diff --git a/internal/c/parts/core/build.mk b/internal/c/parts/core/build.mk index adbb6ffd9..6f04bbeef 100644 --- a/internal/c/parts/core/build.mk +++ b/internal/c/parts/core/build.mk @@ -27,7 +27,7 @@ $(PATH_INTERNAL_C)/parts/core/glew/%.o: $(PATH_INTERNAL_C)/parts/core/glew/%.c $(CC) -O1 $(CFLAGS) $(FREEGLUT_INCLUDE) -DGLEW_STATIC -Wall $< -c -o $@ $(PATH_INTERNAL_C)/parts/core/freeglut/%.o: $(PATH_INTERNAL_C)/parts/core/freeglut/%.c - $(CC) -O3 $(CFLAGS) $(FREEGLUT_INCLUDE) -DFREEGLUT_STATIC -Wall $< -c -o $@ + $(CC) -O3 $(CFLAGS) $(FREEGLUT_INCLUDE) -DFREEGLUT_STATIC -DHAVE_UNISTD_H -DHAVE_FCNTL_H -Wall $< -c -o $@ $(FREEGLUT_LIB): $(FREEGLUT_OBJS) $(AR) rcs $@ $(FREEGLUT_OBJS) diff --git a/internal/c/parts/core/freeglut/freeglut_cursor.c b/internal/c/parts/core/freeglut/freeglut_cursor.c index 4f1fd375b..e5527d7ce 100644 --- a/internal/c/parts/core/freeglut/freeglut_cursor.c +++ b/internal/c/parts/core/freeglut/freeglut_cursor.c @@ -159,6 +159,22 @@ static void fghWarpPointer ( int x, int y ) /* Make the warp visible immediately. */ XFlush( fgDisplay.Display ); } + +void fghGetCursorPos(SFG_XYUse *mouse_pos) +{ + /* Get current pointer location in screen coordinates + */ + Window junk_window; + unsigned int junk_mask; + int junk_pos; + + XQueryPointer(fgDisplay.Display, fgDisplay.RootWindow, + &junk_window, &junk_window, + &mouse_pos->X, &mouse_pos->Y, + &junk_pos, &junk_pos, &junk_mask); + + mouse_pos->Use = GL_TRUE; +} #endif @@ -205,7 +221,7 @@ static void fghSetCursor ( SFG_Window *window, int cursorID ) { MAP_CURSOR( GLUT_CURSOR_RIGHT_ARROW, IDC_ARROW ); MAP_CURSOR( GLUT_CURSOR_LEFT_ARROW, IDC_ARROW ); - MAP_CURSOR( GLUT_CURSOR_INFO, IDC_HAND ); + MAP_CURSOR( GLUT_CURSOR_INFO, IDC_HAND ); // QB64-PE: GLUT_CURSOR_INFO -> IDC_HAND per FreeGLUT 3.4.0 MAP_CURSOR( GLUT_CURSOR_DESTROY, IDC_CROSS ); MAP_CURSOR( GLUT_CURSOR_HELP, IDC_HELP ); MAP_CURSOR( GLUT_CURSOR_CYCLE, IDC_SIZEALL ); @@ -244,6 +260,18 @@ static void fghWarpPointer ( int x, int y ) ClientToScreen( fgStructure.CurrentWindow->Window.Handle, &coords ); SetCursorPos( coords.x, coords.y ); } + +void fghGetCursorPos(SFG_XYUse *mouse_pos) +{ + /* Get current pointer location in screen coordinates + */ + POINT pos; + GetCursorPos(&pos); + + mouse_pos->X = pos.x; + mouse_pos->Y = pos.y; + mouse_pos->Use = GL_TRUE; +} #endif diff --git a/internal/c/parts/core/freeglut/freeglut_ext.c b/internal/c/parts/core/freeglut/freeglut_ext.c index 39aadbf5d..d8aca45ea 100644 --- a/internal/c/parts/core/freeglut/freeglut_ext.c +++ b/internal/c/parts/core/freeglut/freeglut_ext.c @@ -136,6 +136,8 @@ static GLUTproc fghGetGLUTProcAddress( const char* procName ) CHECK_NAME(glutSolidTorus); CHECK_NAME(glutWireDodecahedron); CHECK_NAME(glutSolidDodecahedron); + CHECK_NAME(glutWireTeapot); + CHECK_NAME(glutSolidTeapot); CHECK_NAME(glutWireOctahedron); CHECK_NAME(glutSolidOctahedron); CHECK_NAME(glutWireTetrahedron); diff --git a/internal/c/parts/core/freeglut/freeglut_gamemode.c b/internal/c/parts/core/freeglut/freeglut_gamemode.c index 803026b05..2796d0117 100644 --- a/internal/c/parts/core/freeglut/freeglut_gamemode.c +++ b/internal/c/parts/core/freeglut/freeglut_gamemode.c @@ -58,7 +58,7 @@ static int xrandr_resize(int xsz, int ysz, int rate, int just_checking) /* we only heed the rate if we CAN actually use it (Xrandr >= 1.1) and * the user actually cares about it (rate > 0) */ - use_rate = ( rate > 0 ) && ( ( ver_major >= 1 ) || + use_rate = ( rate > 0 ) && ( ( ver_major > 1 ) || ( ( ver_major == 1 ) && ( ver_minor >= 1 ) ) ); /* this loop is only so that the whole thing will be repeated if someone @@ -105,7 +105,7 @@ static int xrandr_resize(int xsz, int ysz, int rate, int just_checking) if(res_idx == -1) break; /* no matching resolution */ -#if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) ) +#if ( RANDR_MAJOR > 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) ) if(use_rate) { rate = fgState.GameModeRefresh; @@ -130,7 +130,7 @@ static int xrandr_resize(int xsz, int ysz, int rate, int just_checking) break; } -#if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) ) +#if ( RANDR_MAJOR > 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) ) if(use_rate) result = XRRSetScreenConfigAndRate(fgDisplay.Display, xrr_config, fgDisplay.RootWindow, res_idx, rot, rate, timestamp); @@ -154,6 +154,96 @@ static int xrandr_resize(int xsz, int ysz, int rate, int just_checking) } #endif /* TARGET_HOST_POSIX_X11 */ +#if TARGET_HOST_MS_WINDOWS +/* + * Changes to requested devmode, if it doesn't match current mode + */ +GLboolean fghPlatformChangeDisplayMode(GLboolean haveToTest, DEVMODE *devModeRequested) +{ + GLboolean success = GL_FALSE; + DEVMODE devModeCurrent; + char *fggmstr = NULL; + char displayMode[300]; + + /* Get current display mode */ + EnumDisplaySettings( fgDisplay.DisplayName, ENUM_CURRENT_SETTINGS, &devModeCurrent ); + /* Now see if requested matches current mode, then we're done + * There's only four fields we touch: + * - dmPelsWidth + * - dmPelsHeight + * - dmBitsPerPel + * - dmDisplayFrequency + */ + if (devModeCurrent.dmPelsWidth ==devModeRequested->dmPelsWidth && + devModeCurrent.dmPelsHeight ==devModeRequested->dmPelsHeight && + devModeCurrent.dmBitsPerPel ==devModeRequested->dmBitsPerPel && + devModeCurrent.dmDisplayFrequency==devModeRequested->dmDisplayFrequency) + { + if (!haveToTest) + { + /* update vars in case if actual switch was requested */ + EnumDisplaySettings( fgDisplay.DisplayName, ENUM_CURRENT_SETTINGS, &devModeCurrent ); + fgState.GameModeSize.X = devModeCurrent.dmPelsWidth; + fgState.GameModeSize.Y = devModeCurrent.dmPelsHeight; + fgState.GameModeDepth = devModeCurrent.dmBitsPerPel; + fgState.GameModeRefresh = devModeCurrent.dmDisplayFrequency; + } + + /* We're done */ + return GL_TRUE; + } + + + /* Ok, we do have a mode switch to perform/test */ + switch ( ChangeDisplaySettingsEx(fgDisplay.DisplayName, devModeRequested, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) ) + { + case DISP_CHANGE_SUCCESSFUL: + success = GL_TRUE; + + if (!haveToTest) + { + /* update vars in case if windows switched to proper mode */ + EnumDisplaySettings( fgDisplay.DisplayName, ENUM_CURRENT_SETTINGS, &devModeCurrent ); + fgState.GameModeSize.X = devModeCurrent.dmPelsWidth; + fgState.GameModeSize.Y = devModeCurrent.dmPelsHeight; + fgState.GameModeDepth = devModeCurrent.dmBitsPerPel; + fgState.GameModeRefresh = devModeCurrent.dmDisplayFrequency; + } + break; + case DISP_CHANGE_RESTART: + fggmstr = "The computer must be restarted for the graphics mode to work."; + break; + case DISP_CHANGE_BADFLAGS: + fggmstr = "An invalid set of flags was passed in."; + break; + case DISP_CHANGE_BADPARAM: + fggmstr = "An invalid parameter was passed in. This can include an invalid flag or combination of flags."; + break; + case DISP_CHANGE_FAILED: + fggmstr = "The display driver failed the specified graphics mode."; + break; + case DISP_CHANGE_BADMODE: + fggmstr = "The graphics mode is not supported."; + break; + default: + fggmstr = "Unknown error in graphics mode???"; /* dunno if it is possible, MSDN does not mention any other error */ + break; + } + + if ( !success ) + { + /* I'd rather get info whats going on in my program than wonder about */ + /* what magic happens behind my back, its lib for devels after all ;) */ + + /* append display mode to error to make things more informative */ + sprintf(displayMode,"%s Problem with requested mode: %lux%lu:%lu@%lu", fggmstr, devModeRequested->dmPelsWidth, devModeRequested->dmPelsHeight, devModeRequested->dmBitsPerPel, devModeRequested->dmDisplayFrequency); + fgWarning(displayMode); + } + + return success; +} +#endif + /* * Remembers the current visual settings, so that * we can change them and restore later... @@ -190,7 +280,7 @@ static void fghRememberState( void ) fgDisplay.prev_ysz = ssizes[curr].height; fgDisplay.prev_refresh = -1; -# if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) ) +# if ( RANDR_MAJOR > 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) ) if(fgState.GameModeRefresh != -1) { fgDisplay.prev_refresh = XRRConfigCurrentRate(xrr_config); } @@ -355,7 +445,7 @@ static void fghRestoreState( void ) #elif TARGET_HOST_MS_WINDOWS /* Restore the previously remembered desktop display settings */ - ChangeDisplaySettingsEx( fgDisplay.DisplayName,&fgDisplay.DisplayMode, 0,0,0 ); + fghPlatformChangeDisplayMode(GL_FALSE,&fgDisplay.DisplayMode); #endif } @@ -516,11 +606,10 @@ static GLboolean fghChangeDisplayMode( GLboolean haveToTest ) #elif TARGET_HOST_MS_WINDOWS DEVMODE devMode; - char *fggmstr = NULL; - char displayMode[300]; success = GL_FALSE; + /* Get current display mode */ EnumDisplaySettings( fgDisplay.DisplayName, -1, &devMode ); devMode.dmFields = 0; @@ -545,50 +634,7 @@ static GLboolean fghChangeDisplayMode( GLboolean haveToTest ) devMode.dmFields |= DM_DISPLAYFREQUENCY; } - switch ( ChangeDisplaySettingsEx(fgDisplay.DisplayName, &devMode, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) ) - { - case DISP_CHANGE_SUCCESSFUL: - success = GL_TRUE; - - if (!haveToTest) - { - /* update vars in case if windows switched to proper mode */ - EnumDisplaySettings( fgDisplay.DisplayName, FREEGLUT_ENUM_CURRENT_SETTINGS, &devMode ); - fgState.GameModeSize.X = devMode.dmPelsWidth; - fgState.GameModeSize.Y = devMode.dmPelsHeight; - fgState.GameModeDepth = devMode.dmBitsPerPel; - fgState.GameModeRefresh = devMode.dmDisplayFrequency; - } - break; - case DISP_CHANGE_RESTART: - fggmstr = "The computer must be restarted for the graphics mode to work."; - break; - case DISP_CHANGE_BADFLAGS: - fggmstr = "An invalid set of flags was passed in."; - break; - case DISP_CHANGE_BADPARAM: - fggmstr = "An invalid parameter was passed in. This can include an invalid flag or combination of flags."; - break; - case DISP_CHANGE_FAILED: - fggmstr = "The display driver failed the specified graphics mode."; - break; - case DISP_CHANGE_BADMODE: - fggmstr = "The graphics mode is not supported."; - break; - default: - fggmstr = "Unknown error in graphics mode???"; /* dunno if it is possible,MSDN does not mention any other error */ - break; - } - - if ( !success ) - { - /* I'd rather get info whats going on in my program than wonder about */ - /* magic happenings behind my back, its lib for devels at last ;) */ - - /* append display mode to error to make things more informative */ - sprintf(displayMode,"%s Problem with requested mode: %ix%i:%i@%i", fggmstr, devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmDisplayFrequency); - fgWarning(displayMode); - } + success = fghPlatformChangeDisplayMode(haveToTest, &devMode); #endif return success; diff --git a/internal/c/parts/core/freeglut/freeglut_geometry.c b/internal/c/parts/core/freeglut/freeglut_geometry.c index 0f9f5c53f..199879560 100644 --- a/internal/c/parts/core/freeglut/freeglut_geometry.c +++ b/internal/c/parts/core/freeglut/freeglut_geometry.c @@ -391,13 +391,13 @@ void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLi glBegin(GL_TRIANGLES); - glNormal3d(cost[0]*sinn, sint[0]*sinn, cosn); + glNormal3d(cost[0]*cosn, sint[0]*cosn, sinn); for (j=0; j # include # include -# include +# include // QB64-PE: replaced XInput.h with XI.h # ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H # include # endif @@ -138,9 +138,9 @@ #ifdef HAVE_SYS_TYPES_H # include #endif - -#include - +#ifdef HAVE_UNISTD_H +# include +#endif #ifdef TIME_WITH_SYS_TIME # include # include @@ -344,6 +344,8 @@ struct tagSFG_State int AuxiliaryBufferNumber; /* Number of auxiliary buffers */ int SampleNumber; /* Number of samples per pixel */ + GLboolean SkipStaleMotion; /* skip stale motion events */ + int MajorVersion; /* Major OpenGL context version */ int MinorVersion; /* Minor OpenGL context version */ int ContextFlags; /* OpenGL context flags */ @@ -729,7 +731,8 @@ struct tagSFG_Enumerator GLboolean found; /* Used to terminate search */ void* data; /* Custom data pointer */ }; -typedef void (* FGCBenumerator )( SFG_Window *, SFG_Enumerator * ); +typedef void (* FGCBWindowEnumerator )( SFG_Window *, SFG_Enumerator * ); +typedef void (* FGCBMenuEnumerator )( SFG_Menu *, SFG_Enumerator * ); /* The bitmap font structure */ typedef struct tagSFG_Font SFG_Font; @@ -928,8 +931,8 @@ void fgSetCursor ( SFG_Window *window, int cursorID ); * and userData is the a custom user-supplied pointer. Functions * are defined and exported from freeglut_structure.c file. */ -void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ); -void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, +void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator ); +void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator ); #if TARGET_HOST_MS_WINDOWS @@ -938,11 +941,11 @@ void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, * and the window rect from the client area given the style of the window * (or a valid window pointer from which the style can be queried). */ -void fghComputeWindowRectFromClientArea_UseStyle ( const DWORD windowStyle , RECT *clientRect, BOOL posIsOutside ); -void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside ); -void fghComputeClientAreaFromWindowRect ( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside ); -RECT fghGetClientArea ( const SFG_Window *window, BOOL wantPosOutside ); -void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth); +void fghGetDefaultWindowStyle(DWORD *flags); +void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle ); +void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside ); +void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside ); +void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside ); #endif /* @@ -965,6 +968,12 @@ SFG_Window* fgWindowByID( int windowID ); */ SFG_Menu* fgMenuByID( int menuID ); +/* + * Returns active menu, if any. Assumption: only one menu active throughout application at any one time. + * This is easier than fgWindowByXXX as all menus are placed in one doubly linked list... + */ +SFG_Menu* fgGetActiveMenu( ); + /* * The menu activation and deactivation the code. This is the meat * of the menu user interface handling code... @@ -1018,8 +1027,6 @@ SFG_Proc fghGetProcAddress( const char *procName ); extern void (__cdecl *__glutExitFunc)( int return_value ); #endif -#include - #endif /* FREEGLUT_INTERNAL_H */ /*** END OF FILE ***/ diff --git a/internal/c/parts/core/freeglut/freeglut_main.c b/internal/c/parts/core/freeglut/freeglut_main.c index 493fb3c35..d6cf50baa 100644 --- a/internal/c/parts/core/freeglut/freeglut_main.c +++ b/internal/c/parts/core/freeglut/freeglut_main.c @@ -1,2615 +1,2729 @@ -/* - * freeglut_main.c - * - * The windows message processing methods. - * - * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - * Written by Pawel W. Olszta, - * Creation date: Fri Dec 3 1999 - * - * 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. - */ - -#include -#include "freeglut_internal.h" -#ifdef HAVE_ERRNO_H -# include -#endif -#include -#ifdef HAVE_VFPRINTF -# define VFPRINTF(s,f,a) vfprintf((s),(f),(a)) -#elif defined(HAVE__DOPRNT) -# define VFPRINTF(s,f,a) _doprnt((f),(a),(s)) -#else -# define VFPRINTF(s,f,a) -#endif - -// QB64-PE Custom Code -#include "../../../libqb/include/keyhandler.h" - -#define QB64_EVENT_CLOSE 1 -#define QB64_EVENT_KEY 2 -#define QB64_EVENT_RELATIVE_MOUSE_MOVEMENT 3 -#define QB64_EVENT_FILE_DROP 4 - -int qb64_custom_event(int event, int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, void *p1, void *p2); -#if TARGET_HOST_POSIX_X11 -void qb64_os_event_linux(XEvent *event, Display *display, int *qb64_os_event_info); -#else -LRESULT qb64_os_event_windows(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, int *qb64_os_event_info); -#endif - -#ifdef _WIN32_WCE - -typedef struct GXDisplayProperties GXDisplayProperties; -typedef struct GXKeyList GXKeyList; -#include - -typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int); -typedef int (*GXOPENINPUT)(); - -GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL; -GXOPENINPUT GXOpenInput_ = NULL; - -struct GXKeyList gxKeyList; - -#endif /* _WIN32_WCE */ - -/* - * Try to get the maximum value allowed for ints, falling back to the minimum - * guaranteed by ISO C99 if there is no suitable header. - */ -#ifdef HAVE_LIMITS_H -# include -#endif -#ifndef INT_MAX -# define INT_MAX 32767 -#endif - -#ifndef MIN -# define MIN(a,b) (((a)<(b)) ? (a) : (b)) -#endif - -#ifdef WM_TOUCH - typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int); - typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT); - static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF; - static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF; -#endif - -/* - * TODO BEFORE THE STABLE RELEASE: - * - * There are some issues concerning window redrawing under X11, and maybe - * some events are not handled. The Win32 version lacks some more features, - * but seems acceptable for not demanding purposes. - * - * Need to investigate why the X11 version breaks out with an error when - * closing a window (using the window manager, not glutDestroyWindow)... - */ - -/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ - -/* - * Handle a window configuration change. When no reshape - * callback is hooked, the viewport size is updated to - * match the new window size. - */ -static void fghReshapeWindow ( SFG_Window *window, int width, int height ) -{ - SFG_Window *current_window = fgStructure.CurrentWindow; - - freeglut_return_if_fail( window != NULL ); - -#if TARGET_HOST_POSIX_X11 - - XResizeWindow( fgDisplay.Display, window->Window.Handle, - width, height ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) - { - RECT windowRect; - - /* - * For windowed mode, get the current position of the - * window and resize taking the size of the frame - * decorations into account. - */ - - /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ - GetWindowRect( window->Window.Handle, &windowRect ); - - /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */ - windowRect.right = windowRect.left+width; - windowRect.bottom = windowRect.top+height; - - if (window->Parent == NULL) - /* get the window rect from this to feed to SetWindowPos, correct for window decorations */ - fghComputeWindowRectFromClientArea_QueryWindow(window,&windowRect,TRUE); - else - { - /* correct rect for position client area of parent window - * (SetWindowPos input for child windows is in coordinates - * relative to the parent's client area). - * Child windows don't have decoration, so no need to correct - * for them. - */ - RECT parentRect; - parentRect = fghGetClientArea( window->Parent, FALSE ); - windowRect.left -= parentRect.left; - windowRect.right -= parentRect.left; - windowRect.top -= parentRect.top; - windowRect.bottom -= parentRect.top; - } - - /* Do the actual resizing */ - SetWindowPos( window->Window.Handle, - HWND_TOP, - windowRect.left, windowRect.top, - windowRect.right - windowRect.left, - windowRect.bottom- windowRect.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | - SWP_NOZORDER - ); - } -#endif - - if( FETCH_WCB( *window, Reshape ) ) - INVOKE_WCB( *window, Reshape, ( width, height ) ); - else - { - fgSetWindow( window ); - glViewport( 0, 0, width, height ); - } - - /* - * Force a window redraw. In Windows at least this is only a partial - * solution: if the window is increasing in size in either dimension, - * the already-drawn part does not get drawn again and things look funny. - * But without this we get this bad behaviour whenever we resize the - * window. - */ - window->State.Redisplay = GL_TRUE; - - if( window->IsMenu ) - fgSetWindow( current_window ); -} - -/* - * Calls a window's redraw method. This is used when - * a redraw is forced by the incoming window messages. - */ -static void fghRedrawWindow ( SFG_Window *window ) -{ - SFG_Window *current_window = fgStructure.CurrentWindow; - - freeglut_return_if_fail( window ); - freeglut_return_if_fail( FETCH_WCB ( *window, Display ) ); - - window->State.Redisplay = GL_FALSE; - - freeglut_return_if_fail( window->State.Visible ); - - fgSetWindow( window ); - - if( window->State.NeedToResize ) - { - fghReshapeWindow( - window, - window->State.Width, - window->State.Height - ); - - window->State.NeedToResize = GL_FALSE; - } - - INVOKE_WCB( *window, Display, ( ) ); - - fgSetWindow( current_window ); -} - -/* - * A static helper function to execute display callback for a window - */ -static void fghcbDisplayWindow( SFG_Window *window, - SFG_Enumerator *enumerator ) -{ - if( window->State.Redisplay && - window->State.Visible ) - { - window->State.Redisplay = GL_FALSE; - -#if TARGET_HOST_POSIX_X11 - fghRedrawWindow ( window ) ; -#elif TARGET_HOST_MS_WINDOWS - - RedrawWindow( - window->Window.Handle, NULL, NULL, - RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW - ); -#endif - } - - fgEnumSubWindows( window, fghcbDisplayWindow, enumerator ); -} - -/* - * Make all windows perform a display call - */ -static void fghDisplayAll( void ) -{ - SFG_Enumerator enumerator; - - enumerator.found = GL_FALSE; - enumerator.data = NULL; - - fgEnumWindows( fghcbDisplayWindow, &enumerator ); -} - -/* - * Window enumerator callback to check for the joystick polling code - */ -static void fghcbCheckJoystickPolls( SFG_Window *window, - SFG_Enumerator *enumerator ) -{ - long int checkTime = fgElapsedTime( ); - - if( window->State.JoystickLastPoll + window->State.JoystickPollRate <= - checkTime ) - { -#if !defined(_WIN32_WCE) - fgJoystickPollWindow( window ); -#endif /* !defined(_WIN32_WCE) */ - window->State.JoystickLastPoll = checkTime; - } - - fgEnumSubWindows( window, fghcbCheckJoystickPolls, enumerator ); -} - -/* - * Check all windows for joystick polling - */ -static void fghCheckJoystickPolls( void ) -{ - SFG_Enumerator enumerator; - - enumerator.found = GL_FALSE; - enumerator.data = NULL; - - fgEnumWindows( fghcbCheckJoystickPolls, &enumerator ); -} - -/* - * Check the global timers - */ -static void fghCheckTimers( void ) -{ - long checkTime = fgElapsedTime( ); - - while( fgState.Timers.First ) - { - SFG_Timer *timer = fgState.Timers.First; - - if( timer->TriggerTime > checkTime ) - break; - - fgListRemove( &fgState.Timers, &timer->Node ); - fgListAppend( &fgState.FreeTimers, &timer->Node ); - - timer->Callback( timer->ID ); - } -} - - -/* Platform-dependent time in milliseconds, as an unsigned 32-bit integer. - * This value wraps every 49.7 days, but integer overflows cancel - * when subtracting an initial start time, unless the total time exceeds - * 32-bit, where the GLUT API return value is also overflowed. - */ -unsigned long fgSystemTime(void) { -#if TARGET_HOST_SOLARIS || HAVE_GETTIMEOFDAY - struct timeval now; - gettimeofday( &now, NULL ); - return now.tv_usec/1000 + now.tv_sec*1000; -#elif TARGET_HOST_MS_WINDOWS -# if defined(_WIN32_WCE) - return GetTickCount(); -# else - return timeGetTime(); -# endif -#endif -} - -/* - * Elapsed Time - */ -long fgElapsedTime( void ) -{ - return (long) (fgSystemTime() - fgState.Time); -} - -/* - * Error Messages. - */ -void fgError( const char *fmt, ... ) -{ - va_list ap; - - if (fgState.ErrorFunc) { - - va_start( ap, fmt ); - - /* call user set error handler here */ - fgState.ErrorFunc(fmt, ap); - - va_end( ap ); - - } else { - - va_start( ap, fmt ); - - fprintf( stderr, "freeglut "); - if( fgState.ProgramName ) - fprintf( stderr, "(%s): ", fgState.ProgramName ); - VFPRINTF( stderr, fmt, ap ); - fprintf( stderr, "\n" ); - - va_end( ap ); - - if ( fgState.Initialised ) - fgDeinitialize (); - - exit( 1 ); - } -} - -void fgWarning( const char *fmt, ... ) -{ - va_list ap; - - if (fgState.WarningFunc) { - - va_start( ap, fmt ); - - /* call user set warning handler here */ - fgState.WarningFunc(fmt, ap); - - va_end( ap ); - - } else { - - va_start( ap, fmt ); - - fprintf( stderr, "freeglut "); - if( fgState.ProgramName ) - fprintf( stderr, "(%s): ", fgState.ProgramName ); - VFPRINTF( stderr, fmt, ap ); - fprintf( stderr, "\n" ); - - va_end( ap ); - } -} - - -/* - * Indicates whether Joystick events are being used by ANY window. - * - * The current mechanism is to walk all of the windows and ask if - * there is a joystick callback. We have a short-circuit early - * return if we find any joystick handler registered. - * - * The real way to do this is to make use of the glutTimer() API - * to more cleanly re-implement the joystick API. Then, this code - * and all other "joystick timer" code can be yanked. - * - */ -static void fghCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e) -{ - if( FETCH_WCB( *w, Joystick ) ) - { - e->found = GL_TRUE; - e->data = w; - } - fgEnumSubWindows( w, fghCheckJoystickCallback, e ); -} -static int fghHaveJoystick( void ) -{ - SFG_Enumerator enumerator; - - enumerator.found = GL_FALSE; - enumerator.data = NULL; - fgEnumWindows( fghCheckJoystickCallback, &enumerator ); - return !!enumerator.data; -} -static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e) -{ - if( w->State.Redisplay && w->State.Visible ) - { - e->found = GL_TRUE; - e->data = w; - } - fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e ); -} -static int fghHavePendingRedisplays (void) -{ - SFG_Enumerator enumerator; - - enumerator.found = GL_FALSE; - enumerator.data = NULL; - fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator ); - return !!enumerator.data; -} -/* - * Returns the number of GLUT ticks (milliseconds) till the next timer event. - */ -static long fghNextTimer( void ) -{ - long ret = INT_MAX; - SFG_Timer *timer = fgState.Timers.First; - - if( timer ) - ret = timer->TriggerTime - fgElapsedTime(); - if( ret < 0 ) - ret = 0; - - return ret; -} -/* - * Does the magic required to relinquish the CPU until something interesting - * happens. - */ -static void fghSleepForEvents( void ) -{ - long msec; - - if( fgState.IdleCallback || fghHavePendingRedisplays( ) ) - return; - - msec = fghNextTimer( ); - /* XXX Use GLUT timers for joysticks... */ - /* XXX Dumb; forces granularity to .01sec */ - if( fghHaveJoystick( ) && ( msec > 10 ) ) - msec = 10; - -#if TARGET_HOST_POSIX_X11 - /* - * Possibly due to aggressive use of XFlush() and friends, - * it is possible to have our socket drained but still have - * unprocessed events. (Or, this may just be normal with - * X, anyway?) We do non-trivial processing of X events - * after the event-reading loop, in any case, so we - * need to allow that we may have an empty socket but non- - * empty event queue. - */ - if( ! XPending( fgDisplay.Display ) ) - { - fd_set fdset; - int err; - int socket; - struct timeval wait; - - socket = ConnectionNumber( fgDisplay.Display ); - FD_ZERO( &fdset ); - FD_SET( socket, &fdset ); - wait.tv_sec = msec / 1000; - wait.tv_usec = (msec % 1000) * 1000; - err = select( socket+1, &fdset, NULL, NULL, &wait ); - -#ifdef HAVE_ERRNO_H - if( ( -1 == err ) && ( errno != EINTR ) ) - fgWarning ( "freeglut select() error: %d", errno ); -#endif - } -#elif TARGET_HOST_MS_WINDOWS - MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT ); -#endif -} - -#if TARGET_HOST_POSIX_X11 -/* - * Returns GLUT modifier mask for the state field of an X11 event. - */ -int fghGetXModifiers( int state ) -{ - int ret = 0; - - if( state & ( ShiftMask | LockMask ) ) - ret |= GLUT_ACTIVE_SHIFT; - if( state & ControlMask ) - ret |= GLUT_ACTIVE_CTRL; - if( state & Mod1Mask ) - ret |= GLUT_ACTIVE_ALT; - - return ret; -} -#endif - - -#if TARGET_HOST_POSIX_X11 && _DEBUG - -static const char* fghTypeToString( int type ) -{ - switch( type ) { - case KeyPress: return "KeyPress"; - case KeyRelease: return "KeyRelease"; - case ButtonPress: return "ButtonPress"; - case ButtonRelease: return "ButtonRelease"; - case MotionNotify: return "MotionNotify"; - case EnterNotify: return "EnterNotify"; - case LeaveNotify: return "LeaveNotify"; - case FocusIn: return "FocusIn"; - case FocusOut: return "FocusOut"; - case KeymapNotify: return "KeymapNotify"; - case Expose: return "Expose"; - case GraphicsExpose: return "GraphicsExpose"; - case NoExpose: return "NoExpose"; - case VisibilityNotify: return "VisibilityNotify"; - case CreateNotify: return "CreateNotify"; - case DestroyNotify: return "DestroyNotify"; - case UnmapNotify: return "UnmapNotify"; - case MapNotify: return "MapNotify"; - case MapRequest: return "MapRequest"; - case ReparentNotify: return "ReparentNotify"; - case ConfigureNotify: return "ConfigureNotify"; - case ConfigureRequest: return "ConfigureRequest"; - case GravityNotify: return "GravityNotify"; - case ResizeRequest: return "ResizeRequest"; - case CirculateNotify: return "CirculateNotify"; - case CirculateRequest: return "CirculateRequest"; - case PropertyNotify: return "PropertyNotify"; - case SelectionClear: return "SelectionClear"; - case SelectionRequest: return "SelectionRequest"; - case SelectionNotify: return "SelectionNotify"; - case ColormapNotify: return "ColormapNotify"; - case ClientMessage: return "ClientMessage"; - case MappingNotify: return "MappingNotify"; - default: return "UNKNOWN"; - } -} - -static const char* fghBoolToString( Bool b ) -{ - return b == False ? "False" : "True"; -} - -static const char* fghNotifyHintToString( char is_hint ) -{ - switch( is_hint ) { - case NotifyNormal: return "NotifyNormal"; - case NotifyHint: return "NotifyHint"; - default: return "UNKNOWN"; - } -} - -static const char* fghNotifyModeToString( int mode ) -{ - switch( mode ) { - case NotifyNormal: return "NotifyNormal"; - case NotifyGrab: return "NotifyGrab"; - case NotifyUngrab: return "NotifyUngrab"; - case NotifyWhileGrabbed: return "NotifyWhileGrabbed"; - default: return "UNKNOWN"; - } -} - -static const char* fghNotifyDetailToString( int detail ) -{ - switch( detail ) { - case NotifyAncestor: return "NotifyAncestor"; - case NotifyVirtual: return "NotifyVirtual"; - case NotifyInferior: return "NotifyInferior"; - case NotifyNonlinear: return "NotifyNonlinear"; - case NotifyNonlinearVirtual: return "NotifyNonlinearVirtual"; - case NotifyPointer: return "NotifyPointer"; - case NotifyPointerRoot: return "NotifyPointerRoot"; - case NotifyDetailNone: return "NotifyDetailNone"; - default: return "UNKNOWN"; - } -} - -static const char* fghVisibilityToString( int state ) { - switch( state ) { - case VisibilityUnobscured: return "VisibilityUnobscured"; - case VisibilityPartiallyObscured: return "VisibilityPartiallyObscured"; - case VisibilityFullyObscured: return "VisibilityFullyObscured"; - default: return "UNKNOWN"; - } -} - -static const char* fghConfigureDetailToString( int detail ) -{ - switch( detail ) { - case Above: return "Above"; - case Below: return "Below"; - case TopIf: return "TopIf"; - case BottomIf: return "BottomIf"; - case Opposite: return "Opposite"; - default: return "UNKNOWN"; - } -} - -static const char* fghPlaceToString( int place ) -{ - switch( place ) { - case PlaceOnTop: return "PlaceOnTop"; - case PlaceOnBottom: return "PlaceOnBottom"; - default: return "UNKNOWN"; - } -} - -static const char* fghMappingRequestToString( int request ) -{ - switch( request ) { - case MappingModifier: return "MappingModifier"; - case MappingKeyboard: return "MappingKeyboard"; - case MappingPointer: return "MappingPointer"; - default: return "UNKNOWN"; - } -} - -static const char* fghPropertyStateToString( int state ) -{ - switch( state ) { - case PropertyNewValue: return "PropertyNewValue"; - case PropertyDelete: return "PropertyDelete"; - default: return "UNKNOWN"; - } -} - -static const char* fghColormapStateToString( int state ) -{ - switch( state ) { - case ColormapUninstalled: return "ColormapUninstalled"; - case ColormapInstalled: return "ColormapInstalled"; - default: return "UNKNOWN"; - } -} - -static void fghPrintEvent( XEvent *event ) -{ - switch( event->type ) { - - case KeyPress: - case KeyRelease: { - XKeyEvent *e = &event->xkey; - fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " - "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " - "keycode=%u, same_screen=%s", fghTypeToString( e->type ), - e->window, e->root, e->subwindow, (unsigned long)e->time, - e->x, e->y, e->x_root, e->y_root, e->state, e->keycode, - fghBoolToString( e->same_screen ) ); - break; - } - - case ButtonPress: - case ButtonRelease: { - XButtonEvent *e = &event->xbutton; - fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " - "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " - "button=%u, same_screen=%d", fghTypeToString( e->type ), - e->window, e->root, e->subwindow, (unsigned long)e->time, - e->x, e->y, e->x_root, e->y_root, e->state, e->button, - fghBoolToString( e->same_screen ) ); - break; - } - - case MotionNotify: { - XMotionEvent *e = &event->xmotion; - fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " - "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " - "is_hint=%s, same_screen=%d", fghTypeToString( e->type ), - e->window, e->root, e->subwindow, (unsigned long)e->time, - e->x, e->y, e->x_root, e->y_root, e->state, - fghNotifyHintToString( e->is_hint ), - fghBoolToString( e->same_screen ) ); - break; - } - - case EnterNotify: - case LeaveNotify: { - XCrossingEvent *e = &event->xcrossing; - fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " - "(x,y)=(%d,%d), mode=%s, detail=%s, same_screen=%d, " - "focus=%d, state=0x%x", fghTypeToString( e->type ), - e->window, e->root, e->subwindow, (unsigned long)e->time, - e->x, e->y, fghNotifyModeToString( e->mode ), - fghNotifyDetailToString( e->detail ), (int)e->same_screen, - (int)e->focus, e->state ); - break; - } - - case FocusIn: - case FocusOut: { - XFocusChangeEvent *e = &event->xfocus; - fgWarning( "%s: window=0x%x, mode=%s, detail=%s", - fghTypeToString( e->type ), e->window, - fghNotifyModeToString( e->mode ), - fghNotifyDetailToString( e->detail ) ); - break; - } - - case KeymapNotify: { - XKeymapEvent *e = &event->xkeymap; - char buf[32 * 2 + 1]; - int i; - for ( i = 0; i < 32; i++ ) { - snprintf( &buf[ i * 2 ], sizeof( buf ) - i * 2, - "%02x", e->key_vector[ i ] ); - } - buf[ i ] = '\0'; - fgWarning( "%s: window=0x%x, %s", fghTypeToString( e->type ), e->window, - buf ); - break; - } - - case Expose: { - XExposeEvent *e = &event->xexpose; - fgWarning( "%s: window=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " - "count=%d", fghTypeToString( e->type ), e->window, e->x, - e->y, e->width, e->height, e->count ); - break; - } - - case GraphicsExpose: { - XGraphicsExposeEvent *e = &event->xgraphicsexpose; - fgWarning( "%s: drawable=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " - "count=%d, (major_code,minor_code)=(%d,%d)", - fghTypeToString( e->type ), e->drawable, e->x, e->y, - e->width, e->height, e->count, e->major_code, - e->minor_code ); - break; - } - - case NoExpose: { - XNoExposeEvent *e = &event->xnoexpose; - fgWarning( "%s: drawable=0x%x, (major_code,minor_code)=(%d,%d)", - fghTypeToString( e->type ), e->drawable, e->major_code, - e->minor_code ); - break; - } - - case VisibilityNotify: { - XVisibilityEvent *e = &event->xvisibility; - fgWarning( "%s: window=0x%x, state=%s", fghTypeToString( e->type ), - e->window, fghVisibilityToString( e->state) ); - break; - } - - case CreateNotify: { - XCreateWindowEvent *e = &event->xcreatewindow; - fgWarning( "%s: (x,y)=(%d,%d), (width,height)=(%d,%d), border_width=%d, " - "window=0x%x, override_redirect=%s", - fghTypeToString( e->type ), e->x, e->y, e->width, e->height, - e->border_width, e->window, - fghBoolToString( e->override_redirect ) ); - break; - } - - case DestroyNotify: { - XDestroyWindowEvent *e = &event->xdestroywindow; - fgWarning( "%s: event=0x%x, window=0x%x", - fghTypeToString( e->type ), e->event, e->window ); - break; - } - - case UnmapNotify: { - XUnmapEvent *e = &event->xunmap; - fgWarning( "%s: event=0x%x, window=0x%x, from_configure=%s", - fghTypeToString( e->type ), e->event, e->window, - fghBoolToString( e->from_configure ) ); - break; - } - - case MapNotify: { - XMapEvent *e = &event->xmap; - fgWarning( "%s: event=0x%x, window=0x%x, override_redirect=%s", - fghTypeToString( e->type ), e->event, e->window, - fghBoolToString( e->override_redirect ) ); - break; - } - - case MapRequest: { - XMapRequestEvent *e = &event->xmaprequest; - fgWarning( "%s: parent=0x%x, window=0x%x", - fghTypeToString( event->type ), e->parent, e->window ); - break; - } - - case ReparentNotify: { - XReparentEvent *e = &event->xreparent; - fgWarning( "%s: event=0x%x, window=0x%x, parent=0x%x, (x,y)=(%d,%d), " - "override_redirect=%s", fghTypeToString( e->type ), - e->event, e->window, e->parent, e->x, e->y, - fghBoolToString( e->override_redirect ) ); - break; - } - - case ConfigureNotify: { - XConfigureEvent *e = &event->xconfigure; - fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d), " - "(width,height)=(%d,%d), border_width=%d, above=0x%x, " - "override_redirect=%s", fghTypeToString( e->type ), e->event, - e->window, e->x, e->y, e->width, e->height, e->border_width, - e->above, fghBoolToString( e->override_redirect ) ); - break; - } - - case ConfigureRequest: { - XConfigureRequestEvent *e = &event->xconfigurerequest; - fgWarning( "%s: parent=0x%x, window=0x%x, (x,y)=(%d,%d), " - "(width,height)=(%d,%d), border_width=%d, above=0x%x, " - "detail=%s, value_mask=%lx", fghTypeToString( e->type ), - e->parent, e->window, e->x, e->y, e->width, e->height, - e->border_width, e->above, - fghConfigureDetailToString( e->detail ), e->value_mask ); - break; - } - - case GravityNotify: { - XGravityEvent *e = &event->xgravity; - fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d)", - fghTypeToString( e->type ), e->event, e->window, e->x, e->y ); - break; - } - - case ResizeRequest: { - XResizeRequestEvent *e = &event->xresizerequest; - fgWarning( "%s: window=0x%x, (width,height)=(%d,%d)", - fghTypeToString( e->type ), e->window, e->width, e->height ); - break; - } - - case CirculateNotify: { - XCirculateEvent *e = &event->xcirculate; - fgWarning( "%s: event=0x%x, window=0x%x, place=%s", - fghTypeToString( e->type ), e->event, e->window, - fghPlaceToString( e->place ) ); - break; - } - - case CirculateRequest: { - XCirculateRequestEvent *e = &event->xcirculaterequest; - fgWarning( "%s: parent=0x%x, window=0x%x, place=%s", - fghTypeToString( e->type ), e->parent, e->window, - fghPlaceToString( e->place ) ); - break; - } - - case PropertyNotify: { - XPropertyEvent *e = &event->xproperty; - fgWarning( "%s: window=0x%x, atom=%lu, time=%lu, state=%s", - fghTypeToString( e->type ), e->window, - (unsigned long)e->atom, (unsigned long)e->time, - fghPropertyStateToString( e->state ) ); - break; - } - - case SelectionClear: { - XSelectionClearEvent *e = &event->xselectionclear; - fgWarning( "%s: window=0x%x, selection=%lu, time=%lu", - fghTypeToString( e->type ), e->window, - (unsigned long)e->selection, (unsigned long)e->time ); - break; - } - - case SelectionRequest: { - XSelectionRequestEvent *e = &event->xselectionrequest; - fgWarning( "%s: owner=0x%x, requestor=0x%x, selection=0x%x, " - "target=0x%x, property=%lu, time=%lu", - fghTypeToString( e->type ), e->owner, e->requestor, - (unsigned long)e->selection, (unsigned long)e->target, - (unsigned long)e->property, (unsigned long)e->time ); - break; - } - - case SelectionNotify: { - XSelectionEvent *e = &event->xselection; - fgWarning( "%s: requestor=0x%x, selection=0x%x, target=0x%x, " - "property=%lu, time=%lu", fghTypeToString( e->type ), - e->requestor, (unsigned long)e->selection, - (unsigned long)e->target, (unsigned long)e->property, - (unsigned long)e->time ); - break; - } - - case ColormapNotify: { - XColormapEvent *e = &event->xcolormap; - fgWarning( "%s: window=0x%x, colormap=%lu, new=%s, state=%s", - fghTypeToString( e->type ), e->window, - (unsigned long)e->colormap, fghBoolToString( e->new ), - fghColormapStateToString( e->state ) ); - break; - } - - case ClientMessage: { - XClientMessageEvent *e = &event->xclient; - char buf[ 61 ]; - char* p = buf; - char* end = buf + sizeof( buf ); - int i; - switch( e->format ) { - case 8: - for ( i = 0; i < 20; i++, p += 3 ) { - snprintf( p, end - p, " %02x", e->data.b[ i ] ); - } - break; - case 16: - for ( i = 0; i < 10; i++, p += 5 ) { - snprintf( p, end - p, " %04x", e->data.s[ i ] ); - } - break; - case 32: - for ( i = 0; i < 5; i++, p += 9 ) { - snprintf( p, end - p, " %08lx", e->data.l[ i ] ); - } - break; - } - *p = '\0'; - fgWarning( "%s: window=0x%x, message_type=%lu, format=%d, data=(%s )", - fghTypeToString( e->type ), e->window, - (unsigned long)e->message_type, e->format, buf ); - break; - } - - case MappingNotify: { - XMappingEvent *e = &event->xmapping; - fgWarning( "%s: window=0x%x, request=%s, first_keycode=%d, count=%d", - fghTypeToString( e->type ), e->window, - fghMappingRequestToString( e->request ), e->first_keycode, - e->count ); - break; - } - - default: { - fgWarning( "%s", fghTypeToString( event->type ) ); - break; - } - } -} - -#endif - -/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ - -/* - * Executes a single iteration in the freeglut processing loop. - */ -void FGAPIENTRY glutMainLoopEvent( void ) -{ -#if TARGET_HOST_POSIX_X11 - SFG_Window* window; - XEvent event; - - /* This code was repeated constantly, so here it goes into a definition: */ -#define GETWINDOW(a) \ - window = fgWindowByHandle( event.a.window ); \ - if( window == NULL ) \ - break; - -#define GETMOUSE(a) \ - window->State.MouseX = event.a.x; \ - window->State.MouseY = event.a.y; - - - - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); - - while( XPending( fgDisplay.Display ) ) - { - XNextEvent( fgDisplay.Display, &event ); -#if _DEBUG - fghPrintEvent( &event ); -#endif - - int qb64_os_event_info = 0; - - qb64_os_event_info = 1; - qb64_os_event_linux(&event, fgDisplay.Display, &qb64_os_event_info); - if (qb64_os_event_info == 3) - return; - - switch (event.type) { - case ClientMessage: - if (fgIsSpaceballXEvent(&event)) { - fgSpaceballHandleXEvent(&event); - break; - } - /* Destroy the window when the WM_DELETE_WINDOW message arrives */ - if ((Atom)event.xclient.data.l[0] == fgDisplay.DeleteWindow) { - GETWINDOW(xclient); - qb64_custom_event(QB64_EVENT_CLOSE, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL); - /* fgDestroyWindow ( window ); - - if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) - { - fgDeinitialize( ); - exit( 0 ); - } - else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) - fgState.ExecState = GLUT_EXEC_STATE_STOP; - return; - */ - } - break; - - /* - * CreateNotify causes a configure-event so that sub-windows are - * handled compatibly with GLUT. Otherwise, your sub-windows - * (in freeglut only) will not get an initial reshape event, - * which can break things. - * - * GLUT presumably does this because it generally tries to treat - * sub-windows the same as windows. - */ - case CreateNotify: - case ConfigureNotify: - { - int width, height; - if( event.type == CreateNotify ) { - GETWINDOW( xcreatewindow ); - width = event.xcreatewindow.width; - height = event.xcreatewindow.height; - } else { - GETWINDOW( xconfigure ); - width = event.xconfigure.width; - height = event.xconfigure.height; - } - - if( ( width != window->State.OldWidth ) || - ( height != window->State.OldHeight ) ) - { - SFG_Window *current_window = fgStructure.CurrentWindow; - - window->State.OldWidth = width; - window->State.OldHeight = height; - if( FETCH_WCB( *window, Reshape ) ) - INVOKE_WCB( *window, Reshape, ( width, height ) ); - else - { - fgSetWindow( window ); - glViewport( 0, 0, width, height ); - } - glutPostRedisplay( ); - if( window->IsMenu ) - fgSetWindow( current_window ); - } - } - break; - - case DestroyNotify: - /* - * This is sent to confirm the XDestroyWindow call. - * - * XXX WHY is this commented out? Should we re-enable it? - */ - /* fgAddToWindowDestroyList ( window ); */ - break; - - case Expose: - /* - * We are too dumb to process partial exposes... - * - * XXX Well, we could do it. However, it seems to only - * XXX be potentially useful for single-buffered (since - * XXX double-buffered does not respect viewport when we - * XXX do a buffer-swap). - * - */ - if( event.xexpose.count == 0 ) - { - GETWINDOW( xexpose ); - window->State.Redisplay = GL_TRUE; - } - break; - - case MapNotify: - break; - - case UnmapNotify: - /* We get this when iconifying a window. */ - GETWINDOW( xunmap ); - INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) ); - window->State.Visible = GL_FALSE; - break; - - case MappingNotify: - /* - * Have the client's keyboard knowledge updated (xlib.ps, - * page 206, says that's a good thing to do) - */ - XRefreshKeyboardMapping( (XMappingEvent *) &event ); - break; - - case VisibilityNotify: - { - /* - * Sending this event, the X server can notify us that the window - * has just acquired one of the three possible visibility states: - * VisibilityUnobscured, VisibilityPartiallyObscured or - * VisibilityFullyObscured. Note that we DO NOT receive a - * VisibilityNotify event when iconifying a window, we only get an - * UnmapNotify then. - */ - GETWINDOW( xvisibility ); - switch( event.xvisibility.state ) - { - case VisibilityUnobscured: - INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); - window->State.Visible = GL_TRUE; - break; - - case VisibilityPartiallyObscured: - INVOKE_WCB( *window, WindowStatus, - ( GLUT_PARTIALLY_RETAINED ) ); - window->State.Visible = GL_TRUE; - break; - - case VisibilityFullyObscured: - INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); - window->State.Visible = GL_FALSE; - break; - - default: - fgWarning( "Unknown X visibility state: %d", - event.xvisibility.state ); - break; - } - } - break; - - case EnterNotify: - case LeaveNotify: - GETWINDOW( xcrossing ); - GETMOUSE( xcrossing ); - if( ( event.type == LeaveNotify ) && window->IsMenu && - window->ActiveMenu && window->ActiveMenu->IsActive ) - fgUpdateMenuHighlight( window->ActiveMenu ); - - INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ? - GLUT_ENTERED : - GLUT_LEFT ) ); - break; - - case MotionNotify: - { - GETWINDOW( xmotion ); - GETMOUSE( xmotion ); - - if( window->ActiveMenu ) - { - if( window == window->ActiveMenu->ParentWindow ) - { - window->ActiveMenu->Window->State.MouseX = - event.xmotion.x_root - window->ActiveMenu->X; - window->ActiveMenu->Window->State.MouseY = - event.xmotion.y_root - window->ActiveMenu->Y; - } - - fgUpdateMenuHighlight( window->ActiveMenu ); - - break; - } - - /* - * XXX For more than 5 buttons, just check {event.xmotion.state}, - * XXX rather than a host of bit-masks? Or maybe we need to - * XXX track ButtonPress/ButtonRelease events in our own - * XXX bit-mask? - */ - fgState.Modifiers = fghGetXModifiers( event.xmotion.state ); - if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) { - INVOKE_WCB( *window, Motion, ( event.xmotion.x, - event.xmotion.y ) ); - } else { - INVOKE_WCB( *window, Passive, ( event.xmotion.x, - event.xmotion.y ) ); - } - fgState.Modifiers = INVALID_MODIFIERS; - } - break; - - case ButtonRelease: - case ButtonPress: - { - GLboolean pressed = GL_TRUE; - int button; - - if( event.type == ButtonRelease ) - pressed = GL_FALSE ; - - /* - * A mouse button has been pressed or released. Traditionally, - * break if the window was found within the freeglut structures. - */ - GETWINDOW( xbutton ); - GETMOUSE( xbutton ); - - /* - * An X button (at least in XFree86) is numbered from 1. - * A GLUT button is numbered from 0. - * Old GLUT passed through buttons other than just the first - * three, though it only gave symbolic names and official - * support to the first three. - */ - button = event.xbutton.button - 1; - - /* - * Do not execute the application's mouse callback if a menu - * is hooked to this button. In that case an appropriate - * private call should be generated. - */ - if( fgCheckActiveMenu( window, button, pressed, - event.xbutton.x_root, event.xbutton.y_root ) ) - break; - - /* - * Check if there is a mouse or mouse wheel callback hooked to the - * window - */ - if( ! FETCH_WCB( *window, Mouse ) && - ! FETCH_WCB( *window, MouseWheel ) ) - break; - - fgState.Modifiers = fghGetXModifiers( event.xbutton.state ); - - /* Finally execute the mouse or mouse wheel callback */ - if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) - INVOKE_WCB( *window, Mouse, ( button, - pressed ? GLUT_DOWN : GLUT_UP, - event.xbutton.x, - event.xbutton.y ) - ); - else - { - /* - * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1 - * " 6 and 7 " " one; ... - * - * XXX This *should* be behind some variables/macros, - * XXX since the order and numbering isn't certain - * XXX See XFree86 configuration docs (even back in the - * XXX 3.x days, and especially with 4.x). - * - * XXX Note that {button} has already been decremented - * XXX in mapping from X button numbering to GLUT. - * - * XXX Should add support for partial wheel turns as Windows does -- 5/27/11 - */ - int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2; - int direction = -1; - if( button % 2 ) - direction = 1; - - if( pressed ) - INVOKE_WCB( *window, MouseWheel, ( wheel_number, - direction, - event.xbutton.x, - event.xbutton.y ) - ); - } - fgState.Modifiers = INVALID_MODIFIERS; - } - break; - - case KeyRelease: - case KeyPress: - { - FGCBKeyboard keyboard_cb; - FGCBSpecial special_cb; - - GETWINDOW( xkey ); - GETMOUSE( xkey ); - - /* Detect auto repeated keys, if configured globally or per-window */ - - if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) - { - if (event.type==KeyRelease) - { - /* - * Look at X11 keystate to detect repeat mode. - * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs. - */ - - char keys[32]; - XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */ - - if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */ - { - if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) - window->State.KeyRepeating = GL_TRUE; - else - window->State.KeyRepeating = GL_FALSE; - } - } - } - else - window->State.KeyRepeating = GL_FALSE; - - /* Cease processing this event if it is auto repeated */ - - if (window->State.KeyRepeating) - { - if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE; - break; - } - - if( event.type == KeyPress ) - { - keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); - special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); - } - else - { - keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); - special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); - } - - /* Is there a keyboard/special callback hooked for this window? */ - if( keyboard_cb || special_cb ) - { - XComposeStatus composeStatus; - char asciiCode[ 32 ]; - KeySym keySym; - int len; - - /* Check for the ASCII/KeySym codes associated with the event: */ - len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), - &keySym, &composeStatus - ); - - /* GLUT API tells us to have two separate callbacks... */ - if( len > 0 ) - { - /* ...one for the ASCII translateable keypresses... */ - if( keyboard_cb ) - { - fgSetWindow( window ); - fgState.Modifiers = fghGetXModifiers( event.xkey.state ); - keyboard_cb( asciiCode[ 0 ], - event.xkey.x, event.xkey.y - ); - fgState.Modifiers = INVALID_MODIFIERS; - } - } - else - { - int special = -1; - - /* - * ...and one for all the others, which need to be - * translated to GLUT_KEY_Xs... - */ - switch( keySym ) - { - case XK_F1: special = GLUT_KEY_F1; break; - case XK_F2: special = GLUT_KEY_F2; break; - case XK_F3: special = GLUT_KEY_F3; break; - case XK_F4: special = GLUT_KEY_F4; break; - case XK_F5: special = GLUT_KEY_F5; break; - case XK_F6: special = GLUT_KEY_F6; break; - case XK_F7: special = GLUT_KEY_F7; break; - case XK_F8: special = GLUT_KEY_F8; break; - case XK_F9: special = GLUT_KEY_F9; break; - case XK_F10: special = GLUT_KEY_F10; break; - case XK_F11: special = GLUT_KEY_F11; break; - case XK_F12: special = GLUT_KEY_F12; break; - - case XK_KP_Left: - case XK_Left: special = GLUT_KEY_LEFT; break; - case XK_KP_Right: - case XK_Right: special = GLUT_KEY_RIGHT; break; - case XK_KP_Up: - case XK_Up: special = GLUT_KEY_UP; break; - case XK_KP_Down: - case XK_Down: special = GLUT_KEY_DOWN; break; - - case XK_KP_Prior: - case XK_Prior: special = GLUT_KEY_PAGE_UP; break; - case XK_KP_Next: - case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; - case XK_KP_Home: - case XK_Home: special = GLUT_KEY_HOME; break; - case XK_KP_End: - case XK_End: special = GLUT_KEY_END; break; - case XK_KP_Insert: - case XK_Insert: special = GLUT_KEY_INSERT; break; - - case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; - case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; - case XK_KP_Delete: special = GLUT_KEY_DELETE; break; - - case XK_Shift_L: special = GLUT_KEY_SHIFT_L; break; - case XK_Shift_R: special = GLUT_KEY_SHIFT_R; break; - case XK_Control_L: special = GLUT_KEY_CTRL_L; break; - case XK_Control_R: special = GLUT_KEY_CTRL_R; break; - case XK_Alt_L: special = GLUT_KEY_ALT_L; break; - case XK_Alt_R: special = GLUT_KEY_ALT_R; break; - } - - /* - * Execute the callback (if one has been specified), - * given that the special code seems to be valid... - */ - if( special_cb && (special != -1) ) - { - fgSetWindow( window ); - fgState.Modifiers = fghGetXModifiers( event.xkey.state ); - special_cb( special, event.xkey.x, event.xkey.y ); - fgState.Modifiers = INVALID_MODIFIERS; - } - } - } - } - break; - - case ReparentNotify: - break; /* XXX Should disable this event */ - - /* Not handled */ - case GravityNotify: - break; - - default: - /* enter handling of Extension Events here */ - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - fgHandleExtensionEvents( &event ); - #endif - break; - } - - qb64_os_event_info = 2; - qb64_os_event_linux(&event, fgDisplay.Display, &qb64_os_event_info); - if (qb64_os_event_info == 3) - return; //(although we would return anyway) - } - -#elif TARGET_HOST_MS_WINDOWS - - MSG stMsg; - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); - - while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) ) - { - if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 ) - { - if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) - { - fgDeinitialize( ); - exit( 0 ); - } - else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) - fgState.ExecState = GLUT_EXEC_STATE_STOP; - - return; - } - - TranslateMessage( &stMsg ); - DispatchMessage( &stMsg ); - } -#endif - - if( fgState.Timers.First ) - fghCheckTimers( ); - fghCheckJoystickPolls( ); - fghDisplayAll( ); - - fgCloseWindows( ); -} - -/* - * Enters the freeglut processing loop. - * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP". - */ -void FGAPIENTRY glutMainLoop( void ) -{ - int action; - -#if TARGET_HOST_MS_WINDOWS - SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; -#endif - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" ); - -#if TARGET_HOST_MS_WINDOWS - /* - * Processing before the main loop: If there is a window which is open and - * which has a visibility callback, call it. I know this is an ugly hack, - * but I'm not sure what else to do about it. Ideally we should leave - * something uninitialized in the create window code and initialize it in - * the main loop, and have that initialization create a "WM_ACTIVATE" - * message. Then we would put the visibility callback code in the - * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02 - */ - while( window ) - { - if ( FETCH_WCB( *window, Visibility ) ) - { - SFG_Window *current_window = fgStructure.CurrentWindow ; - - INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); - fgSetWindow( current_window ); - } - - window = (SFG_Window *)window->Node.Next ; - } -#endif - - fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; - while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) - { - SFG_Window *window; - - glutMainLoopEvent( ); - /* - * Step through the list of windows, seeing if there are any - * that are not menus - */ - for( window = ( SFG_Window * )fgStructure.Windows.First; - window; - window = ( SFG_Window * )window->Node.Next ) - if ( ! ( window->IsMenu ) ) - break; - - if( ! window ) - fgState.ExecState = GLUT_EXEC_STATE_STOP; - else - { - if( fgState.IdleCallback ) - { - if( fgStructure.CurrentWindow && - fgStructure.CurrentWindow->IsMenu ) - /* fail safe */ - fgSetWindow( window ); - fgState.IdleCallback( ); - } - - fghSleepForEvents( ); - } - } - - /* - * When this loop terminates, destroy the display, state and structure - * of a freeglut session, so that another glutInit() call can happen - * - * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it. - */ - action = fgState.ActionOnWindowClose; - fgDeinitialize( ); - if( action == GLUT_ACTION_EXIT ) - exit( 0 ); -} - -/* - * Leaves the freeglut processing loop. - */ -void FGAPIENTRY glutLeaveMainLoop( void ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveMainLoop" ); - fgState.ExecState = GLUT_EXEC_STATE_STOP ; -} - - -#if TARGET_HOST_MS_WINDOWS -/* - * Determine a GLUT modifer mask based on MS-WINDOWS system info. - */ -static int fghGetWin32Modifiers (void) -{ - return - ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) || - ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | - ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) || - ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | - ( ( ( GetKeyState( VK_LMENU ) < 0 ) || - ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); -} - -/* - * The window procedure for handling Win32 events - */ -LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, - LPARAM lParam ) -{ - int qb64_os_event_info = 0; - LRESULT qb64_os_event_return = 1; - - qb64_os_event_info = 1; - qb64_os_event_return = qb64_os_event_windows(hWnd, uMsg, wParam, lParam, &qb64_os_event_info); - if (qb64_os_event_info == 3) - return qb64_os_event_return; - - static unsigned char lControl = 0, rControl = 0, lShift = 0, rShift = 0, lAlt = 0, rAlt = 0; - - SFG_Window* window; - PAINTSTRUCT ps; - LRESULT lRet = 1; - - FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ; - - window = fgWindowByHandle( hWnd ); - - if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) - return DefWindowProc( hWnd, uMsg, wParam, lParam ); - - /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0, - uMsg, wParam, lParam ); */ - - if ( window ) - { - /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */ - if (hWnd == GetForegroundWindow()) { - if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) ) - { - INVOKE_WCB ( *window, Special, - ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY ) - ); - - lControl = 1; - } - - if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) ) - { - INVOKE_WCB ( *window, Special, - ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY ) - ); - - rControl = 1; - } - - if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) ) - { - INVOKE_WCB ( *window, Special, - ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY ) - ); - - lShift = 1; - } - - if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) ) - { - INVOKE_WCB ( *window, Special, - ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY ) - ); - - rShift = 1; - } - - if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) ) - { - INVOKE_WCB ( *window, Special, - ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY ) - ); - - lAlt = 1; - } - - if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) ) - { - INVOKE_WCB ( *window, Special, - ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY ) - ); - - rAlt = 1; - } - } - - /* Checking for CTRL, ALT, and SHIFT key positions: Key Up! */ - if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) ) - { - INVOKE_WCB ( *window, SpecialUp, - ( GLUT_KEY_CTRL_L, window->State.MouseX, window->State.MouseY ) - ); - - lControl = 0; - } - - if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) ) - { - INVOKE_WCB ( *window, SpecialUp, - ( GLUT_KEY_CTRL_R, window->State.MouseX, window->State.MouseY ) - ); - - rControl = 0; - } - - if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) ) - { - INVOKE_WCB ( *window, SpecialUp, - ( GLUT_KEY_SHIFT_L, window->State.MouseX, window->State.MouseY ) - ); - - lShift = 0; - } - - if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) ) - { - INVOKE_WCB ( *window, SpecialUp, - ( GLUT_KEY_SHIFT_R, window->State.MouseX, window->State.MouseY ) - ); - - rShift = 0; - } - - if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) ) - { - INVOKE_WCB ( *window, SpecialUp, - ( GLUT_KEY_ALT_L, window->State.MouseX, window->State.MouseY ) - ); - - lAlt = 0; - } - - if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) ) - { - INVOKE_WCB ( *window, SpecialUp, - ( GLUT_KEY_ALT_R, window->State.MouseX, window->State.MouseY ) - ); - - rAlt = 0; - } - } - - switch( uMsg ) - { - case WM_CREATE: - /* The window structure is passed as the creation structure parameter... */ - window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams); - FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window", - "fgWindowProc" ); - - window->Window.Handle = hWnd; - window->Window.Device = GetDC( hWnd ); - if( window->IsMenu ) - { - unsigned int current_DisplayMode = fgState.DisplayMode; - fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; -#if !defined(_WIN32_WCE) - fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); -#endif - fgState.DisplayMode = current_DisplayMode; - - if( fgStructure.MenuContext ) - wglMakeCurrent( window->Window.Device, - fgStructure.MenuContext->MContext - ); - else - { - fgStructure.MenuContext = - (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); - fgStructure.MenuContext->MContext = - wglCreateContext( window->Window.Device ); - } - - /* window->Window.Context = wglGetCurrentContext (); */ - window->Window.Context = wglCreateContext( window->Window.Device ); - } - else - { -#if !defined(_WIN32_WCE) - fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); -#endif - - if( ! fgState.UseCurrentContext ) - window->Window.Context = - wglCreateContext( window->Window.Device ); - else - { - window->Window.Context = wglGetCurrentContext( ); - if( ! window->Window.Context ) - window->Window.Context = - wglCreateContext( window->Window.Device ); - } - -#if !defined(_WIN32_WCE) - fgNewWGLCreateContext( window ); -#endif - } - - window->State.NeedToResize = GL_TRUE; - /* if we used CW_USEDEFAULT (thats a negative value) for the size - * of the window, query the window now for the size at which it - * was created. - */ - if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) ) - { - SFG_Window *current_window = fgStructure.CurrentWindow; - - fgSetWindow( window ); - window->State.Width = glutGet( GLUT_WINDOW_WIDTH ); - window->State.Height = glutGet( GLUT_WINDOW_HEIGHT ); - fgSetWindow( current_window ); - } - - ReleaseDC( window->Window.Handle, window->Window.Device ); - -#if defined(_WIN32_WCE) - /* Take over button handling */ - { - HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll")); - if (dxDllLib) - { - GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z")); - GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ")); - } - - if(GXOpenInput_) - (*GXOpenInput_)(); - if(GXGetDefaultKeys_) - gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS); - } - -#endif /* defined(_WIN32_WCE) */ - break; - - case WM_SIZE: - /* - * If the window is visible, then it is the user manually resizing it. - * If it is not, then it is the system sending us a dummy resize with - * zero dimensions on a "glutIconifyWindow" call. - */ - if( window->State.Visible ) - { - window->State.NeedToResize = GL_TRUE; -#if defined(_WIN32_WCE) - window->State.Width = HIWORD(lParam); - window->State.Height = LOWORD(lParam); -#else - window->State.Width = LOWORD(lParam); - window->State.Height = HIWORD(lParam); -#endif /* defined(_WIN32_WCE) */ - } - - break; - - case WM_SETFOCUS: -/* printf("WM_SETFOCUS: %p\n", window ); */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); - break; - - case WM_KILLFOCUS: -/* printf("WM_KILLFOCUS: %p\n", window ); */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); - - if( window->IsMenu && - window->ActiveMenu && window->ActiveMenu->IsActive ) - fgUpdateMenuHighlight( window->ActiveMenu ); - - break; - -#if 0 - case WM_ACTIVATE: - if (LOWORD(wParam) != WA_INACTIVE) - { -/* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window, - window->State.Cursor ); */ - fgSetCursor( window, window->State.Cursor ); - } - - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - break; -#endif - - case WM_SETCURSOR: -/* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */ - if( LOWORD( lParam ) == HTCLIENT ) - fgSetCursor ( window, window->State.Cursor ) ; - else - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - break; - - case WM_SHOWWINDOW: - window->State.Visible = GL_TRUE; - window->State.Redisplay = GL_TRUE; - break; - - case WM_PAINT: - /* Turn on the visibility in case it was turned off somehow */ - window->State.Visible = GL_TRUE; - BeginPaint( hWnd, &ps ); - fghRedrawWindow( window ); - EndPaint( hWnd, &ps ); - break; - - case WM_CLOSE: - // QB64 - /* - fgDestroyWindow ( window ); - if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) - PostQuitMessage(0); - */ - qb64_custom_event(QB64_EVENT_CLOSE, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL); - - break; - - case WM_DROPFILES: - qb64_custom_event(QB64_EVENT_FILE_DROP, 0, 0, 0, 0, 0, 0, 0, 0, (void *)wParam, NULL); - break; - - case WM_DESTROY: - /* - * The window already got destroyed, so don't bother with it. - */ - return 0; - - static int raw_setup = 0; - static RAWINPUTDEVICE Rid[1]; - case WM_INPUT: { - if (raw_setup) { - // QB64 - // adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/ee418864%28v=vs.85%29.aspx#WM_INPUT - UINT dwSize = sizeof(RAWINPUT); - static BYTE lpb[sizeof(RAWINPUT)]; - GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)); - RAWINPUT *raw = (RAWINPUT *)lpb; - if (raw->header.dwType == RIM_TYPEMOUSE) { - int xPosRelative = raw->data.mouse.lLastX; - int yPosRelative = raw->data.mouse.lLastY; - if (xPosRelative || yPosRelative) - qb64_custom_event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT, xPosRelative, yPosRelative, 0, 0, 0, 0, 0, 0, NULL, NULL); - } - } - break; - } - - case WM_MOUSEMOVE: { - - if (!raw_setup) { - raw_setup = 1; -# ifndef HID_USAGE_PAGE_GENERIC -# define HID_USAGE_PAGE_GENERIC ((USHORT)0x01) -# endif -# ifndef HID_USAGE_GENERIC_MOUSE -# define HID_USAGE_GENERIC_MOUSE ((USHORT)0x02) -# endif - Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; - Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; - Rid[0].dwFlags = RIDEV_INPUTSINK; - Rid[0].hwndTarget = window->Window.Handle; - RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])); - } - -# if defined(_WIN32_WCE) - window->State.MouseX = 320-HIWORD( lParam ); - window->State.MouseY = LOWORD( lParam ); -#else - window->State.MouseX = LOWORD( lParam ); - window->State.MouseY = HIWORD( lParam ); -#endif /* defined(_WIN32_WCE) */ - /* Restrict to [-32768, 32767] to match X11 behaviour */ - /* See comment in "freeglut_developer" mailing list 10/4/04 */ - if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; - if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; - - if ( window->ActiveMenu ) - { - fgUpdateMenuHighlight( window->ActiveMenu ); - break; - } - SetFocus(window->Window.Handle); - - fgState.Modifiers = fghGetWin32Modifiers( ); - - if( ( wParam & MK_LBUTTON ) || - ( wParam & MK_MBUTTON ) || - ( wParam & MK_RBUTTON ) ) - INVOKE_WCB( *window, Motion, ( window->State.MouseX, - window->State.MouseY ) ); - else - INVOKE_WCB( *window, Passive, ( window->State.MouseX, - window->State.MouseY ) ); - - fgState.Modifiers = INVALID_MODIFIERS; - } break; - - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - { - GLboolean pressed = GL_TRUE; - int button; - -#if defined(_WIN32_WCE) - window->State.MouseX = 320-HIWORD( lParam ); - window->State.MouseY = LOWORD( lParam ); -#else - window->State.MouseX = LOWORD( lParam ); - window->State.MouseY = HIWORD( lParam ); -#endif /* defined(_WIN32_WCE) */ - - /* Restrict to [-32768, 32767] to match X11 behaviour */ - /* See comment in "freeglut_developer" mailing list 10/4/04 */ - if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; - if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; - - switch( uMsg ) - { - case WM_LBUTTONDOWN: - pressed = GL_TRUE; - button = GLUT_LEFT_BUTTON; - break; - case WM_MBUTTONDOWN: - pressed = GL_TRUE; - button = GLUT_MIDDLE_BUTTON; - break; - case WM_RBUTTONDOWN: - pressed = GL_TRUE; - button = GLUT_RIGHT_BUTTON; - break; - case WM_LBUTTONUP: - pressed = GL_FALSE; - button = GLUT_LEFT_BUTTON; - break; - case WM_MBUTTONUP: - pressed = GL_FALSE; - button = GLUT_MIDDLE_BUTTON; - break; - case WM_RBUTTONUP: - pressed = GL_FALSE; - button = GLUT_RIGHT_BUTTON; - break; - default: - pressed = GL_FALSE; - button = -1; - break; - } - -#if !defined(_WIN32_WCE) - if( GetSystemMetrics( SM_SWAPBUTTON ) ) - { - if( button == GLUT_LEFT_BUTTON ) - button = GLUT_RIGHT_BUTTON; - else - if( button == GLUT_RIGHT_BUTTON ) - button = GLUT_LEFT_BUTTON; - } -#endif /* !defined(_WIN32_WCE) */ - - if( button == -1 ) - return DefWindowProc( hWnd, uMsg, lParam, wParam ); - - /* - * Do not execute the application's mouse callback if a menu - * is hooked to this button. In that case an appropriate - * private call should be generated. - */ - if( fgCheckActiveMenu( window, button, pressed, - window->State.MouseX, window->State.MouseY ) ) - break; - - /* Set capture so that the window captures all the mouse messages */ - /* - * XXX - Multiple button support: Under X11, the mouse is not released - * XXX - from the window until all buttons have been released, even if the - * XXX - user presses a button in another window. This will take more - * XXX - code changes than I am up to at the moment (10/5/04). The present - * XXX - is a 90 percent solution. - */ - if ( pressed == GL_TRUE ) - SetCapture ( window->Window.Handle ) ; - else - ReleaseCapture () ; - - if( ! FETCH_WCB( *window, Mouse ) ) - break; - - fgSetWindow( window ); - fgState.Modifiers = fghGetWin32Modifiers( ); - - INVOKE_WCB( - *window, Mouse, - ( button, - pressed ? GLUT_DOWN : GLUT_UP, - window->State.MouseX, - window->State.MouseY - ) - ); - - fgState.Modifiers = INVALID_MODIFIERS; - } - break; - - case 0x020a: - /* Should be WM_MOUSEWHEEL but my compiler doesn't recognize it */ - { - int wheel_number = LOWORD( wParam ); - short ticks = ( short )HIWORD( wParam ); - fgState.MouseWheelTicks += ticks; - - /* - * XXX Should use WHEEL_DELTA instead of 120 - */ - if ( abs ( fgState.MouseWheelTicks ) > 120 ) - { - int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; - - if( ! FETCH_WCB( *window, MouseWheel ) && - ! FETCH_WCB( *window, Mouse ) ) - break; - - fgSetWindow( window ); - fgState.Modifiers = fghGetWin32Modifiers( ); - - /* - * XXX Should use WHEEL_DELTA instead of 120 - */ - while( abs ( fgState.MouseWheelTicks ) > 120 ) - { - if( FETCH_WCB( *window, MouseWheel ) ) - INVOKE_WCB( *window, MouseWheel, - ( wheel_number, - direction, - window->State.MouseX, - window->State.MouseY - ) - ); - else /* No mouse wheel, call the mouse button callback twice */ - { - /* - * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4 - * " " one +1 to 5, -1 to 6, ... - * - * XXX The below assumes that you have no more than 3 mouse - * XXX buttons. Sorry. - */ - int button = wheel_number * 2 + 3; - if( direction < 0 ) - ++button; - INVOKE_WCB( *window, Mouse, - ( button, GLUT_DOWN, - window->State.MouseX, window->State.MouseY ) - ); - INVOKE_WCB( *window, Mouse, - ( button, GLUT_UP, - window->State.MouseX, window->State.MouseY ) - ); - } - - /* - * XXX Should use WHEEL_DELTA instead of 120 - */ - fgState.MouseWheelTicks -= 120 * direction; - } - - fgState.Modifiers = INVALID_MODIFIERS; - } - } - break ; - - case WM_SYSKEYDOWN: - case WM_KEYDOWN: - { - // QB64 - if (wParam == VK_PAUSE) { - qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_PAUSE, 1, 0, 0, 0, 0, 0, 0, NULL, NULL); - break; - } - if (wParam == VK_CANCEL) { - qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_BREAK, 1, 0, 0, 0, 0, 0, 0, NULL, NULL); - break; - } - - int keypress = -1; - POINT mouse_pos ; - - if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) - break; - - /* - * Remember the current modifiers state. This is done here in order - * to make sure the VK_DELETE keyboard callback is executed properly. - */ - fgState.Modifiers = fghGetWin32Modifiers( ); - - GetCursorPos( &mouse_pos ); - ScreenToClient( window->Window.Handle, &mouse_pos ); - - window->State.MouseX = mouse_pos.x; - window->State.MouseY = mouse_pos.y; - - /* Convert the Win32 keystroke codes to GLUTtish way */ -# define KEY(a,b) case a: keypress = b; break; - - switch( wParam ) - { - KEY( VK_F1, GLUT_KEY_F1 ); - KEY( VK_F2, GLUT_KEY_F2 ); - KEY( VK_F3, GLUT_KEY_F3 ); - KEY( VK_F4, GLUT_KEY_F4 ); - KEY( VK_F5, GLUT_KEY_F5 ); - KEY( VK_F6, GLUT_KEY_F6 ); - KEY( VK_F7, GLUT_KEY_F7 ); - KEY( VK_F8, GLUT_KEY_F8 ); - KEY( VK_F9, GLUT_KEY_F9 ); - KEY( VK_F10, GLUT_KEY_F10 ); - KEY( VK_F11, GLUT_KEY_F11 ); - KEY( VK_F12, GLUT_KEY_F12 ); - KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); - KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); - KEY( VK_HOME, GLUT_KEY_HOME ); - KEY( VK_END, GLUT_KEY_END ); - KEY( VK_LEFT, GLUT_KEY_LEFT ); - KEY( VK_UP, GLUT_KEY_UP ); - KEY( VK_RIGHT, GLUT_KEY_RIGHT ); - KEY( VK_DOWN, GLUT_KEY_DOWN ); - KEY( VK_INSERT, GLUT_KEY_INSERT ); - KEY( VK_LCONTROL, GLUT_KEY_CTRL_L ); - KEY( VK_RCONTROL, GLUT_KEY_CTRL_R ); - KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L ); - KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R ); - KEY( VK_LMENU, GLUT_KEY_ALT_L ); - KEY( VK_RMENU, GLUT_KEY_ALT_R ); - - case VK_DELETE: - /* The delete key should be treated as an ASCII keypress: */ - INVOKE_WCB( *window, Keyboard, - ( 127, window->State.MouseX, window->State.MouseY ) - ); - } - -#if defined(_WIN32_WCE) - if(!(lParam & 0x40000000)) /* Prevent auto-repeat */ - { - if(wParam==(unsigned)gxKeyList.vkRight) - keypress = GLUT_KEY_RIGHT; - else if(wParam==(unsigned)gxKeyList.vkLeft) - keypress = GLUT_KEY_LEFT; - else if(wParam==(unsigned)gxKeyList.vkUp) - keypress = GLUT_KEY_UP; - else if(wParam==(unsigned)gxKeyList.vkDown) - keypress = GLUT_KEY_DOWN; - else if(wParam==(unsigned)gxKeyList.vkA) - keypress = GLUT_KEY_F1; - else if(wParam==(unsigned)gxKeyList.vkB) - keypress = GLUT_KEY_F2; - else if(wParam==(unsigned)gxKeyList.vkC) - keypress = GLUT_KEY_F3; - else if(wParam==(unsigned)gxKeyList.vkStart) - keypress = GLUT_KEY_F4; - } -#endif - - if( keypress != -1 ) - INVOKE_WCB( *window, Special, - ( keypress, - window->State.MouseX, window->State.MouseY ) - ); - - fgState.Modifiers = INVALID_MODIFIERS; - } - break; - - case WM_SYSKEYUP: - case WM_KEYUP: - { - // QB64 - if (wParam == VK_PAUSE) { - qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_PAUSE, -1, 0, 0, 0, 0, 0, 0, NULL, NULL); - break; - } - if (wParam == VK_CANCEL) { - qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_BREAK, -1, 0, 0, 0, 0, 0, 0, NULL, NULL); - break; - } - - int keypress = -1; - POINT mouse_pos; - - /* - * Remember the current modifiers state. This is done here in order - * to make sure the VK_DELETE keyboard callback is executed properly. - */ - fgState.Modifiers = fghGetWin32Modifiers( ); - - GetCursorPos( &mouse_pos ); - ScreenToClient( window->Window.Handle, &mouse_pos ); - - window->State.MouseX = mouse_pos.x; - window->State.MouseY = mouse_pos.y; - - /* - * Convert the Win32 keystroke codes to GLUTtish way. - * "KEY(a,b)" was defined under "WM_KEYDOWN" - */ - - switch( wParam ) - { - KEY( VK_F1, GLUT_KEY_F1 ); - KEY( VK_F2, GLUT_KEY_F2 ); - KEY( VK_F3, GLUT_KEY_F3 ); - KEY( VK_F4, GLUT_KEY_F4 ); - KEY( VK_F5, GLUT_KEY_F5 ); - KEY( VK_F6, GLUT_KEY_F6 ); - KEY( VK_F7, GLUT_KEY_F7 ); - KEY( VK_F8, GLUT_KEY_F8 ); - KEY( VK_F9, GLUT_KEY_F9 ); - KEY( VK_F10, GLUT_KEY_F10 ); - KEY( VK_F11, GLUT_KEY_F11 ); - KEY( VK_F12, GLUT_KEY_F12 ); - KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); - KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); - KEY( VK_HOME, GLUT_KEY_HOME ); - KEY( VK_END, GLUT_KEY_END ); - KEY( VK_LEFT, GLUT_KEY_LEFT ); - KEY( VK_UP, GLUT_KEY_UP ); - KEY( VK_RIGHT, GLUT_KEY_RIGHT ); - KEY( VK_DOWN, GLUT_KEY_DOWN ); - KEY( VK_INSERT, GLUT_KEY_INSERT ); - KEY( VK_LCONTROL, GLUT_KEY_CTRL_L ); - KEY( VK_RCONTROL, GLUT_KEY_CTRL_R ); - KEY( VK_LSHIFT, GLUT_KEY_SHIFT_L ); - KEY( VK_RSHIFT, GLUT_KEY_SHIFT_R ); - KEY( VK_LMENU, GLUT_KEY_ALT_L ); - KEY( VK_RMENU, GLUT_KEY_ALT_R ); - - case VK_DELETE: - /* The delete key should be treated as an ASCII keypress: */ - INVOKE_WCB( *window, KeyboardUp, - ( 127, window->State.MouseX, window->State.MouseY ) - ); - break; - - default: - { -#if !defined(_WIN32_WCE) - BYTE state[ 256 ]; - WORD code[ 2 ]; - - GetKeyboardState( state ); - - if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 ) - wParam=code[ 0 ]; - - INVOKE_WCB( *window, KeyboardUp, - ( (char)wParam, - window->State.MouseX, window->State.MouseY ) - ); -#endif /* !defined(_WIN32_WCE) */ - } - } - - if( keypress != -1 ) - INVOKE_WCB( *window, SpecialUp, - ( keypress, - window->State.MouseX, window->State.MouseY ) - ); - - fgState.Modifiers = INVALID_MODIFIERS; - } break; - - case WM_SYSCHAR: - case WM_CHAR: - { - if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) ) - break; - - fgState.Modifiers = fghGetWin32Modifiers( ); - INVOKE_WCB( *window, Keyboard, - ( (char)wParam, - window->State.MouseX, window->State.MouseY ) - ); - fgState.Modifiers = INVALID_MODIFIERS; - } - break; - - case WM_CAPTURECHANGED: - /* User has finished resizing the window, force a redraw */ - INVOKE_WCB( *window, Display, ( ) ); - - /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */ - break; - - /* Other messages that I have seen and which are not handled already */ - case WM_SETTEXT: /* 0x000c */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - /* Pass it on to "DefWindowProc" to set the window text */ - break; - - case WM_GETTEXT: /* 0x000d */ - /* Ideally we would copy the title of the window into "lParam" */ - /* strncpy ( (char *)lParam, "Window Title", wParam ); - lRet = ( wParam > 12 ) ? 12 : wParam; */ - /* the number of characters copied */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - break; - - case WM_GETTEXTLENGTH: /* 0x000e */ - /* Ideally we would get the length of the title of the window */ - lRet = 12; - /* the number of characters in "Window Title\0" (see above) */ - break; - - case WM_ERASEBKGND: /* 0x0014 */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - break; - -#if !defined(_WIN32_WCE) - case WM_SYNCPAINT: /* 0x0088 */ - /* Another window has moved, need to update this one */ - window->State.Redisplay = GL_TRUE; - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - /* Help screen says this message must be passed to "DefWindowProc" */ - break; - - case WM_NCPAINT: /* 0x0085 */ - /* Need to update the border of this window */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - /* Pass it on to "DefWindowProc" to repaint a standard border */ - break; - - case WM_SYSCOMMAND : /* 0x0112 */ - { - /* - * We have received a system command message. Try to act on it. - * The commands are passed in through the "wParam" parameter: - * The least significant digit seems to be which edge of the window - * is being used for a resize event: - * 4 3 5 - * 1 2 - * 7 6 8 - * Congratulations and thanks to Richard Rauch for figuring this out.. - */ - switch ( wParam & 0xfff0 ) - { - case SC_SIZE : - break ; - - case SC_MOVE : - break ; - - case SC_MINIMIZE : - /* User has clicked on the "-" to minimize the window */ - /* Turn off the visibility */ - window->State.Visible = GL_FALSE ; - - break ; - - case SC_MAXIMIZE : - break ; - - case SC_NEXTWINDOW : - break ; - - case SC_PREVWINDOW : - break ; - - case SC_CLOSE : - /* Followed very closely by a WM_CLOSE message */ - break ; - - case SC_VSCROLL : - break ; - - case SC_HSCROLL : - break ; - - case SC_MOUSEMENU : - break ; - - case SC_KEYMENU : - break ; - - case SC_ARRANGE : - break ; - - case SC_RESTORE : - break ; - - case SC_TASKLIST : - break ; - - case SC_SCREENSAVE : - break ; - - case SC_HOTKEY : - break ; - -#if(WINVER >= 0x0400) - case SC_DEFAULT : - break ; - - case SC_MONITORPOWER : - break ; - - case SC_CONTEXTHELP : - break ; -#endif /* WINVER >= 0x0400 */ - - default: -#if _DEBUG - fgWarning( "Unknown wParam type 0x%x", wParam ); -#endif - break; - } - } -#endif /* !defined(_WIN32_WCE) */ - - /* We need to pass the message on to the operating system as well */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - break; - -#ifdef WM_TOUCH - /* handle multi-touch messages */ - case WM_TOUCH: - { - unsigned int numInputs = (unsigned int)wParam; - unsigned int i = 0; - TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs); - - if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) { - fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo"); - fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle"); - } - - if (!fghGetTouchInputInfo) { - free( (void*)ti ); - break; - } - - if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) { - /* Handle each contact point */ - for (i = 0; i < numInputs; ++i ) { - - POINT tp; - tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x); - tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y); - ScreenToClient( hWnd, &tp ); - - ti[i].dwID = ti[i].dwID * 2; - - if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { - INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) ); - INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) ); - } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { - INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) ); - } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { - INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) ); - INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) ); - } - } - } - fghCloseTouchInputHandle((HTOUCHINPUT)lParam); - free( (void*)ti ); - lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/ - break; - } -#endif - default: - /* Handle unhandled messages */ - lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); - break; - } - - qb64_os_event_info = 2; - qb64_os_event_return = qb64_os_event_windows(hWnd, uMsg, wParam, lParam, &qb64_os_event_info); - if (qb64_os_event_info == 3) - return qb64_os_event_return; - - return lRet; -} -#endif - -/*** END OF FILE ***/ +/* + * freeglut_main.c + * + * The windows message processing methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * 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. + */ + +#include +#include "freeglut_internal.h" +#ifdef HAVE_ERRNO_H +# include +#endif +#include +#ifdef HAVE_VFPRINTF +# define VFPRINTF(s,f,a) vfprintf((s),(f),(a)) +#elif defined(HAVE__DOPRNT) +# define VFPRINTF(s,f,a) _doprnt((f),(a),(s)) +#else +# define VFPRINTF(s,f,a) +#endif + +// QB64-PE: custom code begin +#include "../../../libqb/include/keyhandler.h" + +#define QB64_EVENT_CLOSE 1 +#define QB64_EVENT_KEY 2 +#define QB64_EVENT_RELATIVE_MOUSE_MOVEMENT 3 +#define QB64_EVENT_FILE_DROP 4 + +int qb64_custom_event(int event, int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, void *p1, void *p2); +#if TARGET_HOST_POSIX_X11 +void qb64_os_event_linux(XEvent *event, Display *display, int *qb64_os_event_info); +#else +LRESULT qb64_os_event_windows(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, int *qb64_os_event_info); +#endif +// QB64-PE: custom code end + +#ifdef _WIN32_WCE + +typedef struct GXDisplayProperties GXDisplayProperties; +typedef struct GXKeyList GXKeyList; +#include + +typedef struct GXKeyList (*GXGETDEFAULTKEYS)(int); +typedef int (*GXOPENINPUT)(); + +GXGETDEFAULTKEYS GXGetDefaultKeys_ = NULL; +GXOPENINPUT GXOpenInput_ = NULL; + +struct GXKeyList gxKeyList; + +#endif /* _WIN32_WCE */ + +/* + * Try to get the maximum value allowed for ints, falling back to the minimum + * guaranteed by ISO C99 if there is no suitable header. + */ +#ifdef HAVE_LIMITS_H +# include +#endif +#ifndef INT_MAX +# define INT_MAX 32767 +#endif + +#ifndef MIN +# define MIN(a,b) (((a)<(b)) ? (a) : (b)) +#endif + +#if TARGET_HOST_POSIX_X11 + /* used in the event handling code to match and discard stale mouse motion events */ + static Bool match_motion(Display *dpy, XEvent *xev, XPointer arg) + { + return xev->type == MotionNotify; + } +#endif + +#ifdef WM_TOUCH + typedef BOOL (WINAPI *pGetTouchInputInfo)(HTOUCHINPUT,UINT,PTOUCHINPUT,int); + typedef BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT); + static pGetTouchInputInfo fghGetTouchInputInfo = (pGetTouchInputInfo)0xDEADBEEF; + static pCloseTouchInputHandle fghCloseTouchInputHandle = (pCloseTouchInputHandle)0xDEADBEEF; +#endif + +#if TARGET_HOST_MS_WINDOWS + extern void fgPlatformCheckMenuDeactivate(); +#endif + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * There are some issues concerning window redrawing under X11, and maybe + * some events are not handled. The Win32 version lacks some more features, + * but seems acceptable for not demanding purposes. + * + * Need to investigate why the X11 version breaks out with an error when + * closing a window (using the window manager, not glutDestroyWindow)... + */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +/* + * Handle a window configuration change. When no reshape + * callback is hooked, the viewport size is updated to + * match the new window size. + */ +static void fghReshapeWindow ( SFG_Window *window, int width, int height ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window != NULL ); + +#if TARGET_HOST_POSIX_X11 + + XResizeWindow( fgDisplay.Display, window->Window.Handle, + width, height ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) + { + RECT windowRect; + + /* + * For windowed mode, get the current position of the + * window and resize taking the size of the frame + * decorations into account. + * + * Note on maximizing behavior of Windows: the resize borders are off + * the screen such that the client area extends all the way from the + * leftmost corner to the rightmost corner to maximize screen real + * estate. A caption is still shown however to allow interaction with + * the window controls. This is default behavior of Windows that + * FreeGLUT sticks with. To alter, one would have to check if + * WS_MAXIMIZE style is set when a resize event is triggered, and + * then manually correct the windowRect to put the borders back on + * screen. + */ + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( window->Window.Handle, &windowRect ); + + /* Create rect in FreeGLUT format, (X,Y) topleft outside window, WxH of client area */ + windowRect.right = windowRect.left+width; + windowRect.bottom = windowRect.top+height; + + if (window->Parent == NULL) + /* get the window rect from this to feed to SetWindowPos, correct for window decorations */ + fghComputeWindowRectFromClientArea_QueryWindow(&windowRect,window,TRUE); + else + { + /* correct rect for position client area of parent window + * (SetWindowPos input for child windows is in coordinates + * relative to the parent's client area). + * Child windows don't have decoration, so no need to correct + * for them. + */ + RECT parentRect; + fghGetClientArea( &parentRect, window->Parent, FALSE ); + OffsetRect(&windowRect,-parentRect.left,-parentRect.top); + } + + /* Do the actual resizing */ + SetWindowPos( window->Window.Handle, + HWND_TOP, + windowRect.left, windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom- windowRect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + } +#endif + + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + + /* + * Force a window redraw. In Windows at least this is only a partial + * solution: if the window is increasing in size in either dimension, + * the already-drawn part does not get drawn again and things look funny. + * But without this we get this bad behaviour whenever we resize the + * window. + * DN: Hmm.. the above sounds like a concern only in single buffered mode... + */ + window->State.Redisplay = GL_TRUE; + + if( window->IsMenu ) + fgSetWindow( current_window ); +} + +/* + * Calls a window's redraw method. This is used when + * a redraw is forced by the incoming window messages. + */ +static void fghRedrawWindow ( SFG_Window *window ) +{ + SFG_Window *current_window = fgStructure.CurrentWindow; + + freeglut_return_if_fail( window ); + freeglut_return_if_fail( FETCH_WCB ( *window, Display ) ); + + window->State.Redisplay = GL_FALSE; + + freeglut_return_if_fail( window->State.Visible ); + + fgSetWindow( window ); + + if( window->State.NeedToResize ) + { + /* Set need to resize to false before calling fghReshapeWindow, otherwise + in the case the user's reshape callback calls glutReshapeWindow, + his request would get canceled after fghReshapeWindow gets called. + */ + window->State.NeedToResize = GL_FALSE; + + fghReshapeWindow( + window, + window->State.Width, + window->State.Height + ); + } + + INVOKE_WCB( *window, Display, ( ) ); + + fgSetWindow( current_window ); +} + +/* + * A static helper function to execute display callback for a window + */ +static void fghcbDisplayWindow( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + if( window->State.Redisplay && + window->State.Visible ) + { + window->State.Redisplay = GL_FALSE; + +#if TARGET_HOST_POSIX_X11 + fghRedrawWindow ( window ) ; +#elif TARGET_HOST_MS_WINDOWS + + RedrawWindow( + window->Window.Handle, NULL, NULL, + RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE | RDW_UPDATENOW + ); +#endif + } + + fgEnumSubWindows( window, fghcbDisplayWindow, enumerator ); +} + +/* + * Make all windows perform a display call + */ +static void fghDisplayAll( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbDisplayWindow, &enumerator ); +} + +/* + * Window enumerator callback to check for the joystick polling code + */ +static void fghcbCheckJoystickPolls( SFG_Window *window, + SFG_Enumerator *enumerator ) +{ + long int checkTime = fgElapsedTime( ); + + if( window->State.JoystickLastPoll + window->State.JoystickPollRate <= + checkTime ) + { +#if !defined(_WIN32_WCE) + fgJoystickPollWindow( window ); +#endif /* !defined(_WIN32_WCE) */ + window->State.JoystickLastPoll = checkTime; + } + + fgEnumSubWindows( window, fghcbCheckJoystickPolls, enumerator ); +} + +/* + * Check all windows for joystick polling + */ +static void fghCheckJoystickPolls( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + + fgEnumWindows( fghcbCheckJoystickPolls, &enumerator ); +} + +/* + * Check the global timers + */ +static void fghCheckTimers( void ) +{ + long checkTime = fgElapsedTime( ); + + while( fgState.Timers.First ) + { + SFG_Timer *timer = fgState.Timers.First; + + if( timer->TriggerTime > checkTime ) + break; + + fgListRemove( &fgState.Timers, &timer->Node ); + fgListAppend( &fgState.FreeTimers, &timer->Node ); + + timer->Callback( timer->ID ); + } +} + + +/* Platform-dependent time in milliseconds, as an unsigned 32-bit integer. + * This value wraps every 49.7 days, but integer overflows cancel + * when subtracting an initial start time, unless the total time exceeds + * 32-bit, where the GLUT API return value is also overflowed. + */ +unsigned long fgSystemTime(void) { +#if TARGET_HOST_MS_WINDOWS +# if defined(_WIN32_WCE) + return GetTickCount(); +# else + return timeGetTime(); +# endif +#else +# ifdef CLOCK_MONOTONIC + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return now.tv_nsec/1000000 + now.tv_sec*1000; +# elif HAVE_GETTIMEOFDAY + struct timeval now; + gettimeofday( &now, NULL ); + return now.tv_usec/1000 + now.tv_sec*1000; +# endif +#endif +} + +/* + * Elapsed Time + */ +long fgElapsedTime( void ) +{ + return (long) (fgSystemTime() - fgState.Time); +} + +/* + * Error Messages. + */ +void fgError( const char *fmt, ... ) +{ + va_list ap; + + if (fgState.ErrorFunc) { + + va_start( ap, fmt ); + + /* call user set error handler here */ + fgState.ErrorFunc(fmt, ap); + + va_end( ap ); + + } else { + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); + + if ( fgState.Initialised ) + fgDeinitialize (); + + exit( 1 ); + } +} + +void fgWarning( const char *fmt, ... ) +{ + va_list ap; + + if (fgState.WarningFunc) { + + va_start( ap, fmt ); + + /* call user set warning handler here */ + fgState.WarningFunc(fmt, ap); + + va_end( ap ); + + } else { + + va_start( ap, fmt ); + + fprintf( stderr, "freeglut "); + if( fgState.ProgramName ) + fprintf( stderr, "(%s): ", fgState.ProgramName ); + VFPRINTF( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + + va_end( ap ); + } +} + + +/* + * Indicates whether Joystick events are being used by ANY window. + * + * The current mechanism is to walk all of the windows and ask if + * there is a joystick callback. We have a short-circuit early + * return if we find any joystick handler registered. + * + * The real way to do this is to make use of the glutTimer() API + * to more cleanly re-implement the joystick API. Then, this code + * and all other "joystick timer" code can be yanked. + * + */ +static void fghCheckJoystickCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( FETCH_WCB( *w, Joystick ) ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghCheckJoystickCallback, e ); +} +static int fghHaveJoystick( void ) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghCheckJoystickCallback, &enumerator ); + return !!enumerator.data; +} +static void fghHavePendingRedisplaysCallback( SFG_Window* w, SFG_Enumerator* e) +{ + if( w->State.Redisplay && w->State.Visible ) + { + e->found = GL_TRUE; + e->data = w; + } + fgEnumSubWindows( w, fghHavePendingRedisplaysCallback, e ); +} +static int fghHavePendingRedisplays (void) +{ + SFG_Enumerator enumerator; + + enumerator.found = GL_FALSE; + enumerator.data = NULL; + fgEnumWindows( fghHavePendingRedisplaysCallback, &enumerator ); + return !!enumerator.data; +} +/* + * Returns the number of GLUT ticks (milliseconds) till the next timer event. + */ +static long fghNextTimer( void ) +{ + long ret = INT_MAX; + SFG_Timer *timer = fgState.Timers.First; + + if( timer ) + ret = timer->TriggerTime - fgElapsedTime(); + if( ret < 0 ) + ret = 0; + + return ret; +} +/* + * Does the magic required to relinquish the CPU until something interesting + * happens. + */ +static void fghSleepForEvents( void ) +{ + long msec; + + if( fgState.IdleCallback || fghHavePendingRedisplays( ) ) + return; + + msec = fghNextTimer( ); + /* XXX Use GLUT timers for joysticks... */ + /* XXX Dumb; forces granularity to .01sec */ + if( fghHaveJoystick( ) && ( msec > 10 ) ) + msec = 10; + +#if TARGET_HOST_POSIX_X11 + /* + * Possibly due to aggressive use of XFlush() and friends, + * it is possible to have our socket drained but still have + * unprocessed events. (Or, this may just be normal with + * X, anyway?) We do non-trivial processing of X events + * after the event-reading loop, in any case, so we + * need to allow that we may have an empty socket but non- + * empty event queue. + */ + if( ! XPending( fgDisplay.Display ) ) + { + fd_set fdset; + int err; + int socket; + struct timeval wait; + + socket = ConnectionNumber( fgDisplay.Display ); + FD_ZERO( &fdset ); + FD_SET( socket, &fdset ); + wait.tv_sec = msec / 1000; + wait.tv_usec = (msec % 1000) * 1000; + err = select( socket+1, &fdset, NULL, NULL, &wait ); + +#ifdef HAVE_ERRNO_H + if( ( -1 == err ) && ( errno != EINTR ) ) + fgWarning ( "freeglut select() error: %d", errno ); +#endif + } +#elif TARGET_HOST_MS_WINDOWS + MsgWaitForMultipleObjects( 0, NULL, FALSE, msec, QS_ALLINPUT ); +#endif +} + +#if TARGET_HOST_POSIX_X11 +/* + * Returns GLUT modifier mask for the state field of an X11 event. + */ +int fghGetXModifiers( int state ) +{ + int ret = 0; + + if( state & ( ShiftMask | LockMask ) ) + ret |= GLUT_ACTIVE_SHIFT; + if( state & ControlMask ) + ret |= GLUT_ACTIVE_CTRL; + if( state & Mod1Mask ) + ret |= GLUT_ACTIVE_ALT; + + return ret; +} +#endif + + +#if TARGET_HOST_POSIX_X11 && _DEBUG + +static const char* fghTypeToString( int type ) +{ + switch( type ) { + case KeyPress: return "KeyPress"; + case KeyRelease: return "KeyRelease"; + case ButtonPress: return "ButtonPress"; + case ButtonRelease: return "ButtonRelease"; + case MotionNotify: return "MotionNotify"; + case EnterNotify: return "EnterNotify"; + case LeaveNotify: return "LeaveNotify"; + case FocusIn: return "FocusIn"; + case FocusOut: return "FocusOut"; + case KeymapNotify: return "KeymapNotify"; + case Expose: return "Expose"; + case GraphicsExpose: return "GraphicsExpose"; + case NoExpose: return "NoExpose"; + case VisibilityNotify: return "VisibilityNotify"; + case CreateNotify: return "CreateNotify"; + case DestroyNotify: return "DestroyNotify"; + case UnmapNotify: return "UnmapNotify"; + case MapNotify: return "MapNotify"; + case MapRequest: return "MapRequest"; + case ReparentNotify: return "ReparentNotify"; + case ConfigureNotify: return "ConfigureNotify"; + case ConfigureRequest: return "ConfigureRequest"; + case GravityNotify: return "GravityNotify"; + case ResizeRequest: return "ResizeRequest"; + case CirculateNotify: return "CirculateNotify"; + case CirculateRequest: return "CirculateRequest"; + case PropertyNotify: return "PropertyNotify"; + case SelectionClear: return "SelectionClear"; + case SelectionRequest: return "SelectionRequest"; + case SelectionNotify: return "SelectionNotify"; + case ColormapNotify: return "ColormapNotify"; + case ClientMessage: return "ClientMessage"; + case MappingNotify: return "MappingNotify"; + default: return "UNKNOWN"; + } +} + +static const char* fghBoolToString( Bool b ) +{ + return b == False ? "False" : "True"; +} + +static const char* fghNotifyHintToString( char is_hint ) +{ + switch( is_hint ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyHint: return "NotifyHint"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyModeToString( int mode ) +{ + switch( mode ) { + case NotifyNormal: return "NotifyNormal"; + case NotifyGrab: return "NotifyGrab"; + case NotifyUngrab: return "NotifyUngrab"; + case NotifyWhileGrabbed: return "NotifyWhileGrabbed"; + default: return "UNKNOWN"; + } +} + +static const char* fghNotifyDetailToString( int detail ) +{ + switch( detail ) { + case NotifyAncestor: return "NotifyAncestor"; + case NotifyVirtual: return "NotifyVirtual"; + case NotifyInferior: return "NotifyInferior"; + case NotifyNonlinear: return "NotifyNonlinear"; + case NotifyNonlinearVirtual: return "NotifyNonlinearVirtual"; + case NotifyPointer: return "NotifyPointer"; + case NotifyPointerRoot: return "NotifyPointerRoot"; + case NotifyDetailNone: return "NotifyDetailNone"; + default: return "UNKNOWN"; + } +} + +static const char* fghVisibilityToString( int state ) { + switch( state ) { + case VisibilityUnobscured: return "VisibilityUnobscured"; + case VisibilityPartiallyObscured: return "VisibilityPartiallyObscured"; + case VisibilityFullyObscured: return "VisibilityFullyObscured"; + default: return "UNKNOWN"; + } +} + +static const char* fghConfigureDetailToString( int detail ) +{ + switch( detail ) { + case Above: return "Above"; + case Below: return "Below"; + case TopIf: return "TopIf"; + case BottomIf: return "BottomIf"; + case Opposite: return "Opposite"; + default: return "UNKNOWN"; + } +} + +static const char* fghPlaceToString( int place ) +{ + switch( place ) { + case PlaceOnTop: return "PlaceOnTop"; + case PlaceOnBottom: return "PlaceOnBottom"; + default: return "UNKNOWN"; + } +} + +static const char* fghMappingRequestToString( int request ) +{ + switch( request ) { + case MappingModifier: return "MappingModifier"; + case MappingKeyboard: return "MappingKeyboard"; + case MappingPointer: return "MappingPointer"; + default: return "UNKNOWN"; + } +} + +static const char* fghPropertyStateToString( int state ) +{ + switch( state ) { + case PropertyNewValue: return "PropertyNewValue"; + case PropertyDelete: return "PropertyDelete"; + default: return "UNKNOWN"; + } +} + +static const char* fghColormapStateToString( int state ) +{ + switch( state ) { + case ColormapUninstalled: return "ColormapUninstalled"; + case ColormapInstalled: return "ColormapInstalled"; + default: return "UNKNOWN"; + } +} + +static void fghPrintEvent( XEvent *event ) +{ + switch( event->type ) { + + case KeyPress: + case KeyRelease: { + XKeyEvent *e = &event->xkey; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "keycode=%u, same_screen=%s", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->keycode, + fghBoolToString( e->same_screen ) ); + break; + } + + case ButtonPress: + case ButtonRelease: { + XButtonEvent *e = &event->xbutton; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "button=%u, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, e->button, + fghBoolToString( e->same_screen ) ); + break; + } + + case MotionNotify: { + XMotionEvent *e = &event->xmotion; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, " + "is_hint=%s, same_screen=%d", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, e->x_root, e->y_root, e->state, + fghNotifyHintToString( e->is_hint ), + fghBoolToString( e->same_screen ) ); + break; + } + + case EnterNotify: + case LeaveNotify: { + XCrossingEvent *e = &event->xcrossing; + fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, " + "(x,y)=(%d,%d), mode=%s, detail=%s, same_screen=%d, " + "focus=%d, state=0x%x", fghTypeToString( e->type ), + e->window, e->root, e->subwindow, (unsigned long)e->time, + e->x, e->y, fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ), (int)e->same_screen, + (int)e->focus, e->state ); + break; + } + + case FocusIn: + case FocusOut: { + XFocusChangeEvent *e = &event->xfocus; + fgWarning( "%s: window=0x%x, mode=%s, detail=%s", + fghTypeToString( e->type ), e->window, + fghNotifyModeToString( e->mode ), + fghNotifyDetailToString( e->detail ) ); + break; + } + + case KeymapNotify: { + XKeymapEvent *e = &event->xkeymap; + char buf[32 * 2 + 1]; + int i; + for ( i = 0; i < 32; i++ ) { + snprintf( &buf[ i * 2 ], sizeof( buf ) - i * 2, + "%02x", e->key_vector[ i ] ); + } + buf[ i ] = '\0'; + fgWarning( "%s: window=0x%x, %s", fghTypeToString( e->type ), e->window, + buf ); + break; + } + + case Expose: { + XExposeEvent *e = &event->xexpose; + fgWarning( "%s: window=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d", fghTypeToString( e->type ), e->window, e->x, + e->y, e->width, e->height, e->count ); + break; + } + + case GraphicsExpose: { + XGraphicsExposeEvent *e = &event->xgraphicsexpose; + fgWarning( "%s: drawable=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), " + "count=%d, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->x, e->y, + e->width, e->height, e->count, e->major_code, + e->minor_code ); + break; + } + + case NoExpose: { + XNoExposeEvent *e = &event->xnoexpose; + fgWarning( "%s: drawable=0x%x, (major_code,minor_code)=(%d,%d)", + fghTypeToString( e->type ), e->drawable, e->major_code, + e->minor_code ); + break; + } + + case VisibilityNotify: { + XVisibilityEvent *e = &event->xvisibility; + fgWarning( "%s: window=0x%x, state=%s", fghTypeToString( e->type ), + e->window, fghVisibilityToString( e->state) ); + break; + } + + case CreateNotify: { + XCreateWindowEvent *e = &event->xcreatewindow; + fgWarning( "%s: (x,y)=(%d,%d), (width,height)=(%d,%d), border_width=%d, " + "window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->x, e->y, e->width, e->height, + e->border_width, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case DestroyNotify: { + XDestroyWindowEvent *e = &event->xdestroywindow; + fgWarning( "%s: event=0x%x, window=0x%x", + fghTypeToString( e->type ), e->event, e->window ); + break; + } + + case UnmapNotify: { + XUnmapEvent *e = &event->xunmap; + fgWarning( "%s: event=0x%x, window=0x%x, from_configure=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->from_configure ) ); + break; + } + + case MapNotify: { + XMapEvent *e = &event->xmap; + fgWarning( "%s: event=0x%x, window=0x%x, override_redirect=%s", + fghTypeToString( e->type ), e->event, e->window, + fghBoolToString( e->override_redirect ) ); + break; + } + + case MapRequest: { + XMapRequestEvent *e = &event->xmaprequest; + fgWarning( "%s: parent=0x%x, window=0x%x", + fghTypeToString( event->type ), e->parent, e->window ); + break; + } + + case ReparentNotify: { + XReparentEvent *e = &event->xreparent; + fgWarning( "%s: event=0x%x, window=0x%x, parent=0x%x, (x,y)=(%d,%d), " + "override_redirect=%s", fghTypeToString( e->type ), + e->event, e->window, e->parent, e->x, e->y, + fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureNotify: { + XConfigureEvent *e = &event->xconfigure; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "override_redirect=%s", fghTypeToString( e->type ), e->event, + e->window, e->x, e->y, e->width, e->height, e->border_width, + e->above, fghBoolToString( e->override_redirect ) ); + break; + } + + case ConfigureRequest: { + XConfigureRequestEvent *e = &event->xconfigurerequest; + fgWarning( "%s: parent=0x%x, window=0x%x, (x,y)=(%d,%d), " + "(width,height)=(%d,%d), border_width=%d, above=0x%x, " + "detail=%s, value_mask=%lx", fghTypeToString( e->type ), + e->parent, e->window, e->x, e->y, e->width, e->height, + e->border_width, e->above, + fghConfigureDetailToString( e->detail ), e->value_mask ); + break; + } + + case GravityNotify: { + XGravityEvent *e = &event->xgravity; + fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d)", + fghTypeToString( e->type ), e->event, e->window, e->x, e->y ); + break; + } + + case ResizeRequest: { + XResizeRequestEvent *e = &event->xresizerequest; + fgWarning( "%s: window=0x%x, (width,height)=(%d,%d)", + fghTypeToString( e->type ), e->window, e->width, e->height ); + break; + } + + case CirculateNotify: { + XCirculateEvent *e = &event->xcirculate; + fgWarning( "%s: event=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->event, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case CirculateRequest: { + XCirculateRequestEvent *e = &event->xcirculaterequest; + fgWarning( "%s: parent=0x%x, window=0x%x, place=%s", + fghTypeToString( e->type ), e->parent, e->window, + fghPlaceToString( e->place ) ); + break; + } + + case PropertyNotify: { + XPropertyEvent *e = &event->xproperty; + fgWarning( "%s: window=0x%x, atom=%lu, time=%lu, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->atom, (unsigned long)e->time, + fghPropertyStateToString( e->state ) ); + break; + } + + case SelectionClear: { + XSelectionClearEvent *e = &event->xselectionclear; + fgWarning( "%s: window=0x%x, selection=%lu, time=%lu", + fghTypeToString( e->type ), e->window, + (unsigned long)e->selection, (unsigned long)e->time ); + break; + } + + case SelectionRequest: { + XSelectionRequestEvent *e = &event->xselectionrequest; + fgWarning( "%s: owner=0x%x, requestor=0x%x, selection=0x%x, " + "target=0x%x, property=%lu, time=%lu", + fghTypeToString( e->type ), e->owner, e->requestor, + (unsigned long)e->selection, (unsigned long)e->target, + (unsigned long)e->property, (unsigned long)e->time ); + break; + } + + case SelectionNotify: { + XSelectionEvent *e = &event->xselection; + fgWarning( "%s: requestor=0x%x, selection=0x%x, target=0x%x, " + "property=%lu, time=%lu", fghTypeToString( e->type ), + e->requestor, (unsigned long)e->selection, + (unsigned long)e->target, (unsigned long)e->property, + (unsigned long)e->time ); + break; + } + + case ColormapNotify: { + XColormapEvent *e = &event->xcolormap; + fgWarning( "%s: window=0x%x, colormap=%lu, new=%s, state=%s", + fghTypeToString( e->type ), e->window, + (unsigned long)e->colormap, fghBoolToString( e->new ), + fghColormapStateToString( e->state ) ); + break; + } + + case ClientMessage: { + XClientMessageEvent *e = &event->xclient; + char buf[ 61 ]; + char* p = buf; + char* end = buf + sizeof( buf ); + int i; + switch( e->format ) { + case 8: + for ( i = 0; i < 20; i++, p += 3 ) { + snprintf( p, end - p, " %02x", e->data.b[ i ] ); + } + break; + case 16: + for ( i = 0; i < 10; i++, p += 5 ) { + snprintf( p, end - p, " %04x", e->data.s[ i ] ); + } + break; + case 32: + for ( i = 0; i < 5; i++, p += 9 ) { + snprintf( p, end - p, " %08lx", e->data.l[ i ] ); + } + break; + } + *p = '\0'; + fgWarning( "%s: window=0x%x, message_type=%lu, format=%d, data=(%s )", + fghTypeToString( e->type ), e->window, + (unsigned long)e->message_type, e->format, buf ); + break; + } + + case MappingNotify: { + XMappingEvent *e = &event->xmapping; + fgWarning( "%s: window=0x%x, request=%s, first_keycode=%d, count=%d", + fghTypeToString( e->type ), e->window, + fghMappingRequestToString( e->request ), e->first_keycode, + e->count ); + break; + } + + default: { + fgWarning( "%s", fghTypeToString( event->type ) ); + break; + } + } +} + +#endif + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Executes a single iteration in the freeglut processing loop. + */ +void FGAPIENTRY glutMainLoopEvent( void ) +{ +#if TARGET_HOST_POSIX_X11 + SFG_Window* window; + XEvent event; + + /* This code was repeated constantly, so here it goes into a definition: */ +#define GETWINDOW(a) \ + window = fgWindowByHandle( event.a.window ); \ + if( window == NULL ) \ + break; + +#define GETMOUSE(a) \ + window->State.MouseX = event.a.x; \ + window->State.MouseY = event.a.y; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( XPending( fgDisplay.Display ) ) + { + XNextEvent( fgDisplay.Display, &event ); +#if _DEBUG + fghPrintEvent( &event ); +#endif + + // QB64-PE: custom code begin + int qb64_os_event_info = 0; + + qb64_os_event_info = 1; + qb64_os_event_linux(&event, fgDisplay.Display, &qb64_os_event_info); + if (qb64_os_event_info == 3) + return; + // QB64-PE: custom code end + + switch( event.type ) + { + case ClientMessage: + if (fgStructure.CurrentWindow) + if(fgIsSpaceballXEvent(&event)) { + fgSpaceballHandleXEvent(&event); + break; + } + /* Destroy the window when the WM_DELETE_WINDOW message arrives */ + if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.DeleteWindow ) + { + GETWINDOW( xclient ); + + // QB64-PE: custom code begin + qb64_custom_event(QB64_EVENT_CLOSE, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL); + + /* + fgDestroyWindow ( window ); + + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + + return; + */ + // QB64-PE: custom code end + } + break; + + /* + * CreateNotify causes a configure-event so that sub-windows are + * handled compatibly with GLUT. Otherwise, your sub-windows + * (in freeglut only) will not get an initial reshape event, + * which can break things. + * + * GLUT presumably does this because it generally tries to treat + * sub-windows the same as windows. + */ + case CreateNotify: + case ConfigureNotify: + { + int width, height; + if( event.type == CreateNotify ) { + GETWINDOW( xcreatewindow ); + width = event.xcreatewindow.width; + height = event.xcreatewindow.height; + } else { + GETWINDOW( xconfigure ); + width = event.xconfigure.width; + height = event.xconfigure.height; + } + + if( ( width != window->State.OldWidth ) || + ( height != window->State.OldHeight ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + window->State.OldWidth = width; + window->State.OldHeight = height; + if( FETCH_WCB( *window, Reshape ) ) + INVOKE_WCB( *window, Reshape, ( width, height ) ); + else + { + fgSetWindow( window ); + glViewport( 0, 0, width, height ); + } + glutPostRedisplay( ); + if( window->IsMenu ) + fgSetWindow( current_window ); + } + } + break; + + case DestroyNotify: + /* + * This is sent to confirm the XDestroyWindow call. + * + * XXX WHY is this commented out? Should we re-enable it? + */ + /* fgAddToWindowDestroyList ( window ); */ + break; + + case Expose: + /* + * We are too dumb to process partial exposes... + * + * XXX Well, we could do it. However, it seems to only + * XXX be potentially useful for single-buffered (since + * XXX double-buffered does not respect viewport when we + * XXX do a buffer-swap). + * + */ + if( event.xexpose.count == 0 ) + { + GETWINDOW( xexpose ); + window->State.Redisplay = GL_TRUE; + } + break; + + case MapNotify: + break; + + case UnmapNotify: + /* We get this when iconifying a window. */ + GETWINDOW( xunmap ); + INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) ); + window->State.Visible = GL_FALSE; + break; + + case MappingNotify: + /* + * Have the client's keyboard knowledge updated (xlib.ps, + * page 206, says that's a good thing to do) + */ + XRefreshKeyboardMapping( (XMappingEvent *) &event ); + break; + + case VisibilityNotify: + { + /* + * Sending this event, the X server can notify us that the window + * has just acquired one of the three possible visibility states: + * VisibilityUnobscured, VisibilityPartiallyObscured or + * VisibilityFullyObscured. Note that we DO NOT receive a + * VisibilityNotify event when iconifying a window, we only get an + * UnmapNotify then. + */ + GETWINDOW( xvisibility ); + switch( event.xvisibility.state ) + { + case VisibilityUnobscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityPartiallyObscured: + INVOKE_WCB( *window, WindowStatus, + ( GLUT_PARTIALLY_RETAINED ) ); + window->State.Visible = GL_TRUE; + break; + + case VisibilityFullyObscured: + INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) ); + window->State.Visible = GL_FALSE; + break; + + default: + fgWarning( "Unknown X visibility state: %d", + event.xvisibility.state ); + break; + } + } + break; + + case EnterNotify: + case LeaveNotify: + GETWINDOW( xcrossing ); + GETMOUSE( xcrossing ); + if( ( event.type == LeaveNotify ) && window->IsMenu && + window->ActiveMenu && window->ActiveMenu->IsActive ) + fgUpdateMenuHighlight( window->ActiveMenu ); + + INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ? + GLUT_ENTERED : + GLUT_LEFT ) ); + break; + + case MotionNotify: + { + /* if GLUT_SKIP_STALE_MOTION_EVENTS is true, then discard all but + * the last motion event from the queue + */ + if(fgState.SkipStaleMotion) { + while(XCheckIfEvent(fgDisplay.Display, &event, match_motion, 0)); + } + + GETWINDOW( xmotion ); + GETMOUSE( xmotion ); + + if( window->ActiveMenu ) + { + if( window == window->ActiveMenu->ParentWindow ) + { + window->ActiveMenu->Window->State.MouseX = + event.xmotion.x_root - window->ActiveMenu->X; + window->ActiveMenu->Window->State.MouseY = + event.xmotion.y_root - window->ActiveMenu->Y; + } + + fgUpdateMenuHighlight( window->ActiveMenu ); + + break; + } + + /* + * XXX For more than 5 buttons, just check {event.xmotion.state}, + * XXX rather than a host of bit-masks? Or maybe we need to + * XXX track ButtonPress/ButtonRelease events in our own + * XXX bit-mask? + */ + fgState.Modifiers = fghGetXModifiers( event.xmotion.state ); + if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) { + INVOKE_WCB( *window, Motion, ( event.xmotion.x, + event.xmotion.y ) ); + } else { + INVOKE_WCB( *window, Passive, ( event.xmotion.x, + event.xmotion.y ) ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case ButtonRelease: + case ButtonPress: + { + GLboolean pressed = GL_TRUE; + int button; + + if( event.type == ButtonRelease ) + pressed = GL_FALSE ; + + /* + * A mouse button has been pressed or released. Traditionally, + * break if the window was found within the freeglut structures. + */ + GETWINDOW( xbutton ); + GETMOUSE( xbutton ); + + /* + * An X button (at least in XFree86) is numbered from 1. + * A GLUT button is numbered from 0. + * Old GLUT passed through buttons other than just the first + * three, though it only gave symbolic names and official + * support to the first three. + */ + button = event.xbutton.button - 1; + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + event.xbutton.x_root, event.xbutton.y_root ) ) + break; + + /* + * Check if there is a mouse or mouse wheel callback hooked to the + * window + */ + if( ! FETCH_WCB( *window, Mouse ) && + ! FETCH_WCB( *window, MouseWheel ) ) + break; + + fgState.Modifiers = fghGetXModifiers( event.xbutton.state ); + + /* Finally execute the mouse or mouse wheel callback */ + if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) ) + INVOKE_WCB( *window, Mouse, ( button, + pressed ? GLUT_DOWN : GLUT_UP, + event.xbutton.x, + event.xbutton.y ) + ); + else + { + /* + * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1 + * " 6 and 7 " " one; ... + * + * XXX This *should* be behind some variables/macros, + * XXX since the order and numbering isn't certain + * XXX See XFree86 configuration docs (even back in the + * XXX 3.x days, and especially with 4.x). + * + * XXX Note that {button} has already been decremented + * XXX in mapping from X button numbering to GLUT. + * + * XXX Should add support for partial wheel turns as Windows does -- 5/27/11 + */ + int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2; + int direction = -1; + if( button % 2 ) + direction = 1; + + if( pressed ) + INVOKE_WCB( *window, MouseWheel, ( wheel_number, + direction, + event.xbutton.x, + event.xbutton.y ) + ); + } + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case KeyRelease: + case KeyPress: + { + FGCBKeyboard keyboard_cb; + FGCBSpecial special_cb; + + GETWINDOW( xkey ); + GETMOUSE( xkey ); + + /* Detect auto repeated keys, if configured globally or per-window */ + + if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) + { + if (event.type==KeyRelease) + { + /* + * Look at X11 keystate to detect repeat mode. + * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs. + */ + + char keys[32]; + XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */ + + if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */ + { + if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) ) + window->State.KeyRepeating = GL_TRUE; + else + window->State.KeyRepeating = GL_FALSE; + } + } + } + else + window->State.KeyRepeating = GL_FALSE; + + /* Cease processing this event if it is auto repeated */ + + if (window->State.KeyRepeating) + { + if (event.type == KeyPress) window->State.KeyRepeating = GL_FALSE; + break; + } + + if( event.type == KeyPress ) + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); + } + else + { + keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); + special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); + } + + /* Is there a keyboard/special callback hooked for this window? */ + if( keyboard_cb || special_cb ) + { + XComposeStatus composeStatus; + char asciiCode[ 32 ]; + KeySym keySym; + int len; + + /* Check for the ASCII/KeySym codes associated with the event: */ + len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), + &keySym, &composeStatus + ); + + /* GLUT API tells us to have two separate callbacks... */ + if( len > 0 ) + { + /* ...one for the ASCII translateable keypresses... */ + if( keyboard_cb ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + keyboard_cb( asciiCode[ 0 ], + event.xkey.x, event.xkey.y + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + else + { + int special = -1; + + /* + * ...and one for all the others, which need to be + * translated to GLUT_KEY_Xs... + */ + switch( keySym ) + { + case XK_F1: special = GLUT_KEY_F1; break; + case XK_F2: special = GLUT_KEY_F2; break; + case XK_F3: special = GLUT_KEY_F3; break; + case XK_F4: special = GLUT_KEY_F4; break; + case XK_F5: special = GLUT_KEY_F5; break; + case XK_F6: special = GLUT_KEY_F6; break; + case XK_F7: special = GLUT_KEY_F7; break; + case XK_F8: special = GLUT_KEY_F8; break; + case XK_F9: special = GLUT_KEY_F9; break; + case XK_F10: special = GLUT_KEY_F10; break; + case XK_F11: special = GLUT_KEY_F11; break; + case XK_F12: special = GLUT_KEY_F12; break; + + case XK_KP_Left: + case XK_Left: special = GLUT_KEY_LEFT; break; + case XK_KP_Right: + case XK_Right: special = GLUT_KEY_RIGHT; break; + case XK_KP_Up: + case XK_Up: special = GLUT_KEY_UP; break; + case XK_KP_Down: + case XK_Down: special = GLUT_KEY_DOWN; break; + + case XK_KP_Prior: + case XK_Prior: special = GLUT_KEY_PAGE_UP; break; + case XK_KP_Next: + case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; + case XK_KP_Home: + case XK_Home: special = GLUT_KEY_HOME; break; + case XK_KP_End: + case XK_End: special = GLUT_KEY_END; break; + case XK_KP_Insert: + case XK_Insert: special = GLUT_KEY_INSERT; break; + + case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; + case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; + case XK_KP_Delete: special = GLUT_KEY_DELETE; break; + + case XK_Shift_L: special = GLUT_KEY_SHIFT_L; break; + case XK_Shift_R: special = GLUT_KEY_SHIFT_R; break; + case XK_Control_L: special = GLUT_KEY_CTRL_L; break; + case XK_Control_R: special = GLUT_KEY_CTRL_R; break; + case XK_Alt_L: special = GLUT_KEY_ALT_L; break; + case XK_Alt_R: special = GLUT_KEY_ALT_R; break; + } + + /* + * Execute the callback (if one has been specified), + * given that the special code seems to be valid... + */ + if( special_cb && (special != -1) ) + { + fgSetWindow( window ); + fgState.Modifiers = fghGetXModifiers( event.xkey.state ); + special_cb( special, event.xkey.x, event.xkey.y ); + fgState.Modifiers = INVALID_MODIFIERS; + } + } + } + } + break; + + case ReparentNotify: + break; /* XXX Should disable this event */ + + /* Not handled */ + case GravityNotify: + break; + + default: + /* enter handling of Extension Events here */ + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + fgHandleExtensionEvents( &event ); + #endif + break; + } + + // QB64-PE: custom code begin + qb64_os_event_info = 2; + qb64_os_event_linux(&event, fgDisplay.Display, &qb64_os_event_info); + if (qb64_os_event_info == 3) + return; //(although we would return anyway) + // QB64-PE: custom code end + } + +#elif TARGET_HOST_MS_WINDOWS + + MSG stMsg; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" ); + + while( PeekMessage( &stMsg, NULL, 0, 0, PM_NOREMOVE ) ) + { + if( GetMessage( &stMsg, NULL, 0, 0 ) == 0 ) + { + if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT ) + { + fgDeinitialize( ); + exit( 0 ); + } + else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + + return; + } + + TranslateMessage( &stMsg ); + DispatchMessage( &stMsg ); + } +#endif + + if( fgState.Timers.First ) + fghCheckTimers( ); + fghCheckJoystickPolls( ); + fghDisplayAll( ); + + fgCloseWindows( ); +} + +/* + * Enters the freeglut processing loop. + * Stays until the "ExecState" changes to "GLUT_EXEC_STATE_STOP". + */ +void FGAPIENTRY glutMainLoop( void ) +{ + int action; + +#if TARGET_HOST_MS_WINDOWS + SFG_Window *window = (SFG_Window *)fgStructure.Windows.First ; +#endif + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoop" ); + +#if TARGET_HOST_MS_WINDOWS + /* + * Processing before the main loop: If there is a window which is open and + * which has a visibility callback, call it. I know this is an ugly hack, + * but I'm not sure what else to do about it. Ideally we should leave + * something uninitialized in the create window code and initialize it in + * the main loop, and have that initialization create a "WM_ACTIVATE" + * message. Then we would put the visibility callback code in the + * "case WM_ACTIVATE" block below. - John Fay -- 10/24/02 + */ + while( window ) + { + if ( FETCH_WCB( *window, Visibility ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow ; + + INVOKE_WCB( *window, Visibility, ( window->State.Visible ) ); + fgSetWindow( current_window ); + } + + window = (SFG_Window *)window->Node.Next ; + } +#endif + + fgState.ExecState = GLUT_EXEC_STATE_RUNNING ; + while( fgState.ExecState == GLUT_EXEC_STATE_RUNNING ) + { + SFG_Window *window; + + glutMainLoopEvent( ); + /* + * Step through the list of windows, seeing if there are any + * that are not menus + */ + for( window = ( SFG_Window * )fgStructure.Windows.First; + window; + window = ( SFG_Window * )window->Node.Next ) + if ( ! ( window->IsMenu ) ) + break; + + if( ! window ) + fgState.ExecState = GLUT_EXEC_STATE_STOP; + else + { + if( fgState.IdleCallback ) + { + if( fgStructure.CurrentWindow && + fgStructure.CurrentWindow->IsMenu ) + /* fail safe */ + fgSetWindow( window ); + fgState.IdleCallback( ); + } + + fghSleepForEvents( ); + } + } + + /* + * When this loop terminates, destroy the display, state and structure + * of a freeglut session, so that another glutInit() call can happen + * + * Save the "ActionOnWindowClose" because "fgDeinitialize" resets it. + */ + action = fgState.ActionOnWindowClose; + fgDeinitialize( ); + if( action == GLUT_ACTION_EXIT ) + exit( 0 ); +} + +/* + * Leaves the freeglut processing loop. + */ +void FGAPIENTRY glutLeaveMainLoop( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveMainLoop" ); + fgState.ExecState = GLUT_EXEC_STATE_STOP ; +} + + +#if TARGET_HOST_MS_WINDOWS +/* + * Determine a GLUT modifer mask based on MS-WINDOWS system info. + */ +static int fghGetWin32Modifiers (void) +{ + return + ( ( ( GetKeyState( VK_LSHIFT ) < 0 ) || + ( GetKeyState( VK_RSHIFT ) < 0 )) ? GLUT_ACTIVE_SHIFT : 0 ) | + ( ( ( GetKeyState( VK_LCONTROL ) < 0 ) || + ( GetKeyState( VK_RCONTROL ) < 0 )) ? GLUT_ACTIVE_CTRL : 0 ) | + ( ( ( GetKeyState( VK_LMENU ) < 0 ) || + ( GetKeyState( VK_RMENU ) < 0 )) ? GLUT_ACTIVE_ALT : 0 ); +} + +/* + * The window procedure for handling Win32 events + */ +LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam ) +{ + // QB64-PE: custom code begin + static int raw_setup = 0; + static RAWINPUTDEVICE Rid[1]; + int qb64_os_event_info = 0; + LRESULT qb64_os_event_return = 1; + + qb64_os_event_info = 1; + qb64_os_event_return = qb64_os_event_windows(hWnd, uMsg, wParam, lParam, &qb64_os_event_info); + if (qb64_os_event_info == 3) + return qb64_os_event_return; + // QB64-PE: custom code end + + static unsigned char lControl = 0, rControl = 0, lShift = 0, + rShift = 0, lAlt = 0, rAlt = 0; + + SFG_Window* window, *child_window = NULL; + PAINTSTRUCT ps; + LRESULT lRet = 1; + + FREEGLUT_INTERNAL_ERROR_EXIT_IF_NOT_INITIALISED ( "Event Handler" ) ; + + window = fgWindowByHandle( hWnd ); + + if ( ( window == NULL ) && ( uMsg != WM_CREATE ) ) + return DefWindowProc( hWnd, uMsg, wParam, lParam ); + + /* printf ( "Window %3d message <%04x> %12d %12d\n", window?window->ID:0, + uMsg, wParam, lParam ); */ + + /* Some events only sent to main window. Check if the current window that + * the mouse is over is a child window. Below when handling some messages, + * we make sure that we process callbacks on the child window instead. + * This mirrors how GLUT does things. + */ + if (window && window->Children.First) + { + POINT mouse_pos; + SFG_WindowHandleType hwnd; + SFG_Window* temp_window; + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + hwnd = ChildWindowFromPoint(window->Window.Handle, mouse_pos); + if (hwnd) /* can be NULL if mouse outside parent by the time we get here */ + { + temp_window = fgWindowByHandle(hwnd); + if (temp_window && temp_window->Parent) /* Verify we got a child window */ + child_window = temp_window; + } + } + + if ( window ) + { + SFG_Window* temp_window = child_window?child_window:window; + + fgState.Modifiers = fghGetWin32Modifiers( ); + + /* Checking for CTRL, ALT, and SHIFT key positions: Key Down! */ + if ( !lControl && GetAsyncKeyState ( VK_LCONTROL ) ) + { + INVOKE_WCB ( *temp_window, Special, + ( GLUT_KEY_CTRL_L, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + lControl = 1; + } + + if ( !rControl && GetAsyncKeyState ( VK_RCONTROL ) ) + { + INVOKE_WCB ( *temp_window, Special, + ( GLUT_KEY_CTRL_R, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + rControl = 1; + } + + if ( !lShift && GetAsyncKeyState ( VK_LSHIFT ) ) + { + INVOKE_WCB ( *temp_window, Special, + ( GLUT_KEY_SHIFT_L, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + lShift = 1; + } + + if ( !rShift && GetAsyncKeyState ( VK_RSHIFT ) ) + { + INVOKE_WCB ( *temp_window, Special, + ( GLUT_KEY_SHIFT_R, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + rShift = 1; + } + + if ( !lAlt && GetAsyncKeyState ( VK_LMENU ) ) + { + INVOKE_WCB ( *temp_window, Special, + ( GLUT_KEY_ALT_L, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + lAlt = 1; + } + + if ( !rAlt && GetAsyncKeyState ( VK_RMENU ) ) + { + INVOKE_WCB ( *temp_window, Special, + ( GLUT_KEY_ALT_R, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + rAlt = 1; + } + + /* Checking for CTRL, ALT, and SHIFT key positions: Key Up! */ + if ( lControl && !GetAsyncKeyState ( VK_LCONTROL ) ) + { + INVOKE_WCB ( *temp_window, SpecialUp, + ( GLUT_KEY_CTRL_L, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + lControl = 0; + } + + if ( rControl && !GetAsyncKeyState ( VK_RCONTROL ) ) + { + INVOKE_WCB ( *temp_window, SpecialUp, + ( GLUT_KEY_CTRL_R, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + rControl = 0; + } + + if ( lShift && !GetAsyncKeyState ( VK_LSHIFT ) ) + { + INVOKE_WCB ( *temp_window, SpecialUp, + ( GLUT_KEY_SHIFT_L, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + lShift = 0; + } + + if ( rShift && !GetAsyncKeyState ( VK_RSHIFT ) ) + { + INVOKE_WCB ( *temp_window, SpecialUp, + ( GLUT_KEY_SHIFT_R, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + rShift = 0; + } + + if ( lAlt && !GetAsyncKeyState ( VK_LMENU ) ) + { + INVOKE_WCB ( *temp_window, SpecialUp, + ( GLUT_KEY_ALT_L, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + lAlt = 0; + } + + if ( rAlt && !GetAsyncKeyState ( VK_RMENU ) ) + { + INVOKE_WCB ( *temp_window, SpecialUp, + ( GLUT_KEY_ALT_R, temp_window->State.MouseX, temp_window->State.MouseY ) + ); + + rAlt = 0; + } + + fgState.Modifiers = INVALID_MODIFIERS; + } + + switch( uMsg ) + { + case WM_CREATE: + /* The window structure is passed as the creation structure parameter... */ + window = (SFG_Window *) (((LPCREATESTRUCT) lParam)->lpCreateParams); + FREEGLUT_INTERNAL_ERROR_EXIT ( ( window != NULL ), "Cannot create window", + "fgWindowProc" ); + + window->Window.Handle = hWnd; + window->Window.Device = GetDC( hWnd ); + if( window->IsMenu ) + { + unsigned int current_DisplayMode = fgState.DisplayMode; + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH; +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + fgState.DisplayMode = current_DisplayMode; + + if( fgStructure.MenuContext ) + wglMakeCurrent( window->Window.Device, + fgStructure.MenuContext->MContext + ); + else + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = + wglCreateContext( window->Window.Device ); + } + + /* window->Window.Context = wglGetCurrentContext (); */ + window->Window.Context = wglCreateContext( window->Window.Device ); + } + else + { +#if !defined(_WIN32_WCE) + fgSetupPixelFormat( window, GL_FALSE, PFD_MAIN_PLANE ); +#endif + + if( ! fgState.UseCurrentContext ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + else + { + window->Window.Context = wglGetCurrentContext( ); + if( ! window->Window.Context ) + window->Window.Context = + wglCreateContext( window->Window.Device ); + } + +#if !defined(_WIN32_WCE) + fgNewWGLCreateContext( window ); +#endif + } + + window->State.NeedToResize = GL_TRUE; + /* if we used CW_USEDEFAULT (thats a negative value) for the size + * of the window, query the window now for the size at which it + * was created. + */ + if( ( window->State.Width < 0 ) || ( window->State.Height < 0 ) ) + { + SFG_Window *current_window = fgStructure.CurrentWindow; + + fgSetWindow( window ); + window->State.Width = glutGet( GLUT_WINDOW_WIDTH ); + window->State.Height = glutGet( GLUT_WINDOW_HEIGHT ); + fgSetWindow( current_window ); + } + + ReleaseDC( window->Window.Handle, window->Window.Device ); + +#if defined(_WIN32_WCE) + /* Take over button handling */ + { + HINSTANCE dxDllLib=LoadLibrary(_T("gx.dll")); + if (dxDllLib) + { + GXGetDefaultKeys_=(GXGETDEFAULTKEYS)GetProcAddress(dxDllLib, _T("?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z")); + GXOpenInput_=(GXOPENINPUT)GetProcAddress(dxDllLib, _T("?GXOpenInput@@YAHXZ")); + } + + if(GXOpenInput_) + (*GXOpenInput_)(); + if(GXGetDefaultKeys_) + gxKeyList = (*GXGetDefaultKeys_)(GX_LANDSCAPEKEYS); + } + +#endif /* defined(_WIN32_WCE) */ + break; + + case WM_SIZE: + /* + * If the window is visible, then it is the user manually resizing it. + * If it is not, then it is the system sending us a dummy resize with + * zero dimensions on a "glutIconifyWindow" call. + */ + if( window->State.Visible ) + { + window->State.NeedToResize = GL_TRUE; +#if defined(_WIN32_WCE) + window->State.Width = HIWORD(lParam); + window->State.Height = LOWORD(lParam); +#else + window->State.Width = LOWORD(lParam); + window->State.Height = HIWORD(lParam); +#endif /* defined(_WIN32_WCE) */ + } + + break; + + case WM_SETFOCUS: +/* printf("WM_SETFOCUS: %p\n", window ); */ + + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + + if (child_window) + { + /* If child should have focus instead, set it here. */ + SetFocus(child_window->Window.Handle); + SetActiveWindow( child_window->Window.Handle ); + INVOKE_WCB( *child_window, Entry, ( GLUT_ENTERED ) ); + UpdateWindow ( child_window->Window.Handle ); + } + else + { + SetActiveWindow( window->Window.Handle ); + INVOKE_WCB( *window, Entry, ( GLUT_ENTERED ) ); + } + /* Always request update on main window to be safe */ + UpdateWindow ( hWnd ); + break; + + case WM_KILLFOCUS: + { + SFG_Window* saved_window = fgStructure.CurrentWindow; +/* printf("WM_KILLFOCUS: %p\n", window ); */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + INVOKE_WCB( *window, Entry, ( GLUT_LEFT ) ); + fgSetWindow(saved_window); + + /* Check if there are any open menus that need to be closed */ + fgPlatformCheckMenuDeactivate(); + } + break; + +#if 0 + case WM_ACTIVATE: + if (LOWORD(wParam) != WA_INACTIVE) + { +/* printf("WM_ACTIVATE: fgSetCursor( %p, %d)\n", window, + window->State.Cursor ); */ + fgSetCursor( window, window->State.Cursor ); + } + + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; +#endif + + case WM_SETCURSOR: +/* printf ( "Cursor event %x %x %x %x\n", window, window->State.Cursor, lParam, wParam ) ; */ + if( LOWORD( lParam ) == HTCLIENT ) + fgSetCursor ( window, window->State.Cursor ) ; + else + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_SHOWWINDOW: + window->State.Visible = GL_TRUE; + window->State.Redisplay = GL_TRUE; + break; + + case WM_PAINT: + /* Turn on the visibility in case it was turned off somehow */ + window->State.Visible = GL_TRUE; + InvalidateRect( hWnd, NULL, GL_FALSE ); /* Make sure whole window is repainted. Bit of a hack, but a safe one from what google turns up... */ + BeginPaint( hWnd, &ps ); + fghRedrawWindow( window ); + EndPaint( hWnd, &ps ); + break; + + case WM_CLOSE: + // QB64-PE: custom code begin + qb64_custom_event(QB64_EVENT_CLOSE, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL); + /* + fgDestroyWindow ( window ); + if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION ) + PostQuitMessage(0); + */ + // QB64-PE: custom code end + break; + + // QB64-PE: custom code begin + case WM_DROPFILES: + qb64_custom_event(QB64_EVENT_FILE_DROP, 0, 0, 0, 0, 0, 0, 0, 0, (void *)wParam, NULL); + break; + // QB64-PE: custom code end + + case WM_DESTROY: + /* + * The window already got destroyed, so don't bother with it. + */ + return 0; + + // QB64-PE: custom code begin + case WM_INPUT: { + if (raw_setup) { + // Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/ee418864%28v=vs.85%29.aspx#WM_INPUT + UINT dwSize = sizeof(RAWINPUT); + static BYTE lpb[sizeof(RAWINPUT)]; + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)); + RAWINPUT *raw = (RAWINPUT *)lpb; + if (raw->header.dwType == RIM_TYPEMOUSE) { + int xPosRelative = raw->data.mouse.lLastX; + int yPosRelative = raw->data.mouse.lLastY; + if (xPosRelative || yPosRelative) + qb64_custom_event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT, xPosRelative, yPosRelative, 0, 0, 0, 0, 0, 0, NULL, NULL); + } + } + break; + } + // QB64-PE: custom code end + + case WM_MOUSEMOVE: + { + // QB64-PE: custom code begin + if (!raw_setup) { + raw_setup = 1; +# ifndef HID_USAGE_PAGE_GENERIC +# define HID_USAGE_PAGE_GENERIC ((USHORT)0x01) +# endif +# ifndef HID_USAGE_GENERIC_MOUSE +# define HID_USAGE_GENERIC_MOUSE ((USHORT)0x02) +# endif + Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; + Rid[0].dwFlags = RIDEV_INPUTSINK; + Rid[0].hwndTarget = window->Window.Handle; + RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])); + } + // QB64-PE: custom code end + +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + if ( window->ActiveMenu ) + { + fgUpdateMenuHighlight( window->ActiveMenu ); + break; + } + + fgState.Modifiers = fghGetWin32Modifiers( ); + + if( ( wParam & MK_LBUTTON ) || + ( wParam & MK_MBUTTON ) || + ( wParam & MK_RBUTTON ) ) + INVOKE_WCB( *window, Motion, ( window->State.MouseX, + window->State.MouseY ) ); + else + INVOKE_WCB( *window, Passive, ( window->State.MouseX, + window->State.MouseY ) ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + { + GLboolean pressed = GL_TRUE; + int button; + +#if defined(_WIN32_WCE) + window->State.MouseX = 320-HIWORD( lParam ); + window->State.MouseY = LOWORD( lParam ); +#else + window->State.MouseX = LOWORD( lParam ); + window->State.MouseY = HIWORD( lParam ); +#endif /* defined(_WIN32_WCE) */ + + /* Restrict to [-32768, 32767] to match X11 behaviour */ + /* See comment in "freeglut_developer" mailing list 10/4/04 */ + if ( window->State.MouseX > 32767 ) window->State.MouseX -= 65536; + if ( window->State.MouseY > 32767 ) window->State.MouseY -= 65536; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONDOWN: + pressed = GL_TRUE; + button = GLUT_RIGHT_BUTTON; + break; + case WM_LBUTTONUP: + pressed = GL_FALSE; + button = GLUT_LEFT_BUTTON; + break; + case WM_MBUTTONUP: + pressed = GL_FALSE; + button = GLUT_MIDDLE_BUTTON; + break; + case WM_RBUTTONUP: + pressed = GL_FALSE; + button = GLUT_RIGHT_BUTTON; + break; + default: + pressed = GL_FALSE; + button = -1; + break; + } + +#if !defined(_WIN32_WCE) + if( GetSystemMetrics( SM_SWAPBUTTON ) ) + { + if( button == GLUT_LEFT_BUTTON ) + button = GLUT_RIGHT_BUTTON; + else + if( button == GLUT_RIGHT_BUTTON ) + button = GLUT_LEFT_BUTTON; + } +#endif /* !defined(_WIN32_WCE) */ + + if( button == -1 ) + return DefWindowProc( hWnd, uMsg, lParam, wParam ); + + /* + * Do not execute the application's mouse callback if a menu + * is hooked to this button. In that case an appropriate + * private call should be generated. + */ + if( fgCheckActiveMenu( window, button, pressed, + window->State.MouseX, window->State.MouseY ) ) + break; + + /* Set capture so that the window captures all the mouse messages */ + /* + * XXX - Multiple button support: Under X11, the mouse is not released + * XXX - from the window until all buttons have been released, even if the + * XXX - user presses a button in another window. This will take more + * XXX - code changes than I am up to at the moment (10/5/04). The present + * XXX - is a 90 percent solution. + */ + if ( pressed == GL_TRUE ) + SetCapture ( window->Window.Handle ) ; + else + ReleaseCapture () ; + + if( ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + INVOKE_WCB( + *window, Mouse, + ( button, + pressed ? GLUT_DOWN : GLUT_UP, + window->State.MouseX, + window->State.MouseY + ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_MOUSEWHEEL: + { + int wheel_number = LOWORD( wParam ); + short ticks = ( short )HIWORD( wParam ); + fgState.MouseWheelTicks += ticks; + + /* + * XXX Should use WHEEL_DELTA instead of 120 + */ + if ( abs ( fgState.MouseWheelTicks ) >= 120 ) + { + int direction = ( fgState.MouseWheelTicks > 0 ) ? 1 : -1; + + if( ! FETCH_WCB( *window, MouseWheel ) && + ! FETCH_WCB( *window, Mouse ) ) + break; + + fgSetWindow( window ); + fgState.Modifiers = fghGetWin32Modifiers( ); + + /* + * XXX Should use WHEEL_DELTA instead of 120 + */ + while( abs ( fgState.MouseWheelTicks ) >= 120 ) + { + if( FETCH_WCB( *window, MouseWheel ) ) + INVOKE_WCB( *window, MouseWheel, + ( wheel_number, + direction, + window->State.MouseX, + window->State.MouseY + ) + ); + else /* No mouse wheel, call the mouse button callback twice */ + { + /* + * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4 + * " " one +1 to 5, -1 to 6, ... + * + * XXX The below assumes that you have no more than 3 mouse + * XXX buttons. Sorry. + */ + int button = wheel_number * 2 + 3; + if( direction < 0 ) + ++button; + INVOKE_WCB( *window, Mouse, + ( button, GLUT_DOWN, + window->State.MouseX, window->State.MouseY ) + ); + INVOKE_WCB( *window, Mouse, + ( button, GLUT_UP, + window->State.MouseX, window->State.MouseY ) + ); + } + + /* + * XXX Should use WHEEL_DELTA instead of 120 + */ + fgState.MouseWheelTicks -= 120 * direction; + } + + fgState.Modifiers = INVALID_MODIFIERS; + } + } + break ; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + { + // QB64-PE: custom code begin + if (wParam == VK_PAUSE) { + qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_PAUSE, 1, 0, 0, 0, 0, 0, 0, NULL, NULL); + break; + } + if (wParam == VK_CANCEL) { + qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_BREAK, 1, 0, 0, 0, 0, 0, 0, NULL, NULL); + break; + } + // QB64-PE: custom code end + + int keypress = -1; + POINT mouse_pos ; + + if (child_window) + window = child_window; + + if( ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE ) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* Convert the Win32 keystroke codes to GLUTtish way */ +# define KEY(a,b) case a: keypress = b; break; + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + + case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL: + case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT: + case VK_LMENU: case VK_RMENU: case VK_MENU: + /* These keypresses and releases are handled earlier in the function */ + break; + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, Keyboard, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + } + +#if defined(_WIN32_WCE) + if(!(lParam & 0x40000000)) /* Prevent auto-repeat */ + { + if(wParam==(unsigned)gxKeyList.vkRight) + keypress = GLUT_KEY_RIGHT; + else if(wParam==(unsigned)gxKeyList.vkLeft) + keypress = GLUT_KEY_LEFT; + else if(wParam==(unsigned)gxKeyList.vkUp) + keypress = GLUT_KEY_UP; + else if(wParam==(unsigned)gxKeyList.vkDown) + keypress = GLUT_KEY_DOWN; + else if(wParam==(unsigned)gxKeyList.vkA) + keypress = GLUT_KEY_F1; + else if(wParam==(unsigned)gxKeyList.vkB) + keypress = GLUT_KEY_F2; + else if(wParam==(unsigned)gxKeyList.vkC) + keypress = GLUT_KEY_F3; + else if(wParam==(unsigned)gxKeyList.vkStart) + keypress = GLUT_KEY_F4; + } +#endif + + if( keypress != -1 ) + INVOKE_WCB( *window, Special, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSKEYUP: + case WM_KEYUP: + { + // QB64-PE: custom code begin + if (wParam == VK_PAUSE) { + qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_PAUSE, -1, 0, 0, 0, 0, 0, 0, NULL, NULL); + break; + } + if (wParam == VK_CANCEL) { + qb64_custom_event(QB64_EVENT_KEY, VK + QBVK_BREAK, -1, 0, 0, 0, 0, 0, 0, NULL, NULL); + break; + } + // QB64-PE: custom code end + + int keypress = -1; + POINT mouse_pos; + + if (child_window) + window = child_window; + + /* + * Remember the current modifiers state. This is done here in order + * to make sure the VK_DELETE keyboard callback is executed properly. + */ + fgState.Modifiers = fghGetWin32Modifiers( ); + + GetCursorPos( &mouse_pos ); + ScreenToClient( window->Window.Handle, &mouse_pos ); + + window->State.MouseX = mouse_pos.x; + window->State.MouseY = mouse_pos.y; + + /* + * Convert the Win32 keystroke codes to GLUTtish way. + * "KEY(a,b)" was defined under "WM_KEYDOWN" + */ + + switch( wParam ) + { + KEY( VK_F1, GLUT_KEY_F1 ); + KEY( VK_F2, GLUT_KEY_F2 ); + KEY( VK_F3, GLUT_KEY_F3 ); + KEY( VK_F4, GLUT_KEY_F4 ); + KEY( VK_F5, GLUT_KEY_F5 ); + KEY( VK_F6, GLUT_KEY_F6 ); + KEY( VK_F7, GLUT_KEY_F7 ); + KEY( VK_F8, GLUT_KEY_F8 ); + KEY( VK_F9, GLUT_KEY_F9 ); + KEY( VK_F10, GLUT_KEY_F10 ); + KEY( VK_F11, GLUT_KEY_F11 ); + KEY( VK_F12, GLUT_KEY_F12 ); + KEY( VK_PRIOR, GLUT_KEY_PAGE_UP ); + KEY( VK_NEXT, GLUT_KEY_PAGE_DOWN ); + KEY( VK_HOME, GLUT_KEY_HOME ); + KEY( VK_END, GLUT_KEY_END ); + KEY( VK_LEFT, GLUT_KEY_LEFT ); + KEY( VK_UP, GLUT_KEY_UP ); + KEY( VK_RIGHT, GLUT_KEY_RIGHT ); + KEY( VK_DOWN, GLUT_KEY_DOWN ); + KEY( VK_INSERT, GLUT_KEY_INSERT ); + + case VK_LCONTROL: case VK_RCONTROL: case VK_CONTROL: + case VK_LSHIFT: case VK_RSHIFT: case VK_SHIFT: + case VK_LMENU: case VK_RMENU: case VK_MENU: + /* These keypresses and releases are handled earlier in the function */ + break; + + case VK_DELETE: + /* The delete key should be treated as an ASCII keypress: */ + INVOKE_WCB( *window, KeyboardUp, + ( 127, window->State.MouseX, window->State.MouseY ) + ); + break; + + default: + { +#if !defined(_WIN32_WCE) + BYTE state[ 256 ]; + WORD code[ 2 ]; + + GetKeyboardState( state ); + + if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 ) + wParam=code[ 0 ]; + + INVOKE_WCB( *window, KeyboardUp, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); +#endif /* !defined(_WIN32_WCE) */ + } + } + + if( keypress != -1 ) + INVOKE_WCB( *window, SpecialUp, + ( keypress, + window->State.MouseX, window->State.MouseY ) + ); + + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_SYSCHAR: + case WM_CHAR: + { + if (child_window) + window = child_window; + + if( (fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE) && (HIWORD(lParam) & KF_REPEAT) ) + break; + + fgState.Modifiers = fghGetWin32Modifiers( ); + INVOKE_WCB( *window, Keyboard, + ( (char)wParam, + window->State.MouseX, window->State.MouseY ) + ); + fgState.Modifiers = INVALID_MODIFIERS; + } + break; + + case WM_CAPTURECHANGED: + /* User has finished resizing the window, force a redraw */ + INVOKE_WCB( *window, Display, ( ) ); + + /*lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); */ + break; + + /* Other messages that I have seen and which are not handled already */ + case WM_SETTEXT: /* 0x000c */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to set the window text */ + break; + + case WM_GETTEXT: /* 0x000d */ + /* Ideally we would copy the title of the window into "lParam" */ + /* strncpy ( (char *)lParam, "Window Title", wParam ); + lRet = ( wParam > 12 ) ? 12 : wParam; */ + /* the number of characters copied */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + + case WM_GETTEXTLENGTH: /* 0x000e */ + /* Ideally we would get the length of the title of the window */ + lRet = 12; + /* the number of characters in "Window Title\0" (see above) */ + break; + + case WM_ERASEBKGND: /* 0x0014 */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + +#if !defined(_WIN32_WCE) + case WM_SYNCPAINT: /* 0x0088 */ + /* Another window has moved, need to update this one */ + window->State.Redisplay = GL_TRUE; + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Help screen says this message must be passed to "DefWindowProc" */ + break; + + case WM_NCPAINT: /* 0x0085 */ + /* Need to update the border of this window */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + /* Pass it on to "DefWindowProc" to repaint a standard border */ + break; + + case WM_SYSCOMMAND : /* 0x0112 */ + { + /* + * We have received a system command message. Try to act on it. + * The commands are passed in through the "wParam" parameter: + * The least significant digit seems to be which edge of the window + * is being used for a resize event: + * 4 3 5 + * 1 2 + * 7 6 8 + * Congratulations and thanks to Richard Rauch for figuring this out.. + */ + switch ( wParam & 0xfff0 ) + { + case SC_SIZE : + break ; + + case SC_MOVE : + break ; + + case SC_MINIMIZE : + /* User has clicked on the "-" to minimize the window */ + /* Turn off the visibility */ + window->State.Visible = GL_FALSE ; + + break ; + + case SC_MAXIMIZE : + break ; + + case SC_NEXTWINDOW : + break ; + + case SC_PREVWINDOW : + break ; + + case SC_CLOSE : + /* Followed very closely by a WM_CLOSE message */ + break ; + + case SC_VSCROLL : + break ; + + case SC_HSCROLL : + break ; + + case SC_MOUSEMENU : + break ; + + case SC_KEYMENU : + break ; + + case SC_ARRANGE : + break ; + + case SC_RESTORE : + break ; + + case SC_TASKLIST : + break ; + + case SC_SCREENSAVE : + break ; + + case SC_HOTKEY : + break ; + +#if(WINVER >= 0x0400) + case SC_DEFAULT : + break ; + + case SC_MONITORPOWER : + break ; + + case SC_CONTEXTHELP : + break ; +#endif /* WINVER >= 0x0400 */ + + default: +#if _DEBUG + fgWarning( "Unknown wParam type 0x%x", wParam ); +#endif + break; + } + } +#endif /* !defined(_WIN32_WCE) */ + + /* We need to pass the message on to the operating system as well */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + +#ifdef WM_TOUCH + /* handle multi-touch messages */ + case WM_TOUCH: + { + unsigned int numInputs = (unsigned int)wParam; + unsigned int i = 0; + TOUCHINPUT* ti = (TOUCHINPUT*)malloc( sizeof(TOUCHINPUT)*numInputs); + + if (fghGetTouchInputInfo == (pGetTouchInputInfo)0xDEADBEEF) { + fghGetTouchInputInfo = (pGetTouchInputInfo)GetProcAddress(GetModuleHandle("user32"),"GetTouchInputInfo"); + fghCloseTouchInputHandle = (pCloseTouchInputHandle)GetProcAddress(GetModuleHandle("user32"),"CloseTouchInputHandle"); + } + + if (!fghGetTouchInputInfo) { + free( (void*)ti ); + break; + } + + if (fghGetTouchInputInfo( (HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT) )) { + /* Handle each contact point */ + for (i = 0; i < numInputs; ++i ) { + + POINT tp; + tp.x = TOUCH_COORD_TO_PIXEL(ti[i].x); + tp.y = TOUCH_COORD_TO_PIXEL(ti[i].y); + ScreenToClient( hWnd, &tp ); + + ti[i].dwID = ti[i].dwID * 2; + + if (ti[i].dwFlags & TOUCHEVENTF_DOWN) { + INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_ENTERED ) ); + INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_DOWN ) ); + } else if (ti[i].dwFlags & TOUCHEVENTF_MOVE) { + INVOKE_WCB( *window, MultiMotion, ( ti[i].dwID, tp.x, tp.y ) ); + } else if (ti[i].dwFlags & TOUCHEVENTF_UP) { + INVOKE_WCB( *window, MultiButton, ( ti[i].dwID, tp.x, tp.y, 0, GLUT_UP ) ); + INVOKE_WCB( *window, MultiEntry, ( ti[i].dwID, GLUT_LEFT ) ); + } + } + } + fghCloseTouchInputHandle((HTOUCHINPUT)lParam); + free( (void*)ti ); + lRet = 0; /*DefWindowProc( hWnd, uMsg, wParam, lParam );*/ + break; + } +#endif + default: + /* Handle unhandled messages */ + lRet = DefWindowProc( hWnd, uMsg, wParam, lParam ); + break; + } + + // QB64-PE: custom code begin + qb64_os_event_info = 2; + qb64_os_event_return = qb64_os_event_windows(hWnd, uMsg, wParam, lParam, &qb64_os_event_info); + if (qb64_os_event_info == 3) + return qb64_os_event_return; + // QB64-PE: custom code end + + return lRet; +} +#endif + +/*** END OF FILE ***/ diff --git a/internal/c/parts/core/freeglut/freeglut_menu.c b/internal/c/parts/core/freeglut/freeglut_menu.c index ea5837e80..315478413 100644 --- a/internal/c/parts/core/freeglut/freeglut_menu.c +++ b/internal/c/parts/core/freeglut/freeglut_menu.c @@ -84,6 +84,9 @@ static float menu_pen_hfore [4] = {0.0f, 0.0f, 0.0f, 1.0f}; static float menu_pen_hback [4] = {1.0f, 1.0f, 1.0f, 1.0f}; #endif +extern void fghGetCursorPos(SFG_XYUse *mouse_pos); + + /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ /* @@ -532,14 +535,15 @@ void fgDisplayMenu( void ) static void fghActivateMenu( SFG_Window* window, int button ) { int max_x, max_y; + SFG_XYUse mouse_pos; /* We'll be referencing this menu a lot, so remember its address: */ SFG_Menu* menu = window->Menu[ button ]; SFG_Window* current_window = fgStructure.CurrentWindow; - /* If the menu is already active in another window, deactivate it there */ + /* If the menu is already active in another window, deactivate it (and any submenus) there */ if ( menu->ParentWindow ) - menu->ParentWindow->ActiveMenu = NULL ; + fgDeactivateMenu(menu->ParentWindow); /* Mark the menu as active, so that it gets displayed: */ window->ActiveMenu = menu; @@ -550,9 +554,17 @@ static void fghActivateMenu( SFG_Window* window, int button ) /* Set up the initial menu position now: */ fghGetVMaxExtent(menu->ParentWindow, &max_x, &max_y); fgSetWindow( window ); - menu->X = window->State.MouseX + glutGet( GLUT_WINDOW_X ); - menu->Y = window->State.MouseY + glutGet( GLUT_WINDOW_Y ); + /* get mouse position on screen (window->State.MouseX and window->State.MouseY + * are relative to client area origin), and not easy to correct given that + * glutGet( GLUT_WINDOW_X ) and glutGet( GLUT_WINDOW_Y ) return relative to parent + * origin when looking at a child window + * for parent windows: window->State.MouseX + glutGet( GLUT_WINDOW_X ) == mouse_pos.X + */ + fghGetCursorPos(&mouse_pos); + menu->X = mouse_pos.X; + menu->Y = mouse_pos.Y; + /* Make sure the whole menu is on the screen */ if( menu->X + menu->Width > max_x ) menu->X -=menu->Width; @@ -563,10 +575,21 @@ static void fghActivateMenu( SFG_Window* window, int button ) menu->Y = 0; } - menu->Window->State.MouseX = - window->State.MouseX + glutGet( GLUT_WINDOW_X ) - menu->X; - menu->Window->State.MouseY = - window->State.MouseY + glutGet( GLUT_WINDOW_Y ) - menu->Y; + /* Set position of mouse relative to top-left menu in menu's window state (could as well set 0 at creation time...) */ + menu->Window->State.MouseX = mouse_pos.X - menu->X; + menu->Window->State.MouseY = mouse_pos.Y - menu->Y; + + /* Menu status callback */ + if (fgState.MenuStateCallback || fgState.MenuStatusCallback) + { + fgStructure.CurrentMenu = menu; + fgStructure.CurrentWindow = window; + if (fgState.MenuStateCallback) + 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); + } fgSetWindow( menu->Window ); glutPositionWindow( menu->X, menu->Y ); @@ -645,9 +668,8 @@ GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, /* * Outside the menu, deactivate if it's a downclick * - * XXX This isn't enough. A downclick outside of - * XXX the interior of our freeglut windows should also - * XXX deactivate the menu. This is more complicated. + * A downclick outside of the interior of our freeglut windows + * is dealt with in the WM_KILLFOCUS handler of fgPlatformWindowProc */ fgDeactivateMenu( window->ActiveMenu->ParentWindow ); @@ -684,12 +706,13 @@ GLboolean fgCheckActiveMenu ( SFG_Window *window, int button, GLboolean pressed, void fgDeactivateMenu( SFG_Window *window ) { SFG_Window *parent_window = NULL; - - /* Check if there is an active menu attached to this window... */ - SFG_Menu* menu = window->ActiveMenu; + SFG_Menu* menu; SFG_MenuEntry *menuEntry; /* Did we find an active window? */ + freeglut_return_if_fail( window ); + /* Check if there is an active menu attached to this window... */ + menu = window->ActiveMenu; freeglut_return_if_fail( menu ); parent_window = menu->ParentWindow; @@ -714,12 +737,32 @@ void fgDeactivateMenu( SFG_Window *window ) { menuEntry->IsActive = GL_FALSE; - /* Is that an active submenu by any case? */ + /* Is that an active submenu by any chance? */ if( menuEntry->SubMenu ) fghDeactivateSubMenu( menuEntry ); } fgSetWindow ( parent_window ) ; + + /* Menu status callback */ + if (fgState.MenuStateCallback || fgState.MenuStatusCallback) + { + fgStructure.CurrentMenu = menu; + fgStructure.CurrentWindow = parent_window; + if (fgState.MenuStateCallback) + fgState.MenuStateCallback(GLUT_MENU_NOT_IN_USE); + if (fgState.MenuStatusCallback) + { + /* Get cursor position on screen and convert to relative to parent_window's client area */ + SFG_XYUse mouse_pos; + fghGetCursorPos(&mouse_pos); + + mouse_pos.X -= glutGet( GLUT_WINDOW_X ); + mouse_pos.Y -= glutGet( GLUT_WINDOW_Y ); + + fgState.MenuStatusCallback(GLUT_MENU_NOT_IN_USE, mouse_pos.X, mouse_pos.Y); + } + } } /* @@ -766,6 +809,53 @@ void fghCalculateMenuBoxSize( void ) fgStructure.CurrentMenu->Width = width + 4 * FREEGLUT_MENU_BORDER; } +#if TARGET_HOST_MS_WINDOWS +void fgPlatformCheckMenuDeactivate() +{ + /* If we have an open menu, see if the open menu should be closed + * when focus was lost because user either switched + * application or FreeGLUT window (if one is running multiple + * windows). If so, close menu the active menu. + */ + SFG_Menu* menu = NULL; + + if ( fgStructure.Menus.First ) + menu = fgGetActiveMenu(); + + if ( menu ) + { + SFG_Window* wnd = NULL; + HWND hwnd = GetFocus(); /* Get window with current focus - NULL for non freeglut windows */ + if (hwnd) + /* See which of our windows it is */ + wnd = fgWindowByHandle(hwnd); + + if (!hwnd || !wnd) + /* User switched to another application*/ + fgDeactivateMenu(menu->ParentWindow); + else if (!wnd->IsMenu) /* Make sure we don't kill the menu when trying to enter a submenu */ + { + if (wnd!=menu->ParentWindow) + /* User switched to another FreeGLUT window */ + fgDeactivateMenu(menu->ParentWindow); + else + { + /* Check if focus lost because non-client area of + * window was pressed (pressing on client area is + * handled in fgCheckActiveMenu) + */ + POINT mouse_pos; + RECT clientArea; + fghGetClientArea(&clientArea,menu->ParentWindow, GL_FALSE); + GetCursorPos(&mouse_pos); + if ( !PtInRect( &clientArea, mouse_pos ) ) + fgDeactivateMenu(menu->ParentWindow); + } + } + } +}; +#endif + /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ @@ -776,6 +866,8 @@ int FGAPIENTRY glutCreateMenu( void(* callback)( int ) ) { /* The menu object creation code resides in freeglut_structure.c */ FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); return fgCreateMenu( callback )->ID; } @@ -799,6 +891,9 @@ void FGAPIENTRY glutDestroyMenu( int menuID ) freeglut_return_if_fail( menu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); + /* The menu object destruction code resides in freeglut_structure.c */ fgDestroyMenu( menu ); } @@ -839,7 +934,10 @@ void FGAPIENTRY glutAddMenuEntry( const char* label, int value ) SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAddMenuEntry" ); menuEntry = (SFG_MenuEntry *)calloc( sizeof(SFG_MenuEntry), 1 ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); menuEntry->Text = strdup( label ); menuEntry->ID = value; @@ -863,6 +961,9 @@ void FGAPIENTRY glutAddSubMenu( const char *label, int subMenuID ) subMenu = fgMenuByID( subMenuID ); freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); + freeglut_return_if_fail( subMenu ); menuEntry->Text = strdup( label ); @@ -881,7 +982,10 @@ void FGAPIENTRY glutChangeToMenuEntry( int item, const char* label, int value ) SFG_MenuEntry* menuEntry = NULL; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToMenuEntry" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); /* Get n-th menu entry in the current menu, starting from one: */ menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); @@ -908,10 +1012,15 @@ void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToSubMenu" ); + + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); + + /* Get handle to sub menu */ subMenu = fgMenuByID( subMenuID ); menuEntry = NULL; - freeglut_return_if_fail( fgStructure.CurrentMenu ); freeglut_return_if_fail( subMenu ); /* Get n-th menu entry in the current menu, starting from one: */ @@ -937,7 +1046,10 @@ void FGAPIENTRY glutRemoveMenuItem( int item ) SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutRemoveMenuItem" ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); /* Get n-th menu entry in the current menu, starting from one: */ menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); @@ -960,7 +1072,10 @@ void FGAPIENTRY glutAttachMenu( int button ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAttachMenu" ); freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); freeglut_return_if_fail( button >= 0 ); freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); @@ -976,7 +1091,10 @@ void FGAPIENTRY glutDetachMenu( int button ) FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDetachMenu" ); freeglut_return_if_fail( fgStructure.CurrentWindow ); + freeglut_return_if_fail( fgStructure.CurrentMenu ); + if (fgGetActiveMenu()) + fgError("Menu manipulation not allowed while menus in use."); freeglut_return_if_fail( button >= 0 ); freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); diff --git a/internal/c/parts/core/freeglut/freeglut_state.c b/internal/c/parts/core/freeglut/freeglut_state.c index 258649db0..2e858dd48 100644 --- a/internal/c/parts/core/freeglut/freeglut_state.c +++ b/internal/c/parts/core/freeglut/freeglut_state.c @@ -124,6 +124,10 @@ void FGAPIENTRY glutSetOption( GLenum eWhat, int value ) fgState.SampleNumber = value; break; + case GLUT_SKIP_STALE_MOTION_EVENTS: + fgState.SkipStaleMotion = value; + break; + default: fgWarning( "glutSetOption(): missing enum handle %d", eWhat ); break; @@ -132,7 +136,7 @@ void FGAPIENTRY glutSetOption( GLenum eWhat, int value ) #if TARGET_HOST_MS_WINDOWS /* The following include file is available from SGI but is not standard: - * #include + * #include * So we copy the necessary parts out of it to support the multisampling query */ #define WGL_SAMPLES_ARB 0x2042 @@ -434,7 +438,7 @@ int FGAPIENTRY glutGet( GLenum eWhat ) * behaviour, both under Windows and under UNIX/X11: * - When you create a window with position (x,y) and size * (w,h), the upper left hand corner of the outside of the - * window is at (x,y) and the size of the drawable area is + * window is at (x,y) and the size of the drawable area is * (w,h). * - When you query the size and position of the window--as * is happening here for Windows--"freeglut" will return @@ -451,7 +455,20 @@ int FGAPIENTRY glutGet( GLenum eWhat ) #if defined(_WIN32_WCE) GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); #else - winRect = fghGetClientArea(fgStructure.CurrentWindow, FALSE); + fghGetClientArea(&winRect,fgStructure.CurrentWindow, FALSE); + if (fgStructure.CurrentWindow->Parent && (eWhat==GLUT_WINDOW_X || eWhat==GLUT_WINDOW_Y)) + { + /* For child window, we should return relative to upper-left + * of parent's client area. + */ + POINT topleft; + topleft.x = winRect.left; + topleft.y = winRect.top; + + ScreenToClient(fgStructure.CurrentWindow->Parent->Window.Handle,&topleft); + winRect.left = topleft.x; + winRect.top = topleft.y; + } #endif /* defined(_WIN32_WCE) */ switch( eWhat ) @@ -465,30 +482,47 @@ int FGAPIENTRY glutGet( GLenum eWhat ) break; case GLUT_WINDOW_BORDER_WIDTH : - case GLUT_WINDOW_HEADER_HEIGHT : + case GLUT_WINDOW_BORDER_HEIGHT : #if defined(_WIN32_WCE) return 0; #else { - DWORD windowStyle; + /* We can't get the border width or header height in the simple way + * with some calls to GetSystemMetrics. We'd then have to assume which + * elements are present for a given decoration, and such calculations + * wouldn't be valid for every version of Windows. The below should be + * robust. */ + int borderWidth, captionHeight; + DWORD windowStyle, windowExStyle; + RECT clientRect, winRect; + /* Get style of window, or default style */ + fghGetStyleFromWindow( fgStructure.CurrentWindow, &windowStyle, &windowExStyle ); + /* Get client area if any window */ if (fgStructure.CurrentWindow && fgStructure.CurrentWindow->Window.Handle) - windowStyle = GetWindowLong(fgStructure.CurrentWindow->Window.Handle, GWL_STYLE); + fghGetClientArea(&clientRect,fgStructure.CurrentWindow,FALSE); else - /* If no window, return sizes for a default window with title bar and border */ - windowStyle = WS_OVERLAPPEDWINDOW; - + SetRect(&clientRect,0,0,200,200); + + /* Compute window rect (including non-client area) */ + CopyRect(&winRect,&clientRect); + fghComputeWindowRectFromClientArea_UseStyle(&winRect,windowStyle,windowExStyle,FALSE); + + /* Calculate border width by taking width of whole window minus width of client area and divide by two + * NB: we assume horizontal and vertical borders have the same size, which should always be the case + * unless the user bypassed FreeGLUT and messed with the windowstyle himself. + * Once borderwidth is known, account for it when comparing height of window to height of client area. + * all other extra pixels are assumed to be atop the window, forming the caption. + */ + borderWidth = ((winRect.right-winRect.left)-(clientRect.right-clientRect.left))/2; + captionHeight = (winRect.bottom-winRect.top)-(clientRect.bottom-clientRect.top)-borderWidth*2; + switch( eWhat ) { case GLUT_WINDOW_BORDER_WIDTH: - { - int xBorderWidth, yBorderWidth; - fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth); - return xBorderWidth; - } - case GLUT_WINDOW_HEADER_HEIGHT: - /* Need to query for WS_SYSMENU to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */ - return (windowStyle & WS_SYSMENU)? GetSystemMetrics( SM_CYCAPTION ) : 0; + return borderWidth; + case GLUT_WINDOW_BORDER_HEIGHT: + return captionHeight; } } #endif /* defined(_WIN32_WCE) */ @@ -554,6 +588,9 @@ int FGAPIENTRY glutGet( GLenum eWhat ) case GLUT_MULTISAMPLE: return fgState.SampleNumber; + case GLUT_SKIP_STALE_MOTION_EVENTS: + return fgState.SkipStaleMotion; + default: fgWarning( "glutGet(): missing enum handle %d", eWhat ); break; diff --git a/internal/c/parts/core/freeglut/freeglut_structure.c b/internal/c/parts/core/freeglut/freeglut_structure.c index c5a2d734e..b26b1e331 100644 --- a/internal/c/parts/core/freeglut/freeglut_structure.c +++ b/internal/c/parts/core/freeglut/freeglut_structure.c @@ -380,7 +380,7 @@ void fgDestroyStructure( void ) /* * Helper function to enumerate through all registered top-level windows */ -void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ) +void fgEnumWindows( FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator ) { SFG_Window *window; @@ -399,11 +399,33 @@ void fgEnumWindows( FGCBenumerator enumCallback, SFG_Enumerator* enumerator ) } } +/* + * Helper function to enumerate through all registered top-level windows + */ +void fgEnumMenus( FGCBMenuEnumerator enumCallback, SFG_Enumerator* enumerator ) +{ + SFG_Menu *menu; + + FREEGLUT_INTERNAL_ERROR_EXIT ( enumCallback && enumerator, + "Enumerator or callback missing from window enumerator call", + "fgEnumWindows" ); + + /* It's enough to check all entries in fgStructure.Menus... */ + for( menu = (SFG_Menu *)fgStructure.Menus.First; + menu; + menu = (SFG_Menu *)menu->Node.Next ) + { + enumCallback( menu, enumerator ); + if( enumerator->found ) + return; + } +} + /* * Helper function to enumerate through all a window's subwindows * (single level descent) */ -void fgEnumSubWindows( SFG_Window* window, FGCBenumerator enumCallback, +void fgEnumSubWindows( SFG_Window* window, FGCBWindowEnumerator enumCallback, SFG_Enumerator* enumerator ) { SFG_Window *child; @@ -487,7 +509,7 @@ static void fghcbWindowByID( SFG_Window *window, SFG_Enumerator *enumerator ) } /* - * This function is similiar to the previous one, except it is + * This function is similar to the previous one, except it is * looking for a specified (sub)window identifier. The function * is defined in freeglut_structure.c file. */ @@ -495,7 +517,7 @@ SFG_Window* fgWindowByID( int windowID ) { SFG_Enumerator enumerator; - /* Uses a method very similiar for fgWindowByHandle... */ + /* Uses a method very similar for fgWindowByHandle... */ enumerator.found = GL_FALSE; enumerator.data = ( void * )&windowID; fgEnumWindows( fghcbWindowByID, &enumerator ); @@ -506,18 +528,75 @@ SFG_Window* fgWindowByID( int windowID ) /* * Looks up a menu given its ID. This is easier that fgWindowByXXX + * A static helper function to look for a menu given its ID + */ +static void fghcbMenuByID( SFG_Menu *menu, SFG_Enumerator *enumerator ) +{ + if ( enumerator->found ) + return; + + /* Check the menu's ID. */ + if( menu->ID == (int)(enumerator->data) ) + { + enumerator->found = GL_TRUE; + enumerator->data = menu; + + return; + } +} + +/* + * Looks up a menu given its ID. This is easier than fgWindowByXXX * as all menus are placed in one doubly linked list... */ SFG_Menu* fgMenuByID( int menuID ) { - SFG_Menu *menu = NULL; + SFG_Enumerator enumerator; - /* It's enough to check all entries in fgStructure.Menus... */ - for( menu = (SFG_Menu *)fgStructure.Menus.First; - menu; - menu = (SFG_Menu *)menu->Node.Next ) - if( menu->ID == menuID ) - return menu; + /* This is easy and makes use of the menus enumeration defined above */ + enumerator.found = GL_FALSE; + enumerator.data = (void *)menuID; + fgEnumMenus( fghcbMenuByID, &enumerator ); + + if( enumerator.found ) + return( SFG_Menu *) enumerator.data; + + return NULL; +} + +/* + * A static helper function to look for an active menu + */ +static void fghcbGetActiveMenu( SFG_Menu *menu, SFG_Enumerator *enumerator ) +{ + if ( enumerator->found ) + return; + + /* Check the menu's ID. */ + if( menu->IsActive ) + { + enumerator->found = GL_TRUE; + enumerator->data = menu; + + return; + } +} + +/* + * Returns active menu, if any. Assumption: only one menu active throughout application at any one time. + * This is easier than fgWindowByXXX as all menus are placed in one doubly linked list... + */ +SFG_Menu* fgGetActiveMenu( ) +{ + SFG_Enumerator enumerator; + + /* This is easy and makes use of the menus enumeration defined above */ + enumerator.found = GL_FALSE; + fgEnumMenus( fghcbGetActiveMenu, &enumerator ); + + if( enumerator.found ) + return( SFG_Menu *) enumerator.data; + return NULL; } diff --git a/internal/c/parts/core/freeglut/freeglut_teapot.c b/internal/c/parts/core/freeglut/freeglut_teapot.c new file mode 100644 index 000000000..722bca612 --- /dev/null +++ b/internal/c/parts/core/freeglut/freeglut_teapot.c @@ -0,0 +1,200 @@ +/* + * freeglut_teapot.c + * + * Teapot(tm) rendering code. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 24 1999 + * + * 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. + */ + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +#include +#include "freeglut_internal.h" +#include "freeglut_teapot_data.h" + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + + +static void fghTeapot( GLint grid, GLdouble scale, GLenum type ) +{ +#if defined(_WIN32_WCE) + int i, numV=sizeof(strip_vertices)/4, numI=sizeof(strip_normals)/4; +#else + double p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3]; + long i, j, k, l; +#endif + + glPushAttrib( GL_ENABLE_BIT | GL_EVAL_BIT ); + glEnable( GL_AUTO_NORMAL ); + glEnable( GL_NORMALIZE ); + glEnable( GL_MAP2_VERTEX_3 ); + glEnable( GL_MAP2_TEXTURE_COORD_2 ); + + glPushMatrix(); + glRotated( 270.0, 1.0, 0.0, 0.0 ); + glScaled( 0.5 * scale, 0.5 * scale, 0.5 * scale ); + glTranslated( 0.0, 0.0, -1.5 ); + +#if defined(_WIN32_WCE) + glRotated( 90.0, 1.0, 0.0, 0.0 ); + glBegin( GL_TRIANGLE_STRIP ); + + for( i = 0; i < numV-1; i++ ) + { + int vidx = strip_vertices[i], + nidx = strip_normals[i]; + + if( vidx != -1 ) + { + glNormal3fv( normals[nidx] ); + glVertex3fv( vertices[vidx] ); + } + else + { + glEnd(); + glBegin( GL_TRIANGLE_STRIP ); + } + } + + glEnd(); +#else + for (i = 0; i < 10; i++) { + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + for (l = 0; l < 3; l++) { + p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 1) + q[j][k][l] *= -1.0; + if (i < 6) { + r[j][k][l] = + cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 0) + r[j][k][l] *= -1.0; + s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + if (l == 0) + s[j][k][l] *= -1.0; + if (l == 1) + s[j][k][l] *= -1.0; + } + } + } + } + + glMap2d(GL_MAP2_TEXTURE_COORD_2, 0.0, 1.0, 2, 2, 0.0, 1.0, 4, 2, + &tex[0][0][0]); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &p[0][0][0]); + glMapGrid2d(grid, 0.0, 1.0, grid, 0.0, 1.0); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &q[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + if (i < 6) { + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &r[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &s[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + } + } +#endif /* defined(_WIN32_WCE) */ + + glPopMatrix(); + glPopAttrib(); +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Renders a beautiful wired teapot... + */ +void FGAPIENTRY glutWireTeapot( GLdouble size ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTeapot" ); + /* We will use the general teapot rendering code */ + fghTeapot( 10, size, GL_LINE ); +} + +/* + * Renders a beautiful filled teapot... + */ +void FGAPIENTRY glutSolidTeapot( GLdouble size ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTeapot" ); + /* We will use the general teapot rendering code */ + fghTeapot( 7, size, GL_FILL ); +} + +/*** END OF FILE ***/ + + + + + diff --git a/internal/c/parts/core/freeglut/freeglut_teapot_data.h b/internal/c/parts/core/freeglut/freeglut_teapot_data.h new file mode 100644 index 000000000..3bf83e11f --- /dev/null +++ b/internal/c/parts/core/freeglut/freeglut_teapot_data.h @@ -0,0 +1,2429 @@ +/* + * freeglut_teapot_data.h + * + * The freeglut library teapot data include file. + * + * 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_TEAPOT_DATA_H +#define FREEGLUT_TEAPOT_DATA_H + +#if defined(_WIN32_WCE) +/* + * Submitted through the kind offices of Daniel Wagner (daniel@ims.tuwien.ac.at) + */ + +/* 530 vertices */ + +const int numVertices = 530; +const float vertices[530][3] = { +2.1f, 3.6f, 0.0f, +2.071f, 3.711f, 0.0f, +2.105f, 3.748f, 0.0f, +2.174f, 3.711f, 0.0f, +2.25f, 3.6f, 0.0f, +1.937f, 3.6f, 0.8242f, +1.91f, 3.711f, 0.8128f, +1.942f, 3.748f, 0.8261f, +2.005f, 3.711f, 0.8532f, +2.076f, 3.6f, 0.8831f, +1.491f, 3.6f, 1.491f, +1.47f, 3.711f, 1.47f, +1.494f, 3.748f, 1.494f, +1.543f, 3.711f, 1.543f, +1.597f, 3.6f, 1.597f, +0.8242f, 3.6f, 1.937f, +0.8128f, 3.711f, 1.91f, +0.8261f, 3.748f, 1.942f, +0.8532f, 3.711f, 2.005f, +0.8831f, 3.6f, 2.076f, +0.0f, 3.6f, 2.1f, +0.0f, 3.711f, 2.071f, +0.0f, 3.748f, 2.105f, +0.0f, 3.711f, 2.174f, +0.0f, 3.6f, 2.25f, +-0.8812f, 3.6f, 1.937f, +-0.8368f, 3.711f, 1.91f, +-0.8332f, 3.748f, 1.942f, +-0.8541f, 3.711f, 2.005f, +-0.8831f, 3.6f, 2.076f, +-1.542f, 3.6f, 1.491f, +-1.492f, 3.711f, 1.47f, +-1.501f, 3.748f, 1.494f, +-1.544f, 3.711f, 1.543f, +-1.597f, 3.6f, 1.597f, +-1.956f, 3.6f, 0.8242f, +-1.918f, 3.711f, 0.8128f, +-1.944f, 3.748f, 0.8261f, +-2.006f, 3.711f, 0.8532f, +-2.076f, 3.6f, 0.8831f, +-2.1f, 3.6f, 0.0f, +-2.071f, 3.711f, 0.0f, +-2.105f, 3.748f, 0.0f, +-2.174f, 3.711f, 0.0f, +-2.25f, 3.6f, 0.0f, +-1.937f, 3.6f, -0.8242f, +-1.91f, 3.711f, -0.8128f, +-1.942f, 3.748f, -0.8261f, +-2.005f, 3.711f, -0.8532f, +-2.076f, 3.6f, -0.8831f, +-1.491f, 3.6f, -1.491f, +-1.47f, 3.711f, -1.47f, +-1.494f, 3.748f, -1.494f, +-1.543f, 3.711f, -1.543f, +-1.597f, 3.6f, -1.597f, +-0.8242f, 3.6f, -1.937f, +-0.8128f, 3.711f, -1.91f, +-0.8261f, 3.748f, -1.942f, +-0.8532f, 3.711f, -2.005f, +-0.8831f, 3.6f, -2.076f, +0.0f, 3.6f, -2.1f, +0.0f, 3.711f, -2.071f, +0.0f, 3.748f, -2.105f, +0.0f, 3.711f, -2.174f, +0.0f, 3.6f, -2.25f, +0.8242f, 3.6f, -1.937f, +0.8128f, 3.711f, -1.91f, +0.8261f, 3.748f, -1.942f, +0.8532f, 3.711f, -2.005f, +0.8831f, 3.6f, -2.076f, +1.491f, 3.6f, -1.491f, +1.47f, 3.711f, -1.47f, +1.494f, 3.748f, -1.494f, +1.543f, 3.711f, -1.543f, +1.597f, 3.6f, -1.597f, +1.937f, 3.6f, -0.8242f, +1.91f, 3.711f, -0.8128f, +1.942f, 3.748f, -0.8261f, +2.005f, 3.711f, -0.8532f, +2.076f, 3.6f, -0.8831f, +2.525f, 3.011f, 0.0f, +2.766f, 2.433f, 0.0f, +2.936f, 1.876f, 0.0f, +3.0f, 1.35f, 0.0f, +2.33f, 3.011f, 0.9912f, +2.551f, 2.433f, 1.086f, +2.708f, 1.876f, 1.152f, +2.767f, 1.35f, 1.178f, +1.793f, 3.011f, 1.793f, +1.964f, 2.433f, 1.964f, +2.084f, 1.876f, 2.084f, +2.13f, 1.35f, 2.13f, +0.9912f, 3.011f, 2.33f, +1.086f, 2.433f, 2.551f, +1.152f, 1.876f, 2.708f, +1.178f, 1.35f, 2.767f, +0.0f, 3.011f, 2.525f, +0.0f, 2.433f, 2.766f, +0.0f, 1.876f, 2.936f, +0.0f, 1.35f, 3.0f, +-0.9912f, 3.011f, 2.33f, +-1.086f, 2.433f, 2.551f, +-1.152f, 1.876f, 2.708f, +-1.178f, 1.35f, 2.767f, +-1.793f, 3.011f, 1.793f, +-1.964f, 2.433f, 1.964f, +-2.084f, 1.876f, 2.084f, +-2.13f, 1.35f, 2.13f, +-2.33f, 3.011f, 0.9912f, +-2.551f, 2.433f, 1.086f, +-2.708f, 1.876f, 1.152f, +-2.767f, 1.35f, 1.178f, +-2.525f, 3.011f, 0.0f, +-2.766f, 2.433f, 0.0f, +-2.936f, 1.876f, 0.0f, +-3.0f, 1.35f, 0.0f, +-2.33f, 3.011f, -0.9912f, +-2.551f, 2.433f, -1.086f, +-2.708f, 1.876f, -1.152f, +-2.767f, 1.35f, -1.178f, +-1.793f, 3.011f, -1.793f, +-1.964f, 2.433f, -1.964f, +-2.084f, 1.876f, -2.084f, +-2.13f, 1.35f, -2.13f, +-0.9912f, 3.011f, -2.33f, +-1.086f, 2.433f, -2.551f, +-1.152f, 1.876f, -2.708f, +-1.178f, 1.35f, -2.767f, +0.0f, 3.011f, -2.525f, +0.0f, 2.433f, -2.766f, +0.0f, 1.876f, -2.936f, +0.0f, 1.35f, -3.0f, +0.9912f, 3.011f, -2.33f, +1.086f, 2.433f, -2.551f, +1.152f, 1.876f, -2.708f, +1.178f, 1.35f, -2.767f, +1.793f, 3.011f, -1.793f, +1.964f, 2.433f, -1.964f, +2.084f, 1.876f, -2.084f, +2.13f, 1.35f, -2.13f, +2.33f, 3.011f, -0.9912f, +2.551f, 2.433f, -1.086f, +2.708f, 1.876f, -1.152f, +2.767f, 1.35f, -1.178f, +2.883f, 0.9053f, 0.0f, +2.625f, 0.5766f, 0.0f, +2.367f, 0.3533f, 0.0f, +2.25f, 0.225f, 0.0f, +2.659f, 0.9053f, 1.132f, +2.422f, 0.5766f, 1.03f, +2.184f, 0.3533f, 0.9291f, +2.076f, 0.225f, 0.8831f, +2.047f, 0.9053f, 2.047f, +1.864f, 0.5766f, 1.864f, +1.681f, 0.3533f, 1.681f, +1.597f, 0.225f, 1.597f, +1.132f, 0.9053f, 2.659f, +1.03f, 0.5766f, 2.422f, +0.9291f, 0.3533f, 2.184f, +0.8831f, 0.225f, 2.076f, +0.0f, 0.9053f, 2.883f, +0.0f, 0.5766f, 2.625f, +0.0f, 0.3533f, 2.367f, +0.0f, 0.225f, 2.25f, +-1.132f, 0.9053f, 2.659f, +-1.03f, 0.5766f, 2.422f, +-0.9291f, 0.3533f, 2.184f, +-0.8831f, 0.225f, 2.076f, +-2.047f, 0.9053f, 2.047f, +-1.864f, 0.5766f, 1.864f, +-1.681f, 0.3533f, 1.681f, +-1.597f, 0.225f, 1.597f, +-2.659f, 0.9053f, 1.132f, +-2.422f, 0.5766f, 1.03f, +-2.184f, 0.3533f, 0.9291f, +-2.076f, 0.225f, 0.8831f, +-2.883f, 0.9053f, 0.0f, +-2.625f, 0.5766f, 0.0f, +-2.367f, 0.3533f, 0.0f, +-2.25f, 0.225f, 0.0f, +-2.659f, 0.9053f, -1.132f, +-2.422f, 0.5766f, -1.03f, +-2.184f, 0.3533f, -0.9291f, +-2.076f, 0.225f, -0.8831f, +-2.047f, 0.9053f, -2.047f, +-1.864f, 0.5766f, -1.864f, +-1.681f, 0.3533f, -1.681f, +-1.597f, 0.225f, -1.597f, +-1.132f, 0.9053f, -2.659f, +-1.03f, 0.5766f, -2.422f, +-0.9291f, 0.3533f, -2.184f, +-0.8831f, 0.225f, -2.076f, +0.0f, 0.9053f, -2.883f, +0.0f, 0.5766f, -2.625f, +0.0f, 0.3533f, -2.367f, +0.0f, 0.225f, -2.25f, +1.132f, 0.9053f, -2.659f, +1.03f, 0.5766f, -2.422f, +0.9291f, 0.3533f, -2.184f, +0.8831f, 0.225f, -2.076f, +2.047f, 0.9053f, -2.047f, +1.864f, 0.5766f, -1.864f, +1.681f, 0.3533f, -1.681f, +1.597f, 0.225f, -1.597f, +2.659f, 0.9053f, -1.132f, +2.422f, 0.5766f, -1.03f, +2.184f, 0.3533f, -0.9291f, +2.076f, 0.225f, -0.8831f, +2.199f, 0.1424f, 0.0f, +1.927f, 0.07031f, 0.0f, +1.253f, 0.01934f, 0.0f, +0.0f, 0.0f, 0.0f, +2.029f, 0.1424f, 0.8631f, +1.777f, 0.07031f, 0.7562f, +1.156f, 0.01934f, 0.4919f, +1.561f, 0.1424f, 1.561f, +1.368f, 0.07031f, 1.368f, +0.8899f, 0.01934f, 0.8899f, +0.8631f, 0.1424f, 2.029f, +0.7562f, 0.07031f, 1.777f, +0.4919f, 0.01934f, 1.156f, +0.0f, 0.1424f, 2.199f, +0.0f, 0.07031f, 1.927f, +0.0f, 0.01934f, 1.253f, +-0.8631f, 0.1424f, 2.029f, +-0.7562f, 0.07031f, 1.777f, +-0.4919f, 0.01934f, 1.156f, +-1.561f, 0.1424f, 1.561f, +-1.368f, 0.07031f, 1.368f, +-0.8899f, 0.01934f, 0.8899f, +-2.029f, 0.1424f, 0.8631f, +-1.777f, 0.07031f, 0.7562f, +-1.156f, 0.01934f, 0.4919f, +-2.199f, 0.1424f, 0.0f, +-1.927f, 0.07031f, 0.0f, +-1.253f, 0.01934f, 0.0f, +-2.029f, 0.1424f, -0.8631f, +-1.777f, 0.07031f, -0.7562f, +-1.156f, 0.01934f, -0.4919f, +-1.561f, 0.1424f, -1.561f, +-1.368f, 0.07031f, -1.368f, +-0.8899f, 0.01934f, -0.8899f, +-0.8631f, 0.1424f, -2.029f, +-0.7562f, 0.07031f, -1.777f, +-0.4919f, 0.01934f, -1.156f, +0.0f, 0.1424f, -2.199f, +0.0f, 0.07031f, -1.927f, +0.0f, 0.01934f, -1.253f, +0.8631f, 0.1424f, -2.029f, +0.7562f, 0.07031f, -1.777f, +0.4919f, 0.01934f, -1.156f, +1.561f, 0.1424f, -1.561f, +1.368f, 0.07031f, -1.368f, +0.8899f, 0.01934f, -0.8899f, +2.029f, 0.1424f, -0.8631f, +1.777f, 0.07031f, -0.7562f, +1.156f, 0.01934f, -0.4919f, +-2.4f, 3.038f, 0.0f, +-3.101f, 3.032f, 0.0f, +-3.619f, 2.995f, 0.0f, +-3.94f, 2.895f, 0.0f, +-4.05f, 2.7f, 0.0f, +-2.377f, 3.09f, 0.2531f, +-3.122f, 3.084f, 0.2531f, +-3.669f, 3.041f, 0.2531f, +-4.005f, 2.926f, 0.2531f, +-4.12f, 2.7f, 0.2531f, +-2.325f, 3.206f, 0.3375f, +-3.168f, 3.198f, 0.3375f, +-3.778f, 3.143f, 0.3375f, +-4.15f, 2.993f, 0.3375f, +-4.275f, 2.7f, 0.3375f, +-2.273f, 3.322f, 0.2531f, +-3.214f, 3.313f, 0.2531f, +-3.888f, 3.244f, 0.2531f, +-4.294f, 3.06f, 0.2531f, +-4.43f, 2.7f, 0.2531f, +-2.25f, 3.375f, 0.0f, +-3.234f, 3.364f, 0.0f, +-3.938f, 3.291f, 0.0f, +-4.359f, 3.09f, 0.0f, +-4.5f, 2.7f, 0.0f, +-2.273f, 3.322f, -0.2531f, +-3.214f, 3.313f, -0.2531f, +-3.888f, 3.244f, -0.2531f, +-4.294f, 3.06f, -0.2531f, +-4.43f, 2.7f, -0.2531f, +-2.325f, 3.206f, -0.3375f, +-3.168f, 3.198f, -0.3375f, +-3.778f, 3.143f, -0.3375f, +-4.15f, 2.993f, -0.3375f, +-4.275f, 2.7f, -0.3375f, +-2.377f, 3.09f, -0.2531f, +-3.122f, 3.084f, -0.2531f, +-3.669f, 3.041f, -0.2531f, +-4.005f, 2.926f, -0.2531f, +-4.12f, 2.7f, -0.2531f, +-3.991f, 2.394f, 0.0f, +-3.806f, 2.025f, 0.0f, +-3.48f, 1.656f, 0.0f, +-3.0f, 1.35f, 0.0f, +-4.055f, 2.365f, 0.2531f, +-3.852f, 1.98f, 0.2531f, +-3.496f, 1.6f, 0.2531f, +-2.977f, 1.28f, 0.2531f, +-4.196f, 2.3f, 0.3375f, +-3.952f, 1.881f, 0.3375f, +-3.531f, 1.478f, 0.3375f, +-2.925f, 1.125f, 0.3375f, +-4.336f, 2.235f, 0.2531f, +-4.051f, 1.782f, 0.2531f, +-3.566f, 1.356f, 0.2531f, +-2.873f, 0.9703f, 0.2531f, +-4.4f, 2.205f, 0.0f, +-4.097f, 1.737f, 0.0f, +-3.582f, 1.3f, 0.0f, +-2.85f, 0.9f, 0.0f, +-4.336f, 2.235f, -0.2531f, +-4.051f, 1.782f, -0.2531f, +-3.566f, 1.356f, -0.2531f, +-2.873f, 0.9703f, -0.2531f, +-4.196f, 2.3f, -0.3375f, +-3.952f, 1.881f, -0.3375f, +-3.531f, 1.478f, -0.3375f, +-2.925f, 1.125f, -0.3375f, +-4.055f, 2.365f, -0.2531f, +-3.852f, 1.98f, -0.2531f, +-3.496f, 1.6f, -0.2531f, +-2.977f, 1.28f, -0.2531f, +2.55f, 2.137f, 0.0f, +3.27f, 2.303f, 0.0f, +3.581f, 2.7f, 0.0f, +3.752f, 3.182f, 0.0f, +4.05f, 3.6f, 0.0f, +2.55f, 1.944f, 0.5569f, +3.324f, 2.159f, 0.5028f, +3.652f, 2.617f, 0.3839f, +3.838f, 3.151f, 0.265f, +4.191f, 3.6f, 0.2109f, +2.55f, 1.519f, 0.7425f, +3.445f, 1.844f, 0.6704f, +3.806f, 2.433f, 0.5119f, +4.027f, 3.085f, 0.3533f, +4.5f, 3.6f, 0.2813f, +2.55f, 1.093f, 0.5569f, +3.566f, 1.529f, 0.5028f, +3.961f, 2.249f, 0.3839f, +4.215f, 3.018f, 0.265f, +4.809f, 3.6f, 0.2109f, +2.55f, 0.9f, 0.0f, +3.621f, 1.385f, 0.0f, +4.031f, 2.166f, 0.0f, +4.301f, 2.988f, 0.0f, +4.95f, 3.6f, 0.0f, +2.55f, 1.093f, -0.5569f, +3.566f, 1.529f, -0.5028f, +3.961f, 2.249f, -0.3839f, +4.215f, 3.018f, -0.265f, +4.809f, 3.6f, -0.2109f, +2.55f, 1.519f, -0.7425f, +3.445f, 1.844f, -0.6704f, +3.806f, 2.433f, -0.5119f, +4.027f, 3.085f, -0.3533f, +4.5f, 3.6f, -0.2813f, +2.55f, 1.944f, -0.5569f, +3.324f, 2.159f, -0.5028f, +3.652f, 2.617f, -0.3839f, +3.838f, 3.151f, -0.265f, +4.191f, 3.6f, -0.2109f, +4.158f, 3.663f, 0.0f, +4.238f, 3.684f, 0.0f, +4.261f, 3.663f, 0.0f, +4.2f, 3.6f, 0.0f, +4.308f, 3.666f, 0.1978f, +4.379f, 3.689f, 0.1687f, +4.381f, 3.668f, 0.1397f, +4.294f, 3.6f, 0.1266f, +4.64f, 3.673f, 0.2637f, +4.69f, 3.7f, 0.225f, +4.645f, 3.677f, 0.1863f, +4.5f, 3.6f, 0.1688f, +4.971f, 3.68f, 0.1978f, +5.001f, 3.711f, 0.1687f, +4.909f, 3.687f, 0.1397f, +4.706f, 3.6f, 0.1266f, +5.122f, 3.683f, 0.0f, +5.142f, 3.716f, 0.0f, +5.029f, 3.691f, 0.0f, +4.8f, 3.6f, 0.0f, +4.971f, 3.68f, -0.1978f, +5.001f, 3.711f, -0.1687f, +4.909f, 3.687f, -0.1397f, +4.706f, 3.6f, -0.1266f, +4.64f, 3.673f, -0.2637f, +4.69f, 3.7f, -0.225f, +4.645f, 3.677f, -0.1863f, +4.5f, 3.6f, -0.1688f, +4.308f, 3.666f, -0.1978f, +4.379f, 3.689f, -0.1687f, +4.381f, 3.668f, -0.1397f, +4.294f, 3.6f, -0.1266f, +0.0f, 4.725f, 0.0f, +0.5109f, 4.651f, 0.0f, +0.4875f, 4.472f, 0.0f, +0.2953f, 4.25f, 0.0f, +0.3f, 4.05f, 0.0f, +0.4715f, 4.651f, 0.2011f, +0.4499f, 4.472f, 0.1918f, +0.2725f, 4.25f, 0.1161f, +0.2768f, 4.05f, 0.1178f, +0.3632f, 4.651f, 0.3632f, +0.3465f, 4.472f, 0.3465f, +0.2098f, 4.25f, 0.2098f, +0.213f, 4.05f, 0.213f, +0.2011f, 4.651f, 0.4715f, +0.1918f, 4.472f, 0.4499f, +0.1161f, 4.25f, 0.2725f, +0.1178f, 4.05f, 0.2768f, +0.0f, 4.651f, 0.5109f, +0.0f, 4.472f, 0.4875f, +0.0f, 4.25f, 0.2953f, +0.0f, 4.05f, 0.3f, +-0.2011f, 4.651f, 0.4715f, +-0.1918f, 4.472f, 0.4499f, +-0.1161f, 4.25f, 0.2725f, +-0.1178f, 4.05f, 0.2768f, +-0.3632f, 4.651f, 0.3632f, +-0.3465f, 4.472f, 0.3465f, +-0.2098f, 4.25f, 0.2098f, +-0.213f, 4.05f, 0.213f, +-0.4715f, 4.651f, 0.2011f, +-0.4499f, 4.472f, 0.1918f, +-0.2725f, 4.25f, 0.1161f, +-0.2768f, 4.05f, 0.1178f, +-0.5109f, 4.651f, 0.0f, +-0.4875f, 4.472f, 0.0f, +-0.2953f, 4.25f, 0.0f, +-0.3f, 4.05f, 0.0f, +-0.4715f, 4.651f, -0.2011f, +-0.4499f, 4.472f, -0.1918f, +-0.2725f, 4.25f, -0.1161f, +-0.2768f, 4.05f, -0.1178f, +-0.3632f, 4.651f, -0.3632f, +-0.3465f, 4.472f, -0.3465f, +-0.2098f, 4.25f, -0.2098f, +-0.213f, 4.05f, -0.213f, +-0.2011f, 4.651f, -0.4715f, +-0.1918f, 4.472f, -0.4499f, +-0.1161f, 4.25f, -0.2725f, +-0.1178f, 4.05f, -0.2768f, +0.0f, 4.651f, -0.5109f, +0.0f, 4.472f, -0.4875f, +0.0f, 4.25f, -0.2953f, +0.0f, 4.05f, -0.3f, +0.2011f, 4.651f, -0.4715f, +0.1918f, 4.472f, -0.4499f, +0.1161f, 4.25f, -0.2725f, +0.1178f, 4.05f, -0.2768f, +0.3632f, 4.651f, -0.3632f, +0.3465f, 4.472f, -0.3465f, +0.2098f, 4.25f, -0.2098f, +0.213f, 4.05f, -0.213f, +0.4715f, 4.651f, -0.2011f, +0.4499f, 4.472f, -0.1918f, +0.2725f, 4.25f, -0.1161f, +0.2768f, 4.05f, -0.1178f, +0.6844f, 3.916f, 0.0f, +1.237f, 3.825f, 0.0f, +1.734f, 3.734f, 0.0f, +1.95f, 3.6f, 0.0f, +0.6313f, 3.916f, 0.2686f, +1.142f, 3.825f, 0.4857f, +1.6f, 3.734f, 0.6807f, +1.799f, 3.6f, 0.7654f, +0.4859f, 3.916f, 0.4859f, +0.8786f, 3.825f, 0.8786f, +1.231f, 3.734f, 1.231f, +1.385f, 3.6f, 1.385f, +0.2686f, 3.916f, 0.6313f, +0.4857f, 3.825f, 1.142f, +0.6807f, 3.734f, 1.6f, +0.7654f, 3.6f, 1.799f, +0.0f, 3.916f, 0.6844f, +0.0f, 3.825f, 1.237f, +0.0f, 3.734f, 1.734f, +0.0f, 3.6f, 1.95f, +-0.2686f, 3.916f, 0.6313f, +-0.4857f, 3.825f, 1.142f, +-0.6807f, 3.734f, 1.6f, +-0.7654f, 3.6f, 1.799f, +-0.4859f, 3.916f, 0.4859f, +-0.8786f, 3.825f, 0.8786f, +-1.231f, 3.734f, 1.231f, +-1.385f, 3.6f, 1.385f, +-0.6313f, 3.916f, 0.2686f, +-1.142f, 3.825f, 0.4857f, +-1.6f, 3.734f, 0.6807f, +-1.799f, 3.6f, 0.7654f, +-0.6844f, 3.916f, 0.0f, +-1.237f, 3.825f, 0.0f, +-1.734f, 3.734f, 0.0f, +-1.95f, 3.6f, 0.0f, +-0.6313f, 3.916f, -0.2686f, +-1.142f, 3.825f, -0.4857f, +-1.6f, 3.734f, -0.6807f, +-1.799f, 3.6f, -0.7654f, +-0.4859f, 3.916f, -0.4859f, +-0.8786f, 3.825f, -0.8786f, +-1.231f, 3.734f, -1.231f, +-1.385f, 3.6f, -1.385f, +-0.2686f, 3.916f, -0.6313f, +-0.4857f, 3.825f, -1.142f, +-0.6807f, 3.734f, -1.6f, +-0.7654f, 3.6f, -1.799f, +0.0f, 3.916f, -0.6844f, +0.0f, 3.825f, -1.237f, +0.0f, 3.734f, -1.734f, +0.0f, 3.6f, -1.95f, +0.2686f, 3.916f, -0.6313f, +0.4857f, 3.825f, -1.142f, +0.6807f, 3.734f, -1.6f, +0.7654f, 3.6f, -1.799f, +0.4859f, 3.916f, -0.4859f, +0.8786f, 3.825f, -0.8786f, +1.231f, 3.734f, -1.231f, +1.385f, 3.6f, -1.385f, +0.6313f, 3.916f, -0.2686f, +1.142f, 3.825f, -0.4857f, +1.6f, 3.734f, -0.6807f, +1.799f, 3.6f, -0.7654f +}; + + +/* 530 normals */ +const int numNormals = 530; +const float normals[530][3] = { +0.0486f, -0.9986f, 0.0168f, +0.9976f, -0.0678f, -0.0008f, +-0.233f, 0.8502f, -0.4719f, +-0.2299f, 0.9679f, 0.1004f, +-0.1648f, 0.985f, 0.0501f, +-0.0117f, 0.7461f, 0.6656f, +-0.0888f, 0.9692f, 0.2294f, +0.6449f, -0.7172f, -0.2637f, +-0.066f, 0.9851f, 0.1583f, +-0.6585f, -0.342f, -0.6703f, +-0.293f, 0.9558f, 0.0209f, +0.179f, 0.9825f, -0.0513f, +-0.0094f, 0.903f, 0.4295f, +-0.0059f, -0.986f, -0.1662f, +-0.7355f, 0.6774f, -0.0026f, +-0.997f, 0.0763f, 0.0019f, +-0.1478f, 0.9333f, 0.3271f, +-0.3014f, -0.6034f, -0.7382f, +-0.7048f, -0.0681f, 0.706f, +-0.3361f, 0.9332f, 0.1263f, +0.3709f, 0.1524f, -0.916f, +-0.3399f, -0.4121f, 0.8453f, +0.1921f, 0.9724f, -0.1316f, +-0.2671f, 0.7429f, 0.6137f, +0.0888f, 0.9692f, -0.2294f, +0.066f, 0.9851f, -0.1583f, +0.9411f, 0.338f, 0.001f, +0.8666f, -0.2559f, 0.4282f, +-0.8029f, 0.4968f, 0.3293f, +-0.0008f, -0.0678f, -0.9976f, +-0.8453f, -0.4121f, -0.3399f, +-0.4801f, -0.8741f, 0.0733f, +0.6355f, -0.772f, 0.0006f, +-0.9215f, -0.0678f, 0.3822f, +-0.6698f, -0.6907f, -0.2723f, +0.3734f, 0.876f, -0.3051f, +0.3548f, -0.4118f, 0.8393f, +-0.3629f, 0.2429f, 0.8995f, +0.9033f, 0.2079f, 0.375f, +-0.2824f, 0.5939f, 0.7532f, +0.8938f, 0.4452f, 0.0532f, +0.1478f, 0.9333f, -0.3271f, +0.0085f, -0.0031f, -0.9999f, +0.3595f, 0.933f, 0.0115f, +0.8995f, 0.2429f, 0.3629f, +0.7048f, -0.0681f, -0.706f, +-0.6428f, -0.7172f, -0.2688f, +0.6366f, -0.447f, 0.6283f, +-0.1213f, -0.9861f, -0.1128f, +0.8003f, 0.4978f, 0.334f, +0.3361f, 0.9332f, -0.1263f, +0.3399f, -0.4121f, -0.8453f, +-0.3909f, 0.4452f, 0.8055f, +0.0117f, 0.7462f, -0.6655f, +0.9215f, -0.0678f, -0.3822f, +0.3582f, -0.7656f, 0.5343f, +-0.9782f, 0.2075f, -0.0011f, +0.2824f, 0.5939f, -0.7532f, +0.035f, -0.8413f, 0.5393f, +-0.8044f, 0.5934f, 0.0262f, +-0.1128f, -0.9861f, 0.1213f, +0.13f, -0.1396f, 0.9816f, +0.6644f, 0.3392f, 0.6659f, +-0.0042f, -0.6898f, -0.7239f, +-0.1587f, 0.9851f, 0.065f, +-0.8719f, -0.3415f, 0.3508f, +0.6486f, 0.4756f, -0.5941f, +-0.4991f, 0.8499f, -0.1684f, +-0.3969f, 0.6342f, -0.6634f, +0.7041f, -0.3863f, -0.5956f, +0.3909f, 0.4452f, -0.8055f, +-0.0391f, -0.0113f, 0.9991f, +-0.3321f, 0.5936f, -0.733f, +0.8523f, -0.5219f, -0.0338f, +0.329f, 0.4978f, 0.8023f, +0.8044f, 0.5934f, -0.0262f, +0.1128f, -0.9861f, -0.1213f, +0.0178f, 0.9861f, -0.1651f, +0.3491f, 0.4045f, 0.8452f, +-0.2727f, 0.8505f, 0.4496f, +0.065f, 0.9851f, 0.1587f, +-0.0005f, 0.4037f, 0.9148f, +-0.0077f, -0.4109f, -0.9116f, +0.5609f, -0.604f, 0.5661f, +0.8236f, 0.5668f, -0.0138f, +0.1587f, 0.9851f, -0.065f, +0.8719f, -0.3415f, -0.3508f, +-0.7382f, -0.6034f, 0.3014f, +0.0346f, 0.8495f, 0.5263f, +-0.4373f, -0.7921f, -0.4257f, +-0.0532f, 0.4452f, 0.8938f, +0.0689f, -0.9861f, 0.1509f, +-0.1509f, -0.9861f, 0.0689f, +0.7706f, -0.2424f, -0.5893f, +-0.7543f, -0.6564f, 0.0105f, +0.0005f, 0.4037f, -0.9148f, +-0.9116f, -0.4109f, 0.0077f, +0.0058f, -0.0438f, 0.999f, +0.1719f, 0.985f, 0.0005f, +-0.1697f, 0.9693f, 0.1774f, +0.5874f, -0.5124f, 0.6263f, +0.7382f, -0.6034f, -0.3014f, +-0.1518f, 0.985f, -0.081f, +0.646f, 0.4051f, 0.6468f, +0.334f, 0.4978f, -0.8003f, +-0.7354f, -0.6034f, -0.3082f, +-0.6919f, 0.2428f, -0.6798f, +0.0532f, 0.4452f, -0.8938f, +0.3547f, -0.3173f, 0.8794f, +0.9879f, -0.1547f, -0.0033f, +-0.0462f, -0.9986f, 0.0223f, +-0.6088f, 0.4806f, 0.6311f, +-0.109f, -0.1969f, -0.9743f, +0.1509f, -0.9861f, -0.0689f, +-0.0568f, 0.9983f, 0.0009f, +0.9074f, -0.3096f, -0.2839f, +0.8677f, 0.4969f, 0.0026f, +-0.2723f, -0.6907f, 0.6698f, +-0.4734f, -0.6798f, 0.5599f, +0.9116f, -0.4109f, -0.0077f, +0.1697f, 0.9693f, -0.1774f, +0.5875f, 0.5937f, 0.5497f, +-0.3232f, 0.6846f, 0.6533f, +-0.5078f, -0.6913f, 0.5139f, +-0.4612f, 0.7474f, -0.478f, +-0.2071f, -0.8049f, 0.556f, +-0.6976f, -0.7164f, -0.0027f, +-0.8697f, 0.3388f, 0.3587f, +0.0462f, -0.9986f, -0.0223f, +0.2723f, -0.6907f, -0.6698f, +-0.829f, -0.4466f, -0.3365f, +0.9148f, 0.4037f, 0.0005f, +-0.1583f, 0.9851f, -0.066f, +0.148f, 0.9838f, 0.1002f, +-0.1717f, 0.985f, -0.0162f, +-0.4282f, -0.2559f, 0.8666f, +0.3094f, -0.2556f, 0.9159f, +0.2803f, -0.6907f, 0.6665f, +-0.6154f, 0.497f, 0.6117f, +-0.0262f, 0.5934f, -0.8044f, +0.0286f, 0.1639f, -0.986f, +-0.6924f, 0.2083f, 0.6907f, +-0.0105f, 0.9975f, -0.0685f, +0.5078f, -0.6913f, -0.5139f, +0.2071f, -0.8049f, -0.556f, +-0.4903f, -0.7178f, -0.4942f, +-0.2637f, -0.7172f, -0.6449f, +-0.3822f, -0.0678f, -0.9215f, +0.8697f, 0.3388f, -0.3587f, +0.2461f, -0.805f, 0.5397f, +-0.2615f, 0.9334f, 0.2452f, +0.6187f, 0.747f, -0.243f, +0.0375f, -0.8401f, -0.5411f, +0.0054f, 0.9691f, 0.2464f, +0.3587f, 0.3388f, 0.8697f, +0.3993f, 0.6582f, -0.6381f, +-0.3476f, -0.4464f, -0.8245f, +0.099f, 0.9692f, 0.2251f, +-0.3666f, -0.3412f, 0.8655f, +0.0396f, 0.153f, -0.9874f, +0.0349f, 0.9969f, -0.0698f, +0.1096f, 0.985f, 0.1324f, +-0.0578f, -0.9861f, 0.1556f, +0.4479f, -0.5145f, -0.7311f, +0.6924f, 0.2083f, -0.6907f, +0.6096f, 0.747f, 0.265f, +-0.3508f, -0.3415f, -0.8719f, +-0.6215f, 0.4454f, -0.6443f, +-0.4942f, -0.7178f, 0.4903f, +-0.9402f, -0.3403f, -0.0085f, +0.0056f, -0.0358f, 0.9993f, +0.2615f, 0.9334f, -0.2452f, +-0.0024f, 0.0291f, -0.9995f, +-0.2667f, 0.9637f, -0.001f, +0.0569f, -0.2712f, -0.9608f, +0.7463f, 0.254f, 0.615f, +0.5153f, 0.6516f, -0.5564f, +0.0223f, -0.9986f, 0.0462f, +0.3666f, -0.3412f, -0.8655f, +0.0578f, -0.9861f, -0.1556f, +0.6111f, 0.4984f, 0.6148f, +-0.243f, 0.747f, -0.6187f, +-0.0092f, 0.2338f, -0.9722f, +0.478f, 0.7474f, -0.4612f, +-0.0058f, -0.4457f, -0.8951f, +-0.4856f, -0.6774f, -0.5524f, +0.54f, 0.6414f, 0.5448f, +-0.3365f, -0.4466f, 0.829f, +-0.2257f, 0.795f, 0.5629f, +0.8055f, 0.4452f, 0.3909f, +0.3729f, 0.208f, 0.9042f, +-0.727f, -0.2562f, 0.6369f, +-0.0514f, -0.9986f, 0.0029f, +0.9159f, 0.1555f, -0.3699f, +0.0019f, -0.2377f, -0.9713f, +0.4942f, -0.7178f, -0.4903f, +0.6497f, -0.4127f, 0.6383f, +0.0089f, 0.0486f, -0.9987f, +-0.0213f, 0.6301f, -0.7761f, +-0.9269f, -0.3751f, 0.0038f, +-0.1215f, 0.9852f, 0.1207f, +-0.5856f, 0.5198f, 0.6218f, +0.8655f, -0.3412f, 0.3666f, +-0.2464f, 0.9691f, 0.0054f, +0.0123f, 0.1386f, 0.9902f, +0.0179f, -0.0369f, 0.9991f, +-0.1207f, 0.9852f, -0.1215f, +-0.0081f, 0.5671f, 0.8235f, +-0.8689f, 0.3387f, -0.3607f, +0.0062f, 0.0309f, -0.9995f, +0.3365f, -0.4466f, -0.829f, +-0.3787f, 0.2424f, -0.8931f, +-0.2904f, 0.4454f, -0.8468f, +-0.8707f, 0.4915f, 0.0133f, +0.163f, -0.8182f, 0.5512f, +0.4337f, -0.8052f, 0.4041f, +0.0514f, -0.9986f, -0.0029f, +-0.0084f, 0.1303f, 0.9914f, +-0.706f, -0.0681f, -0.7048f, +-0.556f, -0.8049f, -0.2071f, +0.8448f, 0.4045f, 0.3501f, +0.4259f, -0.5474f, 0.7203f, +-0.6907f, 0.2083f, -0.6924f, +0.1215f, 0.9852f, -0.1207f, +-0.1263f, 0.9332f, -0.3361f, +0.7711f, -0.0741f, -0.6323f, +0.2464f, 0.9691f, -0.0054f, +0.1774f, 0.9693f, 0.1697f, +-0.9042f, 0.208f, 0.3729f, +-0.8393f, -0.4118f, 0.3548f, +0.6888f, -0.7219f, -0.0648f, +0.1556f, -0.9861f, 0.0578f, +0.3271f, 0.9333f, 0.1478f, +-0.0024f, 0.2379f, 0.9712f, +-0.0026f, 0.4969f, 0.8677f, +0.0f, 1.0f, 0.0f, +0.1912f, -0.9815f, -0.0025f, +-0.3762f, -0.6681f, 0.6418f, +-0.7759f, 0.0432f, 0.6292f, +-0.0208f, -0.8044f, -0.5936f, +-0.2274f, 0.8822f, -0.4122f, +0.7532f, 0.5939f, 0.2824f, +-0.9221f, -0.0681f, -0.3807f, +-0.2198f, 0.8494f, 0.4796f, +0.0065f, -0.7656f, 0.6431f, +-0.5876f, 0.4472f, -0.6742f, +0.7981f, -0.6024f, 0.0036f, +-0.0383f, -0.9986f, -0.0341f, +-0.6369f, -0.2562f, -0.727f, +-0.5497f, 0.5937f, 0.5875f, +0.1084f, 0.9431f, 0.314f, +0.9042f, 0.208f, -0.3729f, +-0.6659f, 0.3392f, 0.6644f, +0.8393f, -0.4118f, -0.3548f, +0.0029f, -0.9986f, 0.0514f, +-0.9647f, -0.2552f, -0.0635f, +-0.2294f, 0.9692f, -0.0888f, +0.0026f, 0.4969f, -0.8677f, +0.2452f, 0.9334f, 0.2615f, +0.5171f, -0.4876f, -0.7033f, +-0.8951f, -0.4457f, 0.0058f, +-0.5936f, -0.8044f, 0.0208f, +0.5642f, -0.5426f, -0.6222f, +0.5938f, 0.4451f, 0.6702f, +0.5497f, 0.5937f, -0.5875f, +0.6657f, 0.4653f, 0.5832f, +0.4857f, -0.6243f, 0.6117f, +-0.0486f, -0.9986f, -0.0168f, +-0.6468f, 0.4051f, 0.646f, +0.6659f, 0.3392f, -0.6644f, +0.1833f, 0.9735f, -0.1365f, +0.3955f, 0.8505f, 0.3465f, +0.5139f, -0.6913f, 0.5078f, +0.8023f, 0.4978f, -0.329f, +-0.001f, 0.338f, 0.9411f, +-0.2496f, 0.8321f, -0.4951f, +0.8951f, -0.4457f, -0.0058f, +0.233f, 0.8502f, 0.4719f, +-0.0168f, -0.9986f, 0.0486f, +0.5936f, -0.8044f, -0.0208f, +-0.05f, 0.3155f, 0.9475f, +0.6585f, -0.342f, 0.6703f, +0.4909f, -0.1864f, -0.8509f, +-0.37f, 0.9238f, -0.0973f, +0.6468f, 0.4051f, -0.646f, +0.0059f, -0.986f, 0.1662f, +-0.3724f, 0.9278f, -0.0202f, +-0.3501f, 0.4045f, 0.8448f, +-0.0425f, 0.8398f, -0.5411f, +-0.1684f, 0.8499f, 0.4991f, +-0.6665f, -0.6907f, 0.2803f, +-0.2251f, 0.9692f, 0.099f, +0.9241f, -0.3816f, -0.0169f, +0.001f, 0.338f, -0.9411f, +-0.9411f, 0.338f, -0.001f, +-0.8666f, -0.2559f, -0.4282f, +0.0262f, 0.5183f, -0.8547f, +0.3014f, -0.6034f, 0.7382f, +0.0168f, -0.9986f, -0.0486f, +-0.3548f, -0.4118f, -0.8393f, +-0.6023f, -0.5297f, 0.5971f, +-0.9033f, 0.2079f, -0.375f, +-0.8938f, 0.4452f, -0.0532f, +0.6044f, 0.7397f, 0.2957f, +0.0008f, -0.0678f, 0.9976f, +0.7058f, 0.0906f, -0.7025f, +0.8453f, -0.4121f, 0.3399f, +-0.3595f, 0.933f, -0.0115f, +0.6698f, -0.6907f, 0.2723f, +-0.8995f, 0.2429f, -0.3629f, +-0.6366f, -0.447f, -0.6283f, +0.3501f, 0.4045f, -0.8448f, +-0.01f, -0.0605f, 0.9981f, +-0.8003f, 0.4978f, -0.334f, +0.1684f, 0.8499f, -0.4991f, +0.6665f, -0.6907f, -0.2803f, +0.2251f, 0.9692f, -0.099f, +-0.0036f, -0.6024f, 0.7981f, +0.6637f, -0.2967f, -0.6865f, +-0.081f, 0.985f, 0.1518f, +0.0084f, 0.2423f, 0.9701f, +0.0071f, -0.9029f, -0.4296f, +-0.8679f, 0.4966f, -0.0026f, +0.0123f, 0.5735f, 0.819f, +-0.0005f, 0.985f, 0.1719f, +0.6428f, -0.7172f, 0.2688f, +0.6588f, -0.3366f, 0.6727f, +0.1213f, -0.9861f, 0.1128f, +-0.8931f, 0.2424f, 0.3787f, +-0.1662f, -0.986f, 0.0059f, +0.9994f, 0.0313f, 0.0095f, +0.762f, -0.146f, 0.6308f, +-0.7731f, 0.0861f, -0.6283f, +-0.6644f, 0.3392f, -0.6659f, +-0.0027f, -0.7164f, 0.6976f, +0.0036f, -0.6024f, -0.7981f, +0.9782f, 0.2075f, 0.0011f, +0.0405f, -0.9991f, -0.0018f, +0.6882f, -0.703f, 0.179f, +-0.0115f, 0.933f, 0.3595f, +0.0911f, 0.0518f, -0.9944f, +0.0005f, 0.985f, -0.1719f, +0.5337f, -0.5852f, -0.6104f, +0.0042f, -0.6898f, 0.7239f, +0.4863f, 0.2366f, 0.8411f, +0.4991f, 0.8499f, 0.1684f, +-0.6543f, 0.7561f, 0.0071f, +0.265f, 0.747f, -0.6096f, +-0.329f, 0.4978f, -0.8023f, +0.1662f, -0.986f, -0.0059f, +-0.3491f, 0.4045f, -0.8452f, +0.3321f, 0.5936f, 0.733f, +-0.065f, 0.9851f, -0.1587f, +-0.6283f, -0.447f, 0.6366f, +0.0027f, -0.7164f, -0.6976f, +-0.1316f, 0.6339f, 0.762f, +-0.5609f, -0.604f, -0.5661f, +-0.8452f, 0.4045f, 0.3491f, +-0.5263f, 0.8495f, 0.0346f, +0.0115f, 0.933f, -0.3595f, +-0.0346f, 0.8495f, -0.5263f, +0.0077f, -0.4109f, 0.9116f, +0.5758f, -0.8175f, -0.0017f, +-0.0011f, 0.2075f, 0.9782f, +-0.0689f, -0.9861f, -0.1509f, +0.2934f, -0.5928f, -0.7499f, +0.0724f, 0.1198f, -0.9901f, +-0.7367f, -0.275f, -0.6176f, +-0.3131f, 0.8154f, 0.4868f, +-0.0114f, 0.0022f, 0.9999f, +0.6283f, -0.447f, -0.6366f, +0.8452f, 0.4045f, -0.3491f, +0.5263f, 0.8495f, -0.0346f, +-0.6383f, -0.4127f, 0.6497f, +-0.1719f, 0.985f, -0.0005f, +-0.6703f, -0.342f, 0.6585f, +-0.0085f, -0.3403f, 0.9402f, +-0.646f, 0.4051f, -0.6468f, +0.0011f, 0.2075f, -0.9782f, +-0.7216f, -0.3071f, 0.6204f, +0.0282f, 0.0023f, -0.9995f, +-0.2483f, 0.6806f, -0.6892f, +0.1518f, 0.985f, 0.081f, +0.047f, 0.0466f, -0.9978f, +0.7354f, -0.6034f, 0.3082f, +0.6919f, 0.2428f, 0.6798f, +0.4086f, -0.3626f, -0.8375f, +0.6383f, -0.4127f, -0.6497f, +-0.5875f, 0.5937f, -0.5497f, +0.6703f, -0.342f, -0.6585f, +-0.8245f, -0.4464f, 0.3476f, +0.0085f, -0.3403f, -0.9402f, +-0.0591f, -0.0663f, 0.996f, +0.0f, -1.0f, 0.0f, +0.4612f, 0.7474f, 0.478f, +0.6976f, -0.7164f, 0.0027f, +-0.9148f, 0.4037f, -0.0005f, +0.173f, -0.8158f, -0.5518f, +-0.3607f, 0.3387f, 0.8689f, +0.7836f, -0.2411f, 0.5724f, +-0.1985f, 0.8026f, -0.5623f, +-0.3094f, -0.2556f, -0.9159f, +-0.2803f, -0.6907f, -0.6665f, +0.8245f, -0.4464f, -0.3476f, +0.829f, -0.4466f, 0.3365f, +-0.4848f, 0.7385f, 0.4683f, +0.1583f, 0.9851f, 0.066f, +-0.0077f, 0.7656f, -0.6432f, +-0.0162f, 0.985f, 0.1717f, +0.1717f, 0.985f, 0.0162f, +0.0244f, 0.9805f, -0.1949f, +-0.2461f, -0.805f, -0.5397f, +0.0262f, 0.5934f, 0.8044f, +0.142f, 0.1881f, 0.9718f, +0.1846f, 0.1002f, 0.9776f, +0.4903f, -0.7178f, 0.4942f, +0.2637f, -0.7172f, 0.6449f, +0.3822f, -0.0678f, 0.9215f, +-0.0054f, 0.9691f, -0.2464f, +0.3607f, 0.3387f, -0.8689f, +-0.3587f, 0.3388f, -0.8697f, +-0.5694f, -0.8219f, 0.0081f, +-0.1324f, 0.985f, 0.1096f, +-0.099f, 0.9692f, -0.2251f, +-0.6702f, 0.4451f, 0.5938f, +0.0077f, -0.9976f, 0.0684f, +-0.5661f, -0.604f, 0.5609f, +-0.1096f, 0.985f, -0.1324f, +-0.6096f, 0.747f, -0.265f, +-0.0015f, 0.0295f, -0.9995f, +0.3476f, -0.4464f, 0.8245f, +-0.0635f, -0.2552f, 0.9647f, +-0.8468f, 0.4454f, 0.2904f, +-0.4719f, 0.8502f, 0.233f, +-0.0502f, 0.8385f, 0.5425f, +-0.6671f, 0.7448f, -0.0116f, +0.3508f, -0.3415f, 0.8719f, +-0.4119f, 0.6135f, -0.6736f, +-0.2688f, -0.7172f, 0.6428f, +-0.4041f, -0.8052f, 0.4337f, +-0.375f, 0.2079f, 0.9033f, +-0.0223f, -0.9986f, -0.0462f, +0.6702f, 0.4451f, -0.5938f, +0.9402f, -0.3403f, 0.0085f, +0.5661f, -0.604f, -0.5609f, +-0.6252f, 0.7406f, 0.246f, +-0.0341f, -0.9986f, 0.0383f, +-0.6111f, 0.4984f, -0.6148f, +0.6655f, 0.7462f, 0.0117f, +0.1233f, 0.199f, 0.9722f, +0.8468f, 0.4454f, -0.2904f, +0.7383f, 0.2702f, -0.6179f, +-0.8055f, 0.4452f, -0.3909f, +-0.3729f, 0.208f, -0.9042f, +0.4719f, 0.8502f, -0.233f, +0.243f, 0.747f, 0.6187f, +-0.6497f, -0.4127f, -0.6383f, +-0.5406f, 0.5651f, -0.623f, +0.0058f, -0.4457f, 0.8951f, +-0.3082f, -0.6034f, 0.7354f, +-0.8655f, -0.3412f, -0.3666f, +0.2688f, -0.7172f, -0.6428f, +0.4041f, -0.8052f, -0.4337f, +0.375f, 0.2079f, -0.9033f, +0.0341f, -0.9986f, -0.0383f, +-0.9701f, 0.2423f, 0.0084f, +-0.3807f, -0.0681f, 0.9221f, +0.9643f, -0.2551f, 0.0705f, +-0.8758f, 0.4808f, 0.0415f, +0.1207f, 0.9852f, 0.1215f, +0.4821f, 0.7724f, 0.4133f, +-0.0522f, 0.9982f, 0.0278f, +-0.4337f, -0.8052f, -0.4041f, +-0.6164f, 0.4198f, 0.6661f, +-0.8448f, 0.4045f, -0.3501f, +0.3082f, -0.6034f, -0.7354f, +0.8689f, 0.3387f, 0.3607f, +0.6894f, -0.7242f, 0.0091f, +0.3787f, 0.2424f, 0.8931f, +0.2904f, 0.4454f, 0.8468f, +0.6148f, 0.4984f, -0.6111f, +0.0501f, 0.985f, 0.1648f, +-0.5397f, -0.805f, 0.2461f, +-0.9159f, -0.2556f, 0.3094f, +0.706f, -0.0681f, 0.7048f, +-0.3341f, 0.4972f, 0.8006f, +0.556f, -0.8049f, 0.2071f, +-0.1774f, 0.9693f, -0.1697f, +0.6907f, 0.2083f, 0.6924f, +0.1263f, 0.9332f, 0.3361f, +0.3807f, -0.0681f, -0.9221f, +-0.1556f, -0.9861f, -0.0578f, +-0.3271f, 0.9333f, -0.1478f, +-0.3465f, 0.8505f, 0.3955f, +0.5315f, 0.8438f, -0.0735f, +0.9737f, 0.2276f, -0.0003f, +0.6441f, 0.7648f, -0.0112f, +-0.7239f, -0.6898f, 0.0042f, +-0.7532f, 0.5939f, -0.2824f, +0.1093f, 0.1415f, -0.9838f, +0.5397f, -0.805f, -0.2461f, +-0.7981f, -0.6024f, -0.0036f, +0.9456f, 0.3251f, -0.0052f, +0.1278f, 0.9696f, -0.2085f, +0.0208f, -0.8044f, 0.5936f, +0.1635f, 0.1348f, -0.9772f, +-0.733f, 0.5936f, 0.3321f, +-0.0505f, 0.9852f, -0.1635f, +0.4089f, -0.9069f, -0.1015f, +-0.0029f, -0.9986f, -0.0514f, +-0.1796f, 0.814f, -0.5522f, +0.9221f, -0.0681f, 0.3807f, +0.0383f, -0.9986f, 0.0341f, +0.6369f, -0.2562f, 0.727f, +0.3465f, 0.8505f, -0.3955f, +-0.2452f, 0.9334f, -0.2615f, +0.4921f, -0.247f, 0.8346f, +-0.9976f, -0.0678f, 0.0008f, +-0.5396f, 0.8418f, -0.0094f, +0.2294f, 0.9692f, 0.0888f, +0.7239f, -0.6898f, -0.0042f, +-0.4472f, 0.5952f, 0.6675f, +-0.6449f, -0.7172f, 0.2637f, +0.4543f, 0.2732f, -0.8478f, +-0.6798f, 0.2428f, 0.6919f, +-0.5938f, 0.4451f, -0.6702f, +0.733f, 0.5936f, -0.3321f, +-0.3955f, 0.8505f, -0.3465f, +-0.5139f, -0.6913f, -0.5078f, +-0.623f, -0.5156f, -0.5881f +}; + +/* 1 color */ +/*255 255 0 */ + +/* 1024 faces */ +/* numIdx fidx0 fidx1 fidx2 nidx0 nidx1 nidx2 coloridx */ + +const int numFaces = 1024; +const int faces[1024][8] = { +3, 0, 5, 6, 255, 295, 309, 0, +3, 6, 1, 0, 309, 465, 255, 0, +3, 1, 6, 7, 465, 309, 134, 0, +3, 7, 2, 1, 134, 4, 465, 0, +3, 2, 7, 8, 4, 134, 165, 0, +3, 8, 3, 2, 165, 448, 4, 0, +3, 3, 8, 9, 448, 165, 49, 0, +3, 9, 4, 3, 49, 116, 448, 0, +3, 5, 10, 11, 295, 248, 106, 0, +3, 11, 6, 5, 106, 309, 295, 0, +3, 6, 11, 12, 309, 106, 102, 0, +3, 12, 7, 6, 102, 134, 309, 0, +3, 7, 12, 13, 134, 102, 394, 0, +3, 13, 8, 7, 394, 165, 134, 0, +3, 8, 13, 14, 165, 394, 180, 0, +3, 14, 9, 8, 180, 49, 165, 0, +3, 10, 15, 16, 248, 401, 211, 0, +3, 16, 11, 10, 211, 106, 248, 0, +3, 11, 16, 17, 106, 211, 427, 0, +3, 17, 12, 11, 427, 102, 106, 0, +3, 12, 17, 18, 102, 427, 455, 0, +3, 18, 13, 12, 455, 394, 102, 0, +3, 13, 18, 19, 394, 455, 74, 0, +3, 19, 14, 13, 74, 180, 394, 0, +3, 15, 20, 21, 401, 174, 182, 0, +3, 21, 16, 15, 182, 211, 401, 0, +3, 16, 21, 22, 211, 182, 507, 0, +3, 22, 17, 16, 507, 427, 211, 0, +3, 17, 22, 23, 427, 507, 5, 0, +3, 23, 18, 17, 5, 455, 427, 0, +3, 18, 23, 24, 455, 5, 234, 0, +3, 24, 19, 18, 234, 74, 455, 0, +3, 20, 25, 26, 174, 386, 20, 0, +3, 26, 21, 20, 20, 182, 174, 0, +3, 21, 26, 27, 182, 20, 410, 0, +3, 27, 22, 21, 410, 507, 182, 0, +3, 22, 27, 28, 507, 410, 23, 0, +3, 28, 23, 22, 23, 5, 507, 0, +3, 23, 28, 29, 5, 23, 485, 0, +3, 29, 24, 23, 485, 234, 5, 0, +3, 25, 30, 31, 386, 69, 305, 0, +3, 31, 26, 25, 305, 20, 386, 0, +3, 26, 31, 32, 20, 305, 503, 0, +3, 32, 27, 26, 503, 410, 20, 0, +3, 27, 32, 33, 410, 503, 405, 0, +3, 33, 28, 27, 405, 23, 410, 0, +3, 28, 33, 34, 23, 405, 138, 0, +3, 34, 29, 28, 138, 485, 23, 0, +3, 30, 35, 36, 69, 115, 193, 0, +3, 36, 31, 30, 193, 305, 69, 0, +3, 31, 36, 37, 305, 193, 270, 0, +3, 37, 32, 31, 270, 503, 305, 0, +3, 32, 37, 38, 503, 270, 445, 0, +3, 38, 33, 32, 445, 405, 503, 0, +3, 33, 38, 39, 405, 445, 28, 0, +3, 39, 34, 33, 28, 138, 405, 0, +3, 35, 40, 41, 115, 467, 495, 0, +3, 41, 36, 35, 495, 193, 115, 0, +3, 36, 41, 42, 193, 495, 11, 0, +3, 42, 37, 36, 11, 270, 193, 0, +3, 37, 42, 43, 270, 11, 435, 0, +3, 43, 38, 37, 435, 445, 270, 0, +3, 38, 43, 44, 445, 435, 322, 0, +3, 44, 39, 38, 322, 28, 445, 0, +3, 40, 45, 46, 467, 27, 44, 0, +3, 46, 41, 40, 44, 495, 467, 0, +3, 41, 46, 47, 495, 44, 409, 0, +3, 47, 42, 41, 409, 11, 495, 0, +3, 42, 47, 48, 11, 409, 428, 0, +3, 48, 43, 42, 428, 435, 11, 0, +3, 43, 48, 49, 435, 428, 313, 0, +3, 49, 44, 43, 313, 322, 435, 0, +3, 45, 50, 51, 27, 513, 385, 0, +3, 51, 46, 45, 385, 44, 27, 0, +3, 46, 51, 52, 44, 385, 382, 0, +3, 52, 47, 46, 382, 409, 44, 0, +3, 47, 52, 53, 409, 382, 124, 0, +3, 53, 48, 47, 124, 428, 409, 0, +3, 48, 53, 54, 428, 124, 447, 0, +3, 54, 49, 48, 447, 313, 428, 0, +3, 50, 55, 56, 513, 136, 478, 0, +3, 56, 51, 50, 478, 385, 513, 0, +3, 51, 56, 57, 385, 478, 161, 0, +3, 57, 52, 51, 161, 382, 385, 0, +3, 52, 57, 58, 382, 161, 181, 0, +3, 58, 53, 52, 181, 124, 382, 0, +3, 53, 58, 59, 124, 181, 348, 0, +3, 59, 54, 53, 348, 447, 124, 0, +3, 55, 60, 61, 136, 431, 320, 0, +3, 61, 56, 55, 320, 478, 136, 0, +3, 56, 61, 62, 478, 320, 481, 0, +3, 62, 57, 56, 481, 161, 478, 0, +3, 57, 62, 63, 161, 481, 53, 0, +3, 63, 58, 57, 53, 181, 161, 0, +3, 58, 63, 64, 181, 53, 257, 0, +3, 64, 59, 58, 257, 348, 181, 0, +3, 60, 65, 66, 431, 135, 37, 0, +3, 66, 61, 60, 37, 320, 431, 0, +3, 61, 66, 67, 320, 37, 408, 0, +3, 67, 62, 61, 408, 481, 320, 0, +3, 62, 67, 68, 481, 408, 347, 0, +3, 68, 63, 62, 347, 53, 481, 0, +3, 63, 68, 69, 53, 347, 104, 0, +3, 69, 64, 63, 104, 257, 53, 0, +3, 65, 70, 71, 135, 191, 524, 0, +3, 71, 66, 65, 524, 37, 135, 0, +3, 66, 71, 72, 37, 524, 319, 0, +3, 72, 67, 66, 319, 408, 37, 0, +3, 67, 72, 73, 408, 319, 183, 0, +3, 73, 68, 67, 183, 347, 408, 0, +3, 68, 73, 74, 347, 183, 480, 0, +3, 74, 69, 68, 480, 104, 347, 0, +3, 70, 75, 76, 191, 483, 328, 0, +3, 76, 71, 70, 328, 524, 191, 0, +3, 71, 76, 77, 524, 328, 422, 0, +3, 77, 72, 71, 422, 319, 524, 0, +3, 72, 77, 78, 319, 422, 151, 0, +3, 78, 73, 72, 151, 183, 319, 0, +3, 73, 78, 79, 183, 151, 273, 0, +3, 79, 74, 73, 273, 480, 183, 0, +3, 75, 0, 1, 483, 255, 465, 0, +3, 1, 76, 75, 465, 328, 483, 0, +3, 76, 1, 2, 328, 465, 4, 0, +3, 2, 77, 76, 4, 422, 328, 0, +3, 77, 2, 3, 422, 4, 448, 0, +3, 3, 78, 77, 448, 151, 422, 0, +3, 78, 3, 4, 151, 448, 116, 0, +3, 4, 79, 78, 116, 273, 151, 0, +3, 4, 9, 84, 116, 49, 220, 0, +3, 84, 80, 4, 220, 131, 116, 0, +3, 80, 84, 85, 131, 220, 476, 0, +3, 85, 81, 80, 476, 26, 131, 0, +3, 81, 85, 86, 26, 476, 38, 0, +3, 86, 82, 81, 38, 336, 26, 0, +3, 82, 86, 87, 336, 38, 511, 0, +3, 87, 83, 82, 511, 1, 336, 0, +3, 9, 14, 88, 49, 180, 103, 0, +3, 88, 84, 9, 103, 220, 49, 0, +3, 84, 88, 89, 220, 103, 62, 0, +3, 89, 85, 84, 62, 476, 220, 0, +3, 85, 89, 90, 476, 62, 488, 0, +3, 90, 86, 85, 488, 38, 476, 0, +3, 86, 90, 91, 38, 488, 484, 0, +3, 91, 87, 86, 484, 511, 38, 0, +3, 14, 19, 92, 180, 74, 78, 0, +3, 92, 88, 14, 78, 103, 180, 0, +3, 88, 92, 93, 103, 78, 154, 0, +3, 93, 89, 88, 154, 62, 103, 0, +3, 89, 93, 94, 62, 154, 190, 0, +3, 94, 90, 89, 190, 488, 62, 0, +3, 90, 94, 95, 488, 190, 417, 0, +3, 95, 91, 90, 417, 484, 488, 0, +3, 19, 24, 96, 74, 234, 81, 0, +3, 96, 92, 19, 81, 78, 74, 0, +3, 92, 96, 97, 78, 81, 274, 0, +3, 97, 93, 92, 274, 154, 78, 0, +3, 93, 97, 98, 154, 274, 363, 0, +3, 98, 94, 93, 363, 190, 154, 0, +3, 94, 98, 99, 190, 363, 304, 0, +3, 99, 95, 94, 304, 417, 190, 0, +3, 24, 29, 100, 234, 485, 287, 0, +3, 100, 96, 24, 287, 81, 234, 0, +3, 96, 100, 101, 81, 287, 398, 0, +3, 101, 97, 96, 398, 274, 81, 0, +3, 97, 101, 102, 274, 398, 440, 0, +3, 102, 98, 97, 440, 363, 274, 0, +3, 98, 102, 103, 363, 440, 466, 0, +3, 103, 99, 98, 466, 304, 363, 0, +3, 29, 34, 104, 485, 138, 268, 0, +3, 104, 100, 29, 268, 287, 485, 0, +3, 100, 104, 105, 287, 268, 252, 0, +3, 105, 101, 100, 252, 398, 287, 0, +3, 101, 105, 106, 398, 252, 141, 0, +3, 106, 102, 101, 141, 440, 398, 0, +3, 102, 106, 107, 440, 141, 18, 0, +3, 107, 103, 102, 18, 466, 440, 0, +3, 34, 39, 108, 138, 28, 357, 0, +3, 108, 104, 34, 357, 268, 138, 0, +3, 104, 108, 109, 268, 357, 127, 0, +3, 109, 105, 104, 127, 252, 268, 0, +3, 105, 109, 110, 252, 127, 228, 0, +3, 110, 106, 105, 228, 141, 252, 0, +3, 106, 110, 111, 141, 228, 33, 0, +3, 111, 107, 106, 33, 18, 141, 0, +3, 39, 44, 112, 28, 322, 396, 0, +3, 112, 108, 39, 396, 357, 28, 0, +3, 108, 112, 113, 357, 396, 294, 0, +3, 113, 109, 108, 294, 127, 357, 0, +3, 109, 113, 114, 127, 294, 56, 0, +3, 114, 110, 109, 56, 228, 127, 0, +3, 110, 114, 115, 228, 56, 517, 0, +3, 115, 111, 110, 517, 33, 228, 0, +3, 44, 49, 116, 322, 313, 474, 0, +3, 116, 112, 44, 474, 396, 322, 0, +3, 112, 116, 117, 396, 474, 208, 0, +3, 117, 113, 112, 208, 294, 396, 0, +3, 113, 117, 118, 294, 208, 301, 0, +3, 118, 114, 113, 301, 56, 294, 0, +3, 114, 118, 119, 56, 301, 242, 0, +3, 119, 115, 114, 242, 517, 56, 0, +3, 49, 54, 120, 313, 447, 377, 0, +3, 120, 116, 49, 377, 474, 313, 0, +3, 116, 120, 121, 474, 377, 333, 0, +3, 121, 117, 116, 333, 208, 474, 0, +3, 117, 121, 122, 208, 333, 222, 0, +3, 122, 118, 117, 222, 301, 208, 0, +3, 118, 122, 123, 301, 222, 218, 0, +3, 123, 119, 118, 218, 242, 301, 0, +3, 54, 59, 124, 447, 348, 350, 0, +3, 124, 120, 54, 350, 377, 447, 0, +3, 120, 124, 125, 377, 350, 420, 0, +3, 125, 121, 120, 420, 333, 377, 0, +3, 121, 125, 126, 333, 420, 453, 0, +3, 126, 122, 121, 453, 222, 333, 0, +3, 122, 126, 127, 222, 453, 147, 0, +3, 127, 123, 122, 147, 218, 222, 0, +3, 59, 64, 128, 348, 257, 95, 0, +3, 128, 124, 59, 95, 350, 348, 0, +3, 124, 128, 129, 350, 95, 293, 0, +3, 129, 125, 124, 293, 420, 350, 0, +3, 125, 129, 130, 420, 293, 378, 0, +3, 130, 126, 125, 378, 453, 420, 0, +3, 126, 130, 131, 453, 378, 29, 0, +3, 131, 127, 126, 29, 147, 453, 0, +3, 64, 69, 132, 257, 104, 311, 0, +3, 132, 128, 64, 311, 95, 257, 0, +3, 128, 132, 133, 95, 311, 419, 0, +3, 133, 129, 128, 419, 293, 95, 0, +3, 129, 133, 134, 293, 419, 463, 0, +3, 134, 130, 129, 463, 378, 293, 0, +3, 130, 134, 135, 378, 463, 490, 0, +3, 135, 131, 130, 490, 29, 378, 0, +3, 69, 74, 136, 104, 480, 284, 0, +3, 136, 132, 69, 284, 311, 104, 0, +3, 132, 136, 137, 311, 284, 269, 0, +3, 137, 133, 132, 269, 419, 311, 0, +3, 133, 137, 138, 419, 269, 164, 0, +3, 138, 134, 133, 164, 463, 419, 0, +3, 134, 138, 139, 463, 164, 45, 0, +3, 139, 135, 134, 45, 490, 463, 0, +3, 74, 79, 140, 480, 273, 371, 0, +3, 140, 136, 74, 371, 284, 480, 0, +3, 136, 140, 141, 284, 371, 148, 0, +3, 141, 137, 136, 148, 269, 284, 0, +3, 137, 141, 142, 269, 148, 251, 0, +3, 142, 138, 137, 251, 164, 269, 0, +3, 138, 142, 143, 164, 251, 54, 0, +3, 143, 139, 138, 54, 45, 164, 0, +3, 79, 4, 80, 273, 116, 131, 0, +3, 80, 140, 79, 131, 371, 273, 0, +3, 140, 80, 81, 371, 131, 26, 0, +3, 81, 141, 140, 26, 148, 371, 0, +3, 141, 81, 82, 148, 26, 336, 0, +3, 82, 142, 141, 336, 251, 148, 0, +3, 142, 82, 83, 251, 336, 1, 0, +3, 83, 143, 142, 1, 54, 251, 0, +3, 83, 87, 148, 1, 511, 404, 0, +3, 148, 144, 83, 404, 276, 1, 0, +3, 144, 148, 149, 276, 404, 308, 0, +3, 149, 145, 144, 308, 520, 276, 0, +3, 145, 149, 150, 520, 308, 325, 0, +3, 150, 146, 145, 325, 395, 520, 0, +3, 146, 150, 151, 395, 325, 384, 0, +3, 151, 147, 146, 384, 246, 395, 0, +3, 87, 91, 152, 511, 484, 47, 0, +3, 152, 148, 87, 47, 404, 511, 0, +3, 148, 152, 153, 404, 47, 272, 0, +3, 153, 149, 148, 272, 308, 404, 0, +3, 149, 153, 154, 308, 272, 415, 0, +3, 154, 150, 149, 415, 325, 308, 0, +3, 150, 154, 155, 325, 415, 83, 0, +3, 155, 151, 150, 83, 384, 325, 0, +3, 91, 95, 156, 484, 417, 430, 0, +3, 156, 152, 91, 430, 47, 484, 0, +3, 152, 156, 157, 47, 430, 137, 0, +3, 157, 153, 152, 137, 272, 47, 0, +3, 153, 157, 158, 272, 137, 416, 0, +3, 158, 154, 153, 416, 415, 272, 0, +3, 154, 158, 159, 415, 416, 297, 0, +3, 159, 155, 154, 297, 83, 415, 0, +3, 95, 99, 160, 417, 304, 458, 0, +3, 160, 156, 95, 458, 430, 417, 0, +3, 156, 160, 161, 430, 458, 343, 0, +3, 161, 157, 156, 343, 137, 430, 0, +3, 157, 161, 162, 137, 343, 334, 0, +3, 162, 158, 157, 334, 416, 137, 0, +3, 158, 162, 163, 416, 334, 317, 0, +3, 163, 159, 158, 317, 297, 416, 0, +3, 99, 103, 164, 304, 466, 187, 0, +3, 164, 160, 99, 187, 458, 304, 0, +3, 160, 164, 165, 458, 187, 117, 0, +3, 165, 161, 160, 117, 343, 458, 0, +3, 161, 165, 166, 343, 117, 438, 0, +3, 166, 162, 161, 438, 334, 343, 0, +3, 162, 166, 167, 334, 438, 459, 0, +3, 167, 163, 162, 459, 317, 334, 0, +3, 103, 107, 168, 466, 18, 353, 0, +3, 168, 164, 103, 353, 187, 466, 0, +3, 164, 168, 169, 187, 353, 123, 0, +3, 169, 165, 164, 123, 117, 187, 0, +3, 165, 169, 170, 117, 123, 168, 0, +3, 170, 166, 165, 168, 438, 117, 0, +3, 166, 170, 171, 438, 168, 426, 0, +3, 171, 167, 166, 426, 459, 438, 0, +3, 107, 111, 172, 18, 33, 390, 0, +3, 172, 168, 107, 390, 353, 18, 0, +3, 168, 172, 173, 353, 390, 290, 0, +3, 173, 169, 168, 290, 123, 353, 0, +3, 169, 173, 174, 123, 290, 522, 0, +3, 174, 170, 169, 522, 168, 123, 0, +3, 170, 174, 175, 168, 522, 87, 0, +3, 175, 171, 170, 87, 426, 168, 0, +3, 111, 115, 176, 33, 517, 260, 0, +3, 176, 172, 111, 260, 390, 33, 0, +3, 172, 176, 177, 390, 260, 497, 0, +3, 177, 173, 172, 497, 290, 390, 0, +3, 173, 177, 178, 290, 497, 126, 0, +3, 178, 174, 173, 126, 522, 290, 0, +3, 174, 178, 179, 522, 126, 501, 0, +3, 179, 175, 174, 501, 87, 522, 0, +3, 115, 119, 180, 517, 242, 130, 0, +3, 180, 176, 115, 130, 260, 517, 0, +3, 176, 180, 181, 260, 130, 34, 0, +3, 181, 177, 176, 34, 497, 260, 0, +3, 177, 181, 182, 497, 34, 46, 0, +3, 182, 178, 177, 46, 126, 497, 0, +3, 178, 182, 183, 126, 46, 105, 0, +3, 183, 179, 178, 105, 501, 126, 0, +3, 119, 123, 184, 242, 218, 310, 0, +3, 184, 180, 119, 310, 130, 242, 0, +3, 180, 184, 185, 130, 310, 528, 0, +3, 185, 181, 180, 528, 34, 130, 0, +3, 181, 185, 186, 34, 528, 145, 0, +3, 186, 182, 181, 145, 46, 34, 0, +3, 182, 186, 187, 46, 145, 356, 0, +3, 187, 183, 182, 356, 105, 46, 0, +3, 123, 127, 188, 218, 147, 156, 0, +3, 188, 184, 123, 156, 310, 218, 0, +3, 184, 188, 189, 310, 156, 402, 0, +3, 189, 185, 184, 402, 528, 310, 0, +3, 185, 189, 190, 528, 402, 146, 0, +3, 190, 186, 185, 146, 145, 528, 0, +3, 186, 190, 191, 145, 146, 17, 0, +3, 191, 187, 186, 17, 356, 145, 0, +3, 127, 131, 192, 147, 29, 184, 0, +3, 192, 188, 127, 184, 156, 147, 0, +3, 188, 192, 193, 156, 184, 63, 0, +3, 193, 189, 188, 63, 402, 156, 0, +3, 189, 193, 194, 402, 63, 354, 0, +3, 194, 190, 189, 354, 146, 402, 0, +3, 190, 194, 195, 146, 354, 335, 0, +3, 195, 191, 190, 335, 17, 146, 0, +3, 131, 135, 196, 29, 490, 210, 0, +3, 196, 192, 131, 210, 184, 29, 0, +3, 192, 196, 197, 184, 210, 129, 0, +3, 197, 193, 192, 129, 63, 184, 0, +3, 193, 197, 198, 63, 129, 461, 0, +3, 198, 194, 193, 461, 354, 63, 0, +3, 194, 198, 199, 354, 461, 475, 0, +3, 199, 195, 194, 475, 335, 354, 0, +3, 135, 139, 200, 490, 45, 370, 0, +3, 200, 196, 135, 370, 210, 490, 0, +3, 196, 200, 201, 210, 370, 143, 0, +3, 201, 197, 196, 143, 129, 210, 0, +3, 197, 201, 202, 129, 143, 195, 0, +3, 202, 198, 197, 195, 461, 129, 0, +3, 198, 202, 203, 461, 195, 444, 0, +3, 203, 199, 198, 444, 475, 461, 0, +3, 139, 143, 204, 45, 54, 403, 0, +3, 204, 200, 139, 403, 370, 45, 0, +3, 200, 204, 205, 370, 403, 315, 0, +3, 205, 201, 200, 315, 143, 370, 0, +3, 201, 205, 206, 143, 315, 7, 0, +3, 206, 202, 201, 7, 195, 143, 0, +3, 202, 206, 207, 195, 7, 101, 0, +3, 207, 203, 202, 101, 444, 195, 0, +3, 143, 83, 144, 54, 1, 276, 0, +3, 144, 204, 143, 276, 403, 54, 0, +3, 204, 144, 145, 403, 276, 520, 0, +3, 145, 205, 204, 520, 315, 403, 0, +3, 205, 145, 146, 315, 520, 395, 0, +3, 146, 206, 205, 395, 7, 315, 0, +3, 206, 146, 147, 7, 395, 246, 0, +3, 147, 207, 206, 246, 101, 7, 0, +3, 147, 151, 212, 246, 384, 486, 0, +3, 212, 208, 147, 486, 279, 246, 0, +3, 208, 212, 213, 279, 486, 231, 0, +3, 213, 209, 208, 231, 349, 279, 0, +3, 209, 213, 214, 349, 231, 0, 0, +3, 214, 210, 209, 0, 216, 349, 0, +3, 210, 214, 211, 216, 0, 393, 0, +3, 211, 211, 210, 393, 393, 216, 0, +3, 151, 155, 215, 384, 83, 215, 0, +3, 215, 212, 151, 215, 486, 384, 0, +3, 212, 215, 216, 486, 215, 327, 0, +3, 216, 213, 212, 327, 231, 486, 0, +3, 213, 216, 217, 231, 327, 512, 0, +3, 217, 214, 213, 512, 0, 231, 0, +3, 214, 217, 211, 0, 512, 393, 0, +3, 211, 211, 214, 393, 393, 0, 0, +3, 155, 159, 218, 83, 297, 149, 0, +3, 218, 215, 155, 149, 215, 83, 0, +3, 215, 218, 219, 215, 149, 91, 0, +3, 219, 216, 215, 91, 327, 215, 0, +3, 216, 219, 220, 327, 91, 177, 0, +3, 220, 217, 216, 177, 512, 327, 0, +3, 217, 220, 211, 512, 177, 393, 0, +3, 211, 211, 217, 393, 393, 512, 0, +3, 159, 163, 221, 297, 317, 504, 0, +3, 221, 218, 159, 504, 149, 297, 0, +3, 218, 221, 222, 149, 504, 285, 0, +3, 222, 219, 218, 285, 91, 149, 0, +3, 219, 222, 223, 91, 285, 254, 0, +3, 223, 220, 219, 254, 177, 91, 0, +3, 220, 223, 211, 177, 254, 393, 0, +3, 211, 211, 220, 393, 393, 177, 0, +3, 163, 167, 224, 317, 459, 125, 0, +3, 224, 221, 163, 125, 504, 317, 0, +3, 221, 224, 225, 504, 125, 162, 0, +3, 225, 222, 221, 162, 285, 504, 0, +3, 222, 225, 226, 285, 162, 278, 0, +3, 226, 223, 222, 278, 254, 285, 0, +3, 223, 226, 211, 254, 278, 393, 0, +3, 211, 211, 223, 393, 393, 254, 0, +3, 167, 171, 227, 459, 426, 439, 0, +3, 227, 224, 167, 439, 125, 459, 0, +3, 224, 227, 228, 125, 439, 60, 0, +3, 228, 225, 224, 60, 162, 125, 0, +3, 225, 228, 229, 162, 60, 446, 0, +3, 229, 226, 225, 446, 278, 162, 0, +3, 226, 229, 211, 278, 446, 393, 0, +3, 211, 211, 226, 393, 393, 278, 0, +3, 171, 175, 230, 426, 87, 482, 0, +3, 230, 227, 171, 482, 439, 426, 0, +3, 227, 230, 231, 439, 482, 92, 0, +3, 231, 228, 227, 92, 60, 439, 0, +3, 228, 231, 232, 60, 92, 110, 0, +3, 232, 229, 228, 110, 446, 60, 0, +3, 229, 232, 211, 446, 110, 393, 0, +3, 211, 211, 229, 393, 393, 446, 0, +3, 175, 179, 233, 87, 501, 261, 0, +3, 233, 230, 175, 261, 482, 87, 0, +3, 230, 233, 234, 482, 261, 329, 0, +3, 234, 231, 230, 329, 92, 482, 0, +3, 231, 234, 235, 92, 329, 192, 0, +3, 235, 232, 231, 192, 110, 92, 0, +3, 232, 235, 211, 110, 192, 393, 0, +3, 211, 211, 232, 393, 393, 110, 0, +3, 179, 183, 236, 501, 105, 219, 0, +3, 236, 233, 179, 219, 261, 501, 0, +3, 233, 236, 237, 261, 219, 491, 0, +3, 237, 234, 233, 491, 329, 261, 0, +3, 234, 237, 238, 329, 491, 267, 0, +3, 238, 235, 234, 267, 192, 329, 0, +3, 235, 238, 211, 192, 267, 393, 0, +3, 211, 211, 235, 393, 393, 192, 0, +3, 183, 187, 239, 105, 356, 472, 0, +3, 239, 236, 183, 472, 219, 105, 0, +3, 236, 239, 240, 219, 472, 48, 0, +3, 240, 237, 236, 48, 491, 219, 0, +3, 237, 240, 241, 491, 48, 247, 0, +3, 241, 238, 237, 247, 267, 491, 0, +3, 238, 241, 211, 267, 247, 393, 0, +3, 211, 211, 238, 393, 393, 267, 0, +3, 187, 191, 242, 356, 17, 411, 0, +3, 242, 239, 187, 411, 472, 356, 0, +3, 239, 242, 243, 472, 411, 364, 0, +3, 243, 240, 239, 364, 48, 472, 0, +3, 240, 243, 244, 48, 364, 441, 0, +3, 244, 241, 240, 441, 247, 48, 0, +3, 241, 244, 211, 247, 441, 393, 0, +3, 211, 211, 241, 393, 393, 247, 0, +3, 191, 195, 245, 17, 335, 239, 0, +3, 245, 242, 191, 239, 411, 17, 0, +3, 242, 245, 246, 411, 239, 13, 0, +3, 246, 243, 242, 13, 364, 411, 0, +3, 243, 246, 247, 364, 13, 509, 0, +3, 247, 244, 243, 509, 441, 364, 0, +3, 244, 247, 211, 441, 509, 393, 0, +3, 211, 211, 244, 393, 393, 441, 0, +3, 195, 199, 248, 335, 475, 144, 0, +3, 248, 245, 195, 144, 239, 335, 0, +3, 245, 248, 249, 239, 144, 179, 0, +3, 249, 246, 245, 179, 13, 239, 0, +3, 246, 249, 250, 13, 179, 298, 0, +3, 250, 247, 246, 298, 509, 13, 0, +3, 247, 250, 211, 509, 298, 393, 0, +3, 211, 211, 247, 393, 393, 509, 0, +3, 199, 203, 251, 475, 444, 462, 0, +3, 251, 248, 199, 462, 144, 475, 0, +3, 248, 251, 252, 144, 462, 76, 0, +3, 252, 249, 248, 76, 179, 144, 0, +3, 249, 252, 253, 179, 76, 464, 0, +3, 253, 250, 249, 464, 298, 179, 0, +3, 250, 253, 211, 298, 464, 393, 0, +3, 211, 211, 250, 393, 393, 298, 0, +3, 203, 207, 254, 444, 101, 500, 0, +3, 254, 251, 203, 500, 462, 444, 0, +3, 251, 254, 255, 462, 500, 113, 0, +3, 255, 252, 251, 113, 76, 462, 0, +3, 252, 255, 256, 76, 113, 128, 0, +3, 256, 253, 252, 128, 464, 76, 0, +3, 253, 256, 211, 464, 128, 393, 0, +3, 211, 211, 253, 393, 393, 464, 0, +3, 207, 147, 208, 101, 246, 279, 0, +3, 208, 254, 207, 279, 500, 101, 0, +3, 254, 208, 209, 500, 279, 349, 0, +3, 209, 255, 254, 349, 113, 500, 0, +3, 255, 209, 210, 113, 349, 216, 0, +3, 210, 256, 255, 216, 128, 113, 0, +3, 256, 210, 211, 128, 216, 393, 0, +3, 211, 211, 256, 393, 393, 128, 0, +3, 257, 262, 263, 425, 244, 58, 0, +3, 263, 258, 257, 58, 337, 425, 0, +3, 258, 263, 264, 337, 58, 214, 0, +3, 264, 259, 258, 214, 236, 337, 0, +3, 259, 264, 265, 236, 214, 266, 0, +3, 265, 260, 259, 266, 32, 236, 0, +3, 260, 265, 266, 32, 266, 331, 0, +3, 266, 261, 260, 331, 109, 32, 0, +3, 262, 267, 268, 244, 233, 369, 0, +3, 268, 263, 262, 369, 58, 244, 0, +3, 263, 268, 269, 58, 369, 71, 0, +3, 269, 264, 263, 71, 214, 58, 0, +3, 264, 269, 270, 214, 71, 392, 0, +3, 270, 265, 264, 392, 266, 214, 0, +3, 265, 270, 271, 266, 392, 312, 0, +3, 271, 266, 265, 312, 331, 266, 0, +3, 267, 272, 273, 233, 12, 434, 0, +3, 273, 268, 267, 434, 369, 233, 0, +3, 268, 273, 274, 369, 434, 188, 0, +3, 274, 269, 268, 188, 71, 369, 0, +3, 269, 274, 275, 71, 188, 201, 0, +3, 275, 270, 269, 201, 392, 71, 0, +3, 270, 275, 276, 392, 201, 238, 0, +3, 276, 271, 270, 238, 312, 392, 0, +3, 272, 277, 278, 12, 142, 114, 0, +3, 278, 273, 272, 114, 434, 12, 0, +3, 273, 278, 279, 434, 114, 173, 0, +3, 279, 274, 273, 173, 188, 434, 0, +3, 274, 279, 280, 188, 173, 14, 0, +3, 280, 275, 274, 14, 201, 188, 0, +3, 275, 280, 281, 201, 14, 15, 0, +3, 281, 276, 275, 15, 238, 201, 0, +3, 277, 282, 283, 142, 407, 288, 0, +3, 283, 278, 277, 288, 114, 142, 0, +3, 278, 283, 284, 114, 288, 400, 0, +3, 284, 279, 278, 400, 173, 114, 0, +3, 279, 284, 285, 173, 400, 457, 0, +3, 285, 280, 279, 457, 14, 173, 0, +3, 280, 285, 286, 14, 457, 332, 0, +3, 286, 281, 280, 332, 15, 14, 0, +3, 282, 287, 288, 407, 194, 42, 0, +3, 288, 283, 282, 42, 288, 407, 0, +3, 283, 288, 289, 288, 42, 380, 0, +3, 289, 284, 283, 380, 400, 288, 0, +3, 284, 289, 290, 400, 380, 383, 0, +3, 290, 285, 284, 383, 457, 400, 0, +3, 285, 290, 291, 457, 383, 197, 0, +3, 291, 286, 285, 197, 332, 457, 0, +3, 287, 292, 293, 194, 321, 152, 0, +3, 293, 288, 287, 152, 42, 194, 0, +3, 288, 293, 294, 42, 152, 397, 0, +3, 294, 289, 288, 397, 380, 42, 0, +3, 289, 294, 295, 380, 397, 342, 0, +3, 295, 290, 289, 342, 383, 380, 0, +3, 290, 295, 296, 383, 342, 225, 0, +3, 296, 291, 290, 225, 197, 383, 0, +3, 292, 257, 258, 321, 425, 337, 0, +3, 258, 293, 292, 337, 152, 321, 0, +3, 293, 258, 259, 152, 337, 236, 0, +3, 259, 294, 293, 236, 397, 152, 0, +3, 294, 259, 260, 397, 236, 32, 0, +3, 260, 295, 294, 32, 342, 397, 0, +3, 295, 260, 261, 342, 32, 109, 0, +3, 261, 296, 295, 109, 225, 342, 0, +3, 261, 266, 301, 109, 331, 175, 0, +3, 301, 297, 261, 175, 502, 109, 0, +3, 297, 301, 302, 502, 175, 265, 0, +3, 302, 298, 297, 265, 84, 502, 0, +3, 298, 302, 303, 84, 265, 186, 0, +3, 303, 299, 298, 186, 496, 84, 0, +3, 299, 303, 304, 496, 186, 470, 0, +3, 304, 300, 299, 470, 494, 496, 0, +3, 266, 271, 305, 331, 312, 170, 0, +3, 305, 301, 266, 170, 175, 331, 0, +3, 301, 305, 306, 175, 170, 97, 0, +3, 306, 302, 301, 97, 265, 175, 0, +3, 302, 306, 307, 265, 97, 205, 0, +3, 307, 303, 302, 205, 186, 265, 0, +3, 303, 307, 308, 186, 205, 449, 0, +3, 308, 304, 303, 449, 470, 186, 0, +3, 271, 276, 309, 312, 238, 379, 0, +3, 309, 305, 271, 379, 170, 312, 0, +3, 305, 309, 310, 170, 379, 300, 0, +3, 310, 306, 305, 300, 97, 170, 0, +3, 306, 310, 311, 97, 300, 118, 0, +3, 311, 307, 306, 118, 205, 97, 0, +3, 307, 311, 312, 205, 118, 237, 0, +3, 312, 308, 307, 237, 449, 205, 0, +3, 276, 281, 313, 238, 15, 199, 0, +3, 313, 309, 276, 199, 379, 238, 0, +3, 309, 313, 314, 379, 199, 94, 0, +3, 314, 310, 309, 94, 300, 379, 0, +3, 310, 314, 315, 300, 94, 421, 0, +3, 315, 311, 310, 421, 118, 300, 0, +3, 311, 315, 316, 118, 421, 31, 0, +3, 316, 312, 311, 31, 237, 118, 0, +3, 281, 286, 317, 15, 332, 367, 0, +3, 317, 313, 281, 367, 199, 15, 0, +3, 313, 317, 318, 199, 367, 529, 0, +3, 318, 314, 313, 529, 94, 199, 0, +3, 314, 318, 319, 94, 529, 185, 0, +3, 319, 315, 314, 185, 421, 94, 0, +3, 315, 319, 320, 421, 185, 89, 0, +3, 320, 316, 315, 89, 31, 421, 0, +3, 286, 291, 321, 332, 197, 172, 0, +3, 321, 317, 286, 172, 367, 332, 0, +3, 317, 321, 322, 367, 172, 209, 0, +3, 322, 318, 317, 209, 529, 367, 0, +3, 318, 322, 323, 529, 209, 429, 0, +3, 323, 319, 318, 429, 185, 529, 0, +3, 319, 323, 324, 185, 429, 112, 0, +3, 324, 320, 319, 112, 89, 185, 0, +3, 291, 296, 325, 197, 225, 451, 0, +3, 325, 321, 291, 451, 172, 197, 0, +3, 321, 325, 326, 172, 451, 66, 0, +3, 326, 322, 321, 66, 209, 172, 0, +3, 322, 326, 327, 209, 66, 176, 0, +3, 327, 323, 322, 176, 429, 209, 0, +3, 323, 327, 328, 429, 176, 155, 0, +3, 328, 324, 323, 155, 112, 429, 0, +3, 296, 261, 297, 225, 109, 502, 0, +3, 297, 325, 296, 502, 451, 225, 0, +3, 325, 297, 298, 451, 502, 84, 0, +3, 298, 326, 325, 84, 66, 451, 0, +3, 326, 298, 299, 66, 84, 496, 0, +3, 299, 327, 326, 496, 176, 66, 0, +3, 327, 299, 300, 176, 496, 494, 0, +3, 300, 328, 327, 494, 155, 176, 0, +3, 329, 334, 335, 3, 355, 122, 0, +3, 335, 330, 329, 122, 518, 3, 0, +3, 330, 335, 336, 518, 122, 111, 0, +3, 336, 331, 330, 111, 213, 518, 0, +3, 331, 336, 337, 213, 111, 473, 0, +3, 337, 332, 331, 473, 468, 213, 0, +3, 332, 337, 338, 468, 473, 521, 0, +3, 338, 333, 332, 521, 346, 468, 0, +3, 334, 339, 340, 355, 61, 414, 0, +3, 340, 335, 334, 414, 122, 355, 0, +3, 335, 340, 341, 122, 414, 413, 0, +3, 341, 336, 335, 413, 111, 122, 0, +3, 336, 341, 342, 111, 413, 204, 0, +3, 342, 337, 336, 204, 473, 111, 0, +3, 337, 342, 343, 473, 204, 217, 0, +3, 343, 338, 337, 217, 521, 473, 0, +3, 339, 344, 345, 61, 55, 100, 0, +3, 345, 340, 339, 100, 414, 61, 0, +3, 340, 345, 346, 414, 100, 399, 0, +3, 346, 341, 340, 399, 413, 414, 0, +3, 341, 346, 347, 413, 399, 326, 0, +3, 347, 342, 341, 326, 204, 413, 0, +3, 342, 347, 348, 204, 326, 221, 0, +3, 348, 343, 342, 221, 217, 204, 0, +3, 344, 349, 350, 55, 508, 477, 0, +3, 350, 345, 344, 477, 100, 55, 0, +3, 345, 350, 351, 100, 477, 292, 0, +3, 351, 346, 345, 292, 399, 100, 0, +3, 346, 351, 352, 399, 292, 73, 0, +3, 352, 347, 346, 73, 326, 399, 0, +3, 347, 352, 353, 326, 73, 362, 0, +3, 353, 348, 347, 362, 221, 326, 0, +3, 349, 354, 355, 508, 365, 262, 0, +3, 355, 350, 349, 262, 477, 508, 0, +3, 350, 355, 356, 477, 262, 93, 0, +3, 356, 351, 350, 93, 292, 477, 0, +3, 351, 356, 357, 292, 93, 318, 0, +3, 357, 352, 351, 318, 73, 292, 0, +3, 352, 357, 358, 73, 318, 163, 0, +3, 358, 353, 352, 163, 362, 73, 0, +3, 354, 359, 360, 365, 140, 340, 0, +3, 360, 355, 354, 340, 262, 365, 0, +3, 355, 360, 361, 262, 340, 505, 0, +3, 361, 356, 355, 505, 93, 262, 0, +3, 356, 361, 362, 93, 505, 499, 0, +3, 362, 357, 356, 499, 318, 93, 0, +3, 357, 362, 363, 318, 499, 159, 0, +3, 363, 358, 357, 159, 163, 318, 0, +3, 359, 364, 365, 140, 510, 68, 0, +3, 365, 360, 359, 68, 340, 140, 0, +3, 360, 365, 366, 340, 68, 167, 0, +3, 366, 361, 360, 167, 505, 340, 0, +3, 361, 366, 367, 505, 167, 245, 0, +3, 367, 362, 361, 245, 499, 505, 0, +3, 362, 367, 368, 499, 245, 437, 0, +3, 368, 363, 362, 437, 159, 499, 0, +3, 364, 329, 330, 510, 3, 518, 0, +3, 330, 365, 364, 518, 68, 510, 0, +3, 365, 330, 331, 68, 518, 213, 0, +3, 331, 366, 365, 213, 167, 68, 0, +3, 366, 331, 332, 167, 213, 468, 0, +3, 332, 367, 366, 468, 245, 167, 0, +3, 367, 332, 333, 245, 468, 346, 0, +3, 333, 368, 367, 346, 437, 245, 0, +3, 333, 338, 373, 346, 521, 79, 0, +3, 373, 369, 333, 79, 286, 346, 0, +3, 369, 373, 374, 286, 79, 77, 0, +3, 374, 370, 369, 77, 22, 286, 0, +3, 370, 374, 375, 22, 77, 523, 0, +3, 375, 371, 370, 523, 330, 22, 0, +3, 371, 375, 376, 330, 523, 259, 0, +3, 376, 372, 371, 259, 338, 330, 0, +3, 338, 343, 377, 521, 217, 207, 0, +3, 377, 373, 338, 207, 79, 521, 0, +3, 373, 377, 378, 79, 207, 471, 0, +3, 378, 374, 373, 471, 77, 79, 0, +3, 374, 378, 379, 77, 471, 198, 0, +3, 379, 375, 374, 198, 523, 77, 0, +3, 375, 379, 380, 523, 198, 366, 0, +3, 380, 376, 375, 366, 259, 523, 0, +3, 343, 348, 381, 217, 221, 516, 0, +3, 381, 377, 343, 516, 207, 217, 0, +3, 377, 381, 382, 207, 516, 250, 0, +3, 382, 378, 377, 250, 471, 207, 0, +3, 378, 382, 383, 471, 250, 240, 0, +3, 383, 379, 378, 240, 198, 471, 0, +3, 379, 383, 384, 198, 240, 381, 0, +3, 384, 380, 379, 381, 366, 198, 0, +3, 348, 353, 385, 221, 362, 230, 0, +3, 385, 381, 348, 230, 516, 221, 0, +3, 381, 385, 386, 516, 230, 303, 0, +3, 386, 382, 381, 303, 250, 516, 0, +3, 382, 386, 387, 250, 303, 10, 0, +3, 387, 383, 382, 10, 240, 250, 0, +3, 383, 387, 388, 240, 10, 283, 0, +3, 388, 384, 383, 283, 381, 240, 0, +3, 353, 358, 389, 362, 163, 282, 0, +3, 389, 385, 353, 282, 230, 362, 0, +3, 385, 389, 390, 230, 282, 35, 0, +3, 390, 386, 385, 35, 303, 230, 0, +3, 386, 390, 391, 303, 35, 243, 0, +3, 391, 387, 386, 243, 10, 303, 0, +3, 387, 391, 392, 10, 243, 368, 0, +3, 392, 388, 387, 368, 283, 10, 0, +3, 358, 363, 393, 163, 159, 296, 0, +3, 393, 389, 358, 296, 282, 163, 0, +3, 389, 393, 394, 282, 296, 160, 0, +3, 394, 390, 389, 160, 35, 282, 0, +3, 390, 394, 395, 35, 160, 323, 0, +3, 395, 391, 390, 323, 243, 35, 0, +3, 391, 395, 396, 243, 323, 280, 0, +3, 396, 392, 391, 280, 368, 243, 0, +3, 363, 368, 397, 159, 437, 275, 0, +3, 397, 393, 363, 275, 296, 159, 0, +3, 393, 397, 398, 296, 275, 133, 0, +3, 398, 394, 393, 133, 160, 296, 0, +3, 394, 398, 399, 160, 133, 344, 0, +3, 399, 395, 394, 344, 323, 160, 0, +3, 395, 399, 400, 323, 344, 108, 0, +3, 400, 396, 395, 108, 280, 323, 0, +3, 368, 333, 369, 437, 346, 286, 0, +3, 369, 397, 368, 286, 275, 437, 0, +3, 397, 369, 370, 275, 286, 22, 0, +3, 370, 398, 397, 22, 133, 275, 0, +3, 398, 370, 371, 133, 22, 330, 0, +3, 371, 399, 398, 330, 344, 133, 0, +3, 399, 371, 372, 344, 330, 338, 0, +3, 372, 400, 399, 338, 108, 344, 0, +3, 401, 401, 406, 235, 235, 189, 0, +3, 406, 402, 401, 189, 40, 235, 0, +3, 402, 406, 407, 40, 189, 306, 0, +3, 407, 403, 402, 306, 119, 40, 0, +3, 403, 407, 408, 119, 306, 202, 0, +3, 408, 404, 403, 202, 443, 119, 0, +3, 404, 408, 409, 443, 202, 241, 0, +3, 409, 405, 404, 241, 75, 443, 0, +3, 401, 401, 410, 235, 235, 263, 0, +3, 410, 406, 401, 263, 189, 235, 0, +3, 406, 410, 411, 189, 263, 196, 0, +3, 411, 407, 406, 196, 306, 189, 0, +3, 407, 411, 412, 306, 196, 281, 0, +3, 412, 408, 407, 281, 202, 306, 0, +3, 408, 412, 413, 202, 281, 121, 0, +3, 413, 409, 408, 121, 241, 202, 0, +3, 401, 401, 414, 235, 235, 479, 0, +3, 414, 410, 401, 479, 263, 235, 0, +3, 410, 414, 415, 263, 479, 36, 0, +3, 415, 411, 410, 36, 196, 263, 0, +3, 411, 415, 416, 196, 36, 436, 0, +3, 416, 412, 411, 436, 281, 196, 0, +3, 412, 416, 417, 281, 436, 351, 0, +3, 417, 413, 412, 351, 121, 281, 0, +3, 401, 401, 418, 235, 235, 90, 0, +3, 418, 414, 401, 90, 479, 235, 0, +3, 414, 418, 419, 479, 90, 361, 0, +3, 419, 415, 414, 361, 36, 479, 0, +3, 415, 419, 420, 36, 361, 376, 0, +3, 420, 416, 415, 376, 436, 36, 0, +3, 416, 420, 421, 436, 376, 412, 0, +3, 421, 417, 416, 412, 351, 436, 0, +3, 401, 401, 422, 235, 235, 52, 0, +3, 422, 418, 401, 52, 90, 235, 0, +3, 418, 422, 423, 90, 52, 21, 0, +3, 423, 419, 418, 21, 361, 90, 0, +3, 419, 423, 424, 361, 21, 158, 0, +3, 424, 420, 419, 158, 376, 361, 0, +3, 420, 424, 425, 376, 158, 39, 0, +3, 425, 421, 420, 39, 412, 376, 0, +3, 401, 401, 426, 235, 235, 424, 0, +3, 426, 422, 401, 424, 52, 235, 0, +3, 422, 426, 427, 52, 424, 373, 0, +3, 427, 423, 422, 373, 21, 52, 0, +3, 423, 427, 428, 21, 373, 375, 0, +3, 428, 424, 423, 375, 158, 21, 0, +3, 424, 428, 429, 158, 375, 249, 0, +3, 429, 425, 424, 249, 39, 158, 0, +3, 401, 401, 430, 235, 235, 432, 0, +3, 430, 426, 401, 432, 424, 235, 0, +3, 426, 430, 431, 424, 432, 229, 0, +3, 431, 427, 426, 229, 373, 424, 0, +3, 427, 431, 432, 373, 229, 65, 0, +3, 432, 428, 427, 65, 375, 373, 0, +3, 428, 432, 433, 375, 65, 506, 0, +3, 433, 429, 428, 506, 249, 375, 0, +3, 401, 401, 434, 235, 235, 302, 0, +3, 434, 430, 401, 302, 432, 235, 0, +3, 430, 434, 435, 432, 302, 96, 0, +3, 435, 431, 430, 96, 229, 432, 0, +3, 431, 435, 436, 229, 96, 169, 0, +3, 436, 432, 431, 169, 65, 229, 0, +3, 432, 436, 437, 65, 169, 59, 0, +3, 437, 433, 432, 59, 506, 65, 0, +3, 401, 401, 438, 235, 235, 452, 0, +3, 438, 434, 401, 452, 302, 235, 0, +3, 434, 438, 439, 302, 452, 30, 0, +3, 439, 435, 434, 30, 96, 302, 0, +3, 435, 439, 440, 96, 30, 460, 0, +3, 440, 436, 435, 460, 169, 96, 0, +3, 436, 440, 441, 169, 460, 498, 0, +3, 441, 437, 436, 498, 59, 169, 0, +3, 401, 401, 442, 235, 235, 525, 0, +3, 442, 438, 401, 525, 452, 235, 0, +3, 438, 442, 443, 452, 525, 456, 0, +3, 443, 439, 438, 456, 30, 452, 0, +3, 439, 443, 444, 30, 456, 9, 0, +3, 444, 440, 439, 9, 460, 30, 0, +3, 440, 444, 445, 460, 9, 388, 0, +3, 445, 441, 440, 388, 498, 460, 0, +3, 401, 401, 446, 235, 235, 212, 0, +3, 446, 442, 401, 212, 525, 235, 0, +3, 442, 446, 447, 525, 212, 299, 0, +3, 447, 443, 442, 299, 456, 525, 0, +3, 443, 447, 448, 456, 299, 166, 0, +3, 448, 444, 443, 166, 9, 456, 0, +3, 444, 448, 449, 9, 166, 72, 0, +3, 449, 445, 444, 72, 388, 9, 0, +3, 401, 401, 450, 235, 235, 107, 0, +3, 450, 446, 401, 107, 212, 235, 0, +3, 446, 450, 451, 212, 107, 82, 0, +3, 451, 447, 446, 82, 299, 212, 0, +3, 447, 451, 452, 299, 82, 391, 0, +3, 452, 448, 447, 391, 166, 299, 0, +3, 448, 452, 453, 166, 391, 139, 0, +3, 453, 449, 448, 139, 72, 166, 0, +3, 401, 401, 454, 235, 235, 70, 0, +3, 454, 450, 401, 70, 107, 235, 0, +3, 450, 454, 455, 107, 70, 51, 0, +3, 455, 451, 450, 51, 82, 107, 0, +3, 451, 455, 456, 82, 51, 178, 0, +3, 456, 452, 451, 178, 391, 82, 0, +3, 452, 456, 457, 391, 178, 57, 0, +3, 457, 453, 452, 57, 139, 391, 0, +3, 401, 401, 458, 235, 235, 442, 0, +3, 458, 454, 401, 442, 70, 235, 0, +3, 454, 458, 459, 70, 442, 387, 0, +3, 459, 455, 454, 387, 51, 70, 0, +3, 455, 459, 460, 51, 387, 389, 0, +3, 460, 456, 455, 389, 178, 51, 0, +3, 456, 460, 461, 178, 389, 264, 0, +3, 461, 457, 456, 264, 57, 178, 0, +3, 401, 401, 462, 235, 235, 450, 0, +3, 462, 458, 401, 450, 442, 235, 0, +3, 458, 462, 463, 442, 450, 253, 0, +3, 463, 459, 458, 253, 387, 442, 0, +3, 459, 463, 464, 387, 253, 86, 0, +3, 464, 460, 459, 86, 389, 387, 0, +3, 460, 464, 465, 389, 86, 526, 0, +3, 465, 461, 460, 526, 264, 389, 0, +3, 401, 401, 402, 235, 235, 40, 0, +3, 402, 462, 401, 40, 450, 235, 0, +3, 462, 402, 403, 450, 40, 119, 0, +3, 403, 463, 462, 119, 253, 450, 0, +3, 463, 403, 404, 253, 119, 443, 0, +3, 404, 464, 463, 443, 86, 253, 0, +3, 464, 404, 405, 86, 443, 75, 0, +3, 405, 465, 464, 75, 526, 86, 0, +3, 405, 409, 470, 75, 241, 519, 0, +3, 470, 466, 405, 519, 226, 75, 0, +3, 466, 470, 471, 226, 519, 406, 0, +3, 471, 467, 466, 406, 98, 226, 0, +3, 467, 471, 472, 98, 406, 232, 0, +3, 472, 468, 467, 232, 43, 98, 0, +3, 468, 472, 473, 43, 232, 345, 0, +3, 473, 469, 468, 345, 372, 43, 0, +3, 409, 413, 474, 241, 121, 227, 0, +3, 474, 470, 409, 227, 519, 241, 0, +3, 470, 474, 475, 519, 227, 469, 0, +3, 475, 471, 470, 469, 406, 519, 0, +3, 471, 475, 476, 406, 469, 258, 0, +3, 476, 472, 471, 258, 232, 406, 0, +3, 472, 476, 477, 232, 258, 271, 0, +3, 477, 473, 472, 271, 345, 232, 0, +3, 413, 417, 478, 121, 351, 157, 0, +3, 478, 474, 413, 157, 227, 121, 0, +3, 474, 478, 479, 227, 157, 80, 0, +3, 479, 475, 474, 80, 469, 227, 0, +3, 475, 479, 480, 469, 80, 489, 0, +3, 480, 476, 475, 489, 258, 469, 0, +3, 476, 480, 481, 258, 489, 277, 0, +3, 481, 477, 476, 277, 271, 258, 0, +3, 417, 421, 482, 351, 412, 153, 0, +3, 482, 478, 417, 153, 157, 351, 0, +3, 478, 482, 483, 157, 153, 324, 0, +3, 483, 479, 478, 324, 80, 157, 0, +3, 479, 483, 484, 80, 324, 339, 0, +3, 484, 480, 479, 339, 489, 80, 0, +3, 480, 484, 485, 489, 339, 88, 0, +3, 485, 481, 480, 88, 277, 489, 0, +3, 421, 425, 486, 412, 39, 6, 0, +3, 486, 482, 421, 6, 153, 412, 0, +3, 482, 486, 487, 153, 6, 8, 0, +3, 487, 483, 482, 8, 324, 153, 0, +3, 483, 487, 488, 324, 8, 16, 0, +3, 488, 484, 483, 16, 339, 324, 0, +3, 484, 488, 489, 339, 16, 289, 0, +3, 489, 485, 484, 289, 88, 339, 0, +3, 425, 429, 490, 39, 249, 99, 0, +3, 490, 486, 425, 99, 6, 39, 0, +3, 486, 490, 491, 6, 99, 200, 0, +3, 491, 487, 486, 200, 8, 6, 0, +3, 487, 491, 492, 8, 200, 150, 0, +3, 492, 488, 487, 150, 16, 8, 0, +3, 488, 492, 493, 16, 150, 493, 0, +3, 493, 489, 488, 493, 289, 16, 0, +3, 429, 433, 494, 249, 506, 291, 0, +3, 494, 490, 429, 291, 99, 249, 0, +3, 490, 494, 495, 99, 291, 64, 0, +3, 495, 491, 490, 64, 200, 99, 0, +3, 491, 495, 496, 200, 64, 19, 0, +3, 496, 492, 491, 19, 150, 200, 0, +3, 492, 496, 497, 150, 19, 433, 0, +3, 497, 493, 492, 433, 493, 150, 0, +3, 433, 437, 498, 506, 59, 203, 0, +3, 498, 494, 433, 203, 291, 506, 0, +3, 494, 498, 499, 291, 203, 374, 0, +3, 499, 495, 494, 374, 64, 291, 0, +3, 495, 499, 500, 64, 374, 307, 0, +3, 500, 496, 495, 307, 19, 64, 0, +3, 496, 500, 501, 19, 307, 358, 0, +3, 501, 497, 496, 358, 433, 19, 0, +3, 437, 441, 502, 59, 498, 256, 0, +3, 502, 498, 437, 256, 203, 59, 0, +3, 498, 502, 503, 203, 256, 132, 0, +3, 503, 499, 498, 132, 374, 203, 0, +3, 499, 503, 504, 374, 132, 492, 0, +3, 504, 500, 499, 492, 307, 374, 0, +3, 500, 504, 505, 307, 492, 67, 0, +3, 505, 501, 500, 67, 358, 307, 0, +3, 441, 445, 506, 498, 388, 487, 0, +3, 506, 502, 441, 487, 256, 498, 0, +3, 502, 506, 507, 256, 487, 206, 0, +3, 507, 503, 502, 206, 132, 256, 0, +3, 503, 507, 508, 132, 206, 515, 0, +3, 508, 504, 503, 515, 492, 132, 0, +3, 504, 508, 509, 492, 515, 527, 0, +3, 509, 505, 504, 527, 67, 492, 0, +3, 445, 449, 510, 388, 72, 423, 0, +3, 510, 506, 445, 423, 487, 388, 0, +3, 506, 510, 511, 487, 423, 352, 0, +3, 511, 507, 506, 352, 206, 487, 0, +3, 507, 511, 512, 206, 352, 224, 0, +3, 512, 508, 507, 224, 515, 206, 0, +3, 508, 512, 513, 515, 224, 2, 0, +3, 513, 509, 508, 2, 527, 515, 0, +3, 449, 453, 514, 72, 139, 418, 0, +3, 514, 510, 449, 418, 423, 72, 0, +3, 510, 514, 515, 423, 418, 341, 0, +3, 515, 511, 510, 341, 352, 423, 0, +3, 511, 515, 516, 352, 341, 359, 0, +3, 516, 512, 511, 359, 224, 352, 0, +3, 512, 516, 517, 224, 359, 360, 0, +3, 517, 513, 512, 360, 2, 224, 0, +3, 453, 457, 518, 139, 57, 24, 0, +3, 518, 514, 453, 24, 418, 139, 0, +3, 514, 518, 519, 418, 24, 25, 0, +3, 519, 515, 514, 25, 341, 418, 0, +3, 515, 519, 520, 341, 25, 41, 0, +3, 520, 516, 515, 41, 359, 341, 0, +3, 516, 520, 521, 359, 41, 314, 0, +3, 521, 517, 516, 314, 360, 359, 0, +3, 457, 461, 522, 57, 264, 120, 0, +3, 522, 518, 457, 120, 24, 57, 0, +3, 518, 522, 523, 24, 120, 223, 0, +3, 523, 519, 518, 223, 25, 24, 0, +3, 519, 523, 524, 25, 223, 171, 0, +3, 524, 520, 519, 171, 41, 25, 0, +3, 520, 524, 525, 41, 171, 514, 0, +3, 525, 521, 520, 514, 314, 41, 0, +3, 461, 465, 526, 264, 526, 316, 0, +3, 526, 522, 461, 316, 120, 264, 0, +3, 522, 526, 527, 120, 316, 85, 0, +3, 527, 523, 522, 85, 223, 120, 0, +3, 523, 527, 528, 223, 85, 50, 0, +3, 528, 524, 523, 50, 171, 223, 0, +3, 524, 528, 529, 171, 50, 454, 0, +3, 529, 525, 524, 454, 514, 171, 0, +3, 465, 405, 466, 526, 75, 226, 0, +3, 466, 526, 465, 226, 316, 526, 0, +3, 526, 466, 467, 316, 226, 98, 0, +3, 467, 527, 526, 98, 85, 316, 0, +3, 527, 467, 468, 85, 98, 43, 0, +3, 468, 528, 527, 43, 50, 85, 0, +3, 528, 468, 469, 50, 43, 372, 0, +3, 469, 529, 528, 372, 454, 50, 0 +}; + + +const int strip_vertices[] = { +508, 508, 504, 509, 504, 505, 500, 501, 496, 497, 492, 493, 488, 489, 484, 485, 480, 481, 476, 477, 472, 473, -1, +476, 475, 480, 479, 484, 483, 488, 487, 492, 491, 496, 495, 500, 499, 504, 499, 503, 498, 502, 437, 441, -1, +527, 526, 467, 466, 471, 470, 475, 474, 479, 478, 483, 482, 487, 486, 491, 490, 495, 494, 499, 494, 498, -1, +490, 490, 425, 486, 421, 482, 417, 478, 413, 474, 409, 470, 405, 466, 465, 526, 465, 461, 460, 456, 455, 451, -1, +405, 465, 464, 460, 459, 455, 454, 450, -1, +455, 451, 450, 446, 450, 401, 454, 458, 459, 463, 464, 404, 405, 404, 409, 408, 413, 412, 417, 416, 421, 420, -1, +421, 420, 425, 420, 424, 419, 423, 418, 422, 418, 401, 414, 410, 415, 411, 416, 411, 412, 407, 408, 403, 404, 403, 463, -1, +418, 418, 414, 419, 415, 420, 416, -1, +407, 403, 402, 462, -1, +403, 463, 462, 458, 462, 401, 402, 406, 407, 406, 411, 406, 410, 401, -1, +494, 494, 498, 433, 437, 432, 436, 431, 435, 430, 434, 430, 401, 426, 422, 427, 423, 428, 424, 429, 425, 490, -1, +430, 430, 426, 431, 427, 432, 428, 433, 429, 494, 490, -1, +437, 437, 441, 436, 440, 435, 439, 434, 438, 401, 442, 446, 447, 451, 452, 456, 457, 461, 522, 526, 527, -1, +452, 448, 447, -1, +510, 445, 449, 444, 448, 443, 447, 443, 442, 443, 438, 443, 439, 444, 440, 445, 441, 506, 502, 507, 503, -1, +510, 506, 445, -1, +507, 506, 511, 510, 515, 510, 514, 449, 453, 448, 453, 452, 457, -1, +527, 523, 522, 518, 457, 518, 453, 518, 514, 519, 515, -1, +523, 519, 518, -1, +504, 503, 508, 507, 512, 511, 516, 515, 520, 519, 524, 523, 528, 527, 468, 467, 472, 471, 476, 475, -1, +472, 473, 468, 469, 528, 529, 524, 525, 520, 521, 516, 517, 512, 513, 508, 509, -1, +211, 211, 214, 210, 209, -1, +212, 215, 216, 219, 220, 223, 220, 211, 217, 214, 213, 209, 213, 208, 212, 147, -1, +220, 217, 216, 213, 212, -1, +251, 251, 248, 252, 249, 253, 250, 253, 211, 256, 210, 255, 209, 254, 208, 207, 147, 206, 147, 146, 147, 151, 212, 215, -1, +206, 206, 202, 207, 203, 254, 251, 255, 252, 256, 253, -1, +223, 223, 222, 219, 218, 215, 155, 151, 150, 146, 145, 146, 205, 206, 201, 202, 197, 202, 198, 203, 199, 251, 248, -1, +145, 149, 150, 154, 155, 159, 218, 221, 222, 225, 226, 229, -1, +204, 204, 145, 144, 149, 148, 149, 153, 154, 158, 159, 163, 221, 224, 225, 228, 229, 232, 229, 211, 226, 223, 222, -1, +224, 224, 167, 163, 162, 158, 157, 153, 152, 148, 87, 148, 83, 144, 143, 204, 139, 200, 135, 196, 131, 192, -1, +82, 83, 142, 143, 138, 139, 134, 135, 130, 131, 126, 127, 122, 123, 118, 123, 119, 184, 180, 185, 181, -1, +81, 82, 141, 142, 137, 138, 133, 134, 129, 130, 125, 126, 121, 122, 117, 118, 113, 114, 109, 110, -1, +80, 81, 140, 141, 136, 137, 132, 133, 128, 129, 124, 125, 120, 121, 116, 117, 112, 113, 108, 109, -1, +4, 80, 79, 140, 74, 136, 69, 132, 64, 128, 59, 124, 54, 120, 49, 116, 44, 112, 39, 108, -1, +79, 79, 73, 74, 68, 69, 63, 64, 58, 59, 53, 54, 48, 49, 48, 43, 42, 37, 36, 31, 30, 31, 25, -1, +42, 42, 48, 47, 53, 52, 58, 57, 63, 62, 68, 67, 73, 72, 78, 77, 3, 2, 8, 7, 13, -1, +36, 36, 42, 41, 47, 46, 52, 51, 57, 56, 62, 61, 67, 66, 72, 71, 77, 76, 2, 1, 7, -1, +66, 66, 60, 61, 55, 56, 50, 51, 45, 46, 40, 41, 35, 36, 30, -1, +31, 31, 25, 26, 20, 21, 15, 16, 10, 11, 5, 6, 0, 1, 75, 76, 70, 71, 65, 66, 60, -1, +1, 1, 7, 6, 12, 11, 17, 16, 22, 21, 27, 26, 32, 31, 32, 37, 38, 43, 44, 49, -1, +7, 7, 13, 12, 18, 17, 23, 22, 28, 27, 33, 32, 33, 38, -1, +44, 44, 38, 39, 33, 34, 28, 29, 23, 24, 18, 19, 13, 14, 8, 9, 3, 4, 78, 79, 73, -1, +39, 108, 34, 104, 29, 100, 24, 96, 19, 92, 14, 88, 9, 84, 4, 84, 80, 85, 81, 86, 81, 82, -1, +108, 109, 104, 105, 100, 101, 96, 97, 92, 93, 88, 89, 84, 85, -1, +109, 110, 105, 106, 101, 102, 97, 98, 93, 94, 89, 90, 85, 86, -1, +118, 119, 114, 115, 110, 111, 106, 107, 102, 103, 98, 99, 94, 95, 90, 91, 86, 87, 82, 83, -1, +111, 115, 176, -1, +107, 111, 172, 176, 177, -1, +103, 107, 168, 172, 173, 177, 178, -1, +99, 103, 164, 168, 169, 173, 174, 178, 179, -1, +95, 99, 160, 164, 165, 169, 170, 174, 175, 179, 233, -1, +91, 95, 156, 160, 161, 165, 166, 170, 171, 175, 230, 233, 234, -1, +87, 91, 152, 156, 157, 161, 162, 166, 167, 171, 227, 230, 231, 234, 235, 234, 238, 234, 237, 233, 236, 179, -1, +185, 185, 181, 186, 182, 187, 183, 239, 236, 240, 237, 241, 238, 211, 235, 232, 231, 228, 227, 224, 167, -1, +236, 179, 183, 178, 182, 177, 181, 176, 180, 115, 119, -1, +131, 192, 127, 188, 123, 188, 184, 189, 185, 190, 186, 191, 187, 242, 239, 243, 240, 244, 241, 244, 211, 247, -1, +192, 192, 188, 193, 189, 194, 190, 195, 191, 245, 242, 246, 243, 247, 244, -1, +211, 247, 250, 246, 249, 245, 248, 195, 199, 194, 198, 193, 197, 192, 197, 196, 201, 200, 205, 204, 145, -1, +393, 393, 394, 398, 399, 371, -1, +399, 395, 394, -1, +363, 363, 393, 397, 398, 370, 371, 375, -1, +379, 375, 374, 370, 369, 397, 368, 363, 362, -1, +396, 395, 400, 399, 372, 371, 376, 375, 380, 379, 384, 383, 388, 387, 392, 391, 396, 391, 395, 390, 394, -1, +374, 378, 379, 378, 383, 382, 387, 386, 391, 386, 390, 385, 389, 353, 358, 352, 357, 351, 356, 350, 355, -1, +341, 341, 347, 346, 352, 346, 351, 345, 350, -1, +335, 334, 340, 339, 345, 344, 350, 349, 355, 354, -1, +390, 390, 394, 389, 393, 358, 363, 357, 362, 356, 361, 355, 360, 354, 360, 359, 365, 364, 330, 329, 335, 334, -1, +345, 346, 340, 341, 335, 336, 330, 331, 365, 366, 360, 366, 361, 367, 362, 367, 368, 333, 369, 373, 374, 378, -1, +353, 353, 348, 385, 381, 386, 381, 382, 377, 378, 377, 373, 338, 333, 332, 367, 332, 366, 332, 331, 337, 336, 342, 341, 347, -1, +332, 337, 338, 343, 377, 343, 381, 343, 348, 342, 348, 347, 353, 352, -1, +337, 342, 343, -1, +314, 314, 319, 318, 323, 322, 323, 327, -1, +309, 309, 314, 313, 318, 317, 322, 321, 322, 326, 327, 299, -1, +271, 271, 309, 276, 313, 281, 317, 286, 321, 291, 321, 325, 326, 298, 299, 303, -1, +265, 265, 271, 270, 276, 275, 281, 280, 286, 285, 291, 290, 291, 296, 325, 297, 298, 302, 303, 307, -1, +259, 259, 265, 264, 270, 269, 275, 274, 280, 279, 285, 284, 290, 289, 290, 295, 296, 261, 297, 301, 302, 306, 307, 311, -1, +293, 293, 259, 258, 264, 263, 269, 268, 274, 273, 279, 278, 284, 283, 289, 288, 289, 294, 295, 260, 261, 266, -1, +309, 305, 271, 266, 265, 260, 259, 294, 293, 288, 287, 288, 282, 283, 277, 278, 272, 273, 267, 268, 262, -1, +268, 268, 262, 263, 257, 258, 292, 293, 287, -1, +261, 266, 301, 305, 306, 310, 311, 315, 316, 320, -1, +316, 316, 311, 312, 307, 308, 303, 304, 299, 300, 327, 328, 323, 324, 319, 320, 319, 315, 314, 310, 309, 305, -1 +}; + + +const int strip_normals[] = { +515, 515, 492, 527, 492, 67, 307, 358, 19, 433, 150, 493, 16, 289, 339, 88, 489, 277, 258, 271, 232, 345, -1, +258, 469, 489, 80, 339, 324, 16, 8, 150, 200, 19, 64, 307, 374, 492, 374, 132, 203, 256, 59, 498, -1, +85, 316, 98, 226, 406, 519, 469, 227, 80, 157, 324, 153, 8, 6, 200, 99, 64, 291, 374, 291, 203, -1, +99, 99, 39, 6, 412, 153, 351, 157, 121, 227, 241, 519, 75, 226, 526, 316, 526, 264, 389, 178, 51, 82, -1, +75, 526, 86, 389, 387, 51, 70, 107, -1, +51, 82, 107, 212, 107, 235, 70, 442, 387, 253, 86, 443, 75, 443, 241, 202, 121, 281, 351, 436, 412, 376, -1, +412, 376, 39, 376, 158, 361, 21, 90, 52, 90, 235, 479, 263, 36, 196, 436, 196, 281, 306, 202, 119, 443, 119, 253, -1, +90, 90, 479, 361, 36, 376, 436, -1, +306, 119, 40, 450, -1, +119, 253, 450, 442, 450, 235, 40, 189, 306, 189, 196, 189, 263, 235, -1, +291, 291, 203, 506, 59, 65, 169, 229, 96, 432, 302, 432, 235, 424, 52, 373, 21, 375, 158, 249, 39, 99, -1, +432, 432, 424, 229, 373, 65, 375, 506, 249, 291, 99, -1, +59, 59, 498, 169, 460, 96, 30, 302, 452, 235, 525, 212, 299, 82, 391, 178, 57, 264, 120, 316, 85, -1, +391, 166, 299, -1, +423, 388, 72, 9, 166, 456, 299, 456, 525, 456, 452, 456, 30, 9, 460, 388, 498, 487, 256, 206, 132, -1, +423, 487, 388, -1, +206, 487, 352, 423, 341, 423, 418, 72, 139, 166, 139, 391, 57, -1, +85, 223, 120, 24, 57, 24, 139, 24, 418, 25, 341, -1, +223, 25, 24, -1, +492, 132, 515, 206, 224, 352, 359, 341, 41, 25, 171, 223, 50, 85, 43, 98, 232, 406, 258, 469, -1, +232, 345, 43, 372, 50, 454, 171, 514, 41, 314, 359, 360, 224, 2, 515, 527, -1, +393, 393, 0, 216, 349, -1, +486, 215, 327, 91, 177, 254, 177, 393, 512, 0, 231, 349, 231, 279, 486, 246, -1, +177, 512, 327, 231, 486, -1, +462, 462, 144, 76, 179, 464, 298, 464, 393, 128, 216, 113, 349, 500, 279, 101, 246, 7, 246, 395, 246, 384, 486, 215, -1, +7, 7, 195, 101, 444, 500, 462, 113, 76, 128, 464, -1, +254, 254, 285, 91, 149, 215, 83, 384, 325, 395, 520, 395, 315, 7, 143, 195, 129, 195, 461, 444, 475, 462, 144, -1, +520, 308, 325, 415, 83, 297, 149, 504, 285, 162, 278, 446, -1, +403, 403, 520, 276, 308, 404, 308, 272, 415, 416, 297, 317, 504, 125, 162, 60, 446, 110, 446, 393, 278, 254, 285, -1, +125, 125, 459, 317, 334, 416, 137, 272, 47, 404, 511, 404, 1, 276, 54, 403, 45, 370, 490, 210, 29, 184, -1, +336, 1, 251, 54, 164, 45, 463, 490, 378, 29, 453, 147, 222, 218, 301, 218, 242, 310, 130, 528, 34, -1, +26, 336, 148, 251, 269, 164, 419, 463, 293, 378, 420, 453, 333, 222, 208, 301, 294, 56, 127, 228, -1, +131, 26, 371, 148, 284, 269, 311, 419, 95, 293, 350, 420, 377, 333, 474, 208, 396, 294, 357, 127, -1, +116, 131, 273, 371, 480, 284, 104, 311, 257, 95, 348, 350, 447, 377, 313, 474, 322, 396, 28, 357, -1, +273, 273, 183, 480, 347, 104, 53, 257, 181, 348, 124, 447, 428, 313, 428, 435, 11, 270, 193, 305, 69, 305, 386, -1, +11, 11, 428, 409, 124, 382, 181, 161, 53, 481, 347, 408, 183, 319, 151, 422, 448, 4, 165, 134, 394, -1, +193, 193, 11, 495, 409, 44, 382, 385, 161, 478, 481, 320, 408, 37, 319, 524, 422, 328, 4, 465, 134, -1, +37, 37, 431, 320, 136, 478, 513, 385, 27, 44, 467, 495, 115, 193, 69, -1, +305, 305, 386, 20, 174, 182, 401, 211, 248, 106, 295, 309, 255, 465, 483, 328, 191, 524, 135, 37, 431, -1, +465, 465, 134, 309, 102, 106, 427, 211, 507, 182, 410, 20, 503, 305, 503, 270, 445, 435, 322, 313, -1, +134, 134, 394, 102, 455, 427, 5, 507, 23, 410, 405, 503, 405, 445, -1, +322, 322, 445, 28, 405, 138, 23, 485, 5, 234, 455, 74, 394, 180, 165, 49, 448, 116, 151, 273, 183, -1, +28, 357, 138, 268, 485, 287, 234, 81, 74, 78, 180, 103, 49, 220, 116, 220, 131, 476, 26, 38, 26, 336, -1, +357, 127, 268, 252, 287, 398, 81, 274, 78, 154, 103, 62, 220, 476, -1, +127, 228, 252, 141, 398, 440, 274, 363, 154, 190, 62, 488, 476, 38, -1, +301, 242, 56, 517, 228, 33, 141, 18, 440, 466, 363, 304, 190, 417, 488, 484, 38, 511, 336, 1, -1, +33, 517, 260, -1, +18, 33, 390, 260, 497, -1, +466, 18, 353, 390, 290, 497, 126, -1, +304, 466, 187, 353, 123, 290, 522, 126, 501, -1, +417, 304, 458, 187, 117, 123, 168, 522, 87, 501, 261, -1, +484, 417, 430, 458, 343, 117, 438, 168, 426, 87, 482, 261, 329, -1, +511, 484, 47, 430, 137, 343, 334, 438, 459, 426, 439, 482, 92, 329, 192, 329, 267, 329, 491, 261, 219, 501, -1, +528, 528, 34, 145, 46, 356, 105, 472, 219, 48, 491, 247, 267, 393, 192, 110, 92, 60, 439, 125, 459, -1, +219, 501, 105, 126, 46, 497, 34, 260, 130, 517, 242, -1, +29, 184, 147, 156, 218, 156, 310, 402, 528, 146, 145, 17, 356, 411, 472, 364, 48, 441, 247, 441, 393, 509, -1, +184, 184, 156, 63, 402, 354, 146, 335, 17, 239, 411, 13, 364, 509, 441, -1, +393, 509, 298, 13, 179, 239, 144, 335, 475, 354, 461, 63, 129, 184, 129, 210, 143, 370, 315, 403, 520, -1, +296, 296, 160, 133, 344, 330, -1, +344, 323, 160, -1, +159, 159, 296, 275, 133, 22, 330, 523, -1, +198, 523, 77, 22, 286, 275, 437, 159, 499, -1, +280, 323, 108, 344, 338, 330, 259, 523, 366, 198, 381, 240, 283, 10, 368, 243, 280, 243, 323, 35, 160, -1, +77, 471, 198, 471, 240, 250, 10, 303, 243, 303, 35, 230, 282, 362, 163, 73, 318, 292, 93, 477, 262, -1, +413, 413, 326, 399, 73, 399, 292, 100, 477, -1, +122, 355, 414, 61, 100, 55, 477, 508, 262, 365, -1, +35, 35, 160, 282, 296, 163, 159, 318, 499, 93, 505, 262, 340, 365, 340, 140, 68, 510, 518, 3, 122, 355, -1, +100, 399, 414, 413, 122, 111, 518, 213, 68, 167, 340, 167, 505, 245, 499, 245, 437, 346, 286, 79, 77, 471, -1, +362, 362, 221, 230, 516, 303, 516, 250, 207, 471, 207, 79, 521, 346, 468, 245, 468, 167, 468, 213, 473, 111, 204, 413, 326, -1, +468, 473, 521, 217, 207, 217, 516, 217, 221, 204, 221, 326, 362, 73, -1, +473, 204, 217, -1, +94, 94, 185, 529, 429, 209, 429, 176, -1, +379, 379, 94, 199, 529, 367, 209, 172, 209, 66, 176, 496, -1, +312, 312, 379, 238, 199, 15, 367, 332, 172, 197, 172, 451, 66, 84, 496, 186, -1, +266, 266, 312, 392, 238, 201, 15, 14, 332, 457, 197, 383, 197, 225, 451, 502, 84, 265, 186, 205, -1, +236, 236, 266, 214, 392, 71, 201, 188, 14, 173, 457, 400, 383, 380, 383, 342, 225, 109, 502, 175, 265, 97, 205, 118, -1, +152, 152, 236, 337, 214, 58, 71, 369, 188, 434, 173, 114, 400, 288, 380, 42, 380, 397, 342, 32, 109, 331, -1, +379, 170, 312, 331, 266, 32, 236, 397, 152, 42, 194, 42, 407, 288, 142, 114, 12, 434, 233, 369, 244, -1, +369, 369, 244, 58, 425, 337, 321, 152, 194, -1, +109, 331, 175, 170, 97, 300, 118, 421, 31, 89, -1, +31, 31, 118, 237, 205, 449, 186, 470, 496, 494, 176, 155, 429, 112, 185, 89, 185, 421, 94, 300, 379, 170, -1 +}; + +#else /* defined(_WIN32_WCE) */ + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +/* + * Rim, body, lid, and bottom data must be reflected in x and y; + * handle and spout data across the y axis only. + */ +static int patchdata[][16] = +{ + { 102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, /* rim */ + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, /* body */ + { 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 }, + { 96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3 }, /* lid */ + { 0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117 }, + { 118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37 }, /* bottom */ + { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 }, /* handle */ + { 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67 }, + { 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83 }, /* spout */ + { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 } +}; + +static double cpdata[][3] = +{ + {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0, + -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125}, + {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375, + 0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375, + 2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84, + 2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875}, + {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75, + 1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35}, + {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2, + 0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12, + 0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225}, + {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225}, + {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0, + -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5, + -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3, + 2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0, + 2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0, + 2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8}, + {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3, + -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3, + 1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2, + -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0, + 1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0, + 0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66, + 0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1}, + {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7, + -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0, + 2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375}, + {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475}, + {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4}, + {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0, + 3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8, + 3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4, + -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0, + 2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4, + 2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3, + 2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4}, + {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425, + -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425, + 0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075}, + {0.84, -1.5, 0.075} +}; + +static double tex[2][2][2] = +{ + { {0.0, 0.0}, {1.0, 0.0} }, + { {0.0, 1.0}, {1.0, 1.0} } +}; +#endif /* defined(_WIN32_WCE) */ + + +#endif /* FREEGLUT_TEAPOT_DATA_H */ + diff --git a/internal/c/parts/core/freeglut/freeglut_window.c b/internal/c/parts/core/freeglut/freeglut_window.c index 30be18987..d6c0c517c 100644 --- a/internal/c/parts/core/freeglut/freeglut_window.c +++ b/internal/c/parts/core/freeglut/freeglut_window.c @@ -1,2171 +1,2169 @@ -/* - * freeglut_window.c - * - * Window management methods. - * - * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - * Written by Pawel W. Olszta, - * Creation date: Fri Dec 3 1999 - * - * 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. - */ - -// QB64 -void QB64_Window_Handle(void *handle); - -int QB64_Resizable(); -/* -changed: -WS_OVERLAPPEDWINDOW -...to... -((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) -*/ - -#define FREEGLUT_BUILDING_LIB -#include -#include "freeglut_internal.h" - -#if TARGET_HOST_POSIX_X11 -#include /* LONG_MAX */ -#include /* usleep */ -#endif - -#if defined(_WIN32_WCE) -# include -# ifdef FREEGLUT_LIB_PRAGMAS -# pragma comment( lib, "Aygshell.lib" ) -# endif -#endif /* defined(_WIN32_WCE) */ - - -#if TARGET_HOST_POSIX_X11 -#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB -#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 -#endif - -#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#endif - -#ifndef GLX_CONTEXT_MINOR_VERSION_ARB -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -#endif - -#ifndef GLX_CONTEXT_FLAGS_ARB -#define GLX_CONTEXT_FLAGS_ARB 0x2094 -#endif - -#ifndef GLX_CONTEXT_PROFILE_MASK_ARB -#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 -#endif - -#ifndef GLX_CONTEXT_DEBUG_BIT_ARB -#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 -#endif - -#ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB -#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 -#endif - -#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB -#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#endif - -#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB -#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#endif - -#ifndef GLX_RGBA_FLOAT_TYPE -#define GLX_RGBA_FLOAT_TYPE 0x20B9 -#endif - -#ifndef GLX_RGBA_FLOAT_BIT -#define GLX_RGBA_FLOAT_BIT 0x00000004 -#endif -#endif /* TARGET_HOST_POSIX_X11 */ - - -#if TARGET_HOST_MS_WINDOWS -/* The following include file is available from SGI but is not standard: - * #include - * So we copy the necessary parts out of it. - * XXX: should local definitions for extensions be put in a separate include file? - */ -typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); - -typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); - -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_COLOR_BITS_ARB 0x2014 -#define WGL_ALPHA_BITS_ARB 0x201B -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_FULL_ACCELERATION_ARB 0x2027 - -#define WGL_SAMPLE_BUFFERS_ARB 0x2041 -#define WGL_SAMPLES_ARB 0x2042 - -#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 - -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 - -#ifndef WGL_ARB_create_context -#define WGL_ARB_create_context 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); - -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 - -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 - -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 - -#define ERROR_INVALID_VERSION_ARB 0x2095 -#define ERROR_INVALID_PROFILE_ARB 0x2096 -#endif - -#endif /* TARGET_HOST_MS_WINDOWS */ - -#ifdef WM_TOUCH - typedef BOOL (WINAPI *pRegisterTouchWindow)(HWND,ULONG); - static pRegisterTouchWindow fghRegisterTouchWindow = (pRegisterTouchWindow)0xDEADBEEF; -#endif - -/* pushing attribute/value pairs into an array */ -#define ATTRIB(a) attributes[where++]=(a) -#define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);} - -/* - * TODO BEFORE THE STABLE RELEASE: - * - * fgChooseFBConfig() -- OK, but what about glutInitDisplayString()? - * fgSetupPixelFormat -- ignores the display mode settings - * fgOpenWindow() -- check the Win32 version, -iconic handling! - * fgCloseWindow() -- check the Win32 version - * glutCreateWindow() -- Check when default position and size is {-1,-1} - * glutCreateSubWindow() -- Check when default position and size is {-1,-1} - * glutDestroyWindow() -- check the Win32 version - * glutSetWindow() -- check the Win32 version - * glutGetWindow() -- OK - * glutSetWindowTitle() -- check the Win32 version - * glutSetIconTitle() -- check the Win32 version - * glutShowWindow() -- check the Win32 version - * glutHideWindow() -- check the Win32 version - * glutIconifyWindow() -- check the Win32 version - * glutReshapeWindow() -- check the Win32 version - * glutPositionWindow() -- check the Win32 version - * glutPushWindow() -- check the Win32 version - * glutPopWindow() -- check the Win32 version - */ - -/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ - -static int fghIsLegacyContextVersionRequested( void ) -{ - return fgState.MajorVersion < 2 || (fgState.MajorVersion == 2 && fgState.MinorVersion <= 1); -} - -static int fghIsLegacyContextRequested( void ) -{ - return fghIsLegacyContextVersionRequested() && - fgState.ContextFlags == 0 && - fgState.ContextProfile == 0; -} - -static int fghNumberOfAuxBuffersRequested( void ) -{ - if ( fgState.DisplayMode & GLUT_AUX4 ) { - return 4; - } - if ( fgState.DisplayMode & GLUT_AUX3 ) { - return 3; - } - if ( fgState.DisplayMode & GLUT_AUX2 ) { - return 2; - } - if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */ - return fgState.AuxiliaryBufferNumber; - } - return 0; -} - -static int fghMapBit( int mask, int from, int to ) -{ - return ( mask & from ) ? to : 0; - -} - -static void fghContextCreationError( void ) -{ - fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)", - fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags, - fgState.ContextProfile ); -} - - -/* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */ - -#if TARGET_HOST_POSIX_X11 -/* - * Chooses a visual basing on the current display mode settings - */ - -GLXFBConfig* fgChooseFBConfig( int *numcfgs ) -{ - GLboolean wantIndexedMode = GL_FALSE; - int attributes[ 100 ]; - int where = 0, numAuxBuffers; - - /* First we have to process the display mode settings... */ - if( fgState.DisplayMode & GLUT_INDEX ) { - ATTRIB_VAL( GLX_BUFFER_SIZE, 8 ); - /* Buffer size is selected later. */ - - ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT ); - wantIndexedMode = GL_TRUE; - } else { - ATTRIB_VAL( GLX_RED_SIZE, 1 ); - ATTRIB_VAL( GLX_GREEN_SIZE, 1 ); - ATTRIB_VAL( GLX_BLUE_SIZE, 1 ); - if( fgState.DisplayMode & GLUT_ALPHA ) { - ATTRIB_VAL( GLX_ALPHA_SIZE, 1 ); - } - } - - if( fgState.DisplayMode & GLUT_DOUBLE ) { - ATTRIB_VAL( GLX_DOUBLEBUFFER, True ); - } - - if( fgState.DisplayMode & GLUT_STEREO ) { - ATTRIB_VAL( GLX_STEREO, True ); - } - - if( fgState.DisplayMode & GLUT_DEPTH ) { - ATTRIB_VAL( GLX_DEPTH_SIZE, 1 ); - } - - if( fgState.DisplayMode & GLUT_STENCIL ) { - ATTRIB_VAL( GLX_STENCIL_SIZE, 1 ); - } - - if( fgState.DisplayMode & GLUT_ACCUM ) { - ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 ); - ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 ); - ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 ); - if( fgState.DisplayMode & GLUT_ALPHA ) { - ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 ); - } - } - - numAuxBuffers = fghNumberOfAuxBuffersRequested(); - if ( numAuxBuffers > 0 ) { - ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers ); - } - - if( fgState.DisplayMode & GLUT_SRGB ) { - ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True ); - } - - if (fgState.DisplayMode & GLUT_MULTISAMPLE) { - ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1); - ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber); - } - - /* Push a terminator at the end of the list */ - ATTRIB( None ); - - { - GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ - GLXFBConfig * fbconfig; /* The FBConfig we want */ - int fbconfigArraySize; /* Number of FBConfigs in the array */ - - - /* Get all FBConfigs that match "attributes". */ - fbconfigArray = glXChooseFBConfig( fgDisplay.Display, - fgDisplay.Screen, - attributes, - &fbconfigArraySize ); - - if (fbconfigArray != NULL) - { - int result; /* Returned by glXGetFBConfigAttrib, not checked. */ - - - if( wantIndexedMode ) - { - /* - * In index mode, we want the largest buffer size, i.e. visual - * depth. Here, FBConfigs are sorted by increasing buffer size - * first, so FBConfigs with the largest size come last. - */ - - int bufferSizeMin, bufferSizeMax; - - /* Get bufferSizeMin. */ - result = - glXGetFBConfigAttrib( fgDisplay.Display, - fbconfigArray[0], - GLX_BUFFER_SIZE, - &bufferSizeMin ); - /* Get bufferSizeMax. */ - result = - glXGetFBConfigAttrib( fgDisplay.Display, - fbconfigArray[fbconfigArraySize - 1], - GLX_BUFFER_SIZE, - &bufferSizeMax ); - - if (bufferSizeMax > bufferSizeMin) - { - /* - * Free and reallocate fbconfigArray, keeping only FBConfigs - * with the largest buffer size. - */ - XFree(fbconfigArray); - - /* Add buffer size token at the end of the list. */ - where--; - ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax ); - ATTRIB( None ); - - fbconfigArray = glXChooseFBConfig( fgDisplay.Display, - fgDisplay.Screen, - attributes, - &fbconfigArraySize ); - } - } - - /* - * We now have an array of FBConfigs, the first one being the "best" - * one. So we should return only this FBConfig: - * - * int fbconfigXID; - * - * - pick the XID of the FBConfig we want - * result = glXGetFBConfigAttrib( fgDisplay.Display, - * fbconfigArray[0], - * GLX_FBCONFIG_ID, - * &fbconfigXID ); - * - * - free the array - * XFree(fbconfigArray); - * - * - reset "attributes" with the XID - * where = 0; - * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID ); - * ATTRIB( None ); - * - * - get our FBConfig only - * fbconfig = glXChooseFBConfig( fgDisplay.Display, - * fgDisplay.Screen, - * attributes, - * &fbconfigArraySize ); - * - * However, for some configurations (for instance multisampling with - * Mesa 6.5.2 and ATI drivers), this does not work: - * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid - * XID. Further investigation is needed. - * - * So, for now, we return the whole array of FBConfigs. This should - * not produce any side effects elsewhere. - */ - fbconfig = fbconfigArray; - } - else - { - fbconfig = NULL; - } - - if (numcfgs) - *numcfgs = fbconfigArraySize; - - return fbconfig; - } -} - - -static void fghFillContextAttributes( int *attributes ) { - int where = 0, contextFlags, contextProfile; - - if ( !fghIsLegacyContextVersionRequested() ) { - ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); - ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); - } - - contextFlags = - fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) | - fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); - if ( contextFlags != 0 ) { - ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags ); - } - - contextProfile = - fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) | - fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); - if ( contextProfile != 0 ) { - ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile ); - } - - ATTRIB( 0 ); -} - -typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config, - GLXContext share_list, Bool direct, - const int *attrib_list); - -static GLXContext fghCreateNewContext( SFG_Window* window ) -{ - /* for color model calculation */ - int menu = ( window->IsMenu && !fgStructure.MenuContext ); - int index_mode = ( fgState.DisplayMode & GLUT_INDEX ); - - /* "classic" context creation */ - Display *dpy = fgDisplay.Display; - GLXFBConfig config = *(window->Window.FBConfig); - int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE; - GLXContext share_list = NULL; - Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ); - GLXContext context; - - /* new context creation */ - int attributes[9]; - CreateContextAttribsProc createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" ); - - /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */ - if ( !createContextAttribs && !fghIsLegacyContextRequested() ) { - fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" ); - fgState.MajorVersion = 2; - fgState.MinorVersion = 1; - } - - /* If nothing fancy has been required, simply use the old context creation GLX API entry */ - if ( fghIsLegacyContextRequested() || !createContextAttribs ) - { - context = glXCreateNewContext( dpy, config, render_type, share_list, direct ); - if ( context == NULL ) { - fghContextCreationError(); - } - return context; - } - - /* color index mode is not available anymore with OpenGL 3.0 */ - if ( render_type == GLX_COLOR_INDEX_TYPE ) { - fgWarning( "color index mode is deprecated, using RGBA mode" ); - } - - fghFillContextAttributes( attributes ); - - context = createContextAttribs( dpy, config, share_list, direct, attributes ); - if ( context == NULL ) { - fghContextCreationError(); - } - return context; -} - - -#define _NET_WM_STATE_TOGGLE 2 -static int fghResizeFullscrToggle(void) -{ - XWindowAttributes attributes; - - if(glutGet(GLUT_FULL_SCREEN)) { - /* restore original window size */ - SFG_Window *win = fgStructure.CurrentWindow; - fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; - fgStructure.CurrentWindow->State.Width = win->State.OldWidth; - fgStructure.CurrentWindow->State.Height = win->State.OldHeight; - - } else { - /* resize the window to cover the entire screen */ - XGetWindowAttributes(fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - &attributes); - - /* - * The "x" and "y" members of "attributes" are the window's coordinates - * relative to its parent, i.e. to the decoration window. - */ - XMoveResizeWindow(fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - -attributes.x, - -attributes.y, - fgDisplay.ScreenWidth, - fgDisplay.ScreenHeight); - } - return 0; -} - -static int fghEwmhFullscrToggle(void) -{ - XEvent xev; - long evmask = SubstructureRedirectMask | SubstructureNotifyMask; - - if(!fgDisplay.State || !fgDisplay.StateFullScreen) { - return -1; - } - - xev.type = ClientMessage; - xev.xclient.window = fgStructure.CurrentWindow->Window.Handle; - xev.xclient.message_type = fgDisplay.State; - xev.xclient.format = 32; - xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; - xev.xclient.data.l[1] = fgDisplay.StateFullScreen; - xev.xclient.data.l[2] = 0; /* no second property to toggle */ - xev.xclient.data.l[3] = 1; /* source indication: application */ - xev.xclient.data.l[4] = 0; /* unused */ - - if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) { - return -1; - } - return 0; -} - -static int fghToggleFullscreen(void) -{ - /* first try the EWMH (_NET_WM_STATE) method ... */ - if(fghEwmhFullscrToggle() != -1) { - return 0; - } - - /* fall back to resizing the window */ - if(fghResizeFullscrToggle() != -1) { - return 0; - } - return -1; -} - - -#endif /* TARGET_HOST_POSIX_X11 */ - - -#if TARGET_HOST_MS_WINDOWS -/* - * Setup the pixel format for a Win32 window - */ - -#if defined(_WIN32_WCE) -static wchar_t* fghWstrFromStr(const char* str) -{ - int i,len=strlen(str); - wchar_t* wstr = (wchar_t*)malloc(2*len+2); - for(i=0; iWindow.Device, window->Window.Context ); - - if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) ) - { - return; - } - - /* new context creation */ - fghFillContextAttributes( attributes ); - - wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" ); - if ( wglCreateContextAttribsARB == NULL ) - { - fgError( "wglCreateContextAttribsARB not found" ); - } - - context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes ); - if ( context == NULL ) - { - fghContextCreationError(); - } - - wglMakeCurrent( NULL, NULL ); - wglDeleteContext( window->Window.Context ); - window->Window.Context = context; -} - -#if !defined(_WIN32_WCE) - -static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type ) -{ - int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - if ( fgState.DisplayMode & GLUT_DOUBLE ) { - flags |= PFD_DOUBLEBUFFER; - } - if ( fgState.DisplayMode & GLUT_STEREO ) { - flags |= PFD_STEREO; - } - -#if defined(_MSC_VER) -#pragma message( "fgSetupPixelFormat(): there is still some work to do here!" ) -#endif - - /* Specify which pixel format do we opt for... */ - ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); - ppfd->nVersion = 1; - ppfd->dwFlags = flags; - - if( fgState.DisplayMode & GLUT_INDEX ) { - ppfd->iPixelType = PFD_TYPE_COLORINDEX; - ppfd->cRedBits = 0; - ppfd->cGreenBits = 0; - ppfd->cBlueBits = 0; - ppfd->cAlphaBits = 0; - } else { - ppfd->iPixelType = PFD_TYPE_RGBA; - ppfd->cRedBits = 8; - ppfd->cGreenBits = 8; - ppfd->cBlueBits = 8; - ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0; - } - - ppfd->cColorBits = 24; - ppfd->cRedShift = 0; - ppfd->cGreenShift = 0; - ppfd->cBlueShift = 0; - ppfd->cAlphaShift = 0; - ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0; - ppfd->cAccumRedBits = 0; - ppfd->cAccumGreenBits = 0; - ppfd->cAccumBlueBits = 0; - ppfd->cAccumAlphaBits = 0; - - /* Hmmm, or 32/0 instead of 24/8? */ - ppfd->cDepthBits = 24; - ppfd->cStencilBits = 8; - - ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested(); - ppfd->iLayerType = layer_type; - ppfd->bReserved = 0; - ppfd->dwLayerMask = 0; - ppfd->dwVisibleMask = 0; - ppfd->dwDamageMask = 0; - - ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL ); -} - -static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd ) -{ - int where = 0; - - ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); - ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); - ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); - - ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits ); - ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits ); - ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits ); - ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits ); - - ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 ); - - if ( fgState.DisplayMode & GLUT_SRGB ) { - ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE ); - } - - ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); - ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber ); - ATTRIB( 0 ); -} -#endif - -GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, - unsigned char layer_type ) -{ -#if defined(_WIN32_WCE) - return GL_TRUE; -#else - PIXELFORMATDESCRIPTOR pfd; - PIXELFORMATDESCRIPTOR* ppfd = &pfd; - int pixelformat; - HDC current_hDC; - GLboolean success; - - if (checkOnly) - current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL); - else - current_hDC = window->Window.Device; - - fghFillPFD( ppfd, current_hDC, layer_type ); - - pixelformat = ChoosePixelFormat( current_hDC, ppfd ); - - /* windows hack for multismapling/sRGB */ - if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) || - ( fgState.DisplayMode & GLUT_SRGB ) ) - { - - HGLRC rc, rc_before=wglGetCurrentContext(); - HWND hWnd; - HDC hDC, hDC_before=wglGetCurrentDC(); - WNDCLASS wndCls; - - /* create a dummy window */ - ZeroMemory(&wndCls, sizeof(wndCls)); - wndCls.lpfnWndProc = DefWindowProc; - wndCls.hInstance = fgDisplay.Instance; - wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; - wndCls.lpszClassName = _T("FREEGLUT_dummy"); - RegisterClass( &wndCls ); - - hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())) , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 ); - hDC=GetDC(hWnd); - SetPixelFormat( hDC, pixelformat, ppfd ); - - rc = wglCreateContext( hDC ); - wglMakeCurrent(hDC, rc); - - if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) ) - { - PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc = - (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); - if ( wglChoosePixelFormatARBProc ) - { - int attributes[100]; - int iPixelFormat; - BOOL bValid; - float fAttributes[] = { 0, 0 }; - UINT numFormats; - fghFillPixelFormatAttributes( attributes, ppfd ); - bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats); - - if ( bValid && numFormats > 0 ) - { - pixelformat = iPixelFormat; - } - } - } - - wglMakeCurrent( hDC_before, rc_before); - wglDeleteContext(rc); - ReleaseDC(hWnd, hDC); - DestroyWindow(hWnd); - UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance); - } - - success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) ); - - if (checkOnly) - DeleteDC(current_hDC); - - return success; -#endif /* defined(_WIN32_WCE) */ -} - -#endif /* TARGET_HOST_MS_WINDOWS */ - -/* - * Sets the OpenGL context and the fgStructure "Current Window" pointer to - * the window structure passed in. - */ -void fgSetWindow ( SFG_Window *window ) -{ -#if TARGET_HOST_POSIX_X11 - if ( window ) - { - glXMakeContextCurrent( - fgDisplay.Display, - window->Window.Handle, - window->Window.Handle, - window->Window.Context - ); - } -#elif TARGET_HOST_MS_WINDOWS - if ( window != fgStructure.CurrentWindow ) - { - if( fgStructure.CurrentWindow ) - ReleaseDC( fgStructure.CurrentWindow->Window.Handle, - fgStructure.CurrentWindow->Window.Device ); - - if ( window ) - { - window->Window.Device = GetDC( window->Window.Handle ); - wglMakeCurrent( - window->Window.Device, - window->Window.Context - ); - } - } -#endif - fgStructure.CurrentWindow = window; -} - -#if TARGET_HOST_MS_WINDOWS - -/* Computes position of corners of window Rect (outer position including - * decorations) based on the provided client rect and based on the style - * of the window in question. - * If posIsOutside is set to true, the input client Rect is taken to follow - * freeGLUT's window specification convention in which the top-left corner - * is at the outside of the window, while the size - * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable - * area. - */ -void fghComputeWindowRectFromClientArea_UseStyle( const DWORD windowStyle, RECT *clientRect, BOOL posIsOutside ) -{ - RECT windowRect = {0, 0, 0, 0}; - DWORD windowExStyle = 0; - - CopyRect(&windowRect, clientRect); - - /* Get rect including non-client area */ - AdjustWindowRectEx(&windowRect, windowStyle, FALSE, windowExStyle); - - /* Move window right and down by non-client area extent on left and top, if wanted */ - if (posIsOutside) { - windowRect.right += clientRect->left - windowRect.left; - windowRect.bottom += clientRect->top - windowRect.top; - windowRect.left = clientRect->left; - windowRect.top = clientRect->top; - } - - /* done, copy windowRect to output */ - CopyRect(clientRect, &windowRect); -} - -/* Computes position of corners of window Rect (outer position including - * decorations) based on the provided client rect and based on the style - * of the window in question. If the window pointer or the window handle - * is NULL, a fully decorated window (caption and border) is assumed. - * Furthermore, if posIsOutside is set to true, the input client Rect is - * taken to follow freeGLUT's window specification convention in which the - * top-left corner is at the outside of the window, while the size - * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable - * area. -*/ -void fghComputeWindowRectFromClientArea_QueryWindow( const SFG_Window *window, RECT *clientRect, BOOL posIsOutside ) -{ - DWORD windowStyle = 0; - - if (window && window->Window.Handle) - windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); - else - windowStyle = ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); - - fghComputeWindowRectFromClientArea_UseStyle(windowStyle, clientRect, posIsOutside); -} - -/* Computes position of corners of client area (drawable area) of a window - * based on the provided window Rect (outer position including decorations) - * and based on the style of the window in question. If the window pointer - * or the window handle is NULL, a fully decorated window (caption and - * border) is assumed. - * Furthermore, if wantPosOutside is set to true, the output client Rect - * will follow freeGLUT's window specification convention in which the - * top-left corner is at the outside of the window, the size - * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable - * area. - */ -void fghComputeClientAreaFromWindowRect( const SFG_Window *window, RECT *windowRect, BOOL wantPosOutside ) -{ - DWORD windowStyle = 0; - int xBorderWidth = 0, yBorderWidth = 0; - - if (window && window->Window.Handle) - windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); - else - windowStyle = ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); - - /* If window has title bar, correct rect for it */ - if (windowStyle & WS_SYSMENU) /* Need to query for WS_SYSMENU to see if we have a title bar, the WS_CAPTION query is also true for a WS_DLGFRAME only... */ - if (wantPosOutside) - windowRect->bottom -= GetSystemMetrics( SM_CYCAPTION ); - else - windowRect->top += GetSystemMetrics( SM_CYCAPTION ); - - /* get width of window's borders (frame), correct rect for it. - * Note, borders can be of zero width if style does not specify borders - */ - fghGetBorderWidth(windowStyle, &xBorderWidth, &yBorderWidth); - if (wantPosOutside) - { - windowRect->right -= xBorderWidth * 2; - windowRect->bottom -= yBorderWidth * 2; - } - else - { - windowRect->left += xBorderWidth; - windowRect->right -= xBorderWidth; - windowRect->top += yBorderWidth; - windowRect->bottom -= yBorderWidth; - } -} - -/* Gets the rect describing the client area (drawable area) of the - * specified window. - * Returns an empty rect if window pointer or window handle is NULL. - * If wantPosOutside is set to true, the output client Rect - * will follow freeGLUT's window specification convention in which the - * top-left corner is at the outside of the window, while the size - * (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable - * area. - */ -RECT fghGetClientArea( const SFG_Window *window, BOOL wantPosOutside ) -{ - RECT windowRect = {0,0,0,0}; - - freeglut_return_val_if_fail((window && window->Window.Handle),windowRect); - - /* - * call GetWindowRect() - * (this returns the pixel coordinates of the outside of the window) - */ - GetWindowRect( window->Window.Handle, &windowRect ); - - /* Then correct the results */ - fghComputeClientAreaFromWindowRect(window, &windowRect, wantPosOutside); - - return windowRect; -} - -/* Returns the width of the window borders based on the window's style. - */ -void fghGetBorderWidth(const DWORD windowStyle, int* xBorderWidth, int* yBorderWidth) -{ - if (windowStyle & WS_THICKFRAME) - { - *xBorderWidth = GetSystemMetrics(SM_CXSIZEFRAME); - *yBorderWidth = GetSystemMetrics(SM_CYSIZEFRAME); - } - else if (windowStyle & WS_DLGFRAME) - { - *xBorderWidth = GetSystemMetrics(SM_CXFIXEDFRAME); - *yBorderWidth = GetSystemMetrics(SM_CYFIXEDFRAME); - } - else - { - *xBorderWidth = 0; - *yBorderWidth = 0; - } -} - -#if(WINVER >= 0x500) -typedef struct -{ - int *x; - int *y; - const char *name; -} m_proc_t; - -static BOOL CALLBACK m_proc(HMONITOR mon, - HDC hdc, - LPRECT rect, - LPARAM data) -{ - m_proc_t *dp=(m_proc_t *)data; - MONITORINFOEX info; - BOOL res; - info.cbSize=sizeof(info); - res=GetMonitorInfo(mon,(LPMONITORINFO)&info); - if( res ) - { - if( strcmp(dp->name,info.szDevice)==0 ) - { - *(dp->x)=info.rcMonitor.left; - *(dp->y)=info.rcMonitor.top; - return FALSE; - } - } - return TRUE; -} - -/* - * this function returns the origin of the screen identified by - * fgDisplay.DisplayName, and 0 otherwise. - * This is used in fgOpenWindow to open the gamemode window on the screen - * identified by the -display command line argument. The function should - * not be called otherwise. - */ - -static void get_display_origin(int *xp,int *yp) -{ - *xp = 0; - *yp = 0; - - if( fgDisplay.DisplayName ) - { - m_proc_t st; - st.x=xp; - st.y=yp; - st.name=fgDisplay.DisplayName; - EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st); - } -} -#else -#pragma message( "-display parameter only works if compiled with WINVER >= 0x0500") - -static void get_display_origin(int *xp,int *yp) -{ - *xp = 0; - *yp = 0; - - if( fgDisplay.DisplayName ) - { - fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500"); - } -} -#endif -#endif - - -#if TARGET_HOST_POSIX_X11 -static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg) -{ - Window window = (Window)arg; - return (event->type == MapNotify) && (event->xmap.window == window); -} -#endif - - -/* - * Opens a window. Requires a SFG_Window object created and attached - * to the freeglut structure. OpenGL context is created here. - */ -void fgOpenWindow( SFG_Window* window, const char* title, - GLboolean positionUse, int x, int y, - GLboolean sizeUse, int w, int h, - GLboolean gameMode, GLboolean isSubWindow ) -{ -#if TARGET_HOST_POSIX_X11 - XVisualInfo * visualInfo = NULL; - XSetWindowAttributes winAttr; - XTextProperty textProperty; - XSizeHints sizeHints; - XWMHints wmHints; - XEvent eventReturnBuffer; /* return buffer required for a call */ - unsigned long mask; - int num_FBConfigs, i; - unsigned int current_DisplayMode = fgState.DisplayMode ; - - /* Save the display mode if we are creating a menu window */ - if( window->IsMenu && ( ! fgStructure.MenuContext ) ) - fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ; - - window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); - - if( window->IsMenu && ( ! fgStructure.MenuContext ) ) - fgState.DisplayMode = current_DisplayMode ; - - if( ! window->Window.FBConfig ) - { - /* - * The "fgChooseFBConfig" returned a null meaning that the visual - * context is not available. - * Try a couple of variations to see if they will work. - */ - if( !( fgState.DisplayMode & GLUT_DOUBLE ) ) - { - fgState.DisplayMode |= GLUT_DOUBLE ; - window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); - fgState.DisplayMode &= ~GLUT_DOUBLE; - } - - if( fgState.DisplayMode & GLUT_MULTISAMPLE ) - { - fgState.DisplayMode &= ~GLUT_MULTISAMPLE ; - window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); - fgState.DisplayMode |= GLUT_MULTISAMPLE; - } - } - - FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL, - "FBConfig with necessary capabilities not found", "fgOpenWindow" ); - - /* Get the X visual. */ - for (i = 0; i < num_FBConfigs; i++) { - visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display, - window->Window.FBConfig[i] ); - if (visualInfo) - break; - } - - FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL, - "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" ); - - /* - * XXX HINT: the masks should be updated when adding/removing callbacks. - * XXX This might speed up message processing. Is that true? - * XXX - * XXX A: Not appreciably, but it WILL make it easier to debug. - * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT - * XXX turns off events that it doesn't need and is a whole lot - * XXX more pleasant to trace. (Think mouse-motion! Tons of - * XXX ``bonus'' GUI events stream in.) - */ - winAttr.event_mask = - StructureNotifyMask | SubstructureNotifyMask | ExposureMask | - ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | - VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | - PointerMotionMask | ButtonMotionMask; - winAttr.background_pixmap = None; - winAttr.background_pixel = 0; - winAttr.border_pixel = 0; - - winAttr.colormap = XCreateColormap( - fgDisplay.Display, fgDisplay.RootWindow, - visualInfo->visual, AllocNone - ); - - mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; - - if( window->IsMenu || ( gameMode == GL_TRUE ) ) - { - winAttr.override_redirect = True; - mask |= CWOverrideRedirect; - } - - if( ! positionUse ) - x = y = -1; /* default window position */ - if( ! sizeUse ) - w = h = 300; /* default window size */ - - window->Window.Handle = XCreateWindow( - fgDisplay.Display, - window->Parent == NULL ? fgDisplay.RootWindow : - window->Parent->Window.Handle, - x, y, w, h, 0, - visualInfo->depth, InputOutput, - visualInfo->visual, mask, - &winAttr - ); - - /* - * The GLX context creation, possibly trying the direct context rendering - * or else use the current context if the user has so specified - */ - - if( window->IsMenu ) - { - /* - * If there isn't already an OpenGL rendering context for menu - * windows, make one - */ - if( !fgStructure.MenuContext ) - { - fgStructure.MenuContext = - (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); - fgStructure.MenuContext->MContext = fghCreateNewContext( window ); - } - - /* window->Window.Context = fgStructure.MenuContext->MContext; */ - window->Window.Context = fghCreateNewContext( window ); - } - else if( fgState.UseCurrentContext ) - { - window->Window.Context = glXGetCurrentContext( ); - - if( ! window->Window.Context ) - window->Window.Context = fghCreateNewContext( window ); - } - else - window->Window.Context = fghCreateNewContext( window ); - -#if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) - if( !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) - { - if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) - fgError( "Unable to force direct context rendering for window '%s'", - title ); - } -#endif - - /* - * XXX Assume the new window is visible by default - * XXX Is this a safe assumption? - */ - window->State.Visible = GL_TRUE; - - sizeHints.flags = 0; - if ( positionUse ) - sizeHints.flags |= USPosition; - if ( sizeUse ) - sizeHints.flags |= USSize; - - /* - * Fill in the size hints values now (the x, y, width and height - * settings are obsolete, are there any more WMs that support them?) - * Unless the X servers actually stop supporting these, we should - * continue to fill them in. It is *not* our place to tell the user - * that they should replace a window manager that they like, and which - * works, just because *we* think that it's not "modern" enough. - */ - sizeHints.x = x; - sizeHints.y = y; - sizeHints.width = w; - sizeHints.height = h; - - wmHints.flags = StateHint; - wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState; - /* Prepare the window and iconified window names... */ - XStringListToTextProperty( (char **) &title, 1, &textProperty ); - - XSetWMProperties( - fgDisplay.Display, - window->Window.Handle, - &textProperty, - &textProperty, - 0, - 0, - &sizeHints, - &wmHints, - NULL - ); - XFree( textProperty.value ); - - XSetWMProtocols( fgDisplay.Display, window->Window.Handle, - &fgDisplay.DeleteWindow, 1 ); - - glXMakeContextCurrent( - fgDisplay.Display, - window->Window.Handle, - window->Window.Handle, - window->Window.Context - ); - - /* register extension events _before_ window is mapped */ - #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H - fgRegisterDevices( fgDisplay.Display, &(window->Window.Handle) ); - #endif - - XMapWindow( fgDisplay.Display, window->Window.Handle ); - - XFree(visualInfo); - - if( !isSubWindow) - XPeekIfEvent( fgDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) ); - -#elif TARGET_HOST_MS_WINDOWS - - WNDCLASS wc; - DWORD flags = 0; - DWORD exFlags = 0; - ATOM atom; - - /* Grab the window class we have registered on glutInit(): */ - atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); - FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found", - "fgOpenWindow" ); - - /* Determine window style flags*/ - if( gameMode ) - { - FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL, - "Game mode being invoked on a subwindow", - "fgOpenWindow" ); - - /* - * Set the window creation flags appropriately to make the window - * entirely visible: - */ - flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; - } - else - { - flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; - - /* - * There's a small difference between creating the top, child and - * menu windows - */ - if ( window->IsMenu ) - { - flags |= WS_POPUP; - exFlags |= WS_EX_TOOLWINDOW; - } -#if defined(_WIN32_WCE) - /* no decorations for windows CE */ -#else - /* if this is not a subwindow (child), set its style based on the requested display mode */ - else if( window->Parent == NULL ) - if ( fgState.DisplayMode & GLUT_BORDERLESS ) - { - /* no window decorations needed */ - } - else if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) - /* only window decoration is a border, no title bar or buttons */ - flags |= WS_DLGFRAME; - else - /* window decoration are a border, title bar and buttons. - * NB: we later query whether the window has a title bar or - * not by testing for the maximize button, as the test for - * WS_CAPTION can be true without the window having a title - * bar. This style ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) gives you a maximize - * button. */ - flags |= ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); -#endif - else - /* subwindows always have no decoration, but are marked as a child window to the OS */ - flags |= WS_CHILD; - } - - /* determine window size and position */ - if( gameMode ) - { - /* if in gamemode, query the origin of specified by the -display - * command line parameter (if any) and offset the upper-left corner - * of the window so we create the window on that screen. - * The -display argument doesn't do anything if not trying to enter - * gamemode. - */ - int xoff=0, yoff=0; - get_display_origin(&xoff,&yoff); - x += xoff; - y += yoff; - } - if( !positionUse ) - { - x = CW_USEDEFAULT; - y = CW_USEDEFAULT; - } - if( !sizeUse ) - { - if( ! window->IsMenu ) - { - w = CW_USEDEFAULT; - h = CW_USEDEFAULT; - } - else /* fail safe - Windows can make a window of size (0, 0) */ - w = h = 300; /* default window size */ - } - /* store requested client area width and height */ - window->State.Width = w; - window->State.Height = h; - -#if !defined(_WIN32_WCE) /* no decorations for windows CE */ - if( sizeUse ) - { - RECT windowRect; - /* - * Update the window dimensions, taking the window decorations - * into account. FreeGLUT is to create the window with the - * topleft outside corner at (x,y) and with client area - * dimensions (w,h). - * note: don't need to do this when w=h=CW_USEDEFAULT, so in the - * if( sizeUse ) here is convenient. - */ - windowRect.left = x; - windowRect.top = y; - windowRect.right = x+w; - windowRect.bottom = y+h; - - fghComputeWindowRectFromClientArea_UseStyle(flags,&windowRect,TRUE); - - w = windowRect.right - windowRect.left; - h = windowRect.bottom- windowRect.top; - } -#endif /* !defined(_WIN32_WCE) */ - -#if defined(_WIN32_WCE) - { - wchar_t* wstr = fghWstrFromStr(title); - - window->Window.Handle = CreateWindow( - _T("FREEGLUT"), - wstr, - WS_VISIBLE | WS_POPUP, - 0,0, 240,320, - NULL, - NULL, - fgDisplay.Instance, - (LPVOID) window - ); - - free(wstr); - - SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON); - SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON); - SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR); - MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE); - ShowWindow(window->Window.Handle, SW_SHOW); - UpdateWindow(window->Window.Handle); - } -#else - window->Window.Handle = CreateWindowEx( - exFlags, - _T("FREEGLUT"), - title, - flags, - x, y, w, h, - (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, - (HMENU) NULL, - fgDisplay.Instance, - (LPVOID) window - ); -#endif /* defined(_WIN32_WCE) */ - - if( !( window->Window.Handle ) ) - fgError( "Failed to create a window (%s)!", title ); - -//QB64 -QB64_Window_Handle((void*)window->Window.Handle); - -#if !defined(_WIN32_WCE) - /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */ - SetWindowLong(window->Window.Handle, GWL_STYLE, flags); - SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); -#endif /* defined(_WIN32_WCE) */ - - /* Make a menu window always on top - fix Feature Request 947118 */ - if( window->IsMenu || gameMode ) - SetWindowPos( - window->Window.Handle, - HWND_TOPMOST, - 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE - ); - - /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */ - #ifdef WM_TOUCH - if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF) - fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow"); - if (fghRegisterTouchWindow) - fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM ); - #endif - -#if defined(_WIN32_WCE) - ShowWindow( window->Window.Handle, SW_SHOW ); -#else - ShowWindow( window->Window.Handle, - fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW ); -#endif /* defined(_WIN32_WCE) */ - - UpdateWindow( window->Window.Handle ); - ShowCursor( TRUE ); /* XXX Old comments say "hide cursor"! */ - -#endif - - fgSetWindow( window ); - - window->Window.DoubleBuffered = - ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0; - - if ( ! window->Window.DoubleBuffered ) - { - glDrawBuffer ( GL_FRONT ); - glReadBuffer ( GL_FRONT ); - } -} - -/* - * Closes a window, destroying the frame and OpenGL context - */ -void fgCloseWindow( SFG_Window* window ) -{ - /* if we're in gamemode and we're closing the gamemode window, - * call glutLeaveGameMode first to make sure the gamemode is - * properly closed before closing the window - */ - if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID) - glutLeaveGameMode(); - -#if TARGET_HOST_POSIX_X11 - - if( window->Window.Context ) - glXDestroyContext( fgDisplay.Display, window->Window.Context ); - XFree( window->Window.FBConfig ); - - if( window->Window.Handle ) { - XDestroyWindow( fgDisplay.Display, window->Window.Handle ); - } - /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS - - /* Make sure we don't close a window with current context active */ - if( fgStructure.CurrentWindow == window ) - wglMakeCurrent( NULL, NULL ); - - /* - * Step through the list of windows. If the rendering context - * is not being used by another window, then we delete it. - */ - { - int used = FALSE ; - SFG_Window *iter ; - - for( iter = (SFG_Window *)fgStructure.Windows.First; - iter; - iter = (SFG_Window *)iter->Node.Next ) - { - if( ( iter->Window.Context == window->Window.Context ) && - ( iter != window ) ) - used = TRUE; - } - - if( ! used ) - wglDeleteContext( window->Window.Context ); - } - - DestroyWindow( window->Window.Handle ); -#endif -} - - -/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ - -/* - * Creates a new top-level freeglut window - */ -int FGAPIENTRY glutCreateWindow( const char* title ) -{ - /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the - * XXX application has not already done so. The "freeglut" community - * XXX decided not to go this route (freeglut-developer e-mail from - * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer] - * XXX Desired 'freeglut' behaviour when there is no current window" - */ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" ); - - return fgCreateWindow( NULL, title, fgState.Position.Use, - fgState.Position.X, fgState.Position.Y, - fgState.Size.Use, fgState.Size.X, fgState.Size.Y, - GL_FALSE, GL_FALSE )->ID; -} - -#if TARGET_HOST_MS_WINDOWS -int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) ) -{ - __glutExitFunc = exit_function; - return glutCreateWindow( title ); -} -#endif - -/* - * This function creates a sub window. - */ -int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) -{ - int ret = 0; - SFG_Window* window = NULL; - SFG_Window* parent = NULL; - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" ); - parent = fgWindowByID( parentID ); - freeglut_return_val_if_fail( parent != NULL, 0 ); - if ( x < 0 ) - { - x = parent->State.Width + x ; - if ( w >= 0 ) x -= w ; - } - - if ( w < 0 ) w = parent->State.Width - x + w ; - if ( w < 0 ) - { - x += w ; - w = -w ; - } - - if ( y < 0 ) - { - y = parent->State.Height + y ; - if ( h >= 0 ) y -= h ; - } - - if ( h < 0 ) h = parent->State.Height - y + h ; - if ( h < 0 ) - { - y += h ; - h = -h ; - } - - window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE ); - ret = window->ID; - - return ret; -} - -/* - * Destroys a window and all of its subwindows - */ -void FGAPIENTRY glutDestroyWindow( int windowID ) -{ - SFG_Window* window; - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" ); - window = fgWindowByID( windowID ); - freeglut_return_if_fail( window != NULL ); - { - fgExecutionState ExecState = fgState.ExecState; - fgAddToWindowDestroyList( window ); - fgState.ExecState = ExecState; - } -} - -/* - * This function selects the current window - */ -void FGAPIENTRY glutSetWindow( int ID ) -{ - SFG_Window* window = NULL; - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" ); - if( fgStructure.CurrentWindow != NULL ) - if( fgStructure.CurrentWindow->ID == ID ) - return; - - window = fgWindowByID( ID ); - if( window == NULL ) - { - fgWarning( "glutSetWindow(): window ID %d not found!", ID ); - return; - } - - fgSetWindow( window ); -} - -/* - * This function returns the ID number of the current window, 0 if none exists - */ -int FGAPIENTRY glutGetWindow( void ) -{ - SFG_Window *win = fgStructure.CurrentWindow; - /* - * Since GLUT did not throw an error if this function was called without a prior call to - * "glutInit", this function shouldn't do so here. Instead let us return a zero. - * See Feature Request "[ 1307049 ] glutInit check". - */ - if ( ! fgState.Initialised ) - return 0; - - while ( win && win->IsMenu ) - win = win->Parent; - return win ? win->ID : 0; -} - -/* - * This function makes the current window visible - */ -void FGAPIENTRY glutShowWindow( void ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" ); - -#if TARGET_HOST_POSIX_X11 - - XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS - - ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW ); - -#endif - - fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; -} - -/* - * This function hides the current window - */ -void FGAPIENTRY glutHideWindow( void ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" ); - -#if TARGET_HOST_POSIX_X11 - - if( fgStructure.CurrentWindow->Parent == NULL ) - XWithdrawWindow( fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - fgDisplay.Screen ); - else - XUnmapWindow( fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS - - ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE ); - -#endif - - fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; -} - -/* - * Iconify the current window (top-level windows only) - */ -void FGAPIENTRY glutIconifyWindow( void ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" ); - - fgStructure.CurrentWindow->State.Visible = GL_FALSE; -#if TARGET_HOST_POSIX_X11 - - XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, - fgDisplay.Screen ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS - - ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE ); - -#endif - - fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; -} - -/* - * Set the current window's title - */ -void FGAPIENTRY glutSetWindowTitle( const char* title ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" ); - if( ! fgStructure.CurrentWindow->Parent ) - { -#if TARGET_HOST_POSIX_X11 - - XTextProperty text; - - text.value = (unsigned char *) title; - text.encoding = XA_STRING; - text.format = 8; - text.nitems = strlen( title ); - - XSetWMName( - fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - &text - ); - - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS -# ifdef _WIN32_WCE - { - wchar_t* wstr = fghWstrFromStr(title); - SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); - free(wstr); - } -# else - SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); -# endif - -#endif - } -} - -/* - * Set the current window's iconified title - */ -void FGAPIENTRY glutSetIconTitle( const char* title ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" ); - - if( ! fgStructure.CurrentWindow->Parent ) - { -#if TARGET_HOST_POSIX_X11 - - XTextProperty text; - - text.value = (unsigned char *) title; - text.encoding = XA_STRING; - text.format = 8; - text.nitems = strlen( title ); - - XSetWMIconName( - fgDisplay.Display, - fgStructure.CurrentWindow->Window.Handle, - &text - ); - - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS -# ifdef _WIN32_WCE - { - wchar_t* wstr = fghWstrFromStr(title); - SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); - free(wstr); - } -# else - SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); -# endif - -#endif - } -} - -/* - * Change the current window's size - */ -void FGAPIENTRY glutReshapeWindow( int width, int height ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); - - if (glutGet(GLUT_FULL_SCREEN)) - { - /* Leave full screen state before resizing. */ - glutLeaveFullScreen(); - } - - fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; - fgStructure.CurrentWindow->State.Width = width ; - fgStructure.CurrentWindow->State.Height = height; -} - -/* - * Change the current window's position - */ -void FGAPIENTRY glutPositionWindow( int x, int y ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); - - if (glutGet(GLUT_FULL_SCREEN)) - { - /* Leave full screen state before moving. */ - glutLeaveFullScreen(); - } - -#if TARGET_HOST_POSIX_X11 - - XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, - x, y ); - XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ - -#elif TARGET_HOST_MS_WINDOWS - - { - RECT winRect; - - /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ - GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); - MoveWindow( - fgStructure.CurrentWindow->Window.Handle, - x, - y, - winRect.right - winRect.left, - winRect.bottom - winRect.top, - TRUE - ); - } - -#endif -} - -/* - * Lowers the current window (by Z order change) - */ -void FGAPIENTRY glutPushWindow( void ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" ); - -#if TARGET_HOST_POSIX_X11 - - XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); - -#elif TARGET_HOST_MS_WINDOWS - - SetWindowPos( - fgStructure.CurrentWindow->Window.Handle, - HWND_BOTTOM, - 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE - ); - -#endif -} - -/* - * Raises the current window (by Z order change) - */ -void FGAPIENTRY glutPopWindow( void ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" ); - -#if TARGET_HOST_POSIX_X11 - - XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); - -#elif TARGET_HOST_MS_WINDOWS - - SetWindowPos( - fgStructure.CurrentWindow->Window.Handle, - HWND_TOP, - 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE - ); - -#endif -} - -/* - * Resize the current window so that it fits the whole screen - */ -void FGAPIENTRY glutFullScreen( void ) -{ - SFG_Window *win; - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); - - win = fgStructure.CurrentWindow; - - if (win->Parent) - { - /* Child windows cannot be made fullscreen, consistent with GLUT's behavior - * Also, what would it mean for a child window to be fullscreen, given that it - * is confined to its parent? - */ - fgWarning("glutFullScreen called on a child window, ignoring..."); - return; - } - else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID) - { - /* Ignore fullscreen call on GameMode window, those are always fullscreen already */ - return; - } - -#if TARGET_HOST_POSIX_X11 - if(!glutGet(GLUT_FULL_SCREEN)) { - if(fghToggleFullscreen() != -1) { - win->State.IsFullscreen = GL_TRUE; - } - } - -#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ - - if (glutGet(GLUT_FULL_SCREEN)) - { - /* Leave full screen state before entering fullscreen again (resizing?) */ - glutLeaveFullScreen(); - } - - { -#if(WINVER >= 0x0500) /* Windows 2000 or later */ - DWORD s; - RECT rect; - HMONITOR hMonitor; - MONITORINFO mi; - - /* For fullscreen mode, first remove all window decoration - * and set style to popup so it will overlap the taskbar - * then force to maximize on the screen on which it has the most - * overlap. - */ - - - /* store current window rect */ - GetWindowRect( win->Window.Handle, &win->State.OldRect ); - - /* store current window style */ - win->State.OldStyle = s = GetWindowLong(win->Window.Handle, GWL_STYLE); - - /* remove decorations from style and add popup style*/ - s &= ~((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|(WS_MAXIMIZEBOX*QB64_Resizable())); - s |= WS_POPUP; - SetWindowLong(win->Window.Handle, GWL_STYLE, s); - SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - - /* For fullscreen mode, find the monitor that is covered the most - * by the window and get its rect as the resize target. - */ - hMonitor= MonitorFromRect(&win->State.OldRect, MONITOR_DEFAULTTONEAREST); - mi.cbSize = sizeof(mi); - GetMonitorInfo(hMonitor, &mi); - rect = mi.rcMonitor; -#else /* if (WINVER >= 0x0500) */ - RECT rect; - - /* For fullscreen mode, force the top-left corner to 0,0 - * and adjust the window rectangle so that the client area - * covers the whole screen. - */ - - rect.left = 0; - rect.top = 0; - rect.right = fgDisplay.ScreenWidth; - rect.bottom = fgDisplay.ScreenHeight; - - AdjustWindowRect ( &rect, ((WS_OVERLAPPEDWINDOW*QB64_Resizable())|WS_DLGFRAME|WS_BORDER|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX) | WS_CLIPSIBLINGS | - WS_CLIPCHILDREN, FALSE ); -#endif /* (WINVER >= 0x0500) */ - - /* - * then resize window - * SWP_NOACTIVATE Do not activate the window - * SWP_NOOWNERZORDER Do not change position in z-order - * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message - * SWP_NOZORDER Retains the current Z order (ignore 2nd param) - */ - SetWindowPos( fgStructure.CurrentWindow->Window.Handle, - HWND_TOP, - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | - SWP_NOZORDER - ); - - win->State.IsFullscreen = GL_TRUE; - } -#endif -} - -/* - * If we are fullscreen, resize the current window back to its original size - */ -void FGAPIENTRY glutLeaveFullScreen( void ) -{ - SFG_Window *win; - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); - - win = fgStructure.CurrentWindow; - -#if TARGET_HOST_POSIX_X11 - if(glutGet(GLUT_FULL_SCREEN)) { - if(fghToggleFullscreen() != -1) { - win->State.IsFullscreen = GL_FALSE; - } - } - -#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ - if (!glutGet(GLUT_FULL_SCREEN)) - { - /* nothing to do */ - return; - } - - /* restore style of window before making it fullscreen */ - SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.OldStyle); - SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - - /* Then resize */ - SetWindowPos(win->Window.Handle, - HWND_TOP, - win->State.OldRect.left, - win->State.OldRect.top, - win->State.OldRect.right - win->State.OldRect.left, - win->State.OldRect.bottom - win->State.OldRect.top, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | - SWP_NOZORDER - ); - - win->State.IsFullscreen = GL_FALSE; -#endif -} - -/* - * Toggle the window's full screen state. - */ -void FGAPIENTRY glutFullScreenToggle( void ) -{ - SFG_Window *win; - - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); - - win = fgStructure.CurrentWindow; - -#if TARGET_HOST_POSIX_X11 - if(fghToggleFullscreen() != -1) { - win->State.IsFullscreen = !win->State.IsFullscreen; - } -#elif TARGET_HOST_MS_WINDOWS - if (!win->State.IsFullscreen) - glutFullScreen(); - else - glutLeaveFullScreen(); -#endif -} - -/* - * A.Donev: Set and retrieve the window's user data - */ -void* FGAPIENTRY glutGetWindowData( void ) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" ); - return fgStructure.CurrentWindow->UserData; -} - -void FGAPIENTRY glutSetWindowData(void* data) -{ - FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" ); - FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" ); - fgStructure.CurrentWindow->UserData = data; -} - -/*** END OF FILE ***/ +/* + * freeglut_window.c + * + * Window management methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * 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. + */ + +// QB64-PE: custom code begin +/* +Changed: +WS_OVERLAPPEDWINDOW +...to... +((WS_OVERLAPPEDWINDOW * QB64_Resizable()) | WS_DLGFRAME | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) +*/ +void QB64_Window_Handle(void *handle); +int QB64_Resizable(); +// QB64-PE: custom code end + +#define FREEGLUT_BUILDING_LIB +#include +#include "freeglut_internal.h" + +#if TARGET_HOST_POSIX_X11 +#include /* LONG_MAX */ +#include /* usleep */ +#endif + +#if defined(_WIN32_WCE) +# include +# ifdef FREEGLUT_LIB_PRAGMAS +# pragma comment( lib, "Aygshell.lib" ) +# endif +#endif /* defined(_WIN32_WCE) */ + + +#if TARGET_HOST_POSIX_X11 +#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB +#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2 +#endif + +#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#endif + +#ifndef GLX_CONTEXT_MINOR_VERSION_ARB +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#endif + +#ifndef GLX_CONTEXT_FLAGS_ARB +#define GLX_CONTEXT_FLAGS_ARB 0x2094 +#endif + +#ifndef GLX_CONTEXT_PROFILE_MASK_ARB +#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 +#endif + +#ifndef GLX_CONTEXT_DEBUG_BIT_ARB +#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 +#endif + +#ifndef GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB +#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#endif + +#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB +#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#endif + +#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB +#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#endif + +#ifndef GLX_RGBA_FLOAT_TYPE +#define GLX_RGBA_FLOAT_TYPE 0x20B9 +#endif + +#ifndef GLX_RGBA_FLOAT_BIT +#define GLX_RGBA_FLOAT_BIT 0x00000004 +#endif +#endif /* TARGET_HOST_POSIX_X11 */ + + +#if TARGET_HOST_MS_WINDOWS +/* The following include file is available from SGI but is not standard: + * #include + * So we copy the necessary parts out of it. + * XXX: should local definitions for extensions be put in a separate include file? + */ +typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); + +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_ALPHA_BITS_ARB 0x201B +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 + +#define WGL_SAMPLE_BUFFERS_ARB 0x2041 +#define WGL_SAMPLES_ARB 0x2042 + +#define WGL_TYPE_RGBA_FLOAT_ARB 0x21A0 + +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9 + +#ifndef WGL_ARB_create_context +#define WGL_ARB_create_context 1 +#ifdef WGL_WGLEXT_PROTOTYPES +extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *); +#endif /* WGL_WGLEXT_PROTOTYPES */ +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 + +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 + +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 + +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 +#endif + +#endif /* TARGET_HOST_MS_WINDOWS */ + +#ifdef WM_TOUCH + typedef BOOL (WINAPI *pRegisterTouchWindow)(HWND,ULONG); + static pRegisterTouchWindow fghRegisterTouchWindow = (pRegisterTouchWindow)0xDEADBEEF; +#endif + +/* pushing attribute/value pairs into an array */ +#define ATTRIB(a) attributes[where++]=(a) +#define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);} + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * fgChooseFBConfig() -- OK, but what about glutInitDisplayString()? + * fgSetupPixelFormat -- ignores the display mode settings + * fgOpenWindow() -- check the Win32 version, -iconic handling! + * fgCloseWindow() -- check the Win32 version + * glutCreateWindow() -- Check when default position and size is {-1,-1} + * glutCreateSubWindow() -- Check when default position and size is {-1,-1} + * glutDestroyWindow() -- check the Win32 version + * glutSetWindow() -- check the Win32 version + * glutGetWindow() -- OK + * glutSetWindowTitle() -- check the Win32 version + * glutSetIconTitle() -- check the Win32 version + * glutShowWindow() -- check the Win32 version + * glutHideWindow() -- check the Win32 version + * glutIconifyWindow() -- check the Win32 version + * glutReshapeWindow() -- check the Win32 version + * glutPositionWindow() -- check the Win32 version + * glutPushWindow() -- check the Win32 version + * glutPopWindow() -- check the Win32 version + */ + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + +static int fghIsLegacyContextRequested( void ) +{ + return fgState.MajorVersion < 2 || (fgState.MajorVersion == 2 && fgState.MinorVersion <= 1); +} + +static int fghNumberOfAuxBuffersRequested( void ) +{ + if ( fgState.DisplayMode & GLUT_AUX4 ) { + return 4; + } + if ( fgState.DisplayMode & GLUT_AUX3 ) { + return 3; + } + if ( fgState.DisplayMode & GLUT_AUX2 ) { + return 2; + } + if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */ + return fgState.AuxiliaryBufferNumber; + } + return 0; +} + +static int fghMapBit( int mask, int from, int to ) +{ + return ( mask & from ) ? to : 0; + +} + +static void fghContextCreationError( void ) +{ + fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)", + fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags, + fgState.ContextProfile ); +} + + +/* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */ + +#if TARGET_HOST_POSIX_X11 +/* + * Chooses a visual basing on the current display mode settings + */ + +GLXFBConfig* fgChooseFBConfig( int *numcfgs ) +{ + GLboolean wantIndexedMode = GL_FALSE; + int attributes[ 100 ]; + int where = 0, numAuxBuffers; + + /* First we have to process the display mode settings... */ + if( fgState.DisplayMode & GLUT_INDEX ) { + ATTRIB_VAL( GLX_BUFFER_SIZE, 8 ); + /* Buffer size is selected later. */ + + ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT ); + wantIndexedMode = GL_TRUE; + } else { + ATTRIB_VAL( GLX_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ALPHA_SIZE, 1 ); + } + } + + if( fgState.DisplayMode & GLUT_DOUBLE ) { + ATTRIB_VAL( GLX_DOUBLEBUFFER, True ); + } + + if( fgState.DisplayMode & GLUT_STEREO ) { + ATTRIB_VAL( GLX_STEREO, True ); + } + + if( fgState.DisplayMode & GLUT_DEPTH ) { + ATTRIB_VAL( GLX_DEPTH_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_STENCIL ) { + ATTRIB_VAL( GLX_STENCIL_SIZE, 1 ); + } + + if( fgState.DisplayMode & GLUT_ACCUM ) { + ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 ); + ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 ); + if( fgState.DisplayMode & GLUT_ALPHA ) { + ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 ); + } + } + + numAuxBuffers = fghNumberOfAuxBuffersRequested(); + if ( numAuxBuffers > 0 ) { + ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers ); + } + + if( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True ); + } + + if (fgState.DisplayMode & GLUT_MULTISAMPLE) { + ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1); + ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber); + } + + /* Push a terminator at the end of the list */ + ATTRIB( None ); + + { + GLXFBConfig * fbconfigArray; /* Array of FBConfigs */ + GLXFBConfig * fbconfig; /* The FBConfig we want */ + int fbconfigArraySize; /* Number of FBConfigs in the array */ + + + /* Get all FBConfigs that match "attributes". */ + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + + if (fbconfigArray != NULL) + { + int result; /* Returned by glXGetFBConfigAttrib, not checked. */ + + + if( wantIndexedMode ) + { + /* + * In index mode, we want the largest buffer size, i.e. visual + * depth. Here, FBConfigs are sorted by increasing buffer size + * first, so FBConfigs with the largest size come last. + */ + + int bufferSizeMin, bufferSizeMax; + + /* Get bufferSizeMin. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[0], + GLX_BUFFER_SIZE, + &bufferSizeMin ); + /* Get bufferSizeMax. */ + result = + glXGetFBConfigAttrib( fgDisplay.Display, + fbconfigArray[fbconfigArraySize - 1], + GLX_BUFFER_SIZE, + &bufferSizeMax ); + + if (bufferSizeMax > bufferSizeMin) + { + /* + * Free and reallocate fbconfigArray, keeping only FBConfigs + * with the largest buffer size. + */ + XFree(fbconfigArray); + + /* Add buffer size token at the end of the list. */ + where--; + ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax ); + ATTRIB( None ); + + fbconfigArray = glXChooseFBConfig( fgDisplay.Display, + fgDisplay.Screen, + attributes, + &fbconfigArraySize ); + } + } + + /* + * We now have an array of FBConfigs, the first one being the "best" + * one. So we should return only this FBConfig: + * + * int fbconfigXID; + * + * - pick the XID of the FBConfig we want + * result = glXGetFBConfigAttrib( fgDisplay.Display, + * fbconfigArray[0], + * GLX_FBCONFIG_ID, + * &fbconfigXID ); + * + * - free the array + * XFree(fbconfigArray); + * + * - reset "attributes" with the XID + * where = 0; + * ATTRIB_VAL( GLX_FBCONFIG_ID, fbconfigXID ); + * ATTRIB( None ); + * + * - get our FBConfig only + * fbconfig = glXChooseFBConfig( fgDisplay.Display, + * fgDisplay.Screen, + * attributes, + * &fbconfigArraySize ); + * + * However, for some configurations (for instance multisampling with + * Mesa 6.5.2 and ATI drivers), this does not work: + * glXChooseFBConfig returns NULL, whereas fbconfigXID is a valid + * XID. Further investigation is needed. + * + * So, for now, we return the whole array of FBConfigs. This should + * not produce any side effects elsewhere. + */ + fbconfig = fbconfigArray; + } + else + { + fbconfig = NULL; + } + + if (numcfgs) + *numcfgs = fbconfigArraySize; + + return fbconfig; + } +} + + +static void fghFillContextAttributes( int *attributes ) { + int where = 0, contextFlags, contextProfile; + + ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion ); + ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion ); + + contextFlags = + fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) | + fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB ); + if ( contextFlags != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags ); + } + + contextProfile = + fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) | + fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB ); + if ( contextProfile != 0 ) { + ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile ); + } + + ATTRIB( 0 ); +} + +typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config, + GLXContext share_list, Bool direct, + const int *attrib_list); + +static GLXContext fghCreateNewContext( SFG_Window* window ) +{ + /* for color model calculation */ + int menu = ( window->IsMenu && !fgStructure.MenuContext ); + int index_mode = ( fgState.DisplayMode & GLUT_INDEX ); + + /* "classic" context creation */ + Display *dpy = fgDisplay.Display; + GLXFBConfig config = *(window->Window.FBConfig); + int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE; + GLXContext share_list = NULL; + Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT ); + GLXContext context; + + /* new context creation */ + int attributes[9]; + CreateContextAttribsProc createContextAttribs = (CreateContextAttribsProc) fghGetProcAddress( "glXCreateContextAttribsARB" ); + + /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */ + if ( !createContextAttribs && !fghIsLegacyContextRequested() ) { + fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" ); + fgState.MajorVersion = 2; + fgState.MinorVersion = 1; + } + + /* If nothing fancy has been required, simply use the old context creation GLX API entry */ + if ( fghIsLegacyContextRequested() || !createContextAttribs ) + { + context = glXCreateNewContext( dpy, config, render_type, share_list, direct ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; + } + + /* color index mode is not available anymore with OpenGL 3.0 */ + if ( render_type == GLX_COLOR_INDEX_TYPE ) { + fgWarning( "color index mode is deprecated, using RGBA mode" ); + } + + fghFillContextAttributes( attributes ); + + context = createContextAttribs( dpy, config, share_list, direct, attributes ); + if ( context == NULL ) { + fghContextCreationError(); + } + return context; +} + + +#define _NET_WM_STATE_TOGGLE 2 +static int fghResizeFullscrToggle(void) +{ + XWindowAttributes attributes; + + if(glutGet(GLUT_FULL_SCREEN)) { + /* restore original window size */ + SFG_Window *win = fgStructure.CurrentWindow; + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = win->State.OldWidth; + fgStructure.CurrentWindow->State.Height = win->State.OldHeight; + + } else { + /* resize the window to cover the entire screen */ + XGetWindowAttributes(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &attributes); + + /* + * The "x" and "y" members of "attributes" are the window's coordinates + * relative to its parent, i.e. to the decoration window. + */ + XMoveResizeWindow(fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + -attributes.x, + -attributes.y, + fgDisplay.ScreenWidth, + fgDisplay.ScreenHeight); + } + return 0; +} + +static int fghEwmhFullscrToggle(void) +{ + XEvent xev; + long evmask = SubstructureRedirectMask | SubstructureNotifyMask; + + if(!fgDisplay.State || !fgDisplay.StateFullScreen) { + return -1; + } + + xev.type = ClientMessage; + xev.xclient.window = fgStructure.CurrentWindow->Window.Handle; + xev.xclient.message_type = fgDisplay.State; + xev.xclient.format = 32; + xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; + xev.xclient.data.l[1] = fgDisplay.StateFullScreen; + xev.xclient.data.l[2] = 0; /* no second property to toggle */ + xev.xclient.data.l[3] = 1; /* source indication: application */ + xev.xclient.data.l[4] = 0; /* unused */ + + if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) { + return -1; + } + return 0; +} + +static int fghToggleFullscreen(void) +{ + /* first try the EWMH (_NET_WM_STATE) method ... */ + if(fghEwmhFullscrToggle() != -1) { + return 0; + } + + /* fall back to resizing the window */ + if(fghResizeFullscrToggle() != -1) { + return 0; + } + return -1; +} + + +#endif /* TARGET_HOST_POSIX_X11 */ + + +#if TARGET_HOST_MS_WINDOWS +/* + * Setup the pixel format for a Win32 window + */ + +#if defined(_WIN32_WCE) +static wchar_t* fghWstrFromStr(const char* str) +{ + int i,len=strlen(str); + wchar_t* wstr = (wchar_t*)malloc(2*len+2); + for(i=0; iWindow.Device, window->Window.Context ); + + if ( !fghIsExtensionSupported( window->Window.Device, "WGL_ARB_create_context" ) ) + { + /* wglCreateContextAttribsARB not found, yet the user has requested the new context creation */ + fgWarning( "OpenGL >2.1 context requested but wglCreateContextAttribsARB is not available! Falling back to legacy context creation" ); + /* Legacy context already created at this point in WM_CREATE path of fgPlatformWindowProc, just return */ + return; + } + + /* new context creation */ + fghFillContextAttributes( attributes ); + + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress( "wglCreateContextAttribsARB" ); + if ( wglCreateContextAttribsARB == NULL ) + { + /* wglCreateContextAttribsARB not found, yet the user has requested the new context creation */ + fgWarning( "OpenGL >2.1 context requested but wglCreateContextAttribsARB is not available! Falling back to legacy context creation" ); + /* Legacy context already created at this point in WM_CREATE path of fgPlatformWindowProc, just return */ + return; + } + + context = wglCreateContextAttribsARB( window->Window.Device, 0, attributes ); + if ( context == NULL ) + { + fghContextCreationError(); + } + + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( window->Window.Context ); + window->Window.Context = context; +} + +#if !defined(_WIN32_WCE) + +static void fghFillPFD( PIXELFORMATDESCRIPTOR *ppfd, HDC hdc, unsigned char layer_type ) +{ + int flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + if ( fgState.DisplayMode & GLUT_DOUBLE ) { + flags |= PFD_DOUBLEBUFFER; + } + if ( fgState.DisplayMode & GLUT_STEREO ) { + flags |= PFD_STEREO; + } + +#if defined(_MSC_VER) +#pragma message( "fgSetupPixelFormat(): there is still some work to do here!" ) +#endif + + /* Specify which pixel format do we opt for... */ + ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); + ppfd->nVersion = 1; + ppfd->dwFlags = flags; + + if( fgState.DisplayMode & GLUT_INDEX ) { + ppfd->iPixelType = PFD_TYPE_COLORINDEX; + ppfd->cRedBits = 0; + ppfd->cGreenBits = 0; + ppfd->cBlueBits = 0; + ppfd->cAlphaBits = 0; + } else { + ppfd->iPixelType = PFD_TYPE_RGBA; + ppfd->cRedBits = 8; + ppfd->cGreenBits = 8; + ppfd->cBlueBits = 8; + ppfd->cAlphaBits = ( fgState.DisplayMode & GLUT_ALPHA ) ? 8 : 0; + } + + ppfd->cColorBits = 24; + ppfd->cRedShift = 0; + ppfd->cGreenShift = 0; + ppfd->cBlueShift = 0; + ppfd->cAlphaShift = 0; + ppfd->cAccumBits = ( fgState.DisplayMode & GLUT_ACCUM ) ? 1 : 0; + ppfd->cAccumRedBits = 0; + ppfd->cAccumGreenBits = 0; + ppfd->cAccumBlueBits = 0; + ppfd->cAccumAlphaBits = 0; + + /* Hmmm, or 32/0 instead of 24/8? */ + ppfd->cDepthBits = 24; + ppfd->cStencilBits = 8; + + ppfd->cAuxBuffers = fghNumberOfAuxBuffersRequested(); + ppfd->iLayerType = layer_type; + ppfd->bReserved = 0; + ppfd->dwLayerMask = 0; + ppfd->dwVisibleMask = 0; + ppfd->dwDamageMask = 0; + + ppfd->cColorBits = (BYTE) GetDeviceCaps( hdc, BITSPIXEL ); +} + +static void fghFillPixelFormatAttributes( int *attributes, const PIXELFORMATDESCRIPTOR *ppfd ) +{ + int where = 0; + + ATTRIB_VAL( WGL_DRAW_TO_WINDOW_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SUPPORT_OPENGL_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB ); + + ATTRIB_VAL( WGL_COLOR_BITS_ARB, ppfd->cColorBits ); + ATTRIB_VAL( WGL_ALPHA_BITS_ARB, ppfd->cAlphaBits ); + ATTRIB_VAL( WGL_DEPTH_BITS_ARB, ppfd->cDepthBits ); + ATTRIB_VAL( WGL_STENCIL_BITS_ARB, ppfd->cStencilBits ); + + ATTRIB_VAL( WGL_DOUBLE_BUFFER_ARB, ( fgState.DisplayMode & GLUT_DOUBLE ) != 0 ); + + if ( fgState.DisplayMode & GLUT_SRGB ) { + ATTRIB_VAL( WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, TRUE ); + } + + ATTRIB_VAL( WGL_SAMPLE_BUFFERS_ARB, GL_TRUE ); + ATTRIB_VAL( WGL_SAMPLES_ARB, fgState.SampleNumber ); + ATTRIB( 0 ); +} +#endif + +GLboolean fgSetupPixelFormat( SFG_Window* window, GLboolean checkOnly, + unsigned char layer_type ) +{ +#if defined(_WIN32_WCE) + return GL_TRUE; +#else + PIXELFORMATDESCRIPTOR pfd; + PIXELFORMATDESCRIPTOR* ppfd = &pfd; + int pixelformat; + HDC current_hDC; + GLboolean success; + + if (checkOnly) + current_hDC = CreateDC(TEXT("DISPLAY"), NULL ,NULL ,NULL); + else + current_hDC = window->Window.Device; + + fghFillPFD( ppfd, current_hDC, layer_type ); + pixelformat = ChoosePixelFormat( current_hDC, ppfd ); + + /* windows hack for multismapling/sRGB */ + if ( ( fgState.DisplayMode & GLUT_MULTISAMPLE ) || + ( fgState.DisplayMode & GLUT_SRGB ) ) + { + HGLRC rc, rc_before=wglGetCurrentContext(); + HWND hWnd; + HDC hDC, hDC_before=wglGetCurrentDC(); + WNDCLASS wndCls; + + /* create a dummy window */ + ZeroMemory(&wndCls, sizeof(wndCls)); + wndCls.lpfnWndProc = DefWindowProc; + wndCls.hInstance = fgDisplay.Instance; + wndCls.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wndCls.lpszClassName = _T("FREEGLUT_dummy"); + RegisterClass( &wndCls ); + + // QB64-PE: custom code begin + hWnd = CreateWindow( + _T("FREEGLUT_dummy"), _T(""), + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | + ((WS_OVERLAPPEDWINDOW * QB64_Resizable()) | WS_DLGFRAME | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | (WS_MAXIMIZEBOX * QB64_Resizable())), + 0, 0, 0, 0, 0, 0, fgDisplay.Instance, 0); + // hWnd=CreateWindow(_T("FREEGLUT_dummy"), _T(""), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW , 0,0,0,0, 0, 0, fgDisplay.Instance, 0 ); + // QB64-PE: custom code end + hDC=GetDC(hWnd); + SetPixelFormat( hDC, pixelformat, ppfd ); + + rc = wglCreateContext( hDC ); + wglMakeCurrent(hDC, rc); + + if ( fghIsExtensionSupported( hDC, "WGL_ARB_multisample" ) ) + { + PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARBProc = + (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB"); + if ( wglChoosePixelFormatARBProc ) + { + int attributes[100]; + int iPixelFormat; + BOOL bValid; + float fAttributes[] = { 0, 0 }; + UINT numFormats; + fghFillPixelFormatAttributes( attributes, ppfd ); + bValid = wglChoosePixelFormatARBProc(hDC, attributes, fAttributes, 1, &iPixelFormat, &numFormats); + + if ( bValid && numFormats > 0 ) + { + pixelformat = iPixelFormat; + } + } + } + + wglMakeCurrent( hDC_before, rc_before); + wglDeleteContext(rc); + ReleaseDC(hWnd, hDC); + DestroyWindow(hWnd); + UnregisterClass(_T("FREEGLUT_dummy"), fgDisplay.Instance); + } + + success = ( pixelformat != 0 ) && ( checkOnly || SetPixelFormat( current_hDC, pixelformat, ppfd ) ); + + if (checkOnly) + DeleteDC(current_hDC); + + return success; +#endif /* defined(_WIN32_WCE) */ +} + +#endif /* TARGET_HOST_MS_WINDOWS */ + +/* + * Sets the OpenGL context and the fgStructure "Current Window" pointer to + * the window structure passed in. + */ +void fgSetWindow ( SFG_Window *window ) +{ +#if TARGET_HOST_POSIX_X11 + if ( window ) + { + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + } +#elif TARGET_HOST_MS_WINDOWS + if ( window != fgStructure.CurrentWindow ) + { + if( fgStructure.CurrentWindow ) + ReleaseDC( fgStructure.CurrentWindow->Window.Handle, + fgStructure.CurrentWindow->Window.Device ); + + if ( window ) + { + window->Window.Device = GetDC( window->Window.Handle ); + wglMakeCurrent( + window->Window.Device, + window->Window.Context + ); + } + } +#endif + fgStructure.CurrentWindow = window; +} + +#if TARGET_HOST_MS_WINDOWS + +void fghGetDefaultWindowStyle(DWORD *flags) +{ + if ( fgState.DisplayMode & GLUT_BORDERLESS ) + { + /* no window decorations needed, no-op */ + } + else if ( fgState.DisplayMode & GLUT_CAPTIONLESS ) + /* only window decoration is a border, no title bar or buttons */ + (*flags) |= WS_DLGFRAME; + else + /* window decoration are a border, title bar and buttons. */ + // QB64-PE: custom code begin + (*flags) |= ((WS_OVERLAPPEDWINDOW * QB64_Resizable()) | WS_DLGFRAME | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | (WS_MAXIMIZEBOX * QB64_Resizable())); + //(*flags) |= WS_OVERLAPPEDWINDOW; + // QB64-PE: custom code end +} + +/* Get window style and extended window style of a FreeGLUT window +* If the window pointer or the window handle is NULL, a fully +* decorated window (caption and border) is assumed. +*/ +void fghGetStyleFromWindow( const SFG_Window *window, DWORD *windowStyle, DWORD *windowExStyle ) +{ + if (window && window->Window.Handle) + { + *windowStyle = GetWindowLong(window->Window.Handle, GWL_STYLE); + *windowExStyle = GetWindowLong(window->Window.Handle, GWL_EXSTYLE); + } + else + { + *windowStyle = 0; + fghGetDefaultWindowStyle(windowStyle); + /* WindowExStyle==0 is fine/default, exStyle is currently only used for menu windows */ + *windowExStyle = 0; + } +} + + +/* Computes position of corners of window Rect (outer position including +* decorations) based on the provided client rect and based on the style +* of the window in question. +* If posIsOutside is set to true, the input client Rect is taken to follow +* freeGLUT's window specification convention in which the top-left corner +* is at the outside of the window, while the size +* (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable +* area. +*/ +void fghComputeWindowRectFromClientArea_UseStyle( RECT *clientRect, const DWORD windowStyle, const DWORD windowExStyle, BOOL posIsOutside ) +{ + RECT windowRect = {0,0,0,0}; + CopyRect(&windowRect,clientRect); + + /* Get rect including non-client area */ + AdjustWindowRectEx(&windowRect,windowStyle,FALSE,windowExStyle); + + /* Move window right and down by non-client area extent on left and top, if wanted */ + if (posIsOutside) + { + windowRect.right += clientRect->left-windowRect.left; + windowRect.bottom += clientRect->top -windowRect.top; + windowRect.left = clientRect->left; + windowRect.top = clientRect->top; + } + + /* done, copy windowRect to output */ + CopyRect(clientRect,&windowRect); +} + +/* Computes position of corners of window Rect (outer position including +* decorations) based on the provided client rect and based on the style +* of the window in question. If the window pointer or the window handle +* is NULL, a fully decorated window (caption and border) is assumed. +* Furthermore, if posIsOutside is set to true, the input client Rect is +* taken to follow freeGLUT's window specification convention in which the +* top-left corner is at the outside of the window, while the size +* (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable +* area. +*/ +void fghComputeWindowRectFromClientArea_QueryWindow( RECT *clientRect, const SFG_Window *window, BOOL posIsOutside ) +{ + DWORD windowStyle = 0, windowExStyle = 0; + fghGetStyleFromWindow(window,&windowStyle,&windowExStyle); + + fghComputeWindowRectFromClientArea_UseStyle(clientRect, windowStyle, windowExStyle, posIsOutside); +} + + +/* Gets the rect describing the client area (drawable area) of the +* specified window. Output is position of corners of client area (drawable area) on the screen. +* Returns an empty rect if window pointer or window handle is NULL. +* If wantPosOutside is set to true, the output client Rect +* will follow freeGLUT's window specification convention in which the +* top-left corner is at the outside of the window, while the size +* (rect.right-rect.left,rect.bottom-rect.top) is the size of the drawable +* area. +*/ +void fghGetClientArea( RECT *clientRect, const SFG_Window *window, BOOL wantPosOutside ) +{ + POINT topLeftClient = {0,0}; + POINT topLeftWindow = {0,0}; + + freeglut_return_if_fail((window && window->Window.Handle)); + + /* + * call GetWindowRect() + * (this returns the pixel coordinates of the outside of the window) + * cannot use GetClientRect as it returns a rect relative to + * the top-left point of the client area (.top and .left are thus always 0) + * and is thus only useful for querying the size of the client area, not + * its position. + */ + GetWindowRect( window->Window.Handle, clientRect ); + topLeftWindow.x = clientRect->top; + topLeftWindow.y = clientRect->left; + + /* Get size of client rect */ + GetClientRect(window->Window.Handle, clientRect); + /* Get position of top-left of client area on the screen */ + ClientToScreen(window->Window.Handle,&topLeftClient); + /* Add top-left offset */ + OffsetRect(clientRect,topLeftClient.x,topLeftClient.y); + + /* replace top and left with top and left of window, if wanted */ + if (wantPosOutside) + { + clientRect->left = topLeftWindow.x; + clientRect->top = topLeftWindow.y; + } +} + +#if(WINVER >= 0x500) +typedef struct +{ + int *x; + int *y; + const char *name; +} m_proc_t; + +static BOOL CALLBACK m_proc(HMONITOR mon, + HDC hdc, + LPRECT rect, + LPARAM data) +{ + m_proc_t *dp=(m_proc_t *)data; + MONITORINFOEX info; + BOOL res; + info.cbSize=sizeof(info); + res=GetMonitorInfo(mon,(LPMONITORINFO)&info); + if( res ) + { + if( strcmp(dp->name,info.szDevice)==0 ) + { + *(dp->x)=info.rcMonitor.left; + *(dp->y)=info.rcMonitor.top; + return FALSE; + } + } + return TRUE; +} + +/* + * this function returns the origin of the screen identified by + * fgDisplay.DisplayName, and 0 otherwise. + * This is used in fgOpenWindow to open the gamemode window on the screen + * identified by the -display command line argument. The function should + * not be called otherwise. + */ + +static void get_display_origin(int *xp,int *yp) +{ + *xp = 0; + *yp = 0; + + if( fgDisplay.DisplayName ) + { + m_proc_t st; + st.x=xp; + st.y=yp; + st.name=fgDisplay.DisplayName; + EnumDisplayMonitors(0,0,m_proc,(LPARAM)&st); + } +} +#else +#pragma message( "-display parameter only works if compiled with WINVER >= 0x0500") + +static void get_display_origin(int *xp,int *yp) +{ + *xp = 0; + *yp = 0; + + if( fgDisplay.DisplayName ) + { + fgWarning( "for working -display support FreeGLUT must be compiled with WINVER >= 0x0500"); + } +} +#endif +#endif + + +#if TARGET_HOST_POSIX_X11 +static Bool fghWindowIsVisible( Display *display, XEvent *event, XPointer arg) +{ + Window window = (Window)arg; + return (event->type == MapNotify) && (event->xmap.window == window); +} +#endif + + +/* + * Opens a window. Requires a SFG_Window object created and attached + * to the freeglut structure. OpenGL context is created here. + */ +void fgOpenWindow( SFG_Window* window, const char* title, + GLboolean positionUse, int x, int y, + GLboolean sizeUse, int w, int h, + GLboolean gameMode, GLboolean isSubWindow ) +{ +#if TARGET_HOST_POSIX_X11 + XVisualInfo * visualInfo = NULL; + XSetWindowAttributes winAttr; + XTextProperty textProperty; + XSizeHints sizeHints; + XWMHints wmHints; + XEvent eventReturnBuffer; /* return buffer required for a call */ + unsigned long mask; + int num_FBConfigs, i; + unsigned int current_DisplayMode = fgState.DisplayMode ; + // QB64-PE: custom code begin + // XConfigureEvent fakeEvent = {0}; + // QB64-PE: custom code end + + /* Save the display mode if we are creating a menu window */ + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = GLUT_DOUBLE | GLUT_RGB ; + + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + + if( window->IsMenu && ( ! fgStructure.MenuContext ) ) + fgState.DisplayMode = current_DisplayMode ; + + if( ! window->Window.FBConfig ) + { + /* + * The "fgChooseFBConfig" returned a null meaning that the visual + * context is not available. + * Try a couple of variations to see if they will work. + */ + if( !( fgState.DisplayMode & GLUT_DOUBLE ) ) + { + fgState.DisplayMode |= GLUT_DOUBLE ; + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + fgState.DisplayMode &= ~GLUT_DOUBLE; + } + + if( fgState.DisplayMode & GLUT_MULTISAMPLE ) + { + fgState.DisplayMode &= ~GLUT_MULTISAMPLE ; + window->Window.FBConfig = fgChooseFBConfig( &num_FBConfigs ); + fgState.DisplayMode |= GLUT_MULTISAMPLE; + } + } + + FREEGLUT_INTERNAL_ERROR_EXIT( window->Window.FBConfig != NULL, + "FBConfig with necessary capabilities not found", "fgOpenWindow" ); + + /* Get the X visual. */ + for (i = 0; i < num_FBConfigs; i++) { + visualInfo = glXGetVisualFromFBConfig( fgDisplay.Display, + window->Window.FBConfig[i] ); + if (visualInfo) + break; + } + + FREEGLUT_INTERNAL_ERROR_EXIT( visualInfo != NULL, + "visualInfo could not be retrieved from FBConfig", "fgOpenWindow" ); + + /* + * XXX HINT: the masks should be updated when adding/removing callbacks. + * XXX This might speed up message processing. Is that true? + * XXX + * XXX A: Not appreciably, but it WILL make it easier to debug. + * XXX Try tracing old GLUT and try tracing freeglut. Old GLUT + * XXX turns off events that it doesn't need and is a whole lot + * XXX more pleasant to trace. (Think mouse-motion! Tons of + * XXX ``bonus'' GUI events stream in.) + */ + winAttr.event_mask = + StructureNotifyMask | SubstructureNotifyMask | ExposureMask | + ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | + VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | + PointerMotionMask | ButtonMotionMask; + winAttr.background_pixmap = None; + winAttr.background_pixel = 0; + winAttr.border_pixel = 0; + + winAttr.colormap = XCreateColormap( + fgDisplay.Display, fgDisplay.RootWindow, + visualInfo->visual, AllocNone + ); + + mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; + + if( window->IsMenu || ( gameMode == GL_TRUE ) ) + { + winAttr.override_redirect = True; + mask |= CWOverrideRedirect; + } + + if( ! positionUse ) + x = y = -1; /* default window position */ + if( ! sizeUse ) + w = h = 300; /* default window size */ + + window->Window.Handle = XCreateWindow( + fgDisplay.Display, + window->Parent == NULL ? fgDisplay.RootWindow : + window->Parent->Window.Handle, + x, y, w, h, 0, + visualInfo->depth, InputOutput, + visualInfo->visual, mask, + &winAttr + ); + + // QB64-PE: custom code begin + /* Fake configure event to force viewport setup + * even with no window manager. + */ + /* + fakeEvent.type = ConfigureNotify; + fakeEvent.display = fgDisplay.Display; + fakeEvent.window = window->Window.Handle; + fakeEvent.x = x; + fakeEvent.y = y; + fakeEvent.width = w; + fakeEvent.height = h; + XPutBackEvent(fgDisplay.Display, (XEvent*)&fakeEvent); + */ + // QB64-PE: custom code begin + + /* + * The GLX context creation, possibly trying the direct context rendering + * or else use the current context if the user has so specified + */ + + if( window->IsMenu ) + { + /* + * If there isn't already an OpenGL rendering context for menu + * windows, make one + */ + if( !fgStructure.MenuContext ) + { + fgStructure.MenuContext = + (SFG_MenuContext *)malloc( sizeof(SFG_MenuContext) ); + fgStructure.MenuContext->MContext = fghCreateNewContext( window ); + } + + /* window->Window.Context = fgStructure.MenuContext->MContext; */ + window->Window.Context = fghCreateNewContext( window ); + } + else if( fgState.UseCurrentContext ) + { + window->Window.Context = glXGetCurrentContext( ); + + if( ! window->Window.Context ) + window->Window.Context = fghCreateNewContext( window ); + } + else + window->Window.Context = fghCreateNewContext( window ); + +#if !defined( __FreeBSD__ ) && !defined( __NetBSD__ ) + if( !glXIsDirect( fgDisplay.Display, window->Window.Context ) ) + { + if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT ) + fgError( "Unable to force direct context rendering for window '%s'", + title ); + } +#endif + + /* + * XXX Assume the new window is visible by default + * XXX Is this a safe assumption? + */ + window->State.Visible = GL_TRUE; + + sizeHints.flags = 0; + if ( positionUse ) + sizeHints.flags |= USPosition; + if ( sizeUse ) + sizeHints.flags |= USSize; + + /* + * Fill in the size hints values now (the x, y, width and height + * settings are obsolete, are there any more WMs that support them?) + * Unless the X servers actually stop supporting these, we should + * continue to fill them in. It is *not* our place to tell the user + * that they should replace a window manager that they like, and which + * works, just because *we* think that it's not "modern" enough. + */ + sizeHints.x = x; + sizeHints.y = y; + sizeHints.width = w; + sizeHints.height = h; + + wmHints.flags = StateHint; + wmHints.initial_state = fgState.ForceIconic ? IconicState : NormalState; + /* Prepare the window and iconified window names... */ + XStringListToTextProperty( (char **) &title, 1, &textProperty ); + + XSetWMProperties( + fgDisplay.Display, + window->Window.Handle, + &textProperty, + &textProperty, + 0, + 0, + &sizeHints, + &wmHints, + NULL + ); + XFree( textProperty.value ); + + XSetWMProtocols( fgDisplay.Display, window->Window.Handle, + &fgDisplay.DeleteWindow, 1 ); + + glXMakeContextCurrent( + fgDisplay.Display, + window->Window.Handle, + window->Window.Handle, + window->Window.Context + ); + + /* register extension events _before_ window is mapped */ + #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H + fgRegisterDevices( fgDisplay.Display, &(window->Window.Handle) ); + #endif + + XMapWindow( fgDisplay.Display, window->Window.Handle ); + + XFree(visualInfo); + + if( !isSubWindow) + XPeekIfEvent( fgDisplay.Display, &eventReturnBuffer, &fghWindowIsVisible, (XPointer)(window->Window.Handle) ); + +#elif TARGET_HOST_MS_WINDOWS + + WNDCLASS wc; + DWORD flags = 0; + DWORD exFlags = 0; + ATOM atom; + + /* Grab the window class we have registered on glutInit(): */ + atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc ); + FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Info Not Found", + "fgOpenWindow" ); + + /* Determine window style flags*/ + if( gameMode ) + { + FREEGLUT_INTERNAL_ERROR_EXIT ( window->Parent == NULL, + "Game mode being invoked on a subwindow", + "fgOpenWindow" ); + + /* + * Set the window creation flags appropriately to make the window + * entirely visible: + */ + flags = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + } + else + { + flags = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + + /* + * There's a small difference between creating the top, child and + * menu windows + */ + if ( window->IsMenu ) + { + flags |= WS_POPUP; + exFlags |= WS_EX_TOOLWINDOW; + } +#if defined(_WIN32_WCE) + /* no decorations for windows CE */ +#else + /* if this is not a subwindow (child), set its style based on the requested display mode */ + else if( window->Parent == NULL ) + fghGetDefaultWindowStyle(&flags); +#endif + else + /* subwindows always have no decoration, but are marked as a child window to the OS */ + flags |= WS_CHILD; + } + + /* determine window size and position */ + if( gameMode ) + { + /* if in gamemode, query the origin of specified by the -display + * command line parameter (if any) and offset the upper-left corner + * of the window so we create the window on that screen. + * The -display argument doesn't do anything if not trying to enter + * gamemode. + */ + int xoff=0, yoff=0; + get_display_origin(&xoff,&yoff); + x += xoff; + y += yoff; + } + if( !positionUse ) + { + x = CW_USEDEFAULT; + y = CW_USEDEFAULT; + } + if( !sizeUse ) + { + if( ! window->IsMenu ) + { + w = CW_USEDEFAULT; + h = CW_USEDEFAULT; + } + else /* fail safe - Windows can make a window of size (0, 0) */ + w = h = 300; /* default window size */ + } + /* store requested client area width and height */ + window->State.Width = w; + window->State.Height = h; + +#if !defined(_WIN32_WCE) /* no decorations for windows CE */ + if( sizeUse ) + { + RECT windowRect; + /* + * Update the window dimensions, taking the window decorations + * into account. FreeGLUT is to create the window with the + * topleft outside corner at (x,y) and with client area + * dimensions (w,h). + * note: don't need to do this when w=h=CW_USEDEFAULT, so in the + * if( sizeUse ) here is convenient. + */ + windowRect.left = x; + windowRect.top = y; + windowRect.right = x+w; + windowRect.bottom = y+h; + + fghComputeWindowRectFromClientArea_UseStyle(&windowRect,flags,exFlags,TRUE); + + /* NB: w and h are now width and height of window including non-client area! */ + w = windowRect.right - windowRect.left; + h = windowRect.bottom- windowRect.top; + } +#endif /* !defined(_WIN32_WCE) */ + +#if defined(_WIN32_WCE) + { + wchar_t* wstr = fghWstrFromStr(title); + + window->Window.Handle = CreateWindow( + _T("FREEGLUT"), + wstr, + WS_VISIBLE | WS_POPUP, + 0,0, 240,320, + NULL, + NULL, + fgDisplay.Instance, + (LPVOID) window + ); + + free(wstr); + + SHFullScreen(window->Window.Handle, SHFS_HIDESTARTICON); + SHFullScreen(window->Window.Handle, SHFS_HIDESIPBUTTON); + SHFullScreen(window->Window.Handle, SHFS_HIDETASKBAR); + MoveWindow(window->Window.Handle, 0, 0, 240, 320, TRUE); + ShowWindow(window->Window.Handle, SW_SHOW); + UpdateWindow(window->Window.Handle); + } +#else + window->Window.Handle = CreateWindowEx( + exFlags, + _T("FREEGLUT"), + title, + flags, + x, y, w, h, + (HWND) window->Parent == NULL ? NULL : window->Parent->Window.Handle, + (HMENU) NULL, + fgDisplay.Instance, + (LPVOID) window + ); +#endif /* defined(_WIN32_WCE) */ + + if( !( window->Window.Handle ) ) + fgError( "Failed to create a window (%s)!", title ); + + // QB64-PE: custom code begin + QB64_Window_Handle((void *)window->Window.Handle); + // QB64-PE: custom code end + +#if !defined(_WIN32_WCE) + /* Need to set requested style again, apparently Windows doesn't listen when requesting windows without title bar or borders */ + SetWindowLong(window->Window.Handle, GWL_STYLE, flags); + SetWindowPos(window->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); +#endif /* defined(_WIN32_WCE) */ + + /* Make a menu window always on top - fix Feature Request 947118 */ + if( window->IsMenu || gameMode ) + SetWindowPos( + window->Window.Handle, + HWND_TOPMOST, + 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE + ); + + /* Enable multitouch: additional flag TWF_FINETOUCH, TWF_WANTPALM */ + #ifdef WM_TOUCH + if (fghRegisterTouchWindow == (pRegisterTouchWindow)0xDEADBEEF) + fghRegisterTouchWindow = (pRegisterTouchWindow)GetProcAddress(GetModuleHandle("user32"),"RegisterTouchWindow"); + if (fghRegisterTouchWindow) + fghRegisterTouchWindow( window->Window.Handle, TWF_FINETOUCH | TWF_WANTPALM ); + #endif + +#if defined(_WIN32_WCE) + ShowWindow( window->Window.Handle, SW_SHOW ); +#else + ShowWindow( window->Window.Handle, + fgState.ForceIconic ? SW_SHOWMINIMIZED : SW_SHOW ); +#endif /* defined(_WIN32_WCE) */ + + UpdateWindow( window->Window.Handle ); + ShowCursor( TRUE ); /* XXX Old comments say "hide cursor"! */ + +#endif + + fgSetWindow( window ); + + window->Window.DoubleBuffered = + ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0; + + if ( ! window->Window.DoubleBuffered ) + { + glDrawBuffer ( GL_FRONT ); + glReadBuffer ( GL_FRONT ); + } +} + +/* + * Closes a window, destroying the frame and OpenGL context + */ +void fgCloseWindow( SFG_Window* window ) +{ + /* if we're in gamemode and we're closing the gamemode window, + * call glutLeaveGameMode first to make sure the gamemode is + * properly closed before closing the window + */ + if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID) + glutLeaveGameMode(); + +#if TARGET_HOST_POSIX_X11 + + if( window->Window.Context ) + glXDestroyContext( fgDisplay.Display, window->Window.Context ); + XFree( window->Window.FBConfig ); + + if( window->Window.Handle ) { + XDestroyWindow( fgDisplay.Display, window->Window.Handle ); + } + /* XFlush( fgDisplay.Display ); */ /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + /* Make sure we don't close a window with current context active */ + if( fgStructure.CurrentWindow == window ) + wglMakeCurrent( NULL, NULL ); + + /* + * Step through the list of windows. If the rendering context + * is not being used by another window, then we delete it. + */ + { + int used = FALSE ; + SFG_Window *iter ; + + for( iter = (SFG_Window *)fgStructure.Windows.First; + iter; + iter = (SFG_Window *)iter->Node.Next ) + { + if( ( iter->Window.Context == window->Window.Context ) && + ( iter != window ) ) + used = TRUE; + } + + if( ! used ) + wglDeleteContext( window->Window.Context ); + } + + DestroyWindow( window->Window.Handle ); +#endif +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Creates a new top-level freeglut window + */ +int FGAPIENTRY glutCreateWindow( const char* title ) +{ + /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the + * XXX application has not already done so. The "freeglut" community + * XXX decided not to go this route (freeglut-developer e-mail from + * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer] + * XXX Desired 'freeglut' behaviour when there is no current window" + */ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" ); + + return fgCreateWindow( NULL, title, fgState.Position.Use, + fgState.Position.X, fgState.Position.Y, + fgState.Size.Use, fgState.Size.X, fgState.Size.Y, + GL_FALSE, GL_FALSE )->ID; +} + +#if TARGET_HOST_MS_WINDOWS +int FGAPIENTRY __glutCreateWindowWithExit( const char *title, void (__cdecl *exit_function)(int) ) +{ + __glutExitFunc = exit_function; + return glutCreateWindow( title ); +} +#endif + +/* + * This function creates a sub window. + */ +int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) +{ + int ret = 0; + SFG_Window* window = NULL; + SFG_Window* parent = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" ); + parent = fgWindowByID( parentID ); + freeglut_return_val_if_fail( parent != NULL, 0 ); + if ( x < 0 ) + { + x = parent->State.Width + x ; + if ( w >= 0 ) x -= w ; + } + + if ( w < 0 ) w = parent->State.Width - x + w ; + if ( w < 0 ) + { + x += w ; + w = -w ; + } + + if ( y < 0 ) + { + y = parent->State.Height + y ; + if ( h >= 0 ) y -= h ; + } + + if ( h < 0 ) h = parent->State.Height - y + h ; + if ( h < 0 ) + { + y += h ; + h = -h ; + } + + window = fgCreateWindow( parent, "", GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE ); + ret = window->ID; + + return ret; +} + +/* + * Destroys a window and all of its subwindows + */ +void FGAPIENTRY glutDestroyWindow( int windowID ) +{ + SFG_Window* window; + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" ); + window = fgWindowByID( windowID ); + freeglut_return_if_fail( window != NULL ); + { + fgExecutionState ExecState = fgState.ExecState; + fgAddToWindowDestroyList( window ); + fgState.ExecState = ExecState; + } +} + +/* + * This function selects the current window + */ +void FGAPIENTRY glutSetWindow( int ID ) +{ + SFG_Window* window = NULL; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" ); + if( fgStructure.CurrentWindow != NULL ) + if( fgStructure.CurrentWindow->ID == ID ) + return; + + window = fgWindowByID( ID ); + if( window == NULL ) + { + fgWarning( "glutSetWindow(): window ID %d not found!", ID ); + return; + } + + fgSetWindow( window ); +} + +/* + * This function returns the ID number of the current window, 0 if none exists + */ +int FGAPIENTRY glutGetWindow( void ) +{ + SFG_Window *win = fgStructure.CurrentWindow; + /* + * Since GLUT did not throw an error if this function was called without a prior call to + * "glutInit", this function shouldn't do so here. Instead let us return a zero. + * See Feature Request "[ 1307049 ] glutInit check". + */ + if ( ! fgState.Initialised ) + return 0; + + while ( win && win->IsMenu ) + win = win->Parent; + return win ? win->ID : 0; +} + +/* + * This function makes the current window visible + */ +void FGAPIENTRY glutShowWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XMapWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_SHOW ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; +} + +/* + * This function hides the current window + */ +void FGAPIENTRY glutHideWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" ); + +#if TARGET_HOST_POSIX_X11 + + if( fgStructure.CurrentWindow->Parent == NULL ) + XWithdrawWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + else + XUnmapWindow( fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_HIDE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Iconify the current window (top-level windows only) + */ +void FGAPIENTRY glutIconifyWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" ); + + fgStructure.CurrentWindow->State.Visible = GL_FALSE; +#if TARGET_HOST_POSIX_X11 + + XIconifyWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + fgDisplay.Screen ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + ShowWindow( fgStructure.CurrentWindow->Window.Handle, SW_MINIMIZE ); + +#endif + + fgStructure.CurrentWindow->State.Redisplay = GL_FALSE; +} + +/* + * Set the current window's title + */ +void FGAPIENTRY glutSetWindowTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" ); + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Set the current window's iconified title + */ +void FGAPIENTRY glutSetIconTitle( const char* title ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" ); + + if( ! fgStructure.CurrentWindow->Parent ) + { +#if TARGET_HOST_POSIX_X11 + + XTextProperty text; + + text.value = (unsigned char *) title; + text.encoding = XA_STRING; + text.format = 8; + text.nitems = strlen( title ); + + XSetWMIconName( + fgDisplay.Display, + fgStructure.CurrentWindow->Window.Handle, + &text + ); + + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS +# ifdef _WIN32_WCE + { + wchar_t* wstr = fghWstrFromStr(title); + SetWindowText( fgStructure.CurrentWindow->Window.Handle, wstr ); + free(wstr); + } +# else + SetWindowText( fgStructure.CurrentWindow->Window.Handle, title ); +# endif + +#endif + } +} + +/* + * Change the current window's size + */ +void FGAPIENTRY glutReshapeWindow( int width, int height ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before resizing. */ + glutLeaveFullScreen(); + } + + fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; + fgStructure.CurrentWindow->State.Width = width ; + fgStructure.CurrentWindow->State.Height = height; +} + +/* + * Change the current window's position + */ +void FGAPIENTRY glutPositionWindow( int x, int y ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before moving. */ + glutLeaveFullScreen(); + } + +#if TARGET_HOST_POSIX_X11 + + XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle, + x, y ); + XFlush( fgDisplay.Display ); /* XXX Shouldn't need this */ + +#elif TARGET_HOST_MS_WINDOWS + + { + RECT winRect; + + /* "GetWindowRect" returns the pixel coordinates of the outside of the window */ + GetWindowRect( fgStructure.CurrentWindow->Window.Handle, &winRect ); + MoveWindow( + fgStructure.CurrentWindow->Window.Handle, + x, + y, + winRect.right - winRect.left, + winRect.bottom - winRect.top, + TRUE + ); + } + +#endif +} + +/* + * Lowers the current window (by Z order change) + */ +void FGAPIENTRY glutPushWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XLowerWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_BOTTOM, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +/* + * Raises the current window (by Z order change) + */ +void FGAPIENTRY glutPopWindow( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" ); + +#if TARGET_HOST_POSIX_X11 + + XRaiseWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle ); + +#elif TARGET_HOST_MS_WINDOWS + + SetWindowPos( + fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE + ); + +#endif +} + +/* + * Resize the current window so that it fits the whole screen + */ +void FGAPIENTRY glutFullScreen( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + + win = fgStructure.CurrentWindow; + + if (win->Parent) + { + /* Child windows cannot be made fullscreen, consistent with GLUT's behavior + * Also, what would it mean for a child window to be fullscreen, given that it + * is confined to its parent? + */ + fgWarning("glutFullScreen called on a child window, ignoring..."); + return; + } + else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID) + { + /* Ignore fullscreen call on GameMode window, those are always fullscreen already */ + return; + } + +#if TARGET_HOST_POSIX_X11 + if(!glutGet(GLUT_FULL_SCREEN)) { + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = GL_TRUE; + } + } + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ + + if (glutGet(GLUT_FULL_SCREEN)) + { + /* Leave full screen state before entering fullscreen again (resizing?) */ + glutLeaveFullScreen(); + } + + { +#if(WINVER >= 0x0500) /* Windows 2000 or later */ + DWORD s; + RECT rect; + HMONITOR hMonitor; + MONITORINFO mi; + + /* For fullscreen mode, first remove all window decoration + * and set style to popup so it will overlap the taskbar + * then force to maximize on the screen on which it has the most + * overlap. + */ + + + /* store current window rect */ + GetWindowRect( win->Window.Handle, &win->State.OldRect ); + + /* store current window style */ + win->State.OldStyle = s = GetWindowLong(win->Window.Handle, GWL_STYLE); + + /* remove decorations from style and add popup style*/ + // QB64-PE: custom code begin + s &= ~((WS_OVERLAPPEDWINDOW * QB64_Resizable()) | WS_DLGFRAME | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | (WS_MAXIMIZEBOX * QB64_Resizable())); + // s &= ~WS_OVERLAPPEDWINDOW; + // QB64-PE: custom code end + s |= WS_POPUP; + SetWindowLong(win->Window.Handle, GWL_STYLE, s); + SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + /* For fullscreen mode, find the monitor that is covered the most + * by the window and get its rect as the resize target. + */ + hMonitor= MonitorFromRect(&win->State.OldRect, MONITOR_DEFAULTTONEAREST); + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + rect = mi.rcMonitor; +#else /* if (WINVER >= 0x0500) */ + RECT rect; + + /* For fullscreen mode, force the top-left corner to 0,0 + * and adjust the window rectangle so that the client area + * covers the whole screen. + */ + + rect.left = 0; + rect.top = 0; + rect.right = fgDisplay.ScreenWidth; + rect.bottom = fgDisplay.ScreenHeight; + + // QB64-PE: custom code begin + AdjustWindowRect(&rect, + ((WS_OVERLAPPEDWINDOW * QB64_Resizable()) | WS_DLGFRAME | WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, + FALSE); + // AdjustWindowRect ( &rect, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, FALSE ); + // QB64-PE: custom code end +#endif /* (WINVER >= 0x0500) */ + + /* + * then resize window + * SWP_NOACTIVATE Do not activate the window + * SWP_NOOWNERZORDER Do not change position in z-order + * SWP_NOSENDCHANGING Suppress WM_WINDOWPOSCHANGING message + * SWP_NOZORDER Retains the current Z order (ignore 2nd param) + */ + SetWindowPos( fgStructure.CurrentWindow->Window.Handle, + HWND_TOP, + rect.left, + rect.top, + rect.right - rect.left, + rect.bottom - rect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + + win->State.IsFullscreen = GL_TRUE; + } +#endif +} + +/* + * If we are fullscreen, resize the current window back to its original size + */ +void FGAPIENTRY glutLeaveFullScreen( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(glutGet(GLUT_FULL_SCREEN)) { + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = GL_FALSE; + } + } + +#elif TARGET_HOST_MS_WINDOWS && !defined(_WIN32_WCE) /* FIXME: what about WinCE */ + if (!glutGet(GLUT_FULL_SCREEN)) + { + /* nothing to do */ + return; + } + + /* restore style of window before making it fullscreen */ + SetWindowLong(win->Window.Handle, GWL_STYLE, win->State.OldStyle); + SetWindowPos(win->Window.Handle, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + /* Then resize */ + SetWindowPos(win->Window.Handle, + HWND_TOP, + win->State.OldRect.left, + win->State.OldRect.top, + win->State.OldRect.right - win->State.OldRect.left, + win->State.OldRect.bottom - win->State.OldRect.top, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | + SWP_NOZORDER + ); + + win->State.IsFullscreen = GL_FALSE; +#endif +} + +/* + * Toggle the window's full screen state. + */ +void FGAPIENTRY glutFullScreenToggle( void ) +{ + SFG_Window *win; + + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); + + win = fgStructure.CurrentWindow; + +#if TARGET_HOST_POSIX_X11 + if(fghToggleFullscreen() != -1) { + win->State.IsFullscreen = !win->State.IsFullscreen; + } +#elif TARGET_HOST_MS_WINDOWS + if (!win->State.IsFullscreen) + glutFullScreen(); + else + glutLeaveFullScreen(); +#endif +} + +/* + * A.Donev: Set and retrieve the window's user data + */ +void* FGAPIENTRY glutGetWindowData( void ) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" ); + return fgStructure.CurrentWindow->UserData; +} + +void FGAPIENTRY glutSetWindowData(void* data) +{ + FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" ); + FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" ); + fgStructure.CurrentWindow->UserData = data; +} + +/*** END OF FILE ***/ diff --git a/internal/c/parts/core/freeglut/freeglut_xinput.c b/internal/c/parts/core/freeglut/freeglut_xinput.c index b0d8cc7a7..212dd3513 100644 --- a/internal/c/parts/core/freeglut/freeglut_xinput.c +++ b/internal/c/parts/core/freeglut/freeglut_xinput.c @@ -13,6 +13,9 @@ #include #include +/* convert the XInput button state mask to the regular X mouse event button mask */ +#define BUTTON_MASK(xistate) ((xistate) << 8) + /* import function from freeglut_main.c */ int fghGetXModifiers( int state ); @@ -112,9 +115,9 @@ void fgPrintXIDeviceEvent(XIDeviceEvent* event) printf(" device: %d (%d)\n", event->deviceid, event->sourceid); printf(" detail: %d\n", event->detail); printf(" buttons:"); - for (i = 0; i < event->buttons.mask_len * 8; i++) - if (XIMaskIsSet(event->buttons.mask, i)) - printf(" %d", i); + for (i = 0; i < event->buttons.mask_len * 8; i++) + if (XIMaskIsSet(event->buttons.mask, i)) + printf(" %d", i); printf("\n"); printf(" modifiers: locked 0x%x latched 0x%x base 0x%x\n", @@ -143,76 +146,124 @@ void fgPrintXIDeviceEvent(XIDeviceEvent* event) * \brief This function is called when an Extension Event is received * and calls the corresponding callback functions for these events. */ -void fgHandleExtensionEvents( XEvent* base_ev ) { +void fgHandleExtensionEvents( XEvent* base_ev ) +{ + XEvent std_ev; /* standard single-pointer event to be added to the event queue */ + int i, button = 0; + XGenericEventCookie* cookie = (XGenericEventCookie*)&(base_ev->xcookie); - int i, button = 0; - XGenericEventCookie* cookie = (XGenericEventCookie*)&(base_ev->xcookie); + /* initialize the generic fields from base_ev */ + std_ev.xany = base_ev->xany; if ( XGetEventData( fgDisplay.Display, cookie ) && (cookie->type == GenericEvent) && (cookie->extension == xi_opcode) ) { - XIDeviceEvent* event = (XIDeviceEvent*)(cookie->data); - /*printf("XI2 event type: %d - %d\n", cookie->evtype, event->type );*/ + XIDeviceEvent* event = (XIDeviceEvent*)(cookie->data); + XIEnterEvent *evcross; + /*printf("XI2 event type: %d - %d\n", cookie->evtype, event->type );*/ SFG_Window* window = fgWindowByHandle( event->event ); - if (!window) return; + if (!window) return; - switch (cookie->evtype) { + switch (cookie->evtype) { + case XI_Enter: + case XI_Leave: + evcross = (XIEnterEvent*)event; - case XI_Enter: - case XI_Leave: - fgState.Modifiers = fghGetXModifiers( ((XIEnterEvent*)event)->mods.base ); - INVOKE_WCB( *window, MultiEntry, ( - event->deviceid, - (event->evtype == XI_Enter ? GLUT_ENTERED : GLUT_LEFT) - )); - #if _DEBUG - fgPrintXILeaveEvent((XILeaveEvent*)event); - #endif - break; + fgState.Modifiers = fghGetXModifiers( evcross->mods.base ); + INVOKE_WCB( *window, MultiEntry, ( + event->deviceid, + (event->evtype == XI_Enter ? GLUT_ENTERED : GLUT_LEFT) + )); + #if _DEBUG + fgPrintXILeaveEvent((XILeaveEvent*)event); + #endif - case XI_ButtonPress: - case XI_ButtonRelease: - fgState.Modifiers = fghGetXModifiers( event->mods.base ); - INVOKE_WCB( *window, MultiButton, ( - event->deviceid, - event->event_x, - event->event_y, - (event->detail)-1, - (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP) - )); - INVOKE_WCB( *window, Mouse, ( - (event->detail)-1, - (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP), - event->event_x, - event->event_y - )); - break; + /* Also process the standard crossing event */ + std_ev.type = evcross->evtype == XI_Enter ? EnterNotify : LeaveNotify; + std_ev.xcrossing.window = evcross->event; + std_ev.xcrossing.root = evcross->root; + std_ev.xcrossing.subwindow = evcross->child; + std_ev.xcrossing.x = evcross->event_x; + std_ev.xcrossing.y = evcross->event_y; + std_ev.xcrossing.x_root = evcross->root_x; + std_ev.xcrossing.y_root = evcross->root_y; + std_ev.xcrossing.mode = evcross->mode; + std_ev.xcrossing.detail = evcross->detail; + std_ev.xcrossing.same_screen = evcross->same_screen; + std_ev.xcrossing.focus = evcross->focus; + std_ev.xcrossing.state = BUTTON_MASK(*(unsigned int*)evcross->buttons.mask); - case XI_Motion: - fgState.Modifiers = fghGetXModifiers( event->mods.base ); - for (i = 0; i < event->buttons.mask_len; i++) if (event->buttons.mask[i]) button = 1; - if (button) { - INVOKE_WCB( *window, MultiMotion, ( event->deviceid, event->event_x, event->event_y ) ); - INVOKE_WCB( *window, Motion, ( event->event_x, event->event_y ) ); - } else { - INVOKE_WCB( *window, MultiPassive, ( event->deviceid, event->event_x, event->event_y ) ); - INVOKE_WCB( *window, Passive, ( event->event_x, event->event_y ) ); - } - #if _DEBUG - fgPrintXIDeviceEvent(event); - #endif - break; + XPutBackEvent(fgDisplay.Display, &std_ev); + break; - default: - #if _DEBUG - fgWarning( "Unknown XI2 device event:" ); - fgPrintXIDeviceEvent( event ); - #endif - break; - } - fgState.Modifiers = INVALID_MODIFIERS; - } - XFreeEventData( fgDisplay.Display, cookie ); + case XI_ButtonPress: + case XI_ButtonRelease: + fgState.Modifiers = fghGetXModifiers( event->mods.base ); + INVOKE_WCB( *window, MultiButton, ( + event->deviceid, + event->event_x, + event->event_y, + event->detail-1, + (event->evtype == XI_ButtonPress ? GLUT_DOWN : GLUT_UP) + )); + + /* Also process the standard button event */ + std_ev.type = event->evtype == XI_ButtonPress ? ButtonPress : ButtonRelease; + std_ev.xbutton.window = event->event; + std_ev.xbutton.root = event->root; + std_ev.xbutton.subwindow = event->child; + std_ev.xbutton.x = event->event_x; + std_ev.xbutton.y = event->event_y; + std_ev.xbutton.x_root = event->root_x; + std_ev.xbutton.y_root = event->root_y; + std_ev.xbutton.state = event->mods.base; + std_ev.xbutton.button = event->detail; + + XPutBackEvent(fgDisplay.Display, &std_ev); + break; + + case XI_Motion: + fgState.Modifiers = fghGetXModifiers( event->mods.base ); + for (i = 0; i < event->buttons.mask_len; i++) { + if (event->buttons.mask[i]) { + button = 1; + } + } + if (button) { + INVOKE_WCB( *window, MultiMotion, ( event->deviceid, event->event_x, event->event_y ) ); + } else { + INVOKE_WCB( *window, MultiPassive, ( event->deviceid, event->event_x, event->event_y ) ); + } + #if _DEBUG + fgPrintXIDeviceEvent(event); + #endif + + /* Also process the standard motion event */ + std_ev.type = MotionNotify; + std_ev.xmotion.window = event->event; + std_ev.xmotion.root = event->root; + std_ev.xmotion.subwindow = event->child; + std_ev.xmotion.time = event->time; + std_ev.xmotion.x = event->event_x; + std_ev.xmotion.y = event->event_y; + std_ev.xmotion.x_root = event->root_x; + std_ev.xmotion.y_root = event->root_y; + std_ev.xmotion.state = BUTTON_MASK(*(unsigned int*)event->buttons.mask); + std_ev.xmotion.is_hint = NotifyNormal; + + XPutBackEvent(fgDisplay.Display, &std_ev); + break; + + default: + #if _DEBUG + fgWarning( "Unknown XI2 device event:" ); + fgPrintXIDeviceEvent( event ); + #endif + break; + } + fgState.Modifiers = INVALID_MODIFIERS; + } + XFreeEventData( fgDisplay.Display, cookie ); } #endif diff --git a/internal/c/parts/core/freeglut/include/GL/freeglut_ext.h b/internal/c/parts/core/freeglut/include/GL/freeglut_ext.h index 6bf84b860..e547c56d8 100644 --- a/internal/c/parts/core/freeglut/include/GL/freeglut_ext.h +++ b/internal/c/parts/core/freeglut/include/GL/freeglut_ext.h @@ -74,7 +74,8 @@ #define GLUT_ACTION_ON_WINDOW_CLOSE 0x01F9 #define GLUT_WINDOW_BORDER_WIDTH 0x01FA -#define GLUT_WINDOW_HEADER_HEIGHT 0x01FB +#define GLUT_WINDOW_BORDER_HEIGHT 0x01FB +#define GLUT_WINDOW_HEADER_HEIGHT 0x01FB /* Docs say it should always have been GLUT_WINDOW_BORDER_HEIGHT, keep this for backward compatibility */ #define GLUT_VERSION 0x01FC @@ -83,6 +84,8 @@ #define GLUT_FULL_SCREEN 0x01FF +#define GLUT_SKIP_STALE_MOTION_EVENTS 0x0204 + /* * New tokens for glutInitDisplayMode. * Only one GLUT_AUXn bit may be used at a time. diff --git a/internal/c/parts/core/freeglut/include/GL/freeglut_std.h b/internal/c/parts/core/freeglut/include/GL/freeglut_std.h index cb133863b..691ca7a5f 100644 --- a/internal/c/parts/core/freeglut/include/GL/freeglut_std.h +++ b/internal/c/parts/core/freeglut/include/GL/freeglut_std.h @@ -113,14 +113,21 @@ */ #define FREEGLUT 1 #define GLUT_API_VERSION 4 -#define FREEGLUT_VERSION_2_0 1 #define GLUT_XLIB_IMPLEMENTATION 13 +/* Deprecated: + cf. http://sourceforge.net/mailarchive/forum.php?thread_name=CABcAi1hw7cr4xtigckaGXB5X8wddLfMcbA_rZ3NAuwMrX_zmsw%40mail.gmail.com&forum_name=freeglut-developer */ +#define FREEGLUT_VERSION_2_0 1 /* * Always include OpenGL and GLU headers */ -#include -#include +#if __APPLE__ +# include +# include +#else +# include +# include +#endif /* * GLUT API macro definitions -- the special key codes: @@ -531,6 +538,13 @@ FGAPI void FGAPIENTRY glutSolidTetrahedron( void ); FGAPI void FGAPIENTRY glutWireIcosahedron( void ); FGAPI void FGAPIENTRY glutSolidIcosahedron( void ); +/* + * Teapot rendering functions, found in freeglut_teapot.c + * NB: front facing polygons have clockwise winding, not counter clockwise + */ +FGAPI void FGAPIENTRY glutWireTeapot( GLdouble size ); +FGAPI void FGAPIENTRY glutSolidTeapot( GLdouble size ); + /* * Game mode functions, see freeglut_gamemode.c */