diff --git a/freeglut/freeglut/src/fg_init.c b/freeglut/freeglut/src/fg_init.c index 1538388..752439e 100644 --- a/freeglut/freeglut/src/fg_init.c +++ b/freeglut/freeglut/src/fg_init.c @@ -341,9 +341,6 @@ void FGAPIENTRY glutInit( int* pargc, char** argv ) fgCreateStructure( ); - /* Get start time */ - fgState.Time = fgSystemTime(); - fghParseCommandLineArguments ( pargc, argv, &displayName, &geometry ); /* diff --git a/freeglut/freeglut/src/fg_main.c b/freeglut/freeglut/src/fg_main.c index 0a096f4..885ed45 100644 --- a/freeglut/freeglut/src/fg_main.c +++ b/freeglut/freeglut/src/fg_main.c @@ -224,12 +224,8 @@ static void fghCheckTimers( void ) /* Platform-dependent time in milliseconds, as an unsigned 64-bit integer. * This doesn't overflow in any reasonable time, so no need to worry about * that. The GLUT API return value will however overflow after 49.7 days, - * and on Windows we (currently) do not have access to a 64-bit timestamp, - * which means internal time will still get in trouble when running the + * which means you will still get in trouble when running the * application for more than 49.7 days. - * This value wraps every 49.7 days, but integer overflows cancel - * when subtracting an initial start time, unless the total time exceeds - * 32-bit, where the GLUT API return value is also overflowed. */ fg_time_t fgSystemTime(void) { diff --git a/freeglut/freeglut/src/fg_state.c b/freeglut/freeglut/src/fg_state.c index 5f8c08a..9ddfdd9 100644 --- a/freeglut/freeglut/src/fg_state.c +++ b/freeglut/freeglut/src/fg_state.c @@ -136,6 +136,12 @@ int FGAPIENTRY glutGet( GLenum eWhat ) case GLUT_INIT_STATE: return fgState.Initialised; + /* Although internally the time store is 64bits wide, the return value + * here still wraps every 49.7 days. Integer overflows cancel however + * when subtracting an initial start time, unless the total time exceeds + * 32-bit, so you can still work with this. + * XXX: a glutGet64 to return the time might be an idea... + */ case GLUT_ELAPSED_TIME: return (int) fgElapsedTime(); } diff --git a/freeglut/freeglut/src/mswin/fg_init_mswin.c b/freeglut/freeglut/src/mswin/fg_init_mswin.c index f80fe78..40a4c7e 100644 --- a/freeglut/freeglut/src/mswin/fg_init_mswin.c +++ b/freeglut/freeglut/src/mswin/fg_init_mswin.c @@ -33,6 +33,7 @@ extern LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); +extern void fgPlatformInitSystemTime(); /* @@ -117,6 +118,10 @@ void fgPlatformInitialize( const char* displayName ) } /* Set the timer granularity to 1 ms */ timeBeginPeriod ( 1 ); + /* Init setup to deal with timer wrap, can't query system time before this is done */ + fgPlatformInitSystemTime(); + /* Get start time */ + fgState.Time = fgSystemTime(); fgState.Initialised = GL_TRUE; diff --git a/freeglut/freeglut/src/mswin/fg_main_mswin.c b/freeglut/freeglut/src/mswin/fg_main_mswin.c index 4588ef6..3769cb4 100644 --- a/freeglut/freeglut/src/mswin/fg_main_mswin.c +++ b/freeglut/freeglut/src/mswin/fg_main_mswin.c @@ -135,22 +135,39 @@ void fgPlatformDisplayWindow ( SFG_Window *window ) } -fg_time_t fgPlatformSystemTime ( void ) +/* Get system time, taking special precautions against 32bit timer wrap. + We use timeGetTime and not GetTickCount because of its better stability, + and because we can increase its granularity (to 1 ms in + fgPlatformInitialize). For that reason we can't use GetTickCount64 which + wouldn't have the wrap issue. + Credit: this is based on code in glibc (https://mail.gnome.org/archives/commits-list/2011-November/msg04588.html) + */ +static fg_time_t lastTime32 = 0; +static fg_time_t timeEpoch = 0; +void fgPlatformInitSystemTime() { #if defined(_WIN32_WCE) - return GetTickCount(); + lastTime32 = GetTickCount(); #else - /* TODO: do this with QueryPerformanceCounter as timeGetTime has - * insufficient resolution (only about 5 ms on system under low load). - * See: - * http://msdn.microsoft.com/en-us/library/windows/desktop/dd757629(v=vs.85).aspx - * Or maybe QueryPerformanceCounter is not a good idea either, see - * http://old.nabble.com/Re%3A-glutTimerFunc-does-not-detect-if-system-time-moved-backward-p33479674.html - * for some other ideas (at bottom)... - */ - return timeGetTime(); + lastTime32 = timeGetTime(); #endif } +fg_time_t fgPlatformSystemTime ( void ) +{ + fg_time_t currTime32; +#if defined(_WIN32_WCE) + currTime32 = GetTickCount(); +#else + currTime32 = timeGetTime(); +#endif + /* Check if we just wrapped */ + if (currTime32 < lastTime32) + timeEpoch++; + + lastTime32 = currTime32; + + return currTime32 | timeEpoch << 32; +} void fgPlatformSleepForEvents( fg_time_t msec ) diff --git a/freeglut/freeglut/src/x11/fg_init_x11.c b/freeglut/freeglut/src/x11/fg_init_x11.c index 6cd6048..0df54f2 100644 --- a/freeglut/freeglut/src/x11/fg_init_x11.c +++ b/freeglut/freeglut/src/x11/fg_init_x11.c @@ -238,6 +238,9 @@ void fgPlatformInitialize( const char* displayName ) } } + /* Get start time */ + fgState.Time = fgSystemTime(); + fgState.Initialised = GL_TRUE;