Skyscraper 2.0
sbs.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Core
3 The Skyscraper Project - Version 2.0
4 Copyright (C)2004-2024 Ryan Thoryk
5 https://www.skyscrapersim.net
6 https://sourceforge.net/projects/skyscraper/
7 Contact - ryan@skyscrapersim.net
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*/
23
24#include <OgreRoot.h>
25#include <OgreSceneManager.h>
26#include <OgreFileSystem.h>
27#include <OgreConfigFile.h>
28#include <OgreTimer.h>
29#include "OgreStringVector.h"
30#ifndef DISABLE_SOUND
31#include <fmod.hpp>
32#endif
33#include <OgreBulletDynamicsRigidBody.h>
34#include <OgreBulletCollisionsRay.h>
35#include "globals.h"
36#include "sbs.h"
37#include "manager.h"
38#include "camera.h"
39#include "dynamicmesh.h"
40#include "floor.h"
41#include "elevator.h"
42#include "elevatorcar.h"
43#include "shaft.h"
44#include "stairs.h"
45#include "action.h"
46#include "person.h"
47#include "texture.h"
48#include "light.h"
49#include "wall.h"
50#include "control.h"
51#include "trigger.h"
52#include "soundsystem.h"
53#include "sound.h"
54#include "model.h"
55#include "primitive.h"
56#include "custom.h"
57#include "timer.h"
58#include "profiler.h"
59#include "controller.h"
60#include "callstation.h"
61#include "doorsystem.h"
62#include "gitrev.h"
63#include "buttonpanel.h"
64#include "polymesh.h"
65#include "utility.h"
66#include "geometry.h"
67#include "escalator.h"
68#include "map.h"
69#include "reverb.h"
70
71namespace SBS {
72
73SBS::SBS(Ogre::SceneManager* mSceneManager, FMOD::System *fmodsystem, int instance_number, const Vector3 &position, Real rotation, const Vector3 &area_min, const Vector3 &area_max) : Object(0)
74{
75 sbs = this;
76 this->mSceneManager = mSceneManager;
77
78 version = "1.0.0." + ToString(GIT_REV);
79 version_state = "RC5";
80
81 //root object needs to self-register
82 ObjectCount = 0;
83 RegisterObject(this);
84 InstanceNumber = instance_number;
85
86 //set up SBS object
87 SetValues("SBS", "SBS", true);
88
89 mRoot = Ogre::Root::getSingletonPtr();
90
91 //load config file
92 configfile = new Ogre::ConfigFile();
93 configfile->load("skyscraper.ini");
94
95 //initialize variables
96 BuildingName = "";
97 BuildingDesigner = "";
98 BuildingLocation = "";
99 BuildingDescription = "";
100 BuildingVersion = "";
101 IsRunning = false;
102 Floors = 0;
103 Basements = 0;
104 IsFalling = false;
105 InStairwell = false;
106 InElevator = false;
107 IsBuildingsEnabled = false;
108 IsExternalEnabled = false;
109 IsLandscapeEnabled = false;
110 IsSkyboxEnabled = false;
111 fps_frame_count = 0;
112 fps_tottime = 0;
113 FPS = 0;
114 AutoShafts = GetConfigBool("Skyscraper.SBS.AutoShafts", true);
115 AutoStairs = GetConfigBool("Skyscraper.SBS.AutoStairs", true);
116 ElevatorSync = false;
117 ElevatorNumber = 1;
118 CarNumber = 1;
119 wall_orientation = 1;
120 floor_orientation = 2;
121 DrawMainN = true;
122 DrawMainP = true;
123 DrawSideN = false;
124 DrawSideP = false;
125 DrawTop = false;
126 DrawBottom = false;
127 DrawMainNOld = true;
128 DrawMainPOld = true;
129 DrawSideNOld = false;
130 DrawSidePOld = false;
131 DrawTopOld = false;
132 DrawBottomOld = false;
133 delta = 0.01;
134 ProcessElevators = GetConfigBool("Skyscraper.SBS.ProcessElevators", true);
135 remaining_delta = 0;
136 start_time = 0;
137 running_time = 0;
138 InShaft = false;
139 DeleteColliders = false;
140 soundcount = 0;
141 reverbcount = 0;
142 UnitScale = GetConfigFloat("Skyscraper.SBS.UnitScale", 4);
143 Verbose = GetConfigBool("Skyscraper.SBS.Verbose", false);
144 InterfloorOnTop = false;
145 FastDelete = false;
146 WallCount = 0;
147 PolygonCount = 0;
148 SkyBox = 0;
149 Landscape = 0;
150 External = 0;
151 Buildings = 0;
152 current_time = 0;
153 current_virtual_time = 0;
154 elapsed_time = 0;
155 average_time = 0;
156 timer = new Ogre::Timer();
157 AmbientR = 1;
158 AmbientG = 1;
159 AmbientB = 1;
160 OldAmbientR = 1;
161 OldAmbientG = 1;
162 OldAmbientB = 1;
163 TexelOverride = false;
164 enable_profiling = false;
166 SkyName = GetConfigString("Skyscraper.SBS.SkyName", "noon");
167 ShaftDisplayRange = GetConfigInt("Skyscraper.SBS.ShaftDisplayRange", 3);
168 StairsDisplayRange = GetConfigInt("Skyscraper.SBS.StairsDisplayRange", 5);
169 ShaftOutsideDisplayRange = GetConfigInt("Skyscraper.SBS.ShaftOutsideDisplayRange", 3);
170 StairsOutsideDisplayRange = GetConfigInt("Skyscraper.SBS.StairsOutsideDisplayRange", 3);
171 FloorDisplayRange = GetConfigInt("Skyscraper.SBS.FloorDisplayRange", 3);
172 SmoothFrames = GetConfigInt("Skyscraper.SBS.SmoothFrames", 200);
173 RenderOnStartup = GetConfigBool("Skyscraper.SBS.RenderOnStartup", false);
174 RandomActivity = GetConfigBool("Skyscraper.SBS.RandomActivity", false);
175 Malfunctions = GetConfigBool("Skyscraper.SBS.Malfunctions", false);
176 power_state = true;
177 Lobby = 0;
178 MapGenerator = 0;
179
180 //create utility object
181 utility = new Utility(this);
182
183 //create geometry controller object
184 geometry = new GeometryController(this);
185
186 //set padding factor for meshes
187 Ogre::MeshManager::getSingleton().setBoundsPaddingFactor(0.0);
188
189 camera = 0;
190 Buildings = 0;
191 External = 0;
192 Landscape = 0;
193 mWorld = 0;
194 soundsystem = 0;
195 area_trigger = 0;
196 texturemanager = 0;
197
198 if (UnitScale <= 0)
199 UnitScale = 1;
200
201 //Print SBS banner
202 PrintBanner();
203
204 //add instance number to reports
205 InstancePrompt = ToString(InstanceNumber) + ">";
206
207 //move to specified position
208 Move(position);
209
210 //rotate engine
211 Rotate(0.0, rotation, 0.0);
212
213 //create main engine area trigger
214 SetBounds(area_min, area_max);
215
216 //create sound system object if sound is enabled
217 if (fmodsystem)
218 soundsystem = new SoundSystem(this, fmodsystem);
219}
220
222{
223 //create texture manager
224 texturemanager = new TextureManager(this);
225
226 //set up physics
227 Ogre::AxisAlignedBox box (Vector3::ZERO, Vector3::ZERO);
228 mWorld = new OgreBulletDynamics::DynamicsWorld(mSceneManager, box, Vector3::ZERO, true);
229 mWorld->setAllowedCcdPenetration(0);
230
231 /*debugDrawer = new OgreBulletCollisions::DebugDrawer();
232 debugDrawer->setDrawWireframe(true);
233 mWorld->setDebugDrawer(debugDrawer);
234 Ogre::SceneNode *node = mSceneManager->getRootSceneNode()->createChildSceneNode("debugDrawer", Vector3::ZERO);
235 node->attachObject(static_cast<Ogre::SimpleRenderable*> (debugDrawer));
236 */
237
238 //mount sign texture packs
239 Mount("signs-sans.zip", "signs/sans");
240 Mount("signs-sans_bold.zip", "signs/sans_bold");
241 Mount("signs-sans_cond.zip", "signs/sans_cond");
242 Mount("signs-sans_cond_bold.zip", "signs/sans_cond_bold");
243
244 //create object meshes
245 Buildings = new MeshObject(this, "Buildings");
246 External = new MeshObject(this, "External");
247 Landscape = new MeshObject(this, "Landscape");
248 //Landscape->tricollider = false;
249
250 //create manager objects
251 floor_manager = new FloorManager(this);
252 elevator_manager = new ElevatorManager(this);
253 shaft_manager = new ShaftManager(this);
254 stairwell_manager = new StairwellManager(this);
255 door_manager = new DoorManager(this);
256 revolvingdoor_manager = new RevolvingDoorManager(this);
257 vehicle_manager = new VehicleManager(this);
258 controller_manager = new ControllerManager(this);
259
260 //create camera object
261 this->camera = new Camera(this);
262
263 //create map generator object
264 MapGenerator = new Map(this, "Map Generator");
265
266 //report ready status
267 Report("Ready");
268}
269
271{
272 //engine destructor
273
274 Report("Deleting simulator objects...");
275
276 FastDelete = true;
277
278 //delete people
279 for (size_t i = 0; i < PersonArray.size(); i++)
280 {
281 if (PersonArray[i])
282 {
283 PersonArray[i]->parent_deleting = true;
284 delete PersonArray[i];
285 }
286 PersonArray[i] = 0;
287 }
288
289 //delete controls
290 for (size_t i = 0; i < ControlArray.size(); i++)
291 {
292 if (ControlArray[i])
293 {
294 ControlArray[i]->parent_deleting = true;
295 delete ControlArray[i];
296 }
297 ControlArray[i] = 0;
298 }
299
300 //delete triggers
301 for (size_t i = 0; i < TriggerArray.size(); i++)
302 {
303 if (TriggerArray[i])
304 {
305 TriggerArray[i]->parent_deleting = true;
306 delete TriggerArray[i];
307 }
308 TriggerArray[i] = 0;
309 }
310
311 //delete models
312 for (size_t i = 0; i < ModelArray.size(); i++)
313 {
314 if (ModelArray[i])
315 {
316 ModelArray[i]->parent_deleting = true;
317 delete ModelArray[i];
318 }
319 ModelArray[i] = 0;
320 }
321
322 //delete primitives
323 for (size_t i = 0; i < PrimArray.size(); i++)
324 {
325 if (PrimArray[i])
326 {
327 PrimArray[i]->parent_deleting = true;
328 delete PrimArray[i];
329 }
330 PrimArray[i] = 0;
331 }
332
333 //delete custom objects
334 for (size_t i = 0; i < CustomObjectArray.size(); i++)
335 {
336 if (CustomObjectArray[i])
337 {
338 CustomObjectArray[i]->parent_deleting = true;
339 delete CustomObjectArray[i];
340 }
341 CustomObjectArray[i] = 0;
342 }
343
344 //delete lights
345 for (size_t i = 0; i < lights.size(); i++)
346 {
347 if (lights[i])
348 {
349 lights[i]->parent_deleting = true;
350 delete lights[i];
351 }
352 lights[i] = 0;
353 }
354
355 //delete map generator
356 if (MapGenerator)
357 delete MapGenerator;
358 MapGenerator = 0;
359
360 //delete camera object
361 if (camera)
362 {
363 camera->parent_deleting = true;
364 delete camera;
365 }
366 camera = 0;
367
368 //delete manager objects
369 if (floor_manager)
370 {
371 floor_manager->parent_deleting = true;
372 delete floor_manager;
373 }
374 floor_manager = 0;
375
376 if (elevator_manager)
377 {
378 elevator_manager->parent_deleting = true;
379 delete elevator_manager;
380 }
381 elevator_manager = 0;
382
383 if (shaft_manager)
384 {
385 shaft_manager->parent_deleting = true;
386 delete shaft_manager;
387 }
388 shaft_manager = 0;
389
390 if (stairwell_manager)
391 {
392 stairwell_manager->parent_deleting = true;
393 delete stairwell_manager;
394 }
395 stairwell_manager = 0;
396
397 if (door_manager)
398 {
399 door_manager->parent_deleting = true;
400 delete door_manager;
401 }
402 door_manager = 0;
403
404 if (revolvingdoor_manager)
405 {
406 revolvingdoor_manager->parent_deleting = true;
407 delete revolvingdoor_manager;
408 }
409 revolvingdoor_manager = 0;
410
411 if (vehicle_manager)
412 {
413 vehicle_manager->parent_deleting = true;
414 delete vehicle_manager;
415 }
416 vehicle_manager = 0;
417
418 if (controller_manager)
419 {
420 controller_manager->parent_deleting = true;
421 delete controller_manager;
422 }
423 controller_manager = 0;
424
425 //delete sounds
426 for (size_t i = 0; i < sounds.size(); i++)
427 {
428 if (sounds[i])
429 {
430 sounds[i]->parent_deleting = true;
431 delete sounds[i];
432 }
433 sounds[i] = 0;
434 }
435
436 //delete actions
437 for (size_t i = 0; i < ActionArray.size(); i++)
438 {
439 if (ActionArray[i])
440 delete ActionArray[i];
441 ActionArray[i] = 0;
442 }
443
444 //delete mesh objects
445 if (SkyBox)
446 {
447 SkyBox->parent_deleting = true;
448 delete SkyBox;
449 }
450 SkyBox = 0;
451
452 if (Landscape)
453 {
454 Landscape->parent_deleting = true;
455 delete Landscape;
456 }
457 Landscape = 0;
458
459 if (External)
460 {
461 External->parent_deleting = true;
462 delete External;
463 }
464 External = 0;
465
466 if (Buildings)
467 {
468 Buildings->parent_deleting = true;
469 delete Buildings;
470 }
471 Buildings = 0;
472
473 //delete sound system
474 if (soundsystem)
475 {
476 soundsystem->parent_deleting = true;
477 delete soundsystem;
478 }
479 soundsystem = 0;
480
481 //delete texture manager
482 if (texturemanager)
483 delete texturemanager;
484 texturemanager = 0;
485
486 //delete main area trigger
487 if (area_trigger)
488 {
489 area_trigger->parent_deleting = true;
490 delete area_trigger;
491 }
492 area_trigger = 0;
493
494 //delete physics objects
495 if (mWorld)
496 {
497 //delete mWorld->getDebugDrawer();
498 //mWorld->setDebugDrawer(0);
499 delete mWorld;
500 }
501 mWorld = 0;
502
503 ObjectArray.clear();
504 verify_results.clear();
505
506 if (utility)
507 delete utility;
508 utility = 0;
509
510 if (geometry)
511 delete geometry;
512 geometry = 0;
513
514 if (timer)
515 delete timer;
516 timer = 0;
517
518 if (configfile)
519 delete configfile;
520 configfile = 0;
521
522 Report("Exiting");
523
524 //clear self reference
525 sbs = 0;
526}
527
528bool SBS::Start(std::vector<Ogre::Camera*> &cameras)
529{
530 //Post-init startup code goes here, before the runloop
531
532 //prepare 3D geometry for use
533 Prepare();
534
535 //free text texture memory
536 texturemanager->FreeTextureBoxes();
537
538 //reset building state
539 ResetState();
540
541 //initialize objects (cascades down through entire object tree)
542 Init();
543
544 //play looping global sounds
545 for (size_t i = 0; i < sounds.size(); i++)
546 {
547 if (sounds[i])
548 {
549 if (sounds[i]->GetLoopState() == true)
550 sounds[i]->Play();
551 }
552 }
553
554 //attach camera object
555 AttachCamera(cameras);
556
557 //enable random activity if specified
558 if (RandomActivity == true)
559 EnableRandomActivity(true);
560
561 //enable malfunctions if specified
562 if (Malfunctions == true)
563 EnableMalfunctions(true);
564
565 //turn on reverbs
566 for (size_t i = 0; i < reverbs.size(); i++)
567 {
568 if (reverbs[i])
569 reverbs[i]->Enabled(true);
570 }
571
572 //print a memory report
573 if (Verbose == true)
574 MemoryReport();
575
576 IsRunning = true;
577
578 return true;
579}
580
582{
583 Report("");
584 Report(" Scalable Building Simulator " + version + " " + version_state);
585 Report(" Copyright (C)2004-2024 Ryan Thoryk");
586 Report(" This software comes with ABSOLUTELY NO WARRANTY. This is free");
587 Report(" software, and you are welcome to redistribute it under certain");
588 Report(" conditions. For details, see the file named LICENSE\n");
589}
590
591void SBS::Loop(bool loading, bool isready)
592{
593 //Main simulator loop
594 SBS_PROFILE_MAIN("SBS");
595
596 if (RenderOnStartup == true && (loading == true || isready == false))
597 Prepare(false);
598
599 if (loading == true)
600 return;
601
602 //This makes sure all timer steps are the same size, in order to prevent the physics from changing
603 //depending on frame rate
604
605 unsigned long timing;
606
607 if (SmoothFrames > 0)
608 timing = GetAverageTime();
609 else
610 timing = GetElapsedTime();
611
612 Real elapsed = Real(timing) / 1000.0;
613
614 //calculate start and running time
615 if (start_time == 0)
616 start_time = GetRunTime() / 1000.0;
617 running_time = (GetRunTime() / 1000.0) - start_time;
618
619 //move camera or update character movement
620 camera->MoveCharacter();
621
622 //update physics
623 if (camera->EnableBullet == true)
624 {
625 if (enable_advanced_profiling == false)
626 ProfileManager::Start_Profile("Collisions/Physics");
627 else
629 mWorld->stepSimulation(elapsed, 0);
631 }
632
633 //sync camera to physics
634 camera->Sync();
635
636 //update sound
637 if (soundsystem)
638 soundsystem->Loop();
639
640 elapsed += remaining_delta;
641
642 //limit the elapsed value to prevent major slowdowns during debugging
643 if (elapsed > .5)
644 elapsed = .5;
645
646 ProfileManager::Start_Profile("Simulator Loop");
647 while (elapsed >= delta)
648 {
649 //Determine floor that the camera is on
650 camera->UpdateCameraFloor();
651
652 //process child object dynamic runloops
653 LoopChildren();
654
655 camera->CheckObjects();
656
657 //process auto areas
658 CheckAutoAreas();
659
660 elapsed -= delta;
661 }
662 remaining_delta = elapsed;
663
664 //process timers
665 ProcessTimers();
666
667 //process engine boundary trigger
668 if (area_trigger)
669 area_trigger->Loop();
670
672
673 //process camera loop
674 camera->Loop();
675}
676
678{
679 //calculate frame rate
680 fps_tottime += elapsed_time;
681 fps_frame_count++;
682 if (fps_tottime > 500)
683 {
684 FPS = (Real (fps_frame_count) * 1000.) / Real (fps_tottime);
685 fps_frame_count = 0;
686 fps_tottime = 0;
687 }
688}
689
690bool SBS::AddWallMain(Wall* wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height_in1, Real height_in2, Real altitude1, Real altitude2, Real tw, Real th, bool autosize, bool report)
691{
692 //Adds a wall with the specified dimensions
693
694 //if report is true, report if trying to create a wall outside of the engine boundary
695
696 //exit if coordinates are invalid
697 if (x1 == x2 && z1 == z2)
698 return ReportError("Invalid coordinates for wall '" + name + "'");
699
700 if (height_in1 == 0.0f && height_in2 == 0.0)
701 return ReportError("No wall height specified for wall '" + name + "'");
702
703 //determine axis of wall
704 int axis = 0;
705 if (std::abs(x1 - x2) > (std::abs(z1 - z2) + 0.00001))
706 //x axis
707 axis = 1;
708 else
709 //z axis
710 axis = 2;
711
712 //convert to clockwise coordinates if on x-axis, or counterclockwise if on z-axis
713 if ((x1 > x2 && axis == 1) || (z1 < z2 && axis == 2))
714 {
715 //reverse coordinates
716 std::swap(x1, x2);
717 std::swap(z1, z2);
718 std::swap(altitude1, altitude2);
719 std::swap(height_in1, height_in2);
720 }
721
722 //map coordinates
723 Vector3 v1 (x1, altitude1 + height_in1, z1); //left top
724 Vector3 v2 (x2, altitude2 + height_in2, z2); //right top
725 Vector3 v3 (x2, altitude2, z2); //right base
726 Vector3 v4 (x1, altitude1, z1); //left base
727
728 Vector3 v5 = v1;
729 Vector3 v6 = v2;
730 Vector3 v7 = v3;
731 Vector3 v8 = v4;
732
733 //exit if outside of the engine boundaries
734 if (area_trigger)
735 {
736 Vector3 v1x = wallobject->GetMesh()->GetPosition() + v1;
737 Vector3 v2x = wallobject->GetMesh()->GetPosition() + v3;
738 if (area_trigger->IsOutside(v1x, v2x) == true)
739 {
740 if (report == true)
741 ReportError("Cannot create wall outside of engine boundaries");
742 return false;
743 }
744 }
745
746 //expand to specified thickness
747 if (axis == 1)
748 {
749 //x axis
750 if (wall_orientation == 0)
751 {
752 //left
753 v5.z += thickness;
754 v6.z += thickness;
755 v7.z += thickness;
756 v8.z += thickness;
757 }
758 if (wall_orientation == 1)
759 {
760 //center
761 Real half = thickness / 2;
762 v1.z -= half;
763 v2.z -= half;
764 v3.z -= half;
765 v4.z -= half;
766 v5.z += half;
767 v6.z += half;
768 v7.z += half;
769 v8.z += half;
770 }
771 if (wall_orientation == 2)
772 {
773 //right
774 v1.z -= thickness;
775 v2.z -= thickness;
776 v3.z -= thickness;
777 v4.z -= thickness;
778 }
779 }
780 else
781 {
782 //z axis
783 if (wall_orientation == 0)
784 {
785 //left
786 v5.x += thickness;
787 v6.x += thickness;
788 v7.x += thickness;
789 v8.x += thickness;
790 }
791 if (wall_orientation == 1)
792 {
793 //center
794 Real half = thickness / 2;
795 v1.x -= half;
796 v2.x -= half;
797 v3.x -= half;
798 v4.x -= half;
799 v5.x += half;
800 v6.x += half;
801 v7.x += half;
802 v8.x += half;
803 }
804 if (wall_orientation == 2)
805 {
806 //right
807 v1.x -= thickness;
808 v2.x -= thickness;
809 v3.x -= thickness;
810 v4.x -= thickness;
811 }
812 }
813
814 //create polygons and set names
815 std::string NewName, texture2 = texture;
816 Real tw2 = tw, th2 = th;
817
818 bool FlipTexture = texturemanager->FlipTexture;
819 bool TextureOverride = texturemanager->TextureOverride;
820
821 if (FlipTexture == true)
822 texturemanager->ProcessTextureFlip(tw, th);
823
824 if (DrawMainN == true)
825 {
826 if (FlipTexture == true)
827 {
828 tw2 = texturemanager->widthscale[0];
829 th2 = texturemanager->heightscale[0];
830 }
831 if (TextureOverride == true)
832 texture2 = texturemanager->mainnegtex;
833
834 NewName = name;
835 if (GetDrawWallsCount() > 1)
836 NewName.append(":front");
837 wallobject->AddQuad(NewName, texture2, v1, v2, v3, v4, tw2, th2, autosize); //front wall
838 }
839
840 if (DrawMainP == true)
841 {
842 if (FlipTexture == true)
843 {
844 tw2 = texturemanager->widthscale[1];
845 th2 = texturemanager->heightscale[1];
846 }
847 if (TextureOverride == true)
848 texture2 = texturemanager->mainpostex;
849
850 NewName = name;
851 NewName.append(":back");
852 wallobject->AddQuad(NewName, texture2, v6, v5, v8, v7, tw2, th2, autosize); //back wall
853 }
854
855 if (thickness != 0.0)
856 {
857 if (DrawSideN == true)
858 {
859 if (FlipTexture == true)
860 {
861 tw2 = texturemanager->widthscale[2];
862 th2 = texturemanager->heightscale[2];
863 }
864 if (TextureOverride == true)
865 texture2 = texturemanager->sidenegtex;
866
867 NewName = name;
868 NewName.append(":left");
869 if (axis == 1)
870 wallobject->AddQuad(NewName, texture2, v5, v1, v4, v8, tw2, th2, autosize); //left wall
871 else
872 wallobject->AddQuad(NewName, texture2, v2, v6, v7, v3, tw2, th2, autosize); //left wall
873 }
874
875 if (DrawSideP == true)
876 {
877 if (FlipTexture == true)
878 {
879 tw2 = texturemanager->widthscale[3];
880 th2 = texturemanager->heightscale[3];
881 }
882 if (TextureOverride == true)
883 texture2 = texturemanager->sidepostex;
884
885 NewName = name;
886 NewName.append(":right");
887 if (axis == 1)
888 wallobject->AddQuad(NewName, texture2, v2, v6, v7, v3, tw2, th2, autosize); //right wall
889 else
890 wallobject->AddQuad(NewName, texture2, v5, v1, v4, v8, tw2, th2, autosize); //right wall
891 }
892
893 if (DrawTop == true)
894 {
895 if (FlipTexture == true)
896 {
897 tw2 = texturemanager->widthscale[4];
898 th2 = texturemanager->heightscale[4];
899 }
900 if (TextureOverride == true)
901 texture2 = texturemanager->toptex;
902
903 NewName = name;
904 NewName.append(":top");
905 wallobject->AddQuad(NewName, texture2, v5, v6, v2, v1, tw2, th2, autosize); //top wall
906 }
907
908 if (DrawBottom == true)
909 {
910 if (FlipTexture == true)
911 {
912 tw2 = texturemanager->widthscale[5];
913 th2 = texturemanager->heightscale[5];
914 }
915 if (TextureOverride == true)
916 texture2 = texturemanager->bottomtex;
917
918 NewName = name;
919 NewName.append(":bottom");
920 wallobject->AddQuad(NewName, texture2, v4, v3, v7, v8, tw2, th2, autosize); //bottom wall
921 }
922 }
923
924 return true;
925}
926
927bool SBS::AddFloorMain(Wall* wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real altitude1, Real altitude2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool autosize, bool legacy_behavior, bool report)
928{
929 //Adds a floor with the specified dimensions and vertical offset
930
931 //direction determines the direction of slope (for different altitude values):
932 //false - left/right from altitude1 to altitude2, or legacy (broken) "ReverseAxis = false" behavior if legacy_behavior is true
933 //true - back/forwards from altitude1 to altitude2, or legacy (broken) "ReverseAxis = true" behavior if legacy_behavior is true
934
935 //if report is true, report if trying to create a floor outside of the engine boundary
936
937 //exit if coordinates are invalid
938 if (x1 == x2 || z1 == z2)
939 return ReportError("Invalid coordinates for floor '" + name + "'");
940
941 //convert to clockwise coordinates
942
943 //determine axis of floor
944 int axis = 0;
945 if (std::abs(x1 - x2) > (std::abs(z1 - z2) + 0.00001))
946 //x axis
947 axis = 1;
948 else
949 //z axis
950 axis = 2;
951
952 if (legacy_behavior == false)
953 {
954 //current behavior
955
956 if (x1 > x2)
957 {
958 std::swap(x1, x2);
959
960 if (reverse_axis == true)
961 std::swap(altitude1, altitude2);
962 }
963 if (z1 > z2)
964 {
965 std::swap(z1, z2);
966
967 if (reverse_axis == false)
968 std::swap(altitude1, altitude2);
969 }
970 }
971 else
972 {
973 //legacy (broken) behavior, for compatibility with previous versions
974
975 if ((x1 > x2 && axis == 1) || (z1 > z2 && axis == 2))
976 {
977 //reverse coordinates if the difference between x or z coordinates is greater
978 std::swap(x1, x2);
979 std::swap(z1, z2);
980 std::swap(altitude1, altitude2);
981 }
982 }
983
984 //map coordinates
985 Vector3 v1, v2, v3, v4;
986
987 if (reverse_axis == false)
988 {
989 v1 = Vector3(x1, altitude1, z1); //bottom left
990 v2 = Vector3(x2, altitude1, z1); //bottom right
991 v3 = Vector3(x2, altitude2, z2); //top right
992 v4 = Vector3(x1, altitude2, z2); //top left
993 }
994 else
995 {
996 if (legacy_behavior == true)
997 {
998 v1 = Vector3(x1, altitude1, z1); //bottom left
999 v2 = Vector3(x1, altitude1, z2); //top left
1000 v3 = Vector3(x2, altitude2, z2); //top right
1001 v4 = Vector3(x2, altitude2, z1); //bottom right
1002 }
1003 else
1004 {
1005 v1 = Vector3(x2, altitude2, z1); //bottom right
1006 v2 = Vector3(x2, altitude2, z2); //top right
1007 v3 = Vector3(x1, altitude1, z2); //top left
1008 v4 = Vector3(x1, altitude1, z1); //bottom left
1009 }
1010 }
1011
1012 Vector3 v5 = v1;
1013 Vector3 v6 = v2;
1014 Vector3 v7 = v3;
1015 Vector3 v8 = v4;
1016
1017 //exit if outside of the engine boundaries
1018 if (area_trigger)
1019 {
1020 Vector3 v1x = wallobject->GetMesh()->GetPosition() + v1;
1021 Vector3 v2x = wallobject->GetMesh()->GetPosition() + v3;
1022 if (area_trigger->IsOutside(v1x, v2x) == true)
1023 {
1024 if (report == true)
1025 ReportError("Cannot create floor outside of engine boundaries");
1026 return false;
1027 }
1028 }
1029
1030 //expand to specified thickness
1031 if (floor_orientation == 0)
1032 {
1033 //bottom
1034 v5.y += thickness;
1035 v6.y += thickness;
1036 v7.y += thickness;
1037 v8.y += thickness;
1038 }
1039 if (floor_orientation == 1)
1040 {
1041 //center
1042 Real half = thickness / 2;
1043 v1.y -= half;
1044 v2.y -= half;
1045 v3.y -= half;
1046 v4.y -= half;
1047 v5.y += half;
1048 v6.y += half;
1049 v7.y += half;
1050 v8.y += half;
1051 }
1052 if (floor_orientation == 2)
1053 {
1054 //top
1055 v1.y -= thickness;
1056 v2.y -= thickness;
1057 v3.y -= thickness;
1058 v4.y -= thickness;
1059 }
1060
1061 //create polygons and set names
1062 std::string NewName, texture2 = texture;
1063 Real tw2 = tw, th2 = th;
1064
1065 bool FlipTexture = texturemanager->FlipTexture;
1066 bool TextureOverride = texturemanager->TextureOverride;
1067
1068 if (FlipTexture == true)
1069 texturemanager->ProcessTextureFlip(tw, th);
1070
1071 //turn on rotation if set
1072 bool old_planarrotate = texturemanager->GetPlanarRotate();
1073 texturemanager->SetPlanarRotate(texture_direction);
1074
1075 if (DrawMainN == true)
1076 {
1077 if (FlipTexture == true)
1078 {
1079 tw2 = texturemanager->widthscale[0];
1080 th2 = texturemanager->heightscale[0];
1081 }
1082 if (TextureOverride == true)
1083 texture2 = texturemanager->mainnegtex;
1084
1085 NewName = name;
1086 if (GetDrawWallsCount() > 1)
1087 NewName.append(":front");
1088 wallobject->AddQuad(NewName, texture2, v1, v2, v3, v4, tw2, th2, autosize); //bottom wall
1089 }
1090
1091 if (DrawMainP == true)
1092 {
1093 if (FlipTexture == true)
1094 {
1095 tw2 = texturemanager->widthscale[1];
1096 th2 = texturemanager->heightscale[1];
1097 }
1098 if (TextureOverride == true)
1099 texture2 = texturemanager->mainpostex;
1100
1101 NewName = name;
1102 NewName.append(":back");
1103 wallobject->AddQuad(NewName, texture2, v8, v7, v6, v5, tw2, th2, autosize); //top wall
1104 }
1105
1106 if (thickness != 0.0)
1107 {
1108 if (DrawSideN == true)
1109 {
1110 if (FlipTexture == true)
1111 {
1112 tw2 = texturemanager->widthscale[2];
1113 th2 = texturemanager->heightscale[2];
1114 }
1115 if (TextureOverride == true)
1116 texture2 = texturemanager->sidenegtex;
1117
1118 NewName = name;
1119 NewName.append(":left");
1120 wallobject->AddQuad(NewName, texture2, v8, v5, v1, v4, tw2, th2, autosize); //left wall
1121 }
1122
1123 if (DrawSideP == true)
1124 {
1125 if (FlipTexture == true)
1126 {
1127 tw2 = texturemanager->widthscale[3];
1128 th2 = texturemanager->heightscale[3];
1129 }
1130 if (TextureOverride == true)
1131 texture2 = texturemanager->sidepostex;
1132
1133 NewName = name;
1134 NewName.append(":right");
1135 wallobject->AddQuad(NewName, texture2, v6, v7, v3, v2, tw2, th2, autosize); //right wall
1136 }
1137
1138 if (DrawTop == true)
1139 {
1140 if (FlipTexture == true)
1141 {
1142 tw2 = texturemanager->widthscale[4];
1143 th2 = texturemanager->heightscale[4];
1144 }
1145 if (TextureOverride == true)
1146 texture2 = texturemanager->toptex;
1147
1148 NewName = name;
1149 NewName.append(":top");
1150 wallobject->AddQuad(NewName, texture2, v5, v6, v2, v1, tw2, th2, autosize); //front wall
1151 }
1152
1153 if (DrawBottom == true)
1154 {
1155 if (FlipTexture == true)
1156 {
1157 tw2 = texturemanager->widthscale[5];
1158 th2 = texturemanager->heightscale[5];
1159 }
1160 if (TextureOverride == true)
1161 texture2 = texturemanager->bottomtex;
1162
1163 NewName = name;
1164 NewName.append(":bottom");
1165 wallobject->AddQuad(NewName, texture2, v7, v8, v4, v3, tw2, th2, autosize); //back wall
1166 }
1167 }
1168
1169 texturemanager->SetPlanarRotate(old_planarrotate);
1170
1171 return true;
1172}
1173
1174Wall* SBS::CreateWallBox(MeshObject* mesh, const std::string &name, const std::string &texture, Real x1, Real x2, Real z1, Real z2, Real height_in, Real voffset, Real tw, Real th, bool inside, bool outside, bool top, bool bottom, bool autosize, bool report)
1175{
1176 //create 4 walls
1177
1178 if (!mesh)
1179 return 0;
1180
1181 //exit if coordinates are invalid
1182 if (x1 == x2 && z1 == z2)
1183 {
1184 ReportError("Invalid coordinates for wall '" + name + "'");
1185 return 0;
1186 }
1187
1188 //create wall object
1189 Wall *wall = mesh->CreateWallObject(name);
1190
1191 bool x_thickness = false, z_thickness = false;
1192 std::string NewName, texture2 = texture;
1193
1194 if (x1 != x2)
1195 x_thickness = true;
1196 if (z1 != z2)
1197 z_thickness = true;
1198
1199 //swap values if the first is greater than the second
1200 if (x1 > x2)
1201 std::swap(x1, x2);
1202
1203 if (z1 > z2)
1204 std::swap(z1, z2);
1205
1206 //exit if outside of the engine boundaries
1207 if (sbs->GetAreaTrigger())
1208 {
1209 if (sbs->GetAreaTrigger()->IsOutside(Vector3(x1, voffset, z1), Vector3(x2, voffset + height_in, z2)) == true)
1210 {
1211 if (report == true)
1212 ReportError("Cannot create wall box outside of engine boundaries");
1213 return 0;
1214 }
1215 }
1216
1217 bool TextureOverride = texturemanager->TextureOverride;
1218
1219 if (inside == true)
1220 {
1221 //generate a box visible from the inside
1222
1223 NewName = name;
1224 NewName.append(":inside");
1225
1226 if (x_thickness == true)
1227 {
1228 if (TextureOverride == true)
1229 texture2 = texturemanager->mainnegtex;
1230
1231 wall->AddQuad( //front
1232 NewName,
1233 texture2,
1234 Vector3(x1, voffset, z1),
1235 Vector3(x2, voffset, z1),
1236 Vector3(x2, voffset + height_in, z1),
1237 Vector3(x1, voffset + height_in, z1), tw, th, autosize);
1238
1239 if (TextureOverride == true)
1240 texture2 = texturemanager->mainpostex;
1241
1242 wall->AddQuad( //back
1243 NewName,
1244 texture2,
1245 Vector3(x2, voffset, z2),
1246 Vector3(x1, voffset, z2),
1247 Vector3(x1, voffset + height_in, z2),
1248 Vector3(x2, voffset + height_in, z2), tw, th, autosize);
1249 }
1250 if (z_thickness == true)
1251 {
1252 if (TextureOverride == true)
1253 texture2 = texturemanager->sidepostex;
1254
1255 wall->AddQuad( //right
1256 NewName,
1257 texture2,
1258 Vector3(x2, voffset, z1),
1259 Vector3(x2, voffset, z2),
1260 Vector3(x2, voffset + height_in, z2),
1261 Vector3(x2, voffset + height_in, z1), tw, th, autosize);
1262
1263 if (TextureOverride == true)
1264 texture2 = texturemanager->sidenegtex;
1265
1266 wall->AddQuad( //left
1267 NewName,
1268 texture2,
1269 Vector3(x1, voffset, z2),
1270 Vector3(x1, voffset, z1),
1271 Vector3(x1, voffset + height_in, z1),
1272 Vector3(x1, voffset + height_in, z2), tw, th, autosize);
1273 }
1274 if (x_thickness == true && z_thickness == true)
1275 {
1276 if (bottom == true)
1277 {
1278 if (TextureOverride == true)
1279 texture2 = texturemanager->bottomtex;
1280
1281 wall->AddQuad( //bottom
1282 NewName,
1283 texture2,
1284 Vector3(x1, voffset, z2),
1285 Vector3(x2, voffset, z2),
1286 Vector3(x2, voffset, z1),
1287 Vector3(x1, voffset, z1), tw, th, autosize);
1288 }
1289
1290 if (top == true)
1291 {
1292 if (TextureOverride == true)
1293 texture2 = texturemanager->toptex;
1294
1295 wall->AddQuad( //top
1296 NewName,
1297 texture2,
1298 Vector3(x1, voffset + height_in, z1),
1299 Vector3(x2, voffset + height_in, z1),
1300 Vector3(x2, voffset + height_in, z2),
1301 Vector3(x1, voffset + height_in, z2), tw, th, autosize);
1302 }
1303 }
1304 }
1305
1306 if (outside == true)
1307 {
1308 NewName = name;
1309 NewName.append(":outside");
1310
1311 if (x_thickness == true)
1312 {
1313 if (TextureOverride == true)
1314 texture2 = texturemanager->mainnegtex;
1315
1316 wall->AddQuad( //front
1317 NewName,
1318 texture2,
1319 Vector3(x1, voffset + height_in, z1),
1320 Vector3(x2, voffset + height_in, z1),
1321 Vector3(x2, voffset, z1),
1322 Vector3(x1, voffset, z1), tw, th, autosize);
1323
1324 if (TextureOverride == true)
1325 texture2 = texturemanager->mainpostex;
1326
1327 wall->AddQuad( //back
1328 NewName,
1329 texture2,
1330 Vector3(x2, voffset + height_in, z2),
1331 Vector3(x1, voffset + height_in, z2),
1332 Vector3(x1, voffset, z2),
1333 Vector3(x2, voffset, z2), tw, th, autosize);
1334 }
1335 if (z_thickness == true)
1336 {
1337 if (TextureOverride == true)
1338 texture2 = texturemanager->sidepostex;
1339
1340 wall->AddQuad( //right
1341 NewName,
1342 texture2,
1343 Vector3(x2, voffset + height_in, z1),
1344 Vector3(x2, voffset + height_in, z2),
1345 Vector3(x2, voffset, z2),
1346 Vector3(x2, voffset, z1), tw, th, autosize);
1347
1348 if (TextureOverride == true)
1349 texture2 = texturemanager->sidenegtex;
1350
1351 wall->AddQuad( //left
1352 NewName,
1353 texture2,
1354 Vector3(x1, voffset + height_in, z2),
1355 Vector3(x1, voffset + height_in, z1),
1356 Vector3(x1, voffset, z1),
1357 Vector3(x1, voffset, z2), tw, th, autosize);
1358 }
1359 if (x_thickness == true && z_thickness == true)
1360 {
1361 if (bottom == true)
1362 {
1363 if (TextureOverride == true)
1364 texture2 = texturemanager->bottomtex;
1365
1366 wall->AddQuad( //bottom
1367 NewName,
1368 texture2,
1369 Vector3(x1, voffset, z1),
1370 Vector3(x2, voffset, z1),
1371 Vector3(x2, voffset, z2),
1372 Vector3(x1, voffset, z2), tw, th, autosize);
1373 }
1374 if (top == true)
1375 {
1376 if (TextureOverride == true)
1377 texture2 = texturemanager->toptex;
1378
1379 wall->AddQuad( //top
1380 NewName,
1381 texture2,
1382 Vector3(x1, voffset + height_in, z2),
1383 Vector3(x2, voffset + height_in, z2),
1384 Vector3(x2, voffset + height_in, z1),
1385 Vector3(x1, voffset + height_in, z1), tw, th, autosize);
1386 }
1387 }
1388 }
1389 return wall;
1390}
1391
1392Wall* SBS::CreateWallBox2(MeshObject* mesh, const std::string &name, const std::string &texture, Real CenterX, Real CenterZ, Real WidthX, Real LengthZ, Real height_in, Real voffset, Real tw, Real th, bool inside, bool outside, bool top, bool bottom, bool autosize, bool report)
1393{
1394 //create 4 walls from a central point
1395
1396 Real x1 = CenterX - (WidthX / 2);
1397 Real x2 = CenterX + (WidthX / 2);
1398 Real z1 = CenterZ - (LengthZ / 2);
1399 Real z2 = CenterZ + (LengthZ / 2);
1400
1401 return CreateWallBox(mesh, name, texture, x1, x2, z1, z2, height_in, voffset, tw, th, inside, outside, top, bottom, autosize, report);
1402}
1403
1404void SBS::AddPolygon(Wall* wallobject, const std::string &texture, PolyArray &varray, Real tw, Real th, bool report)
1405{
1406 //creates a polygon in the specified wall object
1407
1408 if (!wallobject)
1409 return;
1410
1411 PolyArray varray1 = varray;
1412 PolyArray varray2;
1413
1414 //get number of stored vertices
1415 size_t num = varray.size();
1416
1417 //create a second array with reversed vertices
1418 varray2.reserve(num);
1419 for (size_t i = num - 1; i < num; --i)
1420 varray2.emplace_back(varray1[i]);
1421
1422 //create 2 polygons (front and back) from the vertex array
1423
1424 //get polygon native direction
1425 Vector3 direction = utility->GetPolygonDirection(varray1);
1426
1427 //if the polygon is facing right, down or to the back, reverse faces
1428 //to keep the vertices clockwise
1429 if (direction.x == 1 || direction.y == -1 || direction.z == 1)
1430 std::swap(varray1, varray2);
1431
1432 std::string name = wallobject->GetName();
1433
1434 //exit if outside of the engine boundaries
1435 if (sbs->GetAreaTrigger())
1436 {
1437 for (size_t i = 0; i < varray1.size(); i++)
1438 {
1439 if (sbs->GetAreaTrigger()->IsOutside(varray1[i]) == true)
1440 {
1441 if (report == true)
1442 ReportError("Cannot create polygon outside of engine boundaries");
1443 return;
1444 }
1445 }
1446 }
1447
1448 //add the polygons
1449 if (DrawMainN == true)
1450 {
1451 std::string NewName = name;
1452 if (DrawMainP == true)
1453 NewName.append(":0");
1454 std::string final_texture = texture;
1455 if (texturemanager->TextureOverride == true)
1456 final_texture = texturemanager->mainnegtex;
1457 wallobject->AddPolygon(NewName, final_texture, varray1, tw, th, true);
1458 }
1459 if (DrawMainP == true)
1460 {
1461 std::string NewName = name;
1462 if (DrawMainN == true)
1463 NewName.append(":1");
1464 std::string final_texture = texture;
1465 if (texturemanager->TextureOverride == true)
1466 final_texture = texturemanager->mainpostex;
1467 wallobject->AddPolygon(NewName, final_texture, varray2, tw, th, true);
1468 }
1469}
1470
1471Wall* SBS::AddCustomWall(MeshObject* mesh, const std::string &name, const std::string &texture, PolyArray &varray, Real tw, Real th)
1472{
1473 //Adds a wall from a specified array of 3D vectors
1474
1475 if (!mesh)
1476 return 0;
1477
1478 //create wall object
1479 Wall *wall = mesh->CreateWallObject(name);
1480
1481 //create polygon in wall object
1482 AddPolygon(wall, texture, varray, tw, th);
1483
1484 return wall;
1485}
1486
1487Wall* SBS::AddCustomFloor(MeshObject* mesh, const std::string &name, const std::string &texture, std::vector<Vector2> &varray, Real altitude, Real tw, Real th)
1488{
1489 //Same as AddCustomWall, with only one altitude value value
1490 PolyArray varray3;
1491
1492 //set up 3D vertex array
1493 varray3.reserve(varray.size());
1494 for (size_t i = 0; i < varray.size(); i++)
1495 {
1496 varray3.emplace_back(Vector3(varray[i].x, altitude, varray[i].y));
1497 }
1498
1499 //pass data on to AddCustomWall function
1500 return AddCustomWall(mesh, name, texture, varray3, tw, th);
1501}
1502
1503Wall* SBS::AddTriangleWall(MeshObject* mesh, const std::string &name, const std::string &texture, Real x1, Real y1, Real z1, Real x2, Real y2, Real z2, Real x3, Real y3, Real z3, Real tw, Real th)
1504{
1505 //Adds a triangular wall with the specified dimensions
1506 PolyArray varray;
1507
1508 //set up temporary vertex array
1509 varray.reserve(3);
1510 varray.emplace_back(Vector3(x1, y1, z1));
1511 varray.emplace_back(Vector3(x2, y2, z2));
1512 varray.emplace_back(Vector3(x3, y3, z3));
1513
1514 //pass data on to AddCustomWall function
1515 return AddCustomWall(mesh, name, texture, varray, tw, th);
1516}
1517
1518void SBS::EnableBuildings(bool value)
1519{
1520 //turns buildings on/off
1521 Buildings->Enabled(value);
1522 IsBuildingsEnabled = value;
1523}
1524
1525void SBS::EnableLandscape(bool value)
1526{
1527 //turns landscape on/off
1528 Landscape->Enabled(value);
1529 IsLandscapeEnabled = value;
1530}
1531
1532void SBS::EnableExternal(bool value)
1533{
1534 //turns external on/off
1535
1536 if (External)
1537 External->Enabled(value);
1538 IsExternalEnabled = value;
1539}
1540
1541void SBS::EnableSkybox(bool value)
1542{
1543 //turns skybox on/off
1544 if (SkyBox)
1545 {
1546 SkyBox->Enabled(value);
1547 IsSkyboxEnabled = value;
1548 }
1549 else
1550 IsSkyboxEnabled = true;
1551}
1552
1554{
1555 //create skybox
1556
1557 //only create skybox if first engine instance
1558 if (InstanceNumber > 0)
1559 return;
1560
1561 bool result = Mount("sky-" + SkyName + ".zip", "sky");
1562
1563 //load textures
1564 if (result == true)
1565 {
1566 SetLighting();
1567 texturemanager->LoadTexture("sky/up.jpg", "SkyTop", -1, -1, false, false, false, 0);
1568 texturemanager->LoadTexture("sky/down.jpg", "SkyBottom", -1, -1, false, false, false, 0);
1569 texturemanager->LoadTexture("sky/left.jpg", "SkyLeft", 1, 1, false, false, false, 0);
1570 texturemanager->LoadTexture("sky/right.jpg", "SkyRight", 1, 1, false, false, false, 0);
1571 texturemanager->LoadTexture("sky/front.jpg", "SkyFront", 1, 1, false, false, false, 0);
1572 texturemanager->LoadTexture("sky/back.jpg", "SkyBack", 1, 1, false, false, false, 0);
1573 ResetLighting();
1574 }
1575
1576 //create a mesh for the skybox
1577 SkyBox = new MeshObject(this, "SkyBox");
1578 SkyBox->create_collider = false; //disable collisions on skybox
1579
1580 //create a skybox size that extends by default 30 miles (30 * 5280 ft) in each direction
1581 Real skysize = GetConfigInt("Skyscraper.SBS.HorizonDistance", 30) * 5280.0;
1582
1583 //reset texture mapping to default
1584 texturemanager->ResetTextureMapping(true);
1585
1586 //set textures that the skybox will use
1587 texturemanager->SetTextureOverride("SkyFront", "SkyBack", "SkyLeft", "SkyRight", "SkyTop", "SkyBottom");
1588
1589 //create a wall box, using the skysize value
1590 CreateWallBox(SkyBox, "SkyBox", "SkyFront", -skysize, skysize, -skysize, skysize, skysize, -skysize / 2, 1, 1, true, true, true, true, false);
1591
1592 //restore previous texture mapping
1593 texturemanager->ResetTextureMapping();
1594}
1595
1596int SBS::GetFloorNumber(Real altitude, int lastfloor, bool checklastfloor)
1597{
1598 //Returns floor number located at a specified altitude
1599
1600 if (GetTotalFloors() == 0)
1601 return 0;
1602
1603 //check to see if altitude is below bottom floor
1604 if (GetFloor(-Basements))
1605 {
1606 if (altitude < GetFloor(-Basements)->Altitude)
1607 return -Basements;
1608 }
1609
1610 //if checklastfloor is specified, compare altitude with lastfloor
1611 if (checklastfloor == true && GetFloor(lastfloor))
1612 {
1613 Real lastfloor_altitude = GetFloor(lastfloor)->Altitude;
1614 Real upperfloor_altitude;
1615 if (lastfloor < Floors - 1)
1616 {
1617 if (GetFloor(lastfloor + 1))
1618 upperfloor_altitude = GetFloor(lastfloor + 1)->Altitude;
1619 else
1620 upperfloor_altitude = GetFloor(lastfloor)->Altitude + GetFloor(lastfloor)->FullHeight();
1621 }
1622 else
1623 upperfloor_altitude = GetFloor(lastfloor)->Altitude + GetFloor(lastfloor)->FullHeight();
1624
1625 if (upperfloor_altitude > altitude && lastfloor_altitude <= altitude)
1626 return lastfloor;
1627 else
1628 {
1629 //if altitude is below lastfloor, search downwards; otherwise search upwards
1630 if (altitude < lastfloor_altitude)
1631 {
1632 for (int i = lastfloor - 1; i >= -Basements; i--)
1633 {
1634 if (!GetFloor(i + 1) || !GetFloor(i))
1635 continue;
1636 if (GetFloor(i + 1)->Altitude > altitude && GetFloor(i)->Altitude <= altitude)
1637 return i;
1638 }
1639 }
1640 else if (altitude >= upperfloor_altitude)
1641 {
1642 for (int i = lastfloor + 1; i < Floors; i++)
1643 {
1644 if (!GetFloor(i))
1645 continue;
1646 if (GetFloor(i - 1))
1647 {
1648 if (GetFloor(i - 1)->Altitude <= altitude && GetFloor(i)->Altitude > altitude)
1649 return i - 1;
1650 }
1651 if (i == Floors - 1 && GetFloor(i)->Altitude <= altitude)
1652 return i; //return top floor if on top
1653 }
1654 }
1655 }
1656 }
1657
1658 //otherwise do a slow linear search through floors
1659 for (int i = -Basements + 1; i < Floors; i++)
1660 {
1661 if (!GetFloor(i))
1662 continue;
1663
1664 //check to see if altitude is within a floor (between the current floor's base and
1665 //the lower floor's base)
1666 if (GetFloor(i - 1))
1667 {
1668 if ((GetFloor(i)->Altitude > altitude) && (GetFloor(i - 1)->Altitude <= altitude))
1669 return i - 1;
1670 }
1671 //check to see if altitude is above top floor's altitude
1672 if ((i == Floors - 1) && (altitude > GetFloor(i)->Altitude))
1673 return i;
1674 }
1675 return 0;
1676}
1677
1679{
1680 //returns the distance between 2 2D vectors
1681
1682 if (z1 == z2)
1683 return std::abs(x1 - x2);
1684 if (x1 == x2)
1685 return std::abs(z1 - z2);
1686 if ((x1 != x2) && (z2 != x2))
1687 return sqrt(pow(std::abs(x1 - x2), 2) + pow(std::abs(z1 - z2), 2)); //calculate diagonals
1688 return 0;
1689}
1690
1691Shaft* SBS::CreateShaft(int number, Real CenterX, Real CenterZ, int startfloor, int endfloor)
1692{
1693 //create a shaft object
1694
1695 return shaft_manager->Create(number, CenterX, CenterZ, startfloor, endfloor);
1696}
1697
1698Stairwell* SBS::CreateStairwell(int number, Real CenterX, Real CenterZ, int startfloor, int endfloor)
1699{
1700 //create a stairwell object
1701
1702 return stairwell_manager->Create(number, CenterX, CenterZ, startfloor, endfloor);
1703}
1704
1706{
1707 //create a new elevator object
1708
1709 return elevator_manager->Create(number);
1710}
1711
1713{
1714 //create a new floor object
1715
1716 return floor_manager->Create(number);
1717}
1718
1720{
1721 //create a new vehicle object
1722
1723 return vehicle_manager->Create(number);
1724}
1725
1727{
1728 //create a new controller object
1729
1730 return controller_manager->Create(number);
1731}
1732
1734{
1735 //return the number of elevators
1736 return elevator_manager->GetCount();
1737}
1738
1740{
1741 //return the number of vehicles
1742 return vehicle_manager->GetCount();
1743}
1744
1746{
1747 //return the number of floors, including basements
1748 return floor_manager->GetCount();
1749}
1750
1752{
1753 //return the number of shafts
1754 return shaft_manager->GetCount();
1755}
1756
1758{
1759 //return the number of stairs
1760 return stairwell_manager->GetCount();
1761}
1762
1764{
1765 //return the number of shafts
1766 return controller_manager->GetCount();
1767}
1768
1770{
1771 //return pointer to floor object
1772
1773 return floor_manager->Get(number);
1774}
1775
1777{
1778 //return pointer to elevator object
1779
1780 return elevator_manager->Get(number);
1781}
1782
1784{
1785 //return pointer to shaft object
1786
1787 return shaft_manager->Get(number);
1788}
1789
1791{
1792 //return pointer to stairs object
1793
1794 return stairwell_manager->Get(number);
1795}
1796
1798{
1799 //return pointer to vehicle object
1800
1801 return vehicle_manager->Get(number);
1802}
1803
1805{
1806 //return pointer to controller object
1807
1808 return controller_manager->Get(number);
1809}
1810
1811bool SBS::SetWallOrientation(std::string direction)
1812{
1813 //changes internal wall orientation parameter.
1814 //direction can either be "left" (negative), "center" (0), or "right" (positive).
1815 //default on startup is 1, or center.
1816 //the parameter is used to determine the location of the wall's
1817 //x1/x2 or z1/z2 coordinates in relation to the thickness extents
1818
1819 SetCase(direction, false);
1820
1821 if (direction == "left")
1822 wall_orientation = 0;
1823 else if (direction == "center")
1824 wall_orientation = 1;
1825 else if (direction == "right")
1826 wall_orientation = 2;
1827 else
1828 return ReportError("SetWallOrientation: Invalid wall orientation");
1829 return true;
1830}
1831
1833{
1834 return wall_orientation;
1835}
1836
1837bool SBS::SetFloorOrientation(std::string direction)
1838{
1839 //changes internal floor orientation parameter.
1840 //direction can either be "bottom" (negative), "center" (0), or "top" (positive).
1841 //default on startup is 2, or top.
1842 //the parameter is used to determine the location of the floor's
1843 //x1/x2 or z1/z2 coordinates in relation to the thickness extents
1844
1845 SetCase(direction, false);
1846
1847 if (direction == "bottom")
1848 floor_orientation = 0;
1849 else if (direction == "center")
1850 floor_orientation = 1;
1851 else if (direction == "top")
1852 floor_orientation = 2;
1853 else
1854 return ReportError("SetFloorOrientation: Invalid floor orientation");
1855 return true;
1856}
1857
1859{
1860 return floor_orientation;
1861}
1862
1863void SBS::DrawWalls(bool MainN, bool MainP, bool SideN, bool SideP, bool Top, bool Bottom)
1864{
1865 //sets which walls should be drawn
1866
1867 //first backup old parameters
1868 DrawMainNOld = DrawMainN;
1869 DrawMainPOld = DrawMainP;
1870 DrawSideNOld = DrawSideN;
1871 DrawSidePOld = DrawSideP;
1872 DrawTopOld = DrawTop;
1873 DrawBottomOld = DrawBottom;
1874
1875 //now set new parameters
1876 DrawMainN = MainN;
1877 DrawMainP = MainP;
1878 DrawSideN = SideN;
1879 DrawSideP = SideP;
1880 DrawTop = Top;
1881 DrawBottom = Bottom;
1882}
1883
1884void SBS::ResetWalls(bool ToDefaults)
1885{
1886 //if ToDefaults is true, this resets the DrawWalls data to the defaults.
1887 //if ToDefaults is false, this reverts the DrawWalls data to the previous settings.
1888
1889 if (ToDefaults == true)
1890 DrawWalls(true, true, false, false, false, false);
1891 else
1892 DrawWalls(DrawMainNOld, DrawMainPOld, DrawSideNOld, DrawSidePOld, DrawTopOld, DrawBottomOld);
1893}
1894
1896{
1897 //gets the number of wall polygons enabled
1898
1899 int sides = 0;
1900
1901 if (DrawMainN == true)
1902 sides++;
1903 if (DrawMainP == true)
1904 sides++;
1905 if (DrawSideN == true)
1906 sides++;
1907 if (DrawSideP == true)
1908 sides++;
1909 if (DrawTop == true)
1910 sides++;
1911 if (DrawBottom == true)
1912 sides++;
1913
1914 return sides;
1915}
1916
1918{
1919 //converts meters to feet
1920 return meters * 3.2808399;
1921}
1922
1924{
1925 //converts feet to meters
1926 return feet / 3.2808399;
1927}
1928
1929Wall* SBS::AddWall(MeshObject* mesh, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height_in1, Real height_in2, Real altitude1, Real altitude2, Real tw, Real th)
1930{
1931 //Adds a wall with the specified dimensions, to the specified mesh object
1932
1933 if (!mesh)
1934 return 0;
1935
1936 Wall *wall = mesh->CreateWallObject(name);
1937
1938 AddWallMain(wall, name, texture, thickness, x1, z1, x2, z2, height_in1, height_in2, altitude1, altitude2, tw, th, true);
1939 return wall;
1940}
1941
1942Wall* SBS::AddFloor(MeshObject* mesh, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real altitude1, Real altitude2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool legacy_behavior)
1943{
1944 //Adds a floor with the specified dimensions and vertical offset, to the specified mesh object
1945
1946 if (!mesh)
1947 return 0;
1948
1949 Wall *wall = mesh->CreateWallObject(name);
1950
1951 AddFloorMain(wall, name, texture, thickness, x1, z1, x2, z2, altitude1, altitude2, reverse_axis, texture_direction, tw, th, true, legacy_behavior);
1952 return wall;
1953}
1954
1955Wall* SBS::AddGround(const std::string &name, const std::string &texture, Real x1, Real z1, Real x2, Real z2, Real altitude, int tile_x, int tile_z)
1956{
1957 //Adds ground based on a tiled-floor layout, with the specified dimensions and vertical offset
1958 //this does not support thickness
1959
1960 Vector3 v1, v2, v3, v4;
1961
1962 Real minx, minz, maxx, maxz;
1963
1964 //get min and max values
1965 if (x1 < x2)
1966 {
1967 minx = x1;
1968 maxx = x2;
1969 }
1970 else
1971 {
1972 minx = x2;
1973 maxx = x1;
1974 }
1975 if (z1 < z2)
1976 {
1977 minz = z1;
1978 maxz = z2;
1979 }
1980 else
1981 {
1982 minz = z2;
1983 maxz = z1;
1984 }
1985
1986 Wall *wall = Landscape->CreateWallObject(name);
1987
1988 Report("Creating ground...");
1989
1990 //create polygon tiles
1991 for (Real i = minx; i < maxx; i += tile_x)
1992 {
1993 Real sizex, sizez;
1994
1995 if (i + tile_x > maxx)
1996 sizex = maxx - i;
1997 else
1998 sizex = (Real)tile_x;
1999
2000 for (Real j = minz; j < maxz; j += tile_z)
2001 {
2002 if (j + tile_z > maxz)
2003 sizez = maxz - i;
2004 else
2005 sizez = (Real)tile_z;
2006
2007 DrawWalls(true, true, false, false, false, false);
2008 AddFloorMain(wall, name, texture, 0, i, j, i + sizex, j + sizez, altitude, altitude, false, false, 1, 1, false, false, false);
2009 ResetWalls(false);
2010 }
2011 }
2012 Report("Finished ground");
2013 return wall;
2014}
2015
2016void SBS::EnableFloorRange(int floor, int range, bool value, bool enablegroups, int shaftnumber, int stairsnumber)
2017{
2018 //turn on/off a range of floors
2019 //if range is 3, show shaft on current floor (floor), and 1 floor below and above (3 total floors)
2020 //if range is 1, show only the current floor (floor)
2021
2022 SBS_PROFILE("SBS::EnableFloorRange");
2023
2024 //range must be greater than 0
2025 if (range < 1)
2026 range = 1;
2027
2028 //range must be an odd number; if it's even, then add 1
2029 if (IsEven(range) == true)
2030 range++;
2031
2032 //floor must be valid
2033 if (!IsValidFloor(floor))
2034 return;
2035
2036 int additionalfloors;
2037 if (range > 1)
2038 additionalfloors = (range - 1) / 2;
2039 else
2040 additionalfloors = 0;
2041
2042 Shaft *shaft = 0;
2043 Stairwell *stairwell = 0;
2044
2045 if (shaftnumber > 0)
2046 shaft = GetShaft(shaftnumber);
2047 if (stairsnumber > 0)
2048 stairwell = GetStairwell(stairsnumber);
2049
2050 //disable floors 1 floor outside of range, unless part of group
2051 if (value == true)
2052 {
2053 int floorval = floor - additionalfloors - 1;
2054 if (IsValidFloor(floorval) && GetFloor(floor)->IsInGroup(floorval) == false)
2055 GetFloor(floorval)->Enabled(false);
2056
2057 floorval = floor + additionalfloors + 1;
2058 if (IsValidFloor(floorval) && GetFloor(floor)->IsInGroup(floorval) == false)
2059 GetFloor(floorval)->Enabled(false);
2060 }
2061
2062 //enable floors within range
2063 for (int i = floor - additionalfloors; i <= floor + additionalfloors; i++)
2064 {
2065 Floor *floorobj = GetFloor(i);
2066
2067 if (floorobj)
2068 {
2069 if (shaft)
2070 {
2071 //if a shaft is specified, only show the floor if it is in the related shaft's ShowFloorsList array
2072 if (shaft->ShowFloors > 0)
2073 {
2074 bool showfloor = shaft->IsShowFloor(i);
2075
2076 if (showfloor == true && value == true)
2077 {
2078 if (floorobj->IsEnabled() == false)
2079 {
2080 floorobj->Enabled(true);
2081 if (enablegroups == true)
2082 floorobj->EnableGroup(true);
2083 }
2084 }
2085 else
2086 {
2087 //only disable floor if it hasn't been enabled separately by a related group
2088 if (floorobj->EnabledGroup == true)
2089 {
2090 //for now check to see if the group floor is a ShowFloor
2091 if (shaft->IsShowFloor(floorobj->EnabledGroup_Floor) == true)
2092 return;
2093 }
2094
2095 if (floorobj->IsEnabled() == true)
2096 {
2097 floorobj->Enabled(false);
2098 if (enablegroups == true)
2099 floorobj->EnableGroup(false);
2100 }
2101 }
2102 }
2103 }
2104 else if (stairwell)
2105 {
2106 //if a stairwell is specified, only show the floor if it is in the related stairwell's ShowFloorsList array
2107 if (stairwell->ShowFloors == true)
2108 {
2109 bool showfloor = stairwell->IsShowFloor(i);
2110
2111 if (showfloor == true && value == true)
2112 {
2113 if (floorobj->IsEnabled() == false)
2114 {
2115 floorobj->Enabled(true);
2116 if (enablegroups == true)
2117 floorobj->EnableGroup(true);
2118 }
2119 }
2120 else
2121 {
2122 //only disable floor if it hasn't been enabled separately by a related group
2123 if (floorobj->EnabledGroup == true)
2124 {
2125 //for now check to see if the group floor is a ShowFloor
2126 if (stairwell->IsShowFloor(floorobj->EnabledGroup_Floor) == true)
2127 return;
2128 }
2129
2130 if (floorobj->IsEnabled() == true)
2131 {
2132 floorobj->Enabled(false);
2133 if (enablegroups == true)
2134 floorobj->EnableGroup(false);
2135 }
2136 }
2137 }
2138 }
2139 else
2140 {
2141 floorobj->Enabled(value);
2142 if (enablegroups == true)
2143 floorobj->EnableGroup(value);
2144 }
2145 }
2146 }
2147}
2148
2150{
2151 //register a timer object for callbacks
2152
2153 if (!timer)
2154 return false;
2155
2156 for (size_t i = 0; i < timercallbacks.size(); i++)
2157 {
2158 if (timercallbacks[i] == timer)
2159 return false;
2160 }
2161
2162 //if timer isn't already in the array, add it
2163 timercallbacks.emplace_back(timer);
2164
2165 return true;
2166}
2167
2169{
2170 if (!timer)
2171 return false;
2172
2173 for (size_t i = 0; i < timercallbacks.size(); i++)
2174 {
2175 //unregister existing call button callback
2176 if (timercallbacks[i] == timer)
2177 {
2178 timercallbacks.erase(timercallbacks.begin() + i);
2179 return true;
2180 }
2181 }
2182
2183 return false;
2184}
2185
2187{
2188 SBS_PROFILE("SBS::ProcessTimers");
2189
2190 //process all registered timers
2191 for (size_t i = 0; i < timercallbacks.size(); i++)
2192 {
2193 if (timercallbacks[i])
2194 timercallbacks[i]->Loop();
2195 }
2196}
2197
2199{
2200 //return the number of registered call button callbacks
2201 return (int)timercallbacks.size();
2202}
2203
2204bool SBS::Mount(const std::string &filename, const std::string &path)
2205{
2206 //mounts a zip file into the virtual filesystem
2207
2208 std::string newfile = "data/" + filename;
2209 std::string file = VerifyFile(newfile);
2210
2211 Report("Mounting " + file + " as path " + path);
2212 try
2213 {
2214 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(file, "Zip", path, true);
2215 }
2216 catch (Ogre::Exception &e)
2217 {
2218 return ReportError("Error mounting file " + file + "\n" + e.getDescription());
2219 }
2220 return true;
2221}
2222
2224{
2225 //adds an auto area that enables/disables floors
2226
2227 AutoArea newarea;
2228 newarea.start = start;
2229 newarea.end = end;
2230 newarea.inside = false;
2231 newarea.camerafloor = 0;
2232 FloorAutoArea.emplace_back(newarea);
2233}
2234
2236{
2237 //check all automatic areas
2238
2239 SBS_PROFILE("SBS::CheckAutoAreas");
2240
2241 Vector3 position = camera->GetPosition();
2242 int floor = camera->CurrentFloor;
2243
2244 for (size_t i = 0; i < FloorAutoArea.size(); i++)
2245 {
2246 //reset inside value if floor changed
2247 if (FloorAutoArea[i].camerafloor != floor)
2248 FloorAutoArea[i].inside = false;
2249
2250 if (InBox(FloorAutoArea[i].start, FloorAutoArea[i].end, position) == true && FloorAutoArea[i].inside == false)
2251 {
2252 //user moved into box; enable floors
2253 FloorAutoArea[i].inside = true;
2254 FloorAutoArea[i].camerafloor = floor;
2255 if (floor > -Basements)
2256 {
2257 GetFloor(floor - 1)->Enabled(true);
2258 GetFloor(floor - 1)->EnableGroup(true);
2259 }
2260 GetFloor(floor)->Enabled(true);
2261 GetFloor(floor)->EnableGroup(true);
2262 if (floor < Floors - 1)
2263 {
2264 GetFloor(floor + 1)->Enabled(true);
2265 GetFloor(floor + 1)->EnableGroup(true);
2266 }
2267 }
2268 if (InBox(FloorAutoArea[i].start, FloorAutoArea[i].end, position) == false && FloorAutoArea[i].inside == true)
2269 {
2270 //user moved out of box; disable floors except current
2271 FloorAutoArea[i].inside = false;
2272 FloorAutoArea[i].camerafloor = 0;
2273 if (floor > -Basements)
2274 {
2275 GetFloor(floor - 1)->Enabled(false);
2276 GetFloor(floor - 1)->EnableGroup(false);
2277 }
2278 if (floor < Floors - 1)
2279 {
2280 GetFloor(floor + 1)->Enabled(false);
2281 GetFloor(floor + 1)->EnableGroup(false);
2282 }
2283 GetFloor(floor)->Enabled(true);
2284 GetFloor(floor)->EnableGroup(true);
2285 }
2286 }
2287}
2288
2290{
2291 //return total number of mesh objects
2292 return (int)meshes.size();
2293}
2294
2295Sound* SBS::AddSound(const std::string &name, const std::string &filename, const Vector3 &position, bool loop, Real volume, int speed, Real min_distance, Real max_distance, Real doppler_level, Real cone_inside_angle, Real cone_outside_angle, Real cone_outside_volume, const Vector3 &direction)
2296{
2297 //create a looping sound object
2298 Sound *sound = new Sound(this, name, false);
2299 sounds.emplace_back(sound);
2300
2301 //set parameters and play sound
2302 sound->SetPosition(position);
2303 sound->SetDirection(direction);
2304 sound->SetVolume(volume);
2305 sound->SetSpeed(speed);
2306 sound->SetDistances(min_distance, max_distance);
2307 sound->SetDirection(direction);
2308 sound->SetDopplerLevel(doppler_level);
2309 sound->SetConeSettings(cone_inside_angle, cone_outside_angle, cone_outside_volume);
2310 sound->Load(filename);
2311 sound->SetLoopState(loop);
2312 if (loop && IsRunning == true)
2313 sound->Play();
2314
2315 return sound;
2316}
2317
2318std::vector<Sound*> SBS::GetSound(const std::string &name)
2319{
2320 //get sound by name
2321
2322 std::string findname = name;
2323 SetCase(findname, false);
2324 std::vector<Sound*> soundlist;
2325 for (size_t i = 0; i < sounds.size(); i++)
2326 {
2327 if (sounds[i])
2328 {
2329 std::string name2 = sounds[i]->GetName();
2330 SetCase(name2, false);
2331 if (findname == name2)
2332 soundlist.emplace_back(sounds[i]);
2333 }
2334 }
2335 return soundlist;
2336}
2337
2339{
2340 //return total number of allocated sounds
2341 return soundcount;
2342}
2343
2345{
2346 soundcount++;
2347}
2348
2350{
2351 soundcount--;
2352}
2353
2354Reverb* SBS::AddReverb(const std::string &name, const std::string &type, const Vector3 &position, Real min_distance, Real max_distance)
2355{
2356 //create a reverb object
2357 Reverb *reverb = new Reverb(this, name, type, position, min_distance, max_distance, false);
2358 reverbs.emplace_back(reverb);
2359 return reverb;
2360}
2361
2362Reverb* SBS::GetReverb(const std::string &name)
2363{
2364 //get reverb by name
2365
2366 std::string findname = name;
2367 SetCase(findname, false);
2368 for (size_t i = 0; i < reverbs.size(); i++)
2369 {
2370 if (reverbs[i])
2371 {
2372 std::string name2 = reverbs[i]->GetName();
2373 SetCase(name2, false);
2374 if (findname == name2)
2375 return reverbs[i];
2376 }
2377 }
2378 return 0;
2379}
2380
2382{
2383 //return total number of allocated reverbs
2384 return reverbcount;
2385}
2386
2388{
2389 reverbcount++;
2390}
2391
2393{
2394 reverbcount--;
2395}
2396
2398{
2399 //convert remote (OGRE) vertex positions to local (SBS) positions
2400
2401 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2402 //this means that all Z values that use this function must be inverted.
2403
2404 return remote_value * UnitScale;
2405}
2406
2407Vector2 SBS::ToLocal(const Vector2& remote_value)
2408{
2409 //convert remote (OGRE) vertex positions to local (SBS) positions
2410
2411 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2412 //this means that all Z values that use this function must be inverted.
2413
2414 return remote_value * UnitScale;
2415}
2416
2417Vector3 SBS::ToLocal(const Vector3& remote_value, bool rescale, bool flip_z)
2418{
2419 //convert remote (OGRE) vertex positions to local (SBS) positions
2420 //also convert Z value to OGRE's right-hand coordinate system
2421
2422 Vector3 newvalue;
2423 newvalue.x = remote_value.x;
2424 newvalue.y = remote_value.y;
2425
2426 if (flip_z == true)
2427 newvalue.z = -remote_value.z; //flip z value for OGRE's right-hand coordinate system
2428 else
2429 newvalue.z = remote_value.z;
2430
2431 if (rescale == true)
2432 return newvalue * UnitScale;
2433 else
2434 return newvalue;
2435}
2436
2438{
2439 //convert local (SBS) vertex positions to remote (OGRE) positions
2440
2441 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2442 //this means that all Z values that use this function must be inverted.
2443
2444 return local_value / UnitScale;
2445}
2446
2447Vector2 SBS::ToRemote(const Vector2& local_value)
2448{
2449 //convert local (SBS) vertex positions to remote (OGRE) positions
2450
2451 //note - OGRE uses a right-hand coordinate system, while SBS uses left-hand.
2452 //this means that all Z values that use this function must be inverted.
2453
2454 return local_value / UnitScale;
2455}
2456
2457Vector3 SBS::ToRemote(const Vector3& local_value, bool rescale, bool flip_z)
2458{
2459 //convert local (SBS) vertex positions to remote (OGRE) positions
2460
2461 Vector3 newvalue;
2462 newvalue.x = local_value.x;
2463 newvalue.y = local_value.y;
2464
2465 if (flip_z == true)
2466 newvalue.z = -local_value.z; //flip z value for OGRE's right-hand coordinate system
2467 else
2468 newvalue.z = local_value.z;
2469
2470 if (rescale == true)
2471 return (newvalue / UnitScale);
2472 else
2473 return newvalue;
2474}
2475
2477{
2478 //return number of registered SBS objects
2479 return ObjectCount;
2480}
2481
2483{
2484 //return object pointer from global array
2485 if (number >= 0 && number < (int)ObjectArray.size())
2486 return ObjectArray[number];
2487 else
2488 return 0;
2489}
2490
2492{
2493 //add object to global array
2494 ObjectCount++;
2495 ObjectArray.emplace_back(object);
2496 return (int)ObjectArray.size() - 1;
2497}
2498
2500{
2501 //remove object
2502 //note - this doesn't delete the objects
2503
2504 if (number < (int)ObjectArray.size())
2505 {
2506 if (ObjectArray[number])
2507 {
2508 if (ObjectArray[number]->GetNumber() == number)
2509 {
2510 std::vector<Object*> objects;
2511 objects.emplace_back(ObjectArray[number]);
2512 RemoveActionParent(objects);
2513 ObjectArray[number] = 0;
2514 ObjectCount--;
2515 return true;
2516 }
2517 }
2518 }
2519 return false;
2520}
2521
2522bool SBS::IsValidFloor(int floor)
2523{
2524 //determine if a floor is valid
2525
2526 if (GetFloor(floor))
2527 return true;
2528 return false;
2529}
2530
2531std::string SBS::DumpState()
2532{
2533 //dump basic simulator state to a string
2534
2535 std::string output = "SBS version: " + version + "\n";
2536 output.append("Instance number: " + ToString(InstanceNumber) + "\n");
2537 output.append("Building Name: " + BuildingName + "\n");
2538 output.append("Building Filename: " + BuildingFilename + "\n");
2539 output.append("Building Version: " + BuildingVersion + "\n");
2540 output.append("InStairwell: ");
2541 output.append(BoolToString(InStairwell));
2542 output.append("\n");
2543 output.append("InElevator: ");
2544 output.append(BoolToString(InElevator));
2545 output.append("\n");
2546 output.append("InShaft: ");
2547 output.append(BoolToString(InShaft));
2548 output.append("\n");
2549 output.append("CameraFloor: ");
2550 if (camera)
2551 output.append(ToString(camera->CurrentFloor));
2552 output.append("\n");
2553 output.append("ElevatorNumber: ");
2554 output.append(ToString(ElevatorNumber));
2555 output.append("\n");
2556 output.append("CarNumber: ");
2557 output.append(ToString(CarNumber));
2558 output.append("\n");
2559 output.append("ElevatorSync: ");
2560 output.append(BoolToString(ElevatorSync));
2561 output.append("\n");
2562 output.append("Running Time: ");
2563 output.append(TruncateNumber(running_time, 2));
2564 output.append("\n");
2565 output.append("BuildingsEnabled: ");
2566 output.append(BoolToString(IsBuildingsEnabled));
2567 output.append("\n");
2568 output.append("ExternalEnabled: ");
2569 output.append(BoolToString(IsExternalEnabled));
2570 output.append("\n");
2571 output.append("LandscapeEnabled: ");
2572 output.append(BoolToString(IsLandscapeEnabled));
2573 output.append("\n");
2574 output.append("SkyboxEnabled: ");
2575 output.append(BoolToString(IsSkyboxEnabled));
2576 output.append("\n");
2577 output.append("Verbose: ");
2578 output.append(BoolToString(Verbose));
2579 output.append("\n");
2580 output.append("InterfloorOnTop: ");
2581 output.append(BoolToString(InterfloorOnTop));
2582 output.append("\n");
2583 output.append("Object Count: ");
2584 output.append(ToString(ObjectCount));
2585 output.append("\n");
2586 if (camera)
2587 {
2588 output.append("Camera Floor: ");
2589 output.append(ToString(camera->CurrentFloor));
2590 output.append("\n");
2591 output.append("Camera Position: " + TruncateNumber(camera->GetPosition().x, 2) + ", " + TruncateNumber(camera->GetPosition().y, 2) + ", " + TruncateNumber(camera->GetPosition().z, 2) + "\n");
2592 }
2593
2594 return output;
2595}
2596
2598{
2599 //object deletion routine
2600 //this should be called to delete a simulator object during runtime
2601
2602 if (!object)
2603 return ReportError("Invalid object");
2604
2605 std::string number = ToString(object->GetNumber());
2606 bool deleted = false;
2607
2608 //don't delete permanent objects
2609 if (object->IsPermanent() == true)
2610 return ReportError("Cannot delete permanent object " + number);
2611
2612 std::string type = object->GetType();
2613
2614 //perform standard delete based on object type
2615 if (type == "Floor")
2616 {
2617 Floor *floor = static_cast<Floor*>(object);
2618
2619 //make sure no shaft is dependent on this floor
2620 for (int i = 0; i < shaft_manager->GetCount(); i++)
2621 {
2622 Shaft *shaft = shaft_manager->GetIndex(i);
2623 if (shaft)
2624 {
2625 if (shaft->IsValidFloor(floor->Number) == true)
2626 return ReportError("Cannot delete floor " + ToString(floor->Number) + " - in use by shaft " + ToString(shaft->ShaftNumber));
2627 }
2628 }
2629
2630 //make sure no stairwell is dependent on this floor
2631 for (int i = 0; i < stairwell_manager->GetCount(); i++)
2632 {
2633 Stairwell *stairwell = stairwell_manager->GetIndex(i);
2634 if (stairwell)
2635 {
2636 if (stairwell->IsValidFloor(floor->Number) == true)
2637 return ReportError("Cannot delete floor " + ToString(floor->Number) + " - in use by stairwell " + ToString(stairwell->StairsNum));
2638 }
2639 }
2640
2641 //restrict deletions to only lowest/highest floors
2642 if (floor->Number >= 0 && GetFloor(floor->Number + 1))
2643 return ReportError("Only the highest floor can be deleted");
2644
2645 if (floor->Number < 0 && GetFloor(floor->Number - 1))
2646 return ReportError("Only the lowest basement can be deleted");
2647
2648 deleted = true;
2649 }
2650 else if (type == "Elevator")
2651 deleted = true;
2652 else if (type == "ButtonPanel")
2653 {
2654 if (object->GetParent()->GetType() == "ElevatorCar")
2655 deleted = true;
2656 }
2657 else if (type == "CallButton")
2658 deleted = true;
2659 else if (type == "DirectionalIndicator")
2660 deleted = true;
2661 else if (type == "Door")
2662 deleted = true;
2663 else if (type == "RevolvingDoor")
2664 deleted = true;
2665 else if (type == "ElevatorDoor")
2666 deleted = true;
2667 else if (type == "FloorIndicator")
2668 deleted = true;
2669 else if (type == "Shaft")
2670 {
2671 Shaft *shaft = static_cast<Shaft*>(object);
2672
2673 //make sure no elevator is dependent on this shaft
2674 for (int i = 0; i < elevator_manager->GetCount(); i++)
2675 {
2676 Elevator *elev = elevator_manager->GetIndex(i);
2677 if (elev)
2678 {
2679 if (elev->AssignedShaft == shaft->ShaftNumber)
2680 return ReportError("Cannot delete shaft " + ToString(shaft->ShaftNumber) + " - in use by elevator " + ToString(elev->Number));
2681 }
2682 }
2683
2684 deleted = true;
2685 }
2686 else if (type == "Sound")
2687 deleted = true;
2688 else if (type == "Stairwell")
2689 deleted = true;
2690 else if (type == "Wall")
2691 deleted = true;
2692 else if (type == "Model")
2693 deleted = true;
2694 else if (type == "Control")
2695 deleted = true;
2696 else if (type == "Trigger")
2697 deleted = true;
2698 else if (type == "DoorWrapper")
2699 {
2700 DoorWrapper* wrapper = static_cast<DoorWrapper*>(object);
2701 if (wrapper->IsShaftDoor == false)
2702 return ReportError("Deleting the main elevator door wrapper is not supported yet");
2703
2704 deleted = true;
2705 }
2706 else if (type == "Escalator")
2707 deleted = true;
2708 else if (type == "Person")
2709 deleted = true;
2710 else if (type == "ElevatorCar")
2711 {
2712 ElevatorCar *car = static_cast<ElevatorCar*>(object);
2713 if (car->Number != car->GetElevator()->GetCarCount())
2714 return ReportError("Only the highest elevator car can be deleted");
2715 if (car->Number == 1)
2716 return ReportError("Cannot delete the primary elevator car");
2717
2718 deleted = true;
2719 }
2720 else if (type == "MovingWalkway")
2721 deleted = true;
2722 else if (type == "Vehicle")
2723 deleted = true;
2724 else if (type == "Light")
2725 deleted = true;
2726 else if (type == "CallStation")
2727 deleted = true;
2728 else if (type == "DispatchController")
2729 deleted = true;
2730 else if (type == "Primitive")
2731 deleted = true;
2732 else if (type == "CustomObject")
2733 deleted = true;
2734 else if (type == "Reverb")
2735 deleted = true;
2736 else if (type == "CameraTexture")
2737 deleted = true;
2738
2739 //delete object
2740 if (deleted == true)
2741 delete object;
2742
2743 camera->ResetCollisions();
2744
2745 return deleted;
2746}
2747
2748bool SBS::DeleteObject(int object)
2749{
2750 //delete object by numeric ID
2751 return DeleteObject(GetObject(object));
2752}
2753
2754bool SBS::MoveObject(Object *object, Vector3 position, bool relative, bool X, bool Y, bool Z)
2755{
2756 //move an object by reference
2757 //if relative is false, the X, Y and Z values determine which position axes should be set
2758
2759 if (!object)
2760 return ReportError("Invalid object");
2761
2762 if (relative == false)
2763 {
2764 if (X == false)
2765 position.x = object->GetPosition().x;
2766 if (Y == false)
2767 position.y = object->GetPosition().y;
2768 if (Z == false)
2769 position.z = object->GetPosition().z;
2770
2771 object->SetPosition(position);
2772 }
2773 else
2774 object->Move(position);
2775
2776 return true;
2777}
2778
2779bool SBS::RotateObject(Object *object, Vector3 rotation, Real speed, bool relative, bool X, bool Y, bool Z)
2780{
2781 //rotate an object by reference
2782 //if relative is false, the X, Y and Z values determine which position axes should be set
2783
2784 if (!object)
2785 return ReportError("Invalid object");
2786
2787 if (relative == true)
2788 object->Rotate(rotation, speed);
2789 else
2790 {
2791 if (X == false)
2792 rotation.x = object->GetRotation().x;
2793 if (Y == false)
2794 rotation.y = object->GetRotation().y;
2795 if (Z == false)
2796 rotation.z = object->GetRotation().z;
2797 object->SetRotation(rotation);
2798 }
2799
2800 return true;
2801}
2802
2804{
2805 //remove a floor (does not delete the object)
2806
2807 floor_manager->Remove(floor);
2808}
2809
2811{
2812 //remove an elevator (does not delete the object)
2813
2814 elevator_manager->Remove(elevator);
2815}
2816
2818{
2819 //remove a shaft (does not delete the object)
2820
2821 shaft_manager->Remove(shaft);
2822}
2823
2825{
2826 //remove a stairs object (does not delete the object)
2827
2828 stairwell_manager->Remove(stairs);
2829}
2830
2832{
2833 //remove a sound from the array
2834 //this does not delete the object
2835
2836 for (size_t i = 0; i < sounds.size(); i++)
2837 {
2838 if (sounds[i] == sound)
2839 {
2840 sounds.erase(sounds.begin() + i);
2841 return;
2842 }
2843 }
2844}
2845
2847{
2848 //remove a reverb from the array
2849 //this does not delete the object
2850
2851 for (size_t i = 0; i < reverbs.size(); i++)
2852 {
2853 if (reverbs[i] == reverb)
2854 {
2855 reverbs.erase(reverbs.begin() + i);
2856 return;
2857 }
2858 }
2859}
2860
2862{
2863 //remove a light reference (does not delete the object itself)
2864 for (size_t i = 0; i < lights.size(); i++)
2865 {
2866 if (lights[i] == light)
2867 {
2868 lights.erase(lights.begin() + i);
2869 return;
2870 }
2871 }
2872}
2873
2875{
2876 //remove a model reference (does not delete the object itself)
2877 for (size_t i = 0; i < ModelArray.size(); i++)
2878 {
2879 if (ModelArray[i] == model)
2880 {
2881 ModelArray.erase(ModelArray.begin() + i);
2882 return;
2883 }
2884 }
2885}
2886
2888{
2889 //remove a prim reference (does not delete the object itself)
2890 for (size_t i = 0; i < PrimArray.size(); i++)
2891 {
2892 if (PrimArray[i] == prim)
2893 {
2894 PrimArray.erase(PrimArray.begin() + i);
2895 return;
2896 }
2897 }
2898}
2899
2901{
2902 //remove a custom object reference (does not delete the object itself)
2903 for (size_t i = 0; i < CustomObjectArray.size(); i++)
2904 {
2905 if (CustomObjectArray[i] == object)
2906 {
2907 CustomObjectArray.erase(CustomObjectArray.begin() + i);
2908 return;
2909 }
2910 }
2911}
2912
2914{
2915 //remove a control reference (does not delete the object itself)
2916 for (size_t i = 0; i < ControlArray.size(); i++)
2917 {
2918 if (ControlArray[i] == control)
2919 {
2920 ControlArray.erase(ControlArray.begin() + i);
2921 return;
2922 }
2923 }
2924}
2925
2927{
2928 //remove a trigger reference (does not delete the object itself)
2929 for (size_t i = 0; i < TriggerArray.size(); i++)
2930 {
2931 if (TriggerArray[i] == trigger)
2932 {
2933 TriggerArray.erase(TriggerArray.begin() + i);
2934 return;
2935 }
2936 }
2937}
2938
2940{
2941 //remove a floor (does not delete the object)
2942
2943 controller_manager->Remove(controller);
2944}
2945
2946std::string SBS::VerifyFile(const std::string &filename)
2947{
2948 bool result = false;
2949 return VerifyFile(filename, result, false);
2950}
2951
2952std::string SBS::VerifyFile(std::string filename, bool &result, bool skip_cache)
2953{
2954 //verify a filename
2955 //if it exists, return the same filename
2956 //otherwise search the related folder and find a matching filename with a different
2957 //case (fixes case-sensitivity issues mainly on Linux)
2958 //returns the original string if not found
2959 //"result" will return if the file exists or not, but only accurately if skip_cache is true
2960
2961 TrimString(filename);
2962 ReplaceAll(filename, "\\", "/");
2963 result = false;
2964
2965 //check for a cached result
2966 if (skip_cache == false)
2967 {
2968 for (size_t i = 0; i < verify_results.size(); i++)
2969 {
2970 if (verify_results[i].filename == filename)
2971 return verify_results[i].result;
2972 }
2973 }
2974
2975 //get filesystem archive
2976 Ogre::Archive *filesystem = 0;
2977 Ogre::ArchiveManager::ArchiveMapIterator it = Ogre::ArchiveManager::getSingleton().getArchiveIterator();
2978 while(it.hasMoreElements())
2979 {
2980 const std::string& key = it.peekNextKey();
2981 filesystem = it.getNext();
2982
2983 if (!filesystem)
2984 return "";
2985
2986 //check for a mount point
2987 Ogre::StringVectorPtr listing;
2988 std::string shortname;
2989 std::string group = GetMountPath(filename, shortname);
2990
2991 if (group == "General")
2992 {
2993 //for the General group, check the native filesystem
2994
2995 if (filesystem->exists(filename) == true)
2996 {
2997 //if exact filename exists, cache and exit
2998 CacheFilename(filename, filename);
2999 result = true;
3000 return filename;
3001 }
3002
3003 //otherwise get listing of files to check
3004 if (!filesystem_listing)
3005 filesystem_listing = filesystem->list();
3006 listing = filesystem_listing;
3007 }
3008 else
3009 {
3010 //for other groups, check resource mount points
3011
3012 if (Ogre::ResourceGroupManager::getSingleton().resourceExists(group, shortname) == true)
3013 {
3014 //if exact filename exists, cache and exit
3015 CacheFilename(filename, filename);
3016 result = true;
3017 return filename;
3018 }
3019
3020 //otherwise get listing of files to check
3021 listing = Ogre::ResourceGroupManager::getSingleton().listResourceNames(group);
3022 }
3023
3024 //go through file listing, to find a match with a different case
3025 for (size_t i = 0; i < listing->size(); i++)
3026 {
3027 std::string check = listing->at(i);
3028 std::string checkoriginal = SetCaseCopy(check, false);
3029 std::string checkfile = SetCaseCopy(filename, false);
3030 if (checkoriginal == checkfile)
3031 {
3032 //if match is found, cache and exit
3033 CacheFilename(filename, check);
3034 result = true;
3035 return check;
3036 }
3037 }
3038 }
3039
3040 //if no match is found, cache original name and exit
3041 CacheFilename(filename, filename);
3042 return filename;
3043}
3044
3045std::string SBS::GetFilesystemPath(std::string filename)
3046{
3047 //returns the filesystem path for the specified file
3048 //the filename needs to be processed by VerifyFile first
3049
3050 TrimString(filename);
3051 ReplaceAll(filename, "\\", "/");
3052
3053 //get filesystem archive
3054 Ogre::Archive *filesystem = 0;
3055 Ogre::ArchiveManager::ArchiveMapIterator it = Ogre::ArchiveManager::getSingleton().getArchiveIterator();
3056 while(it.hasMoreElements())
3057 {
3058 const std::string& key = it.peekNextKey();
3059 filesystem = it.getNext();
3060
3061 if (!filesystem)
3062 return "";
3063
3064 //check for a mount point
3065 std::string shortname;
3066 std::string group = GetMountPath(filename, shortname);
3067
3068 if (group == "General")
3069 {
3070 //for the General group, check the native filesystem
3071
3072 if (filesystem->exists(filename) == true)
3073 {
3074 std::string path = key;
3075 if (key == ".")
3076 path = "";
3077 return std::string(path + filename);
3078 }
3079 }
3080 }
3081
3082 return "";
3083}
3084
3085bool SBS::FileExists(const std::string &filename)
3086{
3087 //check to see if the specified file exists
3088
3089 bool result;
3090 VerifyFile(filename, result, true);
3091
3092 return result;
3093}
3094
3096{
3097 //return total number of registered walls
3098 return WallCount;
3099}
3100
3102{
3103 //return total number of registered walls
3104 return PolygonCount;
3105}
3106
3107void SBS::Prepare(bool report, bool renderonly)
3108{
3109 //prepare objects for run
3110
3111 SBS_PROFILE_MAIN("Prepare");
3112
3113 //prepare mesh objects
3114 if (report == true)
3115 Report("Preparing meshes...");
3116 for (size_t i = 0; i < meshes.size(); i++)
3117 {
3118 meshes[i]->Prepare(false);
3119 }
3120
3121 //process dynamic meshes
3122 if (report == true)
3123 Report("Processing geometry...");
3124 for (size_t i = 0; i < dynamic_meshes.size(); i++)
3125 {
3126 if (sbs->Verbose && report == true)
3127 Report("DynamicMesh " + ToString((int)i) + " of " + ToString((int)dynamic_meshes.size()));
3128 dynamic_meshes[i]->Prepare();
3129 }
3130
3131 if (renderonly == false)
3132 {
3133 if (report == true)
3134 Report("Creating colliders...");
3135 for (size_t i = 0; i < meshes.size(); i++)
3136 {
3137 if (meshes[i]->tricollider == true && meshes[i]->IsPhysical() == false)
3138 meshes[i]->CreateCollider();
3139 else
3140 meshes[i]->CreateBoxCollider();
3141 }
3142 }
3143
3144 if (report == true)
3145 Report("Finished prepare");
3146}
3147
3148Light* SBS::AddLight(const std::string &name, int type)
3149{
3150 //add a global light
3151
3152 Light* light = new Light(this, name, type);
3153 lights.emplace_back(light);
3154 return light;
3155}
3156
3158{
3159 meshes.emplace_back(handle);
3160}
3161
3163{
3164 for (size_t i = 0; i < meshes.size(); i++)
3165 {
3166 if (meshes[i] == handle)
3167 {
3168 meshes.erase(meshes.begin() + i);
3169 return;
3170 }
3171 }
3172}
3173
3174MeshObject* SBS::FindMeshObject(const std::string &name)
3175{
3176 //find a mesh object by searching for matching wrapper
3177 for (size_t i = 0; i < meshes.size(); i++)
3178 {
3179 if (meshes[i]->name == name)
3180 return meshes[i];
3181 }
3182 return 0;
3183}
3184
3185Model* SBS::AddModel(const std::string &name, const std::string &filename, bool center, const Vector3 &position, const Vector3 &rotation, Real max_render_distance, Real scale_multiplier, bool enable_physics, Real restitution, Real friction, Real mass)
3186{
3187 //add a model
3188 Model* model = new Model(this, name, filename, center, position, rotation, max_render_distance, scale_multiplier, enable_physics, restitution, friction, mass);
3189 if (model->load_error == true)
3190 {
3191 delete model;
3192 return 0;
3193 }
3194 ModelArray.emplace_back(model);
3195 return model;
3196}
3197
3199{
3200 //add a model reference
3201
3202 if (!model)
3203 return;
3204
3205 for (size_t i = 0; i < ModelArray.size(); i++)
3206 {
3207 if (ModelArray[i] == model)
3208 return;
3209 }
3210
3211 ModelArray.emplace_back(model);
3212}
3213
3214Primitive* SBS::AddPrimitive(const std::string &name)
3215{
3216 //add a prim
3217 Primitive* prim = new Primitive(this, name);
3218 PrimArray.emplace_back(prim);
3219 return prim;
3220}
3221
3223{
3224 //add a primitive reference
3225
3226 if (!primitive)
3227 return;
3228
3229 for (size_t i = 0; i < PrimArray.size(); i++)
3230 {
3231 if (PrimArray[i] == primitive)
3232 return;
3233 }
3234
3235 PrimArray.emplace_back(primitive);
3236}
3237
3238CustomObject* SBS::AddCustomObject(const std::string &name, const Vector3 &position, const Vector3 &rotation, Real max_render_distance, Real scale_multiplier)
3239{
3240 //add a custom object
3241 CustomObject* object = new CustomObject(this, name, position, rotation, max_render_distance, scale_multiplier);
3242 CustomObjectArray.emplace_back(object);
3243 return object;
3244}
3245
3247{
3248 //add a custom object reference
3249
3250 if (!object)
3251 return;
3252
3253 for (size_t i = 0; i < CustomObjectArray.size(); i++)
3254 {
3255 if (CustomObjectArray[i] == object)
3256 return;
3257 }
3258
3259 CustomObjectArray.emplace_back(object);
3260}
3261
3262int SBS::GetConfigInt(const std::string &key, int default_value)
3263{
3264 std::string result = configfile->getSetting(key, "", ToString(default_value));
3265 return ToInt(result);
3266}
3267
3268std::string SBS::GetConfigString(const std::string &key, const std::string &default_value)
3269{
3270 return configfile->getSetting(key, "", default_value);
3271}
3272
3273bool SBS::GetConfigBool(const std::string &key, bool default_value)
3274{
3275 std::string result = configfile->getSetting(key, "", ToString(default_value));
3276 return ToBool(result);
3277}
3278
3279Real SBS::GetConfigFloat(const std::string &key, Real default_value)
3280{
3281 std::string result = configfile->getSetting(key, "", ToString(default_value));
3282 return ToFloat(result);
3283}
3284
3285bool SBS::InBox(const Vector3 &start, const Vector3 &end, const Vector3 &test)
3286{
3287 //determine if a point (test) is inside the box defines by start and end vertices
3288
3289 if (test.x > start.x && test.y > start.y && test.z > start.z && test.x < end.x && test.y < end.y && test.z < end.z)
3290 return true;
3291 return false;
3292}
3293
3295{
3296 //advance the clock
3297
3298 unsigned long last = current_time;
3299
3300 //get current time
3301 current_time = GetCurrentTime();
3302 if (last == 0)
3303 last = current_time;
3304
3305 if (current_time < last)
3306 elapsed_time = current_time + ((unsigned long)-1 - last) + 1;
3307 else
3308 elapsed_time = current_time - last;
3309 current_virtual_time += elapsed_time;
3310 frame_times.emplace_back(current_time);
3311 CalculateAverageTime();
3312}
3313
3314unsigned long SBS::GetCurrentTime()
3315{
3316 //get current time
3317 return timer->getMilliseconds();
3318}
3319
3320unsigned long SBS::GetRunTime()
3321{
3322 //returns simulator run time
3323 return current_virtual_time;
3324}
3325
3326unsigned long SBS::GetElapsedTime()
3327{
3328 //returns the actual elapsed time between frames
3329 return elapsed_time;
3330}
3331
3332unsigned long SBS::GetAverageTime()
3333{
3334 //returns the average elapsed time between frames
3335 return average_time;
3336}
3337
3339{
3340 //calculates the average frame processing time for a specified number of frames
3341
3342 if (frame_times.size() <= 1)
3343 return;
3344
3345 //SmoothFrames is the maximum number of milliseconds to hold timing info
3346
3347 //find oldest time to keep
3348 std::deque<unsigned long>::iterator it = frame_times.begin(), end = frame_times.end() - 2;
3349
3350 while (it != end)
3351 {
3352 if (frame_times.back() - *it > SmoothFrames)
3353 ++it;
3354 else
3355 break;
3356 }
3357
3358 //remove old times
3359 frame_times.erase(frame_times.begin(), it);
3360
3361 //calculate average time
3362 average_time = (frame_times.back() - frame_times.front()) / ((unsigned long)frame_times.size() - 1);
3363}
3364
3365std::string SBS::GetMountPath(std::string filename, std::string &newfilename)
3366{
3367 //get mountpoint (resource group) path of given file
3368 //if not found, return "General"
3369
3370 Ogre::StringVector list = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
3371 ReplaceAll(filename, "\\", "/");
3372 newfilename = filename;
3373
3374 for (size_t i = 0; i < list.size(); i++)
3375 {
3376 if (StartsWith(filename, list[i] + "/") == true)
3377 {
3378 newfilename = filename.substr(list[i].size() + 1);
3379 return list[i];
3380 }
3381 }
3382 return "General";
3383}
3384
3385void SBS::ShowColliders(bool value)
3386{
3387 try
3388 {
3389 if (mWorld)
3390 mWorld->setShowDebugShapes(value);
3391 camera->ShowDebugShape(value);
3392 }
3393 catch (Ogre::Exception &e)
3394 {
3395 ReportError("Error enabling/disabling collider shapes\n" + e.getDescription());
3396 }
3397}
3398
3399void SBS::CacheFilename(const std::string &filename, const std::string &result)
3400{
3401 //caches filename information for VerifyFile function
3402 VerifyResult verify;
3403 verify.filename = filename;
3404 verify.result = result;
3405 verify_results.emplace_back(verify);
3406}
3407
3408void SBS::SetLighting(Real red, Real green, Real blue)
3409{
3410 OldAmbientR = AmbientR;
3411 OldAmbientG = AmbientG;
3412 OldAmbientB = AmbientB;
3413 AmbientR = red;
3414 AmbientG = green;
3415 AmbientB = blue;
3416}
3417
3419{
3420 AmbientR = OldAmbientR;
3421 AmbientG = OldAmbientG;
3422 AmbientB = OldAmbientB;
3423}
3424
3425Control* SBS::AddControl(const std::string &name, const std::string &sound, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, int selection_position, std::vector<std::string> &action_names, std::vector<std::string> &textures)
3426{
3427 //add a control
3428 std::vector<Action*> actionnull; //not used
3429 Control* control = new Control(this, name, false, sound, action_names, actionnull, textures, direction, width, height, true, selection_position);
3430 control->SetPosition(CenterX, voffset, CenterZ);
3431 ControlArray.emplace_back(control);
3432 return control;
3433}
3434
3435Trigger* SBS::AddTrigger(const std::string &name, const std::string &sound_file, const Vector3 &area_min, const Vector3 &area_max, std::vector<std::string> &action_names)
3436{
3437 //add a trigger
3438 Trigger* trigger = new Trigger(this, name, false, sound_file, area_min, area_max, action_names);
3439 TriggerArray.emplace_back(trigger);
3440 return trigger;
3441}
3442
3443Action* SBS::AddAction(const std::string &name, std::vector<Object*> &action_parents, const std::string &command, const std::vector<std::string> &parameters)
3444{
3445 //add a global action
3446
3447 Action *action = new Action(this, name, action_parents, command, parameters);
3448 ActionArray.emplace_back(action);
3449 return action;
3450}
3451
3452Action* SBS::AddAction(const std::string &name, std::vector<Object*> &action_parents, const std::string &command)
3453{
3454 //add a global action
3455
3456 Action *action = new Action(this, name, action_parents, command);
3457 ActionArray.emplace_back(action);
3458 return action;
3459}
3460
3461std::vector<Action*> SBS::GetAction(std::string name)
3462{
3463 //get action by name
3464 ReplaceAll(name, " ", "");
3465
3466 //for an action that references an elevator's "Car 1", create
3467 //a second check with the "Car 1" part removed for compatibility
3468 std::string name2;
3469 size_t pos = name.find("Car1");
3470 if (name.substr(0, 8) == "Elevator" && pos != std::string::npos)
3471 name2 = name.substr(0, pos - 1) + name.substr(name.find(":", pos));
3472
3473 std::vector<Action*> actionlist;
3474 for (size_t i = 0; i < ActionArray.size(); i++)
3475 {
3476 std::string actionname = ActionArray[i]->GetName();
3477 ReplaceAll(actionname, " ", "");
3478 if (actionname == name || actionname == name2)
3479 actionlist.emplace_back(ActionArray[i]);
3480 }
3481 return actionlist;
3482}
3483
3485{
3486 //get number of registered actions
3487 return (int)ActionArray.size();
3488}
3489
3490bool SBS::AddActionParent(const std::string &name, std::vector<Object*> &parents)
3491{
3492 //add parent to actions specified by 'name'
3493
3494 bool result = false;
3495 std::vector<Action*> actionlist = GetAction(name);
3496
3497 for (size_t i = 0; i < actionlist.size(); i++)
3498 {
3499 Action *action = actionlist[i];
3500 for (size_t j = 0; j < parents.size(); j++)
3501 {
3502 if (action->AddParent(parents[j]))
3503 result = true;
3504 }
3505 }
3506 return result;
3507}
3508
3509bool SBS::RemoveActionParent(const std::string &name, std::vector<Object*> &parents)
3510{
3511 //remove parent object from actions specified by 'name'
3512
3513 bool result = false;
3514 std::vector<Action*> actionlist = GetAction(name);
3515
3516 for (size_t i = 0; i < actionlist.size(); i++)
3517 {
3518 Action *action = actionlist[i];
3519 for (size_t j = 0; j < parents.size(); j++)
3520 {
3521 if (action->RemoveParent(parents[j]))
3522 result = true;
3523 }
3524 }
3525 return result;
3526}
3527
3528bool SBS::RemoveActionParent(std::vector<Object*> &parents)
3529{
3530 //remove parent object from all action objects
3531
3532 bool result = false;
3533 for (size_t i = 0; i < ActionArray.size(); i++)
3534 {
3535 Action *action = ActionArray[i];
3536 for (size_t j = 0; j < parents.size(); j++)
3537 {
3538 if (action->RemoveParent(parents[j]))
3539 result = true;
3540 }
3541 }
3542 return result;
3543}
3544
3545bool SBS::RemoveAction(std::string name)
3546{
3547 //remove action by name
3548
3549 ReplaceAll(name, " ", "");
3550 bool result = false;
3551 for (size_t i = 0; i < ActionArray.size(); i++)
3552 {
3553 if (ActionArray[i])
3554 {
3555 std::string actionname = ActionArray[i]->GetName();
3556 ReplaceAll(actionname, " ", "");
3557 if (actionname == name)
3558 {
3559 delete ActionArray[i];
3560 ActionArray.erase(ActionArray.begin() + i);
3561 i--;
3562 result = true;
3563 }
3564 }
3565 }
3566 return result;
3567}
3568
3570{
3571 //remove action
3572
3573 if (!action)
3574 return false;
3575
3576 bool result = false;
3577 for (size_t i = 0; i < ActionArray.size(); i++)
3578 {
3579 if (ActionArray[i] == action)
3580 {
3581 delete ActionArray[i];
3582 ActionArray.erase(ActionArray.begin() + i);
3583 i--;
3584 result = true;
3585
3586 //remove reference to action in all control objects
3587 for (size_t j = 0; j < control_index.size(); j++)
3588 {
3589 control_index[j]->RemoveAction(action);
3590 }
3591 }
3592 }
3593 return result;
3594}
3595
3596Object* SBS::GetObject(std::string name, bool case_sensitive)
3597{
3598 //get object by name
3599
3600 ReplaceAll(name, " ", "");
3601
3602 //use hints to quickly find a reference
3603 {
3604 //floors
3605 bool found = false;
3606 std::string tmpname = "Floor";
3607 if (case_sensitive == false)
3608 {
3609 SetCase(name, false);
3610 SetCase(tmpname, false);
3611
3612 if (name.find("floor", 0) == 0)
3613 found = true;
3614 }
3615 else
3616 {
3617 if (name.find("Floor", 0) == 0)
3618 found = true;
3619 }
3620
3621 if (found == true && name.find(":", 0) == std::string::npos)
3622 {
3623 std::string number = name.substr(5);
3624 if (IsNumeric(number))
3625 {
3626 int floor = ToInt(number);
3627 return sbs->GetFloor(floor);
3628 }
3629 }
3630 }
3631 {
3632 //elevators
3633 bool found = false;
3634 std::string tmpname = "Elevator";
3635 if (case_sensitive == false)
3636 {
3637 SetCase(name, false);
3638 SetCase(tmpname, false);
3639
3640 if (name.find("elevator", 0) == 0)
3641 found = true;
3642 }
3643 else
3644 {
3645 if (name.find("Elevator", 0) == 0)
3646 found = true;
3647 }
3648
3649 if (found == true && name.find(":", 0) == std::string::npos)
3650 {
3651 std::string number = name.substr(8);
3652 if (IsNumeric(number))
3653 {
3654 int elevator = ToInt(number);
3655 return sbs->GetElevator(elevator);
3656 }
3657 }
3658 }
3659 {
3660 //shafts
3661 bool found = false;
3662 std::string tmpname = "Shaft";
3663 if (case_sensitive == false)
3664 {
3665 SetCase(name, false);
3666 SetCase(tmpname, false);
3667
3668 if (name.find("shaft", 0) == 0)
3669 found = true;
3670 }
3671 else
3672 {
3673 if (name.find("Shaft", 0) == 0)
3674 found = true;
3675 }
3676
3677 if (found == true && name.find(":", 0) == std::string::npos)
3678 {
3679 std::string number = name.substr(5);
3680 if (IsNumeric(number))
3681 {
3682 int shaft = ToInt(number);
3683 return sbs->GetShaft(shaft);
3684 }
3685 }
3686 }
3687 {
3688 //shafts
3689 bool found = false;
3690 std::string tmpname = "Stairwell";
3691 if (case_sensitive == false)
3692 {
3693 SetCase(name, false);
3694 SetCase(tmpname, false);
3695
3696 if (name.find("stairwell", 0) == 0)
3697 found = true;
3698 }
3699 else
3700 {
3701 if (name.find("Stairwell", 0) == 0)
3702 found = true;
3703 }
3704
3705 if (found == true && name.find(":", 0) == std::string::npos)
3706 {
3707 std::string number = name.substr(9);
3708 if (IsNumeric(number))
3709 {
3710 int stair = ToInt(number);
3711 return sbs->GetStairwell(stair);
3712 }
3713 }
3714 }
3715
3716 for (size_t i = 0; i < ObjectArray.size(); i++)
3717 {
3718 if (ObjectArray[i])
3719 {
3720 std::string tmpname = ObjectArray[i]->GetName();
3721 ReplaceAll(tmpname, " ", "");
3722 if (case_sensitive == false)
3723 SetCase(tmpname, false);
3724
3725 //get by object name
3726 if (tmpname == name)
3727 return ObjectArray[i];
3728
3729 if (ObjectArray[i]->GetParent())
3730 {
3731 std::string parent_name = ObjectArray[i]->GetParent()->GetName();
3732 ReplaceAll(parent_name, " ", "");
3733 if (case_sensitive == false)
3734 SetCase(parent_name, false);
3735
3736 //get by "parentname:objectname"
3737 if (name == parent_name + ":" + tmpname)
3738 return ObjectArray[i];
3739
3740 if (ObjectArray[i]->GetParent()->GetParent())
3741 {
3742 std::string grandparent_name = ObjectArray[i]->GetParent()->GetParent()->GetName();
3743 ReplaceAll(grandparent_name, " ", "");
3744 if (case_sensitive == false)
3745 SetCase(grandparent_name, false);
3746
3747 //get by "grandparentname:parentname:objectname"
3748 if (name == grandparent_name + ":" + parent_name + ":" + tmpname)
3749 return ObjectArray[i];
3750 }
3751 }
3752 }
3753 }
3754
3755 return 0;
3756}
3757
3758Object* SBS::GetObjectOfParent(std::string parent_name, std::string name, const std::string &type, bool case_sensitive)
3759{
3760 //get object by name
3761
3762 ReplaceAll(name, " ", "");
3763 ReplaceAll(parent_name, " ", "");
3764 if (case_sensitive == false)
3765 {
3766 SetCase(name, false);
3767 SetCase(parent_name, false);
3768 }
3769
3770 for (size_t i = 0; i < ObjectArray.size(); i++)
3771 {
3772 Object *object = ObjectArray[i];
3773
3774 if (object)
3775 {
3776 if (object->GetType() != type)
3777 continue;
3778
3779 Object* parent = ObjectArray[i]->GetParent();
3780
3781 if (parent)
3782 {
3783 std::string namecheck = parent->GetName();
3784 ReplaceAll(namecheck, " ", "");
3785 if (case_sensitive == false)
3786 SetCase(namecheck, false);
3787
3788 if (namecheck == parent_name) //check object for match if parent matches
3789 {
3790 std::string tmpname = object->GetName();
3791 ReplaceAll(tmpname, " ", "");
3792 if (case_sensitive == false)
3793 SetCase(tmpname, false);
3794
3795 //get by object name
3796 if (tmpname == name)
3797 return object;
3798 }
3799 }
3800 }
3801 }
3802
3803 return 0;
3804}
3805
3806std::vector<Object*> SBS::GetObjectRange(const std::string &expression)
3807{
3808 //get object by name range expression (ex. "Floors 1 to 3")
3809
3810 std::vector<Object*> objects;
3811 size_t temp = expression.find("to", 0);
3812
3813 //the name 'elevator' matches the previous search - in this case, detect it and undo
3814 size_t temp2 = expression.find("tor", 0);
3815 if (temp == temp2)
3816 temp = 0;
3817
3818 std::string type;
3819
3820 if (temp > 0 && temp != std::string::npos)
3821 {
3822 if (expression.substr(0, 6) == "Floors")
3823 type = "floor";
3824 else if (expression.substr(0, 9) == "Elevators")
3825 type = "elevator";
3826 else if (expression.substr(0, 6) == "Shafts")
3827 type = "shaft";
3828 else if (expression.substr(0, 10) == "Stairwells")
3829 type = "stairwell";
3830 else
3831 {
3832 ReportError("GetObjectRange: Invalid object type");
3833 return objects;
3834 }
3835
3836 std::string str1 = expression.substr(type.size() + 1, temp - (type.size() + 1));
3837 std::string str2 = expression.substr(temp + 2, expression.length() - (temp + 2));
3838 TrimString(str1);
3839 TrimString(str2);
3840 int RangeL = 0, RangeH = 0;
3841 if (!IsNumeric(str1, RangeL) || !IsNumeric(str2, RangeH))
3842 {
3843 ReportError("GetObjectRange: Invalid range");
3844 return objects;
3845 }
3846
3847 for (size_t i = 0; i < ObjectArray.size(); i++)
3848 {
3849 if (ObjectArray[i])
3850 {
3851 std::string tmpname = ObjectArray[i]->GetName();
3852 for (int j = RangeL; j <= RangeH; j++)
3853 {
3854 std::string number = ToString(j);
3855 if (type == "floor")
3856 {
3857 if (tmpname == "Floor " + number)
3858 objects.emplace_back(ObjectArray[i]);
3859 }
3860 if (type == "elevator")
3861 {
3862 if (tmpname == "Elevator " + number)
3863 objects.emplace_back(ObjectArray[i]);
3864 }
3865 if (type == "shaft")
3866 {
3867 if (tmpname == "Shaft " + number)
3868 objects.emplace_back(ObjectArray[i]);
3869 }
3870 if (type == "stairwell")
3871 {
3872 if (tmpname == "Stairwell " + number)
3873 objects.emplace_back(ObjectArray[i]);
3874 }
3875 }
3876 }
3877 }
3878 }
3879 else
3880 {
3881 //return single result
3882 Object *obj = GetObject(expression);
3883 if (obj)
3884 objects.emplace_back(obj);
3885 }
3886
3887 return objects;
3888}
3889
3891{
3892 if (index >= 0 && index < (int)ActionArray.size())
3893 return ActionArray[index];
3894 return 0;
3895}
3896
3897bool SBS::RunAction(const std::string &name)
3898{
3899 //run action by name - will run multiple actions if the name is the same
3900
3901 std::vector<Action*> actionlist = GetAction(name);
3902
3903 bool result = true;
3904 for (size_t i = 0; i < actionlist.size(); i++)
3905 {
3906 bool result2 = false;
3907 bool hold = false; //not used
3908
3909 if (actionlist[i])
3910 result2 = actionlist[i]->DoAction(this, hold);
3911
3912 if (result2 == false)
3913 result = false;
3914 }
3915 return result;
3916}
3917
3918bool SBS::RunAction(int index)
3919{
3920 //run action by index number
3921
3922 Action *action = GetAction(index);
3923 bool hold = false; //not used
3924 if (action)
3925 return action->DoAction(this, hold);
3926 return false;
3927}
3928
3929void SBS::AddKey(int keyid, const std::string &name)
3930{
3931 //adds key 'keyid' to the user's keyring
3932 Key key;
3933 key.id = keyid;
3934 key.name = name;
3935 keys.emplace_back(key);
3936
3937 Report("Added key " + ToString(keyid) + " (" + name + ") to keyring");
3938}
3939
3940bool SBS::CheckKey(int keyid)
3941{
3942 //checks to see if the user has the specified key
3943
3944 for (size_t i = 0; i < keys.size(); i++)
3945 {
3946 if (keys[i].id == keyid)
3947 return true;
3948 }
3949 return false;
3950}
3951
3953{
3954 //list all keys
3955
3956 Report("\n--- Keys ---\n");
3957
3958 for (size_t i = 0; i < keys.size(); i++)
3959 {
3960 std::string id = ToString(keys[i].id);
3961 Report(id + " - " + keys[i].name);
3962 }
3963 Report("");
3964}
3965
3967{
3968 //add control to index
3969 control_index.emplace_back(control);
3970}
3971
3973{
3974 //remove control from index
3975
3976 for (size_t i = 0; i < control_index.size(); i++)
3977 {
3978 if (control_index[i] == control)
3979 {
3980 control_index.erase(control_index.begin() + i);
3981 return;
3982 }
3983 }
3984}
3985
3987{
3988 //show floor information for all floors
3989
3990 bool header_shown = false;
3991 for (int i = -Basements; i < Floors; i++)
3992 {
3993 Floor *floor = GetFloor(i);
3994 if (floor)
3995 {
3996 if (header_shown == false)
3997 {
3998 floor->ShowInfo(false, true);
3999 header_shown = true;
4000 }
4001 else
4002 floor->ShowInfo(false, false);
4003 }
4004 }
4005 Report("");
4006}
4007
4008void SBS::ShowSceneNodes(bool value)
4009{
4010 //show all scene nodes for debugging
4011
4012 mSceneManager->setDisplaySceneNodes(value);
4013}
4014
4016{
4017 //show all mesh bounding boxes for debugging
4018
4019 mSceneManager->showBoundingBoxes(value);
4020}
4021
4023{
4024 //list all meshes visible by the main camera
4025
4026 Report("\n--- Visible Dynamic Meshes ---");
4027 Report("Name\t-\tSubmeshes\n");
4028 int count = 0;
4029 int submeshes = 0;
4030 int total = 0;
4031
4032 for (size_t i = 0; i < dynamic_meshes.size(); i++)
4033 {
4034 for (int j = 0; j < dynamic_meshes[i]->GetMeshCount(); j++)
4035 {
4036 if (camera->IsDynamicMeshVisible(dynamic_meshes[i], j) == true)
4037 {
4038 submeshes = dynamic_meshes[i]->GetSubMeshCount(j);
4039 Report(dynamic_meshes[i]->GetMeshName(j) + "\t-\t" + ToString(submeshes));
4040 count++;
4041 total += submeshes;
4042 }
4043 }
4044 }
4045 Report("Total: " + ToString(count) + " meshes, " + ToString(total) + " submeshes");
4046 Report("");
4047}
4048
4050{
4051 //return total number of escalators
4052 return (int)EscalatorArray.size();
4053}
4054
4056{
4057 //return total number of allocated sounds
4058 return (int)MovingWalkwayArray.size();
4059}
4060
4061bool SBS::HitBeam(const Ray &ray, Real max_distance, MeshObject *&mesh, Wall *&wall, Vector3 &hit_position)
4062{
4063 //use a given ray and distance, and return the nearest hit mesh and if applicable, wall object
4064 //note that the ray's origin and direction need to be in engine-relative values
4065
4066 //create a new ray that has absolute positioning, for engine offsets
4067 Ray ray2 (ToRemote(ToGlobal(ToLocal(ray.getOrigin()))), GetOrientation() * ray.getDirection());
4068
4069 //get a collision callback from Bullet
4070 OgreBulletCollisions::CollisionClosestRayResultCallback callback (ray2, mWorld, max_distance);
4071
4072 //check for collision
4073 mWorld->launchRay(callback);
4074
4075 //exit if no collision
4076 if (callback.doesCollide() == false)
4077 return false;
4078
4079 //get collided collision object
4080 OgreBulletCollisions::Object* object = callback.getCollidedObject();
4081
4082 if (!object)
4083 return false;
4084
4085 //get name of collision object's grandparent scenenode (which is the same name as the mesh object)
4086 std::string meshname;
4087 if (dynamic_cast<OgreBulletDynamics::WheeledRigidBody*>(object) == 0)
4088 meshname = object->getRootNode()->getParentSceneNode()->getName();
4089 else
4090 meshname = object->getRootNode()->getChild(0)->getName(); //for vehicles, the child of the root node is the mesh
4091
4092 //get hit/intersection position
4093 hit_position = ToLocal(callback.getCollisionPoint());
4094
4095 //get associated mesh object
4096 mesh = FindMeshObject(meshname);
4097 if (!mesh)
4098 return false;
4099
4100 //get wall object, if any
4101 Vector3 isect;
4102 Real distance = 2000000000.;
4103 Vector3 normal = Vector3::ZERO;
4104 wall = mesh->GetPolyMesh()->FindWallIntersect(ray.getOrigin(), ray.getPoint(max_distance), isect, distance, normal);
4105
4106 return true;
4107}
4108
4110{
4111 //enable random activity, by creating random people
4112
4113 if (value == true)
4114 {
4115 //create regular people
4116 int people = GetConfigInt("Skyscraper.SBS.Person.RandomPeople", 0);
4117 people = people == 0 ? GetTotalFloors() : people;
4118 for (int i = 0; i < people; i++)
4119 {
4120 Person *person = CreatePerson("Random " + ToString(i + 1), Lobby, false);
4121
4122 //enable random activity on the person
4123 person->EnableRandomActivity(true);
4124 }
4125
4126 //create a service person
4127 Person *person = CreatePerson("Random " + ToString(people + 1), Lobby, true);
4128
4129 //enable random activity on the person
4130 person->EnableRandomActivity(true);
4131 }
4132 else if (value == false)
4133 {
4134 for (size_t i = 0; i < PersonArray.size(); i++)
4135 {
4136 if (PersonArray[i]->IsRandomActivityEnabled() == true)
4137 {
4138 Person *person = PersonArray[i];
4139 delete person;
4140 i--;
4141 }
4142 }
4143 }
4144
4145 RandomActivity = value;
4146}
4147
4149{
4150 //enable malfunctions
4151
4152 for (int i = 1; i <= elevator_manager->GetCount(); i++)
4153 {
4154 Elevator *elevator = elevator_manager->Get(i);
4155 if (elevator)
4156 {
4157 elevator->EnableMalfunctions(value);
4158 }
4159 }
4160
4161 for (size_t i = 0; i < EscalatorArray.size(); i++)
4162 {
4163 Escalator *escalator = EscalatorArray[i];
4164 if (escalator)
4165 {
4166 escalator->EnableMalfunctions(value);
4167 }
4168 }
4169
4170 Malfunctions = value;
4171}
4172
4173bool SBS::IsObjectValid(Object *object, std::string type)
4174{
4175 //test if an object is valid
4176
4177 if (type == "Floor")
4178 {
4179 for (int i = 0; i < floor_manager->GetCount(); i++)
4180 {
4181 if (floor_manager->GetIndex(i) == static_cast<Floor*>(object))
4182 return true;
4183 }
4184 }
4185 else if (type == "Elevator")
4186 {
4187 for (int i = 0; i < elevator_manager->GetCount(); i++)
4188 {
4189 if (elevator_manager->GetIndex(i) == static_cast<Elevator*>(object))
4190 return true;
4191 }
4192 }
4193 else if (type == "Shaft")
4194 {
4195 for (int i = 0; i < shaft_manager->GetCount(); i++)
4196 {
4197 if (shaft_manager->GetIndex(i) == static_cast<Shaft*>(object))
4198 return true;
4199 }
4200 }
4201 else if (type == "Stairwell")
4202 {
4203 for (int i = 0; i < stairwell_manager->GetCount(); i++)
4204 {
4205 if (stairwell_manager->GetIndex(i) == static_cast<Stairwell*>(object))
4206 return true;
4207 }
4208 }
4209 else if (type == "Mesh")
4210 {
4211 for (size_t i = 0; i < meshes.size(); i++)
4212 {
4213 if (meshes[i] == static_cast<MeshObject*>(object))
4214 return true;
4215 }
4216 }
4217 else if (type == "Control")
4218 {
4219 for (size_t i = 0; i < control_index.size(); i++)
4220 {
4221 if (control_index[i] == static_cast<Control*>(object))
4222 return true;
4223 }
4224 }
4225
4226 //do a slow full scan of the object array for all other objects
4227 for (size_t i = 0; i < ObjectArray.size(); i++)
4228 {
4229 if (ObjectArray[i] == object)
4230 return true;
4231 }
4232 return false;
4233}
4234
4236{
4237 //test if an action is valid
4238
4239 for (size_t i = 0; i < ActionArray.size(); i++)
4240 {
4241 if (ActionArray[i] == action)
4242 return true;
4243 }
4244 return false;
4245}
4246
4247Person* SBS::CreatePerson(std::string name, int floor, bool service_access)
4248{
4249 //create a person
4250
4251 if (name == "")
4252 {
4253 int number = GetPersonCount() + 1;
4254 name = "Person " + ToString(number);
4255 }
4256 Person *person = new Person(this, name, floor, service_access);
4257 PersonArray.emplace_back(person);
4258 return person;
4259}
4260
4262{
4263 //remove a person (does not delete the object)
4264
4265 for (size_t i = 0; i < PersonArray.size(); i++)
4266 {
4267 if (PersonArray[i] == person)
4268 {
4269 PersonArray.erase(PersonArray.begin() + i);
4270 return;
4271 }
4272 }
4273}
4274
4275bool SBS::AttachCamera(std::vector<Ogre::Camera*> &cameras, bool init_state)
4276{
4277 if (cameras.size() > 0)
4278 return camera->Attach(cameras, init_state);
4279 return false;
4280}
4281
4283{
4284 return camera->Detach();
4285}
4286
4287std::string SBS::ProcessFullName(std::string name, int &instance, int &object_number, bool strip_number)
4288{
4289 //if given a full object ID name (such as "0:(4)Landscape"),
4290 //return base name and parse out instance number and object number
4291
4292 //if strip_number is false, leave object number identifier in string
4293
4294 //get and strip off engine instance number
4295 size_t index = name.find(":(");
4296 instance = ToInt(name.substr(0, index));
4297 name.erase(name.begin(), name.begin() + index + 1);
4298
4299 //get and optionally strip off object number
4300 index = name.find(")");
4301 object_number = ToInt(name.substr(1, index - 1));
4302
4303 if (strip_number == true)
4304 name.erase(name.begin(), name.begin() + index + 1);
4305
4306 return name;
4307}
4308
4310{
4311 if (number < 0 || number > (int)PersonArray.size() - 1)
4312 return 0;
4313
4314 return PersonArray[number];
4315}
4316
4318{
4319 //return true if the user is inside the sim engine's area
4320
4321 if (area_trigger)
4322 return area_trigger->IsInside();
4323
4324 //if no trigger is defined, user is always inside the area
4325 return true;
4326}
4327
4328bool SBS::IsInside(const Vector3 &position)
4329{
4330 //return true if the specified position is inside the sim engine's area
4331
4332 if (area_trigger)
4333 return area_trigger->IsInside(position);
4334
4335 //if no trigger is defined, position is always inside the area
4336 return true;
4337}
4338
4340{
4341 if (area_trigger)
4342 {
4343 min = area_trigger->GetMin();
4344 max = area_trigger->GetMax();
4345 return true;
4346 }
4347
4348 min = Vector3::ZERO;
4349 max = Vector3::ZERO;
4350 return false;
4351}
4352
4353void SBS::CutOutsideBoundaries(bool landscape, bool buildings, bool external, bool floors)
4354{
4355 //cut landscape and buildings for engine bounds if needed
4356 //run this function before calling Start()
4357
4358 if (!area_trigger)
4359 return;
4360
4361 Report("Cutting outside boundaries...");
4362 Vector3 min = area_trigger->GetMin();
4363 Vector3 max = area_trigger->GetMax();
4364
4365 if (landscape == true)
4366 Landscape->CutOutsideBounds(min, max, true, true);
4367 if (buildings == true)
4368 Buildings->CutOutsideBounds(min, max, true, true);
4369 if (external == true && External)
4370 External->CutOutsideBounds(min, max, true, true);
4371
4372 if (floors == true)
4373 {
4374 for (int i = 0; i < floor_manager->GetCount(); i++)
4375 floor_manager->GetIndex(i)->Level->CutOutsideBounds(min, max, true, true);
4376 }
4377}
4378
4379void SBS::CutInsideBoundaries(const Vector3 &min, const Vector3 &max, bool landscape, bool buildings, bool external, bool floors)
4380{
4381 //cut landscape and buildings for specified bounds
4382 //run this function before calling Start()
4383
4384 if (landscape == true)
4385 Landscape->Cut(min, max, true, true);
4386 if (buildings == true)
4387 Buildings->Cut(min, max, true, true);
4388 if (external == true && External)
4389 External->Cut(min, max, true, true);
4390
4391 if (floors == true)
4392 {
4393 for (int i = 0; i < floor_manager->GetCount(); i++)
4394 floor_manager->GetIndex(i)->Level->Cut(min, max, true, true);
4395 }
4396}
4397
4398void SBS::SetBounds(const Vector3 &area_min, const Vector3 &area_max)
4399{
4400 //don't set bounds if the primary engine
4401 if (InstanceNumber == 0)
4402 return;
4403
4404 if (area_min != Vector3::ZERO && area_max != Vector3::ZERO && !area_trigger)
4405 {
4406 std::vector<std::string> names;
4407 names.emplace_back("Off");
4408 area_trigger = new Trigger(this, "System Boundary", true, "", area_min, area_max, names);
4409 }
4410}
4411
4413{
4414 //reset building to original state
4415
4416 //turn on main objects
4417 EnableBuildings(true);
4418 EnableLandscape(true);
4419 EnableExternal(true);
4420 EnableSkybox(true);
4421
4422 //turn off interior objects
4423 floor_manager->EnableAll(false);
4424 shaft_manager->EnableAll(false);
4425 stairwell_manager->EnableAll(false);
4426 elevator_manager->EnableAll(false);
4427
4428 //turn off reverbs
4429 for (size_t i = 0; i < reverbs.size(); i++)
4430 {
4431 if (reverbs[i])
4432 reverbs[i]->Enabled(false);
4433 }
4434
4435 //reset camera state
4436 camera->ResetState();
4437}
4438
4440{
4441 //convert an engine-relative position to a global (scene) position
4442
4443 return (GetOrientation().Inverse() * position) + GetPosition();
4444}
4445
4447{
4448 //convert a global (scene) position to an engine-relative position
4449
4450 return (GetOrientation() * (position - GetPosition()));
4451}
4452
4454{
4455 //convert an engine-relative orientation (rotation) to a global (scene) orientation
4456
4457 return (GetOrientation() * orientation);
4458}
4459
4461{
4462 //convert a global (scene) orientation (rotation) to an engine-relative orientation
4463
4464 return (GetOrientation().Inverse() * orientation);
4465}
4466
4467Light* SBS::GetLight(std::string name)
4468{
4469 //get a light by name
4470
4471 SetCase(name, false);
4472
4473 for (size_t i = 0; i < lights.size(); i++)
4474 {
4475 if (SetCaseCopy(lights[i]->GetName(), false) == name)
4476 return lights[i];
4477 }
4478
4479 return 0;
4480}
4481
4482Model* SBS::GetModel(std::string name)
4483{
4484 //get a model by name
4485
4486 SetCase(name, false);
4487
4488 for (size_t i = 0; i < ModelArray.size(); i++)
4489 {
4490 if (SetCaseCopy(ModelArray[i]->GetName(), false) == name)
4491 return ModelArray[i];
4492 }
4493
4494 return 0;
4495}
4496
4498{
4499 //get a primitive by name
4500
4501 SetCase(name, false);
4502
4503 for (size_t i = 0; i < PrimArray.size(); i++)
4504 {
4505 if (SetCaseCopy(PrimArray[i]->GetName(), false) == name)
4506 return PrimArray[i];
4507 }
4508
4509 return 0;
4510}
4511
4513{
4514 //get a custom object by name
4515
4516 SetCase(name, false);
4517
4518 for (size_t i = 0; i < CustomObjectArray.size(); i++)
4519 {
4520 if (SetCaseCopy(CustomObjectArray[i]->GetName(), false) == name)
4521 return CustomObjectArray[i];
4522 }
4523
4524 return 0;
4525}
4526
4528{
4529 //register a dynamic mesh with the system
4530
4531 dynamic_meshes.emplace_back(dynmesh);
4532}
4533
4535{
4536 //unregister a dynamic mesh from the system
4537
4538 for (size_t i = 0; i < dynamic_meshes.size(); i++)
4539 {
4540 if (dynamic_meshes[i] == dynmesh)
4541 {
4542 dynamic_meshes.erase(dynamic_meshes.begin() + i);
4543 return;
4544 }
4545 }
4546}
4547
4549{
4550 return soundsystem;
4551}
4552
4554{
4555 return (int)PersonArray.size();
4556}
4557
4559{
4560 return (area_trigger != 0);
4561}
4562
4564{
4565 return floor_manager;
4566}
4567
4569{
4570 return elevator_manager;
4571}
4572
4574{
4575 return shaft_manager;
4576}
4577
4579{
4580 return stairwell_manager;
4581}
4582
4584{
4585 return door_manager;
4586}
4587
4589{
4590 return texturemanager;
4591}
4592
4594{
4595 return revolvingdoor_manager;
4596}
4597
4599{
4600 return vehicle_manager;
4601}
4602
4604{
4605 return controller_manager;
4606}
4607
4609{
4610 //register a camera texture
4611
4612 camtexarray.emplace_back(camtex);
4613}
4614
4616{
4617 //unregister a camera texture
4618
4619 for (size_t i = 0; i < camtexarray.size(); i++)
4620 {
4621 if (camtexarray[i] == camtex)
4622 {
4623 camtexarray.erase(camtexarray.begin() + i);
4624 return;
4625 }
4626 }
4627}
4628
4630{
4631 return (int)camtexarray.size();
4632}
4633
4635{
4636 if (number < camtexarray.size())
4637 return camtexarray[number];
4638 return 0;
4639}
4640
4642{
4643 return utility;
4644}
4645
4647{
4648 return geometry;
4649}
4650
4652{
4653 //print a memory report
4654 Report("");
4655 Report("--- Memory Report ---");
4656
4657 size_t total = 0;
4658 for (size_t i = 0; i < meshes.size(); i++)
4659 total += meshes[i]->GetSize();
4660
4661 //texture memory
4662 Report("Textures: " + ToString(texturemanager->GetMemoryUsage() / 1024) + " kb");
4663
4664 //mesh memory
4665 Report("Meshes: " + ToString(total / 1024) + " kb");
4666
4667 Report("");
4668}
4669
4671{
4672 //add escalator to index
4673 EscalatorArray.emplace_back(escalator);
4674}
4675
4677{
4678 //remove escalator from index
4679
4680 for (size_t i = 0; i < EscalatorArray.size(); i++)
4681 {
4682 if (EscalatorArray[i] == escalator)
4683 {
4684 EscalatorArray.erase(EscalatorArray.begin() + i);
4685 return;
4686 }
4687 }
4688}
4689
4691{
4692 if (index >= 0 && index < EscalatorArray.size())
4693 return EscalatorArray[index];
4694 return 0;
4695}
4696
4698{
4699 //add moving walkway to index
4700 MovingWalkwayArray.emplace_back(walkway);
4701}
4702
4704{
4705 //remove moving walkway from index
4706
4707 for (size_t i = 0; i < MovingWalkwayArray.size(); i++)
4708 {
4709 if (MovingWalkwayArray[i] == walkway)
4710 {
4711 MovingWalkwayArray.erase(MovingWalkwayArray.begin() + i);
4712 return;
4713 }
4714 }
4715}
4716
4718{
4719 if (index >= 0 && index < MovingWalkwayArray.size())
4720 return MovingWalkwayArray[index];
4721 return 0;
4722}
4723
4724void SBS::SetPower(bool value)
4725{
4726 //set building power state
4727
4728 power_state = value;
4729}
4730
4732{
4733 //return building power state
4734
4735 return power_state;
4736}
4737
4739{
4740 return (int)reverbs.size();
4741}
4742
4744{
4745 if (index >= 0 && index < (int)reverbs.size())
4746 return reverbs[index];
4747 return 0;
4748}
4749
4750void SBS::EnableMap(bool value)
4751{
4752 //enable or disable map generator
4753 if (MapGenerator)
4754 MapGenerator->Enabled(value);
4755}
4756
4758{
4759 if (GetTextureManager())
4760 return GetTextureManager()->GetMaterialCount();
4761
4762 return 0;
4763}
4764
4766{
4767 return area_trigger;
4768}
4769
4771{
4772 //return the center point of this sim engine, based on the bounds
4773
4774 if (HasBounds() == false)
4775 return Vector3(0, 0, 0);
4776
4777 return area_trigger->GetBounds().getCenter();
4778}
4779
4780}
bool AddParent(Object *parent)
Definition action.cpp:1069
bool RemoveParent(Object *parent)
Definition action.cpp:1084
bool DoAction(Object *caller, bool &hold)
Definition action.cpp:87
Elevator * GetElevator()
void EnableMalfunctions(bool value)
int AssignedShaft
Definition elevator.h:56
void EnableMalfunctions(bool value)
int EnabledGroup_Floor
Definition floor.h:52
bool IsEnabled()
Definition floor.cpp:573
void ShowInfo(bool detailed=true, bool display_header=true)
Definition floor.cpp:1662
int Number
Definition floor.h:36
bool EnabledGroup
Definition floor.h:51
void EnableGroup(bool value)
Definition floor.cpp:712
void Enabled(bool value)
Definition floor.cpp:378
Definition map.h:30
PolyMesh * GetPolyMesh()
Definition mesh.cpp:674
Wall * CreateWallObject(const std::string &name)
Definition mesh.cpp:208
bool load_error
Definition model.h:32
const std::string & GetName()
Definition object.cpp:53
Object * GetParent()
Definition object.cpp:42
bool IsPermanent()
Definition object.cpp:166
virtual Vector3 GetPosition(bool relative=false)
Definition object.cpp:307
int GetNumber()
Definition object.cpp:183
virtual void Enabled(bool value)
Definition object.h:108
virtual void Loop()
Definition object.h:105
const std::string & GetType()
Definition object.cpp:177
virtual void SetPosition(const Vector3 &position, bool relative=false, bool force=false)
Definition object.cpp:280
void EnableRandomActivity(bool value)
Definition person.cpp:101
Wall * FindWallIntersect(const Vector3 &start, const Vector3 &end, Vector3 &isect, Real &distance, Vector3 &normal, Wall *wall=0)
Definition polymesh.cpp:44
static void Stop_Profile(void)
Definition profiler.cpp:245
static void Start_Profile(const char *name)
Definition profiler.cpp:229
std::string ProcessFullName(std::string name, int &instance, int &object_number, bool strip_number=false)
Definition sbs.cpp:4287
Action * AddAction(const std::string &name, std::vector< Object * > &action_parents, const std::string &command, const std::vector< std::string > &parameters)
Definition sbs.cpp:3443
void AddPolygon(Wall *wallobject, const std::string &texture, PolyArray &varray, Real tw, Real th, bool report=true)
Definition sbs.cpp:1404
void RemoveReverb(Reverb *reverb)
Definition sbs.cpp:2846
Escalator * GetEscalator(int index)
Definition sbs.cpp:4690
Shaft * GetShaft(int number)
Definition sbs.cpp:1783
void UnregisterEscalator(Escalator *escalator)
Definition sbs.cpp:4676
Elevator * GetElevator(int number)
Definition sbs.cpp:1776
bool GetPower()
Definition sbs.cpp:4731
void DeleteMeshHandle(MeshObject *handle)
Definition sbs.cpp:3162
Trigger * GetAreaTrigger()
Definition sbs.cpp:4765
void EnableBuildings(bool value)
Definition sbs.cpp:1518
bool AddWallMain(Wall *wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height_in1, Real height_in2, Real altitude1, Real altitude2, Real tw, Real th, bool autosize, bool report=true)
Definition sbs.cpp:690
FloorManager * GetFloorManager()
Definition sbs.cpp:4563
bool HitBeam(const Ray &ray, Real max_distance, MeshObject *&mesh, Wall *&wall, Vector3 &hit_position)
Definition sbs.cpp:4061
Reverb * AddReverb(const std::string &name, const std::string &type, const Vector3 &position, Real min_distance, Real max_distance)
Definition sbs.cpp:2354
void Initialize()
Definition sbs.cpp:221
VehicleManager * GetVehicleManager()
Definition sbs.cpp:4598
void EnableMap(bool value)
Definition sbs.cpp:4750
void UnregisterCameraTexture(CameraTexture *camtex)
Definition sbs.cpp:4615
int GetFloorOrientation()
Definition sbs.cpp:1858
std::string GetConfigString(const std::string &key, const std::string &default_value)
Definition sbs.cpp:3268
void RemoveElevator(Elevator *elevator)
Definition sbs.cpp:2810
void RemoveControl(Control *control)
Definition sbs.cpp:2913
void AddMeshHandle(MeshObject *handle)
Definition sbs.cpp:3157
Vector3 ToGlobal(const Vector3 &position)
Definition sbs.cpp:4439
void ListVisibleMeshes()
Definition sbs.cpp:4022
int GetTotalFloors()
Definition sbs.cpp:1745
MeshObject * FindMeshObject(const std::string &name)
Definition sbs.cpp:3174
void RegisterDynamicMesh(DynamicMesh *dynmesh)
Definition sbs.cpp:4527
Light * GetLight(std::string name)
Definition sbs.cpp:4467
void RegisterMovingWalkway(MovingWalkway *walkway)
Definition sbs.cpp:4697
void RemoveSound(Sound *sound)
Definition sbs.cpp:2831
int GetVehicleCount()
Definition sbs.cpp:1739
void RemoveShaft(Shaft *shaft)
Definition sbs.cpp:2817
bool AttachCamera(std::vector< Ogre::Camera * > &cameras, bool init_state=true)
Definition sbs.cpp:4275
CameraTexture * GetCameraTexture(int number)
Definition sbs.cpp:4634
Real GetConfigFloat(const std::string &key, Real default_value)
Definition sbs.cpp:3279
unsigned long GetAverageTime()
Definition sbs.cpp:3332
void IncrementReverbCount()
Definition sbs.cpp:2387
StairwellManager * GetStairwellManager()
Definition sbs.cpp:4578
bool Mount(const std::string &filename, const std::string &path)
Definition sbs.cpp:2204
Shaft * CreateShaft(int number, Real CenterX, Real CenterZ, int startfloor, int endfloor)
Definition sbs.cpp:1691
DoorManager * GetDoorManager()
Definition sbs.cpp:4583
bool RemoveActionParent(const std::string &name, std::vector< Object * > &parents)
Definition sbs.cpp:3509
void IncrementSoundCount()
Definition sbs.cpp:2344
std::string GetFilesystemPath(std::string filename)
Definition sbs.cpp:3045
int GetTimerCallbackCount()
Definition sbs.cpp:2198
DispatchController * GetController(int number)
Definition sbs.cpp:1804
void CutOutsideBoundaries(bool landscape=true, bool buildings=true, bool external=false, bool floors=false)
Definition sbs.cpp:4353
Sound * AddSound(const std::string &name, const std::string &filename, const Vector3 &position, bool loop=true, Real volume=1.0, int speed=100, Real min_distance=1.0, Real max_distance=-1.0, Real doppler_level=0.0, Real cone_inside_angle=360, Real cone_outside_angle=360, Real cone_outside_volume=1.0, const Vector3 &direction=Vector3(0, 0, 0))
Definition sbs.cpp:2295
CustomObject * GetCustomObject(std::string name)
Definition sbs.cpp:4512
void CreateSky()
Definition sbs.cpp:1553
void AddFloorAutoArea(Vector3 start, Vector3 end)
Definition sbs.cpp:2223
void RegisterCameraTexture(CameraTexture *camtex)
Definition sbs.cpp:4608
std::string GetMountPath(std::string filename, std::string &newfilename)
Definition sbs.cpp:3365
bool FileExists(const std::string &filename)
Definition sbs.cpp:3085
int GetWallOrientation()
Definition sbs.cpp:1832
void RemovePerson(Person *person)
Definition sbs.cpp:4261
void RemoveLight(Light *light)
Definition sbs.cpp:2861
void RegisterEscalator(Escalator *escalator)
Definition sbs.cpp:4670
Vector3 GetCenter()
Definition sbs.cpp:4770
void RemoveStairwell(Stairwell *stairs)
Definition sbs.cpp:2824
int GetReverbCount()
Definition sbs.cpp:4738
Wall * AddFloor(MeshObject *mesh, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real altitude1, Real altitude2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool legacy_behavior=false)
Definition sbs.cpp:1942
unsigned long GetElapsedTime()
Definition sbs.cpp:3326
DispatchController * NewController(int number)
Definition sbs.cpp:1726
bool IsObjectValid(Object *object, std::string type="")
Definition sbs.cpp:4173
void DecrementReverbCount()
Definition sbs.cpp:2392
void ListKeys()
Definition sbs.cpp:3952
void AdvanceClock()
Definition sbs.cpp:3294
int GetElevatorCount()
Definition sbs.cpp:1733
int GetControllerCount()
Definition sbs.cpp:1763
Real MetersToFeet(Real meters)
Definition sbs.cpp:1917
bool AddFloorMain(Wall *wallobject, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real altitude1, Real altitude2, bool reverse_axis, bool texture_direction, Real tw, Real th, bool autosize, bool legacy_behavior=false, bool report=true)
Definition sbs.cpp:927
void ResetWalls(bool ToDefaults=false)
Definition sbs.cpp:1884
void CacheFilename(const std::string &filename, const std::string &result)
Definition sbs.cpp:3399
void EnableMalfunctions(bool value)
Definition sbs.cpp:4148
void ShowBoundingBoxes(bool value)
Definition sbs.cpp:4015
bool IsValidFloor(int floor)
Definition sbs.cpp:2522
Model * GetModel(std::string name)
Definition sbs.cpp:4482
Floor * GetFloor(int number)
Definition sbs.cpp:1769
SBS(Ogre::SceneManager *mSceneManager, FMOD::System *fmodsystem, int instance_number, const Vector3 &position=Vector3::ZERO, Real rotation=0.0f, const Vector3 &area_min=Vector3::ZERO, const Vector3 &area_max=Vector3::ZERO)
Definition sbs.cpp:73
Utility * GetUtility()
Definition sbs.cpp:4641
Vehicle * NewVehicle(int number)
Definition sbs.cpp:1719
MovingWalkway * GetMovingWalkway(int index)
Definition sbs.cpp:4717
void CheckAutoAreas()
Definition sbs.cpp:2235
bool RunAction(const std::string &name)
Definition sbs.cpp:3897
Stairwell * GetStairwell(int number)
Definition sbs.cpp:1790
TextureManager * GetTextureManager()
Definition sbs.cpp:4588
bool MoveObject(Object *object, Vector3 position, bool relative, bool X, bool Y, bool Z)
Definition sbs.cpp:2754
int GetWallCount()
Definition sbs.cpp:3095
void RemoveFloor(Floor *floor)
Definition sbs.cpp:2803
void RemoveModel(Model *model)
Definition sbs.cpp:2874
void ShowSceneNodes(bool value)
Definition sbs.cpp:4008
void ResetLighting()
Definition sbs.cpp:3418
Wall * AddCustomFloor(MeshObject *mesh, const std::string &name, const std::string &texture, std::vector< Vector2 > &varray, Real altitude, Real tw, Real th)
Definition sbs.cpp:1487
void MemoryReport()
Definition sbs.cpp:4651
Vehicle * GetVehicle(int number)
Definition sbs.cpp:1797
Wall * CreateWallBox(MeshObject *mesh, const std::string &name, const std::string &texture, Real x1, Real x2, Real z1, Real z2, Real height_in, Real voffset, Real tw, Real th, bool inside=true, bool outside=true, bool top=true, bool bottom=true, bool autosize=true, bool report=true)
Definition sbs.cpp:1174
bool HasBounds()
Definition sbs.cpp:4558
void EnableLandscape(bool value)
Definition sbs.cpp:1525
int GetTotalReverbCount()
Definition sbs.cpp:2381
void PrintBanner()
Definition sbs.cpp:581
bool IsInside()
Definition sbs.cpp:4317
Primitive * AddPrimitive(const std::string &name)
Definition sbs.cpp:3214
int GetTextureCount()
Definition sbs.cpp:4757
bool RegisterTimerCallback(TimerObject *timer)
Definition sbs.cpp:2149
void AddKey(int keyid, const std::string &name)
Definition sbs.cpp:3929
void EnableSkybox(bool value)
Definition sbs.cpp:1541
bool IsActionValid(Action *action)
Definition sbs.cpp:4235
Object * GetObjectOfParent(std::string parent_name, std::string name, const std::string &type, bool case_sensitive=true)
Definition sbs.cpp:3758
void ProcessTimers()
Definition sbs.cpp:2186
int GetFloorNumber(Real altitude, int lastfloor=0, bool checklastfloor=false)
Definition sbs.cpp:1596
Real GetDistance(Real x1, Real x2, Real z1, Real z2)
Definition sbs.cpp:1678
void CalculateFrameRate()
Definition sbs.cpp:677
int GetPolygonCount()
Definition sbs.cpp:3101
Wall * AddCustomWall(MeshObject *mesh, const std::string &name, const std::string &texture, PolyArray &varray, Real tw, Real th)
Definition sbs.cpp:1471
int GetObjectCount()
Definition sbs.cpp:2476
Model * AddModel(const std::string &name, const std::string &filename, bool center, const Vector3 &position, const Vector3 &rotation, Real max_render_distance=0, Real scale_multiplier=1, bool enable_physics=false, Real restitution=0, Real friction=0, Real mass=0)
Definition sbs.cpp:3185
void RemoveTrigger(Trigger *trigger)
Definition sbs.cpp:2926
void SetBounds(const Vector3 &area_min, const Vector3 &area_max)
Definition sbs.cpp:4398
void EnableRandomActivity(bool value)
Definition sbs.cpp:4109
int GetEscalatorCount()
Definition sbs.cpp:4049
unsigned long GetCurrentTime()
Definition sbs.cpp:3314
int GetSoundCount()
Definition sbs.cpp:2338
Primitive * GetPrimitive(std::string name)
Definition sbs.cpp:4497
int GetCameraTextureCount()
Definition sbs.cpp:4629
Wall * AddTriangleWall(MeshObject *mesh, const std::string &name, const std::string &texture, Real x1, Real y1, Real z1, Real x2, Real y2, Real z2, Real x3, Real y3, Real z3, Real tw, Real th)
Definition sbs.cpp:1503
int GetStairwellCount()
Definition sbs.cpp:1757
Real FeetToMeters(Real feet)
Definition sbs.cpp:1923
bool DetachCamera()
Definition sbs.cpp:4282
void SetPower(bool value)
Definition sbs.cpp:4724
Real ToLocal(Real remote_value)
Definition sbs.cpp:2397
bool AddActionParent(const std::string &name, std::vector< Object * > &parents)
Definition sbs.cpp:3490
bool GetConfigBool(const std::string &key, bool default_value)
Definition sbs.cpp:3273
Wall * AddWall(MeshObject *mesh, const std::string &name, const std::string &texture, Real thickness, Real x1, Real z1, Real x2, Real z2, Real height_in1, Real height_in2, Real altitude1, Real altitude2, Real tw, Real th)
Definition sbs.cpp:1929
void RegisterControl(Control *control)
Definition sbs.cpp:3966
int RegisterObject(Object *object)
Definition sbs.cpp:2491
Person * CreatePerson(std::string name="", int floor=0, bool service_access=false)
Definition sbs.cpp:4247
Floor * NewFloor(int number)
Definition sbs.cpp:1712
int GetConfigInt(const std::string &key, int default_value)
Definition sbs.cpp:3262
void EnableExternal(bool value)
Definition sbs.cpp:1532
void EnableFloorRange(int floor, int range, bool value, bool enablegroups, int shaftnumber=0, int stairsnumber=0)
Definition sbs.cpp:2016
std::vector< Sound * > GetSound(const std::string &name)
Definition sbs.cpp:2318
Vector3 FromGlobal(const Vector3 &position)
Definition sbs.cpp:4446
Trigger * AddTrigger(const std::string &name, const std::string &sound_file, const Vector3 &area_min, const Vector3 &area_max, std::vector< std::string > &action_names)
Definition sbs.cpp:3435
~SBS()
Definition sbs.cpp:270
GeometryController * GetGeometry()
Definition sbs.cpp:4646
CustomObject * AddCustomObject(const std::string &name, const Vector3 &position, const Vector3 &rotation, Real max_render_distance=0, Real scale_multiplier=1)
Definition sbs.cpp:3238
void CutInsideBoundaries(const Vector3 &min, const Vector3 &max, bool landscape=true, bool buildings=true, bool external=false, bool floors=false)
Definition sbs.cpp:4379
std::vector< Action * > GetAction(std::string name)
Definition sbs.cpp:3461
int GetMovingWalkwayCount()
Definition sbs.cpp:4055
Reverb * GetReverb(const std::string &name)
Definition sbs.cpp:2362
Real ToRemote(Real local_value)
Definition sbs.cpp:2437
bool Start(std::vector< Ogre::Camera * > &cameras)
Definition sbs.cpp:528
void CalculateAverageTime()
Definition sbs.cpp:3338
std::string DumpState()
Definition sbs.cpp:2531
void Prepare(bool report=true, bool renderonly=false)
Definition sbs.cpp:3107
unsigned long GetRunTime()
Definition sbs.cpp:3320
int GetMeshCount()
Definition sbs.cpp:2289
void RemoveController(DispatchController *controller)
Definition sbs.cpp:2939
bool SetWallOrientation(std::string direction)
Definition sbs.cpp:1811
ControllerManager * GetControllerManager()
Definition sbs.cpp:4603
bool SetFloorOrientation(std::string direction)
Definition sbs.cpp:1837
void UnregisterControl(Control *control)
Definition sbs.cpp:3972
bool UnregisterTimerCallback(TimerObject *timer)
Definition sbs.cpp:2168
void ResetState()
Definition sbs.cpp:4412
int GetActionCount()
Definition sbs.cpp:3484
void SetLighting(Real red=1.0, Real green=1.0, Real blue=1.0)
Definition sbs.cpp:3408
ElevatorManager * GetElevatorManager()
Definition sbs.cpp:4568
void UnregisterDynamicMesh(DynamicMesh *dynmesh)
Definition sbs.cpp:4534
bool RotateObject(Object *object, Vector3 rotation, Real speed, bool relative, bool X, bool Y, bool Z)
Definition sbs.cpp:2779
bool RemoveAction(std::string name)
Definition sbs.cpp:3545
void DrawWalls(bool MainN, bool MainP, bool SideN, bool SideP, bool Top, bool Bottom)
Definition sbs.cpp:1863
SoundSystem * GetSoundSystem()
Definition sbs.cpp:4548
void DecrementSoundCount()
Definition sbs.cpp:2349
Wall * AddGround(const std::string &name, const std::string &texture, Real x1, Real z1, Real x2, Real z2, Real altitude, int tile_x, int tile_z)
Definition sbs.cpp:1955
int GetShaftCount()
Definition sbs.cpp:1751
void UnregisterMovingWalkway(MovingWalkway *walkway)
Definition sbs.cpp:4703
Object * GetObject(int number)
Definition sbs.cpp:2482
ShaftManager * GetShaftManager()
Definition sbs.cpp:4573
bool InBox(const Vector3 &start, const Vector3 &end, const Vector3 &test)
Definition sbs.cpp:3285
bool CheckKey(int keyid)
Definition sbs.cpp:3940
void RemoveCustomObject(CustomObject *object)
Definition sbs.cpp:2900
bool GetBounds(Vector3 &min, Vector3 &max)
Definition sbs.cpp:4339
Stairwell * CreateStairwell(int number, Real CenterX, Real CenterZ, int startfloor, int endfloor)
Definition sbs.cpp:1698
void RemovePrimitive(Primitive *prim)
Definition sbs.cpp:2887
Light * AddLight(const std::string &name, int type)
Definition sbs.cpp:3148
Wall * CreateWallBox2(MeshObject *mesh, const std::string &name, const std::string &texture, Real CenterX, Real CenterZ, Real WidthX, Real LengthZ, Real height_in, Real voffset, Real tw, Real th, bool inside=true, bool outside=true, bool top=true, bool bottom=true, bool autosize=true, bool report=true)
Definition sbs.cpp:1392
int GetDrawWallsCount()
Definition sbs.cpp:1895
bool UnregisterObject(int number)
Definition sbs.cpp:2499
std::vector< Object * > GetObjectRange(const std::string &expression)
Definition sbs.cpp:3806
void ShowColliders(bool value)
Definition sbs.cpp:3385
bool DeleteObject(Object *object)
Definition sbs.cpp:2597
Person * GetPerson(int number)
Definition sbs.cpp:4309
void ShowFloorList()
Definition sbs.cpp:3986
int GetPersonCount()
Definition sbs.cpp:4553
Elevator * NewElevator(int number)
Definition sbs.cpp:1705
Control * AddControl(const std::string &name, const std::string &sound, const std::string &direction, Real CenterX, Real CenterZ, Real width, Real height, Real voffset, int selection_position, std::vector< std::string > &action_names, std::vector< std::string > &textures)
Definition sbs.cpp:3425
std::string VerifyFile(const std::string &filename)
Definition sbs.cpp:2946
RevolvingDoorManager * GetRevolvingDoorManager()
Definition sbs.cpp:4593
int ShowFloors
Definition shaft.h:44
bool IsShowFloor(int floor)
Definition shaft.cpp:348
bool IsValidFloor(int floor)
Definition shaft.cpp:434
int ShaftNumber
Definition shaft.h:34
bool Load(const std::string &filename, bool force=false)
Definition sound.cpp:386
bool Play(bool reset=true)
Definition sound.cpp:321
void SetSpeed(int percent)
Definition sound.cpp:273
void SetDopplerLevel(Real level)
Definition sound.cpp:462
void SetLoopState(bool value)
Definition sound.cpp:204
void SetConeSettings(Real inside_angle=360.0, Real outside_angle=360.0, Real outside_volume=1.0)
Definition sound.cpp:196
void SetVolume(Real value)
Definition sound.cpp:138
void SetDirection(const Vector3 &direction)
Definition sound.cpp:179
void SetDistances(Real min, Real max)
Definition sound.cpp:158
bool ShowFloors
Definition stairs.h:41
int StairsNum
Definition stairs.h:34
bool IsValidFloor(int floor)
Definition stairs.cpp:327
bool IsShowFloor(int floor)
Definition stairs.cpp:393
bool Create(const Vector3 &position)
Definition vehicle.cpp:144
MeshObject * GetMesh()
Definition wall.cpp:284
Polygon * AddQuad(const std::string &name, const std::string &texture, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, const Vector3 &v4, Real tw, Real th, bool autosize)
Definition wall.cpp:75
Polygon * AddPolygon(const std::string &name, const std::string &texture, PolyArray &vertices, Real tw, Real th, bool autosize)
Definition wall.cpp:89
#define GIT_REV
Definition gitrev.h:4
Ogre::Ray Ray
Definition globals.h:63
Ogre::Vector3 Vector3
Definition globals.h:58
Ogre::Real Real
Definition globals.h:57
Ogre::Vector2 Vector2
Definition globals.h:59
Ogre::Quaternion Quaternion
Definition globals.h:60
std::vector< String > StringVector
Definition sbs.h:50
SharedPtr< StringVector > StringVectorPtr
Definition sbs.h:51
bool SBSIMPEXP enable_profiling
Definition profiler.cpp:15
std::vector< Vector3 > PolyArray
Definition sbs.h:118
std::string TruncateNumber(float value, int decimals)
Definition globals.cpp:416
bool SBSIMPEXP enable_advanced_profiling
Definition profiler.cpp:16
void ReplaceAll(std::string &string, const std::string &original, const std::string &replacement)
Definition globals.cpp:201
int ToInt(const std::string &string)
Definition globals.cpp:402
void SetCase(std::string &string, bool uppercase)
Definition globals.cpp:172
std::string ToString(int number)
Definition globals.cpp:279
std::string SetCaseCopy(std::string string, bool uppercase)
Definition globals.cpp:165
Real ToFloat(const std::string &string)
Definition globals.cpp:397
bool IsNumeric(char character)
Definition globals.cpp:48
bool StartsWith(const std::string &string, const std::string &check_string, bool ignore_case)
Definition globals.cpp:216
std::string BoolToString(bool item)
Definition globals.cpp:101
void TrimString(std::string &string)
Definition globals.cpp:188
bool ToBool(std::string string)
Definition globals.cpp:407
bool IsEven(int Number)
Definition globals.cpp:37
#define SBS_PROFILE(name)
Definition profiler.h:131
#define SBS_PROFILE_MAIN(name)
Definition profiler.h:132
Vector3 end
Definition sbs.h:499
Vector3 start
Definition sbs.h:498
std::string name
Definition sbs.h:572
std::string filename
Definition sbs.h:563
std::string result
Definition sbs.h:564