Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged input branch back to trunk

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