Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/GraphicsEngine.cc @ 1747

Last change on this file since 1747 was 1747, checked in by landauf, 17 years ago

merged core3 back to trunk

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