Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1591 was 1591, checked in by landauf, 16 years ago

Again some heavy changes in ObjectList and Iterator:
there are now two types of iterators:

Iterator<ClassName> can iterate through any objectlist, either given by ObjectList<AnyClassName>::begin() or anyidentifier→getObjects()→begin(). Important note Iterator<ClassName> uses dynamic_cast.
And yes, it's possible to do this: Iterator<WorldEntity> it = ObjectList<SpaceShip>::begin()

ObjectList<ClassName>::iterator is the second iterator - it uses the ObjectList in a templated manner and therefore doesn't need dynamic_cast. But the only thing you can do is iterating through exactly the right ObjectList: ObjectList<ClassName>::iterator it = ObjectList<ClassName>::begin(). Anything else fails.

Those changes bring, at my system, something around +12% FPS compared with trunk and +25% FPS compared with the last revision of core3. Although I have to admit the FPS gain is only that high because iterating through objects is the main thing we're doing ingame right now. It would look totally different with physics, sound, AI, scripts, triggers and so on.

  • Property svn:eol-style set to native
File size: 14.6 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 <fstream>
38
39#include <OgreConfigFile.h>
40#include <OgreException.h>
41#include <OgreLogManager.h>
42#include <OgreRoot.h>
43#include <OgreSceneManager.h>
44#include <OgreTextureManager.h>
45#include <OgreViewport.h>
46
47#include "core/CoreIncludes.h"
48#include "core/ConfigValueIncludes.h"
49#include "core/Iterator.h"
50#include "core/CommandExecutor.h"
51#include "core/ConsoleCommand.h"
52#include "core/input/InputManager.h"
53#include "util/Debug.h"
54
55#include "console/InGameConsole.h"
56#include "hud/HUD.h"
57#include "tools/ParticleInterface.h"
58#include "Settings.h"
59
60
61namespace orxonox {
62  /**
63    @brief Returns the singleton instance and creates it the first time.
64    @return The only instance of GraphicsEngine.
65  */
66  /*static*/ GraphicsEngine& GraphicsEngine::getSingleton()
67  {
68    static GraphicsEngine theOnlyInstance;
69    return theOnlyInstance;
70  }
71
72  /**
73    @brief Only use constructor to initialise variables and pointers!
74  */
75  GraphicsEngine::GraphicsEngine() :
76    root_(0),
77    scene_(0),
78    renderWindow_(0)
79  {
80    RegisterObject(GraphicsEngine);
81
82    this->detailLevelParticle_ = 0;
83
84    this->setConfigValues();
85    CCOUT(4) << "Constructed" << std::endl;
86  }
87
88  void GraphicsEngine::setConfigValues()
89  {
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.");
95    SetConfigValue(ogreLogLevelTrivial_ , 5).description("Corresponding orxonox debug level for ogre Trivial");
96    SetConfigValue(ogreLogLevelNormal_  , 4).description("Corresponding orxonox debug level for ogre Normal");
97    SetConfigValue(ogreLogLevelCritical_, 2).description("Corresponding orxonox debug level for ogre Critical");
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 (ObjectList<ParticleInterface>::iterator it = ObjectList<ParticleInterface>::begin(); it; ++it)
104        it->detailLevelChanged(this->detailLevelParticle_);
105  }
106
107  /**
108    @brief Called after main() --> call destroyObjects()!
109  */
110  GraphicsEngine::~GraphicsEngine()
111  {
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  {
121    CCOUT(4) << "Destroying objects..." << std::endl;
122    Ogre::WindowEventUtilities::removeWindowEventListener(this->renderWindow_, this);
123    if (this->root_)
124      delete this->root_;
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).
129    if (Ogre::LogManager::getSingletonPtr() != 0)
130    {
131      Ogre::LogManager::getSingleton().getDefaultLog()->removeListener(this);
132      Ogre::LogManager::getSingleton().destroyLog(Ogre::LogManager::getSingleton().getDefaultLog());
133      delete Ogre::LogManager::getSingletonPtr();
134    }
135    CCOUT(4) << "Destroying objects done" << std::endl;
136  }
137
138  /**
139    @brief Creates the Ogre Root object and sets up the ogre log.
140  */
141  bool GraphicsEngine::setup()
142  {
143    CCOUT(3) << "Setting up..." << std::endl;
144    // temporary overwrite of dataPath, change ini file for permanent change
145
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
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;
153
154    // create our own log that we can listen to
155    Ogre::Log *myLog;
156    if (this->ogreLogFile_ == "")
157      myLog = logger->createLog("ogre.log", true, false, true);
158    else
159      myLog = logger->createLog(this->ogreLogFile_, true, false, false);
160    CCOUT(4) << "Ogre Log created" << std::endl;
161
162    myLog->setLogDetail(Ogre::LL_BOREME);
163    myLog->addListener(this);
164#endif
165
166    // Root will detect that we've already created a Log
167    CCOUT(4) << "Creating Ogre Root..." << std::endl;
168
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    }
184
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
202#if 0
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
210    CCOUT(4) << "Creating Ogre Root done" << std::endl;
211
212    // specify where Ogre has to look for resources. This call doesn't parse anything yet!
213    if (!declareRessourceLocations())
214      return false;
215
216    CCOUT(3) << "Set up done." << std::endl;
217    return true;
218  }
219
220  bool GraphicsEngine::declareRessourceLocations()
221  {
222    CCOUT(4) << "Declaring Resources" << std::endl;
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)
225
226    if (resourceFile_ == "")
227    {
228      COUT(1) << "Error: Resource file set to \"\". Cannot load." << std::endl;
229      return false;
230    }
231
232    // Load resource paths from data file using configfile ressource type
233    Ogre::ConfigFile cf;
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    }
244
245    // Go through all sections & settings in the file
246    Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
247
248    std::string secName, typeName, archName;
249    while (seci.hasMoreElements())
250    {
251      try
252      {
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
260
261          Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
262              std::string(Settings::getDataPath() + archName), typeName, secName);
263        }
264      }
265      catch (Ogre::Exception ex)
266      {
267        COUT(2) << "Exception while reading resources.cfg. Proceeding.." << ex.getDescription() << std::endl;
268      }
269    }
270    return true;
271  }
272
273  bool GraphicsEngine::loadRenderer()
274  {
275    CCOUT(4) << "Configuring Renderer" << std::endl;
276
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
294    CCOUT(4) << "Creating render window" << std::endl;
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
305    if (!root_->isInitialised())
306    {
307      CCOUT(2) << "Error: Initialising Ogre root object failed." << std::endl;
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
337  /**
338   * @brief Creates the SceneManager
339   */
340  bool GraphicsEngine::createNewScene()
341  {
342    CCOUT(4) << "Creating new SceneManager..." << std::endl;
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  /**
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    {
362      size_t windowHnd = 0;
363      this->renderWindow_->getCustomAttribute("WINDOW", &windowHnd);
364      return windowHnd;
365    }
366    else
367      return 0;
368  }
369
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
394  /**
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  /**
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,
416    Ogre::LogMessageLevel lml, bool maskDebug, const std::string &logName)
417  {
418    int orxonoxLevel;
419    switch (lml)
420    {
421      case Ogre::LML_TRIVIAL:
422        orxonoxLevel = this->ogreLogLevelTrivial_;
423        break;
424      case Ogre::LML_NORMAL:
425        orxonoxLevel = this->ogreLogLevelNormal_;
426        break;
427      case Ogre::LML_CRITICAL:
428        orxonoxLevel = this->ogreLogLevelCritical_;
429        break;
430      default:
431        orxonoxLevel = 0;
432    }
433    OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
434        << "Ogre: " << message << std::endl;
435  }
436
437  /**
438  * Window has resized.
439  * @param rw The render window it occured in
440  */
441  void GraphicsEngine::windowMoved(Ogre::RenderWindow *rw)
442  {
443    // note: this doesn't change the window extents
444  }
445
446  /**
447  * Window has resized.
448  * @param rw The render window it occured in
449  * @note GraphicsEngine has a render window stored itself. This is the same
450  *       as rw. But we have to be careful when using multiple render windows!
451  */
452  void GraphicsEngine::windowResized(Ogre::RenderWindow *rw)
453  {
454    // change the mouse clipping size for absolute mouse movements
455    int w = rw->getWidth();
456    int h = rw->getHeight();
457    InputManager::setWindowExtents(w, h);
458    InGameConsole::getInstance().resize();
459    HUD::getSingleton().resize();
460  }
461
462  /**
463  * Window has resized.
464  * @param rw The render window it occured in
465  */
466  void GraphicsEngine::windowFocusChanged(Ogre::RenderWindow *rw)
467  {
468    // note: this doesn't change the window extents
469  }
470
471  /**
472  * Window has resized.
473  * @param rw The render window it occured in
474  */
475  void GraphicsEngine::windowClosed(Ogre::RenderWindow *rw)
476  {
477    // using CommandExecutor in order to avoid depending on Orxonox class.
478    CommandExecutor::execute("exit", false);
479  }
480
481}
Note: See TracBrowser for help on using the repository browser.