Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Added support for non exclusive mouse mode on Windows. This means you get the normal mouse cursor when displaying a GUI menu in windowed mode.
The feature is activated via InputState (InputState::setIsExclusiveMouse(bool)). Whenever that state is on top of the mouse state stack, the input manager reloads if necessary.

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