INCLUDE(CheckIncludeFiles)
INCLUDE(CheckFunctionExists)
+INCLUDE(CheckTypeSize)
CHECK_INCLUDE_FILES(sys/types.h HAVE_SYS_TYPES_H)
CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H)
CHECK_INCLUDE_FILES(sys/time.h HAVE_SYS_TIME_H)
CHECK_INCLUDE_FILES(errno.h HAVE_ERRNO_H)
CHECK_INCLUDE_FILES(usbhid.h HAVE_USBHID_H)
CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY)
-CHECK_FUNCTION_EXISTS(vfprintf HAVE_VFPRINTF)
-CHECK_FUNCTION_EXISTS(_doprnt HAVE_DOPRNT)
+CHECK_FUNCTION_EXISTS(vfprintf HAVE_VFPRINTF)
+CHECK_FUNCTION_EXISTS(_doprnt HAVE_DOPRNT)
+# decide on suitable type for internal time keeping, 64-bit if possible
+CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H)
+CHECK_INCLUDE_FILES(inttypes.h HAVE_INTTYPES_H)
+CHECK_TYPE_SIZE("unsigned long long" ULONG_LONG BUILTIN_TYPES_ONLY)
+
# The generated config.h is placed in the project's build directory, just to
# ensure that all CMake-generated files are kept away from the main source tree.
#cmakedefine HAVE_GETTIMEOFDAY
#cmakedefine HAVE_VFPRINTF
#cmakedefine HAVE_DOPRNT
+#cmakedefine HAVE_STDINT_H
+#cmakedefine HAVE_INTTYPES_H
+#define HAVE_ULONG_LONG ${HAVE_ULONG_LONG}
/* Use EGL (implies OpenGL ES) */
/* TODO: EGL/GLES builds should be more generally defined, possibly by
generating this file dynamically */
-#include <EGL/egl.h>
+# include <EGL/egl.h>
/* TODO: we probably need 2 builds: -lGLESv1 and -lGLESv2 */
/* #include <GLES/gl.h> */
-#include <GLES2/gl2.h>
+# include <GLES2/gl2.h>
/* TODO: temporary work-around for e.g. glutWireCube */
-#define GLdouble GLfloat
+# define GLdouble GLfloat
#else
-#include <GL/gl.h>
-#include <GL/glu.h>
+# include <GL/gl.h>
+# include <GL/glu.h>
#endif
/*
#endif
/* General defines */
-
#define INVALID_MODIFIERS 0xffffffff
+/* FreeGLUT internal time type */
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+ typedef uint64_t fg_time_t;
+#elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+ typedef uint64_t fg_time_t;
+#elif defined(HAVE_ULONG_LONG)
+ typedef unsigned long long fg_time_t;
+#else
+ typedef unsigned long fg_time_t;
+#endif
+
/* Platform-specific includes */
GLuint SwapCount; /* Count of glutSwapBuffer calls */
GLuint SwapTime; /* Time of last SwapBuffers */
- unsigned long Time; /* Time that glutInit was called */
+ fg_time_t Time; /* Time that glutInit was called */
SFG_List Timers; /* The freeglut timer hooks */
SFG_List FreeTimers; /* The unused timer hooks */
SFG_Node Node;
int ID; /* The timer ID integer */
FGCBTimer Callback; /* The timer callback */
- long TriggerTime; /* The timer trigger time */
+ fg_time_t TriggerTime; /* The timer trigger time */
};
/*
int Cursor; /* The currently selected cursor */
long JoystickPollRate; /* The joystick polling rate */
- long JoystickLastPoll; /* When the last poll happened */
+ fg_time_t JoystickLastPoll; /* When the last poll happened */
int MouseX, MouseY; /* The most recent mouse position */
void fgDisplayMenu( void );
/* Elapsed time as per glutGet(GLUT_ELAPSED_TIME). */
-long fgElapsedTime( void );
+fg_time_t fgElapsedTime( void );
/* System time in milliseconds */
-long unsigned fgSystemTime(void);
+fg_time_t fgSystemTime(void);
/* List functions */
void fgListInit(SFG_List *list);
extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height );
extern void fgPlatformDisplayWindow ( SFG_Window *window );
-extern unsigned long fgPlatformSystemTime ( void );
-extern void fgPlatformSleepForEvents( long msec );
+extern fg_time_t fgPlatformSystemTime ( void );
+extern void fgPlatformSleepForEvents( fg_time_t msec );
extern void fgPlatformProcessSingleEvent ( void );
extern void fgPlatformMainLoopPreliminaryWork ( void );
static void fghcbCheckJoystickPolls( SFG_Window *window,
SFG_Enumerator *enumerator )
{
- long int checkTime = fgElapsedTime( );
+ fg_time_t checkTime = fgElapsedTime( );
if( window->State.JoystickLastPoll + window->State.JoystickPollRate <=
checkTime )
*/
static void fghCheckTimers( void )
{
- long checkTime = fgElapsedTime( );
+ fg_time_t checkTime = fgElapsedTime( );
while( fgState.Timers.First )
{
}
-/* Platform-dependent time in milliseconds, as an unsigned 32-bit integer.
+/* 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
+ * 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.
*/
-unsigned long fgSystemTime(void)
+fg_time_t fgSystemTime(void)
{
- return fgPlatformSystemTime ();
+ return fgPlatformSystemTime();
}
/*
* Elapsed Time
*/
-long fgElapsedTime( void )
+fg_time_t fgElapsedTime( void )
{
- return (long) (fgSystemTime() - fgState.Time);
+ return fgSystemTime() - fgState.Time;
}
/*
/*
* Returns the number of GLUT ticks (milliseconds) till the next timer event.
*/
-static long fghNextTimer( void )
+static fg_time_t fghNextTimer( void )
{
- long ret = INT_MAX;
+ fg_time_t currentTime = fgElapsedTime();
SFG_Timer *timer = fgState.Timers.First;
- if( timer )
- ret = timer->TriggerTime - fgElapsedTime();
- if( ret < 0 )
- ret = 0;
+ if( !timer )
+ return INT_MAX;
- return ret;
+ if( timer->TriggerTime < currentTime )
+ return 0;
+ else
+ return timer->TriggerTime - currentTime;
}
static void fghSleepForEvents( void )
{
- long msec;
+ fg_time_t msec;
if( fgState.IdleCallback || fghHavePendingRedisplays( ) )
return;
return fgState.Initialised;
case GLUT_ELAPSED_TIME:
- return fgElapsedTime();
+ return (int) fgElapsedTime();
}
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGet" );
}
-unsigned long fgPlatformSystemTime ( void )
+fg_time_t fgPlatformSystemTime ( void )
{
#if defined(_WIN32_WCE)
return 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();
#endif
}
-void fgPlatformSleepForEvents( long msec )
+void fgPlatformSleepForEvents( fg_time_t msec )
{
MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT );
}
}
-unsigned long fgPlatformSystemTime ( void )
+fg_time_t fgPlatformSystemTime ( void )
{
#ifdef CLOCK_MONOTONIC
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_nsec/1000000 + now.tv_sec*1000;
-#else
-#ifdef HAVE_GETTIMEOFDAY
+#elif defined(HAVE_GETTIMEOFDAY)
struct timeval now;
gettimeofday( &now, NULL );
return now.tv_usec/1000 + now.tv_sec*1000;
#endif
-#endif
}
/*
* happens.
*/
-void fgPlatformSleepForEvents( long msec )
+void fgPlatformSleepForEvents( fg_time_t msec )
{
/*
* Possibly due to aggressive use of XFlush() and friends,