Index: code/branches/gui/src/orxonox/Orxonox.cc
===================================================================
--- code/branches/gui/src/orxonox/Orxonox.cc	(revision 1636)
+++ code/branches/gui/src/orxonox/Orxonox.cc	(revision 1638)
@@ -22,6 +22,7 @@
  *   Author:
  *      Reto Grieder
+ *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007
  *   Co-authors:
- *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007
+ *      ...
  *
  */
@@ -38,4 +39,5 @@
 //****** STD *******
 #include <deque>
+#include <cassert>
 
 //****** OGRE ******
@@ -50,12 +52,15 @@
 // util
 //#include "util/Sleep.h"
-#include "util/ArgReader.h"
 
 // core
 #include "core/ConfigFileManager.h"
+#include "core/ConfigValueIncludes.h"
 #include "core/ConsoleCommand.h"
 #include "core/Debug.h"
 #include "core/Loader.h"
+#include "core/Exception.h"
 #include "core/input/InputManager.h"
+#include "core/input/SimpleInputState.h"
+#include "core/input/KeyBinder.h"
 #include "core/TclBind.h"
 #include "core/Core.h"
@@ -69,9 +74,9 @@
 
 // objects and tools
-#include "overlays/OverlayGroup.h"
 #include "overlays/console/InGameConsole.h"
 #include "objects/Tickable.h"
 #include "objects/Backlight.h"
 #include "tools/ParticleInterface.h"
+#include "gui/GUIManager.h"
 
 #include "GraphicsEngine.h"
@@ -85,7 +90,8 @@
 namespace orxonox
 {
-  SetConsoleCommandShortcut(Orxonox, exit).setKeybindMode(KeybindMode::OnPress);
-  SetConsoleCommandShortcut(Orxonox, slomo).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0).setAxisParamIndex(0).setIsAxisRelative(false);
-  SetConsoleCommandShortcut(Orxonox, setTimeFactor).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0);
+  SetConsoleCommand(Orxonox, exit, true).setKeybindMode(KeybindMode::OnPress);
+  SetConsoleCommand(Orxonox, slomo, true).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0).setAxisParamIndex(0).setIsAxisRelative(false);
+  SetConsoleCommand(Orxonox, setTimeFactor, true).setAccessLevel(AccessLevel::Offline).setDefaultValue(0, 1.0);
+  SetConsoleCommand(Orxonox, loadGame, true).setAccessLevel(AccessLevel::User).setDefaultValue(0, "standalone");
 
   /**
@@ -106,8 +112,11 @@
     , bAbort_(false)
     , timefactor_(1.0f)
-    , mode_(STANDALONE)
-    , serverIp_("")
-    , serverPort_(NETWORK_PORT)
-  {
+    , mode_(GameMode::GM_Unspecified)
+    , debugRefreshTime_(0.0f)
+  {
+    RegisterRootObject(Orxonox);
+
+    assert(singletonRef_s == 0);
+    singletonRef_s = this;
   }
 
@@ -118,5 +127,5 @@
   {
     // keep in mind: the order of deletion is very important!
-    Loader::unload(startLevel_);
+    Loader::unload();
     if (this->startLevel_)
       delete this->startLevel_;
@@ -136,5 +145,7 @@
       delete this->timer_;
     InputManager::destroy();
-    GraphicsEngine::getSingleton().destroy();
+
+    if (this->ogre_)
+      delete ogre_;
 
     if (network::Client::getSingleton())
@@ -142,4 +153,11 @@
     if (server_g)
       delete network::Server::getSingleton();
+
+    singletonRef_s = 0;
+  }
+
+  void Orxonox::setConfigValues()
+  {
+    SetConfigValue(debugRefreshTime_, 0.2).description("Sets the time interval at which average fps, etc. get updated.");
   }
 
@@ -157,19 +175,8 @@
    * @return singleton reference
    */
