Finished implementing all user-data callbacks (GCC-only for now).
authorRcmaniac25 <rcmaniac25@hotmail.com>
Fri, 30 Jun 2017 23:21:06 +0000 (23:21 +0000)
committerDiederick Niehorster <dcnieho@gmail.com>
Fri, 30 Jun 2017 23:21:06 +0000 (23:21 +0000)
Updated glutCreateMenu, glutIdleFunc, and glutTimerFunc so they handle NULL callback cases.
Removed glutMenuStateFuncUcall (as glutMenuStateFunc is a depreciated function).

git-svn-id: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@1809 7f0cb862-5218-0410-a997-914c9d46530a

include/GL/freeglut_ucall.h
src/fg_callbacks.c
src/fg_ext.c
src/fg_init.c
src/fg_internal.h
src/fg_main.c
src/fg_menu.c
src/fg_structure.c

index 9cbe82a..bbbd32d 100644 (file)
@@ -45,7 +45,6 @@ FGAPI void FGAPIENTRY glutEntryFuncUcall( void (* callback)( int, void* ), void*
 FGAPI void FGAPIENTRY glutKeyboardUpFuncUcall( void (* callback)( unsigned char, int, int, void* ), void* user_data );
 FGAPI void FGAPIENTRY glutSpecialUpFuncUcall( void (* callback)( int, int, int, void* ), void* user_data );
 FGAPI void FGAPIENTRY glutJoystickFuncUcall( void (* callback)( unsigned int, int, int, int, void* ), int pollInterval, void* user_data );
-FGAPI void FGAPIENTRY glutMenuStateFuncUcall( void (* callback)( int, void* ), void* user_data );
 FGAPI void FGAPIENTRY glutMenuStatusFuncUcall( void (* callback)( int, int, int, void* ), void* user_data );
 FGAPI void FGAPIENTRY glutOverlayDisplayFuncUcall( void (* callback)( void* ), void* user_data );
 FGAPI void FGAPIENTRY glutWindowStatusFuncUcall( void (* callback)( int, void* ), void* user_data );
@@ -76,12 +75,12 @@ FGAPI void FGAPIENTRY glutMultiPassiveFuncUcall( void (* callback)( int, int, in
  * Initialization functions, see fg_init.c
  */
 #include <stdarg.h>
-FGAPI void FGAPIENTRY glutInitErrorFuncUcall( void (* callback)( const char *fmt, va_list ap, void* ), void* user_data );
-FGAPI void FGAPIENTRY glutInitWarningFuncUcall( void (* callback)( const char *fmt, va_list ap, void* ), void* user_data );
+FGAPI void FGAPIENTRY glutInitErrorFuncUcall( void (* callback)( const char *fmt, va_list ap, void* user_data ), void* user_data );
+FGAPI void FGAPIENTRY glutInitWarningFuncUcall( void (* callback)( const char *fmt, va_list ap, void* user_data ), void* user_data );
 
 /* Mobile platforms lifecycle */
-FGAPI void FGAPIENTRY glutInitContextFuncUcall(void (* callback)(void*), void* user_data);
-FGAPI void FGAPIENTRY glutAppStatusFuncUcall(void (* callback)(int, void*), void* user_data);
+FGAPI void FGAPIENTRY glutInitContextFuncUcall( void (* callback)( void* ), void* user_data );
+FGAPI void FGAPIENTRY glutAppStatusFuncUcall( void (* callback)( int, void* ), void* user_data );
 
 #ifdef __cplusplus
     }
index b09f421..5f94b65 100644 (file)
@@ -42,7 +42,7 @@ void FGAPIENTRY glutIdleFuncUcall( FGCBIdleUC callback, FGCBUserData userData )
     fgState.IdleCallbackData = userData;
 }
 
-void glutIdleFuncCallback( void* userData )
+static void glutIdleFuncCallback( FGCBUserData userData )
 {
     FGCBIdle callback = (FGCBIdle)userData;
     callback();
@@ -51,7 +51,10 @@ void glutIdleFuncCallback( void* userData )
 void FGAPIENTRY glutIdleFunc( FGCBIdle callback )
 {
     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" );
-    glutIdleFuncUcall( glutIdleFuncCallback, (FGCBUserData)callback );
+    if( callback )
+        glutIdleFuncUcall( glutIdleFuncCallback, (FGCBUserData)callback );
+    else
+        glutIdleFuncUcall( NULL, NULL );
 }
 
 /* Creates a timer and sets its callback */
@@ -87,7 +90,7 @@ void FGAPIENTRY glutTimerFuncUcall( unsigned int timeOut, FGCBTimerUC callback,
     fgListInsert( &fgState.Timers, &node->Node, &timer->Node );
 }
 
-void glutTimerFuncCallback( int ID, FGCBUserData userData )
+static void glutTimerFuncCallback( int ID, FGCBUserData userData )
 {
     FGCBTimer callback = (FGCBTimer)userData;
     callback( ID );
@@ -96,7 +99,10 @@ void glutTimerFuncCallback( int ID, FGCBUserData userData )
 void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID )
 {
     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" );
-    glutTimerFuncUcall( timeOut, glutTimerFuncCallback, timerID, (FGCBUserData)callback );
+    if( callback )
+        glutTimerFuncUcall( timeOut, glutTimerFuncCallback, timerID, (FGCBUserData)callback );
+    else
+        glutTimerFuncUcall( timeOut, NULL, timerID, NULL );
 }
 
 /* Deprecated version of glutMenuStatusFunc callback setting method */
@@ -107,10 +113,26 @@ void FGAPIENTRY glutMenuStateFunc( FGCBMenuState callback )
 }
 
 /* Sets the global menu status callback for the current window */
+void FGAPIENTRY glutMenuStatusFuncUCall( FGCBMenuStatusUC callback, FGCBUserData userData )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFuncUCall" );
+    fgState.MenuStatusCallback = callback;
+    fgState.MenuStatusCallbackData = userData;
+}
+
+static void glutMenuStatusFuncCallback( int menuState, int mouseX, int mouseY, FGCBUserData userData )
+{
+    FGCBMenuStatus callback = (FGCBMenuStatus)userData;
+    callback( menuState, mouseX, mouseY );
+}
+
 void FGAPIENTRY glutMenuStatusFunc( FGCBMenuStatus callback )
 {
     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" );
-    fgState.MenuStatusCallback = callback;
+    if( callback )
+        glutMenuStatusFuncUCall( glutMenuStatusFuncCallback, (FGCBUserData)callback );
+    else
+        glutMenuStatusFuncUCall( NULL, NULL );
 }
 
 
@@ -118,11 +140,29 @@ void FGAPIENTRY glutMenuStatusFunc( FGCBMenuStatus callback )
  * Menu specific callbacks.
  */
 /* Callback upon menu destruction */
