freeglut_gamemode.c
上传用户:gb3593
上传日期:2022-01-07
资源大小:3028k
文件大小:18k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /*
  2.  * freeglut_gamemode.c
  3.  *
  4.  * The game mode handling code.
  5.  *
  6.  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
  7.  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
  8.  * Creation date: Thu Dec 16 1999
  9.  *
  10.  * Permission is hereby granted, free of charge, to any person obtaining a
  11.  * copy of this software and associated documentation files (the "Software"),
  12.  * to deal in the Software without restriction, including without limitation
  13.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  14.  * and/or sell copies of the Software, and to permit persons to whom the
  15.  * Software is furnished to do so, subject to the following conditions:
  16.  *
  17.  * The above copyright notice and this permission notice shall be included
  18.  * in all copies or substantial portions of the Software.
  19.  *
  20.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  21.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  23.  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  24.  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  25.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  */
  27. #include <GL/freeglut.h>
  28. #include "freeglut_internal.h"
  29. /*
  30.  * TODO BEFORE THE STABLE RELEASE:
  31.  *
  32.  *  glutGameModeString()    -- missing
  33.  *  glutEnterGameMode()     -- X11 version
  34.  *  glutLeaveGameMode()     -- is that correct?
  35.  *  glutGameModeGet()       -- is that correct?
  36.  */
  37. /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
  38. /*
  39.  * Remembers the current visual settings, so that
  40.  * we can change them and restore later...
  41.  */
  42. static void fghRememberState( void )
  43. {
  44. #if TARGET_HOST_POSIX_X11
  45.     /*
  46.      * This highly depends on the XFree86 extensions,
  47.      * not approved as X Consortium standards
  48.      */
  49. #   ifdef X_XF86VidModeGetModeLine
  50.     /*
  51.      * Remember the current ViewPort location of the screen to be able to
  52.      * restore the ViewPort on LeaveGameMode():
  53.      */
  54.     if( !XF86VidModeGetViewPort(
  55.              fgDisplay.Display,
  56.              fgDisplay.Screen,
  57.              &fgDisplay.DisplayViewPortX,
  58.              &fgDisplay.DisplayViewPortY ) )
  59.         fgWarning( "XF86VidModeGetViewPort failed" );
  60.     /*
  61.      * Remember the current pointer location before going fullscreen
  62.      * for restoring it later:
  63.      */
  64.     {
  65.         Window junk_window;
  66.         unsigned int mask;
  67.         XQueryPointer(
  68.             fgDisplay.Display, fgDisplay.RootWindow,
  69.             &junk_window, &junk_window,
  70.             &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY,
  71.             &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, &mask
  72.         );
  73.     }
  74.     /* Query the current display settings: */
  75.     fgDisplay.DisplayModeValid =
  76.       XF86VidModeGetModeLine(
  77.         fgDisplay.Display,
  78.         fgDisplay.Screen,
  79.         &fgDisplay.DisplayModeClock,
  80.         &fgDisplay.DisplayMode
  81.     );
  82.     if( !fgDisplay.DisplayModeValid )
  83.             fgWarning( "XF86VidModeGetModeLine failed" );
  84. #   else
  85.     /*
  86.      * XXX warning fghRememberState: missing XFree86 video mode extensions,
  87.      * XXX game mode will not change screen resolution when activated
  88.      */
  89. #   endif
  90. #elif TARGET_HOST_MS_WINDOWS
  91. /*    DEVMODE devMode; */
  92.     /* Grab the current desktop settings... */
  93. /* hack to get around my stupid cross-gcc headers */
  94. #define FREEGLUT_ENUM_CURRENT_SETTINGS -1
  95.     EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS,
  96.                          &fgDisplay.DisplayMode );
  97.     /* Make sure we will be restoring all settings needed */
  98.     fgDisplay.DisplayMode.dmFields |=
  99.         DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
  100. #endif
  101. }
  102. /*
  103.  * Restores the previously remembered visual settings
  104.  */
  105. static void fghRestoreState( void )
  106. {
  107. #if TARGET_HOST_POSIX_X11
  108. #   ifdef X_XF86VidModeGetAllModeLines
  109.     /* Restore the remembered pointer position: */
  110.     XWarpPointer(
  111.         fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0,
  112.         fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY
  113.     );
  114.     /*
  115.      * This highly depends on the XFree86 extensions,
  116.      * not approved as X Consortium standards
  117.      */
  118.     if( fgDisplay.DisplayModeValid )
  119.     {
  120.         XF86VidModeModeInfo** displayModes;
  121.         int i, displayModesCount;
  122.         if( !XF86VidModeGetAllModeLines(
  123.                  fgDisplay.Display,
  124.                  fgDisplay.Screen,
  125.                  &displayModesCount,
  126.                  &displayModes ) )
  127.         {
  128.             fgWarning( "XF86VidModeGetAllModeLines failed" );
  129.             return;
  130.         }
  131.         /*
  132.          * Check every of the modes looking for one that matches our demands.
  133.          * If we find one, switch to it and restore the remembered viewport.
  134.          */
  135.         for( i = 0; i < displayModesCount; i++ )
  136.         {
  137.             if(displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
  138.                displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
  139.                displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
  140.             {
  141.                 if( !XF86VidModeSwitchToMode(
  142.                          fgDisplay.Display,
  143.                          fgDisplay.Screen,
  144.                          displayModes[ i ] ) )
  145.                 {
  146.                     fgWarning( "XF86VidModeSwitchToMode failed" );
  147.                     break;
  148.                 }
  149.                 if( !XF86VidModeSetViewPort(
  150.                          fgDisplay.Display,
  151.                          fgDisplay.Screen,
  152.                          fgDisplay.DisplayViewPortX,
  153.                          fgDisplay.DisplayViewPortY ) )
  154.                     fgWarning( "XF86VidModeSetViewPort failed" );
  155.                 /*
  156.                  * For the case this would be the last X11 call the application
  157.                  * calls exit() we've to flush the X11 output queue to have the
  158.                  * commands sent to the X server before the application exits.
  159.                  */
  160.                 XFlush( fgDisplay.Display );
  161.                 break;
  162.             }
  163.         }
  164.         XFree( displayModes );
  165.     }
  166. #   else
  167.     /*
  168.      * XXX warning fghRestoreState: missing XFree86 video mode extensions,
  169.      * XXX game mode will not change screen resolution when activated
  170.      */
  171. #   endif
  172. #elif TARGET_HOST_MS_WINDOWS
  173.     /* Restore the previously rememebered desktop display settings */
  174.     ChangeDisplaySettings( &fgDisplay.DisplayMode, 0 );
  175. #endif
  176. }
  177. #if TARGET_HOST_POSIX_X11
  178. #ifdef X_XF86VidModeGetAllModeLines
  179. /*
  180.  * Checks a single display mode settings against user's preferences.
  181.  */
  182. static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )
  183. {
  184.     /* The desired values should be stored in fgState structure... */
  185.     return ( width == fgState.GameModeSize.X ) &&
  186.            ( height == fgState.GameModeSize.Y ) &&
  187.            ( depth == fgState.GameModeDepth ) &&
  188.            ( refresh == fgState.GameModeRefresh );
  189. }
  190. /*
  191.  * Checks all display modes settings against user's preferences.
  192.  * Returns the mode number found or -1 if none could be found.
  193.  */
  194. static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes )
  195. {
  196.     int i;
  197.     for( i = 0; i < displayModesCount; i++ )
  198.     {
  199.         /* Compute the displays refresh rate, dotclock comes in kHz. */
  200.         int refresh = ( displayModes[ i ]->dotclock * 1000 ) /
  201.                       ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal );
  202.         if( fghCheckDisplayMode( displayModes[ i ]->hdisplay,
  203.                                  displayModes[ i ]->vdisplay,
  204.                                  fgState.GameModeDepth,
  205.                                  ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) {
  206.             return i;
  207.         }
  208.     }
  209.     return -1;
  210. }
  211. #endif
  212. #endif
  213. /*
  214.  * Changes the current display mode to match user's settings
  215.  */
  216. static GLboolean fghChangeDisplayMode( GLboolean haveToTest )
  217. {
  218.     GLboolean success = GL_FALSE;
  219. #if TARGET_HOST_POSIX_X11
  220.     /*
  221.      * This highly depends on the XFree86 extensions,
  222.      * not approved as X Consortium standards
  223.      */
  224. #   ifdef X_XF86VidModeGetAllModeLines
  225.     /*
  226.      * This is also used by applcations which check modes by calling
  227.      * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
  228.      */
  229.     if( haveToTest || fgDisplay.DisplayModeValid )
  230.     {
  231.         XF86VidModeModeInfo** displayModes;
  232.         int i, displayModesCount;
  233.         if( !XF86VidModeGetAllModeLines(
  234.                  fgDisplay.Display,
  235.                  fgDisplay.Screen,
  236.                  &displayModesCount,
  237.                  &displayModes ) )
  238.         {
  239.             fgWarning( "XF86VidModeGetAllModeLines failed" );
  240.             return success;
  241.         }
  242.         /*
  243.          * Check every of the modes looking for one that matches our demands,
  244.          * ignoring the refresh rate if no exact match could be found.
  245.          */
  246.         i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes );
  247.         if( i < 0 ) {
  248.             i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes );
  249.         }
  250.         success = ( i < 0 ) ? GL_FALSE : GL_TRUE;
  251.         if( !haveToTest && success ) {
  252.             if( !XF86VidModeSwitchToMode(
  253.                      fgDisplay.Display,
  254.                      fgDisplay.Screen,
  255.                      displayModes[ i ] ) )
  256.                 fgWarning( "XF86VidModeSwitchToMode failed" );
  257.         }
  258.         XFree( displayModes );
  259.     }
  260. #   else
  261.     /*
  262.      * XXX warning fghChangeDisplayMode: missing XFree86 video mode extensions,
  263.      * XXX game mode will not change screen resolution when activated
  264.      */
  265.     success = GL_TRUE;
  266. #   endif
  267. #elif TARGET_HOST_MS_WINDOWS
  268.     DEVMODE  devMode;
  269.     char *fggmstr = NULL;
  270.     success = GL_FALSE;
  271.     EnumDisplaySettings( NULL, -1, &devMode ); 
  272.     devMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
  273.     devMode.dmPelsWidth  = fgState.GameModeSize.X;
  274.     devMode.dmPelsHeight = fgState.GameModeSize.Y;
  275.     devMode.dmBitsPerPel = fgState.GameModeDepth;
  276.     devMode.dmDisplayFrequency = fgState.GameModeRefresh;
  277.     devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
  278.     switch ( ChangeDisplaySettingsEx(NULL, &devMode, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) )
  279.     {
  280.     case DISP_CHANGE_SUCCESSFUL:
  281.         success = GL_TRUE;
  282.         /* update vars in case if windows switched to proper mode */
  283.         EnumDisplaySettings( NULL, FREEGLUT_ENUM_CURRENT_SETTINGS, &devMode );
  284.         fgState.GameModeSize.X  = devMode.dmPelsWidth;        
  285.         fgState.GameModeSize.Y  = devMode.dmPelsHeight;
  286.         fgState.GameModeDepth   = devMode.dmBitsPerPel;
  287.         fgState.GameModeRefresh = devMode.dmDisplayFrequency;
  288. break;
  289.     case DISP_CHANGE_RESTART:
  290.         fggmstr = "The computer must be restarted for the graphics mode to work.";
  291.         break;
  292.     case DISP_CHANGE_BADFLAGS:
  293.         fggmstr = "An invalid set of flags was passed in.";
  294.         break;
  295.     case DISP_CHANGE_BADPARAM:
  296.         fggmstr = "An invalid parameter was passed in. This can include an invalid flag or combination of flags.";
  297.         break;
  298.     case DISP_CHANGE_FAILED:
  299.         fggmstr = "The display driver failed the specified graphics mode.";
  300.         break;
  301.     case DISP_CHANGE_BADMODE:
  302.         fggmstr = "The graphics mode is not supported.";
  303.         break;
  304.     default:
  305.         fggmstr = "Unknown error in graphics mode???"; /* dunno if it is possible,MSDN does not mention any other error */
  306.         break;
  307.     }
  308.     if ( !success )
  309.         fgWarning(fggmstr); /* I'd rather get info whats going on in my program than wonder about */
  310.                             /* magic happenings behind my back, its lib for devels at last ;) */
  311. #endif
  312.     return success;
  313. }
  314. /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
  315. /*
  316.  * Sets the game mode display string
  317.  */
  318. void FGAPIENTRY glutGameModeString( const char* string )
  319. {
  320.     int width = 640, height = 480, depth = 16, refresh = 72;
  321.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeString" );
  322.     /*
  323.      * This one seems a bit easier than glutInitDisplayString. The bad thing
  324.      * about it that I was unable to find the game mode string definition, so
  325.      * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which
  326.      * appears in all GLUT game mode programs I have seen to date.
  327.      */
  328.     if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) !=
  329.         4 )
  330.         if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 )
  331.             if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 )
  332.                 if( sscanf( string, "%ix%i", &width, &height ) != 2 )
  333.                     if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 )
  334.                         if( sscanf( string, ":%i", &depth ) != 1 )
  335.                             if( sscanf( string, "@%i", &refresh ) != 1 )
  336.                                 fgWarning(
  337.                                     "unable to parse game mode string `%s'",
  338.                                     string
  339.                                 );
  340.     /* Hopefully it worked, and if not, we still have the default values */
  341.     fgState.GameModeSize.X  = width;
  342.     fgState.GameModeSize.Y  = height;
  343.     fgState.GameModeDepth   = depth;
  344.     fgState.GameModeRefresh = refresh;
  345. }
  346. /*
  347.  * Enters the game mode
  348.  */
  349. int FGAPIENTRY glutEnterGameMode( void )
  350. {
  351.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEnterGameMode" );
  352.     if( fgStructure.GameModeWindow )
  353.         fgAddToWindowDestroyList( fgStructure.GameModeWindow );
  354.     else
  355.         fghRememberState( );
  356.     if( ! fghChangeDisplayMode( GL_FALSE ) )
  357.     {
  358.         fgWarning( "failed to change screen settings" );
  359.         return 0;
  360.     }
  361.     fgStructure.GameModeWindow = fgCreateWindow(
  362.         NULL, "FREEGLUT", GL_TRUE, 0, 0,
  363.         GL_TRUE, fgState.GameModeSize.X, fgState.GameModeSize.Y,
  364.         GL_TRUE, GL_FALSE
  365.     );
  366.     fgStructure.GameModeWindow->State.Width  = fgState.GameModeSize.X;
  367.     fgStructure.GameModeWindow->State.Height = fgState.GameModeSize.Y;
  368.     fgStructure.GameModeWindow->State.NeedToResize = GL_TRUE;
  369. #if TARGET_HOST_POSIX_X11
  370.     /*
  371.      * Sync needed to avoid a real race, the Xserver must have really created
  372.      * the window before we can grab the pointer into it:
  373.      */
  374.     XSync( fgDisplay.Display, False );
  375.     /*
  376.      * Grab the pointer to confine it into the window after the calls to
  377.      * XWrapPointer() which ensure that the pointer really enters the window.
  378.      *
  379.      * We also need to wait here until XGrabPointer() returns GrabSuccess,
  380.      * otherwise the new window is not viewable yet and if the next function
  381.      * (XSetInputFocus) is called with a not yet viewable window, it will exit
  382.      * the application which we have to aviod, so wait until it's viewable:
  383.      */
  384.     while( GrabSuccess != XGrabPointer(
  385.                fgDisplay.Display, fgStructure.GameModeWindow->Window.Handle,
  386.                TRUE,
  387.                ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
  388.                | PointerMotionMask,
  389.                GrabModeAsync, GrabModeAsync,
  390.                fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) )
  391.         usleep( 100 );
  392.     /*
  393.      * Change input focus to the new window. This will exit the application
  394.      * if the new window is not viewable yet, see the XGrabPointer loop above.
  395.      */
  396.     XSetInputFocus(
  397.         fgDisplay.Display,
  398.         fgStructure.GameModeWindow->Window.Handle,
  399.         RevertToNone,
  400.         CurrentTime
  401.     );
  402.     /* Move the Pointer to the middle of the fullscreen window */
  403.     XWarpPointer(
  404.         fgDisplay.Display,
  405.         None,
  406.         fgDisplay.RootWindow,
  407.         0, 0, 0, 0,
  408.         fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2
  409.     );
  410. #   ifdef X_XF86VidModeSetViewPort
  411.     if( fgDisplay.DisplayModeValid )
  412.     {
  413.         int x, y;
  414.         Window child;
  415.         /* Change to viewport to the window topleft edge: */
  416.         if( !XF86VidModeSetViewPort( fgDisplay.Display, fgDisplay.Screen, 0, 0 ) )
  417.             fgWarning( "XF86VidModeSetViewPort failed" );
  418.         /*
  419.          * Final window repositioning: It could be avoided using an undecorated
  420.          * window using override_redirect, but this * would possily require
  421.          * more changes and investigation.
  422.          */
  423.         /* Get the current postion of the drawable area on screen */
  424.         XTranslateCoordinates(
  425.             fgDisplay.Display,
  426.             fgStructure.CurrentWindow->Window.Handle,
  427.             fgDisplay.RootWindow,
  428.             0, 0, &x, &y,
  429.             &child
  430.         );
  431.         /* Move the decorataions out of the topleft corner of the display */
  432.         XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
  433.                      -x, -y);
  434.     }
  435. #endif
  436.     /* Grab the keyboard, too */
  437.     XGrabKeyboard(
  438.         fgDisplay.Display,
  439.         fgStructure.GameModeWindow->Window.Handle,
  440.         FALSE,
  441.         GrabModeAsync, GrabModeAsync,
  442.         CurrentTime
  443.     );
  444. #endif
  445.     return fgStructure.GameModeWindow->ID;
  446. }
  447. /*
  448.  * Leaves the game mode
  449.  */
  450. void FGAPIENTRY glutLeaveGameMode( void )
  451. {
  452.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveGameMode" );
  453.     freeglut_return_if_fail( fgStructure.GameModeWindow );
  454.     fgAddToWindowDestroyList( fgStructure.GameModeWindow );
  455.     fgStructure.GameModeWindow = NULL;
  456. #if TARGET_HOST_POSIX_X11
  457.     XUngrabPointer( fgDisplay.Display, CurrentTime );
  458.     XUngrabKeyboard( fgDisplay.Display, CurrentTime );
  459. #endif
  460.     fghRestoreState();
  461. }
  462. /*
  463.  * Returns information concerning the freeglut game mode
  464.  */
  465. int FGAPIENTRY glutGameModeGet( GLenum eWhat )
  466. {
  467.     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeGet" );
  468.     switch( eWhat )
  469.     {
  470.     case GLUT_GAME_MODE_ACTIVE:
  471.         return !!fgStructure.GameModeWindow;
  472.     case GLUT_GAME_MODE_POSSIBLE:
  473.         return fghChangeDisplayMode( GL_TRUE );
  474.     case GLUT_GAME_MODE_WIDTH:
  475.         return fgState.GameModeSize.X;
  476.     case GLUT_GAME_MODE_HEIGHT:
  477.         return fgState.GameModeSize.Y;
  478.     case GLUT_GAME_MODE_PIXEL_DEPTH:
  479.         return fgState.GameModeDepth;
  480.     case GLUT_GAME_MODE_REFRESH_RATE:
  481.         return fgState.GameModeRefresh;
  482.     case GLUT_GAME_MODE_DISPLAY_CHANGED:
  483.         /*
  484.          * This is true if the game mode has been activated successfully..
  485.          */
  486.         return !!fgStructure.GameModeWindow;
  487.     }
  488.     fgWarning( "Unknown gamemode get: %d", eWhat );
  489.     return -1;
  490. }
  491. /*** END OF FILE ***/