Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/miniprojects/src/orxonox/gamestates/GSRoot.cc @ 2772

Last change on this file since 2772 was 2710, checked in by rgrieder, 16 years ago

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

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