Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/kicklib/src/libraries/core/GraphicsManager.cc @ 8272

Last change on this file since 8272 was 8272, checked in by rgrieder, 13 years ago

Load Ogre plugins and Orxonox modules with the same path composition.
This should load Ogre plugins again on Linux.

  • Property svn:eol-style set to native
File size: 15.2 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#include "GraphicsManager.h"
31
32#include <cstdlib>
33#include <fstream>
34#include <sstream>
35#include <boost/filesystem.hpp>
36#include <boost/shared_array.hpp>
37
38#include <OgreFrameListener.h>
39#include <OgreRoot.h>
40#include <OgreLogManager.h>
41#include <OgreRenderWindow.h>
42#include <OgreRenderSystem.h>
43#include <OgreResourceGroupManager.h>
44#include <OgreTextureManager.h>
45#include <OgreViewport.h>
46#include <OgreWindowEventUtilities.h>
47
48#include "SpecialConfig.h"
49#include "util/Clock.h"
50#include "util/Exception.h"
51#include "util/StringUtils.h"
52#include "util/SubString.h"
53#include "ConfigValueIncludes.h"
54#include "CoreIncludes.h"
55#include "Core.h"
56#include "Game.h"
57#include "GameMode.h"
58#include "Loader.h"
59#include "PathConfig.h"
60#include "WindowEventListener.h"
61#include "XMLFile.h"
62#include "command/ConsoleCommand.h"
63
64namespace orxonox
65{
66    static const std::string __CC_printScreen_name = "printScreen";
67    DeclareConsoleCommand(__CC_printScreen_name, &prototype::void__void);
68
69    class OgreWindowEventListener : public Ogre::WindowEventListener
70    {
71    public:
72        void windowResized     (Ogre::RenderWindow* rw)
73            { orxonox::WindowEventListener::resizeWindow(rw->getWidth(), rw->getHeight()); }
74        void windowFocusChange (Ogre::RenderWindow* rw)
75            { orxonox::WindowEventListener::changeWindowFocus(rw->isActive()); }
76        void windowClosed      (Ogre::RenderWindow* rw)
77            { orxonox::Game::getInstance().stop(); }
78        void windowMoved       (Ogre::RenderWindow* rw)
79            { orxonox::WindowEventListener::moveWindow(); }
80    };
81
82    GraphicsManager* GraphicsManager::singletonPtr_s = 0;
83
84    /**
85    @brief
86        Non-initialising constructor.
87    */
88    GraphicsManager::GraphicsManager(bool bLoadRenderer)
89        : ogreWindowEventListener_(new OgreWindowEventListener())
90        , renderWindow_(0)
91        , viewport_(0)
92    {
93        RegisterObject(GraphicsManager);
94
95        this->setConfigValues();
96
97        // Ogre setup procedure (creating Ogre::Root)
98        this->loadOgreRoot();
99
100        // At first, add the root paths of the data directories as resource locations
101        Ogre::ResourceGroupManager::getSingleton().addResourceLocation(PathConfig::getDataPathString(), "FileSystem");
102        // Load resources
103        resources_.reset(new XMLFile("DefaultResources.oxr"));
104        resources_->setLuaSupport(false);
105        Loader::open(resources_.get());
106
107        // Only for development runs
108        if (PathConfig::isDevelopmentRun())
109        {
110            Ogre::ResourceGroupManager::getSingleton().addResourceLocation(PathConfig::getExternalDataPathString(), "FileSystem");
111            extResources_.reset(new XMLFile("resources.oxr"));
112            extResources_->setLuaSupport(false);
113            Loader::open(extResources_.get());
114        }
115
116        if (bLoadRenderer)
117        {
118            // Reads the ogre config and creates the render window
119            this->upgradeToGraphics();
120        }
121    }
122
123    /**
124    @brief
125        Destruction is done by the member scoped_ptrs.
126    */
127    GraphicsManager::~GraphicsManager()
128    {
129        Loader::unload(debugOverlay_.get());
130
131        Ogre::WindowEventUtilities::removeWindowEventListener(renderWindow_, ogreWindowEventListener_.get());
132        ModifyConsoleCommand(__CC_printScreen_name).resetFunction();
133
134        // Undeclare the resources
135        Loader::unload(resources_.get());
136        if (PathConfig::isDevelopmentRun())
137            Loader::unload(extResources_.get());
138    }
139
140    void GraphicsManager::setConfigValues()
141    {
142        SetConfigValue(ogreConfigFile_,  "ogre.cfg")
143            .description("Location of the Ogre config file");
144        SetConfigValue(ogrePlugins_, specialConfig::ogrePlugins)
145            .description("Comma separated list of all plugins to load.");
146        SetConfigValue(ogreLogFile_,     "ogre.log")
147            .description("Logfile for messages from Ogre. Use \"\" to suppress log file creation.");
148        SetConfigValue(ogreLogLevelTrivial_ , 5)
149            .description("Corresponding orxonox debug level for ogre Trivial");
150        SetConfigValue(ogreLogLevelNormal_  , 4)
151            .description("Corresponding orxonox debug level for ogre Normal");
152        SetConfigValue(ogreLogLevelCritical_, 2)
153            .description("Corresponding orxonox debug level for ogre Critical");
154    }
155
156    /**
157    @brief
158        Loads the renderer and creates the render window if not yet done so.
159    @remarks
160        This operation is irreversible without recreating the GraphicsManager!
161        So if it throws you HAVE to recreate the GraphicsManager!!!
162        It therefore offers almost no exception safety.
163    */
164    void GraphicsManager::upgradeToGraphics()
165    {
166        if (renderWindow_ != NULL)
167            return;
168
169        // load all the required plugins for Ogre
170        this->loadOgrePlugins();
171
172        this->loadRenderer();
173
174        // Initialise all resources (do this AFTER the renderer has been loaded!)
175        // Note: You can only do this once! Ogre will check whether a resource group has
176        // already been initialised. If you need to load resources later, you will have to
177        // choose another resource group.
178        Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
179    }
180
181    /**
182    @brief
183        Creates the Ogre Root object and sets up the ogre log.
184    */
185    void GraphicsManager::loadOgreRoot()
186    {
187        COUT(3) << "Setting up Ogre..." << std::endl;
188
189        if (ogreConfigFile_.empty())
190        {
191            COUT(2) << "Warning: Ogre config file set to \"\". Defaulting to config.cfg" << std::endl;
192            ModifyConfigValue(ogreConfigFile_, tset, "config.cfg");
193        }
194        if (ogreLogFile_.empty())
195        {
196            COUT(2) << "Warning: Ogre log file set to \"\". Defaulting to ogre.log" << std::endl;
197            ModifyConfigValue(ogreLogFile_, tset, "ogre.log");
198        }
199
200        boost::filesystem::path ogreConfigFilepath(PathConfig::getConfigPath() / this->ogreConfigFile_);
201        boost::filesystem::path ogreLogFilepath(PathConfig::getLogPath() / this->ogreLogFile_);
202
203        // create a new logManager
204        // Ogre::Root will detect that we've already created a Log
205        ogreLogger_.reset(new Ogre::LogManager());
206        COUT(4) << "Ogre LogManager created" << std::endl;
207
208        // create our own log that we can listen to
209        Ogre::Log *myLog;
210        myLog = ogreLogger_->createLog(ogreLogFilepath.string(), true, false, false);
211        COUT(4) << "Ogre Log created" << std::endl;
212
213        myLog->setLogDetail(Ogre::LL_BOREME);
214        myLog->addListener(this);
215
216        COUT(4) << "Creating Ogre Root..." << std::endl;
217
218        // check for config file existence because Ogre displays (caught) exceptions if not
219        if (!boost::filesystem::exists(ogreConfigFilepath))
220        {
221            // create a zero sized file
222            std::ofstream creator;
223            creator.open(ogreConfigFilepath.string().c_str());
224            creator.close();
225        }
226
227        // Leave plugins file empty. We're going to do that part manually later
228        ogreRoot_.reset(new Ogre::Root("", ogreConfigFilepath.string(), ogreLogFilepath.string()));
229
230        COUT(3) << "Ogre set up done." << std::endl;
231    }
232
233    void GraphicsManager::loadOgrePlugins()
234    {
235        // Plugin path can have many different locations...
236        std::string pluginPath = specialConfig::ogrePluginsDirectory;
237#ifdef DEPENDENCY_PACKAGE_ENABLE
238        if (!PathConfig::isDevelopmentRun())
239        {
240#  if defined(ORXONOX_PLATFORM_WINDOWS)
241            pluginPath = PathConfig::getExecutablePathString();
242#  elif defined(ORXONOX_PLATFORM_APPLE)
243            // TODO: Where are the plugins being installed to?
244            pluginPath = PathConfig::getExecutablePathString();
245#  endif
246        }
247#endif
248
249#ifdef ORXONOX_PLATFORM_WINDOWS
250        // Add OGRE plugin path to the environment. That way one plugin could
251        // also depend on another without problems on Windows
252        const char* currentPATH = getenv("PATH");
253        std::string newPATH = pluginPath;
254        if (currentPATH != NULL)
255            newPATH = std::string(currentPATH) + ';' + newPATH;
256        putenv(const_cast<char*>(("PATH=" + newPATH).c_str()));
257#endif
258
259        // Do some SubString magic to get the comma separated list of plugins
260        SubString plugins(ogrePlugins_, ",", " ", false, '\\', false, '"', false, '{', '}', false, '\0');
261        for (unsigned int i = 0; i < plugins.size(); ++i)
262            ogreRoot_->loadPlugin(pluginPath + '/' + plugins[i]);
263    }
264
265    void GraphicsManager::loadRenderer()
266    {
267        CCOUT(4) << "Configuring Renderer" << std::endl;
268
269        if (!ogreRoot_->restoreConfig() || Core::getInstance().getOgreConfigTimestamp() > Core::getInstance().getLastLevelTimestamp())
270        {
271            if (!ogreRoot_->showConfigDialog())
272                ThrowException(InitialisationFailed, "OGRE graphics configuration dialogue canceled.");
273            else
274                Core::getInstance().updateOgreConfigTimestamp();
275        }
276
277        CCOUT(4) << "Creating render window" << std::endl;
278
279        this->renderWindow_ = ogreRoot_->initialise(true, "Orxonox");
280        // Propagate the size of the new winodw
281        this->ogreWindowEventListener_->windowResized(renderWindow_);
282
283        Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, ogreWindowEventListener_.get());
284
285        // create a full screen default viewport
286        // Note: This may throw when adding a viewport with an existing z-order!
287        //       But in our case we only have one viewport for now anyway, therefore
288        //       no ScopeGuards or anything to handle exceptions.
289        this->viewport_ = this->renderWindow_->addViewport(0, 0);
290
291        Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(Ogre::MIP_UNLIMITED);
292
293        // add console commands
294        ModifyConsoleCommand(__CC_printScreen_name).setFunction(&GraphicsManager::printScreen, this);
295    }
296
297    void GraphicsManager::loadDebugOverlay()
298    {
299        // Load debug overlay to show info about fps and tick time
300        COUT(4) << "Loading Debug Overlay..." << std::endl;
301        debugOverlay_.reset(new XMLFile("debug.oxo"));
302        Loader::open(debugOverlay_.get());
303    }
304
305    /**
306    @note
307        A note about the Ogre::FrameListener: Even though we don't use them,
308        they still get called. However, the delta times are not correct (except
309        for timeSinceLastFrame, which is the most important). A little research
310        as shown that there is probably only one FrameListener that doesn't even
311        need the time. So we shouldn't run into problems.
312    */
313    void GraphicsManager::postUpdate(const Clock& time)
314    {
315        Ogre::FrameEvent evt;
316        evt.timeSinceLastFrame = time.getDeltaTime();
317        evt.timeSinceLastEvent = time.getDeltaTime(); // note: same time, but shouldn't matter anyway
318
319        // don't forget to call _fireFrameStarted to OGRE to make sure
320        // everything goes smoothly
321        ogreRoot_->_fireFrameStarted(evt);
322
323        // Pump messages in all registered RenderWindows
324        // This calls the WindowEventListener objects.
325        Ogre::WindowEventUtilities::messagePump();
326        // make sure the window stays active even when not focused
327        // (probably only necessary on windows)
328        this->renderWindow_->setActive(true);
329
330        // Time before rendering
331        uint64_t timeBeforeTick = time.getRealMicroseconds();
332
333        // Render frame
334        ogreRoot_->_updateAllRenderTargets();
335
336        uint64_t timeAfterTick = time.getRealMicroseconds();
337        // Subtract the time used for rendering from the tick time counter
338        Game::getInstance().subtractTickTime((int32_t)(timeAfterTick - timeBeforeTick));
339
340        // again, just to be sure OGRE works fine
341        ogreRoot_->_fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
342    }
343
344    void GraphicsManager::setCamera(Ogre::Camera* camera)
345    {
346        this->viewport_->setCamera(camera);
347    }
348
349    /**
350    @brief
351        Method called by the LogListener interface from Ogre.
352        We use it to capture Ogre log messages and handle it ourselves.
353    @param message
354        The message to be logged
355    @param lml
356        The message level the log is using
357    @param maskDebug
358        If we are printing to the console or not
359    @param logName
360        The name of this log (so you can have several listeners
361        for different logs, and identify them)
362    */
363    void GraphicsManager::messageLogged(const std::string& message,
364        Ogre::LogMessageLevel lml, bool maskDebug, const std::string& logName)
365    {
366        int orxonoxLevel;
367        std::string introduction;
368        // Do not show caught OGRE exceptions in front
369        if (message.find("EXCEPTION") != std::string::npos)
370        {
371            orxonoxLevel = OutputLevel::Debug;
372            introduction = "Ogre, caught exception: ";
373        }
374        else
375        {
376            switch (lml)
377            {
378            case Ogre::LML_TRIVIAL:
379                orxonoxLevel = this->ogreLogLevelTrivial_;
380                break;
381            case Ogre::LML_NORMAL:
382                orxonoxLevel = this->ogreLogLevelNormal_;
383                break;
384            case Ogre::LML_CRITICAL:
385                orxonoxLevel = this->ogreLogLevelCritical_;
386                break;
387            default:
388                orxonoxLevel = 0;
389            }
390            introduction = "Ogre: ";
391        }
392        OutputHandler::getOutStream(orxonoxLevel)
393            << introduction << message << std::endl;
394    }
395
396    size_t GraphicsManager::getRenderWindowHandle()
397    {
398        size_t windowHnd = 0;
399        renderWindow_->getCustomAttribute("WINDOW", &windowHnd);
400        return windowHnd;
401    }
402
403    bool GraphicsManager::isFullScreen() const
404    {
405        Ogre::ConfigOptionMap& options = ogreRoot_->getRenderSystem()->getConfigOptions();
406        if (options.find("Full Screen") != options.end())
407        {
408            if (options["Full Screen"].currentValue == "Yes")
409                return true;
410            else
411                return false;
412        }
413        else
414        {
415            COUT(0) << "Could not find 'Full Screen' render system option. Fix This!!!" << std::endl;
416            return false;
417        }
418    }
419
420    void GraphicsManager::printScreen()
421    {
422        assert(this->renderWindow_);
423        this->renderWindow_->writeContentsToTimestampedFile(PathConfig::getLogPathString() + "screenShot_", ".png");
424    }
425}
Note: See TracBrowser for help on using the repository browser.