| [1038] | 1 | /* | 
|---|
| [1293] | 2 |  *   ORXONOX - the hottest 3D action shooter ever to exist | 
|---|
| [1056] | 3 |  *                    > www.orxonox.net < | 
|---|
| [1038] | 4 |  * | 
|---|
 | 5 |  * | 
|---|
 | 6 |  *   License notice: | 
|---|
 | 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. | 
|---|
 | 21 |  * | 
|---|
 | 22 |  *   Author: | 
|---|
| [1535] | 23 |  *      Reto Grieder | 
|---|
 | 24 |  *   Co-authors: | 
|---|
| [1038] | 25 |  *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007 | 
|---|
 | 26 |  * | 
|---|
 | 27 |  */ | 
|---|
 | 28 |  | 
|---|
 | 29 | /** | 
|---|
 | 30 |  @file | 
|---|
 | 31 |  @brief Orxonox Main Class | 
|---|
 | 32 |  */ | 
|---|
 | 33 |  | 
|---|
 | 34 | // Precompiled Headers | 
|---|
 | 35 | #include "OrxonoxStableHeaders.h" | 
|---|
| [1039] | 36 | #include "Orxonox.h" | 
|---|
| [1038] | 37 |  | 
|---|
 | 38 | //****** STD ******* | 
|---|
 | 39 | #include <deque> | 
|---|
 | 40 |  | 
|---|
 | 41 | //****** OGRE ****** | 
|---|
 | 42 | #include <OgreFrameListener.h> | 
|---|
 | 43 | #include <OgreOverlay.h> | 
|---|
 | 44 | #include <OgreOverlayManager.h> | 
|---|
 | 45 | #include <OgreRoot.h> | 
|---|
 | 46 | #include <OgreTimer.h> | 
|---|
 | 47 | #include <OgreWindowEventUtilities.h> | 
|---|
 | 48 |  | 
|---|
 | 49 | //***** ORXONOX **** | 
|---|
 | 50 | // util | 
|---|
 | 51 | //#include "util/Sleep.h" | 
|---|
 | 52 | #include "util/ArgReader.h" | 
|---|
 | 53 |  | 
|---|
| [1293] | 54 | // core | 
|---|
| [1054] | 55 | #include "core/ConfigFileManager.h" | 
|---|
| [1293] | 56 | #include "core/ConsoleCommand.h" | 
|---|
| [1038] | 57 | #include "core/Debug.h" | 
|---|
 | 58 | #include "core/Loader.h" | 
|---|
| [1535] | 59 | #include "core/input/InputManager.h" | 
|---|
| [1637] | 60 | #include "core/input/SimpleInputState.h" | 
|---|
 | 61 | #include "core/input/KeyBinder.h" | 
|---|
| [1293] | 62 | #include "core/TclBind.h" | 
|---|
| [1535] | 63 | #include "core/Core.h" | 
|---|
| [1038] | 64 |  | 
|---|
 | 65 | // audio | 
|---|
 | 66 | #include "audio/AudioManager.h" | 
|---|
 | 67 |  | 
|---|
 | 68 | // network | 
|---|
 | 69 | #include "network/Server.h" | 
|---|
 | 70 | #include "network/Client.h" | 
|---|
 | 71 |  | 
|---|
 | 72 | // objects and tools | 
|---|
| [1629] | 73 | #include "overlays/OverlayGroup.h" | 
|---|
 | 74 | #include "overlays/console/InGameConsole.h" | 
|---|
| [1535] | 75 | #include "objects/Tickable.h" | 
|---|
| [1629] | 76 | #include "objects/Backlight.h" | 
|---|
 | 77 | #include "tools/ParticleInterface.h" | 
|---|
| [1038] | 78 |  | 
|---|
| [1502] | 79 | #include "GraphicsEngine.h" | 
|---|
| [1535] | 80 | #include "Settings.h" | 
|---|
| [1629] | 81 | #include "Radar.h" | 
|---|
| [1502] | 82 |  | 
|---|
| [1038] | 83 | // globals for the server or client | 
|---|
| [1629] | 84 | static network::Client *client_g = 0; | 
|---|
 | 85 | static network::Server *server_g = 0; | 