-void FGAPIENTRY glutMenuDestroyFunc( FGCBDestroy callback )
+void FGAPIENTRY glutMenuDestroyFuncUcall( FGCBDestroyUC callback, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFuncUcall" );
     if( fgStructure.CurrentMenu )
+    {
         fgStructure.CurrentMenu->Destroy = callback;
+        fgStructure.CurrentMenu->DestroyData = userData;
+    }
+}
+
+static void glutMenuDestroyFuncCallback( FGCBUserData userData )
+{
+    FGCBDestroy callback = (FGCBDestroy)userData;
+    callback();
+}
+
+void FGAPIENTRY glutMenuDestroyFunc( FGCBDestroy callback )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuDestroyFunc" );
+    if( callback )
+        glutMenuDestroyFuncUcall( glutMenuDestroyFuncCallback, (FGCBUserData)callback );
+    else
+        glutMenuDestroyFuncUcall( NULL, NULL );
 }
 
 
@@ -134,75 +174,191 @@ do                                                              \
 {                                                               \
     if( fgStructure.CurrentWindow == NULL )                     \
         return;                                                 \
-    SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \
+    SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback, userData ); \
 } while( 0 )
 /*
+ * Types need to be defined for callbacks. It's not ideal, but it works for this.
+ */
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                    \
+static void glut##a##FuncCallback( FGCBUserData userData )             \
+{                                                               \
+    FGCB##b callback = (FGCB##b)userData;                       \
+    callback();                                                 \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b)                    \
+static void glut##a##FuncCallback( int arg1val, FGCBUserData userData ) \
+{                                                               \
+    FGCB##b callback = (FGCB##b)userData;                       \
+    callback( arg1val );                                        \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                    \
+static void glut##a##FuncCallback( int arg1val, int arg2val, FGCBUserData userData ) \
+{                                                               \
+    FGCB##b callback = (FGCB##b)userData;                       \
+    callback( arg1val, arg2val );                               \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,arg1,arg2,arg3) \
+static void glut##a##FuncCallback( arg1 arg1val, arg2 arg2val, arg3 arg3val, FGCBUserData userData ) \
+{                                                               \
+    FGCB##b callback = (FGCB##b)userData;                       \
+    callback( arg1val, arg2val, arg3val );                      \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,b,int,int,int)
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,b)                    \
+static void glut##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, FGCBUserData userData ) \
+{                                                               \
+    FGCB##b callback = (FGCB##b)userData;                       \
+    callback( arg1val, arg2val, arg3val, arg4val );             \
+}
+#define IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,b)                    \
+static void glut##a##FuncCallback( int arg1val, int arg2val, int arg3val, int arg4val, int arg5val, FGCBUserData userData ) \
+{                                                               \
+    FGCB##b callback = (FGCB##b)userData;                       \
+    callback( arg1val, arg2val, arg3val, arg4val, arg5val );    \
+}
+/*
  * And almost every time the callback setter function can be implemented like this:
  */
-#define IMPLEMENT_CALLBACK_FUNC_2NAME(a,b)                      \
-void FGAPIENTRY glut##a##Func( FGCB##b callback )               \
+#define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b)                 \
+void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \
 {                                                               \
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" );    \
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" );   \
     SET_CALLBACK( b );                                          \
+}                                                               \
+void FGAPIENTRY glut##a##Func( FGCB##b callback )               \
+{                                                               \
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" );        \
+    if( callback )                                              \
+        glut##a##FuncUcall( glut##a##FuncCallback, (FGCBUserData)callback ); \
+    else                                                        \
+        glut##a##FuncUcall( NULL, NULL ); \
 }
-#define IMPLEMENT_CALLBACK_FUNC(a) IMPLEMENT_CALLBACK_FUNC_2NAME(a,a)
+/*
+ * Combine _glut and _cb macros:
+ */
+#define IMPLEMENT_CALLBACK_FUNC_ARG0(a)                         \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
 
-/* Implement all these callback setter functions... */
-IMPLEMENT_CALLBACK_FUNC(Position)
-IMPLEMENT_CALLBACK_FUNC(Keyboard)
-IMPLEMENT_CALLBACK_FUNC(KeyboardUp)
-IMPLEMENT_CALLBACK_FUNC(Special)
-IMPLEMENT_CALLBACK_FUNC(SpecialUp)
-IMPLEMENT_CALLBACK_FUNC(Mouse)
-IMPLEMENT_CALLBACK_FUNC(MouseWheel)
-IMPLEMENT_CALLBACK_FUNC(Motion)
-IMPLEMENT_CALLBACK_FUNC_2NAME(PassiveMotion,Passive)
-IMPLEMENT_CALLBACK_FUNC(Entry)
-/* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */
-IMPLEMENT_CALLBACK_FUNC_2NAME(Close,Destroy)
-IMPLEMENT_CALLBACK_FUNC_2NAME(WMClose,Destroy)
-IMPLEMENT_CALLBACK_FUNC(OverlayDisplay)
-IMPLEMENT_CALLBACK_FUNC(WindowStatus)
-IMPLEMENT_CALLBACK_FUNC(ButtonBox)
-IMPLEMENT_CALLBACK_FUNC(Dials)
-IMPLEMENT_CALLBACK_FUNC(TabletMotion)
-IMPLEMENT_CALLBACK_FUNC(TabletButton)
-IMPLEMENT_CALLBACK_FUNC(MultiEntry)
-IMPLEMENT_CALLBACK_FUNC(MultiButton)
-IMPLEMENT_CALLBACK_FUNC(MultiMotion)
-IMPLEMENT_CALLBACK_FUNC(MultiPassive)
-IMPLEMENT_CALLBACK_FUNC(InitContext)
-IMPLEMENT_CALLBACK_FUNC(AppStatus)
+#define IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(a,b)                 \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b)
+
+#define IMPLEMENT_CALLBACK_FUNC_ARG1(a)                         \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CALLBACK_FUNC_ARG2(a)                         \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
 
+#define IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(a,b)                 \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,b)
 
+#define IMPLEMENT_CALLBACK_FUNC_ARG3(a)                         \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3)     \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3)\
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CALLBACK_FUNC_ARG4(a)                         \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+#define IMPLEMENT_CALLBACK_FUNC_ARG5(a)                         \
+        IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a)                    \
+        IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT(a,a)
+
+/* Implement all these callback setter functions... */
+IMPLEMENT_CALLBACK_FUNC_ARG2(Position)
+IMPLEMENT_CALLBACK_FUNC_ARG3_USER(Keyboard,unsigned char,int,int)
+IMPLEMENT_CALLBACK_FUNC_ARG3_USER(KeyboardUp,unsigned char,int,int)
+IMPLEMENT_CALLBACK_FUNC_ARG3(Special)
+IMPLEMENT_CALLBACK_FUNC_ARG3(SpecialUp)
+IMPLEMENT_CALLBACK_FUNC_ARG4(Mouse)
+IMPLEMENT_CALLBACK_FUNC_ARG4(MouseWheel)
+IMPLEMENT_CALLBACK_FUNC_ARG2(Motion)
+IMPLEMENT_CALLBACK_FUNC_ARG2_2NAME(PassiveMotion,Passive)
+IMPLEMENT_CALLBACK_FUNC_ARG1(Entry)
+/* glutWMCloseFunc is an alias for glutCloseFunc; both set the window's Destroy callback */
+IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(Close,Destroy)
+IMPLEMENT_CALLBACK_FUNC_ARG0_2NAME(WMClose,Destroy)
+IMPLEMENT_CALLBACK_FUNC_ARG0(OverlayDisplay)
+IMPLEMENT_CALLBACK_FUNC_ARG1(WindowStatus)
+IMPLEMENT_CALLBACK_FUNC_ARG2(ButtonBox)
+IMPLEMENT_CALLBACK_FUNC_ARG2(Dials)
+IMPLEMENT_CALLBACK_FUNC_ARG2(TabletMotion)
+IMPLEMENT_CALLBACK_FUNC_ARG4(TabletButton)
+IMPLEMENT_CALLBACK_FUNC_ARG2(MultiEntry)
+IMPLEMENT_CALLBACK_FUNC_ARG5(MultiButton)
+IMPLEMENT_CALLBACK_FUNC_ARG3(MultiMotion)
+IMPLEMENT_CALLBACK_FUNC_ARG3(MultiPassive)
+IMPLEMENT_CALLBACK_FUNC_ARG0(InitContext)
+IMPLEMENT_CALLBACK_FUNC_ARG1(AppStatus)
 
 /*
  * Sets the Display callback for the current window
  */
