home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / vid_win.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  75.9 KB  |  3,344 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // vid_win.c -- Win32 video driver
  21.  
  22. #include "quakedef.h"
  23. #include "winquake.h"
  24. #include "d_local.h"
  25. #include "resource.h"
  26.  
  27. #define MAX_MODE_LIST 30
  28. #define VID_ROW_SIZE  3
  29.  
  30. qboolean  dibonly;
  31.  
  32. extern int    Minimized;
  33.  
  34. HWND    mainwindow;
  35.  
  36. HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
  37.  
  38. int     DIBWidth, DIBHeight;
  39. qboolean  DDActive;
  40. RECT    WindowRect;
  41. DWORD   WindowStyle, ExWindowStyle;
  42.  
  43. int     window_center_x, window_center_y, window_x, window_y, window_width, window_height;
  44. RECT    window_rect;
  45.  
  46. static DEVMODE  gdevmode;
  47. static qboolean startwindowed = 0, windowed_mode_set;
  48. static int    firstupdate = 1;
  49. static qboolean vid_initialized = false, vid_palettized;
  50. static int    lockcount;
  51. static int    vid_fulldib_on_focus_mode;
  52. static qboolean force_minimized, in_mode_set, is_mode0x13, force_mode_set;
  53. static int    vid_stretched, windowed_mouse;
  54. static qboolean palette_changed, syscolchg, vid_mode_set, hide_window, pal_is_nostatic;
  55. static HICON  hIcon;
  56.  
  57. viddef_t  vid;        // global video state
  58.  
  59. #define MODE_WINDOWED     0
  60. #define MODE_SETTABLE_WINDOW  2
  61. #define NO_MODE         (MODE_WINDOWED - 1)
  62. #define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 3)
  63.  
  64. // Note that 0 is MODE_WINDOWED
  65. cvar_t    vid_mode = {"vid_mode","0", false};
  66. // Note that 0 is MODE_WINDOWED
  67. cvar_t    _vid_default_mode = {"_vid_default_mode","0", true};
  68. // Note that 3 is MODE_FULLSCREEN_DEFAULT
  69. cvar_t    _vid_default_mode_win = {"_vid_default_mode_win","3", true};
  70. cvar_t    vid_wait = {"vid_wait","0"};
  71. cvar_t    vid_nopageflip = {"vid_nopageflip","0", true};
  72. cvar_t    _vid_wait_override = {"_vid_wait_override", "0", true};
  73. cvar_t    vid_config_x = {"vid_config_x","800", true};
  74. cvar_t    vid_config_y = {"vid_config_y","600", true};
  75. cvar_t    vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
  76. cvar_t    _windowed_mouse = {"_windowed_mouse","0", true};
  77. cvar_t    vid_fullscreen_mode = {"vid_fullscreen_mode","3", true};
  78. cvar_t    vid_windowed_mode = {"vid_windowed_mode","0", true};
  79. cvar_t    block_switch = {"block_switch","0", true};
  80. cvar_t    vid_window_x = {"vid_window_x", "0", true};
  81. cvar_t    vid_window_y = {"vid_window_y", "0", true};
  82.  
  83. typedef struct {
  84.   int   width;
  85.   int   height;
  86. } lmode_t;
  87.  
  88. lmode_t lowresmodes[] = {
  89.   {320, 200},
  90.   {320, 240},
  91.   {400, 300},
  92.   {512, 384},
  93. };
  94.  
  95. int     vid_modenum = NO_MODE;
  96. int     vid_testingmode, vid_realmode;
  97. double    vid_testendtime;
  98. int     vid_default = MODE_WINDOWED;
  99. static int  windowed_default;
  100.  
  101. modestate_t modestate = MS_UNINIT;
  102.  
  103. static byte   *vid_surfcache;
  104. static int    vid_surfcachesize;
  105. static int    VID_highhunkmark;
  106.  
  107. unsigned char vid_curpal[256*3];
  108.  
  109. unsigned short  d_8to16table[256];
  110. unsigned  d_8to24table[256];
  111.  
  112. int     driver = grDETECT,mode;
  113. bool    useWinDirect = true, useDirectDraw = true;
  114. MGLDC *mgldc = NULL,*memdc = NULL,*dibdc = NULL,*windc = NULL;
  115.  
  116. typedef struct {
  117.   modestate_t type;
  118.   int     width;
  119.   int     height;
  120.   int     modenum;
  121.   int     mode13;
  122.   int     stretched;
  123.   int     dib;
  124.   int     fullscreen;
  125.   int     bpp;
  126.   int     halfscreen;
  127.   char    modedesc[13];
  128. } vmode_t;
  129.  
  130. static vmode_t  modelist[MAX_MODE_LIST];
  131. static int    nummodes;
  132. static vmode_t  *pcurrentmode;
  133.  
  134. int   aPage;          // Current active display page
  135. int   vPage;          // Current visible display page
  136. int   waitVRT = true;     // True to wait for retrace on flip
  137.  
  138. static vmode_t  badmode;
  139.  
  140. static byte backingbuf[48*24];
  141.  
  142. void VID_MenuDraw (void);
  143. void VID_MenuKey (int key);
  144.  
  145. LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  146. void AppActivate(BOOL fActive, BOOL minimize);
  147.  
  148.  
  149. /*
  150. ================
  151. VID_RememberWindowPos
  152. ================
  153. */
  154. void VID_RememberWindowPos (void)
  155. {
  156.   RECT  rect;
  157.  
  158.   if (GetWindowRect (mainwindow, &rect))
  159.   {
  160.     if ((rect.left < GetSystemMetrics (SM_CXSCREEN)) &&
  161.       (rect.top < GetSystemMetrics (SM_CYSCREEN))  &&
  162.       (rect.right > 0)                             &&
  163.       (rect.bottom > 0))
  164.     {
  165.       Cvar_SetValue ("vid_window_x", (float)rect.left);
  166.       Cvar_SetValue ("vid_window_y", (float)rect.top);
  167.     }
  168.   }
  169. }
  170.  
  171.  
  172. /*
  173. ================
  174. VID_CheckWindowXY
  175. ================
  176. */
  177. void VID_CheckWindowXY (void)
  178. {
  179.  
  180.   if (((int)vid_window_x.value > (GetSystemMetrics (SM_CXSCREEN) - 160)) ||
  181.     ((int)vid_window_y.value > (GetSystemMetrics (SM_CYSCREEN) - 120)) ||
  182.     ((int)vid_window_x.value < 0)                    ||
  183.     ((int)vid_window_y.value < 0))
  184.   {
  185.     Cvar_SetValue ("vid_window_x", 0.0);
  186.     Cvar_SetValue ("vid_window_y", 0.0 );
  187.   }
  188. }
  189.  
  190.  
  191. /*
  192. ================
  193. VID_UpdateWindowStatus
  194. ================
  195. */
  196. void VID_UpdateWindowStatus (void)
  197. {
  198.  
  199.   window_rect.left = window_x;
  200.   window_rect.top = window_y;
  201.   window_rect.right = window_x + window_width;
  202.   window_rect.bottom = window_y + window_height;
  203.   window_center_x = (window_rect.left + window_rect.right) / 2;
  204.   window_center_y = (window_rect.top + window_rect.bottom) / 2;
  205.  
  206.   IN_UpdateClipCursor ();
  207. }
  208.  
  209.  
  210. /*
  211. ================
  212. ClearAllStates
  213. ================
  214. */
  215. void ClearAllStates (void)
  216. {
  217.   int   i;
  218.   
  219. // send an up event for each key, to make sure the server clears them all
  220.   for (i=0 ; i<256 ; i++)
  221.   {
  222.     Key_Event (i, false);
  223.   }
  224.  
  225.   Key_ClearStates ();
  226.   IN_ClearStates ();
  227. }
  228.  
  229.  
  230. /*
  231. ================
  232. VID_CheckAdequateMem
  233. ================
  234. */
  235. qboolean VID_CheckAdequateMem (int width, int height)
  236. {
  237.   int   tbuffersize;
  238.  
  239.   tbuffersize = width * height * sizeof (*d_pzbuffer);
  240.  
  241.   tbuffersize += D_SurfaceCacheForRes (width, height);
  242.  
  243. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  244. // z, and surface buffers
  245.   if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  246.      0x10000 * 3) < minimum_memory)
  247.   {
  248.     return false;   // not enough memory for mode
  249.   }
  250.  
  251.   return true;
  252. }
  253.  
  254.  
  255. /*
  256. ================
  257. VID_AllocBuffers
  258. ================
  259. */
  260. qboolean VID_AllocBuffers (int width, int height)
  261. {
  262.   int   tsize, tbuffersize;
  263.  
  264.   tbuffersize = width * height * sizeof (*d_pzbuffer);
  265.  
  266.   tsize = D_SurfaceCacheForRes (width, height);
  267.  
  268.   tbuffersize += tsize;
  269.  
  270. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  271. // z, and surface buffers
  272.   if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  273.      0x10000 * 3) < minimum_memory)
  274.   {
  275.     Con_SafePrintf ("Not enough memory for video mode\n");
  276.     return false;   // not enough memory for mode
  277.   }
  278.  
  279.   vid_surfcachesize = tsize;
  280.  
  281.   if (d_pzbuffer)
  282.   {
  283.     D_FlushCaches ();
  284.     Hunk_FreeToHighMark (VID_highhunkmark);
  285.     d_pzbuffer = NULL;
  286.   }
  287.  
  288.   VID_highhunkmark = Hunk_HighMark ();
  289.  
  290.   d_pzbuffer = Hunk_HighAllocName (tbuffersize, "video");
  291.  
  292.   vid_surfcache = (byte *)d_pzbuffer +
  293.       width * height * sizeof (*d_pzbuffer);
  294.   
  295.   return true;
  296. }
  297.  
  298.  
  299. void initFatalError(void)
  300. {
  301.   MGL_exit();
  302.   MGL_fatalError(MGL_errorMsg(MGL_result()));
  303.   exit(EXIT_FAILURE);
  304. }
  305.  
  306.  
  307. int VID_Suspend (MGLDC *dc,m_int flags)
  308. {
  309.  
  310.   if (flags & MGL_DEACTIVATE)
  311.   {
  312.   // FIXME: this doesn't currently work on NT
  313.     if (block_switch.value && !WinNT)
  314.     {
  315.       return MGL_NO_DEACTIVATE;
  316.     }
  317.  
  318.     S_BlockSound ();
  319.     S_ClearBuffer ();
  320.  
  321.     IN_RestoreOriginalMouseState ();
  322.     CDAudio_Pause ();
  323.  
  324.   // keep WM_PAINT from trying to redraw
  325.     in_mode_set = true;
  326.  
  327.     block_drawing = true; // so we don't try to draw while switched away
  328.  
  329.     return MGL_NO_SUSPEND_APP;
  330.   }
  331.   else if (flags & MGL_REACTIVATE)
  332.   {
  333.     IN_SetQuakeMouseState ();
  334.   // fix the leftover Alt from any Alt-Tab or the like that switched us away
  335.     ClearAllStates ();
  336.     CDAudio_Resume ();
  337.     S_UnblockSound ();
  338.  
  339.     in_mode_set = false;
  340.  
  341.     vid.recalc_refdef = 1;
  342.  
  343.     block_drawing = false;
  344.  
  345.     return MGL_NO_SUSPEND_APP;
  346.   }
  347.  
  348. }
  349.  
  350.  
  351. void registerAllDispDrivers(void)
  352. {
  353.   /* Event though these driver require WinDirect, we register
  354.    * them so that they will still be available even if DirectDraw
  355.    * is present and the user has disable the high performance
  356.    * WinDirect modes.
  357.    */
  358.   MGL_registerDriver(MGL_VGA8NAME,VGA8_driver);
  359. //  MGL_registerDriver(MGL_VGAXNAME,VGAX_driver);
  360.  
  361.   /* Register display drivers */
  362.   if (useWinDirect)
  363.   {
  364. //we don't want VESA 1.X drivers    MGL_registerDriver(MGL_SVGA8NAME,SVGA8_driver);
  365.     MGL_registerDriver(MGL_LINEAR8NAME,LINEAR8_driver);
  366.  
  367.     if (!COM_CheckParm ("-novbeaf"))
  368.       MGL_registerDriver(MGL_ACCEL8NAME,ACCEL8_driver);
  369.   }
  370.  
  371.   if (useDirectDraw)
  372.   {
  373.     MGL_registerDriver(MGL_DDRAW8NAME,DDRAW8_driver);
  374.   }
  375. }
  376.  
  377.  
  378. void registerAllMemDrivers(void)
  379. {
  380.   /* Register memory context drivers */
  381.   MGL_registerDriver(MGL_PACKED8NAME,PACKED8_driver);
  382. }
  383.  
  384.  
  385. void VID_InitMGLFull (HINSTANCE hInstance)
  386. {
  387.   int     i, xRes, yRes, bits, vMode, lowres, curmode, temp;
  388.   int     lowstretchedres, stretchedmode, lowstretched;
  389.     uchar   *m;
  390.  
  391. // FIXME: NT is checked for because MGL currently has a bug that causes it
  392. // to try to use WinDirect modes even on NT
  393.   if (COM_CheckParm("-nowindirect") ||
  394.     COM_CheckParm("-nowd") ||
  395.     COM_CheckParm("-novesa") ||
  396.     WinNT)
  397.   {
  398.     useWinDirect = false;
  399.   }
  400.  
  401.   if (COM_CheckParm("-nodirectdraw") || COM_CheckParm("-noddraw") || COM_CheckParm("-nodd"))
  402.     useDirectDraw = false;
  403.  
  404.   // Initialise the MGL
  405.   MGL_unregisterAllDrivers();
  406.   registerAllDispDrivers();
  407.   registerAllMemDrivers();
  408.   MGL_detectGraph(&driver,&mode);
  409.   m = MGL_availableModes();
  410.  
  411.   if (m[0] != 0xFF)
  412.   {
  413.     lowres = lowstretchedres = 99999;
  414.     lowstretched = 0;
  415.     curmode = 0;
  416.  
  417.   // find the lowest-res mode, or a mode we can stretch up to and get
  418.   // lowest-res that way
  419.     for (i = 0; m[i] != 0xFF; i++)
  420.     {
  421.       MGL_modeResolution(m[i], &xRes, &yRes,&bits);
  422.  
  423.       if ((bits == 8) &&
  424.         (xRes <= MAXWIDTH) &&
  425.         (yRes <= MAXHEIGHT) &&
  426.         (curmode < MAX_MODE_LIST))
  427.       {
  428.         if (m[i] == grVGA_320x200x256)
  429.           is_mode0x13 = true;
  430.  
  431.         if (!COM_CheckParm("-noforcevga"))
  432.         {
  433.           if (m[i] == grVGA_320x200x256)
  434.           {
  435.             mode = i;
  436.             break;
  437.           }
  438.         }
  439.  
  440.         if (xRes < lowres)
  441.         {
  442.           lowres = xRes;
  443.           mode = i;
  444.         }
  445.  
  446.         if ((xRes < lowstretchedres) && ((xRes >> 1) >= 320))
  447.         {
  448.           lowstretchedres = xRes >> 1;
  449.           stretchedmode = i;
  450.         }
  451.       }
  452.  
  453.       curmode++;
  454.     }
  455.  
  456.   // if there's a mode we can stretch by 2 up to, thereby effectively getting
  457.   // a lower-res mode than the lowest-res real but still at least 320x200, that
  458.   // will be our default mode
  459.     if (lowstretchedres < lowres)
  460.     {
  461.       mode = stretchedmode;
  462.       lowres = lowstretchedres;
  463.       lowstretched = 1;
  464.     }
  465.  
  466.   // build the mode list, leaving room for the low-res stretched mode, if any
  467.     nummodes++;   // leave room for default mode
  468.  
  469.     for (i = 0; m[i] != 0xFF; i++)
  470.     {
  471.       MGL_modeResolution(m[i], &xRes, &yRes,&bits);
  472.  
  473.       if ((bits == 8) &&
  474.         (xRes <= MAXWIDTH) &&
  475.         (yRes <= MAXHEIGHT) &&
  476.         (nummodes < MAX_MODE_LIST))
  477.       {
  478.         if (i == mode)
  479.         {
  480.           if (lowstretched)
  481.           {
  482.             stretchedmode = nummodes;
  483.             curmode = nummodes++;
  484.           }
  485.           else
  486.           {
  487.             curmode = MODE_FULLSCREEN_DEFAULT;
  488.           }
  489.         }
  490.         else
  491.         {
  492.           curmode = nummodes++;
  493.         }
  494.  
  495.         modelist[curmode].type = MS_FULLSCREEN;
  496.         modelist[curmode].width = xRes;
  497.         modelist[curmode].height = yRes;
  498.         sprintf (modelist[curmode].modedesc, "%dx%d", xRes, yRes);
  499.  
  500.         if (m[i] == grVGA_320x200x256)
  501.           modelist[curmode].mode13 = 1;
  502.         else
  503.           modelist[curmode].mode13 = 0;
  504.  
  505.         modelist[curmode].modenum = m[i];
  506.         modelist[curmode].stretched = 0;
  507.         modelist[curmode].dib = 0;
  508.         modelist[curmode].fullscreen = 1;
  509.         modelist[curmode].halfscreen = 0;
  510.         modelist[curmode].bpp = 8;
  511.       }
  512.     }
  513.  
  514.     if (lowstretched)
  515.     {
  516.       modelist[MODE_FULLSCREEN_DEFAULT] = modelist[stretchedmode];
  517.       modelist[MODE_FULLSCREEN_DEFAULT].stretched = 1;
  518.       modelist[MODE_FULLSCREEN_DEFAULT].width >>= 1;
  519.       modelist[MODE_FULLSCREEN_DEFAULT].height >>= 1;
  520.       sprintf (modelist[MODE_FULLSCREEN_DEFAULT].modedesc, "%dx%d",
  521.            modelist[MODE_FULLSCREEN_DEFAULT].width,
  522.            modelist[MODE_FULLSCREEN_DEFAULT].height);
  523.     }
  524.  
  525.     vid_default = MODE_FULLSCREEN_DEFAULT;
  526.  
  527.     temp = m[0];
  528.  
  529.     if (!MGL_init(&driver, &temp, ""))
  530.     {
  531.       initFatalError();
  532.     }
  533.   }
  534.  
  535.   MGL_setSuspendAppCallback(VID_Suspend);
  536. }
  537.  
  538.  
  539. MGLDC *createDisplayDC(int forcemem)
  540. /****************************************************************************
  541. *
  542. * Function:     createDisplayDC
  543. * Returns:      Pointer to the MGL device context to use for the application
  544. *
  545. * Description:  Initialises the MGL and creates an appropriate display
  546. *               device context to be used by the GUI. This creates and
  547. *               apropriate device context depending on the system being
  548. *               compile for, and should be the only place where system
  549. *               specific code is required.
  550. *
  551. ****************************************************************************/
  552. {
  553.     MGLDC     *dc;
  554.   pixel_format_t  pf;
  555.   int       npages;
  556.  
  557.   // Start the specified video mode
  558.   if (!MGL_changeDisplayMode(mode))
  559.         initFatalError();
  560.  
  561.   npages = MGL_availablePages(mode);
  562.  
  563.   if (npages > 3)
  564.     npages = 3;
  565.  
  566.   if (!COM_CheckParm ("-notriplebuf"))
  567.   {
  568.     if (npages > 2)
  569.     {
  570.       npages = 2;
  571.     }
  572.   }
  573.  
  574.   if ((dc = MGL_createDisplayDC(npages)) == NULL)
  575.     return NULL;
  576.  
  577.   if (!forcemem && (MGL_surfaceAccessType(dc)) == MGL_LINEAR_ACCESS && (dc->mi.maxPage > 0))
  578.   {
  579.     MGL_makeCurrentDC(dc);
  580.     memdc = NULL;
  581.   }
  582.   else
  583.   {
  584.     // Set up for blitting from a memory buffer
  585.     memdc = MGL_createMemoryDC(MGL_sizex(dc)+1,MGL_sizey(dc)+1,8,&pf);
  586.     MGL_makeCurrentDC(memdc);
  587.   }
  588.  
  589.   // Enable page flipping even for even for blitted surfaces
  590.   if (forcemem)
  591.   {
  592.     vid.numpages = 1;
  593.   }
  594.   else
  595.   {
  596.     vid.numpages = dc->mi.maxPage + 1;
  597.  
  598.     if (vid.numpages > 1)
  599.     {
  600.       // Set up for page flipping
  601.       MGL_setActivePage(dc, aPage = 1);
  602.       MGL_setVisualPage(dc, vPage = 0, false);
  603.     }
  604.  
  605.     if (vid.numpages > 3)
  606.       vid.numpages = 3;
  607.   }
  608.  
  609.   if (vid.numpages == 2)
  610.     waitVRT = true;
  611.   else
  612.     waitVRT = false;
  613.  
  614.   return dc;
  615. }
  616.  
  617.  
  618. void VID_InitMGLDIB (HINSTANCE hInstance)
  619. {
  620.   WNDCLASS    wc;
  621.   HDC       hdc;
  622.   int       i;
  623.  
  624.   hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON2));
  625.  
  626.   /* Register the frame class */
  627.     wc.style         = 0;
  628.     wc.lpfnWndProc   = (WNDPROC)MainWndProc;
  629.     wc.cbClsExtra    = 0;
  630.     wc.cbWndExtra    = 0;
  631.     wc.hInstance     = hInstance;
  632.     wc.hIcon         = 0;
  633.     wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
  634.   wc.hbrBackground = NULL;
  635.     wc.lpszMenuName  = 0;
  636.     wc.lpszClassName = "WinQuake";
  637.  
  638.     if (!RegisterClass (&wc) )
  639.     Sys_Error ("Couldn't register window class");
  640.  
  641.   /* Find the size for the DIB window */
  642.   /* Initialise the MGL for windowed operation */
  643.   MGL_setAppInstance(hInstance);
  644.   registerAllMemDrivers();
  645.   MGL_initWindowed("");
  646.  
  647.   modelist[0].type = MS_WINDOWED;
  648.   modelist[0].width = 320;
  649.   modelist[0].height = 240;
  650.   strcpy (modelist[0].modedesc, "320x240");
  651.   modelist[0].mode13 = 0;
  652.   modelist[0].modenum = MODE_WINDOWED;
  653.   modelist[0].stretched = 0;
  654.   modelist[0].dib = 1;
  655.   modelist[0].fullscreen = 0;
  656.   modelist[0].halfscreen = 0;
  657.   modelist[0].bpp = 8;
  658.  
  659.   modelist[1].type = MS_WINDOWED;
  660.   modelist[1].width = 640;
  661.   modelist[1].height = 480;
  662.   strcpy (modelist[1].modedesc, "640x480");
  663.   modelist[1].mode13 = 0;
  664.   modelist[1].modenum = MODE_WINDOWED + 1;
  665.   modelist[1].stretched = 1;
  666.   modelist[1].dib = 1;
  667.   modelist[1].fullscreen = 0;
  668.   modelist[1].halfscreen = 0;
  669.   modelist[1].bpp = 8;
  670.  
  671.   modelist[2].type = MS_WINDOWED;
  672.   modelist[2].width = 800;
  673.   modelist[2].height = 600;
  674.   strcpy (modelist[2].modedesc, "800x600");
  675.   modelist[2].mode13 = 0;
  676.   modelist[2].modenum = MODE_WINDOWED + 2;
  677.   modelist[2].stretched = 1;
  678.   modelist[2].dib = 1;
  679.   modelist[2].fullscreen = 0;
  680.   modelist[2].halfscreen = 0;
  681.   modelist[2].bpp = 8;
  682.  
  683. // automatically stretch the default mode up if > 640x480 desktop resolution
  684.   hdc = GetDC(NULL);
  685.  
  686.   if ((GetDeviceCaps(hdc, HORZRES) > 640) && !COM_CheckParm("-noautostretch"))
  687.   {
  688.     vid_default = MODE_WINDOWED + 1;
  689.   }
  690.   else
  691.   {
  692.     vid_default = MODE_WINDOWED;
  693.   }
  694.  
  695.   windowed_default = vid_default;
  696.  
  697.   ReleaseDC(NULL,hdc);
  698.  
  699.   nummodes = 3; // reserve space for windowed mode
  700.  
  701.   DDActive = 0;
  702. }
  703.  
  704.  
  705. /*
  706. =================
  707. VID_InitFullDIB
  708. =================
  709. */
  710. void VID_InitFullDIB (HINSTANCE hInstance)
  711. {
  712.   DEVMODE devmode;
  713.   int   i, j, modenum, cmodes, existingmode, originalnummodes, lowestres;
  714.   int   numlowresmodes, bpp, done;
  715.   int   cstretch, istretch, mstretch;
  716.   BOOL  stat;
  717.  
  718. // enumerate 8 bpp modes
  719.   originalnummodes = nummodes;
  720.   modenum = 0;
  721.   lowestres = 99999;
  722.  
  723.   do
  724.   {
  725.     stat = EnumDisplaySettings (NULL, modenum, &devmode);
  726.  
  727.     if ((devmode.dmBitsPerPel == 8) &&
  728.       (devmode.dmPelsWidth <= MAXWIDTH) &&
  729.       (devmode.dmPelsHeight <= MAXHEIGHT) &&
  730.       (nummodes < MAX_MODE_LIST))
  731.     {
  732.       devmode.dmFields = DM_BITSPERPEL |
  733.                  DM_PELSWIDTH |
  734.                  DM_PELSHEIGHT;
  735.  
  736.       if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  737.           DISP_CHANGE_SUCCESSFUL)
  738.       {
  739.         modelist[nummodes].type = MS_FULLDIB;
  740.         modelist[nummodes].width = devmode.dmPelsWidth;
  741.         modelist[nummodes].height = devmode.dmPelsHeight;
  742.         modelist[nummodes].modenum = 0;
  743.         modelist[nummodes].mode13 = 0;
  744.         modelist[nummodes].stretched = 0;
  745.         modelist[nummodes].halfscreen = 0;
  746.         modelist[nummodes].dib = 1;
  747.         modelist[nummodes].fullscreen = 1;
  748.         modelist[nummodes].bpp = devmode.dmBitsPerPel;
  749.         sprintf (modelist[nummodes].modedesc, "%dx%d",
  750.              devmode.dmPelsWidth, devmode.dmPelsHeight);
  751.  
  752.       // if the width is more than twice the height, reduce it by half because this
  753.       // is probably a dual-screen monitor
  754.         if (!COM_CheckParm("-noadjustaspect"))
  755.         {
  756.           if (modelist[nummodes].width > (modelist[nummodes].height << 1))
  757.           {
  758.             modelist[nummodes].width >>= 1;
  759.             modelist[nummodes].halfscreen = 1;
  760.             sprintf (modelist[nummodes].modedesc, "%dx%d",
  761.                  modelist[nummodes].width,
  762.                  modelist[nummodes].height);
  763.           }
  764.         }
  765.  
  766.         for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
  767.         {
  768.           if ((modelist[nummodes].width == modelist[i].width) &&
  769.             (modelist[nummodes].height == modelist[i].height))
  770.           {
  771.             existingmode = 1;
  772.             break;
  773.           }
  774.         }
  775.  
  776.         if (!existingmode)
  777.         {
  778.           if (modelist[nummodes].width < lowestres)
  779.             lowestres = modelist[nummodes].width;
  780.  
  781.           nummodes++;
  782.         }
  783.       }
  784.     }
  785.  
  786.     modenum++;
  787.   } while (stat);
  788.  
  789. // see if any of them were actually settable; if so, this is our mode list,
  790. // else enumerate all modes; our mode list is whichever ones are settable
  791. // with > 8 bpp
  792.   if (nummodes == originalnummodes)
  793.   {
  794.     modenum = 0;
  795.     lowestres = 99999;
  796.  
  797.     Con_SafePrintf ("No 8-bpp fullscreen DIB modes found\n");
  798.  
  799.     do
  800.     {
  801.       stat = EnumDisplaySettings (NULL, modenum, &devmode);
  802.  
  803.       if ((((devmode.dmPelsWidth <= MAXWIDTH) &&
  804.           (devmode.dmPelsHeight <= MAXHEIGHT)) ||
  805.          (!COM_CheckParm("-noadjustaspect") &&
  806.           (devmode.dmPelsWidth <= (MAXWIDTH*2)) &&
  807.           (devmode.dmPelsWidth > (devmode.dmPelsHeight*2)))) &&
  808.         (nummodes < MAX_MODE_LIST) &&
  809.         (devmode.dmBitsPerPel > 8))
  810.       {
  811.         devmode.dmFields = DM_BITSPERPEL |
  812.                    DM_PELSWIDTH |
  813.                    DM_PELSHEIGHT;
  814.  
  815.         if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  816.             DISP_CHANGE_SUCCESSFUL)
  817.         {
  818.           modelist[nummodes].type = MS_FULLDIB;
  819.           modelist[nummodes].width = devmode.dmPelsWidth;
  820.           modelist[nummodes].height = devmode.dmPelsHeight;
  821.           modelist[nummodes].modenum = 0;
  822.           modelist[nummodes].mode13 = 0;
  823.           modelist[nummodes].stretched = 0;
  824.           modelist[nummodes].halfscreen = 0;
  825.           modelist[nummodes].dib = 1;
  826.           modelist[nummodes].fullscreen = 1;
  827.           modelist[nummodes].bpp = devmode.dmBitsPerPel;
  828.           sprintf (modelist[nummodes].modedesc, "%dx%d",
  829.                devmode.dmPelsWidth, devmode.dmPelsHeight);
  830.  
  831.         // if the width is more than twice the height, reduce it by half because this
  832.         // is probably a dual-screen monitor
  833.           if (!COM_CheckParm("-noadjustaspect"))
  834.           {
  835.             if (modelist[nummodes].width > (modelist[nummodes].height*2))
  836.             {
  837.               modelist[nummodes].width >>= 1;
  838.               modelist[nummodes].halfscreen = 1;
  839.               sprintf (modelist[nummodes].modedesc, "%dx%d",
  840.                    modelist[nummodes].width,
  841.                    modelist[nummodes].height);
  842.             }
  843.           }
  844.  
  845.           for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
  846.           {
  847.             if ((modelist[nummodes].width == modelist[i].width) &&
  848.               (modelist[nummodes].height == modelist[i].height))
  849.             {
  850.             // pick the lowest available bpp
  851.               if (modelist[nummodes].bpp < modelist[i].bpp)
  852.                 modelist[i] = modelist[nummodes];
  853.  
  854.               existingmode = 1;
  855.               break;
  856.             }
  857.           }
  858.  
  859.           if (!existingmode)
  860.           {
  861.             if (modelist[nummodes].width < lowestres)
  862.               lowestres = modelist[nummodes].width;
  863.  
  864.             nummodes++;
  865.           }
  866.         }
  867.       }
  868.  
  869.       modenum++;
  870.     } while (stat);
  871.   }
  872.  
  873. // see if there are any low-res modes that aren't being reported
  874.   numlowresmodes = sizeof(lowresmodes) / sizeof(lowresmodes[0]);
  875.   bpp = 8;
  876.   done = 0;
  877.  
  878. // first make sure the driver doesn't just answer yes to all tests
  879.   devmode.dmBitsPerPel = 8;
  880.   devmode.dmPelsWidth = 42;
  881.   devmode.dmPelsHeight = 37;
  882.   devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  883.  
  884.   if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  885.       DISP_CHANGE_SUCCESSFUL)
  886.   {
  887.     done = 1;
  888.   }
  889.  
  890.   while (!done)
  891.   {
  892.     for (j=0 ; (j<numlowresmodes) && (nummodes < MAX_MODE_LIST) ; j++)
  893.     {
  894.       devmode.dmBitsPerPel = bpp;
  895.       devmode.dmPelsWidth = lowresmodes[j].width;
  896.       devmode.dmPelsHeight = lowresmodes[j].height;
  897.       devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  898.  
  899.       if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
  900.           DISP_CHANGE_SUCCESSFUL)
  901.       {
  902.           modelist[nummodes].type = MS_FULLDIB;
  903.           modelist[nummodes].width = devmode.dmPelsWidth;
  904.           modelist[nummodes].height = devmode.dmPelsHeight;
  905.           modelist[nummodes].modenum = 0;
  906.           modelist[nummodes].mode13 = 0;
  907.           modelist[nummodes].stretched = 0;
  908.           modelist[nummodes].halfscreen = 0;
  909.           modelist[nummodes].dib = 1;
  910.           modelist[nummodes].fullscreen = 1;
  911.           modelist[nummodes].bpp = devmode.dmBitsPerPel;
  912.           sprintf (modelist[nummodes].modedesc, "%dx%d",
  913.                devmode.dmPelsWidth, devmode.dmPelsHeight);
  914.  
  915.       // we only want the lowest-bpp version of each mode
  916.         for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
  917.         {
  918.           if ((modelist[nummodes].width == modelist[i].width)   &&
  919.             (modelist[nummodes].height == modelist[i].height) &&
  920.             (modelist[nummodes].bpp >= modelist[i].bpp))
  921.           {
  922.             existingmode = 1;
  923.             break;
  924.           }
  925.         }
  926.  
  927.         if (!existingmode)
  928.         {
  929.           if (modelist[nummodes].width < lowestres)
  930.             lowestres = modelist[nummodes].width;
  931.  
  932.           nummodes++;
  933.         }
  934.       }
  935.     }
  936.  
  937.     switch (bpp)
  938.     {
  939.       case 8:
  940.         bpp = 16;
  941.         break;
  942.  
  943.       case 16:
  944.         bpp = 32;
  945.         break;
  946.  
  947.       case 32:
  948.         done = 1;
  949.         break;
  950.     }
  951.   }
  952.  
  953. // now add the lowest stretch-by-2 pseudo-modes between 320-wide
  954. // (inclusive) and lowest real res (not inclusive)
  955. // don't bother if we have a real VGA mode 0x13 mode
  956.   if (!is_mode0x13)
  957.   {
  958.     for (i=originalnummodes, cstretch=0 ; i<nummodes ; i++)
  959.     {
  960.       if (((modelist[i].width >> 1) < lowestres) &&
  961.         ((modelist[i].width >> 1) >= 320))
  962.       {
  963.         lowestres = modelist[i].width >> 1;
  964.         cstretch = 1;
  965.         mstretch = i;
  966.       }
  967.     }
  968.  
  969.     if ((nummodes + cstretch) > MAX_MODE_LIST)
  970.       cstretch = MAX_MODE_LIST - nummodes;
  971.  
  972.     if (cstretch > 0)
  973.     {
  974.       for (i=(nummodes-1) ; i>=originalnummodes ; i--)
  975.         modelist[i+cstretch] = modelist[i];
  976.  
  977.       nummodes += cstretch;
  978.       istretch = originalnummodes;
  979.  
  980.       modelist[istretch] = modelist[mstretch];
  981.       modelist[istretch].width >>= 1;
  982.       modelist[istretch].height >>= 1;
  983.       modelist[istretch].stretched = 1;
  984.       sprintf (modelist[istretch].modedesc, "%dx%d",
  985.            modelist[istretch].width, modelist[istretch].height);
  986.     }
  987.   }
  988.  
  989.   if (nummodes != originalnummodes)
  990.     vid_default = MODE_FULLSCREEN_DEFAULT;
  991.   else
  992.     Con_SafePrintf ("No fullscreen DIB modes found\n");
  993. }
  994.  
  995.  
  996. /*
  997. =================
  998. VID_NumModes
  999. =================
  1000. */
  1001. int VID_NumModes (void)
  1002. {
  1003.   return nummodes;
  1004. }
  1005.  
  1006.   
  1007. /*
  1008. =================
  1009. VID_GetModePtr
  1010. =================
  1011. */
  1012. vmode_t *VID_GetModePtr (int modenum)
  1013. {
  1014.  
  1015.   if ((modenum >= 0) && (modenum < nummodes))
  1016.     return &modelist[modenum];
  1017.   else
  1018.     return &badmode;
  1019. }
  1020.  
  1021.  
  1022. /*
  1023. =================
  1024. VID_CheckModedescFixup
  1025. =================
  1026. */
  1027. void VID_CheckModedescFixup (int mode)
  1028. {
  1029.   int   x, y, stretch;
  1030.  
  1031.   if (mode == MODE_SETTABLE_WINDOW)
  1032.   {
  1033.     modelist[mode].stretched = (int)vid_stretch_by_2.value;
  1034.     stretch = modelist[mode].stretched;
  1035.  
  1036.     if (vid_config_x.value < (320 << stretch))
  1037.       vid_config_x.value = 320 << stretch;
  1038.  
  1039.     if (vid_config_y.value < (200 << stretch))
  1040.       vid_config_y.value = 200 << stretch;
  1041.  
  1042.     x = (int)vid_config_x.value;
  1043.     y = (int)vid_config_y.value;
  1044.     sprintf (modelist[mode].modedesc, "%dx%d", x, y);
  1045.     modelist[mode].width = x;
  1046.     modelist[mode].height = y;
  1047.   }
  1048. }
  1049.  
  1050.  
  1051. /*
  1052. =================
  1053. VID_GetModeDescriptionMemCheck
  1054. =================
  1055. */
  1056. char *VID_GetModeDescriptionMemCheck (int mode)
  1057. {
  1058.   char    *pinfo;
  1059.   vmode_t   *pv;
  1060.  
  1061.   if ((mode < 0) || (mode >= nummodes))
  1062.     return NULL;
  1063.  
  1064.   VID_CheckModedescFixup (mode);
  1065.  
  1066.   pv = VID_GetModePtr (mode);
  1067.   pinfo = pv->modedesc;
  1068.  
  1069.   if (VID_CheckAdequateMem (pv->width, pv->height))
  1070.   {
  1071.     return pinfo;
  1072.   }
  1073.   else
  1074.   {
  1075.     return NULL;
  1076.   }
  1077. }
  1078.  
  1079.  
  1080. /*
  1081. =================
  1082. VID_GetModeDescription
  1083. =================
  1084. */
  1085. char *VID_GetModeDescription (int mode)
  1086. {
  1087.   char    *pinfo;
  1088.   vmode_t   *pv;
  1089.  
  1090.   if ((mode < 0) || (mode >= nummodes))
  1091.     return NULL;
  1092.  
  1093.   VID_CheckModedescFixup (mode);
  1094.  
  1095.   pv = VID_GetModePtr (mode);
  1096.   pinfo = pv->modedesc;
  1097.   return pinfo;
  1098. }
  1099.  
  1100.  
  1101. /*
  1102. =================
  1103. VID_GetModeDescription2
  1104.  
  1105. Tacks on "windowed" or "fullscreen"
  1106. =================
  1107. */
  1108. char *VID_GetModeDescription2 (int mode)
  1109. {
  1110.   static char pinfo[40];
  1111.   vmode_t   *pv;
  1112.  
  1113.   if ((mode < 0) || (mode >= nummodes))
  1114.     return NULL;
  1115.  
  1116.   VID_CheckModedescFixup (mode);
  1117.  
  1118.   pv = VID_GetModePtr (mode);
  1119.  
  1120.   if (modelist[mode].type == MS_FULLSCREEN)
  1121.   {
  1122.     sprintf(pinfo,"%s fullscreen", pv->modedesc);
  1123.   }
  1124.   else if (modelist[mode].type == MS_FULLDIB)
  1125.   {
  1126.     sprintf(pinfo,"%s fullscreen", pv->modedesc);
  1127.   }
  1128.   else
  1129.   {
  1130.     sprintf(pinfo, "%s windowed", pv->modedesc);
  1131.   }
  1132.  
  1133.   return pinfo;
  1134. }
  1135.  
  1136.  
  1137. // KJB: Added this to return the mode driver name in description for console
  1138.  
  1139. char *VID_GetExtModeDescription (int mode)
  1140. {
  1141.   static char pinfo[40];
  1142.   vmode_t   *pv;
  1143.  
  1144.   if ((mode < 0) || (mode >= nummodes))
  1145.     return NULL;
  1146.  
  1147.   VID_CheckModedescFixup (mode);
  1148.  
  1149.   pv = VID_GetModePtr (mode);
  1150.   if (modelist[mode].type == MS_FULLSCREEN)
  1151.   {
  1152.     sprintf(pinfo,"%s fullscreen %s",pv->modedesc,
  1153.         MGL_modeDriverName(pv->modenum));
  1154.   }
  1155.   else if (modelist[mode].type == MS_FULLDIB)
  1156.   {
  1157.     sprintf(pinfo,"%s fullscreen DIB", pv->modedesc);
  1158.   }
  1159.   else
  1160.   {
  1161.     sprintf(pinfo, "%s windowed", pv->modedesc);
  1162.   }
  1163.  
  1164.   return pinfo;
  1165. }
  1166.  
  1167.  
  1168. void DestroyDIBWindow (void)
  1169. {
  1170.  
  1171.   if (modestate == MS_WINDOWED)
  1172.   {
  1173.   // destroy the associated MGL DC's; the window gets reused
  1174.     if (windc)
  1175.       MGL_destroyDC(windc);
  1176.     if (dibdc)
  1177.       MGL_destroyDC(dibdc);
  1178.     windc = dibdc = NULL;
  1179.   }
  1180. }
  1181.  
  1182.  
  1183. void DestroyFullscreenWindow (void)
  1184. {
  1185.  
  1186.   if (modestate == MS_FULLSCREEN)
  1187.   {
  1188.   // destroy the existing fullscreen mode and DC's
  1189.     if (mgldc)
  1190.       MGL_destroyDC (mgldc);
  1191.     if (memdc)
  1192.       MGL_destroyDC (memdc);
  1193.     mgldc = memdc = NULL;
  1194.   }
  1195. }
  1196.  
  1197.  
  1198.  
  1199. void DestroyFullDIBWindow (void)
  1200. {
  1201.   if (modestate == MS_FULLDIB)
  1202.   {
  1203.     ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
  1204.  
  1205.   // Destroy the fullscreen DIB window and associated MGL DC's
  1206.     if (windc)
  1207.       MGL_destroyDC(windc);
  1208.     if (dibdc)
  1209.       MGL_destroyDC(dibdc);
  1210.     windc = dibdc = NULL;
  1211.   }
  1212. }
  1213.  
  1214.  
  1215. qboolean VID_SetWindowedMode (int modenum)
  1216. {
  1217.   HDC       hdc;
  1218.   pixel_format_t  pf;
  1219.   qboolean    stretched;
  1220.   int       lastmodestate;
  1221.   LONG      wlong;
  1222.  
  1223.   if (!windowed_mode_set)
  1224.   {
  1225.     if (COM_CheckParm ("-resetwinpos"))
  1226.     {
  1227.       Cvar_SetValue ("vid_window_x", 0.0);
  1228.       Cvar_SetValue ("vid_window_y", 0.0);
  1229.     }
  1230.  
  1231.     windowed_mode_set;
  1232.   }
  1233.  
  1234.   VID_CheckModedescFixup (modenum);
  1235.  
  1236.   DDActive = 0;
  1237.   lastmodestate = modestate;
  1238.  
  1239.   DestroyFullscreenWindow ();
  1240.   DestroyFullDIBWindow ();
  1241.  
  1242.   if (windc)
  1243.     MGL_destroyDC(windc);
  1244.   if (dibdc)
  1245.     MGL_destroyDC(dibdc);
  1246.   windc = dibdc = NULL;
  1247.  
  1248. // KJB: Signal to the MGL that we are going back to windowed mode
  1249.   if (!MGL_changeDisplayMode(grWINDOWED))
  1250.     initFatalError();
  1251.  
  1252.   WindowRect.top = WindowRect.left = 0;
  1253.  
  1254.   WindowRect.right = modelist[modenum].width;
  1255.   WindowRect.bottom = modelist[modenum].height;
  1256.   stretched = modelist[modenum].stretched;
  1257.  
  1258.   DIBWidth = modelist[modenum].width;
  1259.   DIBHeight = modelist[modenum].height;
  1260.  
  1261.   if (stretched)
  1262.   {
  1263.     DIBWidth >>= 1;
  1264.     DIBHeight >>= 1;
  1265.   }
  1266.  
  1267.   WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU |
  1268.           WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS |
  1269.           WS_CLIPCHILDREN;
  1270.   ExWindowStyle = 0;
  1271.   AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
  1272.  
  1273. // the first time we're called to set the mode, create the window we'll use
  1274. // for the rest of the session
  1275.   if (!vid_mode_set)
  1276.   {
  1277.     mainwindow = CreateWindowEx (
  1278.        ExWindowStyle,
  1279.        "WinQuake",
  1280.        "WinQuake",
  1281.        WindowStyle,
  1282.        0, 0,
  1283.        WindowRect.right - WindowRect.left,
  1284.        WindowRect.bottom - WindowRect.top,
  1285.        NULL,
  1286.        NULL,
  1287.        global_hInstance,
  1288.        NULL);
  1289.  
  1290.     if (!mainwindow)
  1291.       Sys_Error ("Couldn't create DIB window");
  1292.  
  1293.   // tell MGL to use this window for fullscreen modes
  1294.     MGL_registerFullScreenWindow (mainwindow);
  1295.  
  1296.     vid_mode_set = true;
  1297.   }
  1298.   else
  1299.   {
  1300.     SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
  1301.     SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle);
  1302.   }
  1303.  
  1304.   if (!SetWindowPos (mainwindow,
  1305.              NULL,
  1306.              0, 0,
  1307.              WindowRect.right - WindowRect.left,
  1308.              WindowRect.bottom - WindowRect.top,
  1309.              SWP_NOCOPYBITS | SWP_NOZORDER |
  1310.             SWP_HIDEWINDOW))
  1311.   {
  1312.     Sys_Error ("Couldn't resize DIB window");
  1313.   }
  1314.  
  1315.   if (hide_window)
  1316.     return true;
  1317.  
  1318. // position and show the DIB window
  1319.   VID_CheckWindowXY ();
  1320.   SetWindowPos (mainwindow, NULL, (int)vid_window_x.value,
  1321.           (int)vid_window_y.value, 0, 0,
  1322.           SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  1323.  
  1324.   if (force_minimized)
  1325.     ShowWindow (mainwindow, SW_MINIMIZE);
  1326.   else
  1327.     ShowWindow (mainwindow, SW_SHOWDEFAULT);
  1328.  
  1329.   UpdateWindow (mainwindow);
  1330.  
  1331.   modestate = MS_WINDOWED;
  1332.   vid_fulldib_on_focus_mode = 0;
  1333.  
  1334. // because we have set the background brush for the window to NULL
  1335. // (to avoid flickering when re-sizing the window on the desktop),
  1336. // we clear the window to black when created, otherwise it will be
  1337. // empty while Quake starts up.
  1338.   hdc = GetDC(mainwindow);
  1339.   PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
  1340.   ReleaseDC(mainwindow, hdc);
  1341.  
  1342.   /* Create the MGL window DC and the MGL memory DC */
  1343.   if ((windc = MGL_createWindowedDC(mainwindow)) == NULL)
  1344.     MGL_fatalError("Unable to create Windowed DC!");
  1345.  
  1346.   if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL)
  1347.     MGL_fatalError("Unable to create Memory DC!");
  1348.  
  1349.   MGL_makeCurrentDC(dibdc);
  1350.  
  1351.   vid.buffer = vid.conbuffer = vid.direct = dibdc->surface;
  1352.   vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine;
  1353.   vid.numpages = 1;
  1354.   vid.maxwarpwidth = WARP_WIDTH;
  1355.   vid.maxwarpheight = WARP_HEIGHT;
  1356.   vid.height = vid.conheight = DIBHeight;
  1357.   vid.width = vid.conwidth = DIBWidth;
  1358.   vid.aspect = ((float)vid.height / (float)vid.width) *
  1359.         (320.0 / 240.0);
  1360.  
  1361.   vid_stretched = stretched;
  1362.  
  1363.   SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
  1364.   SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
  1365.  
  1366.   return true;
  1367. }
  1368.  
  1369.  
  1370. qboolean VID_SetFullscreenMode (int modenum)
  1371. {
  1372.  
  1373.   DDActive = 1;
  1374.  
  1375.   DestroyDIBWindow ();
  1376.   DestroyFullDIBWindow ();
  1377.  
  1378.   mode = modelist[modenum].modenum;
  1379.  
  1380.   // Destroy old DC's, resetting back to fullscreen mode
  1381.   if (mgldc)
  1382.     MGL_destroyDC (mgldc);
  1383.   if (memdc)
  1384.     MGL_destroyDC (memdc);
  1385.   mgldc = memdc = NULL;
  1386.  
  1387.   if ((mgldc = createDisplayDC (modelist[modenum].stretched ||
  1388.      (int)vid_nopageflip.value)) == NULL)
  1389.   {
  1390.     return false;
  1391.   }
  1392.  
  1393.   modestate = MS_FULLSCREEN;
  1394.   vid_fulldib_on_focus_mode = 0;
  1395.  
  1396.   vid.buffer = vid.conbuffer = vid.direct = NULL;
  1397.   vid.maxwarpwidth = WARP_WIDTH;
  1398.   vid.maxwarpheight = WARP_HEIGHT;
  1399.   DIBHeight = vid.height = vid.conheight = modelist[modenum].height;
  1400.   DIBWidth = vid.width = vid.conwidth = modelist[modenum].width;
  1401.   vid.aspect = ((float)vid.height / (float)vid.width) *
  1402.         (320.0 / 240.0);
  1403.  
  1404.   vid_stretched = modelist[modenum].stretched;
  1405.  
  1406. // needed because we're not getting WM_MOVE messages fullscreen on NT
  1407.   window_x = 0;
  1408.   window_y = 0;
  1409.  
  1410. // set the large icon, so the Quake icon will show up in the taskbar
  1411.   SendMessage (mainwindow, WM_SETICON, (WPARAM)1, (LPARAM)hIcon);
  1412.   SendMessage (mainwindow, WM_SETICON, (WPARAM)0, (LPARAM)hIcon);
  1413.  
  1414. // shouldn't be needed, but Kendall needs to let us get the activation
  1415. // message for this not to be needed on NT
  1416.   AppActivate (true, false);
  1417.  
  1418.   return true;
  1419. }
  1420.  
  1421.  
  1422. qboolean VID_SetFullDIBMode (int modenum)
  1423. {
  1424.   HDC       hdc;
  1425.   pixel_format_t  pf;
  1426.   int       lastmodestate;
  1427.  
  1428.   DDActive = 0;
  1429.  
  1430.   DestroyFullscreenWindow ();
  1431.   DestroyDIBWindow ();
  1432.  
  1433.   if (windc)
  1434.     MGL_destroyDC(windc);
  1435.   if (dibdc)
  1436.     MGL_destroyDC(dibdc);
  1437.   windc = dibdc = NULL;
  1438.  
  1439. // KJB: Signal to the MGL that we are going back to windowed mode
  1440.   if (!MGL_changeDisplayMode(grWINDOWED))
  1441.     initFatalError();
  1442.  
  1443.   gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  1444.   gdevmode.dmBitsPerPel = modelist[modenum].bpp;
  1445.   gdevmode.dmPelsWidth = modelist[modenum].width << modelist[modenum].stretched <<
  1446.                modelist[modenum].halfscreen;
  1447.   gdevmode.dmPelsHeight = modelist[modenum].height << modelist[modenum].stretched;
  1448.   gdevmode.dmSize = sizeof (gdevmode);
  1449.  
  1450.   if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
  1451.     Sys_Error ("Couldn't set fullscreen DIB mode");
  1452.  
  1453.   lastmodestate = modestate;
  1454.   modestate = MS_FULLDIB;
  1455.   vid_fulldib_on_focus_mode = modenum;
  1456.  
  1457.   WindowRect.top = WindowRect.left = 0;
  1458.  
  1459.   hdc = GetDC(NULL);
  1460.  
  1461.   WindowRect.right = modelist[modenum].width << modelist[modenum].stretched;
  1462.   WindowRect.bottom = modelist[modenum].height << modelist[modenum].stretched;
  1463.  
  1464.   ReleaseDC(NULL,hdc);
  1465.  
  1466.   DIBWidth = modelist[modenum].width;
  1467.   DIBHeight = modelist[modenum].height;
  1468.  
  1469.   WindowStyle = WS_POPUP | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
  1470.   ExWindowStyle = 0;
  1471.   AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
  1472.  
  1473.   SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
  1474.   SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle);
  1475.  
  1476.   if (!SetWindowPos (mainwindow,
  1477.              NULL,
  1478.              0, 0,
  1479.              WindowRect.right - WindowRect.left,
  1480.              WindowRect.bottom - WindowRect.top,
  1481.              SWP_NOCOPYBITS | SWP_NOZORDER))
  1482.   {
  1483.     Sys_Error ("Couldn't resize DIB window");
  1484.   }
  1485.  
  1486. // position and show the DIB window
  1487.   SetWindowPos (mainwindow, HWND_TOPMOST, 0, 0, 0, 0,
  1488.           SWP_NOSIZE | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  1489.   ShowWindow (mainwindow, SW_SHOWDEFAULT);
  1490.   UpdateWindow (mainwindow);
  1491.  
  1492.   // Because we have set the background brush for the window to NULL
  1493.   // (to avoid flickering when re-sizing the window on the desktop), we
  1494.   // clear the window to black when created, otherwise it will be
  1495.   // empty while Quake starts up.
  1496.   hdc = GetDC(mainwindow);
  1497.   PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
  1498.   ReleaseDC(mainwindow, hdc);
  1499.  
  1500.   /* Create the MGL window DC and the MGL memory DC */
  1501.   if ((windc = MGL_createWindowedDC(mainwindow)) == NULL)
  1502.     MGL_fatalError("Unable to create Fullscreen DIB DC!");
  1503.  
  1504.   if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL)
  1505.     MGL_fatalError("Unable to create Memory DC!");
  1506.  
  1507.   MGL_makeCurrentDC(dibdc);
  1508.  
  1509.   vid.buffer = vid.conbuffer = vid.direct = dibdc->surface;
  1510.   vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine;
  1511.   vid.numpages = 1;
  1512.   vid.maxwarpwidth = WARP_WIDTH;
  1513.   vid.maxwarpheight = WARP_HEIGHT;
  1514.   vid.height = vid.conheight = DIBHeight;
  1515.   vid.width = vid.conwidth = DIBWidth;
  1516.   vid.aspect = ((float)vid.height / (float)vid.width) *
  1517.         (320.0 / 240.0);
  1518.  
  1519.   vid_stretched = modelist[modenum].stretched;
  1520.  
  1521. // needed because we're not getting WM_MOVE messages fullscreen on NT
  1522.   window_x = 0;
  1523.   window_y = 0;
  1524.  
  1525.   return true;
  1526. }
  1527.  
  1528.  
  1529. void VID_RestoreOldMode (int original_mode)
  1530. {
  1531.   static qboolean inerror = false;
  1532.  
  1533.   if (inerror)
  1534.     return;
  1535.  
  1536.   in_mode_set = false;
  1537.   inerror = true;
  1538.  
  1539. // make sure mode set happens (video mode changes)
  1540.   vid_modenum = original_mode - 1;
  1541.  
  1542.   if (!VID_SetMode (original_mode, vid_curpal))
  1543.   {
  1544.     vid_modenum = MODE_WINDOWED - 1;
  1545.  
  1546.     if (!VID_SetMode (windowed_default, vid_curpal))
  1547.       Sys_Error ("Can't set any video mode");
  1548.   }
  1549.  
  1550.   inerror = false;
  1551. }
  1552.  
  1553.  
  1554. void VID_SetDefaultMode (void)
  1555. {
  1556.  
  1557.   if (vid_initialized)
  1558.     VID_SetMode (0, vid_curpal);
  1559.  
  1560.   IN_DeactivateMouse ();
  1561. }
  1562.  
  1563.  
  1564. int VID_SetMode (int modenum, unsigned char *palette)
  1565. {
  1566.   int       original_mode, temp, dummy;
  1567.   qboolean    stat;
  1568.     MSG       msg;
  1569.   HDC       hdc;
  1570.  
  1571.   while ((modenum >= nummodes) || (modenum < 0))
  1572.   {
  1573.     if (vid_modenum == NO_MODE)
  1574.     {
  1575.       if (modenum == vid_default)
  1576.       {
  1577.         modenum = windowed_default;
  1578.       }
  1579.       else
  1580.       {
  1581.         modenum = vid_default;
  1582.       }
  1583.  
  1584.       Cvar_SetValue ("vid_mode", (float)modenum);
  1585.     }
  1586.     else
  1587.     {
  1588.       Cvar_SetValue ("vid_mode", (float)vid_modenum);
  1589.       return 0;
  1590.     }
  1591.   }
  1592.  
  1593.   if (!force_mode_set && (modenum == vid_modenum))
  1594.     return true;
  1595.  
  1596. // so Con_Printfs don't mess us up by forcing vid and snd updates
  1597.   temp = scr_disabled_for_loading;
  1598.   scr_disabled_for_loading = true;
  1599.   in_mode_set = true;
  1600.  
  1601.   CDAudio_Pause ();
  1602.   S_ClearBuffer ();
  1603.  
  1604.   if (vid_modenum == NO_MODE)
  1605.     original_mode = windowed_default;
  1606.   else
  1607.     original_mode = vid_modenum;
  1608.  
  1609.   // Set either the fullscreen or windowed mode
  1610.   if (modelist[modenum].type == MS_WINDOWED)
  1611.   {
  1612.     if (_windowed_mouse.value)
  1613.     {
  1614.       stat = VID_SetWindowedMode(modenum);
  1615.       IN_ActivateMouse ();
  1616.       IN_HideMouse ();
  1617.     }
  1618.     else
  1619.     {
  1620.       IN_DeactivateMouse ();
  1621.       IN_ShowMouse ();
  1622.       stat = VID_SetWindowedMode(modenum);
  1623.     }
  1624.   }
  1625.   else if (modelist[modenum].type == MS_FULLDIB)
  1626.   {
  1627.     stat = VID_SetFullDIBMode(modenum);
  1628.     IN_ActivateMouse ();
  1629.     IN_HideMouse ();
  1630.   }
  1631.   else
  1632.   {
  1633.     stat = VID_SetFullscreenMode(modenum);
  1634.     IN_ActivateMouse ();
  1635.     IN_HideMouse ();
  1636.   }
  1637.  
  1638.   window_width = vid.width << vid_stretched;
  1639.   window_height = vid.height << vid_stretched;
  1640.   VID_UpdateWindowStatus ();
  1641.  
  1642.   CDAudio_Resume ();
  1643.   scr_disabled_for_loading = temp;
  1644.  
  1645.   if (!stat)
  1646.   {
  1647.     VID_RestoreOldMode (original_mode);
  1648.     return false;
  1649.   }
  1650.  
  1651.   if (hide_window)
  1652.     return true;
  1653.  
  1654. // now we try to make sure we get the focus on the mode switch, because
  1655. // sometimes in some systems we don't.  We grab the foreground, then
  1656. // finish setting up, pump all our messages, and sleep for a little while
  1657. // to let messages finish bouncing around the system, then we put
  1658. // ourselves at the top of the z order, then grab the foreground again,
  1659. // Who knows if it helps, but it probably doesn't hurt
  1660.   if (!force_minimized)
  1661.     SetForegroundWindow (mainwindow);
  1662.  
  1663.   hdc = GetDC(NULL);
  1664.  
  1665.   if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  1666.     vid_palettized = true;
  1667.   else
  1668.     vid_palettized = false;
  1669.  
  1670.   VID_SetPalette (palette);
  1671.  
  1672.   ReleaseDC(NULL,hdc);
  1673.  
  1674.   vid_modenum = modenum;
  1675.   Cvar_SetValue ("vid_mode", (float)vid_modenum);
  1676.  
  1677.   if (!VID_AllocBuffers (vid.width, vid.height))
  1678.   {
  1679.   // couldn't get memory for this mode; try to fall back to previous mode
  1680.     VID_RestoreOldMode (original_mode);
  1681.     return false;
  1682.   }
  1683.  
  1684.   D_InitCaches (vid_surfcache, vid_surfcachesize);
  1685.  
  1686.   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
  1687.   {
  1688.         TranslateMessage (&msg);
  1689.         DispatchMessage (&msg);
  1690.   }
  1691.  
  1692.   Sleep (100);
  1693.  
  1694.   if (!force_minimized)
  1695.   {
  1696.     SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0,
  1697.           SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
  1698.           SWP_NOCOPYBITS);
  1699.  
  1700.     SetForegroundWindow (mainwindow);
  1701.   }
  1702.  
  1703. // fix the leftover Alt from any Alt-Tab or the like that switched us away
  1704.   ClearAllStates ();
  1705.  
  1706.   if (!msg_suppress_1)
  1707.     Con_SafePrintf ("%s\n", VID_GetModeDescription (vid_modenum));
  1708.  
  1709.   VID_SetPalette (palette);
  1710.  
  1711.   in_mode_set = false;
  1712.   vid.recalc_refdef = 1;
  1713.  
  1714.   return true;
  1715. }
  1716.  
  1717. void VID_LockBuffer (void)
  1718. {
  1719.  
  1720.   if (dibdc)
  1721.     return;
  1722.  
  1723.   lockcount++;
  1724.  
  1725.   if (lockcount > 1)
  1726.     return;
  1727.  
  1728.   MGL_beginDirectAccess();
  1729.  
  1730.   if (memdc)
  1731.   {
  1732.     // Update surface pointer for linear access modes
  1733.     vid.buffer = vid.conbuffer = vid.direct = memdc->surface;
  1734.     vid.rowbytes = vid.conrowbytes = memdc->mi.bytesPerLine;
  1735.   }
  1736.   else if (mgldc)
  1737.   {
  1738.     // Update surface pointer for linear access modes
  1739.     vid.buffer = vid.conbuffer = vid.direct = mgldc->surface;
  1740.     vid.rowbytes = vid.conrowbytes = mgldc->mi.bytesPerLine;
  1741.   }
  1742.  
  1743.   if (r_dowarp)
  1744.     d_viewbuffer = r_warpbuffer;
  1745.   else
  1746.     d_viewbuffer = (void *)(byte *)vid.buffer;
  1747.  
  1748.   if (r_dowarp)
  1749.     screenwidth = WARP_WIDTH;
  1750.   else
  1751.     screenwidth = vid.rowbytes;
  1752.  
  1753.   if (lcd_x.value)
  1754.     screenwidth <<= 1;
  1755. }
  1756.     
  1757.     
  1758. void VID_UnlockBuffer (void)
  1759. {
  1760.   if (dibdc)
  1761.     return;
  1762.  
  1763.   lockcount--;
  1764.  
  1765.   if (lockcount > 0)
  1766.     return;
  1767.  
  1768.   if (lockcount < 0)
  1769.     Sys_Error ("Unbalanced unlock");
  1770.  
  1771.   MGL_endDirectAccess();
  1772.  
  1773. // to turn up any unlocked accesses
  1774.   vid.buffer = vid.conbuffer = vid.direct = d_viewbuffer = NULL;
  1775.  
  1776. }
  1777.  
  1778.  
  1779. int VID_ForceUnlockedAndReturnState (void)
  1780. {
  1781.   int lk;
  1782.  
  1783.   if (!lockcount)
  1784.     return 0;
  1785.  
  1786.   lk = lockcount;
  1787.  
  1788.   if (dibdc)
  1789.   {
  1790.     lockcount = 0;
  1791.   }
  1792.   else
  1793.   {
  1794.     lockcount = 1;
  1795.     VID_UnlockBuffer ();
  1796.   }
  1797.  
  1798.   return lk;
  1799. }
  1800.  
  1801.  
  1802. void VID_ForceLockState (int lk)
  1803. {
  1804.  
  1805.   if (!dibdc && lk)
  1806.   {
  1807.     lockcount = 0;
  1808.     VID_LockBuffer ();
  1809.   }
  1810.  
  1811.   lockcount = lk;
  1812. }
  1813.  
  1814.  
  1815. void  VID_SetPalette (unsigned char *palette)
  1816. {
  1817.   INT     i;
  1818.   palette_t pal[256];
  1819.     HDC     hdc;
  1820.  
  1821.   if (!Minimized)
  1822.   {
  1823.     palette_changed = true;
  1824.  
  1825.   // make sure we have the static colors if we're the active app
  1826.     hdc = GetDC(NULL);
  1827.  
  1828.     if (vid_palettized && ActiveApp)
  1829.     {
  1830.       if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC)
  1831.       {
  1832.       // switch to SYSPAL_NOSTATIC and remap the colors
  1833.         SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
  1834.         syscolchg = true;
  1835.         pal_is_nostatic = true;
  1836.       }
  1837.     }
  1838.  
  1839.     ReleaseDC(NULL,hdc);
  1840.  
  1841.     // Translate the palette values to an MGL palette array and
  1842.     // set the values.
  1843.     for (i = 0; i < 256; i++)
  1844.     {
  1845.       pal[i].red = palette[i*3];
  1846.       pal[i].green = palette[i*3+1];
  1847.       pal[i].blue = palette[i*3+2];
  1848.     }
  1849.  
  1850.     if (DDActive)
  1851.     {
  1852.       if (!mgldc)
  1853.         return;
  1854.  
  1855.       MGL_setPalette(mgldc,pal,256,0);
  1856.       MGL_realizePalette(mgldc,256,0,false);
  1857.       if (memdc)
  1858.         MGL_setPalette(memdc,pal,256,0);
  1859.     }
  1860.     else
  1861.     {
  1862.       if (!windc)
  1863.         return;
  1864.  
  1865.       MGL_setPalette(windc,pal,256,0);
  1866.       MGL_realizePalette(windc,256,0,false);
  1867.       if (dibdc)
  1868.       {
  1869.         MGL_setPalette(dibdc,pal,256,0);
  1870.         MGL_realizePalette(dibdc,256,0,false);
  1871.       }
  1872.     }
  1873.   }
  1874.  
  1875.   memcpy (vid_curpal, palette, sizeof(vid_curpal));
  1876.  
  1877.   if (syscolchg)
  1878.   {
  1879.     PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
  1880.     syscolchg = false;
  1881.   }
  1882. }
  1883.  
  1884.  
  1885. void  VID_ShiftPalette (unsigned char *palette)
  1886. {
  1887.   VID_SetPalette (palette);
  1888. }
  1889.  
  1890.  
  1891. /*
  1892. =================
  1893. VID_DescribeCurrentMode_f
  1894. =================
  1895. */
  1896. void VID_DescribeCurrentMode_f (void)
  1897. {
  1898.   Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum));
  1899. }
  1900.  
  1901.  
  1902. /*
  1903. =================
  1904. VID_NumModes_f
  1905. =================
  1906. */
  1907. void VID_NumModes_f (void)
  1908. {
  1909.  
  1910.   if (nummodes == 1)
  1911.     Con_Printf ("%d video mode is available\n", nummodes);
  1912.   else
  1913.     Con_Printf ("%d video modes are available\n", nummodes);
  1914. }
  1915.  
  1916.  
  1917. /*
  1918. =================
  1919. VID_DescribeMode_f
  1920. =================
  1921. */
  1922. void VID_DescribeMode_f (void)
  1923. {
  1924.   int   modenum;
  1925.   
  1926.   modenum = Q_atoi (Cmd_Argv(1));
  1927.  
  1928.   Con_Printf ("%s\n", VID_GetExtModeDescription (modenum));
  1929. }
  1930.  
  1931.  
  1932. /*
  1933. =================
  1934. VID_DescribeModes_f
  1935. =================
  1936. */
  1937. void VID_DescribeModes_f (void)
  1938. {
  1939.   int     i, lnummodes;
  1940.   char    *pinfo;
  1941.   qboolean  na;
  1942.   vmode_t   *pv;
  1943.  
  1944.   na = false;
  1945.  
  1946.   lnummodes = VID_NumModes ();
  1947.  
  1948.   for (i=0 ; i<lnummodes ; i++)
  1949.   {
  1950.     pv = VID_GetModePtr (i);
  1951.     pinfo = VID_GetExtModeDescription (i);
  1952.  
  1953.     if (VID_CheckAdequateMem (pv->width, pv->height))
  1954.     {
  1955.       Con_Printf ("%2d: %s\n", i, pinfo);
  1956.     }
  1957.     else
  1958.     {
  1959.       Con_Printf ("**: %s\n", pinfo);
  1960.       na = true;
  1961.     }
  1962.   }
  1963.  
  1964.   if (na)
  1965.   {
  1966.     Con_Printf ("\n[**: not enough system RAM for mode]\n");
  1967.   }
  1968. }
  1969.  
  1970.  
  1971. /*
  1972. =================
  1973. VID_TestMode_f
  1974. =================
  1975. */
  1976. void VID_TestMode_f (void)
  1977. {
  1978.   int   modenum;
  1979.   double  testduration;
  1980.  
  1981.   if (!vid_testingmode)
  1982.   {
  1983.     modenum = Q_atoi (Cmd_Argv(1));
  1984.  
  1985.     if (VID_SetMode (modenum, vid_curpal))
  1986.     {
  1987.       vid_testingmode = 1;
  1988.       testduration = Q_atof (Cmd_Argv(2));
  1989.       if (testduration == 0)
  1990.         testduration = 5.0;
  1991.       vid_testendtime = realtime + testduration;
  1992.     }
  1993.   }
  1994. }
  1995.  
  1996.  
  1997. /*
  1998. =================
  1999. VID_Windowed_f
  2000. =================
  2001. */
  2002. void VID_Windowed_f (void)
  2003. {
  2004.  
  2005.   VID_SetMode ((int)vid_windowed_mode.value, vid_curpal);
  2006. }
  2007.  
  2008.  
  2009. /*
  2010. =================
  2011. VID_Fullscreen_f
  2012. =================
  2013. */
  2014. void VID_Fullscreen_f (void)
  2015. {
  2016.  
  2017.   VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal);
  2018. }
  2019.  
  2020.  
  2021. /*
  2022. =================
  2023. VID_Minimize_f
  2024. =================
  2025. */
  2026. void VID_Minimize_f (void)
  2027. {
  2028.  
  2029. // we only support minimizing windows; if you're fullscreen,
  2030. // switch to windowed first
  2031.   if (modestate == MS_WINDOWED)
  2032.     ShowWindow (mainwindow, SW_MINIMIZE);
  2033. }
  2034.  
  2035.  
  2036.  
  2037. /*
  2038. =================
  2039. VID_ForceMode_f
  2040. =================
  2041. */
  2042. void VID_ForceMode_f (void)
  2043. {
  2044.   int   modenum;
  2045.   double  testduration;
  2046.  
  2047.   if (!vid_testingmode)
  2048.   {
  2049.     modenum = Q_atoi (Cmd_Argv(1));
  2050.  
  2051.     force_mode_set = 1;
  2052.     VID_SetMode (modenum, vid_curpal);
  2053.     force_mode_set = 0;
  2054.   }
  2055. }
  2056.  
  2057.  
  2058. void  VID_Init (unsigned char *palette)
  2059. {
  2060.   int   i, bestmatch, bestmatchmetric, t, dr, dg, db;
  2061.   int   basenummodes;
  2062.   byte  *ptmp;
  2063.  
  2064.   Cvar_RegisterVariable (&vid_mode);
  2065.   Cvar_RegisterVariable (&vid_wait);
  2066.   Cvar_RegisterVariable (&vid_nopageflip);
  2067.   Cvar_RegisterVariable (&_vid_wait_override);
  2068.   Cvar_RegisterVariable (&_vid_default_mode);
  2069.   Cvar_RegisterVariable (&_vid_default_mode_win);
  2070.   Cvar_RegisterVariable (&vid_config_x);
  2071.   Cvar_RegisterVariable (&vid_config_y);
  2072.   Cvar_RegisterVariable (&vid_stretch_by_2);
  2073.   Cvar_RegisterVariable (&_windowed_mouse);
  2074.   Cvar_RegisterVariable (&vid_fullscreen_mode);
  2075.   Cvar_RegisterVariable (&vid_windowed_mode);
  2076.   Cvar_RegisterVariable (&block_switch);
  2077.   Cvar_RegisterVariable (&vid_window_x);
  2078.   Cvar_RegisterVariable (&vid_window_y);
  2079.  
  2080.   Cmd_AddCommand ("vid_testmode", VID_TestMode_f);
  2081.   Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
  2082.   Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
  2083.   Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
  2084.   Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
  2085.   Cmd_AddCommand ("vid_forcemode", VID_ForceMode_f);
  2086.   Cmd_AddCommand ("vid_windowed", VID_Windowed_f);
  2087.   Cmd_AddCommand ("vid_fullscreen", VID_Fullscreen_f);
  2088.   Cmd_AddCommand ("vid_minimize", VID_Minimize_f);
  2089.  
  2090.   if (COM_CheckParm ("-dibonly"))
  2091.     dibonly = true;
  2092.  
  2093.   VID_InitMGLDIB (global_hInstance);
  2094.  
  2095.   basenummodes = nummodes;
  2096.  
  2097.   if (!dibonly)
  2098.     VID_InitMGLFull (global_hInstance);
  2099.  
  2100. // if there are no non-windowed modes, or only windowed and mode 0x13, then use
  2101. // fullscreen DIBs as well
  2102.   if (((nummodes == basenummodes) ||
  2103.      ((nummodes == (basenummodes + 1)) && is_mode0x13)) &&
  2104.     !COM_CheckParm ("-nofulldib"))
  2105.  
  2106.   {
  2107.     VID_InitFullDIB (global_hInstance);
  2108.   }
  2109.  
  2110.   vid.maxwarpwidth = WARP_WIDTH;
  2111.   vid.maxwarpheight = WARP_HEIGHT;
  2112.   vid.colormap = host_colormap;
  2113.   vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
  2114.   vid_testingmode = 0;
  2115.  
  2116. // GDI doesn't let us remap palette index 0, so we'll remap color
  2117. // mappings from that black to another one
  2118.   bestmatchmetric = 256*256*3;
  2119.  
  2120.   for (i=1 ; i<256 ; i++)
  2121.   {
  2122.     dr = palette[0] - palette[i*3];
  2123.     dg = palette[1] - palette[i*3+1];
  2124.     db = palette[2] - palette[i*3+2];
  2125.  
  2126.     t = (dr * dr) + (dg * dg) + (db * db);
  2127.  
  2128.     if (t < bestmatchmetric)
  2129.     {
  2130.       bestmatchmetric = t;
  2131.       bestmatch = i;
  2132.  
  2133.       if (t == 0)
  2134.         break;
  2135.     }
  2136.   }
  2137.  
  2138.   for (i=0, ptmp = vid.colormap ; i<(1<<(VID_CBITS+8)) ; i++, ptmp++)
  2139.   {
  2140.     if (*ptmp == 0)
  2141.       *ptmp = bestmatch;
  2142.   }
  2143.  
  2144.   if (COM_CheckParm("-startwindowed"))
  2145.   {
  2146.     startwindowed = 1;
  2147.     vid_default = windowed_default;
  2148.   }
  2149.  
  2150.   if (hwnd_dialog)
  2151.     DestroyWindow (hwnd_dialog);
  2152.  
  2153. // sound initialization has to go here, preceded by a windowed mode set,
  2154. // so there's a window for DirectSound to work with but we're not yet
  2155. // fullscreen so the "hardware already in use" dialog is visible if it
  2156. // gets displayed
  2157.  
  2158. // keep the window minimized until we're ready for the first real mode set
  2159.   hide_window = true;
  2160.   VID_SetMode (MODE_WINDOWED, palette);
  2161.   hide_window = false;
  2162.   S_Init ();
  2163.  
  2164.   vid_initialized = true;
  2165.  
  2166.   force_mode_set = true;
  2167.   VID_SetMode (vid_default, palette);
  2168.   force_mode_set = false;
  2169.  
  2170.   vid_realmode = vid_modenum;
  2171.  
  2172.   VID_SetPalette (palette);
  2173.  
  2174.   vid_menudrawfn = VID_MenuDraw;
  2175.   vid_menukeyfn = VID_MenuKey;
  2176.  
  2177.   strcpy (badmode.modedesc, "Bad mode");
  2178. }
  2179.  
  2180.  
  2181. void  VID_Shutdown (void)
  2182. {
  2183.   HDC       hdc;
  2184.   int       dummy;
  2185.  
  2186.   if (vid_initialized)
  2187.   {
  2188.     if (modestate == MS_FULLDIB)
  2189.       ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
  2190.  
  2191.     PostMessage (HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)mainwindow, (LPARAM)0);
  2192.     PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
  2193.  
  2194.     AppActivate(false, false);
  2195.     DestroyDIBWindow ();
  2196.     DestroyFullscreenWindow ();
  2197.     DestroyFullDIBWindow ();
  2198.  
  2199.     if (hwnd_dialog)
  2200.       DestroyWindow (hwnd_dialog);
  2201.  
  2202.     if (mainwindow)
  2203.       DestroyWindow(mainwindow);
  2204.  
  2205.     MGL_exit();
  2206.  
  2207.     vid_testingmode = 0;
  2208.     vid_initialized = 0;
  2209.   }
  2210. }
  2211.  
  2212.  
  2213. /*
  2214. ================
  2215. FlipScreen
  2216. ================
  2217. */
  2218. void FlipScreen(vrect_t *rects)
  2219. {
  2220.   HRESULT   ddrval;
  2221.  
  2222.   // Flip the surfaces
  2223.  
  2224.   if (DDActive)
  2225.   {
  2226.     if (mgldc)
  2227.     {
  2228.       if (memdc)
  2229.       {
  2230.         while (rects)
  2231.         {
  2232.           if (vid_stretched)
  2233.           {
  2234.             MGL_stretchBltCoord(mgldc, memdc,
  2235.                   rects->x,
  2236.                   rects->y,
  2237.                   rects->x + rects->width,
  2238.                   rects->y + rects->height,
  2239.                   rects->x << 1,
  2240.                   rects->y << 1,
  2241.                   (rects->x + rects->width) << 1,
  2242.                   (rects->y + rects->height) << 1);
  2243.           }
  2244.           else
  2245.           {
  2246.             MGL_bitBltCoord(mgldc, memdc,
  2247.                   rects->x, rects->y,
  2248.                   (rects->x + rects->width),
  2249.                   (rects->y + rects->height),
  2250.                   rects->x, rects->y, MGL_REPLACE_MODE);
  2251.           }
  2252.  
  2253.           rects = rects->pnext;
  2254.         }
  2255.       }
  2256.  
  2257.       if (vid.numpages > 1)
  2258.       {
  2259.         // We have a flipping surface, so do a hard page flip
  2260.         aPage = (aPage+1) % vid.numpages;
  2261.         vPage = (vPage+1) % vid.numpages;
  2262.         MGL_setActivePage(mgldc,aPage);
  2263.         MGL_setVisualPage(mgldc,vPage,waitVRT);
  2264.       }
  2265.     }
  2266.   }
  2267.   else
  2268.   {
  2269.     HDC hdcScreen;
  2270.  
  2271.     hdcScreen = GetDC(mainwindow);
  2272.  
  2273.     if (windc && dibdc)
  2274.     {
  2275.       MGL_setWinDC(windc,hdcScreen);
  2276.  
  2277.       while (rects)
  2278.       {
  2279.         if (vid_stretched)
  2280.         {
  2281.           MGL_stretchBltCoord(windc,dibdc,
  2282.             rects->x, rects->y,
  2283.             rects->x + rects->width, rects->y + rects->height,
  2284.             rects->x << 1, rects->y << 1,
  2285.             (rects->x + rects->width) << 1,
  2286.             (rects->y + rects->height) << 1);
  2287.         }
  2288.         else
  2289.         {
  2290.           MGL_bitBltCoord(windc,dibdc,
  2291.             rects->x, rects->y,
  2292.             rects->x + rects->width, rects->y + rects->height,
  2293.             rects->x, rects->y, MGL_REPLACE_MODE);
  2294.         }
  2295.  
  2296.         rects = rects->pnext;
  2297.       }
  2298.     }
  2299.  
  2300.     ReleaseDC(mainwindow, hdcScreen);
  2301.   }
  2302. }
  2303.  
  2304.  
  2305. void  VID_Update (vrect_t *rects)
  2306. {
  2307.   vrect_t rect;
  2308.   RECT  trect;
  2309.  
  2310.   if (!vid_palettized && palette_changed)
  2311.   {
  2312.     palette_changed = false;
  2313.     rect.x = 0;
  2314.     rect.y = 0;
  2315.     rect.width = vid.width;
  2316.     rect.height = vid.height;
  2317.     rect.pnext = NULL;
  2318.     rects = ▭
  2319.   }
  2320.  
  2321.   if (firstupdate)
  2322.   {
  2323.     if (modestate == MS_WINDOWED)
  2324.     {
  2325.       GetWindowRect (mainwindow, &trect);
  2326.  
  2327.       if ((trect.left != (int)vid_window_x.value) ||
  2328.         (trect.top  != (int)vid_window_y.value))
  2329.       {
  2330.         if (COM_CheckParm ("-resetwinpos"))
  2331.         {
  2332.           Cvar_SetValue ("vid_window_x", 0.0);
  2333.           Cvar_SetValue ("vid_window_y", 0.0);
  2334.         }
  2335.  
  2336.         VID_CheckWindowXY ();
  2337.         SetWindowPos (mainwindow, NULL, (int)vid_window_x.value,
  2338.           (int)vid_window_y.value, 0, 0,
  2339.           SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
  2340.       }
  2341.     }
  2342.  
  2343.     if ((_vid_default_mode_win.value != vid_default) &&
  2344.       (!startwindowed || (_vid_default_mode_win.value < MODE_FULLSCREEN_DEFAULT)))
  2345.     {
  2346.       firstupdate = 0;
  2347.  
  2348.       if (COM_CheckParm ("-resetwinpos"))
  2349.       {
  2350.         Cvar_SetValue ("vid_window_x", 0.0);
  2351.         Cvar_SetValue ("vid_window_y", 0.0);
  2352.       }
  2353.  
  2354.       if ((_vid_default_mode_win.value < 0) ||
  2355.         (_vid_default_mode_win.value >= nummodes))
  2356.       {
  2357.         Cvar_SetValue ("_vid_default_mode_win", windowed_default);
  2358.       }
  2359.  
  2360.       Cvar_SetValue ("vid_mode", _vid_default_mode_win.value);
  2361.     }
  2362.   }
  2363.  
  2364.   // We've drawn the frame; copy it to the screen
  2365.   FlipScreen (rects);
  2366.  
  2367.   if (vid_testingmode)
  2368.   {
  2369.     if (realtime >= vid_testendtime)
  2370.     {
  2371.       VID_SetMode (vid_realmode, vid_curpal);
  2372.       vid_testingmode = 0;
  2373.     }
  2374.   }
  2375.   else
  2376.   {
  2377.     if ((int)vid_mode.value != vid_realmode)
  2378.     {
  2379.       VID_SetMode ((int)vid_mode.value, vid_curpal);
  2380.       Cvar_SetValue ("vid_mode", (float)vid_modenum);
  2381.                 // so if mode set fails, we don't keep on
  2382.                 //  trying to set that mode
  2383.       vid_realmode = vid_modenum;
  2384.     }
  2385.   }
  2386.  
  2387. // handle the mouse state when windowed if that's changed
  2388.   if (modestate == MS_WINDOWED)
  2389.   {
  2390.     if ((int)_windowed_mouse.value != windowed_mouse)
  2391.     {
  2392.       if (_windowed_mouse.value)
  2393.       {
  2394.         IN_ActivateMouse ();
  2395.         IN_HideMouse ();
  2396.       }
  2397.       else
  2398.       {
  2399.         IN_DeactivateMouse ();
  2400.         IN_ShowMouse ();
  2401.       }
  2402.  
  2403.       windowed_mouse = (int)_windowed_mouse.value;
  2404.     }
  2405.   }
  2406. }
  2407.  
  2408.  
  2409. /*
  2410. ================
  2411. D_BeginDirectRect
  2412. ================
  2413. */
  2414. void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
  2415. {
  2416.   int   i, j, reps, repshift;
  2417.   vrect_t rect;
  2418.  
  2419.   if (!vid_initialized)
  2420.     return;
  2421.  
  2422.   if (vid.aspect > 1.5)
  2423.   {
  2424.     reps = 2;
  2425.     repshift = 1;
  2426.   }
  2427.   else
  2428.   {
  2429.     reps = 1;
  2430.     repshift = 0;
  2431.   }
  2432.  
  2433.   if (vid.numpages == 1)
  2434.   {
  2435.     VID_LockBuffer ();
  2436.  
  2437.     if (!vid.direct)
  2438.       Sys_Error ("NULL vid.direct pointer");
  2439.  
  2440.     for (i=0 ; i<(height << repshift) ; i += reps)
  2441.     {
  2442.       for (j=0 ; j<reps ; j++)
  2443.       {
  2444.         memcpy (&backingbuf[(i + j) * 24],
  2445.             vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
  2446.             width);
  2447.         memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
  2448.             &pbitmap[(i >> repshift) * width],
  2449.             width);
  2450.       }
  2451.     }
  2452.  
  2453.     VID_UnlockBuffer ();
  2454.  
  2455.     rect.x = x;
  2456.     rect.y = y;
  2457.     rect.width = width;
  2458.     rect.height = height << repshift;
  2459.     rect.pnext = NULL;
  2460.  
  2461.     FlipScreen (&rect);
  2462.   }
  2463.   else
  2464.   {
  2465.   // unlock if locked
  2466.     if (lockcount > 0)
  2467.       MGL_endDirectAccess();
  2468.  
  2469.   // set the active page to the displayed page
  2470.     MGL_setActivePage (mgldc, vPage);
  2471.  
  2472.   // lock the screen
  2473.     MGL_beginDirectAccess ();
  2474.  
  2475.   // save from and draw to screen
  2476.     for (i=0 ; i<(height << repshift) ; i += reps)
  2477.     {
  2478.       for (j=0 ; j<reps ; j++)
  2479.       {
  2480.         memcpy (&backingbuf[(i + j) * 24],
  2481.             (byte *)mgldc->surface + x +
  2482.              ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
  2483.             width);
  2484.         memcpy ((byte *)mgldc->surface + x +
  2485.              ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
  2486.             &pbitmap[(i >> repshift) * width],
  2487.             width);
  2488.       }
  2489.     }
  2490.  
  2491.   // unlock the screen
  2492.     MGL_endDirectAccess ();
  2493.  
  2494.   // restore the original active page
  2495.     MGL_setActivePage (mgldc, aPage);
  2496.  
  2497.   // relock the screen if it was locked
  2498.     if (lockcount > 0)
  2499.       MGL_beginDirectAccess();
  2500.   }
  2501. }
  2502.  
  2503.  
  2504. /*
  2505. ================
  2506. D_EndDirectRect
  2507. ================
  2508. */
  2509. void D_EndDirectRect (int x, int y, int width, int height)
  2510. {
  2511.   int   i, j, reps, repshift;
  2512.   vrect_t rect;
  2513.  
  2514.   if (!vid_initialized)
  2515.     return;
  2516.  
  2517.   if (vid.aspect > 1.5)
  2518.   {
  2519.     reps = 2;
  2520.     repshift = 1;
  2521.   }
  2522.   else
  2523.   {
  2524.     reps = 1;
  2525.     repshift = 0;
  2526.   }
  2527.  
  2528.   if (vid.numpages == 1)
  2529.   {
  2530.     VID_LockBuffer ();
  2531.  
  2532.     if (!vid.direct)
  2533.       Sys_Error ("NULL vid.direct pointer");
  2534.  
  2535.     for (i=0 ; i<(height << repshift) ; i += reps)
  2536.     {
  2537.       for (j=0 ; j<reps ; j++)
  2538.       {
  2539.         memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
  2540.             &backingbuf[(i + j) * 24],
  2541.             width);
  2542.       }
  2543.     }
  2544.  
  2545.     VID_UnlockBuffer ();
  2546.  
  2547.     rect.x = x;
  2548.     rect.y = y;
  2549.     rect.width = width;
  2550.     rect.height = height << repshift;
  2551.     rect.pnext = NULL;
  2552.  
  2553.     FlipScreen (&rect);
  2554.   }
  2555.   else
  2556.   {
  2557.   // unlock if locked
  2558.     if (lockcount > 0)
  2559.       MGL_endDirectAccess();
  2560.  
  2561.   // set the active page to the displayed page
  2562.     MGL_setActivePage (mgldc, vPage);
  2563.  
  2564.   // lock the screen
  2565.     MGL_beginDirectAccess ();
  2566.  
  2567.   // restore to the screen
  2568.     for (i=0 ; i<(height << repshift) ; i += reps)
  2569.     {
  2570.       for (j=0 ; j<reps ; j++)
  2571.       {
  2572.         memcpy ((byte *)mgldc->surface + x +
  2573.              ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
  2574.             &backingbuf[(i + j) * 24],
  2575.             width);
  2576.       }
  2577.     }
  2578.  
  2579.   // unlock the screen
  2580.     MGL_endDirectAccess ();
  2581.  
  2582.   // restore the original active page
  2583.     MGL_setActivePage (mgldc, aPage);
  2584.  
  2585.   // relock the screen if it was locked
  2586.     if (lockcount > 0)
  2587.       MGL_beginDirectAccess();
  2588.   }
  2589. }
  2590.  
  2591.  
  2592. //==========================================================================
  2593.  
  2594. byte        scantokey[128] = 
  2595.           { 
  2596. //  0           1       2       3       4       5       6       7 
  2597. //  8           9       A       B       C       D       E       F 
  2598.   0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6', 
  2599.   '7',    '8',    '9',    '0',    '-',    '=',    K_BACKSPACE, 9, // 0 
  2600.   'q',    'w',    'e',    'r',    't',    'y',    'u',    'i', 
  2601.   'o',    'p',    '[',    ']',    13 ,    K_CTRL,'a',  's',      // 1 
  2602.   'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';', 
  2603.   '\'' ,    '`',    K_SHIFT,'\\',  'z',    'x',    'c',    'v',      // 2 
  2604.   'b',    'n',    'm',    ',',    '.',    '/',    K_SHIFT,'*', 
  2605.   K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3 
  2606.   K_F6, K_F7, K_F8, K_F9, K_F10,  K_PAUSE,    0  , K_HOME, 
  2607.   K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4 
  2608.   K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0,             0,              K_F11, 
  2609.   K_F12,0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 5
  2610.   0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  2611.   0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,        // 6 
  2612.   0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0, 
  2613.   0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7 
  2614. }; 
  2615.  
  2616. /*
  2617. =======
  2618. MapKey
  2619.  
  2620. Map from windows to quake keynums
  2621. =======
  2622. */
  2623. int MapKey (int key)
  2624. {
  2625.   key = (key>>16)&255;
  2626.   if (key > 127)
  2627.     return 0;
  2628.  
  2629.   return scantokey[key];
  2630. }
  2631.  
  2632. void AppActivate(BOOL fActive, BOOL minimize)
  2633. /****************************************************************************
  2634. *
  2635. * Function:     AppActivate
  2636. * Parameters:   fActive - True if app is activating
  2637. *
  2638. * Description:  If the application is activating, then swap the system
  2639. *               into SYSPAL_NOSTATIC mode so that our palettes will display
  2640. *               correctly.
  2641. *
  2642. ****************************************************************************/
  2643. {
  2644.     HDC     hdc;
  2645.     int     i, t;
  2646.   static BOOL sound_active;
  2647.  
  2648.   ActiveApp = fActive;
  2649.  
  2650. // messy, but it seems to work
  2651.   if (vid_fulldib_on_focus_mode)
  2652.   {
  2653.     Minimized = minimize;
  2654.  
  2655.     if (Minimized)
  2656.       ActiveApp = false;
  2657.   }
  2658.  
  2659.   MGL_appActivate(windc, ActiveApp);
  2660.  
  2661.   if (vid_initialized)
  2662.   {
  2663.   // yield the palette if we're losing the focus
  2664.     hdc = GetDC(NULL);
  2665.  
  2666.     if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  2667.     {
  2668.       if (ActiveApp)
  2669.       {
  2670.         if ((modestate == MS_WINDOWED) || (modestate == MS_FULLDIB))
  2671.         {
  2672.           if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC)
  2673.           {
  2674.           // switch to SYSPAL_NOSTATIC and remap the colors
  2675.             SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
  2676.             syscolchg = true;
  2677.             pal_is_nostatic = true;
  2678.           }
  2679.         }
  2680.       }
  2681.       else if (pal_is_nostatic)
  2682.       {
  2683.         if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC)
  2684.         {
  2685.         // switch back to SYSPAL_STATIC and the old mapping
  2686.           SetSystemPaletteUse(hdc, SYSPAL_STATIC);
  2687.           syscolchg = true;
  2688.         }
  2689.  
  2690.         pal_is_nostatic = false;
  2691.       }
  2692.     }
  2693.  
  2694.     if (!Minimized)
  2695.       VID_SetPalette (vid_curpal);
  2696.  
  2697.     scr_fullupdate = 0;
  2698.  
  2699.     ReleaseDC(NULL,hdc);
  2700.   }
  2701.  
  2702. // enable/disable sound on focus gain/loss
  2703.   if (!ActiveApp && sound_active)
  2704.   {
  2705.     S_BlockSound ();
  2706.     S_ClearBuffer ();
  2707.     sound_active = false;
  2708.   }
  2709.   else if (ActiveApp && !sound_active)
  2710.   {
  2711.     S_UnblockSound ();
  2712.     S_ClearBuffer ();
  2713.     sound_active = true;
  2714.   }
  2715.  
  2716. // minimize/restore fulldib windows/mouse-capture normal windows on demand
  2717.   if (!in_mode_set)
  2718.   {
  2719.     if (ActiveApp)
  2720.     {
  2721.       if (vid_fulldib_on_focus_mode)
  2722.       {
  2723.         if (vid_initialized)
  2724.         {
  2725.           msg_suppress_1 = true;  // don't want to see normal mode set message
  2726.           VID_SetMode (vid_fulldib_on_focus_mode, vid_curpal);
  2727.           msg_suppress_1 = false;
  2728.  
  2729.           t = in_mode_set;
  2730.           in_mode_set = true;
  2731.           AppActivate (true, false);
  2732.           in_mode_set = t;
  2733.         }
  2734.  
  2735.         IN_ActivateMouse ();
  2736.         IN_HideMouse ();
  2737.       }
  2738.       else if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
  2739.       {
  2740.         IN_ActivateMouse ();
  2741.         IN_HideMouse ();
  2742.       }
  2743.     }
  2744.  
  2745.     if (!ActiveApp)
  2746.     {
  2747.       if (modestate == MS_FULLDIB)
  2748.       {
  2749.         if (vid_initialized)
  2750.         {
  2751.           force_minimized = true;
  2752.           i = vid_fulldib_on_focus_mode;
  2753.           msg_suppress_1 = true;  // don't want to see normal mode set message
  2754.           VID_SetMode (windowed_default, vid_curpal);
  2755.           msg_suppress_1 = false;
  2756.           vid_fulldib_on_focus_mode = i;
  2757.           force_minimized = false;
  2758.  
  2759.         // we never seem to get WM_ACTIVATE inactive from this mode set, so we'll
  2760.         // do it manually
  2761.           t = in_mode_set;
  2762.           in_mode_set = true;
  2763.           AppActivate (false, true);
  2764.           in_mode_set = t;
  2765.         }
  2766.  
  2767.         IN_DeactivateMouse ();
  2768.         IN_ShowMouse ();
  2769.       }
  2770.       else if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
  2771.       {
  2772.         IN_DeactivateMouse ();
  2773.         IN_ShowMouse ();
  2774.       }
  2775.     }
  2776.   }
  2777. }
  2778.  
  2779.  
  2780. /*
  2781. ================
  2782. VID_HandlePause
  2783. ================
  2784. */
  2785. void VID_HandlePause (qboolean pause)
  2786. {
  2787.  
  2788.   if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
  2789.   {
  2790.     if (pause)
  2791.     {
  2792.       IN_DeactivateMouse ();
  2793.       IN_ShowMouse ();
  2794.     }
  2795.     else
  2796.     {
  2797.       IN_ActivateMouse ();
  2798.       IN_HideMouse ();
  2799.     }
  2800.   }
  2801. }
  2802.  
  2803.  
  2804. /*
  2805. ===================================================================
  2806.  
  2807. MAIN WINDOW
  2808.  
  2809. ===================================================================
  2810. */
  2811.  
  2812. LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  2813.  
  2814. /* main window procedure */
  2815. LONG WINAPI MainWndProc (
  2816.     HWND    hWnd,
  2817.     UINT    uMsg,
  2818.     WPARAM  wParam,
  2819.     LPARAM  lParam)
  2820. {
  2821.   LONG      lRet = 0;
  2822.   int       fwKeys, xPos, yPos, fActive, fMinimized, temp;
  2823.   HDC       hdc;
  2824.   PAINTSTRUCT   ps;
  2825.   static int    recursiveflag;
  2826.  
  2827.   switch (uMsg)
  2828.   {
  2829.     case WM_CREATE:
  2830.       break;
  2831.  
  2832.     case WM_SYSCOMMAND:
  2833.  
  2834.     // Check for maximize being hit
  2835.       switch (wParam & ~0x0F)
  2836.       {
  2837.         case SC_MAXIMIZE:
  2838.         // if minimized, bring up as a window before going fullscreen,
  2839.         // so MGL will have the right state to restore
  2840.           if (Minimized)
  2841.           {
  2842.             force_mode_set = true;
  2843.             VID_SetMode (vid_modenum, vid_curpal);
  2844.             force_mode_set = false;
  2845.           }
  2846.  
  2847.           VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal);
  2848.           break;
  2849.  
  2850.                 case SC_SCREENSAVE:
  2851.                 case SC_MONITORPOWER:
  2852.           if (modestate != MS_WINDOWED)
  2853.           {
  2854.           // don't call DefWindowProc() because we don't want to start
  2855.           // the screen saver fullscreen
  2856.             break;
  2857.           }
  2858.  
  2859.         // fall through windowed and allow the screen saver to start
  2860.  
  2861.         default:
  2862.           if (!in_mode_set)
  2863.           {
  2864.             S_BlockSound ();
  2865.             S_ClearBuffer ();
  2866.           }
  2867.  
  2868.           lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
  2869.  
  2870.           if (!in_mode_set)
  2871.           {
  2872.             S_UnblockSound ();
  2873.           }
  2874.       }
  2875.       break;
  2876.  
  2877.     case WM_MOVE:
  2878.       window_x = (int) LOWORD(lParam);
  2879.       window_y = (int) HIWORD(lParam);
  2880.       VID_UpdateWindowStatus ();
  2881.  
  2882.       if ((modestate == MS_WINDOWED) && !in_mode_set && !Minimized)
  2883.         VID_RememberWindowPos ();
  2884.  
  2885.       break;
  2886.  
  2887.     case WM_SIZE:
  2888.       Minimized = false;
  2889.       
  2890.       if (!(wParam & SIZE_RESTORED))
  2891.       {
  2892.         if (wParam & SIZE_MINIMIZED)
  2893.           Minimized = true;
  2894.       }
  2895.       break;
  2896.  
  2897.     case WM_SYSCHAR:
  2898.     // keep Alt-Space from happening
  2899.       break;
  2900.  
  2901.     case WM_ACTIVATE:
  2902.       fActive = LOWORD(wParam);
  2903.       fMinimized = (BOOL) HIWORD(wParam);
  2904.       AppActivate(!(fActive == WA_INACTIVE), fMinimized);
  2905.  
  2906.     // fix the leftover Alt from any Alt-Tab or the like that switched us away
  2907.       ClearAllStates ();
  2908.  
  2909.       if (!in_mode_set)
  2910.       {
  2911.         if (windc)
  2912.           MGL_activatePalette(windc,true);
  2913.  
  2914.         VID_SetPalette(vid_curpal);
  2915.       }
  2916.  
  2917.       break;
  2918.  
  2919.     case WM_PAINT:
  2920.       hdc = BeginPaint(hWnd, &ps);
  2921.  
  2922.       if (!in_mode_set && host_initialized)
  2923.         SCR_UpdateWholeScreen ();
  2924.  
  2925.       EndPaint(hWnd, &ps);
  2926.       break;
  2927.  
  2928.     case WM_KEYDOWN:
  2929.     case WM_SYSKEYDOWN:
  2930.       if (!in_mode_set)
  2931.         Key_Event (MapKey(lParam), true);
  2932.       break;
  2933.  
  2934.     case WM_KEYUP:
  2935.     case WM_SYSKEYUP:
  2936.       if (!in_mode_set)
  2937.         Key_Event (MapKey(lParam), false);
  2938.       break;
  2939.  
  2940.   // this is complicated because Win32 seems to pack multiple mouse events into
  2941.   // one update sometimes, so we always check all states and look for events
  2942.     case WM_LBUTTONDOWN:
  2943.     case WM_LBUTTONUP:
  2944.     case WM_RBUTTONDOWN:
  2945.     case WM_RBUTTONUP:
  2946.     case WM_MBUTTONDOWN:
  2947.     case WM_MBUTTONUP:
  2948.     case WM_MOUSEMOVE:
  2949.       if (!in_mode_set)
  2950.       {
  2951.         temp = 0;
  2952.  
  2953.         if (wParam & MK_LBUTTON)
  2954.           temp |= 1;
  2955.  
  2956.         if (wParam & MK_RBUTTON)
  2957.           temp |= 2;
  2958.  
  2959.         if (wParam & MK_MBUTTON)
  2960.           temp |= 4;
  2961.  
  2962.         IN_MouseEvent (temp);
  2963.       }
  2964.       break;
  2965.  
  2966.     // JACK: This is the mouse wheel with the Intellimouse
  2967.     // Its delta is either positive or neg, and we generate the proper
  2968.     // Event.
  2969.     case WM_MOUSEWHEEL: 
  2970.       if ((short) HIWORD(wParam) > 0) {
  2971.         Key_Event(K_MWHEELUP, true);
  2972.         Key_Event(K_MWHEELUP, false);
  2973.       } else {
  2974.         Key_Event(K_MWHEELDOWN, true);
  2975.         Key_Event(K_MWHEELDOWN, false);
  2976.       }
  2977.       break;
  2978.     // KJB: Added these new palette functions
  2979.     case WM_PALETTECHANGED:
  2980.       if ((HWND)wParam == hWnd)
  2981.         break;
  2982.       /* Fall through to WM_QUERYNEWPALETTE */
  2983.     case WM_QUERYNEWPALETTE:
  2984.       hdc = GetDC(NULL);
  2985.  
  2986.       if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  2987.         vid_palettized = true;
  2988.       else
  2989.         vid_palettized = false;
  2990.  
  2991.       ReleaseDC(NULL,hdc);
  2992.  
  2993.       scr_fullupdate = 0;
  2994.  
  2995.       if (vid_initialized && !in_mode_set && windc && MGL_activatePalette(windc,false) && !Minimized)
  2996.       {
  2997.         VID_SetPalette (vid_curpal);
  2998.         InvalidateRect (mainwindow, NULL, false);
  2999.  
  3000.       // specifically required if WM_QUERYNEWPALETTE realizes a new palette
  3001.         lRet = TRUE;
  3002.       }
  3003.       break;
  3004.  
  3005.     case WM_DISPLAYCHANGE:
  3006.       if (!in_mode_set && (modestate == MS_WINDOWED) && !vid_fulldib_on_focus_mode)
  3007.       {
  3008.         force_mode_set = true;
  3009.         VID_SetMode (vid_modenum, vid_curpal);
  3010.         force_mode_set = false;
  3011.       }
  3012.       break;
  3013.  
  3014.         case WM_CLOSE:
  3015.     // this causes Close in the right-click task bar menu not to work, but right
  3016.     // now bad things happen if Close is handled in that case (garbage and a
  3017.     // crash on Win95)
  3018.       if (!in_mode_set)
  3019.       {
  3020.         if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit",
  3021.               MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
  3022.         {
  3023.           Sys_Quit ();
  3024.         }
  3025.       }
  3026.       break;
  3027.  
  3028.     case MM_MCINOTIFY:
  3029.             lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
  3030.       break;
  3031.  
  3032.     default:
  3033.             /* pass all unhandled messages to DefWindowProc */
  3034.             lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
  3035.           break;
  3036.     }
  3037.  
  3038.     /* return 0 if handled message, 1 if not */
  3039.     return lRet;
  3040. }
  3041.  
  3042.  
  3043. extern void M_Menu_Options_f (void);
  3044. extern void M_Print (int cx, int cy, char *str);
  3045. extern void M_PrintWhite (int cx, int cy, char *str);
  3046. extern void M_DrawCharacter (int cx, int line, int num);
  3047. extern void M_DrawTransPic (int x, int y, qpic_t *pic);
  3048. extern void M_DrawPic (int x, int y, qpic_t *pic);
  3049.  
  3050. static int  vid_line, vid_wmodes;
  3051.  
  3052. typedef struct
  3053. {
  3054.   int   modenum;
  3055.   char  *desc;
  3056.   int   iscur;
  3057.   int   ismode13;
  3058.   int   width;
  3059. } modedesc_t;
  3060.  
  3061. #define MAX_COLUMN_SIZE   5
  3062. #define MODE_AREA_HEIGHT  (MAX_COLUMN_SIZE + 6)
  3063. #define MAX_MODEDESCS   (MAX_COLUMN_SIZE*3)
  3064.  
  3065. static modedesc_t modedescs[MAX_MODEDESCS];
  3066.  
  3067. /*
  3068. ================
  3069. VID_MenuDraw
  3070. ================
  3071. */
  3072. void VID_MenuDraw (void)
  3073. {
  3074.   qpic_t    *p;
  3075.   char    *ptr;
  3076.   int     lnummodes, i, j, k, column, row, dup, dupmode;
  3077.   char    temp[100];
  3078.   vmode_t   *pv;
  3079.   modedesc_t  tmodedesc;
  3080.  
  3081.   p = Draw_CachePic ("gfx/vidmodes.lmp");
  3082.   M_DrawPic ( (320-p->width)/2, 4, p);
  3083.  
  3084.   for (i=0 ; i<3 ; i++)
  3085.   {
  3086.     ptr = VID_GetModeDescriptionMemCheck (i);
  3087.     modedescs[i].modenum = modelist[i].modenum;
  3088.     modedescs[i].desc = ptr;
  3089.     modedescs[i].ismode13 = 0;
  3090.     modedescs[i].iscur = 0;
  3091.  
  3092.     if (vid_modenum == i)
  3093.       modedescs[i].iscur = 1;
  3094.   }
  3095.  
  3096.   vid_wmodes = 3;
  3097.   lnummodes = VID_NumModes ();
  3098.   
  3099.   for (i=3 ; i<lnummodes ; i++)
  3100.   {
  3101.     ptr = VID_GetModeDescriptionMemCheck (i);
  3102.     pv = VID_GetModePtr (i);
  3103.  
  3104.   // we only have room for 15 fullscreen modes, so don't allow
  3105.   // 360-wide modes, because if there are 5 320-wide modes and
  3106.   // 5 360-wide modes, we'll run out of space
  3107.     if (ptr && ((pv->width != 360) || COM_CheckParm("-allow360")))
  3108.     {
  3109.       dup = 0;
  3110.  
  3111.       for (j=3 ; j<vid_wmodes ; j++)
  3112.       {
  3113.         if (!strcmp (modedescs[j].desc, ptr))
  3114.         {
  3115.           dup = 1;
  3116.           dupmode = j;
  3117.           break;
  3118.         }
  3119.       }
  3120.  
  3121.       if (dup || (vid_wmodes < MAX_MODEDESCS))       
  3122.       {
  3123.         if (!dup || !modedescs[dupmode].ismode13 || COM_CheckParm("-noforcevga"))
  3124.         {
  3125.           if (dup)
  3126.           {
  3127.             k = dupmode;
  3128.           }
  3129.           else
  3130.           {
  3131.             k = vid_wmodes;
  3132.           }
  3133.  
  3134.           modedescs[k].modenum = i;
  3135.           modedescs[k].desc = ptr;
  3136.           modedescs[k].ismode13 = pv->mode13;
  3137.           modedescs[k].iscur = 0;
  3138.           modedescs[k].width = pv->width;
  3139.  
  3140.           if (i == vid_modenum)
  3141.             modedescs[k].iscur = 1;
  3142.  
  3143.           if (!dup)
  3144.             vid_wmodes++;
  3145.         }
  3146.       }
  3147.     }
  3148.   }
  3149.  
  3150. // sort the modes on width (to handle picking up oddball dibonly modes
  3151. // after all the others)
  3152.   for (i=3 ; i<(vid_wmodes-1) ; i++)
  3153.   {
  3154.     for (j=(i+1) ; j<vid_wmodes ; j++)
  3155.     {
  3156.       if (modedescs[i].width > modedescs[j].width)
  3157.       {
  3158.         tmodedesc = modedescs[i];
  3159.         modedescs[i] = modedescs[j];
  3160.         modedescs[j] = tmodedesc;
  3161.       }
  3162.     }
  3163.   }
  3164.  
  3165.  
  3166.   M_Print (13*8, 36, "Windowed Modes");
  3167.  
  3168.   column = 16;
  3169.   row = 36+2*8;
  3170.  
  3171.   for (i=0 ; i<3; i++)
  3172.   {
  3173.     if (modedescs[i].iscur)
  3174.       M_PrintWhite (column, row, modedescs[i].desc);
  3175.     else
  3176.       M_Print (column, row, modedescs[i].desc);
  3177.  
  3178.     column += 13*8;
  3179.   }
  3180.  
  3181.   if (vid_wmodes > 3)
  3182.   {
  3183.     M_Print (12*8, 36+4*8, "Fullscreen Modes");
  3184.  
  3185.     column = 16;
  3186.     row = 36+6*8;
  3187.  
  3188.     for (i=3 ; i<vid_wmodes ; i++)
  3189.     {
  3190.       if (modedescs[i].iscur)
  3191.         M_PrintWhite (column, row, modedescs[i].desc);
  3192.       else
  3193.         M_Print (column, row, modedescs[i].desc);
  3194.  
  3195.       column += 13*8;
  3196.  
  3197.       if (((i - 3) % VID_ROW_SIZE) == (VID_ROW_SIZE - 1))
  3198.       {
  3199.         column = 16;
  3200.         row += 8;
  3201.       }
  3202.     }
  3203.   }
  3204.  
  3205. // line cursor
  3206.   if (vid_testingmode)
  3207.   {
  3208.     sprintf (temp, "TESTING %s",
  3209.         modedescs[vid_line].desc);
  3210.     M_Print (13*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, temp);
  3211.     M_Print (9*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6,
  3212.         "Please wait 5 seconds...");
  3213.   }
  3214.   else
  3215.   {
  3216.     M_Print (9*8, 36 + MODE_AREA_HEIGHT * 8 + 8,
  3217.         "Press Enter to set mode");
  3218.     M_Print (6*8, 36 + MODE_AREA_HEIGHT * 8 + 8*3,
  3219.         "T to test mode for 5 seconds");
  3220.     ptr = VID_GetModeDescription2 (vid_modenum);
  3221.  
  3222.     if (ptr)
  3223.     {
  3224.       sprintf (temp, "D to set default: %s", ptr);
  3225.       M_Print (2*8, 36 + MODE_AREA_HEIGHT * 8 + 8*5, temp);
  3226.     }
  3227.  
  3228.     ptr = VID_GetModeDescription2 ((int)_vid_default_mode_win.value);
  3229.  
  3230.     if (ptr)
  3231.     {
  3232.       sprintf (temp, "Current default: %s", ptr);
  3233.       M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, temp);
  3234.     }
  3235.  
  3236.     M_Print (15*8, 36 + MODE_AREA_HEIGHT * 8 + 8*8,
  3237.         "Esc to exit");
  3238.  
  3239.     row = 36 + 2*8 + (vid_line / VID_ROW_SIZE) * 8;
  3240.     column = 8 + (vid_line % VID_ROW_SIZE) * 13*8;
  3241.  
  3242.     if (vid_line >= 3)
  3243.       row += 3*8;
  3244.  
  3245.     M_DrawCharacter (column, row, 12+((int)(realtime*4)&1));
  3246.   }
  3247. }
  3248.  
  3249.  
  3250. /*
  3251. ================
  3252. VID_MenuKey
  3253. ================
  3254. */
  3255. void VID_MenuKey (int key)
  3256. {
  3257.   if (vid_testingmode)
  3258.     return;
  3259.  
  3260.   switch (key)
  3261.   {
  3262.   case K_ESCAPE:
  3263.     S_LocalSound ("misc/menu1.wav");
  3264.     M_Menu_Options_f ();
  3265.     break;
  3266.  
  3267.   case K_LEFTARROW:
  3268.     S_LocalSound ("misc/menu1.wav");
  3269.     vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) +
  3270.            ((vid_line + 2) % VID_ROW_SIZE);
  3271.  
  3272.     if (vid_line >= vid_wmodes)
  3273.       vid_line = vid_wmodes - 1;
  3274.     break;
  3275.  
  3276.   case K_RIGHTARROW:
  3277.     S_LocalSound ("misc/menu1.wav");
  3278.     vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) +
  3279.            ((vid_line + 4) % VID_ROW_SIZE);
  3280.  
  3281.     if (vid_line >= vid_wmodes)
  3282.       vid_line = (vid_line / VID_ROW_SIZE) * VID_ROW_SIZE;
  3283.     break;
  3284.  
  3285.   case K_UPARROW:
  3286.     S_LocalSound ("misc/menu1.wav");
  3287.     vid_line -= VID_ROW_SIZE;
  3288.  
  3289.     if (vid_line < 0)
  3290.     {
  3291.       vid_line += ((vid_wmodes + (VID_ROW_SIZE - 1)) /
  3292.           VID_ROW_SIZE) * VID_ROW_SIZE;
  3293.  
  3294.       while (vid_line >= vid_wmodes)
  3295.         vid_line -= VID_ROW_SIZE;
  3296.     }
  3297.     break;
  3298.  
  3299.   case K_DOWNARROW:
  3300.     S_LocalSound ("misc/menu1.wav");
  3301.     vid_line += VID_ROW_SIZE;
  3302.  
  3303.     if (vid_line >= vid_wmodes)
  3304.     {
  3305.       vid_line -= ((vid_wmodes + (VID_ROW_SIZE - 1)) /
  3306.           VID_ROW_SIZE) * VID_ROW_SIZE;
  3307.  
  3308.       while (vid_line < 0)
  3309.         vid_line += VID_ROW_SIZE;
  3310.     }
  3311.     break;
  3312.  
  3313.   case K_ENTER:
  3314.     S_LocalSound ("misc/menu1.wav");
  3315.     VID_SetMode (modedescs[vid_line].modenum, vid_curpal);
  3316.     break;
  3317.  
  3318.   case 'T':
  3319.   case 't':
  3320.     S_LocalSound ("misc/menu1.wav");
  3321.   // have to set this before setting the mode because WM_PAINT
  3322.   // happens during the mode set and does a VID_Update, which
  3323.   // checks vid_testingmode
  3324.     vid_testingmode = 1;
  3325.     vid_testendtime = realtime + 5.0;
  3326.  
  3327.     if (!VID_SetMode (modedescs[vid_line].modenum, vid_curpal))
  3328.     {
  3329.       vid_testingmode = 0;
  3330.     }
  3331.     break;
  3332.  
  3333.   case 'D':
  3334.   case 'd':
  3335.     S_LocalSound ("misc/menu1.wav");
  3336.     firstupdate = 0;
  3337.     Cvar_SetValue ("_vid_default_mode_win", vid_modenum);
  3338.     break;
  3339.  
  3340.   default:
  3341.     break;
  3342.   }
  3343. }
  3344.