// @ZBS { // *MODULE_NAME High Precision Full Scale Timer // *MASTER_FILE 1 // +DESCRIPTION { // A portable time system that keeps track of time with high precision // and UTC range as a double. Includes handy framework for real-time // systems and games. // } // *PORTABILITY win32 unix // *REQUIRED_FILES ztime.cpp ztime.h // *VERSION 2.0 // +HISTORY { // 2.0 Naming convention totally revised. // } // +TODO { // } // *SELF_TEST yes console // *PUBLISH yes // } // OPERATING SYSTEM specific includes: #ifdef WIN32 #include "time.h" // #include "windows.h" // #include "mmsystem.h" // The following lines duplicate the code needed from windows.h // In case of a compile problem, comment out the following and // uncomment the above includes. extern "C" { typedef union _LARGE_INTEGER { struct { unsigned long LowPart; long HighPart; }; struct { unsigned long LowPart; long HighPart; } u; __int64 QuadPart; } LARGE_INTEGER; __declspec(dllimport) int __stdcall QueryPerformanceCounter( LARGE_INTEGER *lpPerformanceCount ); __declspec(dllimport) int __stdcall QueryPerformanceFrequency( LARGE_INTEGER *lpFrequency ); __declspec(dllimport) void __stdcall Sleep( unsigned long dwMilliseconds ); __declspec(dllimport) int __stdcall timeGetTime(); } #else #include "sys/time.h" #include "unistd.h" #endif // STDLIB includes: #include "math.h" #include "malloc.h" #include "memory.h" // MODULE includes: #include "ztime.h" // ZBSLIB includes: #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif // Globals //------------------------------------------------------------------------ int zTimeFrameCount = 0; // Incremented each time zTimeTick() is called (once per frame) ZTime zTime = 0.0; // The time during the last call to zTimeSetFrameTime(), ZTime zTimeDT = 0.0; // Delta time on the last frame. float zTimeDTF = 0.f; // Delta time in float on the last frame. ZTime zTimeFPS = 0.0; // The last calculated frames per second. // Always based on local time as opposed to the master time int zTimeAvgWindow = 16; // The number of frames to averge when computing avgFPS ZTime zTimeAvgFPS = 0.0; // The running average of the last DTIME_FRAMES_TO_AVG // Always based on local time as opposed to the master time ZTime zTimeStart = 0.0; // Time that the zTime system was initialized in local time ZTime *zTimeAvgs = 0; // Array of the last tick times for FPS avergaing int zTimeAvgCount = 0; // Number of samples currently in the zTimeAvgs array. int zTimeLastAvgWindow = -1; // The size of the last allocation done for the averging window buffer int zTimeInited = 0; // Has the system been initialized ZTime zTimeLastTick = 0.0; // Last tick int zTimePaused = 0; // Flag indicating if time is paused. (Maybe increment past 1) ZTime zTimeWhenPaused = 0.0; // The time when it was put into pause mode. ZTime zTimePausedAccumulator = 0.0; // Each time zTimeResume() is called, this accumulator is incremented ZTime zTimeClockFrequency = 0.0; // The frequency of the clock. (Only used under Win32) // Public Interface Functions //------------------------------------------------------------------------ void zTimeInit() { zTimeInited = 1; #ifdef WIN32 __int64 frequency; QueryPerformanceFrequency( (LARGE_INTEGER *)&frequency ); zTimeClockFrequency = (double)frequency; #endif zTimeStart = zTimeNow(); zTimeLastTick = zTimeStart; } ZTime zTimeNow() { if( !zTimeInited ) { zTimeInit(); } #ifdef WIN32 __int64 counter; QueryPerformanceCounter( (LARGE_INTEGER *)&counter ); return (ZTime)counter / zTimeClockFrequency; // return (ZTime)timeGetTime() / (ZTime)1000; #else struct timeval tv; struct timezone tz; gettimeofday( &tv, &tz ); int _mils = tv.tv_usec/1000; secs = tv.tv_sec; return (ZTime)secs + ((ZTime)_mils/1000.0) #endif } void zTimeTick() { if( !zTimeInited ) { zTimeInit(); } if( zTimePaused ) { zTime = zTimeWhenPaused; zTimeDT = 0.0; zTimeDTF = 0.f; } else { zTime = zTimeNow() - zTimePausedAccumulator; zTimeDT = zTime - zTimeLastTick; zTimeDTF = (float)zTimeDT; } zTimeLastTick = zTime; // Set the current fps as long as we have one sample if( zTimeFrameCount > 0 ) { zTimeFPS = 0.0; if( zTimeDT > 0.0 ) { zTimeFPS = 1.0 / zTimeDT; } } // REALLOC the averaging window if necessary if( zTimeAvgWindow != zTimeLastAvgWindow ) { ZTime *newAvgs = (ZTime *)realloc( zTimeAvgs, sizeof(ZTime) * zTimeAvgWindow ); zTimeAvgCount = min( zTimeLastAvgWindow, zTimeAvgWindow ); if( zTimeLastAvgWindow > 0 ) { memcpy( newAvgs, zTimeAvgs, sizeof(ZTime) * zTimeAvgCount ); } zTimeAvgs = newAvgs; zTimeLastAvgWindow = zTimeAvgWindow; } zTimeAvgs[ zTimeFrameCount % zTimeAvgWindow ] = zTime; zTimeAvgCount++; // SET the average as long as we have enough samples. if( zTimeAvgCount > zTimeAvgWindow ) { ZTime elapsed = zTime - zTimeAvgs[ (zTimeFrameCount+1) % zTimeAvgWindow ]; zTimeAvgFPS = 0.0; if( elapsed > 0.0 ) { zTimeAvgFPS = (ZTime)zTimeAvgWindow / elapsed; } } zTimeFrameCount++; } int zTimeIsPaused() { return zTimePaused > 0; } void zTimePause() { if( zTimePaused == 0 ) { zTimeWhenPaused = zTimeNow(); } zTimePaused++; } void zTimeResume() { if( zTimePaused ) { zTimePaused--; if( !zTimePaused ) { zTimePausedAccumulator += zTimeNow() - zTimeWhenPaused; } } } void zTimeResetPaused() { zTimePausedAccumulator = 0.0; } void zTimeSleepSecs( int secs ) { #ifdef WIN32 Sleep( secs * 1000 ); #else sleep( secs ); #endif } void zTimeSleepMils( int mils ) { #ifdef WIN32 Sleep( mils ); #else assert( 0 ); // TODO: Use select() #endif } #ifdef SELF_TEST #include "stdio.h" void main() { ZTimer timer0( 2.0 ); ZTimer timer1( 0.5 ); ZTimer timer2; ZTimer timer3( 0.1 ); while( !timer0.isDone() ) { zTimeTick(); if( timer3.isDone() ) { printf( "now=%lf\n", zTime-zTimeStart ); timer3.start( 0.1 ); } zTimeSleepMils( 10 ); if( timer1.isDone() ) { printf( "Pausing time\n" ); zTimePause(); timer1.stop(); timer2.start( 0.5 ); } if( timer2.isDone() ) { printf( "Resuming time\n" ); zTimeResume(); timer2.stop(); } } } #endif