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