Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource2/src/core/GraphicsManager.cc @ 5641

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

Prepared build system for an external media directory.
This revision only runs in console mode! (tcl files working again)

  • Property svn:eol-style set to native
File size: 10.9 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
41#include <OgreFrameListener.h>
42#include <OgreRoot.h>
43#include <OgreLogManager.h>
44#include <OgreException.h>
45#include <OgreRenderWindow.h>
46#include <OgreRenderSystem.h>
47#include <OgreViewport.h>
48#include <OgreWindowEventUtilities.h>
49
50#include "SpecialConfig.h"
51#include "util/Exception.h"
52#include "util/StringUtils.h"
53#include "util/SubString.h"
54#include "Clock.h"
55#include "ConsoleCommand.h"
56#include "ConfigValueIncludes.h"
57#include "CoreIncludes.h"
58#include "Core.h"
59#include "Game.h"
60#include "GameMode.h"
61#include "WindowEventListener.h"
62
63namespace orxonox
64{
65    class OgreWindowEventListener : public Ogre::WindowEventListener
66    {
67    public:
68        void windowResized     (Ogre::RenderWindow* rw)
69            { orxonox::WindowEventListener::resizeWindow(rw->getWidth(), rw->getHeight()); }
70        void windowFocusChange (Ogre::RenderWindow* rw)
71            { orxonox::WindowEventListener::changeWindowFocus(); }
72        void windowClosed      (Ogre::RenderWindow* rw)
73            { orxonox::Game::getInstance().stop(); }
74        void windowMoved       (Ogre::RenderWindow* rw)
75            { orxonox::WindowEventListener::moveWindow(); }
76    };
77
78    GraphicsManager* GraphicsManager::singletonPtr_s = 0;
79
80    /**
81    @brief
82        Non-initialising constructor.
83    */
84    GraphicsManager::GraphicsManager(bool bLoadRenderer)
85        : renderWindow_(0)
86        , viewport_(0)
87        , ogreWindowEventListener_(new OgreWindowEventListener())
88    {
89        RegisterObject(GraphicsManager);
90
91        this->setConfigValues();
92
93        // Ogre setup procedure (creating Ogre::Root)
94        this->loadOgreRoot();
95        // load all the required plugins for Ogre
96        this->loadOgrePlugins();
97
98        if (bLoadRenderer)
99        {
100            // Reads the ogre config and creates the render window
101            this->loadRenderer();
102        }
103    }
104
105    /**
106    @brief
107        Destruction is done by the member scoped_ptrs.
108    */
109    GraphicsManager::~GraphicsManager()
110    {
111    }
112
113    void GraphicsManager::setConfigValues()
114    {
115        SetConfigValue(ogreConfigFile_,  "ogre.cfg")
116            .description("Location of the Ogre config file");
117        SetConfigValue(ogrePluginsDirectory_, specialConfig::ogrePluginsDirectory)
118            .description("Folder where the Ogre plugins are located.");
119        SetConfigValue(ogrePlugins_, specialConfig::ogrePlugins)
120            .description("Comma separated list of all plugins to load.");
121        SetConfigValue(ogreLogFile_,     "ogre.log")
122            .description("Logfile for messages from Ogre. Use \"\" to suppress log file creation.");
123        SetConfigValue(ogreLogLevelTrivial_ , 5)
124            .description("Corresponding orxonox debug level for ogre Trivial");
125        SetConfigValue(ogreLogLevelNormal_  , 4)
126            .description("Corresponding orxonox debug level for ogre Normal");
127        SetConfigValue(ogreLogLevelCritical_, 2)
128            .description("Corresponding orxonox debug level for ogre Critical");
129    }
130
131    /**
132    @brief
133        Loads the renderer and creates the render window if not yet done so.
134    @remarks
135        This operation is irreversible without recreating the GraphicsManager!
136    */
137    void GraphicsManager::upgradeToGraphics()
138    {
139        if (renderWindow_ == NULL)
140        {
141            this->loadRenderer();
142        }
143    }
144
145    /**
146    @brief
147        Creates the Ogre Root object and sets up the ogre log.
148    */
149    void GraphicsManager::loadOgreRoot()
150    {
151        COUT(3) << "Setting up Ogre..." << std::endl;
152
153        if (ogreConfigFile_ == "")
154        {
155            COUT(2) << "Warning: Ogre config file set to \"\". Defaulting to config.cfg" << std::endl;
156            ModifyConfigValue(ogreConfigFile_, tset, "config.cfg");
157        }
158        if (ogreLogFile_ == "")
159        {
160            COUT(2) << "Warning: Ogre log file set to \"\". Defaulting to ogre.log" << std::endl;
161            ModifyConfigValue(ogreLogFile_, tset, "ogre.log");
162        }
163
164        boost::filesystem::path ogreConfigFilepath(Core::getConfigPath() / this->ogreConfigFile_);
165        boost::filesystem::path ogreLogFilepath(Core::getLogPath() / this->ogreLogFile_);
166
167        // create a new logManager
168        // Ogre::Root will detect that we've already created a Log
169        ogreLogger_.reset(new Ogre::LogManager());
170        COUT(4) << "Ogre LogManager created" << std::endl;
171
172        // create our own log that we can listen to
173        Ogre::Log *myLog;
174        myLog = ogreLogger_->createLog(ogreLogFilepath.string(), true, false, false);
175        COUT(4) << "Ogre Log created" << std::endl;
176
177        myLog->setLogDetail(Ogre::LL_BOREME);
178        myLog->addListener(this);
179
180        COUT(4) << "Creating Ogre Root..." << std::endl;
181
182        // check for config file existence because Ogre displays (caught) exceptions if not
183        if (!boost::filesystem::exists(ogreConfigFilepath))
184        {
185            // create a zero sized file
186            std::ofstream creator;
187            creator.open(ogreConfigFilepath.string().c_str());
188            creator.close();
189        }
190
191        // Leave plugins file empty. We're going to do that part manually later
192        ogreRoot_.reset(new Ogre::Root("", ogreConfigFilepath.string(), ogreLogFilepath.string()));
193
194        COUT(3) << "Ogre set up done." << std::endl;
195    }
196
197    void GraphicsManager::loadOgrePlugins()
198    {
199        // just to make sure the next statement doesn't segfault
200        if (ogrePluginsDirectory_ == "")
201            ogrePluginsDirectory_ = ".";
202
203        boost::filesystem::path folder(ogrePluginsDirectory_);
204        // Do some SubString magic to get the comma separated list of plugins
205        SubString plugins(ogrePlugins_, ",", " ", false, '\\', false, '"', false, '(', ')', false, '\0');
206        // Use backslash paths on Windows! file_string() already does that though.
207        for (unsigned int i = 0; i < plugins.size(); ++i)
208            ogreRoot_->loadPlugin((folder / plugins[i]).file_string());
209    }
210
211    void GraphicsManager::loadRenderer()
212    {
213        CCOUT(4) << "Configuring Renderer" << std::endl;
214
215        if (!ogreRoot_->restoreConfig())
216            if (!ogreRoot_->showConfigDialog())
217                ThrowException(InitialisationFailed, "OGRE graphics configuration dialogue failed.");
218
219        CCOUT(4) << "Creating render window" << std::endl;
220
221        this->renderWindow_ = ogreRoot_->initialise(true, "Orxonox");
222        // Propagate the size of the new winodw
223        this->ogreWindowEventListener_->windowResized(renderWindow_);
224
225        Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, ogreWindowEventListener_.get());
226
227        // create a full screen default viewport
228        // Note: This may throw when adding a viewport with an existing z-order!
229        //       But in our case we only have one viewport for now anyway, therefore
230        //       no ScopeGuards or anything to handle exceptions.
231        this->viewport_ = this->renderWindow_->addViewport(0, 0);
232
233        // add console commands
234        FunctorMember<GraphicsManager>* functor1 = createFunctor(&GraphicsManager::printScreen);
235        ccPrintScreen_ = createConsoleCommand(functor1->setObject(this), "printScreen");
236        CommandExecutor::addConsoleCommandShortcut(ccPrintScreen_);
237    }
238
239    void GraphicsManager::update(const Clock& time)
240    {
241        Ogre::FrameEvent evt;
242        evt.timeSinceLastFrame = time.getDeltaTime();
243        evt.timeSinceLastEvent = time.getDeltaTime(); // note: same time, but shouldn't matter anyway
244
245        // don't forget to call _fireFrameStarted to OGRE to make sure
246        // everything goes smoothly
247        ogreRoot_->_fireFrameStarted(evt);
248
249        // Pump messages in all registered RenderWindows
250        // This calls the WindowEventListener objects.
251        Ogre::WindowEventUtilities::messagePump();
252        // make sure the window stays active even when not focused
253        // (probably only necessary on windows)
254        this->renderWindow_->setActive(true);
255
256        // Time before rendering
257        uint64_t timeBeforeTick = time.getRealMicroseconds();
258
259        // Render frame
260        ogreRoot_->_updateAllRenderTargets();
261
262        uint64_t timeAfterTick = time.getRealMicroseconds();
263        // Subtract the time used for rendering from the tick time counter
264        Game::getInstance().subtractTickTime(timeAfterTick - timeBeforeTick);
265
266        // again, just to be sure OGRE works fine
267        ogreRoot_->_fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
268    }
269
270    void GraphicsManager::setCamera(Ogre::Camera* camera)
271    {
272        this->viewport_->setCamera(camera);
273    }
274
275    /**
276    @brief
277        Method called by the LogListener interface from Ogre.
278        We use it to capture Ogre log messages and handle it ourselves.
279    @param message
280        The message to be logged
281    @param lml
282        The message level the log is using
283    @param maskDebug
284        If we are printing to the console or not
285    @param logName
286        The name of this log (so you can have several listeners
287        for different logs, and identify them)
288    */
289    void GraphicsManager::messageLogged(const std::string& message,
290        Ogre::LogMessageLevel lml, bool maskDebug, const std::string& logName)
291    {
292        int orxonoxLevel;
293        switch (lml)
294        {
295        case Ogre::LML_TRIVIAL:
296            orxonoxLevel = this->ogreLogLevelTrivial_;
297            break;
298        case Ogre::LML_NORMAL:
299            orxonoxLevel = this->ogreLogLevelNormal_;
300            break;
301        case Ogre::LML_CRITICAL:
302            orxonoxLevel = this->ogreLogLevelCritical_;
303            break;
304        default:
305            orxonoxLevel = 0;
306        }
307        OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
308            << "Ogre: " << message << std::endl;
309    }
310
311    void GraphicsManager::printScreen()
312    {
313        assert(this->renderWindow_);
314       
315        this->renderWindow_->writeContentsToTimestampedFile(Core::getLogPathString() + "screenShot_", ".jpg");
316    }
317}
Note: See TracBrowser for help on using the repository browser.