|---|
| [1038] | 86 |  | 
|---|
 | 87 | namespace orxonox | 
|---|
| [1293] | 88 | { | 
|---|
| [1502] | 89 |   SetConsoleCommandShortcut(Orxonox, exit).setKeybindMode(KeybindMode::OnPress); | 
|---|
 | 90 |   SetConsoleCommandShortcut(Orxonox, slomo).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0).setAxisParamIndex(0).setIsAxisRelative(false); | 
|---|
 | 91 |   SetConsoleCommandShortcut(Orxonox, setTimeFactor).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0); | 
|---|
| [1505] | 92 |  | 
|---|
| [1038] | 93 |   /** | 
|---|
 | 94 |     @brief Reference to the only instance of the class. | 
|---|
 | 95 |   */ | 
|---|
 | 96 |   Orxonox *Orxonox::singletonRef_s = 0; | 
|---|
 | 97 |  | 
|---|
 | 98 |   /** | 
|---|
| [1293] | 99 |    * Create a new instance of Orxonox. Avoid doing any actual work here. | 
|---|
| [1038] | 100 |    */ | 
|---|
| [1629] | 101 |   Orxonox::Orxonox() | 
|---|
 | 102 |     : ogre_(0) | 
|---|
 | 103 |     , startLevel_(0) | 
|---|
 | 104 |     , hud_(0) | 
|---|
 | 105 |     , radar_(0) | 
|---|
 | 106 |     //, auMan_(0) | 
|---|
 | 107 |     , timer_(0) | 
|---|
 | 108 |     , bAbort_(false) | 
|---|
 | 109 |     , timefactor_(1.0f) | 
|---|
 | 110 |     , mode_(STANDALONE) | 
|---|
 | 111 |     , serverIp_("") | 
|---|
 | 112 |     , serverPort_(NETWORK_PORT) | 
|---|
| [1038] | 113 |   { | 
|---|
 | 114 |   } | 
|---|
 | 115 |  | 
|---|
 | 116 |   /** | 
|---|
| [1293] | 117 |    * Destruct Orxonox. | 
|---|
| [1038] | 118 |    */ | 
|---|
 | 119 |   Orxonox::~Orxonox() | 
|---|
 | 120 |   { | 
|---|
 | 121 |     // keep in mind: the order of deletion is very important! | 
|---|
| [1629] | 122 |     Loader::unload(startLevel_); | 
|---|
 | 123 |     if (this->startLevel_) | 
|---|
 | 124 |       delete this->startLevel_; | 
|---|
 | 125 |  | 
|---|
 | 126 |     Loader::unload(hud_); | 
|---|
 | 127 |     if (this->hud_) | 
|---|
 | 128 |       delete this->hud_; | 
|---|
 | 129 |  | 
|---|
 | 130 |     if (this->radar_) | 
|---|
 | 131 |       delete this->radar_; | 
|---|
 | 132 |  | 
|---|
| [1038] | 133 |     Loader::close(); | 
|---|
| [1293] | 134 |     //if (this->auMan_) | 
|---|
 | 135 |     //  delete this->auMan_; | 
|---|
| [1629] | 136 |     InGameConsole::getInstance().destroy(); | 
|---|
| [1038] | 137 |     if (this->timer_) | 
|---|
 | 138 |       delete this->timer_; | 
|---|
| [1637] | 139 |     dynamic_cast<SimpleInputState*>(InputManager::getState("game"))->removeAndDestroyAllHandlers(); | 
|---|
| [1629] | 140 |     InputManager::destroy(); | 
|---|
| [1038] | 141 |     GraphicsEngine::getSingleton().destroy(); | 
|---|
 | 142 |  | 
|---|
| [1293] | 143 |     if (network::Client::getSingleton()) | 
|---|
 | 144 |       network::Client::destroySingleton(); | 
|---|
| [1038] | 145 |     if (server_g) | 
|---|
| [1534] | 146 |       delete network::Server::getSingleton(); | 
|---|
| [1038] | 147 |   } | 
|---|
 | 148 |  | 
|---|
 | 149 |  | 
