source: nrEngine/src/Clock.cpp @ 22

Revision 22, 9.4 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        Clock::Clock() : ITask(){
29               
30                setTaskName("SystemClock");
31                currentTime = 0;
32                frameTime = 0;
33                frameNumber = 0;
34               
35                sourceStartValue = 0;
36                sourceLastValue = 0;
37               
38                useFixRate = false;
39                fixFrameRate = 0;
40                useMaxRate = false;
41                maxFrameRate = 0;
42                lastCurrentTime = 0;
43
44                // add default frame time       
45                setFrameWindow (7);
46                frameTime = _getFilteredFrameDuration();
47               
48                timeSource.reset();
49
50                // setup some other values
51                nextSyncTime = 0;
52                syncInterval = 0;
53               
54        }
55               
56        //------------------------------------------------------------------------
57        Clock::~Clock(){
58                stopTask();
59        }
60       
61        //------------------------------------------------------------------------     
62        void Clock::setTimeSource(SharedPtr<TimeSource> timeSource)
63        {               
64                this->timeSource = timeSource;
65       
66                if (timeSource != NULL){
67                        timeSource->reset();
68                        sourceStartValue = timeSource->getTime();
69                        sourceLastValue = sourceStartValue;
70                }
71        }
72       
73        //------------------------------------------------------------------------     
74        void Clock::setSyncInterval(uint32 milliseconds)
75        {
76                this->syncInterval = milliseconds;
77        }
78       
79        //------------------------------------------------------------------------
80        bool Clock::isAnySourceBounded(){
81                return (timeSource != NULL);
82        }
83       
84        //------------------------------------------------------------------------
85        SharedPtr<Timer> Clock::createTimer(){
86       
87                // create timer as observer
88                SharedPtr<ITimeObserver> timer(
89                                        new Timer(*this));
90               
91                // add him to the list
92                int32 id = addObserver(timer);
93               
94                if (id == 0){
95                        NR_Log(Log::LOG_ENGINE, Log::LL_WARNING, "Clock::createTimer(): Can not add timer to the observer list");
96                }
97               
98                // set the id of the timer
99                timer->_observerID = id;
100               
101                // return created timer
102                return ::boost::dynamic_pointer_cast<Timer, ITimeObserver>(timer);
103               
104        }
105       
106        //------------------------------------------------------------------------
107        Result Clock::stopTask(){
108                timeSource.reset();
109               
110                for (uint32 i=0; i < observers.size(); i++){
111                        observers[i].reset();
112                }
113                observers.clear();
114               
115                return OK;
116        }
117       
118        //------------------------------------------------------------------------
119        Result Clock::updateTask(){
120
121                // check whenever a time source is bound
122                if (timeSource == NULL) return CLOCK_NO_TIME_SOURCE;
123
124                timeSource->notifyNextFrame();
125               
126                // calculate exact frame duration time
127                float64 exactFrameDuration = _getExactFrameDuration();
128                _addToFrameHistory(exactFrameDuration);
129               
130                // get filtered frame time
131                frameTime = _getFilteredFrameDuration();
132                frameNumber ++;
133
134                // check if we use frame bounder
135                do {
136                        currentTime = timeSource->getTime();
137
138                        // get through the list of connected observers and notify them
139                        ObserverList::iterator it;
140                        for (it = observers.begin(); it != observers.end(); ++it){
141                                (*it)->notifyTimeObserver();
142                        }
143
144                        // check if we need to sync the clock
145                        if (syncInterval > 0 && nextSyncTime < currentTime)
146                        {
147                                timeSource->sync();
148                                nextSyncTime = currentTime + static_cast<float64>(syncInterval) / 1000.0;
149                        }
150
151                } while (useMaxRate && (currentTime - lastCurrentTime) < invMaxFrameRate);
152
153                // set the last current time we used to the current time
154                lastCurrentTime = currentTime;
155
156                // OK
157                return OK;
158        }
159
160        //------------------------------------------------------------------------
161        float64 Clock::getTime() const{
162                return currentTime;
163        }
164       
165        //------------------------------------------------------------------------
166        float32 Clock::getFrameInterval() const{
167                return (float32)frameTime;
168        }
169       
170        //------------------------------------------------------------------------
171        float32 Clock::getRealFrameInterval() const
172        {
173                return (float32)realFrameTime;
174        }
175
176        //------------------------------------------------------------------------
177        float32 Clock::getRealFrameRate() const
178        {
179                return 1.0f / getRealFrameInterval();
180        }
181
182        //------------------------------------------------------------------------
183        int32 Clock::getFrameNumber() const{
184                return frameNumber;
185        }
186       
187        //------------------------------------------------------------------------
188        float32 Clock::getFrameRate() const{
189                return 1.0f / getFrameInterval();
190        }
191               
192        //------------------------------------------------------------------------
193        int32 Clock::addObserver(SharedPtr<ITimeObserver> timeObserver){
194               
195                int32 id = 0;
196               
197                if (timeObserver != NULL){
198                        observers.push_back (timeObserver);
199                        id = observers.size();
200                        observerIDList[::std::string(DEFAULT_OBSERVER_NAME) 
201                                                                                + ::boost::lexical_cast< ::std::string >(id)] = id;
202                        observers[observers.size()-1]->_observerID = id;
203                }
204               
205                return id;
206        }
207       
208        //------------------------------------------------------------------------
209        Result Clock::removeObserver(int32 observerID){
210               
211                int32 id = observerID - 1;
212                if (id <= 0 || id+1 >= static_cast<int32>(observers.size())
213                                || observerIDList.find(::std::string(DEFAULT_OBSERVER_NAME) + 
214                                                        ::boost::lexical_cast< ::std::string >(observerID)) == observerIDList.end()){
215                        return CLOCK_OBSERVER_NOT_FOUND;
216                }
217               
218                // remove it from the list
219                observers.erase(observers.begin() + id);
220               
221                // also clean the map enty for this id
222                observerIDList.erase(observerIDList.find( ::std::string(DEFAULT_OBSERVER_NAME) + 
223                                ::boost::lexical_cast< ::std::string >(observerID) ));
224                               
225                // OK
226                return OK;
227        }
228               
229        //------------------------------------------------------------------------
230        Result Clock::addObserver(const ::std::string& obsName,
231                                                                                                SharedPtr<ITimeObserver> timeObserver){
232                                                               
233       
234                // check whenever such an observer already exists
235                if (observerIDList[obsName]){
236                        return CLOCK_OBSERVER_ALREADY_ADDED;
237                }
238               
239                // add observer
240                if (timeObserver != NULL && obsName.length() > 0){
241                        observers.push_back (timeObserver);
242                        observerIDList[obsName] = observers.size(); 
243                        observers[observers.size()-1]->_observerID = observers.size();
244                }
245               
246                return OK;
247                                       
248        }
249       
250        //------------------------------------------------------------------------
251        Result Clock::removeObserver(const ::std::string& obsName){
252       
253                if (observerIDList[obsName]){
254                        int32 id = observerIDList[obsName] - 1;
255                        observers.erase(observers.begin() + id);
256                }else{
257                        return CLOCK_OBSERVER_NOT_FOUND;
258                }
259               
260                return OK;
261        }
262       
263        //------------------------------------------------------------------------
264        void Clock::setFrameWindow(int32 frameCount, float32 defaultFrameTime){
265               
266                frameFilteringWindow = frameCount > 1 ? frameCount : 1;
267                frameDefaultTime = defaultFrameTime;
268                frameDurationHistory.clear ();
269                frameDurationHistory.push_back(frameDefaultTime);
270        }
271       
272        //------------------------------------------------------------------------
273        void Clock::setFixFrameRate(bool setFixRate, float32 fixFrameRate){
274                useFixRate = setFixRate;
275                this->fixFrameRate = fixFrameRate;
276        }
277               
278        //------------------------------------------------------------------------
279        void Clock::setMaxFrameRate(bool set, float32 maxFPS)
280        {
281                useMaxRate = set;
282                this->maxFrameRate = maxFPS;
283                invMaxFrameRate = 1.0 / (float64)(maxFPS);
284        }
285
286        //------------------------------------------------------------------------
287        float64 Clock::_getExactFrameDuration (){
288               
289               
290                float64 sourceTime = timeSource->getTime();
291                realFrameTime = sourceTime - sourceLastValue;
292                sourceLastValue = sourceTime;
293               
294                /*if (frameDuration > 0.200){
295                        frameDuration = frameDurationHistory.back();
296                }else if (frameDuration < 0){
297                        frameDuration = 0;
298                }*/
299
300                if (useFixRate || timeSource == NULL){
301                        return 1.0f / (fixFrameRate);
302                }
303
304                return realFrameTime;
305        }
306       
307        //------------------------------------------------------------------------
308        void Clock::_addToFrameHistory (float64 exactFrameDuration){
309                frameDurationHistory.push_back (exactFrameDuration);
310                if (frameDurationHistory.size () > (uint32) frameFilteringWindow)
311                        frameDurationHistory.pop_front ();
312        }
313       
314        //------------------------------------------------------------------------
315        float64 Clock::_getFilteredFrameDuration () const{
316               
317                if (useFixRate){
318                        return 1.0f/(fixFrameRate);
319                }
320               
321                float64 totalFrameTime = 0;
322       
323                ::std::deque<float64>::const_iterator it;
324                for (it=frameDurationHistory.begin();it != frameDurationHistory.end(); ++it){
325                        totalFrameTime += *it;
326                }
327               
328                return totalFrameTime/static_cast<float64>(frameDurationHistory.size());
329        }
330       
331}; // end namespace
332
333#undef DEFAULT_OBSERVER_NAME
Note: See TracBrowser for help on using the repository browser.