Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource/src/core/GraphicsManager.cc @ 3346

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

Moved GraphicsManager and GUIManager to the core. Almost no actual code changes though, just moving (here was that Map-hack I had to move to GSGraphics).

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