Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/buildsystem/src/orxonox/gamestates/GSGraphics.cc @ 2274

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

Applied long created patch that removes plugins.cfg and puts the content into orxonox.ini
This also allows to specify the media path for each 'distribution' individually because orxonox.ini has been added to the default files.

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