Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/GraphicsManager.cc @ 3100

Last change on this file since 3100 was 3100, checked in by scheusso, 16 years ago

reapplied retos patch

  • Property svn:eol-style set to native
File size: 15.3 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
[1755]24 *      Benjamin Knecht <beni_at_orxonox.net>, (C) 2007
[612]25 *   Co-authors:
[1755]26 *      Felix Schulthess
[612]27 *
28 */
[1035]29
[1755]30/**
31@file
32@brief
33    Implementation of an partial interface to Ogre.
34*/
[612]35
[1021]36#include "OrxonoxStableHeaders.h"
[2801]37#include "GraphicsManager.h"
[612]38
[2801]39#include <fstream>
40#include <boost/filesystem.hpp>
41
42#include <OgreCompositorManager.h>
43#include <OgreConfigFile.h>
44#include <OgreFrameListener.h>
45#include <OgreRoot.h>
46#include <OgreLogManager.h>
47#include <OgreException.h>
[1755]48#include <OgreRenderWindow.h>
[2801]49#include <OgreRenderSystem.h>
50#include <OgreTextureManager.h>
51#include <OgreViewport.h>
52#include <OgreWindowEventUtilities.h>
[1538]53
[2801]54#include "SpecialConfig.h"
55#include "util/Debug.h"
56#include "util/Exception.h"
57#include "util/String.h"
58#include "util/SubString.h"
[2842]59#include "core/Clock.h"
[2801]60#include "core/ConsoleCommand.h"
61#include "core/ConfigValueIncludes.h"
[1293]62#include "core/CoreIncludes.h"
[2801]63#include "core/Core.h"
[3091]64#include "core/Game.h"
[2848]65#include "core/GameMode.h"
[2801]66#include "tools/WindowEventListener.h"
[1563]67#include "tools/ParticleInterface.h"
[1032]68
[1625]69namespace orxonox
70{
[2801]71    class _OrxonoxExport OgreWindowEventListener : public Ogre::WindowEventListener
72    {
73        void windowResized     (Ogre::RenderWindow* rw);
74        void windowFocusChange (Ogre::RenderWindow* rw);
75        void windowClosed      (Ogre::RenderWindow* rw);
76        //void windowMoved       (Ogre::RenderWindow* rw);
77    };
[1032]78
[2801]79    GraphicsManager* GraphicsManager::singletonRef_s = 0;
[1293]80
[1755]81    /**
82    @brief
[2801]83        Non-initialising constructor.
[1755]84    */
[2801]85    GraphicsManager::GraphicsManager()
86        : ogreRoot_(0)
87        , ogreLogger_(0)
88        , renderWindow_(0)
89        , viewport_(0)
90        , ogreWindowEventListener_(0)
91        , avgTickTime_(0.0f)
92        , avgFramesPerSecond_(0.0f)
[1024]93    {
[2801]94        RegisterObject(GraphicsManager);
95
96        assert(singletonRef_s == 0);
97        singletonRef_s = this;
98
99        this->loaded_ = false;
100
101        this->setConfigValues();
[1024]102    }
[612]103
[2801]104    void GraphicsManager::initialise()
105    {
106        // Ogre setup procedure
107        setupOgre();
108        // load all the required plugins for Ogre
109        loadOgrePlugins();
110        // read resource declaration file
111        this->declareResources();
112        // Reads ogre config and creates the render window
113        this->loadRenderer();
114
115        // TODO: Spread this
116        this->initialiseResources();
117
118        // add console commands
119        FunctorMember<GraphicsManager>* functor1 = createFunctor(&GraphicsManager::printScreen);
120        functor1->setObject(this);
121        ccPrintScreen_ = createConsoleCommand(functor1, "printScreen");
122        CommandExecutor::addConsoleCommandShortcut(ccPrintScreen_);
123
124        this->loaded_ = true;
125    }
126
[1755]127    /**
128    @brief
[2801]129        Destroys all the Ogre related objects
[1755]130    */
[2801]131    GraphicsManager::~GraphicsManager()
[1535]132    {
[2801]133        if (this->loaded_)
134        {
135            delete this->ccPrintScreen_;
[1502]136
[2801]137            if (this->ogreWindowEventListener_)
138            {
139                // remove our WindowEventListener first to avoid bad calls after the window has been destroyed
140                Ogre::WindowEventUtilities::removeWindowEventListener(this->renderWindow_, this->ogreWindowEventListener_);
141                delete this->ogreWindowEventListener_;
142            }
[1535]143
[2801]144            // unload all compositors
145            Ogre::CompositorManager::getSingleton().removeAll();
[2662]146
[2801]147            // Delete OGRE main control organ
148            delete this->ogreRoot_;
149
150            // delete the ogre log and the logManager (since we have created it in the first place).
151            this->ogreLogger_->getDefaultLog()->removeListener(this);
152            this->ogreLogger_->destroyLog(Ogre::LogManager::getSingleton().getDefaultLog());
153            delete this->ogreLogger_;
154        }
155
156        assert(singletonRef_s);
157        singletonRef_s = 0;
[1535]158    }
159
[2801]160    void GraphicsManager::setConfigValues()
[1535]161    {
[2801]162        SetConfigValue(resourceFile_,    "resources.cfg")
163            .description("Location of the resources file in the data path.");
164        SetConfigValue(ogreConfigFile_,  "ogre.cfg")
165            .description("Location of the Ogre config file");
166        SetConfigValue(ogrePluginsFolder_, ORXONOX_OGRE_PLUGINS_FOLDER)
167            .description("Folder where the Ogre plugins are located.");
168        SetConfigValue(ogrePlugins_, ORXONOX_OGRE_PLUGINS)
169            .description("Comma separated list of all plugins to load.");
170        SetConfigValue(ogreLogFile_,     "ogre.log")
171            .description("Logfile for messages from Ogre. Use \"\" to suppress log file creation.");
172        SetConfigValue(ogreLogLevelTrivial_ , 5)
173            .description("Corresponding orxonox debug level for ogre Trivial");
174        SetConfigValue(ogreLogLevelNormal_  , 4)
175            .description("Corresponding orxonox debug level for ogre Normal");
176        SetConfigValue(ogreLogLevelCritical_, 2)
177            .description("Corresponding orxonox debug level for ogre Critical");
178        SetConfigValue(detailLevelParticle_, 2)
179            .description("O: off, 1: low, 2: normal, 3: high").callback(this, &GraphicsManager::detailLevelParticleChanged);
[1535]180    }
[612]181
[2801]182    void GraphicsManager::detailLevelParticleChanged()
[612]183    {
[1755]184        for (ObjectList<ParticleInterface>::iterator it = ObjectList<ParticleInterface>::begin(); it; ++it)
185            it->detailLevelChanged(this->detailLevelParticle_);
[612]186    }
187
[2801]188    void GraphicsManager::update(const Clock& time)
189    {
190        if (this->loaded_)
191        {
192            Ogre::FrameEvent evt;
193            evt.timeSinceLastFrame = time.getDeltaTime();
194            evt.timeSinceLastEvent = time.getDeltaTime(); // note: same time, but shouldn't matter anyway
195
196            // don't forget to call _fireFrameStarted to OGRE to make sure
197            // everything goes smoothly
198            ogreRoot_->_fireFrameStarted(evt);
199
200            // Pump messages in all registered RenderWindows
201            // This calls the WindowEventListener objects.
202            Ogre::WindowEventUtilities::messagePump();
203            // make sure the window stays active even when not focused
204            // (probably only necessary on windows)
205            this->renderWindow_->setActive(true);
206
207            // render
208            ogreRoot_->_updateAllRenderTargets();
209
210            // again, just to be sure OGRE works fine
211            ogreRoot_->_fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
212        }
213    }
214
[2850]215    void GraphicsManager::setCamera(Ogre::Camera* camera)
216    {
217        this->viewport_->setCamera(camera);
218    }
219
[1755]220    /**
221    @brief
[2801]222        Creates the Ogre Root object and sets up the ogre log.
[1755]223    */
[2801]224    void GraphicsManager::setupOgre()
[1538]225    {
[2801]226        COUT(3) << "Setting up Ogre..." << std::endl;
227
228        if (ogreConfigFile_ == "")
229        {
230            COUT(2) << "Warning: Ogre config file set to \"\". Defaulting to config.cfg" << std::endl;
231            ModifyConfigValue(ogreConfigFile_, tset, "config.cfg");
232        }
233        if (ogreLogFile_ == "")
234        {
235            COUT(2) << "Warning: Ogre log file set to \"\". Defaulting to ogre.log" << std::endl;
236            ModifyConfigValue(ogreLogFile_, tset, "ogre.log");
237        }
238
239        boost::filesystem::path ogreConfigFilepath(Core::getConfigPath() / this->ogreConfigFile_);
240        boost::filesystem::path ogreLogFilepath(Core::getLogPath() / this->ogreLogFile_);
241
242        // create a new logManager
243        // Ogre::Root will detect that we've already created a Log
244        ogreLogger_ = new Ogre::LogManager();
245        COUT(4) << "Ogre LogManager created" << std::endl;
246
247        // create our own log that we can listen to
248        Ogre::Log *myLog;
249        myLog = ogreLogger_->createLog(ogreLogFilepath.string(), true, false, false);
250        COUT(4) << "Ogre Log created" << std::endl;
251
252        myLog->setLogDetail(Ogre::LL_BOREME);
253        myLog->addListener(this);
254
255        COUT(4) << "Creating Ogre Root..." << std::endl;
256
257        // check for config file existence because Ogre displays (caught) exceptions if not
258        if (!boost::filesystem::exists(ogreConfigFilepath))
259        {
260            // create a zero sized file
261            std::ofstream creator;
262            creator.open(ogreConfigFilepath.string().c_str());
263            creator.close();
264        }
265
266        // Leave plugins file empty. We're going to do that part manually later
267        ogreRoot_ = new Ogre::Root("", ogreConfigFilepath.string(), ogreLogFilepath.string());
268
269        COUT(3) << "Ogre set up done." << std::endl;
[1538]270    }
[2801]271
272    void GraphicsManager::loadOgrePlugins()
273    {
274        // just to make sure the next statement doesn't segfault
275        if (ogrePluginsFolder_ == "")
276            ogrePluginsFolder_ = ".";
277
278        boost::filesystem::path folder(ogrePluginsFolder_);
279        // Do some SubString magic to get the comma separated list of plugins
280        SubString plugins(ogrePlugins_, ",", " ", false, 92, false, 34, false, 40, 41, false, '\0');
281        // Use backslash paths on Windows! file_string() already does that though.
282        for (unsigned int i = 0; i < plugins.size(); ++i)
283            ogreRoot_->loadPlugin((folder / plugins[i]).file_string());
284    }
285
286    void GraphicsManager::declareResources()
287    {
288        CCOUT(4) << "Declaring Resources" << std::endl;
289        //TODO: Specify layout of data file and maybe use xml-loader
290        //TODO: Work with ressource groups (should be generated by a special loader)
291
292        if (resourceFile_ == "")
293        {
294            COUT(2) << "Warning: Ogre resource file set to \"\". Defaulting to resources.cfg" << std::endl;
295            ModifyConfigValue(resourceFile_, tset, "resources.cfg");
296        }
297
298        // Load resource paths from data file using configfile ressource type
299        Ogre::ConfigFile cf;
300        try
301        {
302            cf.load((Core::getMediaPath() / resourceFile_).string());
303        }
304        catch (...)
305        {
306            //COUT(1) << ex.getFullDescription() << std::endl;
307            COUT(0) << "Have you forgotten to set the data path in orxnox.ini?" << std::endl;
308            throw;
309        }
310
311        // Go through all sections & settings in the file
312        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
313
314        std::string secName, typeName, archName;
315        while (seci.hasMoreElements())
316        {
317            try
318            {
319                secName = seci.peekNextKey();
320                Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
321                Ogre::ConfigFile::SettingsMultiMap::iterator i;
322                for (i = settings->begin(); i != settings->end(); ++i)
323                {
324                    typeName = i->first; // for instance "FileSystem" or "Zip"
325                    archName = i->second; // name (and location) of archive
326
327                    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
328                        (Core::getMediaPath() / archName).string(), typeName, secName);
329                }
330            }
331            catch (Ogre::Exception& ex)
332            {
333                COUT(1) << ex.getFullDescription() << std::endl;
334            }
335        }
336    }
337
338    void GraphicsManager::loadRenderer()
339    {
340        CCOUT(4) << "Configuring Renderer" << std::endl;
341
342        if (!ogreRoot_->restoreConfig())
343            if (!ogreRoot_->showConfigDialog())
344                ThrowException(InitialisationFailed, "Could not show Ogre configuration dialogue.");
345
346        CCOUT(4) << "Creating render window" << std::endl;
347
348        this->renderWindow_ = ogreRoot_->initialise(true, "Orxonox");
349
350        this->ogreWindowEventListener_ = new OgreWindowEventListener();
351        Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, ogreWindowEventListener_);
352
353        Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(0);
354
355        // create a full screen default viewport
356        this->viewport_ = this->renderWindow_->addViewport(0, 0);
357    }
358
359    void GraphicsManager::initialiseResources()
360    {
361        CCOUT(4) << "Initialising resources" << std::endl;
362        //TODO: Do NOT load all the groups, why are we doing that? And do we really do that? initialise != load...
363        //try
364        //{
365            Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
366            /*Ogre::StringVector str = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
367            for (unsigned int i = 0; i < str.size(); i++)
368            {
369            Ogre::ResourceGroupManager::getSingleton().loadResourceGroup(str[i]);
370            }*/
371        //}
372        //catch (...)
373        //{
374        //    CCOUT(2) << "Error: There was a serious error when initialising the resources." << std::endl;
375        //    throw;
376        //}
377    }
378
379    /**
380    @brief
381        Method called by the LogListener interface from Ogre.
382        We use it to capture Ogre log messages and handle it ourselves.
383    @param message
384        The message to be logged
385    @param lml
386        The message level the log is using
387    @param maskDebug
388        If we are printing to the console or not
389    @param logName
390        The name of this log (so you can have several listeners
391        for different logs, and identify them)
392    */
393    void GraphicsManager::messageLogged(const std::string& message,
394        Ogre::LogMessageLevel lml, bool maskDebug, const std::string& logName)
395    {
396        int orxonoxLevel;
397        switch (lml)
398        {
399        case Ogre::LML_TRIVIAL:
400            orxonoxLevel = this->ogreLogLevelTrivial_;
401            break;
402        case Ogre::LML_NORMAL:
403            orxonoxLevel = this->ogreLogLevelNormal_;
404            break;
405        case Ogre::LML_CRITICAL:
406            orxonoxLevel = this->ogreLogLevelCritical_;
407            break;
408        default:
409            orxonoxLevel = 0;
410        }
411        OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
412            << "Ogre: " << message << std::endl;
413    }
414
415    void GraphicsManager::printScreen()
416    {
417        assert(this->renderWindow_);
418       
419        this->renderWindow_->writeContentsToTimestampedFile(Core::getLogPathString() + "screenShot_", ".jpg");
420    }
421
422
423    /****** OgreWindowEventListener ******/
424
425    void OgreWindowEventListener::windowResized(Ogre::RenderWindow* rw)
426    {
427        for (ObjectList<orxonox::WindowEventListener>::iterator it
428            = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
429            it->windowResized(rw->getWidth(), rw->getHeight());
430    }
431    void OgreWindowEventListener::windowFocusChange(Ogre::RenderWindow* rw)
432    {
433        for (ObjectList<orxonox::WindowEventListener>::iterator it
434            = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
435            it->windowFocusChanged();
436    }
437    void OgreWindowEventListener::windowClosed(Ogre::RenderWindow* rw)
438    {
[3091]439        Game::getInstance().stop();
[2801]440    }
[612]441}
Note: See TracBrowser for help on using the repository browser.