Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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