Changeset 1638 for code/branches/gui/src/orxonox/Orxonox.cc
- Timestamp:
- Jul 20, 2008, 7:49:26 PM (16 years ago)
- Location:
- code/branches/gui
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/branches/gui
-
Property
svn:mergeinfo
set to
/code/branches/input merged eligible
-
Property
svn:mergeinfo
set to
-
code/branches/gui/src/orxonox/Orxonox.cc
r1625 r1638 22 22 * Author: 23 23 * Reto Grieder 24 * Benjamin Knecht <beni_at_orxonox.net>, (C) 2007 24 25 * Co-authors: 25 * Benjamin Knecht <beni_at_orxonox.net>, (C) 200726 * ... 26 27 * 27 28 */ … … 38 39 //****** STD ******* 39 40 #include <deque> 41 #include <cassert> 40 42 41 43 //****** OGRE ****** … … 50 52 // util 51 53 //#include "util/Sleep.h" 52 #include "util/ArgReader.h"53 54 54 55 // core 55 56 #include "core/ConfigFileManager.h" 57 #include "core/ConfigValueIncludes.h" 56 58 #include "core/ConsoleCommand.h" 57 59 #include "core/Debug.h" 58 60 #include "core/Loader.h" 61 #include "core/Exception.h" 59 62 #include "core/input/InputManager.h" 63 #include "core/input/SimpleInputState.h" 64 #include "core/input/KeyBinder.h" 60 65 #include "core/TclBind.h" 61 66 #include "core/Core.h" … … 69 74 70 75 // objects and tools 71 #include "overlays/OverlayGroup.h"72 76 #include "overlays/console/InGameConsole.h" 73 77 #include "objects/Tickable.h" 74 78 #include "objects/Backlight.h" 75 79 #include "tools/ParticleInterface.h" 80 #include "gui/GUIManager.h" 76 81 77 82 #include "GraphicsEngine.h" … … 85 90 namespace orxonox 86 91 { 87 SetConsoleCommandShortcut(Orxonox, exit).setKeybindMode(KeybindMode::OnPress); 88 SetConsoleCommandShortcut(Orxonox, slomo).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0).setAxisParamIndex(0).setIsAxisRelative(false); 89 SetConsoleCommandShortcut(Orxonox, setTimeFactor).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0); 92 SetConsoleCommand(Orxonox, exit, true).setKeybindMode(KeybindMode::OnPress); 93 SetConsoleCommand(Orxonox, slomo, true).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0).setAxisParamIndex(0).setIsAxisRelative(false); 94 SetConsoleCommand(Orxonox, setTimeFactor, true).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0); 95 SetConsoleCommand(Orxonox, loadGame, true).setAccessLevel(AccessLevel::User).setDefaultValue(0, "standalone"); 90 96 91 97 /** … … 106 112 , bAbort_(false) 107 113 , timefactor_(1.0f) 108 , mode_(STANDALONE) 109 , serverIp_("") 110 , serverPort_(NETWORK_PORT) 111 { 114 , mode_(GameMode::GM_Unspecified) 115 , debugRefreshTime_(0.0f) 116 { 117 RegisterRootObject(Orxonox); 118 119 assert(singletonRef_s == 0); 120 singletonRef_s = this; 112 121 } 113 122 … … 118 127 { 119 128 // keep in mind: the order of deletion is very important! 120 Loader::unload( startLevel_);129 Loader::unload(); 121 130 if (this->startLevel_) 122 131 delete this->startLevel_; … … 136 145 delete this->timer_; 137 146 InputManager::destroy(); 138 GraphicsEngine::getSingleton().destroy(); 147 148 if (this->ogre_) 149 delete ogre_; 139 150 140 151 if (network::Client::getSingleton()) … … 142 153 if (server_g) 143 154 delete network::Server::getSingleton(); 155 156 singletonRef_s = 0; 157 } 158 159 void Orxonox::setConfigValues() 160 { 161 SetConfigValue(debugRefreshTime_, 0.2).description("Sets the time interval at which average fps, etc. get updated."); 144 162 } 145 163 … … 157 175 * @return singleton reference 158 176 */ 159 Orxonox* Orxonox::getSingleton() 160 { 161 if (!singletonRef_s) 162 singletonRef_s = new Orxonox(); 163 return singletonRef_s; 164 } 165 166 /** 167 @brief Destroys the Orxonox singleton. 168 */ 169 void Orxonox::destroySingleton() 170 { 171 if (singletonRef_s) 172 delete singletonRef_s; 173 singletonRef_s = 0; 177 Orxonox& Orxonox::getSingleton() 178 { 179 assert(singletonRef_s); 180 return *singletonRef_s; 174 181 } 175 182 … … 179 186 void Orxonox::setTimeFactor(float factor) 180 187 { 181 float change = factor / Orxonox::getSingleton() ->getTimeFactor();182 Orxonox::getSingleton() ->timefactor_ = factor;188 float change = factor / Orxonox::getSingleton().getTimeFactor(); 189 Orxonox::getSingleton().timefactor_ = factor; 183 190 for (Iterator<ParticleInterface> it = ObjectList<ParticleInterface>::begin(); it; ++it) 184 191 it->setSpeedFactor(it->getSpeedFactor() * change); 185 192 186 193 for (Iterator<Backlight> it = ObjectList<Backlight>::begin(); it; ++it) 187 it->setTimeFactor(Orxonox::getSingleton()->getTimeFactor()); 188 } 189 190 /** 191 * initialization of Orxonox object 192 * @param argc argument counter 193 * @param argv list of argumenst 194 it->setTimeFactor(Orxonox::getSingleton().getTimeFactor()); 195 } 196 197 198 /** 199 * Starts the whole Game. 194 200 * @param path path to config (in home dir or something) 195 201 */ 196 bool Orxonox::init(int argc, char **argv)202 void Orxonox::start() 197 203 { 198 204 #ifdef _DEBUG … … 203 209 Factory::createClassHierarchy(); 204 210 205 std::string mode; 206 std::string tempDataPath; 207 208 ArgReader ar(argc, argv); 209 ar.checkArgument("mode", &mode, false); 210 ar.checkArgument("data", &tempDataPath, false); 211 ar.checkArgument("ip", &serverIp_, false); 212 ar.checkArgument("port", &serverPort_, false); 213 if(ar.errorHandling()) 214 { 215 COUT(1) << "Error while parsing command line arguments" << std::endl; 216 COUT(1) << ar.getErrorString(); 217 COUT(0) << "Usage:" << std::endl << "orxonox [mode client|server|dedicated|standalone] " 218 << "[--data PATH] [--ip IP] [--port PORT]" << std::endl; 219 return false; 220 } 221 222 if (mode == "client") 223 mode_ = CLIENT; 224 else if (mode == "server") 225 mode_ = SERVER; 226 else if (mode == "dedicated") 227 mode_ = DEDICATED; 228 else 229 { 230 if (mode == "") 231 mode = "standalone"; 232 if (mode != "standalone") 211 setConfigValues(); 212 213 const Settings::CommandLineArgument* mode = Settings::getCommandLineArgument("mode"); 214 assert(mode); 215 if (!mode->bHasDefaultValue_) 216 { 217 Settings::setGameMode(mode->value_); 218 this->mode_ = Settings::getGameMode(); 219 } 220 COUT(3) << "Orxonox: Game mode is " << mode_.name << "." << std::endl; 221 222 const Settings::CommandLineArgument* dataPath = Settings::getCommandLineArgument("dataPath"); 223 assert(dataPath); 224 if (!dataPath->bHasDefaultValue_) 225 { 226 if (*dataPath->value_.getString().end() != '/' && *dataPath->value_.getString().end() != '\\') 227 Settings::tsetDataPath(dataPath->value_.getString() + "/"); 228 else 229 Settings::tsetDataPath(dataPath->value_.getString()); 230 } 231 232 try 233 { 234 // initialise TCL 235 TclBind::getInstance().setDataPath(Settings::getDataPath()); 236 237 ogre_ = new GraphicsEngine(); 238 ogre_->setup(); // creates ogre root and other essentials 239 240 if (mode_.showsGraphics) 241 { 242 ogre_->loadRenderer(); // creates the render window 243 244 // TODO: Spread this so that this call only initialises things needed for the Console and GUI 245 ogre_->initialiseResources(); 246 247 // Calls the InputManager which sets up the input devices. 248 // The render window width and height are used to set up the mouse movement. 249 InputManager::initialise(ogre_->getWindowHandle(), 250 ogre_->getWindowWidth(), ogre_->getWindowHeight(), true, true, true); 251 KeyBinder* keyBinder = new KeyBinder(); 252 InputManager::createSimpleInputState("game", 20)->setHandler(keyBinder); 253 254 // Load the InGameConsole 255 InGameConsole::getInstance().initialise(); 256 257 // load the CEGUI interface 258 GUIManager::getInstance().initialise(); 259 } 260 261 bool showGUI = true; 262 if (mode_.mode != GameMode::Unspecified) 263 { 264 showGUI = false; 265 // a game mode was specified with the command line 266 // we therefore load the game and level directly 267 268 if (!loadLevel(this->mode_)) 269 { 270 COUT(1) << "Loading with predefined mode failed. Showing main menu." << std::endl; 271 showGUI = true; 272 mode_ = GameMode::GM_Unspecified; 273 } 274 } 275 276 if (showGUI) 277 { 278 // show main menu 279 //GraphicsEngine::getSingleton().createNewScene(); 280 GUIManager::getInstance().showGUI("MainMenu", true); 281 } 282 } 283 catch (std::exception& ex) 284 { 285 COUT(1) << ex.what() << std::endl; 286 COUT(1) << "Loading sequence aborted." << std::endl; 287 return; 288 } 289 290 modeRequest_ = mode_; 291 // here happens the game 292 startRenderLoop(); 293 294 if (mode_.mode == GameMode::Client) 295 network::Client::getSingleton()->closeConnection(); 296 297 if (mode_.hasServer) 298 server_g->close(); 299 } 300 301 void Orxonox::loadGame(const std::string& name) 302 { 303 const GameMode& mode = Settings::getGameMode(name); 304 if (mode.mode == GameMode::None) 305 return; 306 307 getSingleton().modeRequest_ = mode; 308 } 309 310 bool Orxonox::loadLevel(const GameMode& mode) 311 { 312 bool success = true; 313 314 if (mode.showsGraphics) 233 315 { 234 COUT(2) << "Warning: mode \"" << mode << "\" doesn't exist. " 235 << "Defaulting to standalone" << std::endl; 236 mode = "standalone"; 316 // create Ogre SceneManager for the level 317 ogre_->createNewScene(); 318 319 if (!loadPlayground()) 320 return false; 237 321 } 238 mode_ = STANDALONE; 239 } 240 COUT(3) << "Orxonox: Mode is " << mode << "." << std::endl; 241 242 if (tempDataPath != "") 243 { 244 if (tempDataPath[tempDataPath.size() - 1] != '/') 245 tempDataPath += "/"; 246 Settings::tsetDataPath(tempDataPath); 247 } 248 249 // initialise TCL 250 TclBind::getInstance().setDataPath(Settings::getDataPath()); 251 252 //if (mode_ == DEDICATED) 253 // TODO: decide what to do here 254 //else 255 256 // for playable server, client and standalone, the startup 257 // procedure until the GUI is identical 258 259 ogre_ = &GraphicsEngine::getSingleton(); 260 if (!ogre_->setup()) // creates ogre root and other essentials 261 return false; 262 263 return true; 264 } 265 266 /** 267 * start modules 268 */ 269 bool Orxonox::start() 270 { 271 if (mode_ == DEDICATED) 272 { 273 // do something else 274 } 275 else 276 { // not dedicated server 277 if (!ogre_->loadRenderer()) // creates the render window 278 return false; 279 280 // TODO: Spread this so that this call only initialises things needed for the Console 281 if (!ogre_->initialiseResources()) 282 return false; 283 284 // Load the InGameConsole 285 InGameConsole::getInstance().initialise(); 286 287 // Calls the InputManager which sets up the input devices. 288 // The render window width and height are used to set up the mouse movement. 289 if (!InputManager::initialise(ogre_->getWindowHandle(), 290 ogre_->getWindowWidth(), ogre_->getWindowHeight(), true, true, true)) 291 return false; 292 293 // TOOD: load the GUI here 294 // set InputManager to GUI mode 295 InputManager::setInputState(InputManager::IS_GUI); 296 // TODO: run GUI here 297 298 // The following lines depend very much on the GUI output, so they're probably misplaced here.. 299 300 InputManager::setInputState(InputManager::IS_NONE); 301 302 // create Ogre SceneManager 303 ogre_->createNewScene(); 304 305 if (!loadPlayground()) 306 return false; 307 } 308 309 switch (mode_) 310 { 311 case SERVER: 312 if (!serverLoad()) 313 return false; 314 break; 315 case CLIENT: 316 if (!clientLoad()) 317 return false; 318 break; 319 case DEDICATED: 320 if (!serverLoad()) 321 return false; 322 break; 323 default: 324 if (!standaloneLoad()) 325 return false; 326 } 327 328 InputManager::setInputState(InputManager::IS_NORMAL); 329 330 return startRenderLoop(); 322 323 switch (mode.mode) 324 { 325 case GameMode::Server: 326 success &= serverLoad(); 327 break; 328 case GameMode::Client: 329 success &= clientLoad(); 330 break; 331 case GameMode::Dedicated: 332 success &= serverLoad(); 333 break; 334 case GameMode::Standalone: 335 success &= standaloneLoad(); 336 break; 337 default: // never happens 338 assert(false); 339 } 340 341 if (success) 342 InputManager::requestEnterState("game"); 343 344 return success; 331 345 } 332 346 … … 337 351 bool Orxonox::loadPlayground() 338 352 { 339 // Init audio 340 //auMan_ = new audio::AudioManager(); 341 //auMan_->ambientAdd("a1"); 342 //auMan_->ambientAdd("a2"); 343 //auMan_->ambientAdd("a3"); 344 //auMan->ambientAdd("ambient1"); 345 //auMan_->ambientStart(); 353 // Start the Radar 354 this->radar_ = new Radar(); 346 355 347 356 // Load the HUD 348 357 COUT(3) << "Orxonox: Loading HUD" << std::endl; 349 358 hud_ = new Level(Settings::getDataPath() + "overlay/hud.oxo"); 350 Loader::load(hud_); 351 352 // Start the Radar 353 this->radar_ = new Radar(); 354 355 return true; 359 return Loader::load(hud_); 360 } 361 362 /** 363 * Helper method to load a level. 364 */ 365 bool Orxonox::loadScene() 366 { 367 COUT(0) << "Loading level..." << std::endl; 368 startLevel_ = new Level(Settings::getDataPath() + "levels/sample.oxw"); 369 return Loader::open(startLevel_); 356 370 } 357 371 … … 363 377 COUT(0) << "Loading level in server mode" << std::endl; 364 378 379 assert(Settings::getCommandLineArgument("port")); 380 int serverPort = Settings::getCommandLineArgument("port")->value_; 365 381 //server_g = new network::Server(serverPort_); 366 server_g = network::Server::createSingleton(serverPort _);382 server_g = network::Server::createSingleton(serverPort); 367 383 368 384 if (!loadScene()) … … 381 397 COUT(0) << "Loading level in client mode" << std::endl;\ 382 398 383 if (serverIp_.compare("") == 0) 399 assert(Settings::getCommandLineArgument("port")); 400 assert(Settings::getCommandLineArgument("ip")); 401 int serverPort = Settings::getCommandLineArgument("port")->value_; 402 std::string serverIP = Settings::getCommandLineArgument("ip")->value_; 403 404 if (serverIP.compare("") == 0) 384 405 client_g = network::Client::createSingleton(); 385 406 else 386 387 client_g = network::Client::createSingleton(serverIp_, serverPort_); 407 client_g = network::Client::createSingleton(serverIP, serverPort); 388 408 389 409 if(!client_g->establishConnection()) … … 408 428 409 429 /** 410 * Helper method to load a level.411 */412 bool Orxonox::loadScene()413 {414 startLevel_ = new Level("levels/sample.oxw");415 Loader::open(startLevel_);416 417 return true;418 }419 420 421 /**422 430 Main loop of the orxonox game. 423 About the loop: The design is almost exactly like the one in ogre, so that 424 if any part of ogre registers a framelisteners, it will still behave 425 correctly. Furthermore the time smoothing feature from ogre has been 426 implemented too. If turned on (see orxonox constructor), it will calculate 427 the dt_n by means of the recent most dt_n-1, dt_n-2, etc. 431 We use the Ogre::Timer to measure time since it uses the most precise 432 method an a platform (however the windows timer lacks time when under 433 heavy kernel load!). 434 There is a simple mechanism to measure the average time spent in our 435 ticks as it may indicate performance issues. 436 A note about the Ogre::FrameListener: Even though we don't use them, 437 they still get called. However, the delta times are not correct (except 438 for timeSinceLastFrame, which is the most important). A little research 439 as shown that there is probably only one FrameListener that doesn't even 440 need the time. So we shouldn't run into problems. 428 441 */ 429 bool Orxonox::startRenderLoop() 430 { 431 // first check whether ogre root object has been created 432 if (Ogre::Root::getSingletonPtr() == 0) 433 { 434 COUT(2) << "Orxonox Error: Could not start rendering. No Ogre root object found" << std::endl; 435 return false; 436 } 442 void Orxonox::startRenderLoop() 443 { 437 444 Ogre::Root& ogreRoot = Ogre::Root::getSingleton(); 438 439 445 440 446 // use the ogre timer class to measure time. … … 444 450 unsigned long frameCount = 0; 445 451 446 // TODO: this would very well fit into a configValue 447 const unsigned long refreshTime = 200000; 452 const unsigned long refreshTime = debugRefreshTime_ * 1000000.0f; 448 453 unsigned long refreshStartTime = 0; 449 454 unsigned long tickTime = 0; … … 454 459 unsigned long timeAfterTick = 0; 455 460 461 int sleepTime = 0; 462 463 // TODO: Update time in seconds every 7 seconds to avoid any overflow (7 secs is very tight) 464 456 465 COUT(3) << "Orxonox: Starting the main loop." << std::endl; 457 466 467 try 468 { 458 469 timer_->reset(); 459 470 while (!bAbort_) 460 471 { 461 // get current time 462 timeBeforeTickOld = timeBeforeTick; 463 timeBeforeTick = timer_->getMicroseconds(); 464 float dt = (timeBeforeTick - timeBeforeTickOld) / 1000000.0; 465 466 467 // tick the core (needs real time for input and tcl thread management) 468 Core::tick(dt); 469 470 // Call those objects that need the real time 471 for (Iterator<TickableReal> it = ObjectList<TickableReal>::start(); it; ++it) 472 it->tick(dt); 473 // Call the scene objects 474 for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; ++it) 475 it->tick(dt * this->timefactor_); 476 477 // call server/client with normal dt 478 if (client_g) 479 client_g->tick(dt * this->timefactor_); 480 if (server_g) 481 server_g->tick(dt * this->timefactor_); 482 483 484 // get current time once again 485 timeAfterTick = timer_->getMicroseconds(); 486 487 tickTime += timeAfterTick - timeBeforeTick; 488 if (timeAfterTick > refreshStartTime + refreshTime) 489 { 490 GraphicsEngine::getSingleton().setAverageTickTime( 491 (float)tickTime * 0.001 / (frameCount - oldFrameCount)); 492 GraphicsEngine::getSingleton().setAverageFramesPerSecond( 493 (float)(frameCount - oldFrameCount) / (timeAfterTick - refreshStartTime) * 1000000.0); 494 oldFrameCount = frameCount; 495 tickTime = 0; 496 refreshStartTime = timeAfterTick; 497 } 498 499 500 // don't forget to call _fireFrameStarted in ogre to make sure 501 // everything goes smoothly 502 Ogre::FrameEvent evt; 503 evt.timeSinceLastFrame = dt; 504 evt.timeSinceLastEvent = dt; // note: same time, but shouldn't matter anyway 505 ogreRoot._fireFrameStarted(evt); 506 507 if (mode_ != DEDICATED) 508 { 509 // Pump messages in all registered RenderWindows 510 // This calls the WindowEventListener objects. 511 Ogre::WindowEventUtilities::messagePump(); 512 // make sure the window stays active even when not focused 513 // (probably only necessary on windows) 514 GraphicsEngine::getSingleton().setWindowActivity(true); 515 516 // render 517 ogreRoot._updateAllRenderTargets(); 518 } 519 520 // again, just to be sure ogre works fine 521 ogreRoot._fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted 522 523 ++frameCount; 524 } 525 526 if (mode_ == CLIENT) 527 network::Client::getSingleton()->closeConnection(); 528 else if (mode_ == SERVER) 529 server_g->close(); 530 531 return true; 472 // get current time 473 timeBeforeTickOld = timeBeforeTick; 474 timeBeforeTick = timer_->getMicroseconds(); 475 float dt = (timeBeforeTick - timeBeforeTickOld) / 1000000.0; 476 477 // check whether we have to load a game 478 if (mode_.mode != modeRequest_.mode && mode_.mode == GameMode::Unspecified) 479 { 480 this->loadLevel(modeRequest_); 481 this->modeRequest_ = GameMode::GM_None; 482 } 483 484 485 // tick the core (needs real time for input and tcl thread management) 486 Core::tick(dt); 487 488 // Call those objects that need the real time 489 for (Iterator<TickableReal> it = ObjectList<TickableReal>::start(); it; ++it) 490 it->tick(dt); 491 // Call the scene objects 492 for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; ++it) 493 it->tick(dt * this->timefactor_); 494 495 // call server/client with normal dt 496 if (client_g) 497 client_g->tick(dt * this->timefactor_); 498 if (server_g) 499 server_g->tick(dt * this->timefactor_); 500 501 502 // get current time once again 503 timeAfterTick = timer_->getMicroseconds(); 504 505 tickTime += timeAfterTick - timeBeforeTick; 506 if (timeAfterTick > refreshStartTime + refreshTime) 507 { 508 GraphicsEngine::getSingleton().setAverageTickTime( 509 (float)tickTime * 0.001 / (frameCount - oldFrameCount)); 510 float avgFPS = (float)(frameCount - oldFrameCount) / (timeAfterTick - refreshStartTime) * 1000000.0; 511 GraphicsEngine::getSingleton().setAverageFramesPerSecond(avgFPS); 512 513 if (avgFPS > 60.0) 514 sleepTime++; 515 else 516 sleepTime--; 517 if (sleepTime < 0) 518 sleepTime = 0; 519 520 oldFrameCount = frameCount; 521 tickTime = 0; 522 refreshStartTime = timeAfterTick; 523 } 524 525 // do some sleeping when the frameRate is over 60 526 if (sleepTime > 0) 527 msleep(sleepTime); 528 529 530 // don't forget to call _fireFrameStarted in ogre to make sure 531 // everything goes smoothly 532 Ogre::FrameEvent evt; 533 evt.timeSinceLastFrame = dt; 534 evt.timeSinceLastEvent = dt; // note: same time, but shouldn't matter anyway 535 ogreRoot._fireFrameStarted(evt); 536 537 if (mode_.showsGraphics) 538 { 539 // Pump messages in all registered RenderWindows 540 // This calls the WindowEventListener objects. 541 Ogre::WindowEventUtilities::messagePump(); 542 // make sure the window stays active even when not focused 543 // (probably only necessary on windows) 544 GraphicsEngine::getSingleton().setWindowActivity(true); 545 546 // tick CEGUI 547 GUIManager::getInstance().tick(dt); 548 549 // render 550 ogreRoot._updateAllRenderTargets(); 551 } 552 553 // again, just to be sure ogre works fine 554 ogreRoot._fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted 555 556 ++frameCount; 557 } 558 } 559 catch (std::exception& ex) 560 { 561 // something went wrong. 562 COUT(1) << ex.what() << std::endl; 563 COUT(1) << "Main loop was stopped by an unhandled exception. Shutting down." << std::endl; 564 } 532 565 } 533 566 }
Note: See TracChangeset
for help on using the changeset viewer.