home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / vid_win.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  74.9 KB  |  3,392 lines

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