X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ffg_callback_macros.h;h=2aa6ccd97e22767ef45a373bf573072d7506db77;hb=af47c3f93c7834b4006c49ec9df6a6ffdd3025de;hp=2406243b63701ea24f7617407d187356fd650ba1;hpb=580b9f6bd513a4dab7527538c8e7aeca2daeaed6;p=freeglut diff --git a/src/fg_callback_macros.h b/src/fg_callback_macros.h index 2406243..2aa6ccd 100644 --- a/src/fg_callback_macros.h +++ b/src/fg_callback_macros.h @@ -27,17 +27,44 @@ #ifndef FREEGLUT_CALLBACK_MACROS_H #define FREEGLUT_CALLBACK_MACROS_H -#ifndef FREEGLUT_INTERNAL_H -#error "fg_internal.h needs to be included before this header" -#endif +/* + * ---------------------------------------------------------------------------------------------------------------------- + * There are two sets of macros here. One is for executing window callbacks, the others are for setting window callbacks. + * ---------------------------------------------------------------------------------------------------------------------- + */ /* * Compiler defines: - * FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK: if the compiler supports GCC's varadic macro implementation (AKA, ##__VA_ARGS__) - * FG_COMPILER_SUPPORTS_VA_ARGS: if the compiler supports varadic macros + * FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK: if the compiler supports GCC's variadic macro implementation (AKA, ##__VA_ARGS__) + * 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 + +/* If __VA_ARGS__ is supported, it needs to be GCC(-like) or Clang (since Clang mimics GCC) */ +#if FG_COMPILER_SUPPORTS_VA_ARGS && \ + (defined(__GNUC__)) || \ + (defined(__clang__)) +#define FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK 1 +#else +#define FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK 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 @@ -58,20 +85,20 @@ * There is one for GCC/Clang(/and supposedly the Intel compiler) which supports the non-standard ##__VA_ARGS__ token. The code may * look ugly, but the result is, if this was standard, no one would ever need to open this file unless they were curious (or needed * more then 5 arguments for a callback, but that's trivial to add). It works by adding many fake macros to a "picker" macro - * (PP_HAS_ARGS_IMPL2) which then indictaes which macro counter to use. As we can already use varadic macros (the VA in __VA_ARGS__), + * (PP_HAS_ARGS_IMPL2) which then indictaes which macro counter to use. As we can already use variadic macros (the VA in __VA_ARGS__), * this just becomes a "reuse the arguments*. * * The next is for any non-GCC/Clang/etc. compiler *cough* MSVC/compiler you probably shouldn't be using *cough* 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 varadic macros, it just reuses the arguments. + * return one or more arguments along with userData (ONE_OR_MORE) where, with variadic macros, it just reuses the arguments. * * The last 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. * - * A note on parathesis, as earlier mentioned, if the GCC varadic macro element was standard, then instead of needing: + * A note on parathesis, as earlier mentioned, if the GCC variadic macro element was standard, then instead of needing: * * func EXPAND_WCB(Mouse)(( (GLUT_LEFT_BUTTON, GLUT_DOWN, 10, 30), userData)); * @@ -84,7 +111,7 @@ * implicitly passes "userData" and only works on GCC vardiac macro supporting compilers. */ -#ifdef FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK +#if FG_COMPILER_SUPPORTS_GCC_VA_ARGS_HACK /* * EXPAND_WCB() is used as: @@ -108,19 +135,19 @@ * should not require any modification unless additional arguments are to * be supported. * - * Supports callbacks up to 5 args (follow the pattern of PP_HAS_ARGS_IMPL2 - * and PP_HAS_ARGS_SOURCE to add more) + * Supports callbacks up to 5 args (follow the pattern of + * EXPAND_WCB_PP_HAS_ARGS_IMPL2 and EXPAND_WCB_PP_HAS_ARGS_SOURCE to add more) * * Edit with care. */ #define EXPAND_WCB_UNPARAN(...) __VA_ARGS__ -#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 EXPAND_WCB_PP_HAS_ARGS_IMPL2(_0, _1, _2, _3, _4, _5, N, ...) N +#define EXPAND_WCB_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_PP_HAS_ARGS_IMPL(...) EXPAND_WCB_PP_HAS_ARGS_IMPL2( __VA_ARGS__ ) +#define EXPAND_WCB_PP_HAS_ARGS(...) EXPAND_WCB_PP_HAS_ARGS_IMPL( NOT_EXIST, ##__VA_ARGS__, EXPAND_WCB_PP_HAS_ARGS_SOURCE() ) #define EXPAND_WCB_ZERO(args, userData) ( userData ) #define EXPAND_WCB_ONE_OR_MORE(args, userData) ( EXPAND_WCB_UNPARAN args, userData ) @@ -128,7 +155,7 @@ #define EXPAND_WCB_DISAMBIGUATE2(has_args, args, userData) EXPAND_WCB_ ## has_args ( args, userData ) #define EXPAND_WCB_DISAMBIGUATE(has_args, args, userData) EXPAND_WCB_DISAMBIGUATE2( has_args, args, userData ) -#define EXPAND_WCB_UNWRAP_ARGS2(args, userData) EXPAND_WCB_DISAMBIGUATE( PP_HAS_ARGS args, args, userData ) +#define EXPAND_WCB_UNWRAP_ARGS2(args, userData) EXPAND_WCB_DISAMBIGUATE( EXPAND_WCB_PP_HAS_ARGS args, args, userData ) #define EXPAND_WCB_UNWRAP_ARGS(args) EXPAND_WCB_UNWRAP_ARGS2 args #define EXPAND_WCB(cbname) EXPAND_WCB_UNWRAP_ARGS @@ -159,7 +186,7 @@ * #define EXPAND_WCB_SUB_Entry(args) EXPAND_WCB_ONE args */ -#ifdef FG_COMPILER_SUPPORTS_VA_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 ) @@ -172,17 +199,17 @@ #else -#define EXTRACT_ONE_ARGS(arg1) arg1 -#define EXTRACT_TWO_ARGS(arg1, arg2) arg1, arg2 -#define EXTRACT_THREE_ARGS(arg1, arg2, arg3) arg1, arg2, arg3 -#define EXTRACT_FOUR_ARGS(arg1, arg2, arg3, arg4) arg1, arg2, arg3, arg4 -#define EXTRACT_FIVE_ARGS(arg1, arg2, arg3, arg4, arg5) arg1, arg2, arg3, arg4, arg5 +#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) (EXTRACT_ONE_ARGS args, userData) -#define EXPAND_WCB_TWO(args, userData) (EXTRACT_TWO_ARGS args, userData) -#define EXPAND_WCB_THREE(args, userData) (EXTRACT_THREE_ARGS args, userData) -#define EXPAND_WCB_FOUR(args, userData) (EXTRACT_FOUR_ARGS args, userData) -#define EXPAND_WCB_FIVE(args, userData) (EXTRACT_FIVE_ARGS args, userData) +#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 @@ -230,6 +257,156 @@ #endif +/* + * ------------------------ + * 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 ***/