|---|
 | 150 |   /** | 
|---|
 | 151 |     Asks the mainloop nicely to abort. | 
|---|
 | 152 |   */ | 
|---|
 | 153 |   void Orxonox::abortRequest() | 
|---|
 | 154 |   { | 
|---|
| [1293] | 155 |     COUT(3) << "Orxonox: Abort requested." << std::endl; | 
|---|
| [1038] | 156 |     bAbort_ = true; | 
|---|
 | 157 |   } | 
|---|
 | 158 |  | 
|---|
 | 159 |   /** | 
|---|
| [1293] | 160 |    * @return singleton reference | 
|---|
| [1038] | 161 |    */ | 
|---|
 | 162 |   Orxonox* Orxonox::getSingleton() | 
|---|
 | 163 |   { | 
|---|
 | 164 |     if (!singletonRef_s) | 
|---|
 | 165 |       singletonRef_s = new Orxonox(); | 
|---|
 | 166 |     return singletonRef_s; | 
|---|
 | 167 |   } | 
|---|
 | 168 |  | 
|---|
 | 169 |   /** | 
|---|
 | 170 |     @brief Destroys the Orxonox singleton. | 
|---|
 | 171 |   */ | 
|---|
 | 172 |   void Orxonox::destroySingleton() | 
|---|
 | 173 |   { | 
|---|
 | 174 |     if (singletonRef_s) | 
|---|
 | 175 |       delete singletonRef_s; | 
|---|
 | 176 |     singletonRef_s = 0; | 
|---|
 | 177 |   } | 
|---|
 | 178 |  | 
|---|
 | 179 |   /** | 
|---|
| [1629] | 180 |     @brief Changes the speed of Orxonox | 
|---|
 | 181 |   */ | 
|---|
 | 182 |   void Orxonox::setTimeFactor(float factor) | 
|---|
 | 183 |   { | 
|---|
 | 184 |     float change = factor / Orxonox::getSingleton()->getTimeFactor(); | 
|---|
 | 185 |     Orxonox::getSingleton()->timefactor_ = factor; | 
|---|
 | 186 |     for (Iterator<ParticleInterface> it = ObjectList<ParticleInterface>::begin(); it; ++it) | 
|---|
 | 187 |         it->setSpeedFactor(it->getSpeedFactor() * change); | 
|---|
 | 188 |  | 
|---|
 | 189 |     for (Iterator<Backlight> it = ObjectList<Backlight>::begin(); it; ++it) | 
|---|
 | 190 |         it->setTimeFactor(Orxonox::getSingleton()->getTimeFactor()); | 
|---|
 | 191 |   } | 
|---|
 | 192 |  | 
|---|
 | 193 |   /** | 
|---|
| [1038] | 194 |    * initialization of Orxonox object | 
|---|
 | 195 |    * @param argc argument counter | 
|---|
 | 196 |    * @param argv list of argumenst | 
|---|
 | 197 |    * @param path path to config (in home dir or something) | 
|---|
 | 198 |    */ | 
