Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource/src/orxonox/GraphicsManager.cc @ 3336

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

Moved Config value detailLevelParticle from GraphicsManager to ParticleInterface.
The resulting section name problem is to be resolved later. We've got a mess of config values anyway.

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