source: nrEngine/src/Clock.cpp @ 23

Revision 23, 11.5 KB checked in by art, 13 years ago (diff)
Line 
1/***************************************************************************
2 *                                                                         *
3 *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
4 *       mailto: <tevs@mpi-sb.mpg.de>                                      *
5 *                                                                         *
6 *   This program is free software; you can redistribute it and/or modify  *
7 *   it under the terms of the GNU General Public License as published by  *
8 *   the Free Software Foundation; either version 2 of the License, or     *
9 *   (at your option) any later version.                                   *
10 *                                                                         *
11 ***************************************************************************/
12
13//----------------------------------------------------------------------------------
14// Includes
15//----------------------------------------------------------------------------------
16#include "Clock.h"
17#include "Log.h"
18
19//----------------------------------------------------------------------------------
20// Defines
21//----------------------------------------------------------------------------------
22#define DEFAULT_OBSERVER_NAME "__no_name__"
23
24
25namespace nrEngine{
26       
27        //----------------------------------------------------------------------------------
28        ScriptFunctionDec(scriptResetClock, Clock)
29        {
30                // check parameter count
31                if (args.size() < 1)
32                {
33                        return ScriptResult(std::string("resetClock([timeToReset = 0, [reset_all_timers = 0]]) - Not valid parameter count!"));
34                }
35
36                if (param.size() == 0)
37                {
38                        return ScriptResult(std::string("resetClock() was not properly registered before. Clock was not passed!"));
39                }
40               
41                // get clock
42                Clock* clock = nrEngine::ScriptEngine::parameter_cast<Clock* >(param[0]);
43                if (clock == NULL)
44                {
45                        return ScriptResult(std::string("resetClock() was not properly registered before. Clock was not passed!"));             
46                }
47               
48                // get parameters
49                bool shouldResetTimers = false;
50                float64 timeToReset = 0;
51                if (args.size() > 1) timeToReset = boost::lexical_cast<float64>(args[1]);
52                if (args.size() > 2) shouldResetTimers = boost::lexical_cast<bool>(args[2]);
53               
54                // reset the clock
55                clock->reset(timeToReset, shouldResetTimers);
56
57                return ScriptResult();
58        }
59
60        //------------------------------------------------------------------------
61        Clock::Clock() : ITask(){
62               
63                setTaskName("SystemClock");
64                currentTime = 0;
65                frameTime = 0;
66                frameNumber = 0;
67               
68                sourceStartValue = 0;
69                sourceLastValue = 0;
70               
71                useFixRate = false;
72                fixFrameRate = 0;
73                useMaxRate = false;
74                maxFrameRate = 0;
75                lastCurrentTime = 0;
76
77                // add default frame time       
78                setFrameWindow (7);
79                frameTime = _getFilteredFrameDuration();
80               
81                timeSource.reset();
82
83                // setup some other values
84                nextSyncTime = 0;
85                syncInterval = 0;
86               
87        }
88               
89        //------------------------------------------------------------------------
90        Clock::~Clock(){
91                stopTask();
92        }
93       
94        //------------------------------------------------------------------------     
95        void Clock::reset(float64 resetToTime, bool resetAllObservers)
96        {
97                // check if we have to reset observers
98                if (resetAllObservers)
99                {
100                        ObserverList::iterator it = observers.begin();
101                        for (; it != observers.end(); it++)
102                                (*it)->resetObserver(resetToTime);
103                }
104               
105                // reset the clock
106                lastCurrentTime = resetToTime;
107                currentTime = resetToTime;
108                frameTime = frameDefaultTime;
109                frameNumber = 0;
110                realFrameTime = frameDefaultTime;
111                nextSyncTime = 0;
112               
113                // reset time source
114                setTimeSource(timeSource);
115               
116                // reset the frame history
117                setFrameWindow(frameFilteringWindow, frameDefaultTime);
118               
119                NR_Log(Log::LOG_ENGINE, "Clock: Reset clock to %f", resetToTime);               
120        }
121
122        //------------------------------------------------------------------------     
123        void Clock::setTimeSource(SharedPtr<TimeSource> timeSource)
124        {               
125                this->timeSource = timeSource;
126       
127                if (timeSource != NULL){
128                        timeSource->reset();
129                        sourceStartValue = timeSource->getTime();
130                        sourceLastValue = sourceStartValue;
131                }
132        }
133       
134        //------------------------------------------------------------------------     
135        void Clock::setSyncInterval(uint32 milliseconds)
136        {
137                this->syncInterval = milliseconds;
138        }
139       
140        //------------------------------------------------------------------------
141        bool Clock::isAnySourceBounded(){
142                return (timeSource != NULL);
143        }
144       
145        //------------------------------------------------------------------------
146        SharedPtr<Timer> Clock::createTimer(){
147       
148                // create timer as observer
149                SharedPtr<ITimeObserver> timer(new Timer(*this));
150               
151                // add him to the list
152                int32 id = addObserver(timer);
153               
154                if (id == 0){
155                        NR_Log(Log::LOG_ENGINE, Log::LL_WARNING, "Clock::createTimer(): Can not add timer to the observer list");
156                }
157               
158                // set the id of the timer
159                timer->_observerID = id;
160               
161                // return created timer
162                return ::boost::dynamic_pointer_cast<Timer, ITimeObserver>(timer);
163               
164        }
165       
166        //------------------------------------------------------------------------
167        Result Clock::onStartTask()
168        {
169                // register function by the manager
170                std::vector<nrEngine::ScriptParam> param;
171                param.push_back(this);
172                Engine::sScriptEngine()->add("resetClock", scriptResetClock, param);
173               
174                return OK;
175        }
176
177        //------------------------------------------------------------------------
178        Result Clock::stopTask()
179        {
180       
181                timeSource.reset();
182               
183                for (uint32 i=0; i < observers.size(); i++){
184                        observers[i].reset();
185                }
186                observers.clear();
187               
188                Engine::sScriptEngine()->del("resetClock");
189               
190                return OK;
191        }
192       
193        //------------------------------------------------------------------------
194        Result Clock::updateTask(){
195
196                // check whenever a time source is bound
197                if (timeSource == NULL) return CLOCK_NO_TIME_SOURCE;
198
199                timeSource->notifyNextFrame();
200               
201                // calculate exact frame duration time
202                float64 exactFrameDuration = _getExactFrameDuration();
203                _addToFrameHistory(exactFrameDuration);
204               
205                // get filtered frame time
206                frameTime = _getFilteredFrameDuration();
207                frameNumber ++;
208
209                // check if we use frame bounder
210                do {
211                        currentTime = timeSource->getTime();
212
213                        // get through the list of connected observers and notify them
214                        ObserverList::iterator it;
215                        for (it = observers.begin(); it != observers.end(); ++it){
216                                (*it)->notifyTimeObserver();
217                        }
218
219                        // check if we need to sync the clock
220                        if (syncInterval > 0 && nextSyncTime < currentTime)
221                        {
222                                timeSource->sync();
223                                nextSyncTime = currentTime + static_cast<float64>(syncInterval) / 1000.0;
224                        }
225
226                } while (useMaxRate && (currentTime - lastCurrentTime) < invMaxFrameRate);
227
228                // set the last current time we used to the current time
229                lastCurrentTime = currentTime;
230               
231                // OK
232                return OK;
233        }
234
235        //------------------------------------------------------------------------
236        float64 Clock::getTime() const{
237                return currentTime;
238        }
239       
240        //------------------------------------------------------------------------
241        float32 Clock::getFrameInterval() const{
242                return (float32)frameTime;
243        }
244       
245        //------------------------------------------------------------------------
246        float32 Clock::getRealFrameInterval() const
247        {
248                return (float32)realFrameTime;
249        }
250
251        //------------------------------------------------------------------------
252        float32 Clock::getRealFrameRate() const
253        {
254                return 1.0f / getRealFrameInterval();
255        }
256
257        //------------------------------------------------------------------------
258        int32 Clock::getFrameNumber() const{
259                return frameNumber;
260        }
261       
262        //------------------------------------------------------------------------
263        float32 Clock::getFrameRate() const{
264                return 1.0f / getFrameInterval();
265        }
266               
267        //------------------------------------------------------------------------
268        int32 Clock::addObserver(SharedPtr<ITimeObserver> timeObserver){
269               
270                int32 id = 0;
271               
272                if (timeObserver != NULL){
273                        observers.push_back (timeObserver);
274                        id = observers.size();
275                        observerIDList[::std::string(DEFAULT_OBSERVER_NAME) + ::boost::lexical_cast< ::std::string >(id)] = id;
276                        observers[observers.size()-1]->_observerID = id;
277                }
278               
279                return id;
280        }
281       
282        //------------------------------------------------------------------------
283        Result Clock::removeObserver(int32 observerID){
284               
285                int32 id = observerID - 1;
286                if (id <= 0 || id+1 >= static_cast<int32>(observers.size())
287                                || observerIDList.find(::std::string(DEFAULT_OBSERVER_NAME) + 
288                                ::boost::lexical_cast< ::std::string >(observerID)) == observerIDList.end()){
289                        return CLOCK_OBSERVER_NOT_FOUND;
290                }
291               
292                // remove it from the list
293                observers.erase(observers.begin() + id);
294               
295                // also clean the map enty for this id
296                observerIDList.erase(observerIDList.find( ::std::string(DEFAULT_OBSERVER_NAME) + 
297                                ::boost::lexical_cast< ::std::string >(observerID) ));
298                               
299                // OK
300                return OK;
301        }
302               
303        //------------------------------------------------------------------------
304        Result Clock::addObserver(const ::std::string& obsName,SharedPtr<ITimeObserver> timeObserver)
305        {
306       
307                // check whenever such an observer already exists
308                if (observerIDList[obsName]){
309                        return CLOCK_OBSERVER_ALREADY_ADDED;
310                }
311               
312                // add observer
313                if (timeObserver != NULL && obsName.length() > 0){
314                        observers.push_back (timeObserver);
315                        observerIDList[obsName] = observers.size(); 
316                        observers[observers.size()-1]->_observerID = observers.size();
317                }
318               
319                return OK;
320                                       
321        }
322       
323        //------------------------------------------------------------------------
324        Result Clock::removeObserver(const ::std::string& obsName){
325       
326                if (observerIDList[obsName]){
327                        int32 id = observerIDList[obsName] - 1;
328                        observers.erase(observers.begin() + id);
329                }else{
330                        return CLOCK_OBSERVER_NOT_FOUND;
331                }
332               
333                return OK;
334        }
335       
336        //------------------------------------------------------------------------
337        void Clock::setFrameWindow(int32 frameCount, float32 defaultFrameTime){
338               
339                frameFilteringWindow = frameCount > 1 ? frameCount : 1;
340                frameDefaultTime = defaultFrameTime;
341                frameDurationHistory.clear ();
342                frameDurationHistory.push_back(frameDefaultTime);
343        }
344       
345        //------------------------------------------------------------------------
346        void Clock::setFixFrameRate(bool setFixRate, float32 fixFrameRate){
347                useFixRate = setFixRate;
348                this->fixFrameRate = fixFrameRate;
349        }
350               
351        //------------------------------------------------------------------------
352        void Clock::setMaxFrameRate(bool set, float32 maxFPS)
353        {
354                useMaxRate = set;
355                this->maxFrameRate = maxFPS;
356                invMaxFrameRate = 1.0 / (float64)(maxFPS);
357        }
358
359        //------------------------------------------------------------------------
360        float64 Clock::_getExactFrameDuration (){
361               
362               
363                float64 sourceTime = timeSource->getTime();
364                realFrameTime = sourceTime - sourceLastValue;
365                sourceLastValue = sourceTime;
366               
367                /*if (frameDuration > 0.200){
368                        frameDuration = frameDurationHistory.back();
369                }else if (frameDuration < 0){
370                        frameDuration = 0;
371                }*/
372
373                if (useFixRate || timeSource == NULL){
374                        return 1.0f / (fixFrameRate);
375                }
376
377                return realFrameTime;
378        }
379       
380        //------------------------------------------------------------------------
381        void Clock::_addToFrameHistory (float64 exactFrameDuration){
382                frameDurationHistory.push_back (exactFrameDuration);
383                if (frameDurationHistory.size () > (uint32) frameFilteringWindow)
384                        frameDurationHistory.pop_front ();
385        }
386       
387        //------------------------------------------------------------------------
388        float64 Clock::_getFilteredFrameDuration () const{
389               
390                if (useFixRate){
391                        return 1.0f/(fixFrameRate);
392                }
393               
394                float64 totalFrameTime = 0;
395       
396                ::std::deque<float64>::const_iterator it;
397                for (it=frameDurationHistory.begin();it != frameDurationHistory.end(); ++it){
398                        totalFrameTime += *it;
399                }
400               
401                return totalFrameTime/static_cast<float64>(frameDurationHistory.size());
402        }
403       
404}; // end namespace
405
406#undef DEFAULT_OBSERVER_NAME
Note: See TracBrowser for help on using the repository browser.