home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mesa5.zip / mesa5src.zip / MesaDLL / glut_gamemode.cpp < prev    next >
Text File  |  2002-12-14  |  17KB  |  683 lines

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