Merge pull request #42 from rcmaniac25/feature/usr_callback_support

User data callback support
This commit is contained in:
Diederick C. Niehorster 2017-07-01 01:14:41 +02:00 committed by GitHub
commit 913c66e35e
16 changed files with 1185 additions and 217 deletions

View File

@ -68,6 +68,7 @@ ENDIF()
SET(FREEGLUT_HEADERS
include/GL/freeglut.h
include/GL/freeglut_ucall.h
include/GL/freeglut_ext.h
include/GL/freeglut_std.h
)
@ -90,6 +91,7 @@ SET(FREEGLUT_SRCS
src/fg_init.c
src/fg_init.h
src/fg_internal.h
src/fg_callback_macros.h
src/fg_input_devices.c
src/fg_joystick.c
src/fg_main.c
@ -551,6 +553,7 @@ IF(UNIX)
ENDIF()
ADD_DEMO(subwin progs/demos/subwin/subwin.c)
ADD_DEMO(timer progs/demos/timer/timer.c)
ADD_DEMO(timer_callback progs/demos/timer_callback/timer.c)

View File

@ -261,7 +261,7 @@ FGAPI void FGAPIENTRY glutSetVertexAttribNormal(GLint attrib);
FGAPI void FGAPIENTRY glutSetVertexAttribTexCoord2( GLint attrib );
/* Mobile platforms lifecycle */
FGAPI void FGAPIENTRY glutInitContextFunc(void (* callback)());
FGAPI void FGAPIENTRY glutInitContextFunc( void (* callback)( void ) );
FGAPI void FGAPIENTRY glutAppStatusFunc( void (* callback)( int ) );
/* state flags that can be passed to callback set by glutAppStatusFunc */
#define GLUT_APPSTATUS_PAUSE 0x0001
@ -274,6 +274,9 @@ FGAPI void FGAPIENTRY glutAppStatusFunc(void (* callback)(int));
#define GLUT_BORDERLESS 0x0800
#define GLUT_SRGB 0x1000
/* User-argument callbacks and implementation */
#include "freeglut_ucall.h"
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,113 @@
#ifndef __FREEGLUT_UCALL_H__
#define __FREEGLUT_UCALL_H__
/*
* freeglut_ucall.h
*
* Callbacks with user data arguments.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Menu stuff, see fg_menu.c
*/
FGAPI int FGAPIENTRY glutCreateMenuUcall( void (* callback)( int menu, void* user_data ), void* user_data );
/*
* Global callback functions, see fg_callbacks.c
*/
FGAPI void FGAPIENTRY glutTimerFuncUcall( unsigned int time, void (* callback)( int, void* ), int value, void* user_data );
FGAPI void FGAPIENTRY glutIdleFuncUcall( void (* callback)( void* ), void* user_data );
/*
* Window-specific callback functions, see fg_callbacks.c
*/
FGAPI void FGAPIENTRY glutKeyboardFuncUcall( void (* callback)( unsigned char, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutSpecialFuncUcall( void (* callback)( int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutReshapeFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutVisibilityFuncUcall( void (* callback)( int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutDisplayFuncUcall( void (* callback)( void* ), void* user_data );
FGAPI void FGAPIENTRY glutMouseFuncUcall( void (* callback)( int, int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutMotionFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutPassiveMotionFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutEntryFuncUcall( void (* callback)( int, void* ), void* user_data );
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 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 );
FGAPI void FGAPIENTRY glutSpaceballMotionFuncUcall( void (* callback)( int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutSpaceballRotateFuncUcall( void (* callback)( int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutSpaceballButtonFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutButtonBoxFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutDialsFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutTabletMotionFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutTabletButtonFuncUcall( void (* callback)( int, int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutMouseWheelFuncUcall( void (* callback)( int, int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutPositionFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutCloseFuncUcall( void (* callback)( void* ), void* user_data );
FGAPI void FGAPIENTRY glutWMCloseFuncUcall( void (* callback)( void* ), void* user_data );
FGAPI void FGAPIENTRY glutMenuDestroyFuncUcall( void (* callback)( void* ), void* user_data );
/*
* Multi-touch/multi-pointer extensions
*/
FGAPI void FGAPIENTRY glutMultiEntryFuncUcall( void (* callback)( int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutMultiButtonFuncUcall( void (* callback)( int, int, int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutMultiMotionFuncUcall( void (* callback)( int, int, int, void* ), void* user_data );
FGAPI void FGAPIENTRY glutMultiPassiveFuncUcall( void (* callback)( int, int, int, void* ), void* user_data );
/*
* Initialization functions, see fg_init.c
*/
#include <stdarg.h>
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 );
/*
* Continued "hack" from GLUT applied to Ucall functions.
* For more info, see bottom of freeglut_std.h
*/
/* to get the prototype for exit() */
#include <stdlib.h>
#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) && !defined(__WATCOMC__)
FGAPI int FGAPIENTRY __glutCreateMenuUcallWithExit(void(*func)(int, void*), void(__cdecl *exitfunc)(int), void* user_data);
#ifndef FREEGLUT_BUILDING_LIB
#if defined(__GNUC__)
#define FGUNUSED __attribute__((unused))
#else
#define FGUNUSED
#endif
static int FGAPIENTRY FGUNUSED glutCreateMenuUcall_ATEXIT_HACK(void(*func)(int, void*), void* user_data) { return __glutCreateMenuUcallWithExit(func, exit, user_data); }
#define glutCreateMenuUcall glutCreateMenuUcall_ATEXIT_HACK
#endif
#endif
#ifdef __cplusplus
}
#endif
/*** END OF FILE ***/
#endif /* __FREEGLUT_UCALL_H__ */

View File

@ -0,0 +1,174 @@
/* Timer (callback) demo
*
* Written by John Tsiombikas <nuclear@member.fsf.org>
* Modified by Vincent Simonetti
*
* A modification of the timer sample, but with this
* offering a use of the user-data callback.
*/
#include <stdio.h>
#include <GL/freeglut.h>
struct display_index_s
{
/* color index will be advanced every time the timer expires */
int surround_color_index;
int center_color_index;
};
typedef struct display_index_s display_index_t;
struct timer_state_s
{
int* color_index_ptr;
int* timer_time_ptr;
};
typedef struct timer_state_s timer_state_t;
struct menu_state_s
{
int* timer_time_ptr;
int menu_id;
};
typedef struct menu_state_s menu_state_t;
void disp(void* uptr);
void timer_func(int which, void* uptr);
const float color[][3] = {
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
{1, 1, 0},
{0, 1, 1},
{1, 0, 1}
};
const int timerInts[] = {
250,
500,
1000
};
void createMenuEntries(menu_state_t* menuState)
{
int i;
for (i = 0; i < sizeof(timerInts) / sizeof(*timerInts); i++)
{
char temp[10] = {'\0'};
/* flag current value */
if ((*menuState->timer_time_ptr) == timerInts[i])
temp[0] = '+';
else
temp[0] = '-';
sprintf(temp + 1, " %4d ms", timerInts[i]);
glutAddMenuEntry(temp, timerInts[i]);
}
}
void updateMenuEntries(menu_state_t* menuState)
{
int i;
for (i = 0; i < sizeof(timerInts) / sizeof(*timerInts); i++)
{
char temp[10] = { '\0' };
/* flag current value */
if ((*menuState->timer_time_ptr) == timerInts[i])
temp[0] = '+';
else
temp[0] = '-';
sprintf(temp + 1, " %4d ms", timerInts[i]);
glutChangeToMenuEntry(i+1, temp, timerInts[i]);
}
}
void MenuHandler(int timerInt, void* user_ptr)
{
menu_state_t* menuState;
if (!user_ptr)
{
/* In case main menu is selected somehow */
return;
}
menuState = (menu_state_t*)user_ptr;
*menuState->timer_time_ptr = timerInt;
glutSetMenu(menuState->menu_id);
updateMenuEntries(menuState);
}
int main(int argc, char **argv)
{
int timerSurroundInt = 1000, timerCenterInt = 500;
display_index_t displayIndex = { 0, 2 };
timer_state_t surroundTimerState = { &displayIndex.surround_color_index, &timerSurroundInt };
timer_state_t centerTimerState = { &displayIndex.center_color_index, &timerCenterInt };
menu_state_t surroundMenuState = { &timerSurroundInt, 0 };
menu_state_t centerMenuState = { &timerCenterInt, 0 };
glutInit(&argc, argv);
glutInitWindowSize(128, 128);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("timer test");
glutDisplayFuncUcall(disp, &displayIndex);
/* get timer started, its reset in the timer function itself */
glutTimerFuncUcall(timerSurroundInt, timer_func, 1, &surroundTimerState);
glutTimerFuncUcall(timerCenterInt, timer_func, 2, &centerTimerState);
/* menus for setting timing */
surroundMenuState.menu_id = glutCreateMenuUcall(MenuHandler, &surroundMenuState);
createMenuEntries(&surroundMenuState);
centerMenuState.menu_id = glutCreateMenuUcall(MenuHandler, &centerMenuState);
createMenuEntries(&centerMenuState);
glutCreateMenuUcall(MenuHandler, NULL); /* doesn't matter, no clickable entries in this menu */
glutAddSubMenu("Center", centerMenuState.menu_id);
glutAddSubMenu("Surround", surroundMenuState.menu_id);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();
return 0;
}
void disp(void* user_ptr)
{
const display_index_t* displayIndex;
int cidx, pcidx;
displayIndex = (display_index_t*)user_ptr;
cidx = displayIndex->surround_color_index;
glClearColor(color[cidx][0], color[cidx][1], color[cidx][2], 1);
glClear(GL_COLOR_BUFFER_BIT);
pcidx = displayIndex->center_color_index;
glPointSize(10.f);
glColor3f(color[pcidx][0], color[pcidx][1], color[pcidx][2]);
glBegin(GL_POINTS);
glVertex2i(0,0);
glEnd();
glutSwapBuffers();
}
void timer_func(int which, void* user_ptr)
{
const timer_state_t* timerState;
timerState = (timer_state_t*)user_ptr;
/* advance the color index and trigger a redisplay */
*timerState->color_index_ptr = (*timerState->color_index_ptr + 1) % (sizeof color / sizeof *color);
glutPostRedisplay();
/* (re)set the timer callback and ask glut to call it in x ms */
glutTimerFuncUcall(*timerState->timer_time_ptr, timer_func, which, user_ptr);
}

View File

@ -0,0 +1,333 @@
/*
* fg_callback_macros.h
*
* The freeglut library callback macro file.
*
* Copyright (C) 2016 Vincent Simonetti
* Creation date: Sat Jan 16 2016
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef FREEGLUT_CALLBACK_MACROS_H
#define FREEGLUT_CALLBACK_MACROS_H
/*
* ----------------------------------------------------------------------------------------------------------------------
* There are two sets of macros here. One is for executing window callbacks, the others are for setting window callbacks.
* ----------------------------------------------------------------------------------------------------------------------
*/
/*
* Compiler define: FG_COMPILER_SUPPORTS_VA_ARGS: if the compiler supports variadic macros
*/
/* What supports variadic macros based off Wikipedia article on it (GCC-like must support C99 or higher to use variadic macros) */
#if (((defined(__GNUC__) && (__GNUC__ >= 3)) || \
(defined(__clang__))) && \
(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))) || \
(defined(_MSC_VER) && (_MSC_VER >= 1400)) || \
(defined(__BORLANDC__) && (__BORLANDC__ >= 0x570)) || \
(defined(__SUNPRO_C) && (__SUNPRO_C >= 0x530))
#define FG_COMPILER_SUPPORTS_VA_ARGS 1
#else
#define FG_COMPILER_SUPPORTS_VA_ARGS 0
#endif
/*
* --------------------------
* Executing window callbacks
* --------------------------
*
* Info:
*
* This took a while to figure out, so be sure try to understand what is happening so that you can ensure that whatever you
* change won't break other areas.
*
* If you are just adding a new callback/changing it's argument count, just go to the bottom of the file.
*
* This whole file exists purely for the sake of preventing the need to implement additional parsing logic for each callback
* to pass user arguments. Of course, the necessity to support older compilers means that, as seen in the line above, there
* is still a requirement to add/modify code to handle callbacks. If freeglut ever requires newer compilers (at minimum, ones
* that support C99 or higher), code can very slowly be removed from this file. Even better would be if the C standard eventually
* supports something similar to what GCC has implemented or offers an alternative. Another option is if C++ would be "allowed" by
* project maintaners, as then templates can be used and function overloading. Ironically, the template would probably look worse
* then the GCC macro, so maybe it's good to stay as is.
*
* Onto the different "versions" of macros:
*
* The first is for any compiler that supports C99 by default. It requires each callback to have a specific argument count
* passthrough macro. The only reason there are specific count macros is so that (see paraghraph below) don't need have their own
* set of callback macros. Ideally, there would only be ZERO and ONE_OR_MORE. This works by having callback-specific macros call a
* specific handler macro to return user data (ZERO) or return one or more arguments along with userData (ONE_OR_MORE) where, with
* variadic macros, it just reuses the arguments.
*
* The last macro set is for the poor individual who has to use a compiler that doesn't support C99 by default, or may not support
* it at all. Stuff like MSVC6... It works by having a specific-count macro that "extracts" each argument to have them reused without
* the parathesis.
*
* There is a 3rd macro set that only worked on GCC/Clang, and thus was removed (last seen in revision e9676fc of the GIT mirror.
* Not sure at this time what the SVN number is.) as it's a non-standard functionality.
*/
/*
* EXPAND_WCB() is used as:
*
* EXPAND_WCB( cbname )(( arg_list, userData ))
*
* ... where {(arg_list)} is the parameter list and userData is user
* provided data.
*
* This will take the arg_list and extend it by one argument, adding
* the argument "userData" to the end of the list.
*
* In order for this to work, each callback must have a define that
* properly handles the arguments as needed by the callback.
* This callback is in the format of EXPAND_WCB_SUB_<cbname>.
* Helper functions exist for zero to five parameters: EXPAND_WCB_ZERO,
* EXPAND_WCB_ONE, EXPAND_WCB_TWO, EXPAND_WCB_THREE< EXPAND_WCB_FOUR,
* and EXPAND_WCB_FIVE. Each handle the callback argument counts.
*
* An example for the "Entry" callback, where "Entry" is the cbname:
* typedef void (* FGCBEntry )( int );
* typedef void (* FGCBEntryUC)( int, FGCBUserData );
* #define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args
*/
#if FG_COMPILER_SUPPORTS_VA_ARGS
#define EXPAND_WCB_UNPARAN(...) __VA_ARGS__
#define EXPAND_WCB_ONE_OR_MORE(args, userData) ( EXPAND_WCB_UNPARAN args, userData )
#define EXPAND_WCB_ONE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
#define EXPAND_WCB_TWO(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
#define EXPAND_WCB_THREE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
#define EXPAND_WCB_FOUR(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
#define EXPAND_WCB_FIVE(args, userData) EXPAND_WCB_ONE_OR_MORE( args, userData )
#else
#define EXPAND_WCB_EXTRACT_ONE_ARGS(arg1) arg1
#define EXPAND_WCB_EXTRACT_TWO_ARGS(arg1, arg2) arg1, arg2
#define EXPAND_WCB_EXTRACT_THREE_ARGS(arg1, arg2, arg3) arg1, arg2, arg3
#define EXPAND_WCB_EXTRACT_FOUR_ARGS(arg1, arg2, arg3, arg4) arg1, arg2, arg3, arg4
#define EXPAND_WCB_EXTRACT_FIVE_ARGS(arg1, arg2, arg3, arg4, arg5) arg1, arg2, arg3, arg4, arg5
#define EXPAND_WCB_ONE(args, userData) (EXPAND_WCB_EXTRACT_ONE_ARGS args, userData)
#define EXPAND_WCB_TWO(args, userData) (EXPAND_WCB_EXTRACT_TWO_ARGS args, userData)
#define EXPAND_WCB_THREE(args, userData) (EXPAND_WCB_EXTRACT_THREE_ARGS args, userData)
#define EXPAND_WCB_FOUR(args, userData) (EXPAND_WCB_EXTRACT_FOUR_ARGS args, userData)
#define EXPAND_WCB_FIVE(args, userData) (EXPAND_WCB_EXTRACT_FIVE_ARGS args, userData)
#endif
#define EXPAND_WCB_ZERO(args, userData) ( userData )
#define EXPAND_WCB(cbname) EXPAND_WCB_SUB_ ## cbname
/*
* Freeglut callbacks type definitions macros
*
* Every time a callback is updated in fg_internal.h is updated, this needs updated
* if argument counts change, new callbacks are added, or callbacks are removed.
*/
#define EXPAND_WCB_SUB_Display(args) EXPAND_WCB_ZERO args
#define EXPAND_WCB_SUB_Reshape(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_Position(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_Visibility(args) EXPAND_WCB_ONE args
#define EXPAND_WCB_SUB_Keyboard(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_KeyboardUp(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_Special(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_SpecialUp(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_Mouse(args) EXPAND_WCB_FOUR args
#define EXPAND_WCB_SUB_MouseWheel(args) EXPAND_WCB_FOUR args
#define EXPAND_WCB_SUB_Motion(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_Passive(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args
#define EXPAND_WCB_SUB_WindowStatus(args) EXPAND_WCB_ONE args
#define EXPAND_WCB_SUB_Joystick(args) EXPAND_WCB_FOUR args
#define EXPAND_WCB_SUB_OverlayDisplay(args) EXPAND_WCB_ZERO args
#define EXPAND_WCB_SUB_SpaceMotion(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_SpaceRotation(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_SpaceButton(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_Dials(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_ButtonBox(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_TabletMotion(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_TabletButton(args) EXPAND_WCB_FOUR args
#define EXPAND_WCB_SUB_Destroy(args) EXPAND_WCB_ZERO args
#define EXPAND_WCB_SUB_MultiEntry(args) EXPAND_WCB_TWO args
#define EXPAND_WCB_SUB_MultiButton(args) EXPAND_WCB_FIVE args
#define EXPAND_WCB_SUB_MultiMotion(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_MultiPassive(args) EXPAND_WCB_THREE args
#define EXPAND_WCB_SUB_InitContext(args) EXPAND_WCB_ZERO args
#define EXPAND_WCB_SUB_AppStatus(args) EXPAND_WCB_ONE args
/*
* ------------------------
* Setting window callbacks
* ------------------------
*
* These originally existed in fg_callbacks.c
*/
/*
* All of the window-specific callbacks setting methods can be generalized to this:
*/
#define SET_CURRENT_WINDOW_CALLBACK(a) \
do \
{ \
if( fgStructure.CurrentWindow == NULL ) \
return; \
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 fgh##a##FuncCallback( FGCBUserData userData ) \
{ \
FGCB##b callback = (FGCB##b)userData; \
callback(); \
}
#define IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,b) \
static void fgh##a##FuncCallback( int arg1val, FGCBUserData userData ) \
{ \
FGCB##b callback = (FGCB##b)userData; \
callback( arg1val ); \
}
#define IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \
static void fgh##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 fgh##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 fgh##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 fgh##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 with these:
*/
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b) \
void FGAPIENTRY glut##a##FuncUcall( FGCB##b##UC callback, FGCBUserData userData ) \
{ \
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"FuncUcall" ); \
SET_CURRENT_WINDOW_CALLBACK( b ); \
}
#define IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b) \
void FGAPIENTRY glut##a##Func( FGCB##b callback ) \
{ \
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" ); \
if( callback ) \
glut##a##FuncUcall( fgh##a##FuncCallback, (FGCBUserData)callback ); \
else \
glut##a##FuncUcall( NULL, NULL ); \
}
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT_UCALL(a,b) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
/*
* Combine _glut and _cb macros:
*/
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(a,b) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,a) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0_2NAME(a,b) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG0(a,b) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG1(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG1(a,a) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2_2NAME(a,b) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,b)
#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,a) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2_2NAME(a,b) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG2(a,b) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(a,arg1,arg2,arg3) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG3_USER(a,a,arg1,arg2,arg3) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,a) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,a)
#define IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(a,b) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG3(a,b) \
IMPLEMENT_CALLBACK_FUNC_2NAME_GLUT_BASE(a,b)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG4(a,a) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
#define IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG5(a) \
IMPLEMENT_CALLBACK_FUNC_CB_ARG5(a,a) \
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_2NAME_GLUT(a,a)
#endif /* FREEGLUT_CALLBACK_MACROS_H */
/*** END OF FILE ***/

View File

@ -30,23 +30,26 @@
/* -- INTERFACE FUNCTIONS -------------------------------------------------- */
/*
* Global callbacks.
*/
/* Sets the global idle callback */
void FGAPIENTRY glutIdleFunc( FGCBIdle callback )
void FGAPIENTRY glutIdleFuncUcall( FGCBIdleUC callback, FGCBUserData userData )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFunc" );
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIdleFuncUcall" );
fgState.IdleCallback = callback;
fgState.IdleCallbackData = userData;
}
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(Idle)
/* Creates a timer and sets its callback */
void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID )
void FGAPIENTRY glutTimerFuncUcall( unsigned int timeOut, FGCBTimerUC callback, int timerID, FGCBUserData userData )
{
SFG_Timer *timer, *node;
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" );
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFuncUcall" );
if( (timer = fgState.FreeTimers.Last) )
{
@ -60,6 +63,7 @@ void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int tim
}
timer->Callback = callback;
timer->CallbackData = userData;
timer->ID = timerID;
timer->TriggerTime = fgElapsedTime() + timeOut;
@ -73,6 +77,17 @@ void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int tim
fgListInsert( &fgState.Timers, &node->Node, &timer->Node );
}
IMPLEMENT_CALLBACK_FUNC_CB_ARG1(Timer, Timer)
void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" );
if( callback )
glutTimerFuncUcall( timeOut, fghTimerFuncCallback, timerID, (FGCBUserData)callback );
else
glutTimerFuncUcall( timeOut, NULL, timerID, NULL );
}
/* Deprecated version of glutMenuStatusFunc callback setting method */
void FGAPIENTRY glutMenuStateFunc( FGCBMenuState callback )
{
@ -81,102 +96,92 @@ void FGAPIENTRY glutMenuStateFunc( FGCBMenuState callback )
}
/* Sets the global menu status callback for the current window */
void FGAPIENTRY glutMenuStatusFunc( FGCBMenuStatus callback )
void FGAPIENTRY glutMenuStatusFuncUcall( FGCBMenuStatusUC callback, FGCBUserData userData )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFunc" );
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMenuStatusFuncUcall" );
fgState.MenuStatusCallback = callback;
fgState.MenuStatusCallbackData = userData;
}
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3(MenuStatus)
/*
* 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;
}
}
/*
* All of the window-specific callbacks setting methods can be generalized to this:
*/
#define SET_CALLBACK(a) \
do \
{ \
if( fgStructure.CurrentWindow == NULL ) \
return; \
SET_WCB( ( *( fgStructure.CurrentWindow ) ), a, callback ); \
} while( 0 )
/*
* 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 ) \
{ \
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glut"#a"Func" ); \
SET_CALLBACK( b ); \
}
#define IMPLEMENT_CALLBACK_FUNC(a) IMPLEMENT_CALLBACK_FUNC_2NAME(a,a)
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0_2NAME(MenuDestroy, Destroy)
/* 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)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(Position)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(Keyboard,unsigned char,int,int)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3_USER(KeyboardUp,unsigned char,int,int)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(Special)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(SpecialUp)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(Mouse)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(MouseWheel)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(Motion)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2_2NAME(PassiveMotion,Passive)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(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)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(Close,Destroy)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0_2NAME(WMClose,Destroy)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(OverlayDisplay)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG1(WindowStatus)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(ButtonBox)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(Dials)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(TabletMotion)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG4(TabletButton)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG2(MultiEntry)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG5(MultiButton)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(MultiMotion)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG3(MultiPassive)
IMPLEMENT_CURRENT_WINDOW_CALLBACK_FUNC_ARG0(InitContext)
IMPLEMENT_CURRENT_WINDOW_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 );
SET_CURRENT_WINDOW_CALLBACK( Display );
}
void fghDefaultReshape(int width, int height)
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG0(Display)
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;
SET_CALLBACK( Reshape );
userData = NULL;
}
SET_CURRENT_WINDOW_CALLBACK( Reshape );
}
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2(Reshape)
/*
* Sets the Visibility callback for the current window.
* NB: the Visibility func is deprecated in favor of the WindowStatus func,
@ -192,7 +197,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;
@ -200,7 +205,7 @@ static void fghVisibility( int status )
freeglut_return_if_fail( fgStructure.CurrentWindow );
/* Translate window status func states to visibility states */
if( ( GLUT_HIDDEN == status ) || ( GLUT_FULLY_COVERED == status ) )
if( ( status == GLUT_HIDDEN) || ( status == GLUT_FULLY_COVERED) )
vis_status = GLUT_NOT_VISIBLE;
else /* GLUT_FULLY_RETAINED, GLUT_PARTIALLY_RETAINED */
vis_status = GLUT_VISIBLE;
@ -208,23 +213,31 @@ 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" );
SET_CALLBACK( Visibility );
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutVisibilityFuncUcall" );
if ( !callback )
{
userData = NULL;
}
SET_CURRENT_WINDOW_CALLBACK( Visibility );
if( callback )
glutWindowStatusFunc( fghVisibility );
glutWindowStatusFuncUcall( fghVisibility, NULL );
else
glutWindowStatusFunc( NULL );
glutWindowStatusFuncUcall( NULL, NULL );
}
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG1(Visibility)
/*
* 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 ( (
@ -244,7 +257,7 @@ void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
) )
--fgState.NumActiveJoysticks;
SET_CALLBACK( Joystick );
SET_CURRENT_WINDOW_CALLBACK( Joystick );
fgStructure.CurrentWindow->State.JoystickPollRate = pollInterval;
/* set last poll time such that joystick will be polled asap */
@ -255,39 +268,58 @@ void FGAPIENTRY glutJoystickFunc( FGCBJoystick callback, int pollInterval )
fgStructure.CurrentWindow->State.JoystickLastPoll -= pollInterval;
}
static void fghJoystickFuncCallback( 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( fghJoystickFuncCallback, 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 );
SET_CURRENT_WINDOW_CALLBACK( SpaceMotion );
}
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(SpaceballMotion, SpaceMotion)
/*
* 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 );
SET_CURRENT_WINDOW_CALLBACK( SpaceRotation );
}
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG3_2NAME(SpaceballRotate, SpaceRotation)
/*
* 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 );
SET_CURRENT_WINDOW_CALLBACK( SpaceButton );
}
IMPLEMENT_GLUT_CALLBACK_FUNC_ARG2_2NAME(SpaceballButton, SpaceButton)
/*** END OF FILE ***/

View File

@ -210,6 +210,46 @@ static GLUTproc fghGetGLUTProcAddress( const char* procName )
CHECK_NAME(glutSetVertexAttribCoord3);
CHECK_NAME(glutSetVertexAttribNormal);
CHECK_NAME(glutSetVertexAttribTexCoord2);
/* freeglut user callback functions */
CHECK_NAME(glutCreateMenuUcall);
CHECK_NAME(glutTimerFuncUcall);
CHECK_NAME(glutIdleFuncUcall);
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;

View File

@ -70,9 +70,11 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */
{ NULL, NULL }, /* Timers */
{ NULL, NULL }, /* FreeTimers */
NULL, /* IdleCallback */
NULL, /* IdleCallbackData */
0, /* ActiveMenus */
NULL, /* MenuStateCallback */
NULL, /* MenuStatusCallback */
NULL, /* MenuStatusCallbackData */
FREEGLUT_MENU_FONT,
{ -1, -1, GL_TRUE }, /* GameModeSize */
-1, /* GameModeDepth */
@ -95,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 */
};
@ -298,9 +302,11 @@ void fgDeinitialize( void )
fgListInit( &fgState.Timers );
fgListInit( &fgState.FreeTimers );
fgState.IdleCallback = NULL;
fgState.IdleCallback = ( FGCBIdleUC )NULL;
fgState.IdleCallbackData = NULL;
fgState.MenuStateCallback = ( FGCBMenuState )NULL;
fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL;
fgState.MenuStatusCallback = ( FGCBMenuStatusUC )NULL;
fgState.MenuStatusCallbackData = NULL;
fgState.SwapCount = 0;
fgState.SwapTime = 0;
@ -668,19 +674,57 @@ 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 fghInitErrorFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
{
FGError callback = (FGError)userData;
callback( fmt, ap );
}
void FGAPIENTRY glutInitErrorFunc( FGError callback )
{
if (callback)
{
glutInitErrorFuncUcall( fghInitErrorFuncCallback, (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 fghInitWarningFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
{
FGWarning callback = (FGWarning)userData;
callback( fmt, ap );
}
void FGAPIENTRY glutInitWarningFunc( FGWarning callback )
{
if (callback)
{
glutInitWarningFuncUcall( fghInitWarningFuncCallback, (FGCBUserData)callback );
}
else
{
glutInitWarningFuncUcall( NULL, NULL );
}
}
/*** END OF FILE ***/

View File

@ -33,12 +33,14 @@
#endif
#include "fg_version.h"
#include "fg_callback_macros.h"
/* Freeglut is intended to function under all Unix/X11 and Win32 platforms. */
/* XXX: Don't all MS-Windows compilers (except Cygwin) have _WIN32 defined?
* XXX: If so, remove the first set of defined()'s below.
*/
#if !defined(TARGET_HOST_POSIX_X11) && !defined(TARGET_HOST_MS_WINDOWS) && !defined(TARGET_HOST_MAC_OSX) && !defined(TARGET_HOST_SOLARIS)
#if !defined(TARGET_HOST_POSIX_X11) && !defined(TARGET_HOST_MS_WINDOWS) && !defined(TARGET_HOST_MAC_OSX) && !defined(TARGET_HOST_SOLARIS) && \
!defined(TARGET_HOST_ANDROID) && !defined(TARGET_HOST_BLACKBERRY) && !defined(TARGET_HOST_POSIX_WAYLAND)
#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__MINGW32__) \
|| defined(_WIN32) || defined(_WIN32_WCE) \
|| ( defined(__CYGWIN__) && defined(X_DISPLAY_MISSING) )
@ -215,52 +217,97 @@
/* -- GLOBAL TYPE DEFINITIONS ---------------------------------------------- */
/* Freeglut callbacks type definitions */
/*
* Freeglut callbacks type definitions
*
* If anything here is modified or added, update fg_callback_macros.h functions.
*
* This is not ideal, but freeglut needs to either define minimal compiler specs,
* or update header every time this is changed or updated.
*/
typedef void* FGCBUserData;
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)();
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 (* FGCBMenuStatusUC )( int, int, int, FGCBUserData );
/* The callback used when creating/using menus */
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 (* 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 */
@ -327,11 +374,13 @@ struct tagSFG_State
SFG_List Timers; /* The freeglut timer hooks */
SFG_List FreeTimers; /* The unused timer hooks */
FGCBIdle IdleCallback; /* The global idle callback */
FGCBIdleUC IdleCallback; /* The global idle callback */
FGCBUserData IdleCallbackData; /* The global idle callback data */
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 */
@ -361,8 +410,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 */
@ -384,7 +435,8 @@ struct tagSFG_Timer
{
SFG_Node Node;
int ID; /* The timer ID integer */
FGCBTimer Callback; /* The timer callback */
FGCBTimerUC Callback; /* The timer callback */
FGCBUserData CallbackData; /* The timer callback user data */
fg_time_t TriggerTime; /* The timer trigger time */
};
@ -511,11 +563,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-
@ -524,12 +577,25 @@ typedef void (*SFG_Proc)();
* The {if( FETCH_WCB( ... ) != func )} test is to do type-checking
* and for no other reason. Since it's hidden in the macro, the
* ugliness is felt to be rather benign.
*
* If the function-pointer is the same, the data will be the only
* value updated. If the function-pointer changes, the data will
* be changed as well, preventing stail data from being passed in.
* Just updating the data does nothing unless a function-pointer
* exists, as the data is otherwise already allocated.
*/
#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)); \
} \
else if( FETCH_USER_DATA_WCB( window, cbname ) != udata ) \
{ \
(((window).CallbackDatas[WCB_ ## cbname]) = (udata)); \
} \
} while( 0 )
/*
@ -546,6 +612,39 @@ do \
#define FETCH_WCB(window,cbname) \
((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.
*
* 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( cbname )(( arg_list, userData ))
*
* ... where {(arg_list)} is the parameter list and userData is user
* provided data.
*
* This will take the arg_list and extend it by one argument, adding
* the argument "userData" to the end of the list.
*
* All of this is defined in fg_callback_macros.h
*
* See that header for more info.
*
* ------------------------------------------------------------------
*/
/*
* INVOKE_WCB() is used as:
*
@ -557,36 +656,26 @@ do \
*
* The callback is invoked as:
*
* callback( arg_list );
* callback( arg_list, userData );
*
* ...so the parentheses are REQUIRED in the {arg_list}.
* ...where userData is added to the arg_list, but the parentheses
* are REQUIRED in the {arg_list}.
*
* NOTE that it does a sanity-check and also sets the
* current window.
*
*/
#if TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: also WinCE? */
#define INVOKE_WCB(window,cbname,arg_list) \
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( cbname )(( arg_list, userData )); \
} \
} while( 0 )
#else
#define INVOKE_WCB(window,cbname,arg_list) \
do \
{ \
if( FETCH_WCB( window, cbname ) ) \
{ \
fgSetWindow( &window ); \
((FGCB ## cbname)FETCH_WCB( window, cbname )) arg_list; \
} \
} while( 0 )
#endif
/*
* The window callbacks the user can supply us with. Should be kept portable.
@ -662,8 +751,10 @@ struct tagSFG_Menu
void *UserData; /* User data passed back at callback */
int ID; /* The global menu ID */
SFG_List Entries; /* The menu entries list */
FGCBMenu Callback; /* The menu callback */
FGCBDestroy Destroy; /* Destruction callback */
FGCBMenuUC Callback; /* The menu callback */
FGCBUserData CallbackData; /* The menu callback user data */
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 */
@ -701,6 +792,7 @@ 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 */
@ -970,7 +1062,7 @@ void fgCloseWindows ();
void fgDestroyWindow( SFG_Window* window );
/* Menu creation and destruction. Defined in fg_structure.c */
SFG_Menu* fgCreateMenu( FGCBMenu menuCallback );
SFG_Menu* fgCreateMenu( FGCBMenuUC menuCallback, FGCBUserData userData );
void fgDestroyMenu( SFG_Menu* menu );
/* Joystick device management functions, defined in fg_joystick.c */

View File

@ -233,7 +233,7 @@ static void fghCheckTimers( void )
fgListRemove( &fgState.Timers, &timer->Node );
fgListAppend( &fgState.FreeTimers, &timer->Node );
timer->Callback( timer->ID );
timer->Callback( timer->ID, timer->CallbackData );
}
}
@ -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 );
@ -509,7 +509,7 @@ void FGAPIENTRY glutMainLoop( void )
fgStructure.CurrentWindow->IsMenu )
/* fail safe */
fgSetWindow( window );
fgState.IdleCallback( );
fgState.IdleCallback( fgState.IdleCallbackData );
}
else
fghSleepForEvents( );

View 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 );
@ -609,7 +609,7 @@ GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed,
/* Deactivate menu and then call callback (we don't want menu to stay in view while callback is executing, and user should be able to change menus in callback) */
fgDeactivateMenu( parent_window );
active_menu->Callback( active_entry->ID );
active_menu->Callback( active_entry->ID, active_menu->CallbackData );
/* Restore the current window and menu */
fgSetWindow( save_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);
}
}
}
@ -780,14 +780,33 @@ void fghCalculateMenuBoxSize( void )
/*
* Creates a new menu object, adding it to the freeglut structure
*/
int FGAPIENTRY glutCreateMenu( FGCBMenu callback )
int FGAPIENTRY glutCreateMenuUcall( FGCBMenuUC callback, FGCBUserData userData )
{
/* The menu object creation code resides in fg_structure.c */
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" );
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenuUcall" );
if (fgState.ActiveMenus)
{
fgError( "Menu manipulation not allowed while menus in use." );
}
return fgCreateMenu( callback )->ID;
return fgCreateMenu( callback, userData )->ID;
}
/* Standard glutCreateMenu */
static void fghCreateMenuCallback( int menu, FGCBUserData userData )
{
FGCBMenu callback = (FGCBMenu)userData;
callback( menu );
}
int FGAPIENTRY glutCreateMenu( FGCBMenu callback )
{
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" );
if (!callback)
{
return glutCreateMenuUcall( NULL, NULL );
}
return glutCreateMenuUcall( fghCreateMenuCallback, (FGCBUserData)callback );
}
/*

View 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;
@ -116,7 +119,7 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title,
/*
* This private function creates a menu and adds it to the menus list
*/
SFG_Menu* fgCreateMenu( FGCBMenu menuCallback )
SFG_Menu* fgCreateMenu( FGCBMenuUC menuCallback, FGCBUserData userData )
{
SFG_Window *current_window = fgStructure.CurrentWindow;
@ -136,6 +139,7 @@ SFG_Menu* fgCreateMenu( FGCBMenu menuCallback )
/* Initialize the object properties: */
menu->ID = ++fgStructure.MenuID;
menu->Callback = menuCallback;
menu->CallbackData = userData;
menu->ActiveEntry = NULL;
menu->Font = fgState.MenuFont;
@ -173,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 );
}
}
@ -302,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;
}