-  Orxonox* Orxonox::getSingleton()
-  {
-    if (!singletonRef_s)
-      singletonRef_s = new Orxonox();
-    return singletonRef_s;
-  }
-
-  /**
-    @brief Destroys the Orxonox singleton.
-  */
-  void Orxonox::destroySingleton()
-  {
-    if (singletonRef_s)
-      delete singletonRef_s;
-    singletonRef_s = 0;
+  Orxonox& Orxonox::getSingleton()
+  {
+    assert(singletonRef_s);
+    return *singletonRef_s;
   }
 
@@ -179,20 +186,19 @@
   void Orxonox::setTimeFactor(float factor)
   {
-    float change = factor / Orxonox::getSingleton()->getTimeFactor();
-    Orxonox::getSingleton()->timefactor_ = factor;
+    float change = factor / Orxonox::getSingleton().getTimeFactor();
+    Orxonox::getSingleton().timefactor_ = factor;
     for (Iterator<ParticleInterface> it = ObjectList<ParticleInterface>::begin(); it; ++it)
         it->setSpeedFactor(it->getSpeedFactor() * change);
 
     for (Iterator<Backlight> it = ObjectList<Backlight>::begin(); it; ++it)
-        it->setTimeFactor(Orxonox::getSingleton()->getTimeFactor());
-  }
-
-  /**
-   * initialization of Orxonox object
-   * @param argc argument counter
-   * @param argv list of argumenst
+        it->setTimeFactor(Orxonox::getSingleton().getTimeFactor());
+  }
+
+
+  /**
+   * Starts the whole Game.
    * @param path path to config (in home dir or something)
    */
-  bool Orxonox::init(int argc, char **argv)
+  void Orxonox::start()
   {
 #ifdef _DEBUG
@@ -203,130 +209,138 @@
     Factory::createClassHierarchy();
 
-    std::string mode;
-    std::string tempDataPath;
-
-    ArgReader ar(argc, argv);
-    ar.checkArgument("mode", &mode, false);
-    ar.checkArgument("data", &tempDataPath, false);
-    ar.checkArgument("ip",   &serverIp_, false);
-    ar.checkArgument("port", &serverPort_, false);
-    if(ar.errorHandling())
-    {
-      COUT(1) << "Error while parsing command line arguments" << std::endl;
-      COUT(1) << ar.getErrorString();
-      COUT(0) << "Usage:" << std::endl << "orxonox [mode client|server|dedicated|standalone] "
-        << "[--data PATH] [--ip IP] [--port PORT]" << std::endl;
-      return false;
-    }
-
-    if (mode == "client")
-      mode_ = CLIENT;
-    else if (mode == "server")
-      mode_ = SERVER;
-    else if (mode == "dedicated")
-      mode_ = DEDICATED;
-    else
-    {
-      if (mode == "")
-        mode = "standalone";
-      if (mode != "standalone")
+    setConfigValues();
+
+    const Settings::CommandLineArgument* mode = Settings::getCommandLineArgument("mode");
+    assert(mode);
+    if (!mode->bHasDefaultValue_)
+    {
+      Settings::setGameMode(mode->value_);
+      this->mode_ = Settings::getGameMode();
+    }
+    COUT(3) << "Orxonox: Game mode is " << mode_.name << "." << std::endl;
+
+    const Settings::CommandLineArgument* dataPath = Settings::getCommandLineArgument("dataPath");
+    assert(dataPath);
+    if (!dataPath->bHasDefaultValue_)
+    {
+      if (*dataPath->value_.getString().end() != '/' && *dataPath->value_.getString().end() != '\\')
+        Settings::tsetDataPath(dataPath->value_.getString() + "/");
+      else
+        Settings::tsetDataPath(dataPath->value_.getString());
+    }
+
+    try
+    {
+        // initialise TCL
+        TclBind::getInstance().setDataPath(Settings::getDataPath());
+
+        ogre_ = new GraphicsEngine();
+        ogre_->setup();       // creates ogre root and other essentials
+
+        if (mode_.showsGraphics)
+        {
+          ogre_->loadRenderer();    // creates the render window
+
+          // TODO: Spread this so that this call only initialises things needed for the Console and GUI
+          ogre_->initialiseResources();
+
+          // Calls the InputManager which sets up the input devices.
+          // The render window width and height are used to set up the mouse movement.
+          InputManager::initialise(ogre_->getWindowHandle(),
+                ogre_->getWindowWidth(), ogre_->getWindowHeight(), true, true, true);
+          KeyBinder* keyBinder = new KeyBinder();
+          InputManager::createSimpleInputState("game", 20)->setHandler(keyBinder);
+
+          // Load the InGameConsole
+          InGameConsole::getInstance().initialise();
+
+          // load the CEGUI interface
+          GUIManager::getInstance().initialise();
+        }
+
+        bool showGUI = true;
+        if (mode_.mode != GameMode::Unspecified)
+        {
+          showGUI = false;
+          // a game mode was specified with the command line
+          // we therefore load the game and level directly
+
+          if (!loadLevel(this->mode_))
+          {
+            COUT(1) << "Loading with predefined mode failed. Showing main menu." << std::endl;
+            showGUI = true;
+            mode_ = GameMode::GM_Unspecified;
+          }
+        }
+        
+        if (showGUI)
+        {
+          // show main menu
+          //GraphicsEngine::getSingleton().createNewScene();
+          GUIManager::getInstance().showGUI("MainMenu", true);
+        }
+    }
+    catch (std::exception& ex)
+    {
+      COUT(1) << ex.what() << std::endl;
+      COUT(1) << "Loading sequence aborted." << std::endl;
+      return;
+    }
+
+    modeRequest_ = mode_;
+    // here happens the game
+    startRenderLoop();
+
+    if (mode_.mode == GameMode::Client)
+      network::Client::getSingleton()->closeConnection();
+
+    if (mode_.hasServer)
+      server_g->close();
+  }
+
+  void Orxonox::loadGame(const std::string& name)
+  {
+      const GameMode& mode = Settings::getGameMode(name);
+      if (mode.mode == GameMode::None)
+          return;
+
+      getSingleton().modeRequest_ = mode;
+  }
+
+  bool Orxonox::loadLevel(const GameMode& mode)
+  {
+      bool success = true;
+
+      if (mode.showsGraphics)
       {
-        COUT(2) << "Warning: mode \"" << mode << "\" doesn't exist. "
-          << "Defaulting to standalone" << std::endl;
-        mode = "standalone";
+        // create Ogre SceneManager for the level
+        ogre_->createNewScene();
+
+        if (!loadPlayground())
+            return false;
       }
-      mode_ = STANDALONE;
-    }
-    COUT(3) << "Orxonox: Mode is " << mode << "." << std::endl;
-
-    if (tempDataPath != "")
-    {
-      if (tempDataPath[tempDataPath.size() - 1] != '/')
-        tempDataPath += "/";
-      Settings::tsetDataPath(tempDataPath);
-    }
-
-    // initialise TCL
-    TclBind::getInstance().setDataPath(Settings::getDataPath());
-
-    //if (mode_ == DEDICATED)
-      // TODO: decide what to do here
-    //else
-
-    // for playable server, client and standalone, the startup
-    // procedure until the GUI is identical
-
-    ogre_ = &GraphicsEngine::getSingleton();
-    if (!ogre_->setup())       // creates ogre root and other essentials
-      return false;
-
-    return true;
-  }
-
-  /**
-   * start modules
-   */
-  bool Orxonox::start()
-  {
-    if (mode_ == DEDICATED)
-    {
-      // do something else
-    }
-    else
-    { // not dedicated server
-      if (!ogre_->loadRenderer())    // creates the render window
-        return false;
-
-      // TODO: Spread this so that this call only initialises things needed for the Console
-      if (!ogre_->initialiseResources())
-        return false;
-
-      // Load the InGameConsole
-      InGameConsole::getInstance().initialise();
-
-      // Calls the InputManager which sets up the input devices.
-      // The render window width and height are used to set up the mouse movement.
-      if (!InputManager::initialise(ogre_->getWindowHandle(),
-            ogre_->getWindowWidth(), ogre_->getWindowHeight(), true, true, true))
-        return false;
-
-      // TOOD: load the GUI here
-      // set InputManager to GUI mode
-      InputManager::setInputState(InputManager::IS_GUI);
-      // TODO: run GUI here
-
-      // The following lines depend very much on the GUI output, so they're probably misplaced here..
-
-      InputManager::setInputState(InputManager::IS_NONE);
-
-      // create Ogre SceneManager
-      ogre_->createNewScene();
-
-      if (!loadPlayground())
-        return false;
-    }
-
-    switch (mode_)
-    {
-    case SERVER:
-      if (!serverLoad())
-        return false;
-      break;
-    case CLIENT:
-      if (!clientLoad())
-        return false;
-      break;
-    case DEDICATED:
-      if (!serverLoad())
-        return false;
-      break;
-    default:
-      if (!standaloneLoad())
-        return false;
-    }
-
-    InputManager::setInputState(InputManager::IS_NORMAL);
-
-    return startRenderLoop();
+
+      switch (mode.mode)
+      {
+      case GameMode::Server:
+        success &= serverLoad();
+        break;
+      case GameMode::Client:
+        success &= clientLoad();
+        break;
+      case GameMode::Dedicated:
+        success &= serverLoad();
+        break;
+      case GameMode::Standalone:
+        success &= standaloneLoad();
+        break;
+      default: // never happens
+          assert(false);
+      }
+      
+      if (success)
+        InputManager::requestEnterState("game");
+
+      return success;
   }
 
@@ -337,21 +351,21 @@
   bool Orxonox::loadPlayground()
   {
-    // Init audio
-    //auMan_ = new audio::AudioManager();
-    //auMan_->ambientAdd("a1");
-    //auMan_->ambientAdd("a2");
-    //auMan_->ambientAdd("a3");
-    //auMan->ambientAdd("ambient1");
-    //auMan_->ambientStart();
+    // Start the Radar
+    this->radar_ = new Radar();
 
     // Load the HUD
     COUT(3) << "Orxonox: Loading HUD" << std::endl;
     hud_ = new Level(Settings::getDataPath() + "overlay/hud.oxo");
-    Loader::load(hud_);
-
-    // Start the Radar
-    this->radar_ = new Radar();
-
-    return true;
+    return Loader::load(hud_);
+  }
+
+  /**
+   * Helper method to load a level.
+   */
+  bool Orxonox::loadScene()
+  {
+    COUT(0) << "Loading level..." << std::endl;
+    startLevel_ = new Level(Settings::getDataPath() + "levels/sample.oxw");
+    return Loader::open(startLevel_);
   }
 
@@ -363,6 +377,8 @@
     COUT(0) << "Loading level in server mode" << std::endl;
 
+    assert(Settings::getCommandLineArgument("port"));
+    int serverPort = Settings::getCommandLineArgument("port")->value_;
     //server_g = new network::Server(serverPort_);
-    server_g = network::Server::createSingleton(serverPort_);
+    server_g = network::Server::createSingleton(serverPort);
 
     if (!loadScene())
@@ -381,9 +397,13 @@
     COUT(0) << "Loading level in client mode" << std::endl;\
 
-    if (serverIp_.compare("") == 0)
+    assert(Settings::getCommandLineArgument("port"));
+    assert(Settings::getCommandLineArgument("ip"));
+    int serverPort = Settings::getCommandLineArgument("port")->value_;
+    std::string serverIP = Settings::getCommandLineArgument("ip")->value_;
+
+    if (serverIP.compare("") == 0)
       client_g = network::Client::createSingleton();
     else
-
-      client_g = network::Client::createSingleton(serverIp_, serverPort_);
+      client_g = network::Client::createSingleton(serverIP, serverPort);
 
     if(!client_g->establishConnection())
@@ -408,33 +428,19 @@
 
   /**
-   * Helper method to load a level.
-   */
-  bool Orxonox::loadScene()
-  {
-    startLevel_ = new Level("levels/sample.oxw");
-    Loader::open(startLevel_);
-
-    return true;
-  }
-
-
-  /**
     Main loop of the orxonox game.
-    About the loop: The design is almost exactly like the one in ogre, so that
-    if any part of ogre registers a framelisteners, it will still behave
-    correctly. Furthermore the time smoothing feature from ogre has been
-    implemented too. If turned on (see orxonox constructor), it will calculate
-    the dt_n by means of the recent most dt_n-1, dt_n-2, etc.
+    We use the Ogre::Timer to measure time since it uses the most precise
+    method an a platform (however the windows timer lacks time when under
+    heavy kernel load!).
+    There is a simple mechanism to measure the average time spent in our
+    ticks as it may indicate performance issues.
+    A note about the Ogre::FrameListener: Even though we don't use them,
+    they still get called. However, the delta times are not correct (except
+    for timeSinceLastFrame, which is the most important). A little research
+    as shown that there is probably only one FrameListener that doesn't even
+    need the time. So we shouldn't run into problems.
   */
-  bool Orxonox::startRenderLoop()
-  {
-    // first check whether ogre root object has been created
-    if (Ogre::Root::getSingletonPtr() == 0)
-    {
-      COUT(2) << "Orxonox Error: Could not start rendering. No Ogre root object found" << std::endl;
-      return false;
-    }
+  void Orxonox::startRenderLoop()
+  {
     Ogre::Root& ogreRoot = Ogre::Root::getSingleton();
-
 
     // use the ogre timer class to measure time.
@@ -444,6 +450,5 @@
     unsigned long frameCount = 0;
     
-    // TODO: this would very well fit into a configValue
-    const unsigned long refreshTime = 200000;
+    const unsigned long refreshTime = debugRefreshTime_ * 1000000.0f;
     unsigned long refreshStartTime = 0;
     unsigned long tickTime = 0;
@@ -454,80 +459,108 @@
     unsigned long timeAfterTick = 0;
 
+    int sleepTime = 0;
+
+    // TODO: Update time in seconds every 7 seconds to avoid any overflow (7 secs is very tight)
+
     COUT(3) << "Orxonox: Starting the main loop." << std::endl;
 
+    try
+    {
     timer_->reset();
     while (!bAbort_)
     {
-      // get current time
-      timeBeforeTickOld = timeBeforeTick;
-      timeBeforeTick    = timer_->getMicroseconds();
-      float dt = (timeBeforeTick - timeBeforeTickOld) / 1000000.0;
-
-
-      // tick the core (needs real time for input and tcl thread management)
-      Core::tick(dt);
-
-      // Call those objects that need the real time
-      for (Iterator<TickableReal> it = ObjectList<TickableReal>::start(); it; ++it)
-        it->tick(dt);
-      // Call the scene objects
-      for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; ++it)
-        it->tick(dt * this->timefactor_);
-
-      // call server/client with normal dt
-      if (client_g)
-        client_g->tick(dt * this->timefactor_);
-      if (server_g)
-        server_g->tick(dt * this->timefactor_);
-
-
-      // get current time once again
-      timeAfterTick = timer_->getMicroseconds();
-
-      tickTime += timeAfterTick - timeBeforeTick;
-      if (timeAfterTick > refreshStartTime + refreshTime)
-      {
-        GraphicsEngine::getSingleton().setAverageTickTime(
-            (float)tickTime * 0.001 / (frameCount - oldFrameCount));
-        GraphicsEngine::getSingleton().setAverageFramesPerSecond(
-            (float)(frameCount - oldFrameCount) / (timeAfterTick - refreshStartTime) * 1000000.0);
-        oldFrameCount = frameCount;
-        tickTime = 0;
-        refreshStartTime = timeAfterTick;
-      }
-
-
-      // don't forget to call _fireFrameStarted in ogre to make sure
-      // everything goes smoothly
-      Ogre::FrameEvent evt;
-      evt.timeSinceLastFrame = dt;
-      evt.timeSinceLastEvent = dt; // note: same time, but shouldn't matter anyway
-      ogreRoot._fireFrameStarted(evt);
-
-      if (mode_ != DEDICATED)
-      {
-        // Pump messages in all registered RenderWindows
-        // This calls the WindowEventListener objects.
-        Ogre::WindowEventUtilities::messagePump();
-        // make sure the window stays active even when not focused
-        // (probably only necessary on windows)
-        GraphicsEngine::getSingleton().setWindowActivity(true);
-
-        // render
-        ogreRoot._updateAllRenderTargets();
-      }
-
-      // again, just to be sure ogre works fine
-      ogreRoot._fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
-
-      ++frameCount;
-    }
-
-    if (mode_ == CLIENT)
-      network::Client::getSingleton()->closeConnection();
-    else if (mode_ == SERVER)
-      server_g->close();
-
-    return true;
+        // get current time
+        timeBeforeTickOld = timeBeforeTick;
+        timeBeforeTick    = timer_->getMicroseconds();
+        float dt = (timeBeforeTick - timeBeforeTickOld) / 1000000.0;
+
+        // check whether we have to load a game
+        if (mode_.mode != modeRequest_.mode && mode_.mode == GameMode::Unspecified)
+        {
+            this->loadLevel(modeRequest_);
+            this->modeRequest_ = GameMode::GM_None;
+        }
+
+
+        // tick the core (needs real time for input and tcl thread management)
+        Core::tick(dt);
+
+        // Call those objects that need the real time
+        for (Iterator<TickableReal> it = ObjectList<TickableReal>::start(); it; ++it)
+          it->tick(dt);
+        // Call the scene objects
+        for (Iterator<Tickable> it = ObjectList<Tickable>::start(); it; ++it)
+          it->tick(dt * this->timefactor_);
+
+        // call server/client with normal dt
+        if (client_g)
+          client_g->tick(dt * this->timefactor_);
+        if (server_g)
+          server_g->tick(dt * this->timefactor_);
+
+
+        // get current time once again
+        timeAfterTick = timer_->getMicroseconds();
+
+        tickTime += timeAfterTick - timeBeforeTick;
+        if (timeAfterTick > refreshStartTime + refreshTime)
+        {
+          GraphicsEngine::getSingleton().setAverageTickTime(
+              (float)tickTime * 0.001 / (frameCount - oldFrameCount));
+          float avgFPS = (float)(frameCount - oldFrameCount) / (timeAfterTick - refreshStartTime) * 1000000.0;
+          GraphicsEngine::getSingleton().setAverageFramesPerSecond(avgFPS);
+
+          if (avgFPS > 60.0)
+            sleepTime++;
+          else
+            sleepTime--;
+          if (sleepTime < 0)
+              sleepTime = 0;
+
+          oldFrameCount = frameCount;
+          tickTime = 0;
+          refreshStartTime = timeAfterTick;
+        }
+
+        // do some sleeping when the frameRate is over 60
+        if (sleepTime > 0)
+          msleep(sleepTime);
+
+
+        // don't forget to call _fireFrameStarted in ogre to make sure
+        // everything goes smoothly
+        Ogre::FrameEvent evt;
+        evt.timeSinceLastFrame = dt;
+        evt.timeSinceLastEvent = dt; // note: same time, but shouldn't matter anyway
+        ogreRoot._fireFrameStarted(evt);
+
+        if (mode_.showsGraphics)
+        {
+          // Pump messages in all registered RenderWindows
+          // This calls the WindowEventListener objects.
+          Ogre::WindowEventUtilities::messagePump();
+          // make sure the window stays active even when not focused
+          // (probably only necessary on windows)
+          GraphicsEngine::getSingleton().setWindowActivity(true);
+
+          // tick CEGUI
+          GUIManager::getInstance().tick(dt);
+
+          // render
+          ogreRoot._updateAllRenderTargets();
+        }
+
+        // again, just to be sure ogre works fine
+        ogreRoot._fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
+
+        ++frameCount;
+    }
+    }
+    catch (std::exception& ex)
+    {
+      // something went wrong.
+      COUT(1) << ex.what() << std::endl;
+      COUT(1) << "Main loop was stopped by an unhandled exception. Shutting down." << std::endl;
+    }
   }
 }