-void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback )
+void FGAPIENTRY glutDisplayFuncUcall( FGCBDisplayUC callback, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFuncUcall" );
     if( !callback )
         fgError( "Fatal error in program.  NULL display callback not "
                  "permitted in GLUT 3.0+ or freeglut 2.0.1+" );
     SET_CALLBACK( Display );
 }
 
-void fghDefaultReshape(int width, int height)
+static void glutDisplayFuncCallback( FGCBUserData userData )
+{
+    FGCBDisplay callback = (FGCBDisplay)userData;
+    callback();
+}
+
+void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" );
+    if( callback )
+        glutDisplayFuncUcall( glutDisplayFuncCallback, (FGCBUserData)callback );
+    else
+        glutDisplayFuncUcall( NULL, NULL );
+}
+
+void fghDefaultReshape( int width, int height, FGCBUserData userData )
 {
     glViewport( 0, 0, width, height );
 }
 
-void FGAPIENTRY glutReshapeFunc( FGCBReshape callback )
+void FGAPIENTRY glutReshapeFuncUcall( FGCBReshapeUC callback, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFuncUcall" );
     
     if( !callback )
+    {
         callback = fghDefaultReshape;
+        userData = NULL;
+    }
 
     SET_CALLBACK( Reshape );
 }
 
+static void glutReshapeFuncCallback( int width, int height, FGCBUserData userData )
+{
+    FGCBReshape callback = (FGCBReshape)userData;
+    callback( width, height );
+}
+
+void FGAPIENTRY glutReshapeFunc( FGCBReshape callback )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeFunc" );
+    if( callback )
+        glutReshapeFuncUcall( glutReshapeFuncCallback, (FGCBUserData)callback );
+    else
+        glutReshapeFuncUcall( NULL, NULL );
+}
+
 /*
  * Sets the Visibility callback for the current window.
  * NB: the Visibility func is deprecated in favor of the WindowStatus func,
@@ -218,7 +374,7 @@ void FGAPIENTRY glutReshapeFunc( FGCBReshape callback )
  * http://stackoverflow.com/questions/5445889/get-which-process-window-is-actually-visible-in-c-sharp
  * for an implementation outline (but it would be polling based, not push based).
  */
-static void fghVisibility( int status )
+static void fghVisibility( int status, FGCBUserData userData )
 {
     int vis_status;
 
@@ -234,23 +390,44 @@ static void fghVisibility( int status )
     INVOKE_WCB( *( fgStructure.CurrentWindow ), Visibility, ( vis_status ) );
 }
 
-void FGAPIENTRY glutVisibilityFunc( FGCBVisibility callback )
+void FGAPIENTRY glutVisibilityFuncUcall( FGCBVisibilityUC callback, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFuncUcall" );
+
+    if ( !callback )
+    {
+        userData = NULL;
+    }
+
     SET_CALLBACK( Visibility );
 
     if( callback )
-        glutWindowStatusFunc( fghVisibility );
+        glutWindowStatusFuncUcall( fghVisibility, NULL );
     else
-        glutWindowStatusFunc( NULL );
+        glutWindowStatusFuncUcall( NULL, NULL );
+}
+
+static void glutVisibilityFuncCallback( int visibility, FGCBUserData userData )
+{
+    FGCBVisibility callback = (FGCBVisibility)userData;
+    callback( visibility );
+}
+
+void FGAPIENTRY glutVisibilityFunc( FGCBVisibility callback )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFunc" );
+    if( callback )
+        glutVisibilityFuncUcall( glutVisibilityFuncCallback, (FGCBUserData)callback );
+    else
+        glutVisibilityFuncUcall( NULL, NULL );
 }
 
 /*
  * Sets the joystick callback and polling rate for the current window
  */
-void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
+void FGAPIENTRY glutJoystickFuncUcall( FGCBJoystickUC callback, int pollInterval, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFuncUcall" );
     fgInitialiseJoysticks ();
 
     if ( (
@@ -281,39 +458,97 @@ void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
         fgStructure.CurrentWindow->State.JoystickLastPoll -= pollInterval;
 }
 
+static void glutJoystickFuncCallback( unsigned int buttons, int axis0, int axis1, int axis2, FGCBUserData userData )
+{
+    FGCBJoystick callback = (FGCBJoystick)userData;
+    callback( buttons, axis0, axis1, axis2 );
+}
 
+void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutJoystickFunc" );
+    if( callback )
+        glutJoystickFuncUcall( glutJoystickFuncCallback, pollInterval, (FGCBUserData)callback );
+    else
+        glutJoystickFuncUcall( NULL, pollInterval, NULL );
+}
 
 /*
  * Sets the spaceball motion callback for the current window
  */
-void FGAPIENTRY glutSpaceballMotionFunc( FGCBSpaceMotion callback )
+void FGAPIENTRY glutSpaceballMotionFuncUcall( FGCBSpaceMotionUC callback, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFuncUcall" );
     fgInitialiseSpaceball();
 
     SET_CALLBACK( SpaceMotion );
 }
 
+static void glutSpaceballMotionFuncCallback( int x, int y, int z, FGCBUserData userData )
+{
+    FGCBSpaceMotion callback = (FGCBSpaceMotion)userData;
+    callback( x, y, z );
+}
+
+void FGAPIENTRY glutSpaceballMotionFunc( FGCBSpaceMotion callback )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballMotionFunc" );
+    if( callback )
+        glutSpaceballMotionFuncUcall( glutSpaceballMotionFuncCallback, (FGCBUserData)callback );
+    else
+        glutSpaceballMotionFuncUcall( NULL, NULL );
+}
+
 /*
  * Sets the spaceball rotate callback for the current window
  */
