4 Skyscraper 1.11 Alpha - Simulation Frontend
5 Copyright (C)2003-2017 Ryan Thoryk
6 http://www.skyscrapersim.com
7 http://sourceforge.net/projects/skyscraper
8 Contact - ryan@skyscrapersim.com
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "wx/wxprec.h"
29 #include "wx/progdlg.h"
30 #include "wx/cmdline.h"
31 #include "wx/filename.h"
32 #include "wx/filefn.h"
33 #include "wx/stdpaths.h"
37 #include <OgreRenderWindow.h>
38 #include <OgreConfigFile.h>
39 #include <OgreFontManager.h>
40 #include <OgreRectangle2D.h>
46 #include "debugpanel.h"
47 #include "skyscraper.h"
48 #include "enginecontext.h"
49 #include "scriptprocessor.h"
51 #include "mainscreen.h"
52 #include "loaddialog.h"
56 #if OGRE_VERSION >= 0x00010900
57 #include <OgreOverlaySystem.h>
60 #if defined(__WXGTK__)
61 // NOTE: Find the GTK install config with `pkg-config --cflags gtk+-2.0`
70 namespace Skyscraper {
72 IMPLEMENT_APP_NO_MAIN(Skyscraper)
76 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
77 #include "uexception.h"
81 #define SW_SHOWNORMAL 1
84 int main (int argc, char* argv[])
86 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
87 //initialize top-level exception handler
88 Skyscraper::InitUnhandledExceptionFilter();
91 //main wxWidgets entry point
97 namespace Skyscraper {
99 bool Skyscraper::OnInit(void)
102 version_rev = SVN_REVSTR;
103 version_state = "Alpha";
104 version_frontend = version + ".0." + version_rev;
105 StartupRunning = false;
109 #if OGRE_VERSION >= 0x00010900
130 new_location = false;
136 ConcurrentLoads = false;
137 RenderOnStartup = false;
144 show_progress = false;
149 #if !defined(__WXMAC__)
150 //switch current working directory to executable's path, if needed
151 wxString exefile = wxStandardPaths::Get().GetExecutablePath(); //get full path and filename
152 wxString app_path = wxPathOnly(exefile); //strip off filename
153 wxSetWorkingDirectory(app_path); //set working directory to path
156 //define command line options
157 static const wxCmdLineEntryDesc cmdLineDesc[] =
159 { wxCMD_LINE_SWITCH, "h", "help", "show this help message",
160 wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
162 { wxCMD_LINE_SWITCH, "c", "no-console", "hide the console",
163 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
165 { wxCMD_LINE_SWITCH, "f", "fullscreen", "start up in full-screen mode",
166 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
168 { wxCMD_LINE_SWITCH, "k", "check-script", "quickly check building script, and exit after",
169 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
171 { wxCMD_LINE_SWITCH, "m", "no-menu", "hide the main menu",
172 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
174 { wxCMD_LINE_SWITCH, "M", "no-music", "disable the intro music",
175 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
177 { wxCMD_LINE_SWITCH, "p", "no-panel", "hide the control panel",
178 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
180 { wxCMD_LINE_SWITCH, "H", "headless", "run in headless mode",
181 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
183 { wxCMD_LINE_SWITCH, "v", "verbose", "enable verbose mode",
184 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
186 { wxCMD_LINE_SWITCH, "V", "version", "show version",
187 wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
189 { wxCMD_LINE_PARAM, NULL, NULL, "building filename",
190 wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
195 //set up command line parser
196 parser = new wxCmdLineParser(cmdLineDesc, argc, argv);
198 //process command line options
199 switch (parser->Parse())
202 return false; //help was given, exit
204 break; //everything is good, continue
206 return false; //exit if parameters are incorrect
209 //only run idle events on specified windows, to reduce overhead
210 wxIdleEvent::SetMode(wxIDLE_PROCESS_SPECIFIED);
212 //set up unhandled exception handler (crash report system)
213 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
214 UnhandledExceptionSetRoot(this);
217 //set locale to default for conversion functions
218 #ifdef OGRE_DEFAULT_LOCALE
219 setlocale(LC_ALL, OGRE_DEFAULT_LOCALE);
221 setlocale(LC_ALL, "C");
224 //show version number and exit if specified
225 if (parser->Found(wxT("version")) == true)
227 printf("Skyscraper version %s\n", version_frontend.c_str());
231 //set verbose mode if specified
232 if (parser->Found(wxT("verbose")) == true)
235 //set CheckScript mode if specified
236 if (parser->Found(wxT("check-script")) == true)
239 //set headless mode if specified
240 if (parser->Found(wxT("headless")) == true)
246 configfile = new Ogre::ConfigFile();
247 configfile->load("skyscraper.ini");
249 catch (Ogre::Exception &e)
251 return ReportFatalError("Error loading skyscraper.ini file\nDetails: " + e.getDescription());
254 showconsole = GetConfigBool("Skyscraper.Frontend.ShowConsole", true);
256 //turn off console if specified on command line
257 if (parser->Found(wxT("no-console")) == true)
260 //create console window
261 if (showconsole == true)
264 //Create main window and set size from INI file defaults
265 //if (Headless == false)
267 window = new MainScreen(this, GetConfigInt("Skyscraper.Frontend.MenuWidth", 640), GetConfigInt("Skyscraper.Frontend.MenuHeight", 480));
268 //AllowResize(false);
269 window->ShowWindow();
270 window->CenterOnScreen();
273 //start and initialize OGRE
275 return ReportError("Error initializing frontend");
277 //autoload a building file if specified
278 std::string filename;
279 if (parser->GetParamCount() > 0)
281 filename = parser->GetParam(0).ToStdString();
283 //strip path from filename
284 wxFileName file (filename);
285 filename = file.GetFullName();
288 filename = GetConfigString("Skyscraper.Frontend.AutoLoad", "");
290 ShowMenu = GetConfigBool("Skyscraper.Frontend.Menu.Show", true);
292 //turn off menu if specified on command line
293 if (parser->Found(wxT("no-menu")) == true)
296 if (Headless == true)
300 return Load(filename);
302 if (ShowMenu == true)
304 StartupRunning = true;
309 //or show building selection window if ShowMenu is false
310 return Load(SelectBuilding());
316 int Skyscraper::OnExit()
321 Report("Cleaning up...");
324 loaddialog->Destroy();
328 progdialog->Destroy();
335 delete mCaelumSystem;
342 //delete console window
347 CloseProgressDialog();
361 #if OGRE_VERSION >= 0x00010900
362 delete mOverlaySystem;
365 Ogre::ResourceGroupManager::getSingleton().shutdownAll();
367 mRoot->shutdown(); //shutdown root instead of delete, to fix a crash on certain systems
370 return wxApp::OnExit();
373 void Skyscraper::UnloadSim()
375 //delete control panel object
382 mCaelumSystem->clear();
383 mCaelumSystem->detachAllViewports();
384 delete mCaelumSystem;
386 Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("Caelum");
390 console->bSend->Enable(false);
394 //do a full clear of Ogre objects
397 Ogre::MeshManager::getSingleton().removeAll();
399 //remove all materials
400 Ogre::MaterialManager::getSingleton().removeAll();
401 Ogre::MaterialManager::getSingleton().initialise(); //restore default materials
404 Ogre::FontManager::getSingleton().removeAll();
406 //remove all textures
407 Ogre::TextureManager::getSingleton().removeAll();
409 //clear scene manager
410 mSceneMgr->clearScene();
413 void Skyscraper::Render()
415 SBS_PROFILE_MAIN("Render");
417 if (Headless == true)
420 // Render to the frame buffer
421 mRoot->renderOneFrame();
423 #if defined(__WXGTK__)
425 mRenderWindow->update(true);
429 bool Skyscraper::Initialize()
434 mRoot = Ogre::Root::getSingletonPtr();
436 catch (Ogre::Exception &e)
438 return ReportFatalError("Error during initial OGRE check\nDetails: " + e.getDescription());
445 //set up custom logger
448 logger = new Ogre::LogManager();
449 Ogre::Log *log = logger->createLog("skyscraper.log", true, !showconsole, false);
450 log->addListener(this);
454 mRoot = new Ogre::Root();
456 catch (Ogre::Exception &e)
458 return ReportFatalError("Error initializing OGRE\nDetails: " + e.getDescription());
462 return ReportFatalError("Error initializing OGRE");
466 //set up overlay system
467 #if OGRE_VERSION >= 0x00010900
470 mOverlaySystem = new Ogre::OverlaySystem();
472 catch (Ogre::Exception &e)
474 return ReportFatalError("Error creating overlay system\nDetails: " + e.getDescription());
478 //configure render system
481 if(!mRoot->getRenderSystem())
483 //if no render systems are loaded, try to load previous config
484 if(!mRoot->restoreConfig())
486 //show dialog if load failed
487 mRoot->showConfigDialog();
491 catch (Ogre::Exception &e)
493 return ReportFatalError("Error configuring render system\nDetails: " + e.getDescription());
496 //if using DirectX, prevent it from switching into single-point floating point mode
497 Ogre::RenderSystem *rendersystem = mRoot->getRenderSystem();
500 Ogre::ConfigOptionMap& CurrentRendererOptions = mRoot->getRenderSystem()->getConfigOptions();
501 Ogre::ConfigOptionMap::iterator configItr = CurrentRendererOptions.begin();
503 for (; configItr != CurrentRendererOptions.end(); configItr++)
505 if ((configItr)->first == "Floating-point mode")
507 rendersystem->setConfigOption("Floating-point mode", "Consistent");
513 //initialize render window
516 mRoot->initialise(false);
518 if (Headless == false)
519 mRenderWindow = CreateRenderWindow();
521 catch (Ogre::Exception &e)
523 return ReportFatalError("Error initializing render window\nDetails: " + e.getDescription());
526 if (Headless == false)
529 Renderer = mRoot->getRenderSystem()->getCapabilities()->getRenderSystemName();
532 int loc = Renderer.find("Rendering Subsystem");
533 Renderer = Renderer.substr(0, loc - 1);
536 //load resource configuration
540 cf.load("resources.cfg");
542 catch (Ogre::Exception &e)
544 return ReportFatalError("Error loading resources.cfg\nDetails: " + e.getDescription());
546 Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
548 //add resource locations
551 std::string secName, typeName, archName;
552 while(seci.hasMoreElements())
554 secName = seci.peekNextKey();
555 Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
556 Ogre::ConfigFile::SettingsMultiMap::iterator i;
557 for(i = settings->begin(); i != settings->end(); ++i)
560 archName = i->second;
561 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);
565 //add app's directory to resource manager
566 Ogre::ResourceGroupManager::getSingleton().addResourceLocation(".", "FileSystem", "General", true);
568 //add materials group, and autoload
569 Ogre::ResourceGroupManager::getSingleton().addResourceLocation("data/materials", "FileSystem", "Materials", true);
570 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Materials");
572 catch (Ogre::Exception &e)
574 return ReportFatalError("Error initializing resources\nDetails: " + e.getDescription());
577 //create scene manager
580 mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);
582 catch (Ogre::Exception &e)
584 return ReportFatalError("Error creating scene manager\nDetails: " + e.getDescription());
587 #if OGRE_VERSION >= 0x00010900
588 mSceneMgr->addRenderQueueListener(mOverlaySystem);
592 //mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
593 //mSceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_MODULATIVE);
595 if (Headless == false)
599 mCamera = mSceneMgr->createCamera("Main Camera");
600 mViewport = mRenderWindow->addViewport(mCamera);
601 mCamera->setAspectRatio(Ogre::Real(mViewport->getActualWidth()) / Ogre::Real(mViewport->getActualHeight()));
603 catch (Ogre::Exception &e)
605 return ReportFatalError("Error creating camera and viewport\nDetails: " + e.getDescription());
609 //setup texture filtering
610 int filtermode = GetConfigInt("Skyscraper.Frontend.TextureFilter", 3);
611 int maxanisotropy = GetConfigInt("Skyscraper.Frontend.MaxAnisotropy", 8);
613 if (filtermode < 0 || filtermode > 3)
619 Ogre::TextureFilterOptions filter;
621 filter = Ogre::TFO_NONE;
622 else if (filtermode == 1)
623 filter = Ogre::TFO_BILINEAR;
624 else if (filtermode == 2)
625 filter = Ogre::TFO_TRILINEAR;
626 else if (filtermode == 3)
627 filter = Ogre::TFO_ANISOTROPIC;
629 Ogre::MaterialManager::getSingleton().setDefaultTextureFiltering(filter);
630 Ogre::MaterialManager::getSingleton().setDefaultAnisotropy(maxanisotropy);
632 //initialize FMOD (sound)
633 DisableSound = GetConfigBool("Skyscraper.Frontend.DisableSound", false);
634 if (DisableSound == false)
636 Report("\n FMOD Sound System, copyright (C) Firelight Technologies Pty, Ltd., 1994-2017\n");
638 FMOD_RESULT result = FMOD::System_Create(&soundsys);
639 if (result != FMOD_OK)
641 ReportFatalError("Error initializing sound");
646 char name [30] = "Skyscraper"; //set name for PulseAudio on Linux
647 result = soundsys->init(100, FMOD_INIT_NORMAL, &name);
648 if (result != FMOD_OK)
650 ReportFatalError("Error initializing sound");
655 //get FMOD version information
656 unsigned int version;
657 soundsys->getVersion(&version);
658 int major = version >> 16;
659 int minor = (version >> 8) & 255;
660 int rev = version & 255;
664 name = "FMOD Studio";
667 Report("Sound initialized: " + name + " version " + ToString(major) + "." + ToString(minor) + "." + ToString(rev));
672 Report("Sound Disabled");
675 if (GetConfigBool("Skyscraper.Frontend.Caelum", true) == true)
679 if (!Caelum::CaelumPlugin::getSingletonPtr())
680 mRoot->installPlugin(new Caelum::CaelumPlugin());
682 catch (Ogre::Exception &e)
684 return ReportFatalError("Error initializing Caelum plugin:\nDetails: " + e.getDescription());
691 #if OGRE_ARCH_TYPE == OGRE_ARCHITECTURE_32
694 #if OGRE_ARCH_TYPE == OGRE_ARCHITECTURE_64
698 #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
699 Platform = "Windows " + arch;
701 #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
702 Platform = "Linux " + arch;
704 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
705 Platform = "MacOS " + arch;
711 void Skyscraper::Report(const std::string &message)
715 if (Ogre::LogManager::getSingletonPtr())
716 Ogre::LogManager::getSingleton().logMessage(message);
718 catch (Ogre::Exception &e)
720 ShowError("Error writing message to log\n" + e.getDescription());
724 bool Skyscraper::ReportError(const std::string &message)
728 if (Ogre::LogManager::getSingletonPtr())
729 Ogre::LogManager::getSingleton().logMessage(message, Ogre::LML_CRITICAL);
731 catch (Ogre::Exception &e)
733 ShowError("Error writing message to log\n" + e.getDescription());
738 bool Skyscraper::ReportFatalError(const std::string &message)
740 ReportError(message);
745 void Skyscraper::ShowError(const std::string &message)
748 wxMessageDialog dialog(0, message, _("Skyscraper"), wxOK | wxICON_ERROR);
752 void Skyscraper::ShowMessage(const std::string &message)
754 //show message dialog
755 wxMessageDialog dialog(0, message, _("Skyscraper"), wxOK | wxICON_INFORMATION);
759 void Skyscraper::Loop()
761 //Main simulator loop
763 ProfileManager::Reset();
764 ProfileManager::Increment_Frame_Counter();
767 if (StartupRunning == true)
775 //show progress dialog if needed
776 if (show_progress == true)
777 ShowProgressDialog();
779 //run sim engine instances
780 bool result = RunEngines();
782 //delete an engine if requested
783 HandleEngineShutdown();
785 //exit if full shutdown request received
786 if (Shutdown == true)
792 if (result == false && (ConcurrentLoads == false || GetEngineCount() == 1))
798 //make sure active engine is the one the camera is active in
799 if (active_engine->IsCameraActive() == false)
800 active_engine = FindActiveEngine();
802 //exit if active engine is loading
803 if (active_engine->IsLoading() == true)
806 //if in CheckScript mode, exit
807 if (CheckScript == true)
819 //handle a building reload
822 //handle behavior when a user exits an engine area
825 //ProfileManager::dumpAll();
828 void Skyscraper::DrawBackground()
830 //draw menu background
832 DrawImage("data/" + GetConfigString("Skyscraper.Frontend.Menu.Image", "menu.png"), 0, -1, -1, false);
834 if (buttoncount == 0)
836 buttoncount = GetConfigInt("Skyscraper.Frontend.Menu.Buttons", 5);
837 buttons = new buttondata[buttoncount];
839 for (int i = 0; i < buttoncount; i++)
842 buttons[i].drawn_selected = false;
843 buttons[i].drawn_pressed = false;
844 buttons[i].active_button = 0;
849 for (int i = 0; i < buttoncount; i++)
851 std::string b1, b2, b3;
854 std::string number = ToString(i + 1);
858 b1 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button1.Image", "button_triton.png");
859 b2 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button1.Selected", "button_triton_selected.png");
860 b3 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button1.Pressed", "button_triton_pressed.png");
861 x = GetConfigFloat("Skyscraper.Frontend.Menu.Button1.X", 0.0f);
862 y = GetConfigFloat("Skyscraper.Frontend.Menu.Button1.Y", -0.08f);
863 center = GetConfigBool("Skyscraper.Frontend.Menu.Button1.Center", true);
867 b1 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button2.Image", "button_glasstower.png");
868 b2 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button2.Selected", "button_glasstower_selected.png");
869 b3 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button2.Pressed", "button_glasstower_pressed.png");
870 x = GetConfigFloat("Skyscraper.Frontend.Menu.Button2.X", 0.0f);
871 y = GetConfigFloat("Skyscraper.Frontend.Menu.Button2.Y", 0.125f);
872 center = GetConfigBool("Skyscraper.Frontend.Menu.Button2.Center", true);
876 b1 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button3.Image", "button_searstower.png");
877 b2 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button3.Selected", "button_searstower_selected.png");
878 b3 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button3.Pressed", "button_searstower_pressed.png");
879 x = GetConfigFloat("Skyscraper.Frontend.Menu.Button3.X", 0.0f);
880 y = GetConfigFloat("Skyscraper.Frontend.Menu.Button3.Y", 0.333f);
881 center = GetConfigBool("Skyscraper.Frontend.Menu.Button3.Center", true);
885 b1 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button4.Image", "button_simple.png");
886 b2 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button4.Selected", "button_simple_selected.png");
887 b3 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button4.Pressed", "button_simple_pressed.png");
888 x = GetConfigFloat("Skyscraper.Frontend.Menu.Button4.X", 0.0f);
889 y = GetConfigFloat("Skyscraper.Frontend.Menu.Button4.Y", 0.541f);
890 center = GetConfigBool("Skyscraper.Frontend.Menu.Button4.Center", true);
894 b1 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button5.Image", "button_other.png");
895 b2 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button5.Selected", "button_other_selected.png");
896 b3 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button5.Pressed", "button_other_pressed.png");
897 x = GetConfigFloat("Skyscraper.Frontend.Menu.Button5.X", 0.0f);
898 y = GetConfigFloat("Skyscraper.Frontend.Menu.Button5.Y", 0.75f);
899 center = GetConfigBool("Skyscraper.Frontend.Menu.Button5.Center", true);
903 b1 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button" + number + ".Image", "");
904 b2 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button" + number + ".Selected", "");
905 b3 = "data/" + GetConfigString("Skyscraper.Frontend.Menu.Button" + number + ".Pressed", "");
906 x = GetConfigFloat("Skyscraper.Frontend.Menu.Button" + number + ".X", 0.0f);
907 y = GetConfigFloat("Skyscraper.Frontend.Menu.Button" + number + ".Y", 0.0f);
908 center = GetConfigBool("Skyscraper.Frontend.Menu.Button" + number + ".Center", true);
911 DrawImage(b1, &buttons[i], x, y, center, b2, b3);
915 void Skyscraper::DrawImage(const std::string &filename, buttondata *button, float x, float y, bool center, const std::string &filename_selected, const std::string &filename_pressed)
917 //X and Y represent the image's top-left location.
918 //values are -1 for the top left, 1 for the top right, -1 for the top, and 1 for the bottom
922 int w_orig = 0, h_orig = 0, w2 = 0, h2 = 0;
923 bool background = false;
925 std::string material = "";
926 std::string Filename = filename;
931 //exit if background has already been drawn
932 if (background_image == Filename)
935 Ogre::TextureManager::getSingleton().setVerbose(false);
936 Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName(Filename);
937 if (tex.isNull() == false)
940 //load image data from file, if not already preloaded
947 for (int i = 0; i < count; i++)
952 Filename = filename_selected;
954 Filename = filename_pressed;
956 //create new material
957 Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create(Filename, "General");
959 //load image data from file
963 img.load(Filename, "General");
965 catch (Ogre::Exception &e)
967 ReportError("Error loading texture " + Filename + "\n" + e.getDescription());
971 w_orig = img.getWidth();
972 h_orig = img.getHeight();
974 //round up image size to power-of-2 value
975 w2 = powf(2, ceilf(Log2((float)w_orig)));
976 h2 = powf(2, ceilf(Log2((float)h_orig)));
978 //create texture and blit image onto it - this solves texture quality issues on mainly D3D9
979 tex = Ogre::TextureManager::getSingleton().createManual(Filename, "General", Ogre::TEX_TYPE_2D, w2, h2, 0, Ogre::PF_R8G8B8A8, Ogre::TU_STATIC);
980 tex->getBuffer(0, 0)->blitFromMemory(img.getPixelBox(0, 0), Ogre::Box(0, 0, 0, w_orig, h_orig, img.getDepth()));
982 //bind texture to material and set options
983 Ogre::TextureUnitState *state = mat->getTechnique(0)->getPass(0)->createTextureUnitState(Filename);
984 Ogre::Pass *pass = mat->getTechnique(0)->getPass(0);
985 pass->setDepthCheckEnabled(false);
986 pass->setDepthWriteEnabled(false);
987 pass->setLightingEnabled(false);
988 pass->setTextureFiltering(Ogre::TFO_NONE);
991 state->setTextureScale((Ogre::Real)w2 / (Ogre::Real)w_orig, (Ogre::Real)h2 / (Ogre::Real)h_orig);
992 state->setTextureScroll(-(Ogre::Real(w2 - w_orig) / (Ogre::Real)w2) / 2.0f, -(Ogre::Real(h2 - h_orig) / (Ogre::Real)h2) / 2.0f);
994 if (tex->hasAlpha() == true && button)
996 mat->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA);
997 mat->getTechnique(0)->getPass(0)->setAlphaRejectSettings(Ogre::CMPF_GREATER_EQUAL, 128);
1000 material = Filename;
1004 button->drawn_selected = false;
1005 button->drawn_pressed = false;
1006 button->active_button = 0;
1011 background_rect = 0;
1012 background_node = 0;
1016 //exit if requested button is already visible
1019 if (button->drawn_selected == false && button->drawn_pressed == false)
1021 if (button->active_button == 1)
1025 button->active_button = 1;
1026 material = filename;
1030 if (button->drawn_selected == true)
1032 if (button->active_button == 2)
1036 button->active_button = 2;
1037 material = filename_selected;
1041 if (button->drawn_pressed == true)
1043 if (button->active_button == 3)
1047 button->active_button = 3;
1048 material = filename_pressed;
1053 //set values and draw button
1056 w = w_orig / (mRenderWindow->getWidth() / 2.0);
1057 h = h_orig / (mRenderWindow->getHeight() / 2.0);
1060 //delete previous object
1062 button->node->detachAllObjects();
1064 delete button->rect;
1067 if (button->filename == "")
1069 //store general button data
1070 button->filename = filename;
1071 button->filename_selected = filename_selected;
1072 button->filename_pressed = filename_pressed;
1074 button->offset_x = x;
1075 button->offset_y = y;
1078 button->x = x - (w / 2);
1079 button->y = y - (h / 2);
1097 background_image = material;
1107 Ogre::Rectangle2D* rect = new Ogre::Rectangle2D(true);
1108 rect->setCorners(x, -y, x + w, -(y + h));
1109 rect->setMaterial(material);
1110 if (background == true)
1111 rect->setRenderQueueGroup(Ogre::RENDER_QUEUE_BACKGROUND);
1113 //set infinite bounding box
1114 Ogre::AxisAlignedBox aabInf;
1115 aabInf.setInfinite();
1116 rect->setBoundingBox(aabInf);
1119 Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
1120 node->attachObject(rect);
1123 button->node = node;
1124 button->rect = rect;
1128 background_node = node;
1129 background_rect = rect;
1134 void Skyscraper::GetMenuInput()
1136 //input handler for main menu
1138 //exit if there aren't any buttons
1139 if (!buttons || buttoncount == 0)
1142 //get mouse coordinates
1143 int mouse_x = window->ScreenToClient(wxGetMousePosition()).x;
1144 int mouse_y = window->ScreenToClient(wxGetMousePosition()).y;
1146 for (int i = 0; i < buttoncount; i++)
1148 buttondata *button = &buttons[i];
1150 //only process buttons if main window is selected
1151 if (window->Active != false)
1155 float w = mx / window->GetClientSize().x;
1156 float h = my / window->GetClientSize().y;
1157 float mouse_x_rel = (w * 2) - 1;
1158 float mouse_y_rel = (h * 2) - 1;
1160 //change button status based on mouse position and button press status
1161 if (mouse_x_rel > button->x && mouse_x_rel < button->x + button->size_x && mouse_y_rel > button->y && mouse_y_rel < button->y + button->size_y)
1163 if (button->drawn_selected == false && wxGetMouseState().LeftIsDown() == false)
1165 if (button->drawn_pressed == true)
1167 //user clicked on button
1168 button->drawn_selected = true;
1172 button->drawn_selected = true;
1174 if (button->drawn_pressed == false && wxGetMouseState().LeftIsDown() == true)
1176 button->drawn_pressed = true;
1177 button->drawn_selected = false;
1180 else if (button->drawn_selected == true || button->drawn_pressed == true)
1182 button->drawn_selected = false;
1183 button->drawn_pressed = false;
1189 void Skyscraper::Click(int index)
1191 //user clicked a button
1193 std::string number = ToString(index + 1);
1194 std::string filename = "";
1197 filename = GetConfigString("Skyscraper.Frontend.Menu.Button1.File", "Triton Center.bld");
1199 filename = GetConfigString("Skyscraper.Frontend.Menu.Button2.File", "Glass Tower.bld");
1201 filename = GetConfigString("Skyscraper.Frontend.Menu.Button3.File", "Sears Tower.bld");
1203 filename = GetConfigString("Skyscraper.Frontend.Menu.Button4.File", "Simple.bld");
1205 filename = GetConfigString("Skyscraper.Frontend.Menu.Button" + number + ".File", "");
1209 //show file selection dialog
1210 filename = SelectBuilding();
1219 void Skyscraper::DeleteButtons()
1221 if (buttoncount > 0)
1223 for (int i = 0; i < buttoncount; i++)
1225 buttondata *button = &buttons[i];
1229 button->node->detachAllObjects();
1230 button->node->getParent()->removeChild(button->node);
1234 delete button->rect;
1242 if (background_node)
1244 background_node->detachAllObjects();
1245 background_node->getParent()->removeChild(background_node);
1246 background_node = 0;
1248 if (background_rect)
1249 delete background_rect;
1250 background_rect = 0;
1251 background_image = "";
1254 void Skyscraper::StartSound()
1256 //load and start background music
1258 if (DisableSound == true)
1261 if (GetConfigBool("Skyscraper.Frontend.IntroMusic", true) == false)
1264 if (parser->Found(wxT("no-music")) == true)
1267 std::string filename = GetConfigString("Skyscraper.Frontend.IntroMusicFile", "intro.ogg");
1268 std::string filename_full = "data/" + filename;
1271 #if (FMOD_VERSION >> 16 == 4)
1272 FMOD_RESULT result = soundsys->createSound(filename_full.c_str(), (FMOD_MODE)(FMOD_2D | FMOD_ACCURATETIME | FMOD_SOFTWARE | FMOD_LOOP_NORMAL), 0, &sound);
1274 FMOD_RESULT result = soundsys->createSound(filename_full.c_str(), (FMOD_MODE)(FMOD_2D | FMOD_ACCURATETIME | FMOD_LOOP_NORMAL), 0, &sound);
1276 if (result != FMOD_OK)
1278 ReportError("Can't load file '" + filename_full + "'");
1282 #if (FMOD_VERSION >> 16 == 4)
1283 result = soundsys->playSound(FMOD_CHANNEL_FREE, sound, true, &channel);
1285 result = soundsys->playSound(sound, 0, true, &channel);
1288 if (result != FMOD_OK)
1290 ReportError("Error playing " + filename);
1294 channel->setLoopCount(-1);
1295 channel->setVolume(1.0f);
1296 channel->setPaused(false);
1299 void Skyscraper::StopSound()
1301 //stop and unload sound
1309 std::string Skyscraper::SelectBuilding()
1311 //choose a building from a script file
1313 std::string filename = "";
1315 //get listing of building files
1316 wxArrayString filelist;
1317 wxDir::GetAllFiles(_("buildings/"), &filelist, _("*.bld"), wxDIR_FILES);
1319 //strip directory name and extension from entries
1320 for (size_t i = 0; i < filelist.size(); i++)
1322 filelist[i] = filelist[i].substr(10);
1323 filelist[i] = filelist[i].substr(0, filelist[i].length() - 4);
1329 //show selection dialog window
1330 wxSingleChoiceDialog Selector (0, _("Select a Building"), _("Load Building"), filelist);
1331 Selector.SetSize(wxSize(350, 350));
1332 Selector.CenterOnScreen();
1334 if (Selector.ShowModal() == wxID_OK)
1336 filename = Selector.GetStringSelection();
1343 bool Skyscraper::Load(const std::string &filename, EngineContext *parent, const Ogre::Vector3 &position, float rotation, const Ogre::Vector3 &area_min, const Ogre::Vector3 &area_max)
1345 //load simulator and data file
1347 if (StartupRunning == true)
1350 StartupRunning = false;
1353 //exit if no building specified
1358 if (GetEngineCount() == 0)
1359 SkyName = GetConfigString("Skyscraper.Frontend.SkyName", "DefaultSky");
1362 if (GetEngineCount() == 0)
1363 mSceneMgr->clearScene();
1366 if (Headless == false)
1367 mRenderWindow->update();
1369 //set parent to master engine, if not set
1370 if (parent == 0 && GetEngineCount() >= 1)
1371 parent = GetFirstValidEngine();
1373 //Create simulator instance
1374 EngineContext* engine = CreateEngine(parent, position, rotation, area_min, area_max);
1377 active_engine = engine;
1379 //have instance load building
1380 bool result = engine->Load(filename);
1382 if (result == false)
1384 if (GetEngineCount() == 1)
1387 DeleteEngine(engine);
1391 //override SBS startup render option, if specified
1392 if (RenderOnStartup == true)
1393 engine->GetSystem()->RenderOnStartup = true;
1398 bool Skyscraper::Start(EngineContext *engine)
1405 ::SBS::SBS *Simcore = engine->GetSystem();
1407 if (engine == active_engine)
1409 //the sky needs to be created before Prepare() is called
1410 bool sky_result = false;
1411 if (GetConfigBool("Skyscraper.Frontend.Caelum", true) == true)
1412 sky_result = InitSky(engine);
1414 //create old sky if Caelum is turned off, or failed to initialize
1415 if (sky_result == false)
1416 Simcore->CreateSky();
1418 //switch to fullscreen mode if specified
1419 bool fullscreen = GetConfigBool("Skyscraper.Frontend.FullScreen", false);
1421 //override fullscreen setting if specified on the command line
1422 if (parser->Found(wxT("fullscreen")) == true)
1425 if (fullscreen == true)
1426 SetFullScreen(true);
1428 //resize main window
1429 if (FullScreen == false)
1431 window->SetBackgroundColour(*wxBLACK);
1432 window->SetClientSize(GetConfigInt("Skyscraper.Frontend.ScreenWidth", 800), GetConfigInt("Skyscraper.Frontend.ScreenHeight", 600));
1438 if (!engine->Start(mCamera))
1441 //close progress dialog if no engines are loading
1442 if (IsEngineLoading() == false)
1443 CloseProgressDialog();
1445 //load control panel
1446 if (engine == active_engine)
1448 bool panel = GetConfigBool("Skyscraper.Frontend.ShowControlPanel", true);
1450 //override if disabled on the command line
1451 if (parser->Found(wxT("no-panel")) == true)
1457 dpanel = new DebugPanel(this, NULL, -1);
1459 dpanel->SetPosition(wxPoint(GetConfigInt("Skyscraper.Frontend.ControlPanelX", 10), GetConfigInt("Skyscraper.Frontend.ControlPanelY", 25)));
1466 Report("Running simulation...");
1469 console->bSend->Enable(true);
1473 void Skyscraper::AllowResize(bool value)
1475 //changes the window style to either allow or disallow resizing
1478 window->SetWindowStyleFlag(wxDEFAULT_FRAME_STYLE | wxMAXIMIZE);
1480 window->SetWindowStyleFlag(wxDEFAULT_FRAME_STYLE & ~wxMAXIMIZE);
1484 void Skyscraper::UnloadToMenu()
1486 //unload to main menu
1488 //exit app if ShowMenu is false
1489 if (ShowMenu == false)
1498 CloseProgressDialog();
1500 //return to main menu
1501 SetFullScreen(false);
1502 window->SetClientSize(GetConfigInt("Skyscraper.Frontend.Menu.Width", 640), GetConfigInt("Skyscraper.Frontend.Menu.Height", 480));
1504 window->SetCursor(wxNullCursor);
1506 ConcurrentLoads = false;
1507 RenderOnStartup = false;
1510 StartupRunning = true;
1513 void Skyscraper::Quit()
1517 dpanel->EnableTimer(false);
1522 Ogre::RenderWindow* Skyscraper::CreateRenderWindow(const Ogre::NameValuePairList* miscParams, const std::string& windowName)
1524 std::string name = windowName;
1527 window->GetClientSize(&width, &height);
1529 Ogre::NameValuePairList params;
1531 params = *miscParams;
1533 bool vsync = GetConfigBool("Skyscraper.Frontend.Vsync", true);
1535 params["vsync"] = "true";
1537 params["vsync"] = "false";
1538 params["vsyncInterval"] = "1";
1539 params["externalWindowHandle"] = getOgreHandle();
1541 #if defined(__WXMAC__)
1542 params["macAPI"] = "cocoa";
1543 params["macAPICocoaUseNSView"] = "true";
1546 //create the render window
1547 mRenderWindow = Ogre::Root::getSingleton().createRenderWindow(name, width, height, false, ¶ms);
1549 mRenderWindow->setActive(true);
1550 mRenderWindow->windowMovedOrResized();
1552 return mRenderWindow;
1555 void Skyscraper::destroyRenderWindow()
1558 Ogre::Root::getSingleton().detachRenderTarget(mRenderWindow);
1560 mRenderWindow->destroy();
1564 const std::string Skyscraper::getOgreHandle() const
1566 #if defined(__WXMSW__)
1567 // Handle for Windows systems
1568 return Ogre::StringConverter::toString((size_t)((HWND)window->GetHandle()));
1569 #elif defined(__WXGTK__)
1570 // Handle for GTK-based systems
1572 // wxWidgets uses several internal GtkWidgets, the GetHandle method
1573 // returns a different one than this, but wxWidgets's GLCanvas uses this
1574 // one to interact with GLX, so we do the same.
1575 // NOTE: this method relies on implementation details in wxGTK and could
1576 // change without any notification from the developers.
1577 GtkWidget* privHandle = window->m_wxwindow;
1579 // prevents flickering
1580 gtk_widget_set_double_buffered(privHandle, false);
1582 gtk_widget_realize(privHandle);
1584 // grab the window object
1585 GdkWindow* gdkWin = gtk_widget_get_window((GtkWidget*)window->GetHandle());
1586 Display* display = GDK_WINDOW_XDISPLAY(gdkWin);
1587 Window wid = GDK_WINDOW_XWINDOW(gdkWin);
1589 // screen (returns "display.screen")
1590 std::string screenStr = DisplayString(display);
1591 screenStr = screenStr.substr(screenStr.find(".") + 1, screenStr.size());
1593 std::stringstream handleStream;
1594 handleStream << (unsigned long)display << ':' << screenStr << ':' << wid;
1596 // retrieve XVisualInfo
1597 // NOTE: '-lGL' linker flag must be specified.
1598 int attrlist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 8, None };
1599 XVisualInfo* vi = glXChooseVisual(display, DefaultScreen(display), attrlist);
1600 handleStream << ':' << (unsigned long)vi;
1602 return std::string(handleStream.str());
1604 #elif defined(__WXMAC__)
1605 return Ogre::StringConverter::toString((size_t)window->GetHandle());
1608 #error Not supported on this platform!
1612 int Skyscraper::GetConfigInt(const std::string &key, int default_value)
1614 std::string result = configfile->getSetting(key, "", ToString(default_value));
1615 return ToInt(result);
1618 std::string Skyscraper::GetConfigString(const std::string &key, const std::string &default_value)
1620 return configfile->getSetting(key, "", default_value);
1623 bool Skyscraper::GetConfigBool(const std::string &key, bool default_value)
1625 std::string result = configfile->getSetting(key, "", BoolToString(default_value));
1626 return ToBool(result);
1629 float Skyscraper::GetConfigFloat(const std::string &key, float default_value)
1631 std::string result = configfile->getSetting(key, "", ToString(default_value));
1632 return ToFloat(result);
1635 bool Skyscraper::InitSky(EngineContext *engine)
1642 if (Headless == true)
1645 //ensure graphics card and render system are capable of Caelum's shaders
1646 if (Renderer == "Direct3D9")
1648 //on DirectX, Caelum requires a card capable of 3.0 shader levels, which would be
1649 //an ATI Radeon HD 2000, nVidia Geforce 6, Intel G965 or newer
1650 //Intel cards: http://www.intel.com/support/graphics/sb/cs-014257.htm
1651 Ogre::RenderSystemCapabilities::ShaderProfiles profiles = mRoot->getRenderSystem()->getCapabilities()->getSupportedShaderProfiles();
1653 //for general sky, require both DirectX pixel and vertex shaders 2.0
1654 if (profiles.find("ps_2_0") == profiles.end() ||
1655 profiles.find("vs_2_0") == profiles.end())
1656 return ReportFatalError("Error initializing Caelum: 2.0 shaders not supported");
1658 //for clouds, require either DirectX pixel shaders 3.0 or nVidia fragment shaders 4.0
1659 if (profiles.find("ps_3_0") == profiles.end() &&
1660 profiles.find("fp40") == profiles.end())
1661 return ReportFatalError("Error initializing Caelum: 3.0 fragment shaders not supported");
1663 //for clouds, require either DirectX vetex shaders 3.0 or nVidia vertex shaders 4.0
1664 if (profiles.find("vs_3_0") == profiles.end() &&
1665 profiles.find("vp40") == profiles.end())
1666 return ReportFatalError("Error initializing Caelum: 3.0 vertex shaders not supported");
1669 if (Renderer == "OpenGL")
1671 //on OpenGL, Caelum requires hardware support for shaders (OpenGL 2.0 or newer)
1672 Ogre::RenderSystemCapabilities::ShaderProfiles profiles = mRoot->getRenderSystem()->getCapabilities()->getSupportedShaderProfiles();
1674 //require OpenGL ARB fragment programs
1675 if (profiles.find("arbfp1") == profiles.end())
1676 return ReportFatalError("Error initializing Caelum: fragment programs not supported");
1678 //require OpenGL ARB vertex programs
1679 if (profiles.find("arbvp1") == profiles.end())
1680 return ReportFatalError("Error initializing Caelum: vertex programs not supported");
1683 //load Caelum resources
1686 Ogre::ResourceGroupManager::getSingleton().addResourceLocation("data/caelum", "FileSystem", "Caelum", false);
1687 Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Caelum");
1690 mCaelumSystem = new Caelum::CaelumSystem(mRoot, mSceneMgr, Caelum::CaelumSystem::CAELUM_COMPONENTS_NONE);
1691 Caelum::CaelumPlugin::getSingleton().loadCaelumSystemFromScript(mCaelumSystem, SkyName);
1693 catch (Ogre::Exception &e)
1695 ReportFatalError("Error initializing Caelum:\nDetails: " + e.getDescription());
1699 ReportFatalError("Error initializing Caelum");
1705 //attach caelum to running viewport
1708 mCaelumSystem->attachViewport(mViewport);
1709 mCaelumSystem->setAutoNotifyCameraChanged(false);
1710 mCaelumSystem->setSceneFogDensityMultiplier(GetConfigFloat("Skyscraper.Frontend.FogMultiplier", 0.1f) / 1000);
1711 if (GetConfigBool("Skyscraper.Frontend.EnableFog", true) == false)
1712 mCaelumSystem->setManageSceneFog(Ogre::FOG_NONE);
1713 mCaelumSystem->setManageAmbientLight(GetConfigBool("Skyscraper.Frontend.ModifyAmbient", false));
1716 Ogre::Quaternion rot(Ogre::Degree(180.0f), Ogre::Vector3::UNIT_Y);
1717 mCaelumSystem->getCaelumGroundNode()->setOrientation(rot);
1718 mCaelumSystem->getCaelumCameraNode()->setOrientation(rot);
1720 //have sky use SBS scaling factor
1721 float scale = 1 / engine->GetSystem()->UnitScale;
1722 mCaelumSystem->getCaelumGroundNode()->setScale(scale, scale, scale);
1723 mCaelumSystem->getCaelumCameraNode()->setScale(scale, scale, scale);
1725 catch (Ogre::Exception &e)
1727 ReportFatalError("Error setting Caelum parameters:\nDetails: " + e.getDescription());
1731 ReportFatalError("Error setting Caelum parameters");
1734 //set sky time multiplier if not already set
1736 SkyMult = mCaelumSystem->getTimeScale();
1738 //set location if specified
1739 if (new_location == true)
1741 mCaelumSystem->setObserverLatitude(Ogre::Degree(latitude));
1742 mCaelumSystem->setObserverLongitude(Ogre::Degree(longitude));
1743 new_location = false;
1746 //set date/time if specified
1747 if (new_time == true)
1749 mCaelumSystem->setJulianDay(datetime);
1756 void Skyscraper::UpdateSky()
1759 SBS_PROFILE_MAIN("Sky");
1763 mCaelumSystem->notifyCameraChanged(mCamera);
1764 mCaelumSystem->setTimeScale(SkyMult);
1765 mCaelumSystem->updateSubcomponents(float(active_engine->GetSystem()->GetElapsedTime()) / 1000);
1769 void Skyscraper::messageLogged(const Ogre::String &message, Ogre::LogMessageLevel lml, bool maskDebug, const Ogre::String &logName, bool &skipThisMessage)
1771 //callback function that receives OGRE log messages
1774 console->Write(message);
1779 void Skyscraper::ShowConsole(bool send_button)
1782 console = new Console(this, NULL, -1);
1785 console->SetPosition(wxPoint(GetConfigInt("Skyscraper.Frontend.ConsoleX", 10), GetConfigInt("Skyscraper.Frontend.ConsoleY", 25)));
1786 console->bSend->Enable(send_button);
1789 void Skyscraper::CreateProgressDialog(const std::string &message)
1791 //don't create progress dialog if concurrent loading is enabled, and one engine is already running
1792 if (GetEngineCount() > 1 && ConcurrentLoads == true)
1794 if (GetFirstValidEngine()->IsRunning() == true)
1800 //show progress dialog in a queued fashion
1801 show_progress = true;
1802 prog_text = message;
1806 wxString msg = progdialog->GetMessage();
1809 progdialog->Update(progdialog->GetValue(), msg);
1812 //stop control panel timer
1814 dpanel->EnableTimer(false);
1817 void Skyscraper::CloseProgressDialog()
1819 //close progress dialog
1821 progdialog->Destroy();
1824 //start control panel timer
1826 dpanel->EnableTimer(true);
1829 void Skyscraper::ShowProgressDialog()
1832 progdialog = new wxProgressDialog(wxT("Loading..."), prog_text, 100, window);
1834 show_progress = false;
1837 void Skyscraper::UpdateProgress()
1842 int total_percent = GetEngineCount() * 100;
1843 int current_percent = 0;
1845 for (size_t i = 0; i < engines.size(); i++)
1848 current_percent += engines[i]->GetProgress();
1851 int final = ((float)current_percent / (float)total_percent) * 100;
1852 progdialog->Update(final);
1855 void Skyscraper::SetFullScreen(bool enabled)
1857 //enable/disable fullscreen
1859 FullScreen = enabled;
1860 window->ShowFullScreen(FullScreen);
1862 #if defined(__WXMSW__)
1863 //in Windows, enable double-buffering when switching to fullscreen
1864 //to fix framerate drop issues
1865 /*if (enabled == true)
1866 window->SetDoubleBuffered(true);
1868 window->SetDoubleBuffered(false);*/
1872 void Skyscraper::SetLocation(float latitude, float longitude)
1874 this->latitude = latitude;
1875 this->longitude = longitude;
1876 new_location = true;
1879 void Skyscraper::SetDateTime(double julian_date_time)
1881 datetime = julian_date_time;
1885 EngineContext* Skyscraper::CreateEngine(EngineContext *parent, const Ogre::Vector3 &position, float rotation, const Ogre::Vector3 &area_min, const Ogre::Vector3 &area_max)
1887 EngineContext* engine = new EngineContext(parent, this, mSceneMgr, soundsys, position, rotation, area_min, area_max);
1891 bool Skyscraper::DeleteEngine(EngineContext *engine)
1893 //delete a specified sim engine instance
1898 for (size_t i = 0; i < engines.size(); i++)
1900 if (engines[i] == engine)
1905 int count = GetEngineCount();
1907 if (active_engine == engine)
1912 int number = GetFirstValidEngine()->GetNumber();
1913 SetActiveEngine(number);
1916 else if (active_engine)
1917 active_engine->RefreshCamera();
1919 //exit to main menu if all engines have been deleted
1929 void Skyscraper::DeleteEngines()
1931 //delete all sim emgine instances
1933 for (size_t i = 0; i < engines.size(); i++)
1942 EngineContext* Skyscraper::FindActiveEngine()
1944 //find engine instance with an active camera
1946 for (size_t i = 0; i < engines.size(); i++)
1950 if (engines[i]->IsCameraActive() == true)
1954 return active_engine;
1957 void Skyscraper::SetActiveEngine(int number, bool switch_engines)
1959 //set an engine instance to be active
1961 EngineContext *engine = GetEngine(number);
1966 if (active_engine == engine)
1969 //don't switch if the camera's already active in the specified engine
1970 if (engine->IsCameraActive() == true)
1973 //don't switch to engine if it's loading
1974 if (engine->IsLoading() == true)
1978 bool state_set = false;
1982 //get previous engine's camera state
1983 if (switch_engines == true)
1985 state = active_engine->GetCameraState();
1989 //detach camera from current engine
1990 active_engine->DetachCamera(switch_engines);
1993 Report("Setting engine " + ToString(number) + " as active");
1995 //switch context to new engine instance
1996 active_engine = engine;
1997 active_engine->AttachCamera(mCamera, !switch_engines);
1999 //apply camera state to new engine
2000 if (switch_engines == true && state_set == true)
2001 active_engine->SetCameraState(state, false);
2003 //update mouse cursor for freelook mode
2004 window->EnableFreelook(active_engine->GetSystem()->camera->Freelook);
2007 bool Skyscraper::RunEngines()
2010 bool isloading = IsEngineLoading();
2012 if (ConcurrentLoads == true && isloading == true)
2015 for (size_t i = 0; i < engines.size(); i++)
2020 //process engine run loops, and also prevent other instances from running if
2021 //one or more engines are loading
2022 if (ConcurrentLoads == true || isloading == false || engines[i]->IsLoading() == true)
2025 if (i > 0 && ConcurrentLoads == false)
2027 //if concurrent loads is off, skip running if previous engine is not finished loading
2030 if (engines[i - 1]->IsLoading() == true && engines[i - 1]->IsLoadingFinished() == false)
2035 if (engines[i]->IsLoadingFinished() == false && run == true)
2037 if (engines[i]->Run() == false)
2042 //start engine if loading is finished
2043 if (engines[i]->IsLoadingFinished() == true)
2047 //exit if active engine is still loading
2048 if (active_engine->IsLoading() == true && active_engine->IsLoadingFinished() == false)
2051 //exit if active engine is finished, but other buildings are still loading
2052 if (active_engine->IsLoadingFinished() == true && isloading == true)
2061 bool Skyscraper::IsEngineLoading()
2063 //return true if an engine is loading
2065 bool result = false;
2066 for (size_t i = 0; i < engines.size(); i++)
2070 if (engines[i]->IsLoading() == true && engines[i]->IsLoadingFinished() == false)
2077 void Skyscraper::HandleEngineShutdown()
2079 bool deleted = false;
2081 for (size_t i = 0; i < engines.size(); i++)
2085 if (engines[i]->GetShutdownState() == true)
2087 if (DeleteEngine(engines[i]) == true)
2097 //clean up empty engine slots at the end of the list
2098 if (deleted == true)
2100 for (size_t i = engines.size() - 1; i < engines.size(); --i)
2103 engines.erase(engines.begin() + i);
2110 void Skyscraper::HandleReload()
2112 //reload building if requested
2114 for (size_t i = 0; i < engines.size(); i++)
2118 if (engines[i]->Reload == true)
2121 engines[i]->DoReload();
2127 EngineContext* Skyscraper::GetEngine(int number)
2129 //get an engine by instance number
2131 if (number < 0 || number >= (int)engines.size())
2134 return engines[number];
2137 int Skyscraper::GetEngineCount()
2139 //get number of valid engines
2143 for (size_t i = 0; i < engines.size(); i++)
2151 void Skyscraper::RaiseWindow()
2157 void Skyscraper::RefreshConsole()
2166 void Skyscraper::RefreshViewport()
2168 //refresh viewport to prevent rendering issues
2170 if (Headless == false)
2171 mViewport->_updateDimensions();
2174 void Skyscraper::SwitchEngines()
2176 //if user is no longer inside the active engine, find a new engine to attach to
2181 if (active_engine->IsInside() == true)
2184 EngineContext *parent = active_engine->GetParent();
2186 //if active engine has a parent, switch to the parent if possible
2189 if (parent->IsInside() == true && parent->IsCameraActive() == false)
2191 SetActiveEngine(parent->GetNumber(), true);
2196 //otherwise search for a valid engine to attach to
2197 for (size_t i = 0; i < engines.size(); i++)
2199 if (engines[i] != active_engine && engines[i])
2201 if (engines[i]->IsInside() == true && engines[i]->IsCameraActive() == false)
2203 SetActiveEngine((int)i, true);
2209 //if user has stepped outside of all sim engines, revert the movement
2210 //to place them back into the active engine
2211 active_engine->RevertMovement();
2214 bool Skyscraper::IsValidEngine(EngineContext *engine)
2219 for (size_t i = 0; i < engines.size(); i++)
2221 if (engines[i] == engine)
2227 bool Skyscraper::IsValidSystem(::SBS::SBS *sbs)
2232 for (size_t i = 0; i < engines.size(); i++)
2236 if (engines[i]->GetSystem() == sbs)
2243 int Skyscraper::GetFreeInstanceNumber()
2245 //get an available engine instance number
2247 for (size_t i = 0; i < engines.size(); i++)
2252 return (int)engines.size();
2255 int Skyscraper::RegisterEngine(EngineContext *engine)
2257 //register an engine with the frontend, returning the assigned instance number
2259 int number = GetFreeInstanceNumber();
2261 if (number < (int)engines.size())
2262 engines[number] = engine;
2264 engines.push_back(engine);
2269 EngineContext* Skyscraper::GetFirstValidEngine()
2271 for (size_t i = 0; i < engines.size(); i++)
2279 void Skyscraper::EnableSky(bool value)
2281 //enable or disable sky system
2283 //enable/disable old skybox system in engine 0
2285 GetEngine(0)->GetSystem()->EnableSkybox(value);
2287 //enable/disable Caelum sky system
2290 mCaelumSystem->getCaelumGroundNode()->setVisible(value);
2291 mCaelumSystem->getCaelumCameraNode()->setVisible(value);
2295 void Skyscraper::MacOpenFile(const wxString &filename)
2297 //support launching app with a building file, on Mac
2299 if (IsEngineLoading() == true)
2302 if (StartupRunning == true)
2305 //strip path from filename
2306 wxFileName file (filename);
2308 Load(file.GetFullName().ToStdString());