|---|
| [1535] | 199 |   bool Orxonox::init(int argc, char **argv) | 
|---|
| [1038] | 200 |   { | 
|---|
| [1535] | 201 | #ifdef _DEBUG | 
|---|
 | 202 |     ConfigFileManager::getSingleton()->setFile(CFT_Settings, "orxonox_d.ini"); | 
|---|
 | 203 | #else | 
|---|
 | 204 |     ConfigFileManager::getSingleton()->setFile(CFT_Settings, "orxonox.ini"); | 
|---|
 | 205 | #endif | 
|---|
 | 206 |     Factory::createClassHierarchy(); | 
|---|
 | 207 |  | 
|---|
| [1038] | 208 |     std::string mode; | 
|---|
| [1535] | 209 |     std::string tempDataPath; | 
|---|
| [1038] | 210 |  | 
|---|
 | 211 |     ArgReader ar(argc, argv); | 
|---|
| [1535] | 212 |     ar.checkArgument("mode", &mode, false); | 
|---|
 | 213 |     ar.checkArgument("data", &tempDataPath, false); | 
|---|
 | 214 |     ar.checkArgument("ip",   &serverIp_, false); | 
|---|
 | 215 |     ar.checkArgument("port", &serverPort_, false); | 
|---|
| [1293] | 216 |     if(ar.errorHandling()) | 
|---|
| [1535] | 217 |     { | 
|---|
 | 218 |       COUT(1) << "Error while parsing command line arguments" << std::endl; | 
|---|
 | 219 |       COUT(1) << ar.getErrorString(); | 
|---|
 | 220 |       COUT(0) << "Usage:" << std::endl << "orxonox [mode client|server|dedicated|standalone] " | 
|---|
 | 221 |         << "[--data PATH] [--ip IP] [--port PORT]" << std::endl; | 
|---|
| [1293] | 222 |       return false; | 
|---|
| [1535] | 223 |     } | 
|---|
| [1293] | 224 |  | 
|---|
 | 225 |     if (mode == "client") | 
|---|
| [1038] | 226 |       mode_ = CLIENT; | 
|---|
| [1293] | 227 |     else if (mode == "server") | 
|---|
| [1038] | 228 |       mode_ = SERVER; | 
|---|
| [1502] | 229 |     else if (mode == "dedicated") | 
|---|
 | 230 |       mode_ = DEDICATED; | 
|---|
| [1293] | 231 |     else | 
|---|
 | 232 |     { | 
|---|
| [1535] | 233 |       if (mode == "") | 
|---|
 | 234 |         mode = "standalone"; | 
|---|
 | 235 |       if (mode != "standalone") | 
|---|
 | 236 |       { | 
|---|
 | 237 |         COUT(2) << "Warning: mode \"" << mode << "\" doesn't exist. " | 
|---|
 | 238 |           << "Defaulting to standalone" << std::endl; | 
|---|
 | 239 |         mode = "standalone"; | 
|---|
 | 240 |       } | 
|---|
| [1038] | 241 |       mode_ = STANDALONE; | 
|---|
 | 242 |     } | 
|---|
| [1293] | 243 |     COUT(3) << "Orxonox: Mode is " << mode << "." << std::endl; | 
|---|
| [1038] | 244 |  | 
|---|
| [1535] | 245 |     if (tempDataPath != "") | 
|---|
 | 246 |     { | 
|---|
 | 247 |       if (tempDataPath[tempDataPath.size() - 1] != '/') | 
|---|
 | 248 |         tempDataPath += "/"; | 
|---|
 | 249 |       Settings::tsetDataPath(tempDataPath); | 
|---|
 | 250 |     } | 
|---|
 | 251 |  | 
|---|
 | 252 |     // initialise TCL | 
|---|
 | 253 |     TclBind::getInstance().setDataPath(Settings::getDataPath()); | 
|---|
 | 254 |  | 
|---|
| [1293] | 255 |     //if (mode_ == DEDICATED) | 
|---|
 | 256 |       // TODO: decide what to do here | 
|---|
 | 257 |     //else | 
|---|
| [1052] | 258 |  | 
|---|
| [1293] | 259 |     // for playable server, client and standalone, the startup | 
|---|
 | 260 |     // procedure until the GUI is identical | 
|---|
| [1052] | 261 |  | 
|---|
| [1293] | 262 |     ogre_ = &GraphicsEngine::getSingleton(); | 
|---|
| [1535] | 263 |     if (!ogre_->setup())       // creates ogre root and other essentials | 
|---|
| [1293] | 264 |       return false; | 
|---|
| [1052] | 265 |  | 
|---|
| [1293] | 266 |     return true; | 
|---|
| [1038] | 267 |   } | 
|---|
| [1052] | 268 |  | 
|---|
| [1038] | 269 |   /** | 
|---|
 | 270 |    * start modules | 
|---|
 | 271 |    */ | 
