Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 1689 was 1689, checked in by rgrieder, 16 years ago
  • renamed:

GameState —> GameStateBase
GameStateTyped<T> —> GameState

  • moved command line parsing from GSRoot to RootGameState.
  • 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        : GameState<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.