Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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