-void FGAPIENTRY glutSpaceballRotateFunc( FGCBSpaceRotation callback )
+void FGAPIENTRY glutSpaceballRotateFuncUcall( FGCBSpaceRotationUC callback, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFuncUcall" );
     fgInitialiseSpaceball();
 
     SET_CALLBACK( SpaceRotation );
 }
 
+static void glutSpaceballRotateFuncCallback( int x, int y, int z, FGCBUserData userData )
+{
+    FGCBSpaceRotation callback = (FGCBSpaceRotation)userData;
+    callback( x, y, z );
+}
+
+void FGAPIENTRY glutSpaceballRotateFunc( FGCBSpaceRotation callback )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballRotateFunc" );
+    if( callback )
+        glutSpaceballRotateFuncUcall( glutSpaceballRotateFuncCallback, (FGCBUserData)callback );
+    else
+        glutSpaceballRotateFuncUcall( NULL, NULL );
+}
+
 /*
  * Sets the spaceball button callback for the current window
  */
-void FGAPIENTRY glutSpaceballButtonFunc( FGCBSpaceButton callback )
+void FGAPIENTRY glutSpaceballButtonFuncUcall( FGCBSpaceButtonUC callback, FGCBUserData userData )
 {
-    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" );
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFuncUcall" );
     fgInitialiseSpaceball();
 
     SET_CALLBACK( SpaceButton );
 }
 
+static void glutSpaceballButtonFuncCallback( int button, int buttonState, FGCBUserData userData )
+{
+    FGCBSpaceButton callback = (FGCBSpaceButton)userData;
+    callback( button, buttonState );
+}
+
+void FGAPIENTRY glutSpaceballButtonFunc( FGCBSpaceButton callback )
+{
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSpaceballButtonFunc" );
+    if( callback )
+        glutSpaceballButtonFuncUcall( glutSpaceballButtonFuncCallback, (FGCBUserData)callback );
+    else
+        glutSpaceballButtonFuncUcall( NULL, NULL );
+}
+
 /*** END OF FILE ***/
index 4c1f9c9..0ddb560 100644 (file)
@@ -215,7 +215,41 @@ static GLUTproc fghGetGLUTProcAddress( const char* procName )
     CHECK_NAME(glutCreateMenuUcall);
     CHECK_NAME(glutTimerFuncUcall);
     CHECK_NAME(glutIdleFuncUcall);
-    //TODO
+    CHECK_NAME(glutKeyboardFuncUcall);
+    CHECK_NAME(glutSpecialFuncUcall);
+    CHECK_NAME(glutReshapeFuncUcall);
+    CHECK_NAME(glutVisibilityFuncUcall);
+    CHECK_NAME(glutDisplayFuncUcall);
+    CHECK_NAME(glutMouseFuncUcall);
+    CHECK_NAME(glutMotionFuncUcall);
+    CHECK_NAME(glutPassiveMotionFuncUcall);
+    CHECK_NAME(glutEntryFuncUcall);
+    CHECK_NAME(glutKeyboardUpFuncUcall);
+    CHECK_NAME(glutSpecialUpFuncUcall);
+    CHECK_NAME(glutJoystickFuncUcall);
+    CHECK_NAME(glutMenuStatusFuncUcall);
+    CHECK_NAME(glutOverlayDisplayFuncUcall);
+    CHECK_NAME(glutWindowStatusFuncUcall);
+    CHECK_NAME(glutSpaceballMotionFuncUcall);
+    CHECK_NAME(glutSpaceballRotateFuncUcall);
+    CHECK_NAME(glutSpaceballButtonFuncUcall);
+    CHECK_NAME(glutButtonBoxFuncUcall);
+    CHECK_NAME(glutDialsFuncUcall);
+    CHECK_NAME(glutTabletMotionFuncUcall);
+    CHECK_NAME(glutTabletButtonFuncUcall);
+    CHECK_NAME(glutMouseWheelFuncUcall);
+    CHECK_NAME(glutPositionFuncUcall);
+    CHECK_NAME(glutCloseFuncUcall);
+    CHECK_NAME(glutWMCloseFuncUcall);
+    CHECK_NAME(glutMenuDestroyFuncUcall);
+    CHECK_NAME(glutMultiEntryFuncUcall);
+    CHECK_NAME(glutMultiButtonFuncUcall);
+    CHECK_NAME(glutMultiMotionFuncUcall);
+    CHECK_NAME(glutMultiPassiveFuncUcall);
+    CHECK_NAME(glutInitErrorFuncUcall);
+    CHECK_NAME(glutInitWarningFuncUcall);
+    CHECK_NAME(glutInitContextFuncUcall);
+    CHECK_NAME(glutAppStatusFuncUcall);
 #undef CHECK_NAME
 
     return NULL;