|---|
| [1293] | 272 |   bool Orxonox::start() | 
|---|
| [1038] | 273 |   { | 
|---|
| [1502] | 274 |     if (mode_ == DEDICATED) | 
|---|
 | 275 |     { | 
|---|
 | 276 |       // do something else | 
|---|
 | 277 |     } | 
|---|
 | 278 |     else | 
|---|
 | 279 |     { // not dedicated server | 
|---|
 | 280 |       if (!ogre_->loadRenderer())    // creates the render window | 
|---|
 | 281 |         return false; | 
|---|
| [1293] | 282 |  | 
|---|
| [1629] | 283 |       // TODO: Spread this so that this call only initialises things needed for the Console | 
|---|
 | 284 |       if (!ogre_->initialiseResources()) | 
|---|
 | 285 |         return false; | 
|---|
 | 286 |  | 
|---|
 | 287 |       // Load the InGameConsole | 
|---|
 | 288 |       InGameConsole::getInstance().initialise(); | 
|---|
 | 289 |  | 
|---|
| [1502] | 290 |       // Calls the InputManager which sets up the input devices. | 
|---|
 | 291 |       // The render window width and height are used to set up the mouse movement. | 
|---|
 | 292 |       if (!InputManager::initialise(ogre_->getWindowHandle(), | 
|---|
 | 293 |             ogre_->getWindowWidth(), ogre_->getWindowHeight(), true, true, true)) | 
|---|
 | 294 |         return false; | 
|---|
| [1637] | 295 |       KeyBinder* keyBinder = new KeyBinder(); | 
|---|
 | 296 |       InputManager::createSimpleInputState("game", 20)->setHandler(keyBinder); | 
|---|
| [1293] | 297 |  | 
|---|
| [1502] | 298 |       // TOOD: load the GUI here | 
|---|
 | 299 |       // set InputManager to GUI mode | 
|---|
 | 300 |       // TODO: run GUI here | 
|---|
| [1293] | 301 |  | 
|---|
| [1502] | 302 |       // The following lines depend very much on the GUI output, so they're probably misplaced here.. | 
|---|
| [1293] | 303 |  | 
|---|
| [1637] | 304 |       keyBinder->loadBindings(); | 
|---|
 | 305 |       InputManager::requestEnterState("game"); | 
|---|
| [1293] | 306 |  | 
|---|
| [1502] | 307 |       // create Ogre SceneManager | 
|---|
 | 308 |       ogre_->createNewScene(); | 
|---|
| [1293] | 309 |  | 
|---|
| [1502] | 310 |       if (!loadPlayground()) | 
|---|
 | 311 |         return false; | 
|---|
 | 312 |     } | 
|---|
| [1293] | 313 |  | 
|---|
 | 314 |     switch (mode_) | 
|---|
 | 315 |     { | 
|---|
 | 316 |     case SERVER: | 
|---|
 | 317 |       if (!serverLoad()) | 
|---|
 | 318 |         return false; | 
|---|
 | 319 |       break; | 
|---|
| [1038] | 320 |     case CLIENT: | 
|---|
| [1293] | 321 |       if (!clientLoad()) | 
|---|
 | 322 |         return false; | 
|---|
| [1038] | 323 |       break; | 
|---|
| [1502] | 324 |     case DEDICATED: | 
|---|
 | 325 |       if (!serverLoad()) | 
|---|
 | 326 |         return false; | 
|---|
 | 327 |       break; | 
|---|
| [1038] | 328 |     default: | 
|---|
| [1293] | 329 |       if (!standaloneLoad()) | 
|---|
 | 330 |         return false; | 
|---|
| [1038] | 331 |     } | 
|---|
| [1293] | 332 |  | 
|---|
 | 333 |     return startRenderLoop(); | 
|---|
| [1038] | 334 |   } | 
|---|
| [1052] | 335 |  | 
|---|
| [1293] | 336 |   /** | 
|---|
 | 337 |    * Loads everything in the scene except for the actual objects. | 
|---|
| [1629] | 338 |    * This includes HUD, audio.. | 
|---|
| [1293] | 339 |    */ | 
|---|
 | 340 |   bool Orxonox::loadPlayground() | 
