Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/gamestates/GSGraphics.cc @ 1824

Last change on this file since 1824 was 1824, checked in by rgrieder, 16 years ago

Added some more Ogre shutdown code. Does not yet work properly if you wish to reload GSGraphics.

  • 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 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "OrxonoxStableHeaders.h"
30#include "GSGraphics.h"
31
32#include <fstream>
33#include <OgreConfigFile.h>
34#include <OgreFrameListener.h>
35#include <OgreRoot.h>
36#include <OgreException.h>
37#include <OgreRenderWindow.h>
38#include <OgreTextureManager.h>
39#include <OgreViewport.h>
40#include <OgreWindowEventUtilities.h>
41
42#include "util/Debug.h"
43#include "util/Exception.h"
44#include "core/ConsoleCommand.h"
45#include "core/ConfigValueIncludes.h"
46#include "core/CoreIncludes.h"
47#include "core/input/InputManager.h"
48#include "core/input/KeyBinder.h"
49#include "core/input/ExtendedInputState.h"
50#include "overlays/console/InGameConsole.h"
51#include "gui/GUIManager.h"
52#include "tools/WindowEventListener.h"
53#include "Settings.h"
54
55// for compatibility
56#include "GraphicsEngine.h"
57
58namespace orxonox
59{
60    GSGraphics::GSGraphics()
61        : GameState<GSRoot>("graphics")
62        , ogreRoot_(0)
63        , inputManager_(0)
64        , console_(0)
65        , guiManager_(0)
66        , masterKeyBinder_(0)
67        , frameCount_(0)
68        , statisticsRefreshCycle_(0)
69        , statisticsStartTime_(0)
70        , statisticsStartCount_(0)
71        , tickTime_(0)
72    {
73        RegisterRootObject(GSGraphics);
74    }
75
76    GSGraphics::~GSGraphics()
77    {
78    }
79
80    void GSGraphics::setConfigValues()
81    {
82        SetConfigValue(resourceFile_, "resources.cfg").description("Location of the resources file in the data path.");
83        SetConfigValue(statisticsRefreshCycle_, 200000).description("Sets the time in microseconds interval at which average fps, etc. get updated.");
84    }
85
86    void GSGraphics::enter()
87    {
88        Settings::_getInstance().bShowsGraphics_ = true;
89
90        setConfigValues();
91
92        this->ogreRoot_ = getParent()->getOgreRoot();
93
94        this->declareResources();
95        this->loadRenderer();    // creates the render window
96        // TODO: Spread this so that this call only initialises things needed for the Console and GUI
97        this->initialiseResources();
98
99
100        // HACK: temporary:
101        GraphicsEngine* graphicsEngine = getParent()->getGraphicsEngine();
102        graphicsEngine->renderWindow_  = this->renderWindow_;
103        graphicsEngine->root_          = this->ogreRoot_;
104        graphicsEngine->viewport_      = this->viewport_;
105
106
107        // Calls the InputManager which sets up the input devices.
108        // The render window width and height are used to set up the mouse movement.
109        inputManager_ = new InputManager();
110        size_t windowHnd = 0;
111        this->renderWindow_->getCustomAttribute("WINDOW", &windowHnd);
112        inputManager_->initialise(windowHnd, renderWindow_->getWidth(), renderWindow_->getHeight(), true);
113        // Configure master input state with a KeyBinder
114        //masterKeyBinder_ = new KeyBinder();
115        //inputManager_->getMasterInputState()->addKeyHandler(masterKeyBinder_);
116
117        // Load the InGameConsole
118        console_ = new InGameConsole();
119        console_->initialise();
120
121        // load the CEGUI interface
122        guiManager_ = new GUIManager();
123        guiManager_->initialise(this->renderWindow_);
124
125        // reset frame counter
126        this->frameCount_ = 0;
127        this->tickTime_ = 0;
128        statisticsStartTime_ = 0;
129        statisticsStartCount_ = 0;
130
131        // add console commands
132        FunctorMember<GSGraphics>* functor1 = createFunctor(&GSGraphics::printScreen);
133        functor1->setObject(this);
134        CommandExecutor::addConsoleCommandShortcut(createConsoleCommand(functor1, "printScreen"));
135    }
136
137    void GSGraphics::leave()
138    {
139        using namespace Ogre;
140
141        delete this->guiManager_;
142
143        delete this->console_;
144
145        //inputManager_->getMasterInputState()->removeKeyHandler(this->masterKeyBinder_);
146        //delete this->masterKeyBinder_;
147        delete this->inputManager_;
148
149        // destroy render window
150        this->renderWindow_->removeAllViewports();
151        this->renderWindow_->removeAllListeners();
152        RenderSystem* renderer = this->ogreRoot_->getRenderSystem();
153        renderer->destroyRenderWindow("Orxonox");
154
155        // Does the opposite of initialise()
156        ogreRoot_->shutdown();
157
158        // Remove all resources and resource groups
159        StringVector groups = ResourceGroupManager::getSingleton().getResourceGroups();
160        for (StringVector::iterator it = groups.begin(); it != groups.end(); ++it)
161        {
162            ResourceGroupManager::getSingleton().destroyResourceGroup(*it);
163        }
164
165        ParticleSystemManager::getSingleton().removeAllTemplates();
166
167        // Shutdown the render system
168        this->ogreRoot_->setRenderSystem(0);
169
170        Settings::_getInstance().bShowsGraphics_ = false;
171    }
172
173    /**
174        Main loop of the orxonox game.
175        We use the Ogre::Timer to measure time since it uses the most precise
176        method an a platform (however the windows timer lacks time when under
177        heavy kernel load!).
178        There is a simple mechanism to measure the average time spent in our
179        ticks as it may indicate performance issues.
180        A note about the Ogre::FrameListener: Even though we don't use them,
181        they still get called. However, the delta times are not correct (except
182        for timeSinceLastFrame, which is the most important). A little research
183        as shown that there is probably only one FrameListener that doesn't even
184        need the time. So we shouldn't run into problems.
185    */
186    void GSGraphics::ticked(const Clock& time)
187    {
188        unsigned long long timeBeforeTick = time.getRealMicroseconds();
189        float dt = time.getDeltaTime();
190
191        this->inputManager_->tick(dt);
192        // tick console
193        this->console_->tick(dt);
194        this->tickChild(time);
195       
196        unsigned long long timeAfterTick = time.getRealMicroseconds();
197
198        tickTime_ += (unsigned int)(timeAfterTick - timeBeforeTick);
199        if (timeAfterTick > statisticsStartTime_ + statisticsRefreshCycle_)
200        {
201            GraphicsEngine::getInstance().setAverageTickTime(
202                (float)tickTime_ * 0.001f / (frameCount_ - statisticsStartCount_));
203            float avgFPS = (float)(frameCount_ - statisticsStartCount_)
204                / (timeAfterTick - statisticsStartTime_) * 1000000.0;
205            GraphicsEngine::getInstance().setAverageFramesPerSecond(avgFPS);
206
207            tickTime_ = 0;
208            statisticsStartCount_ = frameCount_;
209            statisticsStartTime_  = timeAfterTick;
210        }
211
212        // don't forget to call _fireFrameStarted in ogre to make sure
213        // everything goes smoothly
214        Ogre::FrameEvent evt;
215        evt.timeSinceLastFrame = dt;
216        evt.timeSinceLastEvent = dt; // note: same time, but shouldn't matter anyway
217        ogreRoot_->_fireFrameStarted(evt);
218
219        // Pump messages in all registered RenderWindows
220        // This calls the WindowEventListener objects.
221        Ogre::WindowEventUtilities::messagePump();
222        // make sure the window stays active even when not focused
223        // (probably only necessary on windows)
224        this->renderWindow_->setActive(true);
225
226        // render
227        ogreRoot_->_updateAllRenderTargets();
228
229        // again, just to be sure ogre works fine
230        ogreRoot_->_fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
231
232        ++frameCount_;
233    }
234
235    void GSGraphics::declareResources()
236    {
237        CCOUT(4) << "Declaring Resources" << std::endl;
238        //TODO: Specify layout of data file and maybe use xml-loader
239        //TODO: Work with ressource groups (should be generated by a special loader)
240
241        if (resourceFile_ == "")
242        {
243            COUT(2) << "Warning: Ogre resource file set to \"\". Defaulting to resources.cfg" << std::endl;
244            ModifyConfigValue(resourceFile_, tset, "resources.cfg");
245        }
246
247        // Load resource paths from data file using configfile ressource type
248        Ogre::ConfigFile cf;
249        try
250        {
251            cf.load(Settings::getDataPath() + resourceFile_);
252        }
253        catch (...)
254        {
255            //COUT(1) << ex.getFullDescription() << std::endl;
256            COUT(0) << "Have you forgotten to set the data path in orxnox.ini?" << std::endl;
257            throw;
258        }
259
260        // Go through all sections & settings in the file
261        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
262
263        std::string secName, typeName, archName;
264        while (seci.hasMoreElements())
265        {
266            try
267            {
268                secName = seci.peekNextKey();
269                Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
270                Ogre::ConfigFile::SettingsMultiMap::iterator i;
271                for (i = settings->begin(); i != settings->end(); ++i)
272                {
273                    typeName = i->first; // for instance "FileSystem" or "Zip"
274                    archName = i->second; // name (and location) of archive
275
276                    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
277                        std::string(Settings::getDataPath() + archName), typeName, secName);
278                }
279            }
280            catch (Ogre::Exception& ex)
281            {
282                COUT(1) << ex.getFullDescription() << std::endl;
283            }
284        }
285    }
286
287    void GSGraphics::loadRenderer()
288    {
289        CCOUT(4) << "Configuring Renderer" << std::endl;
290
291        if (!ogreRoot_->restoreConfig())
292            if (!ogreRoot_->showConfigDialog())
293                ThrowException(InitialisationFailed, "Could not show Ogre configuration dialogue.");
294
295        CCOUT(4) << "Creating render window" << std::endl;
296
297        this->renderWindow_ = ogreRoot_->initialise(true, "Orxonox");
298
299        Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, this);
300
301        Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(0);
302
303        // create a full screen default viewport
304        this->viewport_ = this->renderWindow_->addViewport(0, 0);
305    }
306
307    void GSGraphics::initialiseResources()
308    {
309        CCOUT(4) << "Initialising resources" << std::endl;
310        //TODO: Do NOT load all the groups, why are we doing that? And do we really do that? initialise != load...
311        //try
312        //{
313            Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
314            /*Ogre::StringVector str = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
315            for (unsigned int i = 0; i < str.size(); i++)
316            {
317            Ogre::ResourceGroupManager::getSingleton().loadResourceGroup(str[i]);
318            }*/
319        //}
320        //catch (...)
321        //{
322        //    CCOUT(2) << "Error: There was a serious error when initialising the resources." << std::endl;
323        //    throw;
324        //}
325    }
326
327
328    /**
329    @brief
330        Window has moved.
331    @param rw
332        The render window it occured in
333    */
334    void GSGraphics::windowMoved(Ogre::RenderWindow *rw)
335    {
336        for (ObjectList<orxonox::WindowEventListener>::iterator it = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
337            it->windowMoved();
338    }
339
340    /**
341    @brief
342        Window has resized.
343    @param rw
344        The render window it occured in
345    @note
346        GraphicsEngine has a render window stored itself. This is the same
347        as rw. But we have to be careful when using multiple render windows!
348    */
349    void GSGraphics::windowResized(Ogre::RenderWindow *rw)
350    {
351        for (ObjectList<orxonox::WindowEventListener>::iterator it = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
352            it->windowResized(this->renderWindow_->getWidth(), this->renderWindow_->getHeight());
353    }
354
355    /**
356    @brief
357        Window focus has changed.
358    @param rw
359        The render window it occured in
360    */
361    void GSGraphics::windowFocusChanged(Ogre::RenderWindow *rw)
362    {
363        for (ObjectList<orxonox::WindowEventListener>::iterator it = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
364            it->windowFocusChanged();
365    }
366
367    /**
368    @brief
369        Window was closed.
370    @param rw
371        The render window it occured in
372    */
373    void GSGraphics::windowClosed(Ogre::RenderWindow *rw)
374    {
375        // using CommandExecutor in order to avoid depending on Orxonox.h.
376        //CommandExecutor::execute("exit", false);
377        this->requestState("root");
378    }
379
380    void GSGraphics::printScreen()
381    {
382        if (this->renderWindow_)
383        {
384            this->renderWindow_->writeContentsToTimestampedFile("shot_", ".jpg");
385        }
386    }
387}
Note: See TracBrowser for help on using the repository browser.