Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Fixed two issues with input:

  • Buffer gets cleared now when the window focus changes
  • Added a configValue in the InGameConsole:

Until now the input was always transparent to the level when activating the console (exception keyboard input of course)
bHidesAllInput_ can change that setting (configured in orxonox.ini)

@Oli: Sorry, couldn't apply the patch in the network branch because of conflicts (I have already made some changes to the InputManager in the trunk)

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