View File

@ -106,3 +106,8 @@ int FGAPIENTRY __glutCreateMenuWithExit( void(* callback)( int ), void (__cdecl
return glutCreateMenu( callback );
}
int FGAPIENTRY __glutCreateMenuUcallWithExit(void(*callback)(int, void*), void(__cdecl *exit_function)(int), void* user_data)
{
__glutExitFunc = exit_function;
return glutCreateMenuUcall(callback, user_data);
}

View File

@ -71,8 +71,10 @@ void fghKeyboardInterpretKeysym( SFG_Window* window,
xkb_keysym_t sym,
uint32_t state )
{
FGCBKeyboard keyboard_cb;
FGCBSpecial special_cb;
FGCBKeyboardUC keyboard_cb;
FGCBSpecialUC special_cb;
FGCBUserData keyboard_ud;
FGCBUserData special_ud;
char string[16];
int special = -1;
@ -81,13 +83,17 @@ void fghKeyboardInterpretKeysym( SFG_Window* window,
* others, which need to be translated to GLUT_KEY_Xs... */
if( state )
{
keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special ));
keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, Keyboard ));
special_cb = (FGCBSpecialUC) ( FETCH_WCB( *window, Special ));
keyboard_ud = FETCH_USER_DATA_WCB( *window, Keyboard );
special_ud = FETCH_USER_DATA_WCB( *window, Special );
}
else
{
keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp ));
keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, KeyboardUp ));
special_cb = (FGCBSpecialUC) ( FETCH_WCB( *window, SpecialUp ));
keyboard_ud = FETCH_USER_DATA_WCB( *window, KeyboardUp );
special_ud = FETCH_USER_DATA_WCB( *window, SpecialUp );
}
switch( sym )
@ -127,13 +133,13 @@ void fghKeyboardInterpretKeysym( SFG_Window* window,
if( special_cb && (special != -1) )
{
fgSetWindow( window );
special_cb( special, window->State.MouseX, window->State.MouseY );
special_cb( special, window->State.MouseX, window->State.MouseY, special_ud );
}
else if( keyboard_cb && (special == -1) )
{
fgSetWindow( window );
xkb_keysym_to_utf8( sym, string, sizeof( string ) );
keyboard_cb( string[0], window->State.MouseX, window->State.MouseY );
keyboard_cb( string[0], window->State.MouseX, window->State.MouseY, keyboard_ud );
}
}