|---|
 | 341 |   { | 
|---|
| [1502] | 342 |     // Init audio | 
|---|
| [1293] | 343 |     //auMan_ = new audio::AudioManager(); | 
|---|
 | 344 |     //auMan_->ambientAdd("a1"); | 
|---|
 | 345 |     //auMan_->ambientAdd("a2"); | 
|---|
 | 346 |     //auMan_->ambientAdd("a3"); | 
|---|
 | 347 |     //auMan->ambientAdd("ambient1"); | 
|---|
 | 348 |     //auMan_->ambientStart(); | 
|---|
| [1052] | 349 |  | 
|---|
| [1293] | 350 |     // Load the HUD | 
|---|
| [1629] | 351 |     COUT(3) << "Orxonox: Loading HUD" << std::endl; | 
|---|
 | 352 |     hud_ = new Level(Settings::getDataPath() + "overlay/hud.oxo"); | 
|---|
 | 353 |     Loader::load(hud_); | 
|---|
 | 354 |  | 
|---|
 | 355 |     // Start the Radar | 
|---|
 | 356 |     this->radar_ = new Radar(); | 
|---|
 | 357 |  | 
|---|
| [1293] | 358 |     return true; | 
|---|
 | 359 |   } | 
|---|
| [1052] | 360 |  | 
|---|
| [1293] | 361 |   /** | 
|---|
 | 362 |    * Level loading method for server mode. | 
|---|
 | 363 |    */ | 
|---|
 | 364 |   bool Orxonox::serverLoad() | 
|---|
 | 365 |   { | 
|---|
| [1629] | 366 |     COUT(0) << "Loading level in server mode" << std::endl; | 
|---|
| [1052] | 367 |  | 
|---|
| [1534] | 368 |     //server_g = new network::Server(serverPort_); | 
|---|
 | 369 |     server_g = network::Server::createSingleton(serverPort_); | 
|---|
| [1052] | 370 |  | 
|---|
| [1293] | 371 |     if (!loadScene()) | 
|---|
 | 372 |       return false; | 
|---|
| [1052] | 373 |  | 
|---|
| [1038] | 374 |     server_g->open(); | 
|---|
| [1052] | 375 |  | 
|---|
| [1293] | 376 |     return true; | 
|---|
| [1038] | 377 |   } | 
|---|
| [1052] | 378 |  | 
|---|
| [1293] | 379 |   /** | 
|---|
 | 380 |    * Level loading method for client mode. | 
|---|
 | 381 |    */ | 
|---|
 | 382 |   bool Orxonox::clientLoad() | 
|---|
 | 383 |   { | 
|---|
| [1629] | 384 |     COUT(0) << "Loading level in client mode" << std::endl;\ | 
|---|
| [1052] | 385 |  | 
|---|
| [1293] | 386 |     if (serverIp_.compare("") == 0) | 
|---|
 | 387 |       client_g = network::Client::createSingleton(); | 
|---|
 | 388 |     else | 
|---|
 | 389 |  | 
|---|
| [1502] | 390 |       client_g = network::Client::createSingleton(serverIp_, serverPort_); | 
|---|
 | 391 |  | 
|---|
 | 392 |     if(!client_g->establishConnection()) | 
|---|
 | 393 |       return false; | 
|---|
| [1293] | 394 |     client_g->tick(0); | 
|---|
 | 395 |  | 
|---|
 | 396 |     return true; | 
|---|
| [1038] | 397 |   } | 
|---|
 | 398 |  | 
|---|
| [1293] | 399 |   /** | 
|---|
 | 400 |    * Level loading method for standalone mode. | 
|---|
 | 401 |    */ | 
|---|
 | 402 |   bool Orxonox::standaloneLoad() | 
|---|
| [1038] | 403 |   { | 
|---|
| [1629] | 404 |     COUT(0) << "Loading level in standalone mode" << std::endl; | 
|---|
| [1038] | 405 |  | 
|---|
| [1293] | 406 |     if (!loadScene()) | 
|---|
 | 407 |       return false; | 
|---|
| [1038] | 408 |  | 
|---|
| [1293] | 409 |     return true; | 
|---|
| [1038] | 410 |   } | 
|---|
 | 411 |  | 
|---|
 | 412 |   /** | 
|---|
| [1293] | 413 |    * Helper method to load a level. | 
|---|
 | 414 |    */ | 
|---|
 | 415 |   bool Orxonox::loadScene() | 
