Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Added a master InputState that is always active (except of course in game state 'ioConsole' when there is no InputManager in the first place)
This is necessary to call the console whenever you like. The state is of 'extended' nature, so it can hold an arbitrary number of Handlers.
The KeyBinder however is not yet configured to manage multiple keybindings.ini —> next job ;)

  • Property svn:eol-style set to native
File size: 12.5 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        delete this->guiManager_;
140
141        delete this->console_;
142
143        //inputManager_->getMasterInputState()->removeKeyHandler(this->masterKeyBinder_);
144        //delete this->masterKeyBinder_;
145        delete this->inputManager_;
146
147        this->ogreRoot_->detachRenderTarget(this->renderWindow_);
148        delete this->renderWindow_;
149        //this->ogreRoot_->shutdown
150        // TODO: destroy render window
151
152        Settings::_getInstance().bShowsGraphics_ = false;
153    }
154
155    /**
156        Main loop of the orxonox game.
157        We use the Ogre::Timer to measure time since it uses the most precise
158        method an a platform (however the windows timer lacks time when under
159        heavy kernel load!).
160        There is a simple mechanism to measure the average time spent in our
161        ticks as it may indicate performance issues.
162        A note about the Ogre::FrameListener: Even though we don't use them,
163        they still get called. However, the delta times are not correct (except
164        for timeSinceLastFrame, which is the most important). A little research
165        as shown that there is probably only one FrameListener that doesn't even
166        need the time. So we shouldn't run into problems.
167    */
168    void GSGraphics::ticked(const Clock& time)
169    {
170        unsigned long long timeBeforeTick = time.getRealMicroseconds();
171        float dt = time.getDeltaTime();
172
173        this->inputManager_->tick(dt);
174        // tick console
175        this->console_->tick(dt);
176        this->tickChild(time);
177       
178        unsigned long long timeAfterTick = time.getRealMicroseconds();
179
180        tickTime_ += (unsigned int)(timeAfterTick - timeBeforeTick);
181        if (timeAfterTick > statisticsStartTime_ + statisticsRefreshCycle_)
182        {
183            GraphicsEngine::getInstance().setAverageTickTime(
184                (float)tickTime_ * 0.001f / (frameCount_ - statisticsStartCount_));
185            float avgFPS = (float)(frameCount_ - statisticsStartCount_)
186                / (timeAfterTick - statisticsStartTime_) * 1000000.0;
187            GraphicsEngine::getInstance().setAverageFramesPerSecond(avgFPS);
188
189            tickTime_ = 0;
190            statisticsStartCount_ = frameCount_;
191            statisticsStartTime_  = timeAfterTick;
192        }
193
194        // don't forget to call _fireFrameStarted in ogre to make sure
195        // everything goes smoothly
196        Ogre::FrameEvent evt;
197        evt.timeSinceLastFrame = dt;
198        evt.timeSinceLastEvent = dt; // note: same time, but shouldn't matter anyway
199        ogreRoot_->_fireFrameStarted(evt);
200
201        // Pump messages in all registered RenderWindows
202        // This calls the WindowEventListener objects.
203        Ogre::WindowEventUtilities::messagePump();
204        // make sure the window stays active even when not focused
205        // (probably only necessary on windows)
206        this->renderWindow_->setActive(true);
207
208        // render
209        ogreRoot_->_updateAllRenderTargets();
210
211        // again, just to be sure ogre works fine
212        ogreRoot_->_fireFrameEnded(evt); // note: uses the same time as _fireFrameStarted
213
214        ++frameCount_;
215    }
216
217    void GSGraphics::declareResources()
218    {
219        CCOUT(4) << "Declaring Resources" << std::endl;
220        //TODO: Specify layout of data file and maybe use xml-loader
221        //TODO: Work with ressource groups (should be generated by a special loader)
222
223        if (resourceFile_ == "")
224        {
225            COUT(2) << "Warning: Ogre resource file set to \"\". Defaulting to resources.cfg" << std::endl;
226            ModifyConfigValue(resourceFile_, tset, "resources.cfg");
227        }
228
229        // Load resource paths from data file using configfile ressource type
230        Ogre::ConfigFile cf;
231        try
232        {
233            cf.load(Settings::getDataPath() + resourceFile_);
234        }
235        catch (...)
236        {
237            //COUT(1) << ex.getFullDescription() << std::endl;
238            COUT(0) << "Have you forgotten to set the data path in orxnox.ini?" << std::endl;
239            throw;
240        }
241
242        // Go through all sections & settings in the file
243        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
244
245        std::string secName, typeName, archName;
246        while (seci.hasMoreElements())
247        {
248            try
249            {
250                secName = seci.peekNextKey();
251                Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
252                Ogre::ConfigFile::SettingsMultiMap::iterator i;
253                for (i = settings->begin(); i != settings->end(); ++i)
254                {
255                    typeName = i->first; // for instance "FileSystem" or "Zip"
256                    archName = i->second; // name (and location) of archive
257
258                    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
259                        std::string(Settings::getDataPath() + archName), typeName, secName);
260                }
261            }
262            catch (Ogre::Exception& ex)
263            {
264                COUT(1) << ex.getFullDescription() << std::endl;
265            }
266        }
267    }
268
269    void GSGraphics::loadRenderer()
270    {
271        CCOUT(4) << "Configuring Renderer" << std::endl;
272
273        if (!ogreRoot_->restoreConfig())
274            if (!ogreRoot_->showConfigDialog())
275                ThrowException(InitialisationFailed, "Could not show Ogre configuration dialogue.");
276
277        CCOUT(4) << "Creating render window" << std::endl;
278
279        this->renderWindow_ = ogreRoot_->initialise(true, "OrxonoxV2");
280
281        Ogre::WindowEventUtilities::addWindowEventListener(this->renderWindow_, this);
282
283        //Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
284
285        // create a full screen default viewport
286        this->viewport_ = this->renderWindow_->addViewport(0, 0);
287    }
288
289    void GSGraphics::initialiseResources()
290    {
291        CCOUT(4) << "Initialising resources" << std::endl;
292        //TODO: Do NOT load all the groups, why are we doing that? And do we really do that? initialise != load...
293        try
294        {
295            Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
296            /*Ogre::StringVector str = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
297            for (unsigned int i = 0; i < str.size(); i++)
298            {
299            Ogre::ResourceGroupManager::getSingleton().loadResourceGroup(str[i]);
300            }*/
301        }
302        catch (...)
303        {
304            CCOUT(2) << "Error: There was a serious error when initialising the resources." << std::endl;
305            throw;
306        }
307    }
308
309
310    /**
311    @brief
312        Window has moved.
313    @param rw
314        The render window it occured in
315    */
316    void GSGraphics::windowMoved(Ogre::RenderWindow *rw)
317    {
318        for (ObjectList<orxonox::WindowEventListener>::iterator it = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
319            it->windowMoved();
320    }
321
322    /**
323    @brief
324        Window has resized.
325    @param rw
326        The render window it occured in
327    @note
328        GraphicsEngine has a render window stored itself. This is the same
329        as rw. But we have to be careful when using multiple render windows!
330    */
331    void GSGraphics::windowResized(Ogre::RenderWindow *rw)
332    {
333        for (ObjectList<orxonox::WindowEventListener>::iterator it = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
334            it->windowResized(this->renderWindow_->getWidth(), this->renderWindow_->getHeight());
335    }
336
337    /**
338    @brief
339        Window focus has changed.
340    @param rw
341        The render window it occured in
342    */
343    void GSGraphics::windowFocusChanged(Ogre::RenderWindow *rw)
344    {
345        for (ObjectList<orxonox::WindowEventListener>::iterator it = ObjectList<orxonox::WindowEventListener>::begin(); it; ++it)
346            it->windowFocusChanged();
347    }
348
349    /**
350    @brief
351        Window was closed.
352    @param rw
353        The render window it occured in
354    */
355    void GSGraphics::windowClosed(Ogre::RenderWindow *rw)
356    {
357        // using CommandExecutor in order to avoid depending on Orxonox.h.
358        //CommandExecutor::execute("exit", false);
359        this->requestState("root");
360    }
361
362    void GSGraphics::printScreen()
363    {
364        if (this->renderWindow_)
365        {
366            this->renderWindow_->writeContentsToTimestampedFile("shot_", ".jpg");
367        }
368    }
369}
Note: See TracBrowser for help on using the repository browser.