source: nrEngine/src/Clock.cpp @ 25

Revision 25, 11.7 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                sourceLastRealValue = 0;
71               
72                useFixRate = false;
73                fixFrameRate = 0;
74                useMaxRate = false;
75                maxFrameRate = 0;
76                lastCurrentTime = 0;
77
78                // add default frame time       
79                setFrameWindow (7);
80                frameTime = _getFilteredFrameDuration();
81               
82                timeSource.reset();
83                realTimeSource.reset(new TimeSource());
84               
85                // setup some other values
86                nextSyncTime = 0;
87                syncInterval = 0;
88               
89        }
90               
91        //------------------------------------------------------------------------
92        Clock::~Clock(){
93                stopTask();
94        }
95       
96        //------------------------------------------------------------------------     
97        void Clock::reset(float64 resetToTime, bool resetAllObservers)
98        {
99                // check if we have to reset observers
100                if (resetAllObservers)
101                {
102                        ObserverList::iterator it = observers.begin();
103                        for (; it != observers.end(); it++)
104                                (*it)->resetObserver(resetToTime);
105                }
106               
107                // reset the clock
108                lastCurrentTime = resetToTime;
109                currentTime = resetToTime;
110                frameTime = frameDefaultTime;
111                frameNumber = 0;
112                realFrameTime = frameDefaultTime;
113                nextSyncTime = 0;
114               
115                // reset time source
116                setTimeSource(timeSource);
117               
118                // reset the frame history
119                setFrameWindow(frameFilteringWindow, frameDefaultTime);
120               
121                NR_Log(Log::LOG_ENGINE, "Clock: Reset clock to %f", resetToTime);               
122        }
123
124        //------------------------------------------------------------------------     
125        void Clock::setTimeSource(SharedPtr<TimeSource> timeSource)
126        {               
127                this->timeSource = timeSource;
128       
129                if (timeSource != NULL){
130                        timeSource->reset();
131                        sourceStartValue = timeSource->getTime();
132                        sourceLastValue = sourceStartValue;
133                }
134        }
135       
136        //------------------------------------------------------------------------     
137        void Clock::setSyncInterval(uint32 milliseconds)
138        {
139                this->syncInterval = milliseconds;
140        }
141       
142        //------------------------------------------------------------------------
143        bool Clock::isAnySourceBounded(){
144                return (timeSource != NULL);
145        }
146       
147        //------------------------------------------------------------------------
148        SharedPtr<Timer> Clock::createTimer(){
149       
150                // create timer as observer
151                SharedPtr<ITimeObserver> timer(new Timer(*this));
152               
153                // add him to the list
154                int32 id = addObserver(timer);
155               
156                if (id == 0){
157                        NR_Log(Log::LOG_ENGINE, Log::LL_WARNING, "Clock::createTimer(): Can not add timer to the observer list");
158                }
159               
160                // set the id of the timer
161                timer->_observerID = id;
162               
163                // return created timer
164                return ::boost::dynamic_pointer_cast<Timer, ITimeObserver>(timer);
165               
166        }
167       
168        //------------------------------------------------------------------------
169        Result Clock::onStartTask()
170        {
171                // register function by the manager
172                std::vector<nrEngine::ScriptParam> param;
173                param.push_back(this);
174                Engine::sScriptEngine()->add("resetClock", scriptResetClock, param);
175               
176                return OK;
177        }
178
179        //------------------------------------------------------------------------
180        Result Clock::stopTask()
181        {
182       
183                timeSource.reset();
184               
185                for (uint32 i=0; i < observers.size(); i++){
186                        observers[i].reset();
187                }
188                observers.clear();
189               
190                Engine::sScriptEngine()->del("resetClock");
191               
192                return OK;
193        }
194       
195        //------------------------------------------------------------------------
196        Result Clock::updateTask(){
197
198                // check whenever a time source is bound
199                if (timeSource == NULL) return CLOCK_NO_TIME_SOURCE;
200
201                timeSource->notifyNextFrame();
202               
203                // calculate exact frame duration time
204                float64 exactFrameDuration = _getExactFrameDuration();
205                _addToFrameHistory(exactFrameDuration);
206               
207                // get filtered frame time
208                frameTime = _getFilteredFrameDuration();
209                frameNumber ++;
210
211                // check if we use frame bounder
212                do {
213                        currentTime = timeSource->getTime();
214
215                        // get through the list of connected observers and notify them
216                        ObserverList::iterator it;
217                        for (it = observers.begin(); it != observers.end(); ++it){
218                                (*it)->notifyTimeObserver();
219                        }
220
221                        // check if we need to sync the clock
222                        if (syncInterval > 0 && nextSyncTime < currentTime)
223                        {
224                                timeSource->sync();
225                                nextSyncTime = currentTime + static_cast<float64>(syncInterval) / 1000.0;
226                        }
227
228                } while (useMaxRate && (currentTime - lastCurrentTime) < invMaxFrameRate);
229
230                // set the last current time we used to the current time
231                lastCurrentTime = currentTime;
232               
233                // OK
234                return OK;
235        }
236
237        //------------------------------------------------------------------------
238        float64 Clock::getTime() const{
239                return currentTime;
240        }
241       
242        //------------------------------------------------------------------------
243        float32 Clock::getFrameInterval() const{
244                return (float32)frameTime;
245        }
246       
247        //------------------------------------------------------------------------
248        float32 Clock::getRealFrameInterval() const
249        {
250                return (float32)realFrameTime;
251        }
252
253        //------------------------------------------------------------------------
254        float32 Clock::getRealFrameRate() const
255        {
256                return 1.0f / getRealFrameInterval();
257        }
258
259        //------------------------------------------------------------------------
260        int32 Clock::getFrameNumber() const{
261                return frameNumber;
262        }
263       
264        //------------------------------------------------------------------------
265        float32 Clock::getFrameRate() const{
266                return 1.0f / getFrameInterval();
267        }
268               
269        //------------------------------------------------------------------------
270        int32 Clock::addObserver(SharedPtr<ITimeObserver> timeObserver){
271               
272                int32 id = 0;
273               
274                if (timeObserver != NULL){
275                        observers.push_back (timeObserver);
276                        id = observers.size();
277                        observerIDList[::std::string(DEFAULT_OBSERVER_NAME) + ::boost::lexical_cast< ::std::string >(id)] = id;
278                        observers[observers.size()-1]->_observerID = id;
279                }
280               
281                return id;
282        }
283       
284        //------------------------------------------------------------------------
285        Result Clock::removeObserver(int32 observerID){
286               
287                int32 id = observerID - 1;
288                if (id <= 0 || id+1 >= static_cast<int32>(observers.size())
289                                || observerIDList.find(::std::string(DEFAULT_OBSERVER_NAME) + 
290                                ::boost::lexical_cast< ::std::string >(observerID)) == observerIDList.end()){
291                        return CLOCK_OBSERVER_NOT_FOUND;
292                }
293               
294                // remove it from the list
295                observers.erase(observers.begin() + id);
296               
297                // also clean the map enty for this id
298                observerIDList.erase(observerIDList.find( ::std::string(DEFAULT_OBSERVER_NAME) + 
299                                ::boost::lexical_cast< ::std::string >(observerID) ));
300                               
301                // OK
302                return OK;
303        }
304               
305        //------------------------------------------------------------------------
306        Result Clock::addObserver(const ::std::string& obsName,SharedPtr<ITimeObserver> timeObserver)
307        {
308       
309                // check whenever such an observer already exists
310                if (observerIDList[obsName]){
311                        return CLOCK_OBSERVER_ALREADY_ADDED;
312                }
313               
314                // add observer
315                if (timeObserver != NULL && obsName.length() > 0){
316                        observers.push_back (timeObserver);
317                        observerIDList[obsName] = observers.size(); 
318                        observers[observers.size()-1]->_observerID = observers.size();
319                }
320               
321                return OK;
322                                       
323        }
324       
325        //------------------------------------------------------------------------
326        Result Clock::removeObserver(const ::std::string& obsName){
327       
328                if (observerIDList[obsName]){
329                        int32 id = observerIDList[obsName] - 1;
330                        observers.erase(observers.begin() + id);
331                }else{
332                        return CLOCK_OBSERVER_NOT_FOUND;
333                }
334               
335                return OK;
336        }
337       
338        //------------------------------------------------------------------------
339        void Clock::setFrameWindow(int32 frameCount, float32 defaultFrameTime){
340               
341                frameFilteringWindow = frameCount > 1 ? frameCount : 1;
342                frameDefaultTime = defaultFrameTime;
343                frameDurationHistory.clear ();
344                frameDurationHistory.push_back(frameDefaultTime);
345        }
346       
347        //------------------------------------------------------------------------
348        void Clock::setFixFrameRate(bool setFixRate, float32 fixFrameRate){
349                useFixRate = setFixRate;
350                this->fixFrameRate = fixFrameRate;
351        }
352               
353        //------------------------------------------------------------------------
354        void Clock::setMaxFrameRate(bool set, float32 maxFPS)
355        {
356                useMaxRate = set;
357                this->maxFrameRate = maxFPS;
358                invMaxFrameRate = 1.0 / (float64)(maxFPS);
359        }
360
361        //------------------------------------------------------------------------
362        float64 Clock::_getExactFrameDuration (){
363               
364               
365                float64 sourceTime = timeSource->getTime();
366                float64 sourceRealTime = realTimeSource->getTime();
367               
368                realFrameTime = sourceRealTime - sourceLastRealValue;
369               
370                sourceLastValue = sourceTime;
371                sourceLastRealValue = sourceRealTime;
372               
373                /*if (frameDuration > 0.200){
374                        frameDuration = frameDurationHistory.back();
375                }else if (frameDuration < 0){
376                        frameDuration = 0;
377                }*/
378
379                if (useFixRate || timeSource == NULL){
380                        return 1.0f / (fixFrameRate);
381                }
382
383                return realFrameTime;
384        }
385       
386        //------------------------------------------------------------------------
387        void Clock::_addToFrameHistory (float64 exactFrameDuration){
388                frameDurationHistory.push_back (exactFrameDuration);
389                if (frameDurationHistory.size () > (uint32) frameFilteringWindow)
390                        frameDurationHistory.pop_front ();
391        }
392       
393        //------------------------------------------------------------------------
394        float64 Clock::_getFilteredFrameDuration () const{
395               
396                if (useFixRate){
397                        return 1.0f/(fixFrameRate);
398                }
399               
400                float64 totalFrameTime = 0;
401       
402                ::std::deque<float64>::const_iterator it;
403                for (it=frameDurationHistory.begin();it != frameDurationHistory.end(); ++it){
404                        totalFrameTime += *it;
405                }
406               
407                return totalFrameTime/static_cast<float64>(frameDurationHistory.size());
408        }
409       
410}; // end namespace
411
412#undef DEFAULT_OBSERVER_NAME
Note: See TracBrowser for help on using the repository browser.