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