Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gui/src/orxonox/gamestates/GSGraphics.cc @ 1688

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

Modified the GameState hierarchy so that you can get the parent with the actual type by calling getParent().

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