Skyscraper 2.0
skyscraper.cpp
Go to the documentation of this file.
1/*
2 Skyscraper 2.0 Alpha - Simulation Frontend
3 Copyright (C)2003-2024 Ryan Thoryk
4 https://www.skyscrapersim.net
5 https://sourceforge.net/projects/skyscraper/
6 Contact - ryan@skyscrapersim.net
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21*/
22
23#ifdef USING_WX
24#include "wx/wx.h"
25#include "wx/dir.h"
26#include "wx/cmdline.h"
27#include "wx/filename.h"
28#include "wx/filefn.h"
29#include "wx/stdpaths.h"
30#include "wx/joystick.h"
31#else
32#include <filesystem>
33#include "Ogre.h"
34#include "OgreApplicationContext.h"
35#include "OgreInput.h"
36#include "OgreRTShaderSystem.h"
37#include "OgreCameraMan.h"
38#endif
39#include <locale>
40#include <time.h>
41#include <thread>
42#include "globals.h"
43#include "sbs.h"
44#include "camera.h"
45#include "skyscraper.h"
46#include "vm.h"
47#include "gui.h"
48#include "hal.h"
49#include "sky.h"
50#include "enginecontext.h"
51#include "scriptproc.h"
52#ifdef USING_WX
53#include "mainscreen.h"
54#endif
55#include "profiler.h"
56#include "startscreen.h"
57#include "gitrev.h"
58
59#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
60#include <sysdir.h> // for sysdir_start_search_path_enumeration
61#include <glob.h> // for glob needed to expand ~ to user dir
62#include <stdio.h>
63#include <sys/sysctl.h>
64#endif
65
66#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
67#include <windows.h>
68#endif
69
70using namespace SBS;
71
72#ifdef USING_WX
73namespace Skyscraper {
74
75IMPLEMENT_APP_NO_MAIN(Skyscraper)
76
77}
78#endif
79
80#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
81#if OGRE_CPU != OGRE_CPU_ARM
82#ifdef USING_WX
83#include "uexception.h"
84#endif
85#endif
86#endif
87
88#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
89
90//code to get Application Support folder on Mac
91
92std::string expandTilde(const char* str) {
93 if (!str) return {};
94
95 glob_t globbuf;
96 if (glob(str, GLOB_TILDE, nullptr, &globbuf) == 0) {
97 std::string result(globbuf.gl_pathv[0]);
98 globfree(&globbuf);
99 return result;
100 } else {
101 throw "Unable to expand tilde";
102 }
103}
104
105std::string settingsPath() {
106 char path[PATH_MAX];
107 auto state = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_APPLICATION_SUPPORT,
108 SYSDIR_DOMAIN_MASK_USER);
109 if ((state = sysdir_get_next_search_path_enumeration(state, path))) {
110 return expandTilde(path);
111 } else {
112 throw "Failed to get settings folder";
113 }
114}
115
116#endif
117
118namespace Skyscraper {
119
120#ifndef USING_WX
121Skyscraper::Skyscraper() : OgreBites::ApplicationContext("Skyscraper")
122{
123}
124
126{
127 OnInit();
128}
129#endif
130
132{
133#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
134#if OGRE_CPU != OGRE_CPU_ARM
135#ifdef USING_WX
136 //initialize top-level exception handler
138#endif
139#endif
140#endif
141
142 StartupRunning = false;
143 FullScreen = false;
144 Maximized = false;
145 ShowMenu = false;
146 mRenderWindow = 0;
147 window = 0;
148 wireframe = 0;
149
150 //reset input states
151 boxes = false;
152 colliders = false;
153 strafe_left = false;
154 strafe_right = false;
155 float_up = false;
156 float_down = false;
157 spin_up = false;
158 spin_down = false;
159 turn_left = false;
160 turn_right = false;
161 look_up = false;
162 look_down = false;
163 step_forward = false;
164 step_backward = false;
165 freelook = false;
166
167 //reset loop states
168 startscreen_loaded = false;
169
170#ifdef USING_WX
171 parser = 0;
172#else
173 alt_down = false;
174 ctrl_down = false;
175 shift_down = false;
176#endif
177
178 //create VM instance
179 vm = new VM();
180
181 vm->version = "2.0";
182 vm->version_rev = ToString(GIT_REV);
183 vm->version_state = "RC3";
184 vm->version_frontend = vm->version + ".0." + vm->version_rev;
185
186#ifdef USING_WX
187 gui = vm->GetGUI();
188#endif
189 startscreen = new StartScreen(this);
190
191 //set working directory
192 SetCWD();
193
194 //set up unhandled exception handler (crash report system)
195#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
196#if OGRE_CPU != OGRE_CPU_ARM
197#ifdef USING_WX
199#endif
200#endif
201#endif
202
203 //set locale to default for conversion functions
204#ifdef OGRE_DEFAULT_LOCALE
205 setlocale(LC_ALL, OGRE_DEFAULT_LOCALE);
206#else
207 setlocale(LC_ALL, "C");
208#endif
209
210bool showconsole = true;
211#ifdef USING_WX
212 //show version number and exit if specified
213 if (parser->Found(wxT("version")) == true)
214 {
215 printf("Skyscraper version %s\n", vm->version_frontend.c_str());
216 return false;
217 }
218
219 //set verbose mode if specified
220 if (parser->Found(wxT("verbose")) == true)
221 vm->Verbose = true;
222
223 //set CheckScript mode if specified
224 if (parser->Found(wxT("check-script")) == true)
225 vm->CheckScript = true;
226
227 //turn off console if specified on command line
228 if (parser->Found(wxT("no-console")) == true)
229 showconsole = false;
230#endif
231
232 //load config files
233 HAL *hal = vm->GetHAL();
234 hal->LoadConfiguration(vm->data_path, showconsole);
235
236#ifdef USING_WX
237 //Create main window and set size from INI file defaults
238 window = new MainScreen(this, hal->GetConfigInt(hal->configfile, "Skyscraper.Frontend.Menu.Width", 800), hal->GetConfigInt(hal->configfile, "Skyscraper.Frontend.Menu.Height", 600));
239 //AllowResize(false);
240 window->ShowWindow();
241 window->CenterOnScreen();
242 window->Maximize(hal->GetConfigBool(hal->configfile, "Skyscraper.Frontend.Maximized", false));
243
244 vm->SetParent(window);
245#else
246
247 //initialize Ogre
248 OgreBites::ApplicationContext::setup();
249 addInputListener(this);
250
251 //get overlay system if already created
252 Ogre::OverlaySystem *overlay = getOverlaySystem();
253#endif
254
255 //start and initialize abstraction layer
256#ifdef USING_WX
257 if (!hal->Initialize(vm->data_path))
258#else
259 if (!hal->Initialize(vm->data_path, getRoot(), overlay))
260#endif
261 return ReportError("Error initializing HAL");
262
263 Report("");
264 Report("Creating render window...");
265#ifdef USING_WX
266 mRenderWindow = CreateRenderWindow(0, "SkyscraperVR");
267#else
268 mRenderWindow = getRenderWindow();
269#endif
270
271 //load system
272 if (!hal->LoadSystem(vm->data_path, mRenderWindow))
273 return ReportError("Error loading system");
274
275#ifndef __FreeBSD__
276#ifdef USING_WX
277 //set up joystick if available
278 wxJoystick joystick(wxJOYSTICK1);
279 if (!joystick.IsOk())
280 Report("No joystick detected");
281 else
282 {
283 Report("");
284 Report("Joystick detected: " + joystick.GetProductName().ToStdString());
285 Report("Joystick buttons: " + ToString(joystick.GetNumberButtons()));
286 Report("");
287 }
288#endif
289#endif
290 vm->ShowPlatform();
291
292 //autoload a building file if specified
293 std::string filename;
294#ifdef USING_WX
295 if (parser->GetParamCount() > 0)
296 {
297 filename = parser->GetParam(0).ToStdString();
298
299 //strip path from filename
300 wxFileName file (filename);
301 filename = file.GetFullName();
302 }
303 else
304 filename = hal->GetConfigString(hal->configfile, "Skyscraper.Frontend.AutoLoad", "");
305
306 ShowMenu = hal->GetConfigBool(hal->configfile, "Skyscraper.Frontend.Menu.Show", true);
307
308 //turn off menu if specified on command line
309 if (parser->Found(wxT("no-menu")) == true)
310 ShowMenu = false;
311
312 if (hal->GetConfigBool(hal->configfile, "Skyscraper.Frontend.VR", false) == true)
313 ShowMenu = false;
314#else
315 ShowMenu = false;
316
317#endif
318
319 //start console
320 vm->StartConsole();
321#ifdef USING_WX
322 gui->EnableConsole(true);
323#endif
324
325 if (filename != "")
326 return Load(filename);
327
328 if (ShowMenu == true)
329 {
330 StartupRunning = true;
331 StartSound();
332 }
333 else
334 {
335 //or show building selection window if ShowMenu is false
336 return Load(SelectBuilding());
337 }
338
339 return true;
340}
341
343{
344 //clean up
345
346 //cleanup
347 Report("Cleaning up...");
348
349 UnloadSim();
350
351 //cleanup sound
352 vm->GetHAL()->StopSound();
353
354#ifdef USING_WX
355 if (window)
356 window->Destroy();
357 window = 0;
358
359 if (parser)
360 delete parser;
361 parser = 0;
362#endif
363
364 delete startscreen;
365 delete vm;
366
367#ifdef USING_WX
368 return wxApp::OnExit();
369#else
370 return 0;
371#endif
372}
373
375{
376 //unload GUI
377#ifdef USING_WX
378 gui->Unload();
379#endif
380
381 //unload sky system
382 vm->GetSkySystem()->UnloadSky();
383
384 //delete all sim engines
385 vm->DeleteEngines();
386
387 //clear scene
388 vm->GetHAL()->Clear();
389}
390
392{
393 //Main simulator loop
394
397
398 if (vm->unloaded == true)
399 {
400 UnloadSim();
401 vm->unloaded = false;
402 vm->loadstart = false;
403 return true;
404 }
405
406 vm->ProcessConsole();
407
408 //main menu routine
409 if (StartupRunning == true)
410 {
411 bool result = false;
412
413 if (startscreen_loaded == false)
414 {
415#ifdef USING_WX
416 Maximized = window->IsMaximized();
417 if (Maximized == true)
418 window->Maximize(false);
419
420 window->SetClientSize(vm->GetHAL()->GetConfigInt(vm->GetHAL()->configfile, "Skyscraper.Frontend.Menu.Width", 800), vm->GetHAL()->GetConfigInt(vm->GetHAL()->configfile, "Skyscraper.Frontend.Menu.Height", 600));
421 window->Center();
422 window->SetCursor(wxNullCursor);
423#endif
424 }
425
426 result = startscreen->DrawBackground();
427
428 if (result == false)
429 return false;
430
431 result = startscreen->GetMenuInput();
432
433 if (result == false)
434 return false;
435
436 if (vm->loadstart == true)
437 {
438 StopMenu();
439 vm->loadstart = false;
440 return true;
441 }
442
443 if (startscreen_loaded == false)
444 {
445#ifdef USING_WX
446 if (Maximized == true)
447 window->Maximize();
448#endif
449 }
450
451 startscreen_loaded = true;
452
453 //have HAL render frame
454 return vm->GetHAL()->Render();
455 }
456
457#ifdef USING_WX
458 gui->ShowProgress();
459#endif
460
461 //run sim engine instances
462 std::vector<EngineContext*> newengines;
463 int status = vm->Run(newengines);
464
465 //start a new engine if needed
466 if (status == 3)
467 {
468 for (size_t i = 0; i < newengines.size(); i++)
469 {
470 Start(newengines[i]);
471 }
472 }
473
474 if (status == 2 || status == -1)
475 UnloadToMenu();
476
477 //ProfileManager::dumpAll();
478
479 return true;
480}
481
483{
484 //load and start background music
485
486 if (vm->GetHAL()->DisableSound == true)
487 return;
488
489 if (vm->GetHAL()->GetConfigBool(vm->GetHAL()->configfile, "Skyscraper.Frontend.IntroMusic", true) == false)
490 return;
491
492#ifdef USING_WX
493 if (parser->Found(wxT("no-music")) == true)
494 return;
495#endif
496
497 std::string filename = vm->GetHAL()->GetConfigString(vm->GetHAL()->configfile, "Skyscraper.Frontend.IntroMusicFile", "intro.ogg");
498 std::string filename_full = "data/" + filename;
499
500#ifdef USING_WX
501 //check for an intro sound file in the data path location instead
502 if (wxFileExists(vm->data_path + filename_full))
503 filename_full = vm->data_path + filename_full;
504#endif
505
506 Real volume = vm->GetHAL()->GetConfigFloat(vm->GetHAL()->configfile, "Skyscraper.Frontend.IntroMusicVolume", 1.0);
507
508 //fix name clash
509 #undef PlaySound
510
511 //play music
512 vm->GetHAL()->PlaySound(filename_full, volume);
513}
514
516{
517#ifdef USING_WX
518
519 if (vm->GetHAL()->GetConfigBool(vm->GetHAL()->configfile, "Skyscraper.Frontend.SelectBuildingNative", false) == false)
520 return gui->SelectBuilding(vm->data_path);
521 else
522 return gui->SelectBuildingNative(vm->data_path);
523#else
524 return "";
525#endif
526}
527
528bool Skyscraper::Load(const std::string &filename, EngineContext *parent, const Vector3 &position, Real rotation, const Vector3 &area_min, const Vector3 &area_max)
529{
530 //load simulator and data file
531
532 StopMenu();
533
534 bool result = vm->Load(true, filename, parent, position, rotation, area_min, area_max);
535
536 if (result == false && vm->GetEngineCount() == 1)
537 UnloadToMenu();
538
539 return result;
540}
541
543{
544 if (StartupRunning == true)
545 {
546 startscreen->DeleteButtons();
547 StartupRunning = false;
548 startscreen_loaded = false;
549 }
550}
551
553{
554 //start simulator
555
556 if (!engine)
557 return false;
558
559 ::SBS::SBS *Simcore = engine->GetSystem();
560 HAL *hal = vm->GetHAL();
561
562 if (engine == vm->GetActiveEngine())
563 {
564 //the sky needs to be created before Prepare() is called
565 vm->GetSkySystem()->CreateSky(engine);
566
567 //switch to fullscreen mode if specified
568 bool fullscreen = hal->GetConfigBool(hal->configfile, "Skyscraper.Frontend.FullScreen", false);
569
570#ifdef USING_WX
571 //override fullscreen setting if specified on the command line
572 if (parser->Found(wxT("fullscreen")) == true)
573 fullscreen = true;
574#endif
575
576 if (fullscreen == true)
577 SetFullScreen(true);
578
579#ifdef USING_WX
580 Maximized = window->IsMaximized();
581
582 //resize main window
583 if (FullScreen == false)
584 {
585#if !defined(__WXMAC__)
586 window->SetBackgroundColour(*wxBLACK);
587#endif
588 if (Maximized == false)
589 {
590 window->SetClientSize(hal->GetConfigInt(hal->configfile, "Skyscraper.Frontend.ScreenWidth", 1024), hal->GetConfigInt(hal->configfile, "Skyscraper.Frontend.ScreenHeight", 768));
591 window->Center();
592 }
593 }
594#endif
595 }
596
597 //start simulation
598 if (!vm->StartEngine(engine, hal->mCameras))
599 return false;
600
601 //close progress dialog if no engines are loading
602#ifdef USING_WX
603 if (vm->IsEngineLoading() == false)
604 gui->CloseProgressDialog();
605#endif
606
607 //load control panel
608 if (engine == vm->GetActiveEngine())
609 {
610 bool panel = vm->GetHAL()->GetConfigBool(hal->configfile, "Skyscraper.Frontend.ShowControlPanel", true);
611
612#ifdef USING_WX
613 //override if disabled on the command line
614 if (parser->Found(wxT("no-panel")) == true)
615 panel = false;
616
617 if (panel == true)
618 gui->CreateDebugPanel();
619#endif
620 }
621
622 hal->RefreshViewport();
623
624 //set ambient light
625 if (hal->GetConfigBool(hal->configfile, "Skyscraper.SBS.Lighting", false) == true)
626 {
627 Real value = hal->GetConfigFloat(hal->configfile, "Skyscraper.SBS.AmbientLight", 0.5);
628 hal->GetSceneManager()->setAmbientLight(Ogre::ColourValue(value, value, value));
629 }
630
631 //show frame stats
632 hal->EnableStats(hal->GetConfigBool(hal->configfile, "Skyscraper.Frontend.Stats", true));
633
634 //run simulation
635 Report("Running simulation...");
636 hal->StopSound();
637
638 return true;
639}
640
642{
643 //unload to main menu
644
645 //exit app if ShowMenu is false
646 if (ShowMenu == false)
647 Quit();
648
649 vm->Pause = false;
650 UnloadSim();
651
652 //cleanup sound
653 vm->GetHAL()->StopSound();
654
655#ifdef USING_WX
656 gui->CloseProgressDialog();
657#endif
658
659 //return to main menu
660 SetFullScreen(false);
661
662 vm->ConcurrentLoads = false;
663 vm->SetRenderOnStartup(false);
664
665 StartSound();
666 StartupRunning = true;
667}
668
670{
671 //exit app
672
673#ifdef USING_WX
674 gui->EnableTimer(false);
675
676 wxGetApp().Exit();
677#else
678 OnExit();
679#endif
680}
681
683{
684 vm->GetHAL()->DestroyRenderWindow();
685}
686
688{
689 //enable/disable fullscreen
690
691 FullScreen = enabled;
692#ifdef USING_WX
693 window->ShowFullScreen(FullScreen);
694#endif
695
696#if defined(__WXMSW__)
697 //in Windows, enable double-buffering when switching to fullscreen
698 //to fix framerate drop issues
699 /*if (enabled == true)
700 window->SetDoubleBuffered(true);
701 else
702 window->SetDoubleBuffered(false);*/
703#endif
704}
705
707{
708#ifdef USING_WX
709 window->Raise();
710 window->SetFocus();
711#endif
712}
713
714#ifdef USING_WX
715void Skyscraper::MacOpenFile(const wxString &filename)
716{
717 //support launching app with a building file, on Mac
718
719 if (vm->IsEngineLoading() == true)
720 return;
721
722 if (StartupRunning == true)
723 vm->GetHAL()->StopSound();
724
725 //strip path from filename
726 wxFileName file (filename);
727
728 Load(file.GetFullName().ToStdString());
729}
730#endif
731
733{
734 return vm->data_path;
735}
736
738{
739 return window;
740}
741
743{
744 return vm;
745}
746
747#ifdef USING_WX
748GUI* Skyscraper::GetGUI()
749{
750 return gui;
751}
752#endif
753
754void Skyscraper::Report(const std::string &message)
755{
756 vm->GetHAL()->Report(message, "");
757}
758
759bool Skyscraper::ReportError(const std::string &message)
760{
761 return vm->GetHAL()->ReportError(message, "");
762}
763
764}
static void Reset(void)
Definition profiler.cpp:263
static void Increment_Frame_Counter(void)
Definition profiler.cpp:279
void LoadConfiguration(const std::string data_path, bool show_console)
Definition hal.cpp:954
std::string GetConfigString(Ogre::ConfigFile *file, const std::string &key, const std::string &default_value)
Definition hal.cpp:292
int GetConfigInt(Ogre::ConfigFile *file, const std::string &key, int default_value)
Definition hal.cpp:286
void EnableStats(bool value)
Definition hal.cpp:773
bool LoadSystem(const std::string &data_path, Ogre::RenderWindow *renderwindow)
Definition hal.cpp:438
Ogre::SceneManager * GetSceneManager()
Definition hal.cpp:895
Real GetConfigFloat(Ogre::ConfigFile *file, const std::string &key, Real default_value)
Definition hal.cpp:307
bool GetConfigBool(Ogre::ConfigFile *file, const std::string &key, bool default_value)
Definition hal.cpp:299
std::vector< Ogre::Camera * > mCameras
Definition hal.h:90
bool Initialize(const std::string &data_path, Ogre::Root *root=0, Ogre::OverlaySystem *overlay=0)
Definition hal.cpp:315
void RefreshViewport()
Definition hal.cpp:929
Ogre::ConfigFile * configfile
Definition hal.h:97
void StopSound()
Definition hal.cpp:731
MainScreen * GetWindow()
void Report(const std::string &message)
bool ReportError(const std::string &message)
virtual bool OnInit()
std::string SelectBuilding()
bool Load(const std::string &filename, EngineContext *parent=0, const Vector3 &position=Vector3::ZERO, Real rotation=0.0, const Vector3 &area_min=Vector3::ZERO, const Vector3 &area_max=Vector3::ZERO)
std::string GetDataPath()
bool Start(EngineContext *engine)
void SetFullScreen(bool enabled)
#define GIT_REV
Definition gitrev.h:4
Ogre::Vector3 Vector3
Definition globals.h:58
Ogre::Real Real
Definition globals.h:57
std::string ToString(int number)
Definition globals.cpp:279
static void UnhandledExceptionSetRoot(Skyscraper *root)
Definition uexception.h:181
static void InitUnhandledExceptionFilter()
Definition uexception.h:164
std::string expandTilde(const char *str)
std::string settingsPath()