index ffd3f99..a408bbe 100644 (file)
@@ -74,6 +74,7 @@ SFG_State fgState = { { -1, -1, GL_FALSE },  /* Position */
                       0,                      /* ActiveMenus */
                       NULL,                   /* MenuStateCallback */
                       NULL,                   /* MenuStatusCallback */
+                      NULL,                   /* MenuStatusCallbackData */
                       FREEGLUT_MENU_FONT,
                       { -1, -1, GL_TRUE },    /* GameModeSize */
                       -1,                     /* GameModeDepth */
@@ -96,7 +97,9 @@ SFG_State fgState = { { -1, -1, GL_FALSE },  /* Position */
                       0,                      /* OpenGL ContextProfile */
                       0,                      /* HasOpenGL20 */
                       NULL,                   /* ErrorFunc */
-                      NULL                    /* WarningFunc */
+                      NULL,                   /* ErrorFuncData */
+                      NULL,                   /* WarningFunc */
+                      NULL                    /* WarningFuncData */
 };
 
 
@@ -299,10 +302,11 @@ void fgDeinitialize( void )
     fgListInit( &fgState.Timers );
     fgListInit( &fgState.FreeTimers );
 
-    fgState.IdleCallback = NULL;
-    fgState.IdleCallbackData = NULL;
-    fgState.MenuStateCallback = ( FGCBMenuState )NULL;
-    fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL;
+    fgState.IdleCallback           = ( FGCBIdleUC )NULL;
+    fgState.IdleCallbackData       = NULL;
+    fgState.MenuStateCallback      = ( FGCBMenuState )NULL;
+    fgState.MenuStatusCallback     = ( FGCBMenuStatusUC )NULL;
+    fgState.MenuStatusCallbackData = NULL;
 
     fgState.SwapCount   = 0;
     fgState.SwapTime    = 0;
@@ -670,19 +674,49 @@ void FGAPIENTRY glutInitContextProfile( int profile )
 /*
  * Sets the user error handler (note the use of va_list for the args to the fmt)
  */
-void FGAPIENTRY glutInitErrorFunc( FGError callback )
+void FGAPIENTRY glutInitErrorFuncUcall( FGErrorUC callback, FGCBUserData userData )
 {
     /* This allows user programs to handle freeglut errors */
     fgState.ErrorFunc = callback;
+    fgState.ErrorFuncData = userData;
+}
+
+static void glutInitErrorFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
+{
+    FGError callback = (FGError)userData;
+    callback( fmt, ap );
+}
+
+void FGAPIENTRY glutInitErrorFunc( FGError callback )
+{
+  if (callback)
+    glutInitErrorFuncUcall( glutInitErrorFuncCallback, (FGCBUserData)callback );
+  else
+    glutInitErrorFuncUcall( NULL, NULL );
 }
 
 /*
  * Sets the user warning handler (note the use of va_list for the args to the fmt)
  */
-void FGAPIENTRY glutInitWarningFunc( FGWarning callback )
+void FGAPIENTRY glutInitWarningFuncUcall( FGWarningUC callback, FGCBUserData userData )
 {
     /* This allows user programs to handle freeglut warnings */
     fgState.WarningFunc = callback;
+    fgState.WarningFuncData = userData;
+}
+
+static void glutInitWarningFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
+{
+    FGWarning callback = (FGWarning)userData;
+    callback( fmt, ap );
+}
+
+void FGAPIENTRY glutInitWarningFunc( FGWarning callback )
+{
+  if (callback)
+    glutInitWarningFuncUcall( glutInitWarningFuncCallback, (FGCBUserData)callback );
+  else
+    glutInitWarningFuncUcall( NULL, NULL );
 }
 
 /*** END OF FILE ***/
index 8e27f54..69401d0 100644 (file)
 /* Freeglut callbacks type definitions */
 typedef void* FGCBUserData;
 
-typedef void (* FGCBDisplay       )( void );
-typedef void (* FGCBReshape       )( int, int );
-typedef void (* FGCBPosition      )( int, int );
-typedef void (* FGCBVisibility    )( int );
-typedef void (* FGCBKeyboard      )( unsigned char, int, int );
-typedef void (* FGCBKeyboardUp    )( unsigned char, int, int );
-typedef void (* FGCBSpecial       )( int, int, int );
-typedef void (* FGCBSpecialUp     )( int, int, int );
-typedef void (* FGCBMouse         )( int, int, int, int );
-typedef void (* FGCBMouseWheel    )( int, int, int, int );
-typedef void (* FGCBMotion        )( int, int );
-typedef void (* FGCBPassive       )( int, int );
-typedef void (* FGCBEntry         )( int );
-typedef void (* FGCBWindowStatus  )( int );
-typedef void (* FGCBJoystick      )( unsigned int, int, int, int );
-typedef void (* FGCBOverlayDisplay)( void );
-typedef void (* FGCBSpaceMotion   )( int, int, int );
-typedef void (* FGCBSpaceRotation )( int, int, int );
-typedef void (* FGCBSpaceButton   )( int, int );
-typedef void (* FGCBDials         )( int, int );
-typedef void (* FGCBButtonBox     )( int, int );
-typedef void (* FGCBTabletMotion  )( int, int );
-typedef void (* FGCBTabletButton  )( int, int, int, int );
-typedef void (* FGCBDestroy       )( void );    /* Used for both window and menu destroy callbacks */
-
-typedef void (* FGCBMultiEntry   )( int, int );
-typedef void (* FGCBMultiButton  )( int, int, int, int, int );
-typedef void (* FGCBMultiMotion  )( int, int, int );
-typedef void (* FGCBMultiPassive )( int, int, int );
-
-typedef void (* FGCBInitContext)();
-typedef void (* FGCBAppStatus)(int);
+typedef void (* FGCBDisplay         )( void );
+typedef void (* FGCBDisplayUC       )( FGCBUserData );
+typedef void (* FGCBReshape         )( int, int );
+typedef void (* FGCBReshapeUC       )( int, int, FGCBUserData );
+typedef void (* FGCBPosition        )( int, int );
+typedef void (* FGCBPositionUC      )( int, int, FGCBUserData );
+typedef void (* FGCBVisibility      )( int );
+typedef void (* FGCBVisibilityUC    )( int, FGCBUserData );
+typedef void (* FGCBKeyboard        )( unsigned char, int, int );
+typedef void (* FGCBKeyboardUC      )( unsigned char, int, int, FGCBUserData );
+typedef void (* FGCBKeyboardUp      )( unsigned char, int, int );
+typedef void (* FGCBKeyboardUpUC    )( unsigned char, int, int, FGCBUserData );
+typedef void (* FGCBSpecial         )( int, int, int );
+typedef void (* FGCBSpecialUC       )( int, int, int, FGCBUserData );
+typedef void (* FGCBSpecialUp       )( int, int, int );
+typedef void (* FGCBSpecialUpUC     )( int, int, int, FGCBUserData );
+typedef void (* FGCBMouse           )( int, int, int, int );
+typedef void (* FGCBMouseUC         )( int, int, int, int, FGCBUserData );
+typedef void (* FGCBMouseWheel      )( int, int, int, int );
+typedef void (* FGCBMouseWheelUC    )( int, int, int, int, FGCBUserData );
+typedef void (* FGCBMotion          )( int, int );
+typedef void (* FGCBMotionUC        )( int, int, FGCBUserData );
+typedef void (* FGCBPassive         )( int, int );
+typedef void (* FGCBPassiveUC       )( int, int, FGCBUserData );
+typedef void (* FGCBEntry           )( int );
+typedef void (* FGCBEntryUC         )( int, FGCBUserData );
+typedef void (* FGCBWindowStatus    )( int );
+typedef void (* FGCBWindowStatusUC  )( int, FGCBUserData );
+typedef void (* FGCBJoystick        )( unsigned int, int, int, int );
+typedef void (* FGCBJoystickUC      )( unsigned int, int, int, int, FGCBUserData );
+typedef void (* FGCBOverlayDisplay  )( void );
+typedef void (* FGCBOverlayDisplayUC)( FGCBUserData );
+typedef void (* FGCBSpaceMotion     )( int, int, int );
+typedef void (* FGCBSpaceMotionUC   )( int, int, int, FGCBUserData );
+typedef void (* FGCBSpaceRotation   )( int, int, int );
+typedef void (* FGCBSpaceRotationUC )( int, int, int, FGCBUserData );
+typedef void (* FGCBSpaceButton     )( int, int );
+typedef void (* FGCBSpaceButtonUC   )( int, int, FGCBUserData );
+typedef void (* FGCBDials           )( int, int );
+typedef void (* FGCBDialsUC         )( int, int, FGCBUserData );
+typedef void (* FGCBButtonBox       )( int, int );
+typedef void (* FGCBButtonBoxUC     )( int, int, FGCBUserData );
+typedef void (* FGCBTabletMotion    )( int, int );
+typedef void (* FGCBTabletMotionUC  )( int, int, FGCBUserData );
+typedef void (* FGCBTabletButton    )( int, int, int, int );
+typedef void (* FGCBTabletButtonUC  )( int, int, int, int, FGCBUserData );
+typedef void (* FGCBDestroy         )( void );    /* Used for both window and menu destroy callbacks */
+typedef void (* FGCBDestroyUC       )( FGCBUserData );
+
+typedef void (* FGCBMultiEntry      )( int, int );
+typedef void (* FGCBMultiEntryUC    )( int, int, FGCBUserData );
+typedef void (* FGCBMultiButton     )( int, int, int, int, int );
+typedef void (* FGCBMultiButtonUC   )( int, int, int, int, int, FGCBUserData );
+typedef void (* FGCBMultiMotion     )( int, int, int );
+typedef void (* FGCBMultiMotionUC   )( int, int, int, FGCBUserData );
+typedef void (* FGCBMultiPassive    )( int, int, int );
+typedef void (* FGCBMultiPassiveUC  )( int, int, int, FGCBUserData );
+
+typedef void (* FGCBInitContext     )( void );
+typedef void (* FGCBInitContextUC   )( FGCBUserData );
+typedef void (* FGCBAppStatus       )( int );
+typedef void (* FGCBAppStatusUC     )( int, FGCBUserData );
 
 /* The global callbacks type definitions */
-typedef void (* FGCBIdle          )( void );
-typedef void (* FGCBIdleUC        )( FGCBUserData );
-typedef void (* FGCBTimer         )( int );
-typedef void (* FGCBTimerUC       )( int, FGCBUserData );
-typedef void (* FGCBMenuState     )( int );
-typedef void (* FGCBMenuStatus    )( int, int, int );
+typedef void (* FGCBIdle            )( void ); \
+typedef void (* FGCBIdleUC          )( FGCBUserData );
+typedef void (* FGCBTimer           )( int );
+typedef void (* FGCBTimerUC         )( int, FGCBUserData );
+typedef void (* FGCBMenuState       )( int );
+typedef void (* FGCBMenuStatus      )( int, int, int );
+typedef void (* FGCBMenuStatusUC    )( int, int, int, FGCBUserData );
 
 /* The callback used when creating/using menus */
-typedef void (* FGCBMenu          )( int );
-typedef void (* FGCBMenuUC        )( int, FGCBUserData );
+typedef void (* FGCBMenu            )( int );
+typedef void (* FGCBMenuUC          )( int, FGCBUserData );
 
 /* The FreeGLUT error/warning handler type definition */
-typedef void (* FGError           ) ( const char *fmt, va_list ap);
-typedef void (* FGWarning         ) ( const char *fmt, va_list ap);
+typedef void (* FGError             )( const char *fmt, va_list ap );
+typedef void (* FGErrorUC           )( const char *fmt, va_list ap, FGCBUserData userData );
+typedef void (* FGWarning           )( const char *fmt, va_list ap );
+typedef void (* FGWarningUC         )( const char *fmt, va_list ap, FGCBUserData userData );
 
 
 /* A list structure */
@@ -337,24 +370,25 @@ struct tagSFG_State
 
     int              ActiveMenus;          /* Num. of currently active menus */
     FGCBMenuState    MenuStateCallback;    /* Menu callbacks are global      */
-    FGCBMenuStatus   MenuStatusCallback;
+    FGCBMenuStatusUC MenuStatusCallback;
+    FGCBUserData     MenuStatusCallbackData;
     void*            MenuFont;             /* Font to be used for newly created menus */
 
     SFG_XYUse        GameModeSize;         /* Game mode screen's dimensions  */
     int              GameModeDepth;        /* The pixel depth for game mode  */
     int              GameModeRefresh;      /* The refresh rate for game mode */
 
-    int              ActionOnWindowClose; /* Action when user closes window  */
+    int              ActionOnWindowClose;  /* Action when user closes window  */
 
-    fgExecutionState ExecState;           /* Used for GLUT termination       */
-    char            *ProgramName;         /* Name of the invoking program    */
-    GLboolean        JoysticksInitialised;  /* Only initialize if application calls for them */
-    int              NumActiveJoysticks;    /* Number of active joysticks (callback defined and positive pollrate) -- if zero, don't poll joysticks */
-    GLboolean        InputDevsInitialised;  /* Only initialize if application calls for them */
+    fgExecutionState ExecState;            /* Used for GLUT termination       */
+    char            *ProgramName;          /* Name of the invoking program    */
+    GLboolean        JoysticksInitialised; /* Only initialize if application calls for them */
+    int              NumActiveJoysticks;   /* Number of active joysticks (callback defined and positive pollrate) -- if zero, don't poll joysticks */
+    GLboolean        InputDevsInitialised; /* Only initialize if application calls for them */
 
        int              MouseWheelTicks;      /* Number of ticks the mouse wheel has turned */
 
-    int              AuxiliaryBufferNumber;  /* Number of auxiliary buffers */
+    int              AuxiliaryBufferNumber;/* Number of auxiliary buffers */
     int              SampleNumber;         /*  Number of samples per pixel  */
 
     GLboolean        SkipStaleMotion;      /* skip stale motion events */
@@ -367,8 +401,10 @@ struct tagSFG_State
     int              ContextFlags;         /* OpenGL context flags          */
     int              ContextProfile;       /* OpenGL context profile        */
     int              HasOpenGL20;          /* fgInitGL2 could find all OpenGL 2.0 functions */
-    FGError          ErrorFunc;            /* User defined error handler    */
-    FGWarning        WarningFunc;          /* User defined warning handler  */
+    FGErrorUC        ErrorFunc;            /* User defined error handler    */
+    FGCBUserData     ErrorFuncData;        /* User defined error handler user data */
+    FGWarningUC      WarningFunc;          /* User defined warning handler  */
+    FGCBUserData     WarningFuncData;      /* User defined warning handler user data */
 };
 
 /* The structure used by display initialization in fg_init.c */
