Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core3/src/orxonox/GraphicsEngine.cc @ 1610

Last change on this file since 1610 was 1610, checked in by landauf, 16 years ago
  • fixed bug #1 in ConfigValueContainer (callback not being called the first time)
  • fixed another bug in XMLPort, caused by the recently added support for extern types
  • Property svn:eol-style set to native
File size: 14.6 KB
RevLine 
[612]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
[1293]3 *                    > www.orxonox.net <
[612]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
[1349]11 *   of the License, or (at your option) any later version.
12 *
[612]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
[612]24 *   Co-authors:
[1535]25 *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007, Felix Schulthess
[612]26 *
27 */
[1035]28
[612]29 /**
30    @file orxonox.cc
31    @brief Orxonox class
32  */
33
[1021]34#include "OrxonoxStableHeaders.h"
[1039]35#include "GraphicsEngine.h"
[612]36
[1538]37#include <fstream>
38
[1535]39#include <OgreConfigFile.h>
[1021]40#include <OgreException.h>
[1024]41#include <OgreLogManager.h>
[1535]42#include <OgreRoot.h>
43#include <OgreSceneManager.h>
[612]44#include <OgreTextureManager.h>
[1535]45#include <OgreViewport.h>
46
[1293]47#include "core/CoreIncludes.h"
48#include "core/ConfigValueIncludes.h"
[1591]49#include "core/Iterator.h"
[1505]50#include "core/CommandExecutor.h"
[1535]51#include "core/ConsoleCommand.h"
52#include "core/input/InputManager.h"
[1586]53#include "util/Debug.h"
[1535]54
[1502]55#include "console/InGameConsole.h"
[1564]56#include "hud/HUD.h"
[1563]57#include "tools/ParticleInterface.h"
[1535]58#include "Settings.h"
[1032]59
[612]60
61namespace orxonox {
[1032]62  /**
63    @brief Returns the singleton instance and creates it the first time.
64    @return The only instance of GraphicsEngine.
65  */
[1293]66  /*static*/ GraphicsEngine& GraphicsEngine::getSingleton()
[1032]67  {
68    static GraphicsEngine theOnlyInstance;
69    return theOnlyInstance;
70  }
71
72  /**
73    @brief Only use constructor to initialise variables and pointers!
74  */
[1293]75  GraphicsEngine::GraphicsEngine() :
76    root_(0),
77    scene_(0),
[1535]78    renderWindow_(0)
[612]79  {
[1021]80    RegisterObject(GraphicsEngine);
[1293]81
[1563]82    this->detailLevelParticle_ = 0;
83
[1021]84    this->setConfigValues();
[1293]85    CCOUT(4) << "Constructed" << std::endl;
[612]86  }
87
[1293]88  void GraphicsEngine::setConfigValues()
89  {
[1535]90    SetConfigValue(resourceFile_,    "resources.cfg").description("Location of the resources file in the data path.");
91    SetConfigValue(ogreConfigFile_,  "ogre.cfg").description("Location of the Ogre config file");
92    SetConfigValue(ogrePluginsFile_, "plugins.cfg").description("Location of the Ogre plugins file");
93    SetConfigValue(ogreLogFile_,     "ogre.log").description("Logfile for messages from Ogre. \
94                                                             Use \"\" to suppress log file creation.");
[1293]95    SetConfigValue(ogreLogLevelTrivial_ , 5).description("Corresponding orxonox debug level for ogre Trivial");
96    SetConfigValue(ogreLogLevelNormal_  , 4).description("Corresponding orxonox debug level for ogre Normal");
[1505]97    SetConfigValue(ogreLogLevelCritical_, 2).description("Corresponding orxonox debug level for ogre Critical");
[1563]98
[1610]99    SetConfigValue(detailLevelParticle_, 2).description("O: off, 1: low, 2: normal, 3: high").callback(this, &GraphicsEngine::detailLevelParticleChanged);
[1596]100  }
[1563]101
[1596]102  void GraphicsEngine::detailLevelParticleChanged()
103  {
104    for (ObjectList<ParticleInterface>::iterator it = ObjectList<ParticleInterface>::begin(); it; ++it)
105      it->detailLevelChanged(this->detailLevelParticle_);
[1293]106  }
107
[1032]108  /**
109    @brief Called after main() --> call destroyObjects()!
110  */
[612]111  GraphicsEngine::~GraphicsEngine()
112  {
[1032]113    this->destroy();
114  }
115
116  /**
117    @brief Destroys all the internal objects. Call this method when you
118           normally would call the destructor.
119  */
120  void GraphicsEngine::destroy()
121  {
[1293]122    CCOUT(4) << "Destroying objects..." << std::endl;
[1214]123    Ogre::WindowEventUtilities::removeWindowEventListener(this->renderWindow_, this);
[1024]124    if (this->root_)
[1021]125      delete this->root_;
[1032]126    this->root_ = 0;
127    this->scene_ = 0;
128    this->renderWindow_ = 0;
129    // delete the ogre log and the logManager (since we have created it).
[1052]130    if (Ogre::LogManager::getSingletonPtr() != 0)
[1024]131    {
[1052]132      Ogre::LogManager::getSingleton().getDefaultLog()->removeListener(this);
133      Ogre::LogManager::getSingleton().destroyLog(Ogre::LogManager::getSingleton().getDefaultLog());
134      delete Ogre::LogManager::getSingletonPtr();
[1024]135    }
[1293]136    CCOUT(4) << "Destroying objects done" << std::endl;
[612]137  }
138
[1024]139  /**
140    @brief Creates the Ogre Root object and sets up the ogre log.
141  */
[1535]142  bool GraphicsEngine::setup()
[612]143  {
[1293]144    CCOUT(3) << "Setting up..." << std::endl;
145    // temporary overwrite of dataPath, change ini file for permanent change
146
[1502]147// TODO: LogManager doesn't work on specific systems. The why is unknown yet.
148#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
149    // create a logManager
[1293]150    // note: If there's already a logManager, Ogre will complain by a failed assertation.
151    // but that shouldn't happen, since this is the first time to create a logManager..
152    Ogre::LogManager* logger = new Ogre::LogManager();
153    CCOUT(4) << "Ogre LogManager created" << std::endl;
[1024]154
155    // create our own log that we can listen to
[1062]156    Ogre::Log *myLog;
[1535]157    if (this->ogreLogFile_ == "")
[1024]158      myLog = logger->createLog("ogre.log", true, false, true);
159    else
[1535]160      myLog = logger->createLog(this->ogreLogFile_, true, false, false);
[1293]161    CCOUT(4) << "Ogre Log created" << std::endl;
[1024]162
[1062]163    myLog->setLogDetail(Ogre::LL_BOREME);
[1502]164    myLog->addListener(this);
165#endif
[1024]166
167    // Root will detect that we've already created a Log
[1293]168    CCOUT(4) << "Creating Ogre Root..." << std::endl;
[1502]169
[1535]170    if (ogrePluginsFile_ == "")
171    {
172      COUT(1) << "Error: Ogre plugins file set to \"\". Cannot load." << std::endl;
173      return false;
174    }
175    if (ogreConfigFile_ == "")
176    {
177      COUT(1) << "Error: Ogre config file set to \"\". Cannot load." << std::endl;
178      return false;
179    }
180    if (ogreLogFile_ == "")
181    {
182      COUT(1) << "Error: Ogre log file set to \"\". Cannot load." << std::endl;
183      return false;
184    }
[1502]185
[1535]186    try
187    {
188      root_ = new Ogre::Root(ogrePluginsFile_, ogreConfigFile_, ogreLogFile_);
189    }
190    catch (Ogre::Exception ex)
191    {
192      COUT(2) << "Error: There was an exception when creating Ogre Root." << std::endl;
193      return false;
194    }
195
196    if (!root_->getInstalledPlugins().size())
197    {
198      COUT(1) << "Error: No plugins declared. Cannot load Ogre." << std::endl;
199      COUT(0) << "Is the plugins file correctly declared?" << std::endl;
200      return false;
201    }
202
[1507]203#if 0
[1502]204    // tame the ogre ouput so we don't get all the mess in the console
205    Ogre::Log* defaultLog = Ogre::LogManager::getSingleton().getDefaultLog();
206    defaultLog->setDebugOutputEnabled(false);
207    defaultLog->setLogDetail(Ogre::LL_BOREME);
208    defaultLog->addListener(this);
209#endif
210
[1293]211    CCOUT(4) << "Creating Ogre Root done" << std::endl;
[612]212
[1293]213    // specify where Ogre has to look for resources. This call doesn't parse anything yet!
[1535]214    if (!declareRessourceLocations())
215      return false;
[612]216
[1293]217    CCOUT(3) << "Set up done." << std::endl;
[612]218    return true;
219  }
220
[1535]221  bool GraphicsEngine::declareRessourceLocations()
[612]222  {
[1293]223    CCOUT(4) << "Declaring Resources" << std::endl;
[612]224    //TODO: Specify layout of data file and maybe use xml-loader
225    //TODO: Work with ressource groups (should be generated by a special loader)
[1535]226
227    if (resourceFile_ == "")
228    {
229      COUT(1) << "Error: Resource file set to \"\". Cannot load." << std::endl;
230      return false;
231    }
232
[612]233    // Load resource paths from data file using configfile ressource type
[1052]234    Ogre::ConfigFile cf;
[1535]235    try
236    {
237      cf.load(Settings::getDataPath() + resourceFile_);
238    }
239    catch (Ogre::Exception ex)
240    {
241      COUT(1) << "Error: Could not load resources.cfg in path " << Settings::getDataPath() << std::endl;
242      COUT(0) << "Have you forgotten to set the data path in orxnox.ini?" << std::endl;
243      return false;
244    }
[612]245
246    // Go through all sections & settings in the file
[1052]247    Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
[612]248
[715]249    std::string secName, typeName, archName;
[612]250    while (seci.hasMoreElements())
251    {
[1535]252      try
[612]253      {
[1535]254        secName = seci.peekNextKey();
255        Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
256        Ogre::ConfigFile::SettingsMultiMap::iterator i;
257        for (i = settings->begin(); i != settings->end(); ++i)
258        {
259          typeName = i->first; // for instance "FileSystem" or "Zip"
260          archName = i->second; // name (and location) of archive
[612]261
[1535]262          Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
263              std::string(Settings::getDataPath() + archName), typeName, secName);
264        }
[612]265      }
[1535]266      catch (Ogre::Exception ex)
267      {
268        COUT(2) << "Exception while reading resources.cfg. Proceeding.." << ex.getDescription() << std::endl;
269      }
[612]270    }
[1535]271    return true;
[612]272  }
273
[1293]274  bool GraphicsEngine::loadRenderer()
275  {
276    CCOUT(4) << "Configuring Renderer" << std::endl;
277
[1538]278    // check for file existence because Ogre displays exceptions if not
279    std::ifstream probe;
280    probe.open(ogreConfigFile_.c_str());
281    if (!probe)
282    {
283      // create a zero sized file
284      std::ofstream creator;
285      creator.open(ogreConfigFile_.c_str());
286      creator.close();
287    }
288    else
289      probe.close();
290
291    if (!root_->restoreConfig())
292      if (!root_->showConfigDialog())
293        return false;
294
[1293]295    CCOUT(4) << "Creating render window" << std::endl;
[1535]296    try
297    {
298      this->renderWindow_ = root_->initialise(true, "OrxonoxV2");
299    }
300    catch (Ogre::Exception ex)
301    {
302      COUT(2) << "Error: There was an exception when initialising Ogre Root." << std::endl;
303      return false;
304    }
305
[1293]306    if (!root_->isInitialised())
307    {
[1535]308      CCOUT(2) << "Error: Initialising Ogre root object failed." << std::endl;
[1293]309      return false;
310    }
311    Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, this);
312    Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
313    return true;
314  }
315
316  bool GraphicsEngine::initialiseResources()
317  {
318    CCOUT(4) << "Initialising resources" << std::endl;
319    //TODO: Do NOT load all the groups, why are we doing that? And do we really do that? initialise != load...
320    try
321    {
322      Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
323      /*Ogre::StringVector str = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
324      for (unsigned int i = 0; i < str.size(); i++)
325      {
326        Ogre::ResourceGroupManager::getSingleton().loadResourceGroup(str[i]);
327      }*/
328    }
329    catch (Ogre::Exception e)
330    {
331      CCOUT(2) << "Error: There was an Error when initialising the resources." << std::endl;
332      CCOUT(2) << "ErrorMessage: " << e.getFullDescription() << std::endl;
333      return false;
334    }
335    return true;
336  }
337
[1021]338  /**
[1293]339   * @brief Creates the SceneManager
340   */
341  bool GraphicsEngine::createNewScene()
342  {
[1502]343    CCOUT(4) << "Creating new SceneManager..." << std::endl;
[1293]344    if (scene_)
345    {
346      CCOUT(2) << "SceneManager already exists! Skipping." << std::endl;
347      return false;
348    }
349    scene_ = root_->createSceneManager(Ogre::ST_GENERIC, "Default SceneManager");
350    CCOUT(3) << "Created SceneManager: " << scene_ << std::endl;
351    return true;
352  }
353
354  /**
[1021]355    Returns the window handle of the render window.
356    At least the InputHandler uses this to create the OIS::InputManager
357    @return The window handle of the render window
358  */
359  size_t GraphicsEngine::getWindowHandle()
360  {
361    if (this->renderWindow_)
362    {
[1024]363      size_t windowHnd = 0;
[1032]364      this->renderWindow_->getCustomAttribute("WINDOW", &windowHnd);
[1024]365      return windowHnd;
366    }
[1021]367    else
368      return 0;
369  }
[612]370
[1021]371  /**
372    Get the width of the current render window
373    @return The width of the current render window
374  */
375  int GraphicsEngine::getWindowWidth() const
376  {
377    if (this->renderWindow_)
378      return this->renderWindow_->getWidth();
379    else
380      return 0;
381  }
382
383  /**
384    Get the height of the current render window
385    @return The height of the current render window
386  */
387  int GraphicsEngine::getWindowHeight() const
388  {
389    if (this->renderWindow_)
390      return this->renderWindow_->getHeight();
391    else
392      return 0;
393  }
394
[1024]395  /**
[1505]396    @brief Returns the window aspect ratio height/width.
397    @return The ratio
398  */
399  float GraphicsEngine::getWindowAspectRatio() const
400  {
401    if (this->renderWindow_)
402        return (float)this->renderWindow_->getHeight() / (float)this->renderWindow_->getWidth();
403    else
404        return 1.0f;
405  }
406
407  /**
[1024]408    @brief Method called by the LogListener interface from Ogre.
409    We use it to capture Ogre log messages and handle it ourselves.
410    @param message The message to be logged
411    @param lml The message level the log is using
412    @param maskDebug If we are printing to the console or not
413    @param logName the name of this log (so you can have several listeners
414                   for different logs, and identify them)
415  */
416  void GraphicsEngine::messageLogged(const std::string& message,
[1052]417    Ogre::LogMessageLevel lml, bool maskDebug, const std::string &logName)
[1024]418  {
419    int orxonoxLevel;
420    switch (lml)
421    {
[1052]422      case Ogre::LML_TRIVIAL:
[1024]423        orxonoxLevel = this->ogreLogLevelTrivial_;
424        break;
[1052]425      case Ogre::LML_NORMAL:
[1024]426        orxonoxLevel = this->ogreLogLevelNormal_;
427        break;
[1052]428      case Ogre::LML_CRITICAL:
[1024]429        orxonoxLevel = this->ogreLogLevelCritical_;
430        break;
431      default:
432        orxonoxLevel = 0;
433    }
434    OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
[1293]435        << "Ogre: " << message << std::endl;
[1024]436  }
[1214]437
[1293]438  /**
439  * Window has resized.
440  * @param rw The render window it occured in
441  */
442  void GraphicsEngine::windowMoved(Ogre::RenderWindow *rw)
443  {
444    // note: this doesn't change the window extents
445  }
[1214]446
[1293]447  /**
448  * Window has resized.
449  * @param rw The render window it occured in
450  * @note GraphicsEngine has a render window stored itself. This is the same
451  *       as rw. But we have to be careful when using multiple render windows!
452  */
[1505]453  void GraphicsEngine::windowResized(Ogre::RenderWindow *rw)
454  {
[1293]455    // change the mouse clipping size for absolute mouse movements
456    int w = rw->getWidth();
457    int h = rw->getHeight();
458    InputManager::setWindowExtents(w, h);
[1502]459    InGameConsole::getInstance().resize();
[1564]460    HUD::getSingleton().resize();
[1293]461  }
[1214]462
[1293]463  /**
464  * Window has resized.
465  * @param rw The render window it occured in
466  */
467  void GraphicsEngine::windowFocusChanged(Ogre::RenderWindow *rw)
468  {
469    // note: this doesn't change the window extents
470  }
471
472  /**
473  * Window has resized.
474  * @param rw The render window it occured in
475  */
476  void GraphicsEngine::windowClosed(Ogre::RenderWindow *rw)
477  {
478    // using CommandExecutor in order to avoid depending on Orxonox class.
479    CommandExecutor::execute("exit", false);
480  }
[1502]481
[612]482}
Note: See TracBrowser for help on using the repository browser.