Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/orxonox/GraphicsEngine.cc @ 1652

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