@@ -518,11 +554,12 @@ typedef void (*SFG_Proc)();
 /*
  * SET_WCB() is used as:
  *
- *     SET_WCB( window, cbname, func );
+ *     SET_WCB( window, cbname, func, udata );
  *
  * ...where {window} is the freeglut window to set the callback,
  *          {cbname} is the window-specific callback to set,
- *          {func} is a function-pointer.
+ *          {func} is a function-pointer,
+ *          {udata} is a void* pointer for user data.
  *
  * Originally, {FETCH_WCB( ... ) = func} was rather sloppily used,
  * but this can cause warnings because the FETCH_WCB() macro type-
@@ -532,11 +569,14 @@ typedef void (*SFG_Proc)();
  * and for no other reason.  Since it's hidden in the macro, the
  * ugliness is felt to be rather benign.
  */
-#define SET_WCB(window,cbname,func)                            \
+#define SET_WCB(window,cbname,func,udata)                      \
 do                                                             \
 {                                                              \
     if( FETCH_WCB( window, cbname ) != (SFG_Proc)(func) )      \
+    {                                                          \
         (((window).CallBacks[WCB_ ## cbname]) = (SFG_Proc)(func)); \
+        (((window).CallbackDatas[WCB_ ## cbname]) = (udata));  \
+    }                                                          \
 } while( 0 )
 
 /*
@@ -554,6 +594,82 @@ do                                                             \
     ((window).CallBacks[WCB_ ## cbname])
 
 /*
+ * FETCH_USER_DATA_WCB() is used as:
+ * 
+ *     FETCH_USER_DATA_WCB( window, cbname );
+ *
+ * ...where {window} is the freeglut window,
+ *          {cbname} is the window-specific callback to be invoked,
+ *
+ * This expects a variable named "window" of type tagSFG_Window to exist.
+ */
+/*
+ * FETCH_USER_DATA_WCB() is used as:
+ *
+ *     FETCH_USER_DATA_WCB( window, cbname );
+ *
+ * ...where {window} is the freeglut window to fetch the callback data from,
+ *          {cbname} is the window-specific callback data to fetch.
+ *
+ * The result is the callback data pointer.
+ */
+#define FETCH_USER_DATA_WCB(window,cbname) \
+    ((window).CallbackDatas[WCB_ ## cbname])
+
+/*
+ * EXPAND_WCB() is used as:
+ * 
+ *     EXPAND_WCB arg_list
+ * 
+ * ... where {(arg_list)} is the parameter list.
+ *
+ * This will take the arg_list and extend it by one argument, adding
+ * the argument "userData" to the end of the list.
+ * 
+ * All additional args are to get around trailing ',', argument counts,
+ * and not needing a GCC extension to make this work.
+ *
+ * Minor modification of:
+ * http://stackoverflow.com/questions/5355241/generating-function-declaration-using-a-macro-iteration/5355946#5355946
+ *
+ * Supports up to five arguments
+ */
+#if TARGET_HOST_MS_WINDOWS
+
+/* FIXME: Does VC6 support variadic macros? I don't think so (variadic macros came with C99. VC6 came out in 1998) */
+
+/* FIXME: VC++ has a greedy preprocessor.
+ * The preprocessor resolves the macros on use instead of after on argument completion/token usage.
+ * e.g.: PP_HAS_ARGS_IMPL2(ONE_OR_MORE, ...) -> PP_HAS_ARGS_IMPL2(, ...) -> "Error, not enough tokens for PP_HAS_ARGS_IMPL2"
+ */
+#define EXPAND_WCB(...) (__VA_ARGS__)
+
+#else // #if TARGET_HOST_MS_WINDOWS
+
+#define PP_HAS_ARGS_IMPL2(_0, _1, _2, _3, _4, _5, N, ...) N
+#define PP_HAS_ARGS_SOURCE() \
+    ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ONE_OR_MORE, ZERO
+
+#define PP_HAS_ARGS_IMPL(...) \
+    PP_HAS_ARGS_IMPL2(__VA_ARGS__)
+#define PP_HAS_ARGS(...) \
+    PP_HAS_ARGS_IMPL(NOT_EXIST, ##__VA_ARGS__, PP_HAS_ARGS_SOURCE())
+
+#define EXPAND_WCB_ZERO(x) \
+    (userData)
+#define EXPAND_WCB_ONE_OR_MORE(...) \
+    (__VA_ARGS__, userData)
+
+#define EXPAND_WCB_DISAMBIGUATE2(has_args, ...) \
+    EXPAND_WCB_ ## has_args (__VA_ARGS__)
+#define EXPAND_WCB_DISAMBIGUATE(has_args, ...) \
+    EXPAND_WCB_DISAMBIGUATE2(has_args, __VA_ARGS__)
+#define EXPAND_WCB(...) \
+    EXPAND_WCB_DISAMBIGUATE(PP_HAS_ARGS(__VA_ARGS__), __VA_ARGS__)
+
+#endif // #if TARGET_HOST_MS_WINDOWS
+
+/*
  * INVOKE_WCB() is used as:
  *
  *     INVOKE_WCB( window, cbname, ( arg_list ) );
@@ -578,9 +694,10 @@ do                                            \
 {                                             \
     if( FETCH_WCB( window, cbname ) )         \
     {                                         \
-        FGCB ## cbname func = (FGCB ## cbname)(FETCH_WCB( window, cbname )); \
+        FGCB ## cbname ## UC func = (FGCB ## cbname ## UC)(FETCH_WCB( window, cbname )); \
+        FGCBUserData userData = FETCH_USER_DATA_WCB( window, cbname ); \
         fgSetWindow( &window );               \
-        func arg_list;                        \
+        func EXPAND_WCB arg_list;             \
     }                                         \
 } while( 0 )
 #else
@@ -590,7 +707,8 @@ do                                            \
     if( FETCH_WCB( window, cbname ) )         \
     {                                         \
         fgSetWindow( &window );               \
-        ((FGCB ## cbname)FETCH_WCB( window, cbname )) arg_list; \
+        FGCBUserData userData = FETCH_USER_DATA_WCB( window, cbname ); \
+        ((FGCB ## cbname ## UC)FETCH_WCB( window, cbname )) EXPAND_WCB arg_list; \
     }                                         \
 } while( 0 )
 #endif
@@ -671,7 +789,8 @@ struct tagSFG_Menu
     SFG_List            Entries;      /* The menu entries list               */
     FGCBMenuUC          Callback;     /* The menu callback                   */
     FGCBUserData        CallbackData; /* The menu callback user data         */
-    FGCBDestroy         Destroy;      /* Destruction callback                */
+    FGCBDestroyUC       Destroy;      /* Destruction callback                */
+    FGCBUserData        DestroyData;  /* Destruction callback user data      */
     GLboolean           IsActive;     /* Is the menu selected?               */
     void*               Font;         /* Font to be used for displaying this menu */
     int                 Width;        /* Menu box width in pixels            */
@@ -709,10 +828,11 @@ struct tagSFG_Window
     SFG_Context         Window;                 /* Window and OpenGL context */
     SFG_WindowState     State;                  /* The window state          */
     SFG_Proc            CallBacks[ TOTAL_CALLBACKS ]; /* Array of window callbacks */
+    FGCBUserData        CallbackDatas[ TOTAL_CALLBACKS ]; /* Array of window callback datas */
     void               *UserData ;              /* For use by user           */
 
-    SFG_Menu*       Menu[ FREEGLUT_MAX_MENUS ]; /* Menus appended to window  */
-    SFG_Menu*       ActiveMenu;                 /* The window's active menu  */
+    SFG_Menu*           Menu[ FREEGLUT_MAX_MENUS ]; /* Menus appended to window  */
+    SFG_Menu*           ActiveMenu;             /* The window's active menu  */
 
     SFG_Window*         Parent;                 /* The parent to this window */
     SFG_List            Children;               /* The subwindows d.l. list  */
index 6e9ff48..45f13f5 100644 (file)
@@ -269,7 +269,7 @@ void fgError( const char *fmt, ... )
         va_start( ap, fmt );
 
         /* call user set error handler here */
-        fgState.ErrorFunc(fmt, ap);
+        fgState.ErrorFunc(fmt, ap, fgState.ErrorFuncData);
 
         va_end( ap );
 
@@ -302,7 +302,7 @@ void fgWarning( const char *fmt, ... )
         va_start( ap, fmt );
 
         /* call user set warning handler here */
-        fgState.WarningFunc(fmt, ap);
+        fgState.WarningFunc(fmt, ap, fgState.WarningFuncData);
 
         va_end( ap );
 
index cad5b83..1b07b1a 100644 (file)
@@ -531,7 +531,7 @@ static void fghActivateMenu( SFG_Window* window, int button )
             fgState.MenuStateCallback(GLUT_MENU_IN_USE);
         if (fgState.MenuStatusCallback)
             /* window->State.MouseX and window->State.MouseY are relative to client area origin, as needed */
-            fgState.MenuStatusCallback(GLUT_MENU_IN_USE, window->State.MouseX, window->State.MouseY);
+            fgState.MenuStatusCallback(GLUT_MENU_IN_USE, window->State.MouseX, window->State.MouseY, fgState.MenuStatusCallbackData);
     }
 
     fgSetWindow( menu->Window );
@@ -725,7 +725,7 @@ void fgDeactivateMenu( SFG_Window *window )
             SFG_XYUse mouse_pos;
             fghPlatformGetCursorPos(parent_window, GL_TRUE, &mouse_pos);
 
-            fgState.MenuStatusCallback(GLUT_MENU_NOT_IN_USE, mouse_pos.X, mouse_pos.Y);
+            fgState.MenuStatusCallback(GLUT_MENU_NOT_IN_USE, mouse_pos.X, mouse_pos.Y, fgState.MenuStatusCallbackData);
         }
     }
 }
@@ -791,7 +791,7 @@ int FGAPIENTRY glutCreateMenuUcall( FGCBMenuUC callback, FGCBUserData userData )
 }
 
 /* Standard glutCreateMenu */
-void glutCreateMenuCallback( int menu, FGCBUserData userData )
+static void glutCreateMenuCallback( int menu, FGCBUserData userData )
 {
     FGCBMenu callback = (FGCBMenu)userData;
     callback( menu );
@@ -800,6 +800,8 @@ void glutCreateMenuCallback( int menu, FGCBUserData userData )
 int FGAPIENTRY glutCreateMenu( FGCBMenu callback )
 {
     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" );
+    if (!callback)
+        return glutCreateMenuUcall( NULL, NULL );
     return glutCreateMenuUcall( glutCreateMenuCallback, (FGCBUserData)callback );
 }
 
index c279b4a..4274667 100644 (file)
@@ -49,7 +49,7 @@ SFG_Structure fgStructure = { { NULL, NULL },  /* The list of windows       */
 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
 
 extern void fgPlatformCreateWindow ( SFG_Window *window );
-extern void fghDefaultReshape(int width, int height);
+extern void fghDefaultReshape(int width, int height, FGCBUserData userData);
 
 static void fghClearCallBacks( SFG_Window *window )
 {
@@ -57,7 +57,10 @@ static void fghClearCallBacks( SFG_Window *window )
     {
         int i;
         for( i = 0; i < TOTAL_CALLBACKS; ++i )
+        {
             window->CallBacks[ i ] = NULL;
+            window->CallbackDatas[ i ] = NULL;
+        }
     }
 }
 
@@ -83,7 +86,7 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title,
        fgPlatformCreateWindow ( window );
 
     fghClearCallBacks( window );
-    SET_WCB( *window, Reshape, fghDefaultReshape);
+    SET_WCB( *window, Reshape, fghDefaultReshape, NULL);
 
     /* Initialize the object properties */
     window->ID = ++fgStructure.WindowID;
@@ -174,9 +177,10 @@ void fgAddToWindowDestroyList( SFG_Window* window )
      * to ensure that they are no longer called after this point.
      */
     {
-        FGCBDestroy destroy = (FGCBDestroy)FETCH_WCB( *window, Destroy );
+        FGCBDestroyUC destroy = (FGCBDestroyUC)FETCH_WCB( *window, Destroy );
+        FGCBUserData destroyData = FETCH_USER_DATA_WCB( *window, Destroy );
         fghClearCallBacks( window );
-        SET_WCB( *window, Destroy, destroy );
+        SET_WCB( *window, Destroy, destroy, destroyData );
     }
 }
 
@@ -303,7 +307,7 @@ void fgDestroyMenu( SFG_Menu* menu )
     {
         SFG_Menu *activeMenu=fgStructure.CurrentMenu;
         fgStructure.CurrentMenu = menu;
-        menu->Destroy( );
+        menu->Destroy( menu->DestroyData );
         fgStructure.CurrentMenu = activeMenu;
     }