Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

shutdown sequence poses problems after all…

  • 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.