glut_gamemode.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:17k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /* Copyright (c) Mark J. Kilgard, 1998. */
  2. /* This program is freely distributable without licensing fees 
  3.    and is provided without guarantee or warrantee expressed or 
  4.    implied. This program is -not- in the public domain. */
  5. #include <assert.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include "glutint.h"
  10. #ifndef _WIN32
  11. #include <X11/Xlib.h>
  12. #include <X11/Xatom.h>
  13. /* SGI optimization introduced in IRIX 6.3 to avoid X server
  14.    round trips for interning common X atoms. */
  15. #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
  16. #include <X11/SGIFastAtom.h>
  17. #else
  18. #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
  19. #endif
  20. #endif  /* not _WIN32 */
  21. int __glutDisplaySettingsChanged = 0;
  22. static DisplayMode *dmodes, *currentDm = NULL;
  23. static int ndmodes = -1;
  24. GLUTwindow *__glutGameModeWindow = NULL;
  25.     
  26. #ifdef TEST
  27. static char *compstr[] =
  28. {
  29.   "none", "=", "!=", "<=", ">=", ">", "<", "~"
  30. };
  31. static char *capstr[] =
  32. {
  33.   "width", "height", "bpp", "hertz", "num"
  34. };
  35. #endif
  36. void
  37. __glutCloseDownGameMode(void)
  38. {
  39.   if (__glutDisplaySettingsChanged) {
  40. #ifdef _WIN32
  41.     /* Assumes that display settings have been changed, that
  42.        is __glutDisplaySettingsChanged is true. */
  43.     ChangeDisplaySettings(NULL, 0);
  44. #endif
  45.     __glutDisplaySettingsChanged = 0;
  46.   }
  47.   __glutGameModeWindow = NULL;
  48. }
  49. void APIENTRY
  50. glutLeaveGameMode(void)
  51. {
  52.   if (__glutGameModeWindow == NULL) {
  53.     __glutWarning("not in game mode so cannot leave game mode");
  54.     return;
  55.   }
  56.   __glutDestroyWindow(__glutGameModeWindow,
  57.     __glutGameModeWindow);
  58.   XFlush(__glutDisplay);
  59.   __glutGameModeWindow = NULL;
  60. }
  61. #ifdef _WIN32
  62. /* Same values as from MSDN's SetDisp.c example. */
  63. #define MIN_WIDTH 400
  64. #define MIN_FREQUENCY 60
  65. static void
  66. initGameModeSupport(void)
  67. {
  68.   DEVMODE dm;
  69.   DWORD mode;
  70.   int i;
  71.   if (ndmodes >= 0) {
  72.     /* ndmodes is initially -1 to indicate no
  73.        dmodes allocated yet. */
  74.     return;
  75.   }
  76.   /* Determine how many display modes there are. */
  77.   ndmodes = 0;
  78.   mode = 0;
  79.   while (EnumDisplaySettings(NULL, mode, &dm)) {
  80.     if (dm.dmPelsWidth >= MIN_WIDTH &&
  81.       (dm.dmDisplayFrequency == 0 ||
  82.       dm.dmDisplayFrequency >= MIN_FREQUENCY)) {
  83.       ndmodes++;
  84.     }
  85.     mode++;
  86.   }
  87.   /* Allocate memory for a list of all the display modes. */
  88.   dmodes = (DisplayMode*)
  89.     malloc(ndmodes * sizeof(DisplayMode));
  90.   /* Now that we know how many display modes to expect,
  91.      enumerate them again and save the information in
  92.      the list we allocated above. */
  93.   i = 0;
  94.   mode = 0;
  95.   while (EnumDisplaySettings(NULL, mode, &dm)) {
  96.     /* Try to reject any display settings that seem unplausible. */
  97.     if (dm.dmPelsWidth >= MIN_WIDTH &&
  98.       (dm.dmDisplayFrequency == 0 ||
  99.       dm.dmDisplayFrequency >= MIN_FREQUENCY)) {
  100.       dmodes[i].devmode = dm;
  101.       dmodes[i].valid = 1;  /* XXX Not used for now. */
  102.       dmodes[i].cap[DM_WIDTH] = dm.dmPelsWidth;
  103.       dmodes[i].cap[DM_HEIGHT] = dm.dmPelsHeight;
  104.       dmodes[i].cap[DM_PIXEL_DEPTH] = dm.dmBitsPerPel;
  105.       if (dm.dmDisplayFrequency == 0) {
  106.   /* Guess a reasonable guess. */
  107. /* Lame Windows 95 version of EnumDisplaySettings. */
  108.         dmodes[i].cap[DM_HERTZ] = 60;
  109.       } else {
  110. dmodes[i].cap[DM_HERTZ] = dm.dmDisplayFrequency;
  111.       }
  112.       i++;
  113.     }
  114.     mode++;
  115.   }
  116.   assert(i == ndmodes);
  117. }
  118. #else
  119. /* X Windows version of initGameModeSupport. */
  120. static void
  121. initGameModeSupport(void)
  122. {
  123.   if (ndmodes >= 0) {
  124.     /* ndmodes is initially -1 to indicate no
  125.        dmodes allocated yet. */
  126.     return;
  127.   }
  128.   /* Determine how many display modes there are. */
  129.   ndmodes = 0;
  130. }
  131. #endif
  132. /* This routine is based on similiar code in glut_dstr.c */
  133. static DisplayMode *
  134. findMatch(DisplayMode * dmodes, int ndmodes,
  135.   Criterion * criteria, int ncriteria)
  136. {
  137.   DisplayMode *found;
  138.   int *bestScore, *thisScore;
  139.   int i, j, numok, result, worse, better;
  140.   found = NULL;
  141.   numok = 1;            /* "num" capability is indexed from 1,
  142.                            not 0. */
  143.   /* XXX alloca canidate. */
  144.   bestScore = (int *) malloc(ncriteria * sizeof(int));
  145.   if (!bestScore) {
  146.     __glutFatalError("out of memory.");
  147.   }
  148.   for (j = 0; j < ncriteria; j++) {
  149.     /* Very negative number. */
  150.     bestScore[j] = -32768;
  151.   }
  152.   /* XXX alloca canidate. */
  153.   thisScore = (int *) malloc(ncriteria * sizeof(int));
  154.   if (!thisScore) {
  155.     __glutFatalError("out of memory.");
  156.   }
  157.   for (i = 0; i < ndmodes; i++) {
  158.     if (dmodes[i].valid) {
  159.       worse = 0;
  160.       better = 0;
  161.       for (j = 0; j < ncriteria; j++) {
  162.         int cap, cvalue, dvalue;
  163.         cap = criteria[j].capability;
  164.         cvalue = criteria[j].value;
  165.         if (cap == NUM) {
  166.           dvalue = numok;
  167.         } else {
  168.           dvalue = dmodes[i].cap[cap];
  169.         }
  170. #ifdef TEST
  171.         if (verbose)
  172.           printf("  %s %s %d to %dn",
  173.             capstr[cap], compstr[criteria[j].comparison], cvalue, dvalue);
  174. #endif
  175.         switch (criteria[j].comparison) {
  176.         case EQ:
  177.           result = cvalue == dvalue;
  178.           thisScore[j] = 1;
  179.           break;
  180.         case NEQ:
  181.           result = cvalue != dvalue;
  182.           thisScore[j] = 1;
  183.           break;
  184.         case LT:
  185.           result = dvalue < cvalue;
  186.           thisScore[j] = dvalue - cvalue;
  187.           break;
  188.         case GT:
  189.           result = dvalue > cvalue;
  190.           thisScore[j] = dvalue - cvalue;
  191.           break;
  192.         case LTE:
  193.           result = dvalue <= cvalue;
  194.           thisScore[j] = dvalue - cvalue;
  195.           break;
  196.         case GTE:
  197.           result = (dvalue >= cvalue);
  198.           thisScore[j] = dvalue - cvalue;
  199.           break;
  200.         case MIN:
  201.           result = dvalue >= cvalue;
  202.           thisScore[j] = cvalue - dvalue;
  203.           break;
  204.         }
  205. #ifdef TEST
  206.         if (verbose)
  207.           printf("                result=%d   score=%d   bestScore=%dn", result, thisScore[j], bestScore[j]);
  208. #endif
  209.         if (result) {
  210.           if (better || thisScore[j] > bestScore[j]) {
  211.             better = 1;
  212.           } else if (thisScore[j] == bestScore[j]) {
  213.             /* Keep looking. */
  214.           } else {
  215.             goto nextDM;
  216.           }
  217.         } else {
  218.           if (cap == NUM) {
  219.             worse = 1;
  220.           } else {
  221.             goto nextDM;
  222.           }
  223.         }
  224.       }
  225.       if (better && !worse) {
  226.         found = &dmodes[i];
  227.         for (j = 0; j < ncriteria; j++) {
  228.           bestScore[j] = thisScore[j];
  229.         }
  230.       }
  231.       numok++;
  232.     nextDM:;
  233.     }
  234.   }
  235.   free(bestScore);
  236.   free(thisScore);
  237.   return found;
  238. }
  239. /**
  240.  * Parses strings in the form of:
  241.  *  800x600
  242.  *  800x600:16
  243.  *  800x600@60
  244.  *  800x600:16@60
  245.  *  @60
  246.  *  :16
  247.  *  :16@60
  248.  * NOTE that @ before : is not parsed.
  249.  */
  250. static int
  251. specialCaseParse(char *word, Criterion * criterion, int mask)
  252. {
  253.   char *xstr, *response;
  254.   int got;
  255.   int width, height, bpp, hertz;
  256.   switch(word[0]) {
  257.   case '0':
  258.   case '1':
  259.   case '2':
  260.   case '3':
  261.   case '4':
  262.   case '5':
  263.   case '6':
  264.   case '7':
  265.   case '8':
  266.   case '9':
  267.     /* The WWWxHHH case. */
  268.     if (mask & (1 << DM_WIDTH)) {
  269.       return -1;
  270.     }
  271.     xstr = strpbrk(&word[1], "x");
  272.     if (xstr) {
  273.       width = (int) strtol(word, &response, 0);
  274.       if (response == word || response[0] != 'x') {
  275.         /* Not a valid number OR needs to be followed by 'x'. */
  276. return -1;
  277.       }
  278.       height = (int) strtol(&xstr[1], &response, 0);
  279.       if (response == &xstr[1]) {
  280.         /* Not a valid number. */
  281. return -1;
  282.       }
  283.       criterion[0].capability = DM_WIDTH;
  284.       criterion[0].comparison = EQ;
  285.       criterion[0].value = width;
  286.       criterion[1].capability = DM_HEIGHT;
  287.       criterion[1].comparison = EQ;
  288.       criterion[1].value = height;
  289.       got = specialCaseParse(response,
  290.         &criterion[2], 1 << DM_WIDTH);
  291.       if (got >= 0) {
  292.         return got + 2;
  293.       } else {
  294.         return -1;
  295.       }
  296.     }
  297.     return -1;
  298.   case ':':
  299.     /* The :BPP case. */
  300.     if (mask & (1 << DM_PIXEL_DEPTH)) {
  301.       return -1;
  302.     }
  303.     bpp = (int) strtol(&word[1], &response, 0);
  304.     if (response == &word[1]) {
  305.       /* Not a valid number. */
  306.       return -1;
  307.     }
  308.     criterion[0].capability = DM_PIXEL_DEPTH;
  309.     criterion[0].comparison = EQ;
  310.     criterion[0].value = bpp;
  311.     got = specialCaseParse(response,
  312.       &criterion[1], (1 << DM_WIDTH) | (1 << DM_PIXEL_DEPTH));
  313.     if (got >= 0) {
  314.       return got + 1;
  315.     } else {
  316.       return -1;
  317.     }
  318.   case '@':
  319.     /* The @HZ case. */
  320.     if (mask & (1 << DM_HERTZ)) {
  321.       return -1;
  322.     }
  323.     hertz = (int) strtol(&word[1], &response, 0);
  324.     if (response == &word[1]) {
  325.       /* Not a valid number. */
  326.       return -1;
  327.     }
  328.     criterion[0].capability = DM_HERTZ;
  329.     criterion[0].comparison = EQ;
  330.     criterion[0].value = hertz;
  331.     got = specialCaseParse(response,
  332.       &criterion[1], ~DM_HERTZ);
  333.     if (got >= 0) {
  334.       return got + 1;
  335.     } else {
  336.       return -1;
  337.     }
  338.   case '':
  339.     return 0;
  340.   }
  341.   return -1;
  342. }
  343. /* This routine is based on similiar code in glut_dstr.c */
  344. static int
  345. parseCriteria(char *word, Criterion * criterion)
  346. {
  347.   char *cstr, *vstr, *response;
  348.   int comparator, value;
  349.   cstr = strpbrk(word, "=><!~");
  350.   if (cstr) {
  351.     switch (cstr[0]) {
  352.     case '=':
  353.       comparator = EQ;
  354.       vstr = &cstr[1];
  355.       break;
  356.     case '~':
  357.       comparator = MIN;
  358.       vstr = &cstr[1];
  359.       break;
  360.     case '>':
  361.       if (cstr[1] == '=') {
  362.         comparator = GTE;
  363.         vstr = &cstr[2];
  364.       } else {
  365.         comparator = GT;
  366.         vstr = &cstr[1];
  367.       }
  368.       break;
  369.     case '<':
  370.       if (cstr[1] == '=') {
  371.         comparator = LTE;
  372.         vstr = &cstr[2];
  373.       } else {
  374.         comparator = LT;
  375.         vstr = &cstr[1];
  376.       }
  377.       break;
  378.     case '!':
  379.       if (cstr[1] == '=') {
  380.         comparator = NEQ;
  381.         vstr = &cstr[2];
  382.       } else {
  383.         return -1;
  384.       }
  385.       break;
  386.     default:
  387.       return -1;
  388.     }
  389.     value = (int) strtol(vstr, &response, 0);
  390.     if (response == vstr) {
  391.       /* Not a valid number. */
  392.       return -1;
  393.     }
  394.     *cstr = '';
  395.   } else {
  396.     comparator = NONE;
  397.   }
  398.   switch (word[0]) {
  399.   case 'b':
  400.     if (!strcmp(word, "bpp")) {
  401.       criterion[0].capability = DM_PIXEL_DEPTH;
  402.       if (comparator == NONE) {
  403.         return -1;
  404.       } else {
  405.         criterion[0].comparison = comparator;
  406.         criterion[0].value = value;
  407.         return 1;
  408.       }
  409.     }
  410.     return -1;
  411.   case 'h':
  412.     if (!strcmp(word, "height")) {
  413.       criterion[0].capability = DM_HEIGHT;
  414.       if (comparator == NONE) {
  415.         return -1;
  416.       } else {
  417.         criterion[0].comparison = comparator;
  418.         criterion[0].value = value;
  419.         return 1;
  420.       }
  421.     }
  422.     if (!strcmp(word, "hertz")) {
  423.       criterion[0].capability = DM_HERTZ;
  424.       if (comparator == NONE) {
  425.         return -1;
  426.       } else {
  427.         criterion[0].comparison = comparator;
  428.         criterion[0].value = value;
  429.         return 1;
  430.       }
  431.     }
  432.     return -1;
  433.   case 'n':
  434.     if (!strcmp(word, "num")) {
  435.       criterion[0].capability = DM_NUM;
  436.       if (comparator == NONE) {
  437.         return -1;
  438.       } else {
  439.         criterion[0].comparison = comparator;
  440.         criterion[0].value = value;
  441.         return 1;
  442.       }
  443.     }
  444.     return -1;
  445.   case 'w':
  446.     if (!strcmp(word, "width")) {
  447.       criterion[0].capability = DM_WIDTH;
  448.       if (comparator == NONE) {
  449.         return -1;
  450.       } else {
  451.         criterion[0].comparison = comparator;
  452.         criterion[0].value = value;
  453.         return 1;
  454.       }
  455.     }
  456.     return -1;
  457.   }
  458.   if (comparator == NONE) {
  459.     return specialCaseParse(word, criterion, 0);
  460.   }
  461.   return -1;
  462. }
  463. /* This routine is based on similiar code in glut_dstr.c */
  464. static Criterion *
  465. parseDisplayString(const char *display, int *ncriteria)
  466. {
  467.   Criterion *criteria = NULL;
  468.   int n, parsed;
  469.   char *copy, *word;
  470.   copy = __glutStrdup(display);
  471.   /* Attempt to estimate how many criteria entries should be
  472.      needed. */
  473.   n = 0;
  474.   word = strtok(copy, " t");
  475.   while (word) {
  476.     n++;
  477.     word = strtok(NULL, " t");
  478.   }
  479.   /* Allocate number of words of criteria.  A word
  480.      could contain as many as four criteria in the
  481.      worst case.  Example: 800x600:16@60 */
  482.   criteria = (Criterion *) malloc(4 * n * sizeof(Criterion));
  483.   if (!criteria) {
  484.     __glutFatalError("out of memory.");
  485.   }
  486.   /* Re-copy the copy of the display string. */
  487.   strcpy(copy, display);
  488.   n = 0;
  489.   word = strtok(copy, " t");
  490.   while (word) {
  491.     parsed = parseCriteria(word, &criteria[n]);
  492.     if (parsed >= 0) {
  493.       n += parsed;
  494.     } else {
  495.       __glutWarning("Unrecognized game mode string word: %s (ignoring)n", word);
  496.     }
  497.     word = strtok(NULL, " t");
  498.   }
  499.   free(copy);
  500.   *ncriteria = n;
  501.   return criteria;
  502. }
  503. void APIENTRY
  504. glutGameModeString(const char *string)
  505. {
  506.   Criterion *criteria;
  507.   int ncriteria;
  508.   initGameModeSupport();
  509.   criteria = parseDisplayString(string, &ncriteria);
  510.   currentDm = findMatch(dmodes, ndmodes, criteria, ncriteria);
  511.   free(criteria);
  512. }
  513. int APIENTRY
  514. glutEnterGameMode(void)
  515. {
  516.   GLUTwindow *window;
  517.   int width, height;
  518.   Window win;
  519.   if (__glutMappedMenu) {
  520.     __glutFatalUsage("entering game mode not allowed while menus in use");
  521.   }
  522.   if (__glutGameModeWindow) {
  523.     /* Already in game mode, so blow away game mode
  524.        window so apps can change resolutions. */
  525.     window = __glutGameModeWindow;
  526.     /* Setting the game mode window to NULL tricks
  527.        the window destroy code into not undoing the
  528.        screen display change since we plan on immediately
  529.        doing another mode change. */
  530.     __glutGameModeWindow = NULL;
  531.     __glutDestroyWindow(window, window);
  532.   }
  533.   /* Assume default screen size until we find out if we
  534.      can actually change the display settings. */
  535.   width = __glutScreenWidth;
  536.   height = __glutScreenHeight;
  537.   if (currentDm) {
  538. #ifdef _WIN32
  539.     LONG status;
  540.     static int registered = 0;
  541.     status = ChangeDisplaySettings(&currentDm->devmode,
  542.       CDS_FULLSCREEN);
  543.     if (status == DISP_CHANGE_SUCCESSFUL) {
  544.       __glutDisplaySettingsChanged = 1;
  545.       width = currentDm->cap[DM_WIDTH];
  546.       height = currentDm->cap[DM_HEIGHT];
  547.       if (!registered) {
  548.         atexit(__glutCloseDownGameMode);
  549.         registered = 1;
  550.       }
  551.     } else {
  552.       /* Switch back to default resolution. */
  553.       ChangeDisplaySettings(NULL, 0);
  554.     }
  555. #endif
  556.   }
  557.   window = __glutCreateWindow(NULL, 0, 0,
  558.     width, height, /* game mode */ 1);
  559.   win = window->win;
  560. #if !defined(_WIN32)
  561.   if (__glutMotifHints == None) {
  562.     __glutMotifHints = XSGIFastInternAtom(__glutDisplay, "_MOTIF_WM_HINTS",
  563.       SGI_XA__MOTIF_WM_HINTS, 0);
  564.     if (__glutMotifHints == None) {
  565.       __glutWarning("Could not intern X atom for _MOTIF_WM_HINTS.");
  566.     }
  567.   }
  568.   /* Game mode window is a toplevel window. */
  569.   XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
  570. #endif
  571.   /* Schedule the fullscreen property to be added and to
  572.      make sure the window is configured right.  Win32
  573.      doesn't need this. */
  574.   window->desiredX = 0;
  575.   window->desiredY = 0;
  576.   window->desiredWidth = width;
  577.   window->desiredHeight = height;
  578.   window->desiredConfMask |= CWX | CWY | CWWidth | CWHeight;
  579. #ifdef _WIN32
  580.   /* Win32 does not want to use GLUT_FULL_SCREEN_WORK
  581.      for game mode because we need to be maximizing
  582.      the window in game mode, not just sizing it to
  583.      take up the full screen.  The Win32-ness of game
  584.      mode happens when you pass 1 in the gameMode parameter
  585.      to __glutCreateWindow above.  A gameMode of creates
  586.      a WS_POPUP window, not a standard WS_OVERLAPPEDWINDOW
  587.      window.  WS_POPUP ensures the taskbar is hidden. */
  588.   __glutPutOnWorkList(window,
  589.     GLUT_CONFIGURE_WORK);
  590. #else
  591.   __glutPutOnWorkList(window,
  592.     GLUT_CONFIGURE_WORK | GLUT_FULL_SCREEN_WORK);
  593. #endif
  594.   __glutGameModeWindow = window;
  595.   return window->num + 1;
  596. }
  597. int APIENTRY
  598. glutGameModeGet(GLenum mode)
  599. {
  600.   switch (mode) {
  601.   case GLUT_GAME_MODE_ACTIVE:
  602.     return __glutGameModeWindow != NULL;
  603.   case GLUT_GAME_MODE_POSSIBLE:
  604.     return currentDm != NULL;
  605.   case GLUT_GAME_MODE_WIDTH:
  606.     return currentDm ? currentDm->cap[DM_WIDTH] : -1;
  607.   case GLUT_GAME_MODE_HEIGHT:
  608.     return currentDm ? currentDm->cap[DM_HEIGHT] : -1;
  609.   case GLUT_GAME_MODE_PIXEL_DEPTH:
  610.     return currentDm ? currentDm->cap[DM_PIXEL_DEPTH] : -1;
  611.   case GLUT_GAME_MODE_REFRESH_RATE:
  612.     return currentDm ? currentDm->cap[DM_HERTZ] : -1;
  613.   case GLUT_GAME_MODE_DISPLAY_CHANGED:
  614.     return __glutDisplaySettingsChanged;
  615.   default:
  616.     return -1;
  617.   }
  618. }