View File

@ -890,8 +890,10 @@ void fgPlatformProcessSingleEvent ( void )
case KeyRelease:
case KeyPress:
{
FGCBKeyboard keyboard_cb;
FGCBSpecial special_cb;
FGCBKeyboardUC keyboard_cb;
FGCBSpecialUC special_cb;
FGCBUserData keyboard_ud;
FGCBUserData special_ud;
GETWINDOW( xkey );
GETMOUSE( xkey );
@ -932,13 +934,17 @@ void fgPlatformProcessSingleEvent ( void )
if( event.type == KeyPress )
{
keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special ));
keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, Keyboard ));
special_cb = (FGCBSpecialUC) ( FETCH_WCB( *window, Special ));
keyboard_ud = FETCH_USER_DATA_WCB( *window, Keyboard );
special_ud = FETCH_USER_DATA_WCB( *window, Special );
}
else
{
keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp ));
keyboard_cb = (FGCBKeyboardUC)( FETCH_WCB( *window, KeyboardUp ));
special_cb = (FGCBSpecialUC) ( FETCH_WCB( *window, SpecialUp ));
keyboard_ud = FETCH_USER_DATA_WCB( *window, KeyboardUp );
special_ud = FETCH_USER_DATA_WCB( *window, SpecialUp );
}
/* Is there a keyboard/special callback hooked for this window? */
@ -963,7 +969,8 @@ void fgPlatformProcessSingleEvent ( void )
fgSetWindow( window );
fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state );
keyboard_cb( asciiCode[ 0 ],
event.xkey.x, event.xkey.y
event.xkey.x, event.xkey.y,
keyboard_ud
);
fgState.Modifiers = INVALID_MODIFIERS;
}
@ -1031,7 +1038,7 @@ void fgPlatformProcessSingleEvent ( void )
{
fgSetWindow( window );
fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state );
special_cb( special, event.xkey.x, event.xkey.y );
special_cb( special, event.xkey.x, event.xkey.y, special_ud );
fgState.Modifiers = INVALID_MODIFIERS;
}
}

