Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core4/src/orxonox/GraphicsManager.cc @ 3293

Last change on this file since 3293 was 3291, checked in by rgrieder, 15 years ago

Added window size as static variable to the WindowEventListener interface.
This resolves several hacks and inconveniences in Mouse, InputManager, InGameConsole, GSGraphics and OrxonoxOverlay.

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