Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/network/src/orxonox/gamestates/GSGraphics.cc @ 1914

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

Moved Exception to util now that debug has been moved.

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