Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1689 was 1625, checked in by rgrieder, 16 years ago

merged hud branch back to trunk

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