Clock.cpp

00001 /***************************************************************************
00002  *                                                                         *
00003  *   (c) Art Tevs, MPI Informatik Saarbruecken                             *
00004  *       mailto: <tevs@mpi-sb.mpg.de>                                      *
00005  *                                                                         *
00006  *   This program is free software; you can redistribute it and/or modify  *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or     *
00009  *   (at your option) any later version.                                   *
00010  *                                                                         *
00011  ***************************************************************************/
00012 
00013 //----------------------------------------------------------------------------------
00014 // Includes
00015 //----------------------------------------------------------------------------------
00016 #include "Clock.h"
00017 #include "Log.h"
00018 
00019 //----------------------------------------------------------------------------------
00020 // Defines
00021 //----------------------------------------------------------------------------------
00022 #define DEFAULT_OBSERVER_NAME "__no_name__"
00023 
00024 
00025 namespace nrEngine{
00026         
00027         //----------------------------------------------------------------------------------
00028         ScriptFunctionDec(scriptResetClock, Clock)
00029         {
00030                 // check parameter count
00031                 if (args.size() < 1)
00032                 {
00033                         return ScriptResult(std::string("resetClock([timeToReset = 0, [reset_all_timers = 1]]) - Not valid parameter count!"));
00034                 }
00035 
00036                 if (param.size() == 0)
00037                 {
00038                         return ScriptResult(std::string("resetClock() was not properly registered before. Clock was not passed!"));
00039                 }
00040                 
00041                 // get clock 
00042                 Clock* clock = nrEngine::ScriptEngine::parameter_cast<Clock* >(param[0]);
00043                 if (clock == NULL)
00044                 {
00045                         return ScriptResult(std::string("resetClock() was not properly registered before. Clock was not passed!"));             
00046                 }
00047                 
00048                 // get parameters
00049                 bool shouldResetTimers = true;
00050                 float64 timeToReset = 0;
00051                 if (args.size() > 1) timeToReset = boost::lexical_cast<float64>(args[1]);
00052                 if (args.size() > 2) shouldResetTimers = boost::lexical_cast<bool>(args[2]);
00053                 
00054                 // reset the clock 
00055                 clock->reset(timeToReset, shouldResetTimers);
00056 
00057                 return ScriptResult();
00058         }
00059 
00060         //------------------------------------------------------------------------
00061         Clock::Clock() : ITask(){
00062                 
00063                 setTaskName("SystemClock");
00064                 currentTime = 0;
00065                 frameTime = 0;
00066                 frameNumber = 0;
00067                 
00068                 sourceStartValue = 0;
00069                 sourceLastValue = 0;
00070                 sourceLastRealValue = 0;
00071                 
00072                 useFixRate = false;
00073                 fixFrameRate = 0;
00074                 useMaxRate = false;
00075                 maxFrameRate = 0;
00076                 lastCurrentTime = 0;
00077 
00078                 // add default frame time       
00079                 setFrameWindow (7);
00080                 frameTime = _getFilteredFrameDuration();
00081                 
00082                 timeSource.reset();
00083                 realTimeSource.reset(new TimeSource());
00084                 
00085                 // setup some other values
00086                 nextSyncTime = 0;
00087                 syncInterval = 0;
00088                 
00089         }
00090                 
00091         //------------------------------------------------------------------------
00092         Clock::~Clock(){
00093                 stopTask();
00094         }
00095         
00096         //------------------------------------------------------------------------      
00097         void Clock::reset(float64 resetToTime, bool resetAllObservers)
00098         {
00099                 // check if we have to reset observers
00100                 if (resetAllObservers)
00101                 {
00102                         NR_Log(Log::LOG_ENGINE, "Clock: Reset time observers");
00103                         ObserverList::iterator it = observers.begin();
00104                         for (; it != observers.end(); it++) (*it)->resetObserver(resetToTime);
00105                 }
00106                 
00107                 // reset the clock 
00108                 lastCurrentTime = resetToTime;
00109                 currentTime = resetToTime;
00110                 frameTime = frameDefaultTime;
00111                 //frameNumber = 0;
00112                 realFrameTime = frameDefaultTime;
00113                 nextSyncTime = lastCurrentTime + static_cast<float64>(syncInterval) / 1000.0;
00114                 
00115                 // reset time source
00116                 setTimeSource(timeSource);
00117                 if (timeSource != NULL) timeSource->reset(resetToTime);
00118                 
00119                 // reset the frame history
00120                 setFrameWindow(frameFilteringWindow, frameDefaultTime);
00121                 
00122                 NR_Log(Log::LOG_ENGINE, "Clock: Reset clock to %f", resetToTime);               
00123         }
00124 
00125         //------------------------------------------------------------------------      
00126         void Clock::setTimeSource(SharedPtr<TimeSource> timeSource)
00127         {
00128                 this->timeSource = timeSource;
00129         
00130                 if (timeSource != NULL){
00131                         sourceStartValue = timeSource->getTime();
00132                         sourceLastValue = sourceStartValue;
00133                 }
00134         }
00135         
00136         //------------------------------------------------------------------------      
00137         void Clock::setSyncInterval(uint32 milliseconds)
00138         {
00139                 this->syncInterval = milliseconds;
00140         }
00141         
00142         //------------------------------------------------------------------------
00143         bool Clock::isAnySourceBounded(){
00144                 return (timeSource != NULL);
00145         }
00146         
00147         //------------------------------------------------------------------------
00148         SharedPtr<Timer> Clock::createTimer(){
00149         
00150                 // create timer as observer
00151                 SharedPtr<ITimeObserver> timer(new Timer(*this));
00152                 
00153                 // add him to the list
00154                 int32 id = addObserver(timer);
00155                 
00156                 if (id == 0){
00157                         NR_Log(Log::LOG_ENGINE, Log::LL_WARNING, "Clock::createTimer(): Can not add timer to the observer list");
00158                 }
00159                 
00160                 // set the id of the timer
00161                 timer->_observerID = id;
00162                 NR_Log(Log::LOG_ENGINE, Log::LL_DEBUG, "Clock::createTimer(): New timer created (id=%d)", id);
00163                 
00164                 // return created timer
00165                 return ::boost::dynamic_pointer_cast<Timer, ITimeObserver>(timer);
00166                 
00167         }
00168         
00169         //------------------------------------------------------------------------
00170         Result Clock::onStartTask()
00171         {
00172                 // register function by the manager
00173                 std::vector<nrEngine::ScriptParam> param;
00174                 param.push_back(this);
00175                 Engine::sScriptEngine()->add("resetClock", scriptResetClock, param);
00176                 
00177                 return OK;
00178         }
00179 
00180         //------------------------------------------------------------------------
00181         Result Clock::stopTask()
00182         {
00183         
00184                 timeSource.reset();
00185                 
00186                 for (uint32 i=0; i < observers.size(); i++){
00187                         observers[i].reset();
00188                 }
00189                 observers.clear();
00190                 
00191                 Engine::sScriptEngine()->del("resetClock");
00192                 
00193                 return OK;
00194         }
00195         
00196         //------------------------------------------------------------------------
00197         Result Clock::updateTask(){
00198 
00199                 // check whenever a time source is bound
00200                 if (timeSource == NULL) return CLOCK_NO_TIME_SOURCE;
00201 
00202                 timeSource->notifyNextFrame();
00203                 
00204                 // calculate exact frame duration time
00205                 float64 exactFrameDuration = _getExactFrameDuration();
00206                 _addToFrameHistory(exactFrameDuration);
00207                 
00208                 // get filtered frame time
00209                 frameTime = _getFilteredFrameDuration();
00210                 frameNumber ++;
00211 
00212                 // check if we use frame bounder
00213                 do {
00214                         currentTime = timeSource->getTime();
00215 
00216                         // get through the list of connected observers and notify them
00217                         ObserverList::iterator it;
00218                         for (it = observers.begin(); it != observers.end(); ++it){
00219                                 (*it)->notifyTimeObserver();
00220                         }
00221 
00222                         // check if we need to sync the clock
00223                         if (syncInterval > 0 && nextSyncTime < currentTime)
00224                         {
00225                                 timeSource->sync();
00226                                 nextSyncTime = currentTime + static_cast<float64>(syncInterval) / 1000.0;
00227                         }
00228 
00229                 } while (useMaxRate && (currentTime - lastCurrentTime) < invMaxFrameRate);
00230 
00231                 // set the last current time we used to the current time
00232                 lastCurrentTime = currentTime;
00233                 
00234                 // OK
00235                 return OK;
00236         }
00237 
00238         //------------------------------------------------------------------------
00239         float64 Clock::getTime() const{
00240                 return currentTime;
00241         }
00242         
00243         //------------------------------------------------------------------------
00244         float32 Clock::getFrameInterval() const{
00245                 return (float32)frameTime;
00246         }
00247         
00248         //------------------------------------------------------------------------
00249         float32 Clock::getRealFrameInterval() const
00250         {
00251                 return (float32)realFrameTime;
00252         }
00253 
00254         //------------------------------------------------------------------------
00255         float32 Clock::getRealFrameRate() const
00256         {
00257                 return 1.0f / getRealFrameInterval();
00258         }
00259 
00260         //------------------------------------------------------------------------
00261         int32 Clock::getFrameNumber() const{
00262                 return frameNumber;
00263         }
00264         
00265         //------------------------------------------------------------------------
00266         float32 Clock::getFrameRate() const{
00267                 return 1.0f / getFrameInterval();
00268         }
00269                 
00270         //------------------------------------------------------------------------
00271         int32 Clock::addObserver(SharedPtr<ITimeObserver> timeObserver){
00272                 
00273                 int32 id = 0;
00274                 
00275                 if (timeObserver != NULL){
00276                         observers.push_back (timeObserver);
00277                         id = observers.size();
00278                         observerIDList[std::string(DEFAULT_OBSERVER_NAME) + ::boost::lexical_cast< std::string >(id)] = id;
00279                         observers[observers.size()-1]->_observerID = id;
00280                 }
00281                 
00282                 return id;
00283         }
00284         
00285         //------------------------------------------------------------------------
00286         Result Clock::removeObserver(int32 observerID){
00287                 
00288                 int32 id = observerID - 1;
00289                 if (id <= 0 || id+1 >= static_cast<int32>(observers.size())
00290                                 || observerIDList.find(std::string(DEFAULT_OBSERVER_NAME) + 
00291                                 ::boost::lexical_cast< std::string >(observerID)) == observerIDList.end()){
00292                         return CLOCK_OBSERVER_NOT_FOUND;
00293                 }
00294                 
00295                 // remove it from the list
00296                 observers.erase(observers.begin() + id);
00297                 
00298                 // also clean the map enty for this id
00299                 observerIDList.erase(observerIDList.find( std::string(DEFAULT_OBSERVER_NAME) + 
00300                                 ::boost::lexical_cast< std::string >(observerID) ));
00301                                 
00302                 // OK
00303                 return OK;
00304         }
00305                 
00306         //------------------------------------------------------------------------
00307         Result Clock::addObserver(const std::string& obsName,SharedPtr<ITimeObserver> timeObserver)
00308         {
00309         
00310                 // check whenever such an observer already exists
00311                 if (observerIDList[obsName]){
00312                         return CLOCK_OBSERVER_ALREADY_ADDED;
00313                 }
00314                 
00315                 // add observer 
00316                 if (timeObserver != NULL && obsName.length() > 0){
00317                         observers.push_back (timeObserver);
00318                         observerIDList[obsName] = observers.size(); 
00319                         observers[observers.size()-1]->_observerID = observers.size();
00320                 }
00321                 
00322                 return OK;
00323                                         
00324         }
00325         
00326         //------------------------------------------------------------------------
00327         Result Clock::removeObserver(const std::string& obsName){
00328         
00329                 if (observerIDList[obsName]){
00330                         int32 id = observerIDList[obsName] - 1;
00331                         observers.erase(observers.begin() + id);
00332                 }else{
00333                         return CLOCK_OBSERVER_NOT_FOUND;
00334                 }
00335                 
00336                 return OK;
00337         }
00338         
00339         //------------------------------------------------------------------------
00340         void Clock::setFrameWindow(int32 frameCount, float32 defaultFrameTime){
00341                 
00342                 frameFilteringWindow = frameCount > 1 ? frameCount : 1;
00343                 frameDefaultTime = defaultFrameTime;
00344                 frameDurationHistory.clear ();
00345                 frameDurationHistory.push_back(frameDefaultTime);
00346         }
00347         
00348         //------------------------------------------------------------------------
00349         void Clock::setFixFrameRate(bool setFixRate, float32 fixFrameRate){
00350                 useFixRate = setFixRate;
00351                 this->fixFrameRate = fixFrameRate;
00352         }
00353                 
00354         //------------------------------------------------------------------------
00355         void Clock::setMaxFrameRate(bool set, float32 maxFPS)
00356         {
00357                 useMaxRate = set;
00358                 this->maxFrameRate = maxFPS;
00359                 invMaxFrameRate = 1.0 / (float64)(maxFPS);
00360         }
00361 
00362         //------------------------------------------------------------------------
00363         float64 Clock::_getExactFrameDuration (){
00364                 
00365                 
00366                 float64 sourceTime = timeSource->getTime();
00367                 float64 sourceRealTime = realTimeSource->getTime();
00368                 
00369                 realFrameTime = sourceRealTime - sourceLastRealValue;
00370                 
00371                 sourceLastValue = sourceTime;
00372                 sourceLastRealValue = sourceRealTime;
00373                 
00374                 /*if (frameDuration > 0.200){
00375                         frameDuration = frameDurationHistory.back();
00376                 }else if (frameDuration < 0){
00377                         frameDuration = 0;
00378                 }*/
00379 
00380                 if (useFixRate || timeSource == NULL){
00381                         return 1.0f / (fixFrameRate);
00382                 }
00383 
00384                 return realFrameTime;
00385         }
00386         
00387         //------------------------------------------------------------------------
00388         void Clock::_addToFrameHistory (float64 exactFrameDuration){
00389                 frameDurationHistory.push_back (exactFrameDuration);
00390                 if (frameDurationHistory.size () > (uint32) frameFilteringWindow)
00391                         frameDurationHistory.pop_front ();
00392         }
00393         
00394         //------------------------------------------------------------------------
00395         float64 Clock::_getFilteredFrameDuration () const{
00396                 
00397                 if (useFixRate){
00398                         return 1.0f/(fixFrameRate);
00399                 }
00400                 
00401                 float64 totalFrameTime = 0;
00402         
00403                 std::deque<float64>::const_iterator it;
00404                 for (it=frameDurationHistory.begin();it != frameDurationHistory.end(); ++it){
00405                         totalFrameTime += *it;
00406                 }
00407                 
00408                 return totalFrameTime/static_cast<float64>(frameDurationHistory.size());
00409         }
00410         
00411 }; // end namespace
00412 
00413 #undef DEFAULT_OBSERVER_NAME

Generated on Wed Sep 12 23:19:42 2007 for nrEngine by  doxygen 1.5.1