src/tools/tSysTime.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 *************************************************************************
00004 
00005 ArmageTron -- Just another Tron Lightcycle Game in 3D.
00006 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
00007 
00008 **************************************************************************
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00023 
00024 ***************************************************************************
00025 
00026 */
00027 
00028 #include "aa_config.h"
00029 
00030 #include "tSysTime.h"
00031 #include "tRecorder.h"
00032 #include "tError.h"
00033 #include "tConsole.h"
00034 #include "tConfiguration.h"
00035 #include "tLocale.h"
00036 
00037 #if HAVE_UNISTD_H
00038 #include <unistd.h>
00039 #endif
00040 
00041 // Both implementations are stolen from Q1.
00042 
00044 struct tTime
00045 {
00046     int microseconds;   
00047     int seconds;        
00048 
00049     #define NORMALIZER 1000000
00050 
00051     tTime(): microseconds(0), seconds(0){}
00052 
00054     void Normalize()
00055     {
00056         int overflow = microseconds / NORMALIZER;
00057         microseconds -= overflow * NORMALIZER;
00058         seconds += overflow;
00059 
00060         while ( microseconds < 0 )
00061         {
00062             microseconds += NORMALIZER;
00063             seconds --;
00064         }
00065     }
00066 
00067     tTime operator + ( const tTime & other )
00068     {
00069         tTime ret;
00070         ret.microseconds = other.microseconds + microseconds;
00071         ret.seconds = other.seconds + seconds;
00072 
00073         ret.Normalize();
00074         return ret;
00075     }
00076 
00077     tTime operator - ( const tTime & other )
00078     {
00079         tTime ret;
00080         ret.microseconds = -other.microseconds + microseconds;
00081         ret.seconds = -other.seconds + seconds;
00082 
00083         ret.Normalize();
00084         return ret;
00085     }
00086 };
00087 
00088 
00089 #ifdef WIN32
00090 #include <windows.h>
00091 #include <sys/timeb.h>
00092 #ifndef DEDICATED
00093 #include "rSDL.h"
00094 #endif
00095 
00096 // flag indicating whether the HPC is reliable
00097 static bool st_hpcReliable = true;
00098 
00099 void GetTimeInner( tTime & time )
00100 {
00101     LARGE_INTEGER mtime,frq;
00102 
00103     // Check if high-resolution performance counter is supported
00104     if (!QueryPerformanceFrequency(&frq))
00105     {
00106         st_hpcReliable = false;
00107     }
00108 
00109     if (st_hpcReliable)
00110     {
00111         QueryPerformanceCounter(&mtime);
00112         time.seconds = mtime.QuadPart/frq.QuadPart;
00113         time.microseconds = ( ( mtime.QuadPart - time.seconds * frq.QuadPart ) * 1000000 ) / frq.QuadPart;
00114     }
00115     else
00116     {
00117         // Nope, not supported, do it the old way.
00118         struct _timeb tstruct;
00119         _ftime( &tstruct );
00120         time.microseconds = tstruct.millitm*1000;
00121         time.seconds = tstruct.time;
00122     }
00123 
00124     time.Normalize();
00125 }
00126 
00127 void GetTime( tTime & relative )
00128 {
00129     tTime time;
00130     GetTimeInner( time );
00131     static tTime start = time;
00132     relative = time - start;
00133 
00134     // detect timer trouble
00135     if ( st_hpcReliable )
00136     {
00137         static struct tTime lastTime = relative;
00138 
00139         // test transition
00140         //if ( relative.seconds > 10 )
00141         //    lastTime.seconds = lastTime.seconds+1;
00142 
00143         if ( (time - lastTime).seconds < 0 )
00144         {
00145             st_hpcReliable = false;
00146 
00147             GetTimeInner( time );
00148             start = start + time - lastTime;
00149             relative = time - start;
00150         }
00151         lastTime = time;
00152     }
00153 }
00154 
00156 bool tTimerIsAccurate()
00157 {
00158     return st_hpcReliable;
00159 }
00160 
00161 /*
00162 void GetTime( tTime & time )
00163 {
00164     struct _timeb tstruct;
00165     _ftime( &tstruct );
00166 
00167     time.microseconds = tstruct.millitm*1000;
00168     time.seconds = tstruct.time;
00169 
00170     time.Normalize();
00171 }
00172 */
00173 
00174 // static double        blocktime;
00175 
00176 static unsigned int sleep_rest=0;
00177 void usleep(int x)
00178 {
00179     sleep_rest+=x;
00180     unsigned int r=sleep_rest/1000;
00181 #ifndef DEDICATED
00182     SDL_Delay(r);
00183 #else
00184 
00185 #ifdef DEBUG
00186     double tb = tSysTimeFloat();
00187 #endif
00188 
00189     SleepEx(r,false);
00190 
00191 #ifdef DEBUG
00192     double ta = tSysTimeFloat();
00193     if ((tb-ta) > r*.01)
00194     {
00195         int x;
00196         x = 1;
00197     }
00198 #endif
00199 
00200 #endif
00201     sleep_rest-=r*1000;
00202 }
00203 
00204 #else
00205 
00206 #include <sys/time.h>
00207 
00208 void GetTime( tTime & time )
00209 {
00210     struct timeval tp;
00211     struct timezone tzp;
00212 
00213     gettimeofday(&tp, &tzp);
00214 
00215     time.microseconds = tp.tv_usec;
00216     time.seconds = tp.tv_sec;
00217 
00218     time.Normalize();
00219 }
00220 
00222 bool tTimerIsAccurate()
00223 {
00224     return true; // always on unix
00225 }
00226 
00227 #endif
00228 
00229 static char const * recordingSection = "T";
00230 
00231 template< class Archiver > class TimeArchiver
00232 {
00233 public:
00234     static bool Archive( tTime & time )
00235     {
00236         // start archive block if archiving is active
00237         Archiver archive;
00238         if ( archive.Initialize( recordingSection ) )
00239         {
00240             archive.Archive( time.seconds ).Archive( time.microseconds );
00241             return true;
00242         }
00243 
00244         return false;
00245     }
00246 };
00247 
00248 static struct tTime timeStart;        // the time at the start of the program
00249 static struct tTime timeRelative;     // the time since the system start ( eventually from a playback )
00250 
00251 void tAdvanceFrameSys( tTime & start, tTime & relative )
00252 {
00253     struct tTime time;
00254 
00255     // get time from OS
00256     GetTime( time );
00257 
00258     // test hickupery
00259     // time.seconds -= time.seconds/10;
00260 
00261     // record starting point
00262     if ( start.microseconds == 0 && start.seconds == 0 )
00263     {
00264         start = time;
00265     }
00266 
00267     // detect and counter timer hickups
00268     tTime newRelative = time - start;
00269     tTime timeStep = newRelative - relative;
00270     if ( !tRecorder::IsPlayingBack() && ( timeStep.seconds < 0 || timeStep.seconds > 10 ) )
00271     {
00272         static bool warn = true;
00273         if ( warn )
00274         {
00275             warn = false;
00276             con << tOutput( "$timer_hickup", float( timeStep.seconds + timeStep.microseconds * 1E-6  ) );
00277         }
00278 
00279         start = start + timeStep;
00280     }
00281     else
00282     {
00283         relative = newRelative;
00284     }
00285 
00286 
00287     if ( relative.seconds > 20 )
00288     {
00289         int x;
00290         x = 0;
00291     }
00292 }
00293 
00294 static bool s_delayedInPlayback = false;
00295 void tDelay( int usecdelay )
00296 {
00297     // delay a bit if we're not playing back
00298     if ( ! tRecorder::IsPlayingBack() )
00299         usleep( usecdelay );
00300     else
00301         s_delayedInPlayback = true;
00302 }
00303 
00304 void tDelayForce( int usecdelay )
00305 {
00306     // delay a bit
00307     if ( !s_delayedInPlayback )
00308         usleep( usecdelay );
00309     else
00310     {
00311         // when recording, the machine was idling around. No need to play that back.
00312         // Only pretend to delay.
00313         tTime timeDelay;
00314         timeDelay.microseconds = usecdelay;
00315         timeStart = timeStart - timeDelay;
00316     }
00317 
00318     s_delayedInPlayback = false;
00319 }
00320 
00321 void tAdvanceFrame( int usecdelay )
00322 {
00323     // delay a bit if we're not playing back
00324     if ( usecdelay > 0 )
00325         tDelay( usecdelay );
00326 
00327     static tTime timeNewRelative;
00328     tAdvanceFrameSys( timeStart, timeNewRelative );
00329 
00330     // try to fetch time from playback
00331     // tTime timeAdvance;
00332     if ( TimeArchiver< tPlaybackBlock >::Archive( timeRelative ) )
00333     {
00334         // timeRelative = timeRelative + timeAdvance;
00335 
00336         // correct start time so transition to normal time after the recording ended is smooth
00337         timeStart = timeStart + timeNewRelative - timeRelative;
00338     }
00339     else
00340     {
00341         // must never be called when a recording is running
00342         tASSERT( !tRecorder::IsPlayingBack() );
00343 
00344 #ifdef FIXED_FRAMERATE
00345         tTime fixed, catchup, timeFixedRelative;
00346     fixed.seconds = 0;
00347     fixed.microseconds = (int)(1000000. / FIXED_FRAMERATE);
00348         timeFixedRelative = timeRelative + fixed;
00349 
00350     catchup = timeFixedRelative/*game-time*/ - timeNewRelative/*real-time*/;
00351     if (catchup.seconds >= 0) {
00352 #ifdef DEBUG
00353             printf("catching up %d.%d seconds\n", catchup.seconds, catchup.microseconds);
00354 #endif
00355             for (int i = catchup.seconds; i; --i)
00356                 tDelay(1000000);
00357             tDelay(catchup.microseconds);
00358             timeNewRelative = timeFixedRelative;
00359         } else {
00360             printf("WARNING: Real time ahead of game time!\nreal: %d.%06d\ngame: %d.%06d\ncatchup: %d.%06d\n", timeNewRelative.seconds, timeNewRelative.microseconds, timeFixedRelative.seconds, timeFixedRelative.microseconds, 1 - catchup.seconds, 1000000 - catchup.microseconds);
00361 #ifdef FIXED_FRAMERATE_PRIORITY
00362             timeNewRelative = timeFixedRelative;
00363 #endif
00364         }
00365 #endif
00366 
00367         // timeAdvance = timeRealRelative - timeRelative;
00368         timeRelative = timeNewRelative;
00369     }
00370 
00371     // try to archive it
00372     TimeArchiver< tRecordingBlock >::Archive( timeRelative );
00373 #ifdef DEBUG
00374     {
00375         if ( timeRelative.microseconds == 337949 && timeRelative.seconds == 25 )
00376         {
00377             st_Breakpoint();
00378         }
00379     }
00380 #endif
00381 }
00382 
00383 static float st_timeFactor = 1.0;
00384 static tSettingItem< float > st_timeFactorConf( "TIME_FACTOR", st_timeFactor );
00385 
00386 double tSysTimeFloat ()
00387 {
00388 #ifdef DEBUG
00389     // if ( ! tRecorder::IsPlayingBack() )
00390     // {
00391     // static tTime time;
00392     // tAdvanceFrameSys( timeStart, time );
00393     // tTime timeStep = time - timeRelative;
00394     //        if ( timeStep.seconds > 5 )
00395     //        {
00396     //            std::cout << "tAdvanceFrame not called often enough!\n";
00397     //            st_Breakpoint();
00398     //            tAdvanceFrameSys( timeRealRelative );
00399     //        }
00400     // }
00401 #endif
00402 
00403     return ( timeRelative.seconds + timeRelative.microseconds*1E-6 ) * st_timeFactor;
00404 }
00405 
00406 static struct tTime timeRealStart;    // the real time at the start of the program
00407 static struct tTime timeRealRelative; // the time since the system start
00408 
00409 double tRealSysTimeFloat ()
00410 {
00411     // get real time from real OS
00412     tAdvanceFrameSys( timeRealStart, timeRealRelative );
00413     return ( timeRealRelative.seconds + timeRealRelative.microseconds*1E-6 ) * st_timeFactor;
00414 }

Generated on Sat Mar 15 22:56:02 2008 for Armagetron Advanced by  doxygen 1.5.4