View File

@ -327,6 +327,40 @@ area--which is <u>NOT</u> the (x,y) position of the window you specified
when you created it.</ul>
</p>
<h3>3.2.2 User-data callbacks</h3>
<p>
GLUT was created as a tool to help teach OpenGL programming. To simplify
development, callbacks were used for handling display, input, and other
events. But at the time it was developed, the purpose, or for some other
unknown reason, the callbacks lacked any user-provided data argument.
This has caused considerable difficulties for any significantly advanced
usage of GLUT, and now <i>freeglut</i>. This has prevented any attempt to
wrap <i>freeglut</i> in a C++ wrapper, make per-window, per-callback data
structure, and potentially made it undesirable to modern C developers who
tend to be well versed in "don't use globals". To combat these
complaints and <i>issues</i>, many callbacks (with some deprecated
callbacks excluded) support user-data callbacks provided through additional
functions provided in <i>freeglut</i>. All callbacks that support user-data
callbacks are marked as such.
</p>
<p>
The general rule to follow is to take the <i>freeglut</i> callback function
and append "Ucall" to the end of the function, add an additional <tt>void*</tt>
argument to the end of the argument list of both the <i>freeglut</i> function
and the callback function. This will pass the user-data to the callback when it's
invoked.
</p>
<p><b>Examples</b></p>
<p><tt>void glutPositionFunc ( void (* func)( int x, int y ) );</tt><br>
<tt>void glutPositionFuncUcall ( void (* func)( int x, int y, void* user_data ), void* user_data );</tt></p>
<p><tt>void glutKeyboardUpFunc ( void (* func)( unsigned char key, int x, int y ) );</tt><br>
<tt>void glutKeyboardUpFuncUcall ( void (* func)( unsigned char key, int x, int y, void* user_data ), void* user_data );</tt></p>
<h2>3.3 Terminology</h2>
<h2>3.4 Differences from GLUT 3.7</h2>
@ -524,6 +558,8 @@ from the library can be handled by the user.
<p><tt>void glutInitErrorFunc&nbsp;&nbsp;&nbsp;( void (* callback)( const char *fmt, va_list ap) );</tt><br/>
<tt>void glutInitWarningFunc&nbsp;( void (* callback)( const char *fmt, va_list ap) );</tt> </p>
<p>These functions have user-data callback functions.</p>
<p><b>Description</b></p>
<p>
The users callback is passed a format string and a variable argument
@ -943,6 +979,8 @@ The <tt>glutShowOverlay</tt> and <tt>glutHideOverlay</tt> functions are not impl
<h2>10.1 glutCreateMenu</h2>
<p>Has user-data callback function.</p>
<h2>10.2 glutDestroyMenu</h2>
<h2>10.3 glutGetMenu, glutSetMenu</h2>
@ -985,10 +1023,14 @@ stroke font, or an unknown font.
<h2>10.11 glutMenuDestroyFunc</h2>
<p>Has user-data callback function.</p>
<h1>11. <a name="GlobalCallback"></a>Global Callback Registration Functions</h1>
<h2>11.1 glutTimerFunc</h2>
<p>Has user-data callback function.</p>
<h2>11.2 glutIdleFunc</h2>
<p>
@ -998,11 +1040,11 @@ freeglut</i> calls the idle callback when there are no inputs from the user.
<p><b>Usage</b></p>
<p><tt>void glutIdleFunc ( void (*func)
( void ) );</tt> </p>
<p><tt>void glutIdleFunc ( void (*func ) ( void ) );</tt> </p>
<p><tt>func</tt>The new
global idle callback function </p>
<p><tt>func</tt> The new global idle callback function</p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
@ -1042,16 +1084,24 @@ the idle callback. </p>
<h2>11.3 glutMenuStatusFunc</h2>
<p>Has user-data callback function.</p>
<h2>11.4 glutMenuStateFunc</h2>
<h1>12. <a name="WindowCallback"></a>Window-Specific Callback Registration Functions</h1>
<h2>12.1 glutDisplayFunc</h2>
<p>Has user-data callback function.</p>
<h2>12.2 glutOverlayDisplayFunc</h2>
<p>Has user-data callback function.</p>
<h2>12.3 glutReshapeFunc</h2>
<p>Has user-data callback function.</p>
<h2>12.4 glutPositionFunc</h2>
<p>
@ -1065,6 +1115,8 @@ repositioned/moved programatically or by the user.
<p><tt>void glutPositionFunc ( void
(* func)( int x, int y) );</tt></p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>When <i>freeglut</i> calls this callback, it provides the new
@ -1094,6 +1146,8 @@ about to be destroyed.
<p><tt>func</tt> The window's new closure callback function <br/>
</p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>
@ -1121,6 +1175,8 @@ alias to <tt>glutCloseFunc</tt>.
<h2>12.6 glutKeyboardFunc</h2>
<p>Has user-data callback function.</p>
<h2>12.7 glutSpecialFunc</h2>
<p>
@ -1145,6 +1201,8 @@ to the window at the time the key is pressed <br/>
</tt>The y-coordinate of the mouse relative
to the window at the time the key is pressed </p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>
@ -1200,6 +1258,8 @@ to the window at the time the key is released <br/>
</tt>The y-coordinate of the mouse relative
to the window at the time the key is released </p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>
@ -1252,6 +1312,8 @@ to the window at the time the key is released <br/>
</tt>The y-coordinate of the mouse relative
to the window at the time the key is released </p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>
@ -1289,8 +1351,12 @@ have them fixed.
<h2>12.10 glutMotionFunc, glutPassiveMotionFunc</h2>
<p>Both functions have user-data callback functions.</p>
<h2>12.11 glutMouseFunc</h2>
<p>Has user-data callback function.</p>
<h2>12.12 glutMouseWheelFunc</h2>
<p>
@ -1304,6 +1370,8 @@ spins the mouse wheel.
<p><tt>void glutMouseWheelFunc ( void( *callback )( int wheel, int
direction, int x, int y ));</tt></p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>If the mouse wheel is spun over your (sub)window, <i>freeglut</i>
@ -1320,8 +1388,12 @@ as mouse buttons.
<h2>12.13 glutEntryFunc</h2>
<p>Has user-data callback function.</p>
<h2>12.14 glutJoystickFunc</h2>
<p>Has user-data callback function.</p>
<h2>12.15 glutSpaceballMotionFunc</h2>
<p>
@ -1337,6 +1409,8 @@ provided so that GLUT-based programs can compile and link against
<p><tt>void glutSpaceballMotionFunc ( void (* callback)( int x, int y, int z ) );</tt></p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>The <i>x</i>, <i>y</i>, and <i>z</i> arguments indicate the amount of translation in integer along x, y, and z axis respectively.</p>
@ -1357,6 +1431,8 @@ provided so that GLUT-based programs can compile and link against
<p><tt>void glutSpaceballRotateFunc ( void (* callback)( int rx, int ry, int rz ) );</tt></p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>The <i>rx</i>, <i>ry</i>, and <i>rz</i> arguments indicate the amount of rotation in integer with respect to x, y, and z axis respectively.</p>
@ -1379,6 +1455,8 @@ The <tt>glutSpaceballButtonFunc</tt> function sets the window's Spaceball button
<p><tt>void glutSpaceballButtonFunc ( void
(* callback)( int button, int updown )</tt><tt> );</tt></p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>The <i>button</i> argument may take one of the following defined
@ -1418,6 +1496,8 @@ The <tt>glutDialsFunc</tt> function sets the global dials&buttons box callback.
<tt>void glutButtonBoxFunc ( void (* callback)( int button, int updown ) );</tt>
</p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>
@ -1442,6 +1522,8 @@ The <tt>glutDialsFunc</tt> function sets the global dials&buttons box callback.
<p><tt>void glutDialsFunc ( void (* callback)(
int dial, int value )</tt><tt> );</tt></p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>
@ -1469,6 +1551,8 @@ that a call to the function will not produce an error..
<tt>void glutTabletMotionFunc ( void (* callback)( int x, int y ) );</tt>
</p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>The <tt>glutTabletMotionFunc</tt> function
@ -1491,6 +1575,8 @@ that a call to the function will not produce an error..
<p><tt>void glutTabletButtonFunc ( void
(* callback)( int button, int updown, int x, int y )</tt><tt> );</tt></p>
<p>Has user-data callback function.</p>
<p><b>Description</b></p>
<p>
@ -1517,6 +1603,8 @@ these callbacks when the visibility status of a window changes.
<br><tt>void glutWindowStatusFunc ( void( *callback )( int state ));</tt>
</p>
<p>Both functions have user-data callback functions.</p>
<p><b>Description</b></p>
<p>
@ -2701,6 +2789,8 @@ Currently, under windows, the first (oldest) touch point also controls
the mouse cursor, which triggers the non-multi callbacks as
usual.<br />
All these functions have user-data callback functions.
<br />
Limitation: currently on the cursor id is provided. It may be
@ -2729,9 +2819,11 @@ whether/how to implement it.</p>
<ul>
<li><code>glutInitContextFunc &larr; void</code> : called when the context
is initialized or re-initialized (e.g. after a pause)</li>
is initialized or re-initialized (e.g. after a pause). Has user-data callback
function.</li>
<li><code>glutAppStatusFunc &larr; event</code> : called when the
application's status changes, with event identifying the state entered.
application's status changes, with event identifying the state entered. Has
user-data callback function.
Possible states:
<ul>
<li>application goes on a pause (or a stop) &rarr; GLUT_APPSTATUS_PAUSE</li>