Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/gamestates/GSRoot.cc @ 2756

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

Minimising problems when including windows.h because it defines macros like "min" and "max" if not explicitly specified.
There are two headers we use that include windows.h: OgreWindowEventUtilities.h and enet.h. I had to tweak a little bit there as well.

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