|---|
| [1038] | 416 |   { | 
|---|
| [1629] | 417 |     startLevel_ = new Level("levels/sample.oxw"); | 
|---|
 | 418 |     Loader::open(startLevel_); | 
|---|
 | 419 |  | 
|---|
| [1293] | 420 |     return true; | 
|---|
| [1038] | 421 |   } | 
|---|
 | 422 |  | 
|---|
| [1293] | 423 |  | 
|---|
| [1038] | 424 |   /** | 
|---|
 | 425 |     Main loop of the orxonox game. | 
|---|
 | 426 |     About the loop: The design is almost exactly like the one in ogre, so that | 
|---|
 | 427 |     if any part of ogre registers a framelisteners, it will still behave | 
|---|
 | 428 |     correctly. Furthermore the time smoothing feature from ogre has been | 
|---|
 | 429 |     implemented too. If turned on (see orxonox constructor), it will calculate | 
|---|
 | 430 |     the dt_n by means of the recent most dt_n-1, dt_n-2, etc. | 
|---|
 | 431 |   */ | 
|---|
| [1293] | 432 |   bool Orxonox::startRenderLoop() | 
|---|
| [1038] | 433 |   { | 
|---|
 | 434 |     // first check whether ogre root object has been created | 
|---|
 | 435 |     if (Ogre::Root::getSingletonPtr() == 0) | 
|---|
 | 436 |     { | 
|---|
| [1293] | 437 |       COUT(2) << "Orxonox Error: Could not start rendering. No Ogre root object found" << std::endl; | 
|---|
 | 438 |       return false; | 
|---|
| [1038] | 439 |     } | 
|---|
| [1120] | 440 |     Ogre::Root& ogreRoot = Ogre::Root::getSingleton(); | 
|---|
| [1038] | 441 |  | 
|---|
| [1120] | 442 |  | 
|---|
| [1038] | 443 |     // use the ogre timer class to measure time. | 
|---|
 | 444 |     if (!timer_) | 
|---|
 | 445 |       timer_ = new Ogre::Timer(); | 
|---|
 | 446 |  | 
|---|
| [1629] | 447 |     unsigned long frameCount = 0; | 
|---|
| [1502] | 448 |      | 
|---|
| [1629] | 449 |     // TODO: this would very well fit into a configValue | 
|---|
 | 450 |     const unsigned long refreshTime = 200000; | 
|---|
 | 451 |     unsigned long refreshStartTime = 0; | 
|---|
 | 452 |     unsigned long tickTime = 0; | 
|---|
 | 453 |     unsigned long oldFrameCount = 0; | 
|---|
| [1502] | 454 |  | 
|---|
| [1629] | 455 |     unsigned long timeBeforeTick = 0; | 
|---|
 | 456 |     unsigned long timeBeforeTickOld = 0; | 
|---|
 | 457 |     unsigned long timeAfterTick = 0; | 
|---|
 | 458 |  | 
|---|
| [1293] | 459 |     COUT(3) << "Orxonox: Starting the main loop." << std::endl; | 
|---|
| [1629] | 460 |  | 
|---|
 | 461 |     timer_->reset(); | 
|---|
| [1502] | 462 |     while (!bAbort_) | 
|---|
 | 463 |     { | 
|---|
| [1038] | 464 |       // get current time | 
|---|
| [1629] | 465 |       timeBeforeTickOld = timeBeforeTick; | 
|---|
 | 466 |       timeBeforeTick    = timer_->getMicroseconds(); | 
|---|
 | 467 |       float dt = (timeBeforeTick - timeBeforeTickOld) / 1000000.0; | 
|---|
| [1038] | 468 |  | 
|---|
 | 469 |  | 
|---|
| [1629] | 470 |       // tick the core (needs real time for input and tcl thread management) | 
|---|
 | 471 |       Core::tick(dt); | 
|---|
| [1038] | 472 |  | 
|---|
| [1502] | 473 |       // Call those objects that need the real time | 
|---|
 | 474 |       for (Iterator<TickableReal> it = ObjectList<TickableReal>::start(); it; ++it) | 
|---|
| [1629] | 475 |         it->tick(dt); | 
|---|
| [1502] | 476 |       // Call the scene objects | 
|---|
| [1092] | 477 |       for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; ++it) | 
|---|
| [1629] | 478 |         it->tick(dt * this->timefactor_); | 
|---|
 | 479 |  | 
|---|
 | 480 |       // call server/client with normal dt | 
|---|
| [1535] | 481 |       if (client_g) | 
|---|
| [1629] | 482 |         client_g->tick(dt * this->timefactor_); | 
|---|
| [1535] | 483 |       if (server_g) | 
|---|
| [1629] | 484 |         server_g->tick(dt * this->timefactor_); | 
|---|
| [1038] | 485 |  | 
|---|
| [1629] | 486 |  | 
|---|
 | 487 |       // get current time once again | 
|---|
 | 488 |       timeAfterTick = timer_->getMicroseconds(); | 
|---|
 | 489 |  | 
|---|
 | 490 |       tickTime += timeAfterTick - timeBeforeTick; | 
|---|
 | 491 |       if (timeAfterTick > refreshStartTime + refreshTime) | 
|---|
 | 492 |       { | 
|---|
 | 493 |         GraphicsEngine::getSingleton().setAverageTickTime( | 
|---|
 | 494 |             (float)tickTime * 0.001 / (frameCount - oldFrameCount)); | 
|---|
 | 495 |         GraphicsEngine::getSingleton().setAverageFramesPerSecond( | 
|---|
 | 496 |             (float)(frameCount - oldFrameCount) / (timeAfterTick - refreshStartTime) * 1000000.0); | 
|---|
 | 497 |         oldFrameCount = frameCount; | 
|---|
 | 498 |         tickTime = 0; | 
|---|
 | 499 |         refreshStartTime = timeAfterTick; | 
|---|
 | 500 |       } | 
|---|
 | 501 |  | 
|---|
 | 502 |  | 
|---|
| [1038] | 503 |       // don't forget to call _fireFrameStarted in ogre to make sure | 
|---|
 | 504 |       // everything goes smoothly | 
|---|
| [1629] | 505 |       Ogre::FrameEvent evt; | 
|---|
 | 506 |       evt.timeSinceLastFrame = dt; | 
|---|
 | 507 |       evt.timeSinceLastEvent = dt; // note: same time, but shouldn't matter anyway | 
|---|
| [1120] | 508 |       ogreRoot._fireFrameStarted(evt); | 
|---|
| [1038] | 509 |  | 
|---|
| [1502] | 510 |       if (mode_ != DEDICATED) | 
|---|
 | 511 |       { | 
|---|
 | 512 |         // Pump messages in all registered RenderWindows | 
|---|
 | 513 |         // This calls the WindowEventListener objects. | 
|---|
 | 514 |         Ogre::WindowEventUtilities::messagePump(); | 
|---|
| [1629] | 515 |         // make sure the window stays active even when not focused | 
|---|
 | 516 |         // (probably only necessary on windows) | 
|---|
 | 517 |         GraphicsEngine::getSingleton().setWindowActivity(true); | 
|---|
| [1502] | 518 |  | 
|---|
 | 519 |         // render | 
|---|
 | 520 |         ogreRoot._updateAllRenderTargets(); | 
|---|
 | 521 |       } | 
|---|
 | 522 |  | 
|---|
| [1629] | 523 |       // again, just to be sure ogre works fine | 
|---|
 | 524 |       ogreRoot._fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted | 
|---|
| [1038] | 525 |  | 
|---|
| [1629] | 526 |       ++frameCount; | 
|---|
| [1502] | 527 |     } | 
|---|
| [1293] | 528 |  | 
|---|
| [1502] | 529 |     if (mode_ == CLIENT) | 
|---|
| [1293] | 530 |       network::Client::getSingleton()->closeConnection(); | 
|---|
| [1502] | 531 |     else if (mode_ == SERVER) | 
|---|
| [1293] | 532 |       server_g->close(); | 
|---|
| [1502] | 533 |  | 
|---|
| [1293] | 534 |     return true; | 
|---|
| [1038] | 535 |   } | 
|---|
 | 536 | } | 
|---|