Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/orxonox/gamestates/GSRoot.cc @ 2549

Last change on this file since 2549 was 2549, checked in by rgrieder, 15 years ago

Moved tick time measurement to GSRoot. The values get combined with the one from GSGraphics.

  • Property svn:eol-style set to native
File size: 10.7 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 "GSRoot.h"
31
32#include "util/Exception.h"
33#include "util/Debug.h"
34#include "core/Core.h"
35#include "core/Factory.h"
36#include "core/ConfigValueIncludes.h"
37#include "core/CoreIncludes.h"
38#include "core/ConsoleCommand.h"
39#include "core/CommandLine.h"
40#include "core/Shell.h"
41#include "core/TclBind.h"
42#include "core/TclThreadManager.h"
43#include "core/LuaBind.h"
44#include "tools/Timer.h"
45#include "objects/Tickable.h"
46#include "Settings.h"
47
48#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
49#  ifndef WIN32_LEAN_AND_MEAN
50#    define WIN32_LEAN_AND_MEAN
51#  endif
52#  include "windows.h"
53
54   //Get around Windows hackery
55#  ifdef max
56#    undef max
57#  endif
58#  ifdef min
59#    undef min
60#  endif
61#endif
62
63namespace orxonox
64{
65    SetCommandLineArgument(dataPath, "").information("PATH");
66    SetCommandLineArgument(limitToCPU, 1).information("0: off | #cpu");
67
68    GSRoot::GSRoot()
69        : RootGameState("root")
70        , timeFactor_(1.0f)
71        , bPaused_(false)
72        , timeFactorPauseBackup_(1.0f)
73        , settings_(0)
74        , tclBind_(0)
75        , tclThreadManager_(0)
76        , shell_(0)
77    {
78        RegisterRootObject(GSRoot);
79        setConfigValues();
80
81        this->ccSetTimeFactor_ = 0;
82        this->ccPause_ = 0;
83    }
84
85    GSRoot::~GSRoot()
86    {
87    }
88
89    void GSRoot::setConfigValues()
90    {
91        SetConfigValue(statisticsRefreshCycle_, 250000)
92            .description("Sets the time in microseconds interval at which average fps, etc. get updated.");
93        SetConfigValue(statisticsAvgLength_, 1000000)
94            .description("Sets the time in microseconds interval at which average fps, etc. gets calculated.");
95    }
96
97    void GSRoot::enter()
98    {
99        // creates the class hierarchy for all classes with factories
100        Factory::createClassHierarchy();
101
102        // reset game speed to normal
103        timeFactor_ = 1.0f;
104
105        // reset frame counter
106        this->frameCount_ = 0;
107        this->statisticsStartTime_ = 0;
108        this->statisticsTickTimes_.clear();
109        this->periodTickTime_ = 0;
110        this->avgFPS_ = 0.0f;
111        this->avgTickTime_ = 0.0f;
112
113        // Create the lua interface
114        this->luaBind_ = new LuaBind();
115
116        // instantiate Settings class
117        this->settings_ = new Settings();
118
119        std::string dataPath = CommandLine::getValue("dataPath");
120        if (dataPath != "")
121        {
122            if (*dataPath.end() != '/' && *dataPath.end() != '\\')
123                Settings::tsetDataPath(dataPath + "/");
124            else
125                Settings::tsetDataPath(dataPath);
126        }
127
128        // initialise TCL
129        this->tclBind_ = new TclBind(Settings::getDataPath());
130        this->tclThreadManager_ = new TclThreadManager(tclBind_->getTclInterpreter());
131
132        // create a shell
133        this->shell_ = new Shell();
134
135        // limit the main thread to the first core so that QueryPerformanceCounter doesn't jump
136        // do this after ogre has initialised. Somehow Ogre changes the settings again (not through
137        // the timer though).
138        int limitToCPU = CommandLine::getValue("limitToCPU");
139        if (limitToCPU > 0)
140            setThreadAffinity((unsigned int)(limitToCPU - 1));
141
142        {
143            // add console commands
144            FunctorMember<GSRoot>* functor = createFunctor(&GSRoot::exitGame);
145            functor->setObject(this);
146            this->ccExit_ = createConsoleCommand(functor, "exit");
147            CommandExecutor::addConsoleCommandShortcut(this->ccExit_);
148        }
149
150        {
151            // add console commands
152            FunctorMember01<GameStateBase, const std::string&>* functor = createFunctor(&GameStateBase::requestState);
153            functor->setObject(this);
154            this->ccSelectGameState_ = createConsoleCommand(functor, "selectGameState");
155            CommandExecutor::addConsoleCommandShortcut(this->ccSelectGameState_);
156        }
157
158        {
159            // time factor console command
160            FunctorMember<GSRoot>* functor = createFunctor(&GSRoot::setTimeFactor);
161            functor->setObject(this);
162            this->ccSetTimeFactor_ = createConsoleCommand(functor, "setTimeFactor");
163            CommandExecutor::addConsoleCommandShortcut(this->ccSetTimeFactor_).accessLevel(AccessLevel::Offline).defaultValue(0, 1.0);
164        }
165
166        {
167            // time factor console command
168            FunctorMember<GSRoot>* functor = createFunctor(&GSRoot::pause);
169            functor->setObject(this);
170            this->ccPause_ = createConsoleCommand(functor, "pause");
171            CommandExecutor::addConsoleCommandShortcut(this->ccPause_).accessLevel(AccessLevel::Offline);
172        }
173    }
174
175    void GSRoot::leave()
176    {
177        // destroy console commands
178        delete this->ccExit_;
179        delete this->ccSelectGameState_;
180
181        delete this->shell_;
182        delete this->tclThreadManager_;
183        delete this->tclBind_;
184
185        delete this->settings_;
186        delete this->luaBind_;
187
188        if (this->ccSetTimeFactor_)
189        {
190            delete this->ccSetTimeFactor_;
191            this->ccSetTimeFactor_ = 0;
192        }
193
194        if (this->ccPause_)
195        {
196            delete this->ccPause_;
197            this->ccPause_ = 0;
198        }
199    }
200
201    void GSRoot::ticked(const Clock& time)
202    {
203        uint64_t timeBeforeTick = time.getRealMicroseconds();
204
205        TclThreadManager::getInstance().tick(time.getDeltaTime());
206
207        for (ObjectList<TimerBase>::iterator it = ObjectList<TimerBase>::begin(); it; ++it)
208            it->tick(time);
209
210        /*** HACK *** HACK ***/
211        // Call the Tickable objects
212        float leveldt = time.getDeltaTime();
213        if (leveldt > 1.0f)
214        {
215            // just loaded
216            leveldt = 0.0f;
217        }
218        for (ObjectList<Tickable>::iterator it = ObjectList<Tickable>::begin(); it; ++it)
219            it->tick(leveldt * this->timeFactor_);
220        /*** HACK *** HACK ***/
221
222        uint64_t timeAfterTick = time.getRealMicroseconds();
223
224        // STATISTICS
225        statisticsTickInfo tickInfo = {timeAfterTick, timeAfterTick - timeBeforeTick};
226        statisticsTickTimes_.push_back(tickInfo);
227
228        // Ticks GSGraphics or GSDedicated
229        this->tickChild(time);
230
231        // Note: tickInfo.tickLength is modified by GSGraphics or GSDedicated!
232        this->periodTickTime_ += tickInfo.tickLength;
233        if (timeAfterTick > statisticsStartTime_ + statisticsRefreshCycle_)
234        {
235            while (statisticsTickTimes_.front().tickTime < timeAfterTick - statisticsAvgLength_)
236            {
237                this->periodTickTime_ -= this->statisticsTickTimes_.front().tickLength;
238                this->statisticsTickTimes_.pop_front();
239            }
240
241            uint32_t framesPerPeriod = this->statisticsTickTimes_.size();
242            this->avgFPS_ = (float)framesPerPeriod / (tickInfo.tickTime - this->statisticsTickTimes_.front().tickTime) * 1000000.0;
243            this->avgTickTime_ = (float)this->periodTickTime_ / framesPerPeriod / 1000.0;
244
245            statisticsStartTime_ = timeAfterTick;
246        }
247
248        ++this->frameCount_;
249    }
250
251    /**
252    @note
253        The code of this function has been copied and adjusted from OGRE, an open source graphics engine.
254            (Object-oriented Graphics Rendering Engine)
255        For the latest info, see http://www.ogre3d.org/
256
257        Copyright (c) 2000-2008 Torus Knot Software Ltd
258
259        OGRE is licensed under the LGPL. For more info, see OGRE license.
260    */
261    void GSRoot::setThreadAffinity(unsigned int limitToCPU)
262    {
263#if ORXONOX_PLATFORM == ORXONOX_PLATFORM_WIN32
264        // Get the current process core mask
265        DWORD procMask;
266        DWORD sysMask;
267#  if _MSC_VER >= 1400 && defined (_M_X64)
268        GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask, (PDWORD_PTR)&sysMask);
269#  else
270        GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
271#  endif
272
273        // If procMask is 0, consider there is only one core available
274        // (using 0 as procMask will cause an infinite loop below)
275        if (procMask == 0)
276            procMask = 1;
277
278        // if the core specified with limitToCPU is not available, take the lowest one
279        if (!(procMask & (1 << limitToCPU)))
280            limitToCPU = 0;
281
282        // Find the lowest core that this process uses and limitToCPU suggests
283        DWORD threadMask = 1;
284        while ((threadMask & procMask) == 0 || (threadMask < (1u << limitToCPU)))
285            threadMask <<= 1;
286
287        // Set affinity to the first core
288        SetThreadAffinityMask(GetCurrentThread(), threadMask);
289#endif
290    }
291
292    /**
293    @brief
294        Changes the speed of Orxonox
295    */
296    void GSRoot::setTimeFactor(float factor)
297    {
298        if (Core::isMaster())
299        {
300            if (!this->bPaused_)
301            {
302                TimeFactorListener::timefactor_s = factor;
303
304                for (ObjectList<TimeFactorListener>::iterator it = ObjectList<TimeFactorListener>::begin(); it != ObjectList<TimeFactorListener>::end(); ++it)
305                    it->changedTimeFactor(factor, this->timeFactor_);
306
307                this->timeFactor_ = factor;
308            }
309            else
310                this->timeFactorPauseBackup_ = factor;
311        }
312    }
313
314    void GSRoot::pause()
315    {
316        if (Core::isMaster())
317        {
318            if (!this->bPaused_)
319            {
320                this->timeFactorPauseBackup_ = this->timeFactor_;
321                this->setTimeFactor(0.0f);
322                this->bPaused_ = true;
323            }
324            else
325            {
326                this->bPaused_ = false;
327                this->setTimeFactor(this->timeFactorPauseBackup_);
328            }
329        }
330    }
331
332    ////////////////////////
333    // TimeFactorListener //
334    ////////////////////////
335    float TimeFactorListener::timefactor_s = 1.0f;
336
337    TimeFactorListener::TimeFactorListener()
338    {
339        RegisterRootObject(TimeFactorListener);
340    }
341}
Note: See TracBrowser for help on using the repository browser.