aboutsummaryrefslogtreecommitdiffstats
path: root/QW/client/vid_win.c
diff options
context:
space:
mode:
Diffstat (limited to 'QW/client/vid_win.c')
-rw-r--r--QW/client/vid_win.c3391
1 files changed, 3391 insertions, 0 deletions
diff --git a/QW/client/vid_win.c b/QW/client/vid_win.c
new file mode 100644
index 0000000..0194362
--- /dev/null
+++ b/QW/client/vid_win.c
@@ -0,0 +1,3391 @@
+/*
+Copyright (C) 1996-1997 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+// vid_win.c -- Win32 video driver
+
+#include "quakedef.h"
+#include "winquake.h"
+#include "d_local.h"
+#include "resource.h"
+
+#define MINIMUM_MEMORY 0x550000
+
+#define MAX_MODE_LIST 30
+#define VID_ROW_SIZE 3
+
+qboolean dibonly;
+
+extern int Minimized;
+
+HWND mainwindow;
+
+HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow);
+
+int DIBWidth, DIBHeight;
+qboolean DDActive;
+RECT WindowRect;
+DWORD WindowStyle, ExWindowStyle;
+
+int window_center_x, window_center_y, window_x, window_y, window_width, window_height;
+RECT window_rect;
+
+static DEVMODE gdevmode;
+static qboolean startwindowed = 0, windowed_mode_set;
+static int firstupdate = 1;
+static qboolean vid_initialized = false, vid_palettized;
+static int lockcount;
+static int vid_fulldib_on_focus_mode;
+static qboolean force_minimized, in_mode_set, is_mode0x13, force_mode_set;
+static int vid_stretched, windowed_mouse;
+static qboolean palette_changed, syscolchg, vid_mode_set, hide_window, pal_is_nostatic;
+static HICON hIcon;
+
+qboolean mouseactive; // from in_win.c
+
+viddef_t vid; // global video state
+
+#define MODE_WINDOWED 0
+#define MODE_SETTABLE_WINDOW 2
+#define NO_MODE (MODE_WINDOWED - 1)
+#define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 3)
+
+// Note that 0 is MODE_WINDOWED
+cvar_t vid_mode = {"vid_mode","0", false};
+// Note that 0 is MODE_WINDOWED
+cvar_t _vid_default_mode = {"_vid_default_mode","0", true};
+// Note that 3 is MODE_FULLSCREEN_DEFAULT
+cvar_t _vid_default_mode_win = {"_vid_default_mode_win","3", true};
+cvar_t vid_wait = {"vid_wait","0"};
+cvar_t vid_nopageflip = {"vid_nopageflip","0", true};
+cvar_t _vid_wait_override = {"_vid_wait_override", "0", true};
+cvar_t vid_config_x = {"vid_config_x","800", true};
+cvar_t vid_config_y = {"vid_config_y","600", true};
+cvar_t vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
+cvar_t _windowed_mouse = {"_windowed_mouse","0", true};
+cvar_t vid_fullscreen_mode = {"vid_fullscreen_mode","3", true};
+cvar_t vid_windowed_mode = {"vid_windowed_mode","0", true};
+cvar_t block_switch = {"block_switch","0", true};
+cvar_t vid_window_x = {"vid_window_x", "0", true};
+cvar_t vid_window_y = {"vid_window_y", "0", true};
+
+typedef struct {
+ int width;
+ int height;
+} lmode_t;
+
+lmode_t lowresmodes[] = {
+ {320, 200},
+ {320, 240},
+ {400, 300},
+ {512, 384},
+};
+
+int vid_modenum = NO_MODE;
+int vid_testingmode, vid_realmode;
+double vid_testendtime;
+int vid_default = MODE_WINDOWED;
+static int windowed_default;
+
+modestate_t modestate = MS_UNINIT;
+
+static byte *vid_surfcache;
+static int vid_surfcachesize;
+static int VID_highhunkmark;
+
+unsigned char vid_curpal[256*3];
+
+unsigned short d_8to16table[256];
+unsigned d_8to24table[256];
+
+int driver = grDETECT,mode;
+bool useWinDirect = true, useDirectDraw = true;
+MGLDC *mgldc = NULL,*memdc = NULL,*dibdc = NULL,*windc = NULL;
+
+typedef struct {
+ modestate_t type;
+ int width;
+ int height;
+ int modenum;
+ int mode13;
+ int stretched;
+ int dib;
+ int fullscreen;
+ int bpp;
+ int halfscreen;
+ char modedesc[13];
+} vmode_t;
+
+static vmode_t modelist[MAX_MODE_LIST];
+static int nummodes;
+static vmode_t *pcurrentmode;
+
+int aPage; // Current active display page
+int vPage; // Current visible display page
+int waitVRT = true; // True to wait for retrace on flip
+
+static vmode_t badmode;
+
+static byte backingbuf[48*24];
+
+void VID_MenuDraw (void);
+void VID_MenuKey (int key);
+
+LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+void AppActivate(BOOL fActive, BOOL minimize);
+
+
+/*
+================
+VID_RememberWindowPos
+================
+*/
+void VID_RememberWindowPos (void)
+{
+ RECT rect;
+
+ if (GetWindowRect (mainwindow, &rect))
+ {
+ if ((rect.left < GetSystemMetrics (SM_CXSCREEN)) &&
+ (rect.top < GetSystemMetrics (SM_CYSCREEN)) &&
+ (rect.right > 0) &&
+ (rect.bottom > 0))
+ {
+ Cvar_SetValue ("vid_window_x", (float)rect.left);
+ Cvar_SetValue ("vid_window_y", (float)rect.top);
+ }
+ }
+}
+
+
+/*
+================
+VID_CheckWindowXY
+================
+*/
+void VID_CheckWindowXY (void)
+{
+
+ if (((int)vid_window_x.value > (GetSystemMetrics (SM_CXSCREEN) - 160)) ||
+ ((int)vid_window_y.value > (GetSystemMetrics (SM_CYSCREEN) - 120)) ||
+ ((int)vid_window_x.value < 0) ||
+ ((int)vid_window_y.value < 0))
+ {
+ Cvar_SetValue ("vid_window_x", 0.0);
+ Cvar_SetValue ("vid_window_y", 0.0 );
+ }
+}
+
+
+/*
+================
+VID_UpdateWindowStatus
+================
+*/
+void VID_UpdateWindowStatus (void)
+{
+
+ window_rect.left = window_x;
+ window_rect.top = window_y;
+ window_rect.right = window_x + window_width;
+ window_rect.bottom = window_y + window_height;
+ window_center_x = (window_rect.left + window_rect.right) / 2;
+ window_center_y = (window_rect.top + window_rect.bottom) / 2;
+
+ IN_UpdateClipCursor ();
+}
+
+
+/*
+================
+ClearAllStates
+================
+*/
+void ClearAllStates (void)
+{
+ int i;
+
+// send an up event for each key, to make sure the server clears them all
+ for (i=0 ; i<256 ; i++)
+ {
+ Key_Event (i, false);
+ }
+
+ Key_ClearStates ();
+ IN_ClearStates ();
+}
+
+
+/*
+================
+VID_CheckAdequateMem
+================
+*/
+qboolean VID_CheckAdequateMem (int width, int height)
+{
+ int tbuffersize;
+
+ tbuffersize = width * height * sizeof (*d_pzbuffer);
+
+ tbuffersize += D_SurfaceCacheForRes (width, height);
+
+// see if there's enough memory, allowing for the normal mode 0x13 pixel,
+// z, and surface buffers
+ if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
+ 0x10000 * 3) < MINIMUM_MEMORY)
+ {
+ return false; // not enough memory for mode
+ }
+
+ return true;
+}
+
+
+/*
+================
+VID_AllocBuffers
+================
+*/
+qboolean VID_AllocBuffers (int width, int height)
+{
+ int tsize, tbuffersize;
+
+ tbuffersize = width * height * sizeof (*d_pzbuffer);
+
+ tsize = D_SurfaceCacheForRes (width, height);
+
+ tbuffersize += tsize;
+
+// see if there's enough memory, allowing for the normal mode 0x13 pixel,
+// z, and surface buffers
+ if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
+ 0x10000 * 3) < MINIMUM_MEMORY)
+ {
+ Con_SafePrintf ("Not enough memory for video mode\n");
+ return false; // not enough memory for mode
+ }
+
+ vid_surfcachesize = tsize;
+
+ if (d_pzbuffer)
+ {
+ D_FlushCaches ();
+ Hunk_FreeToHighMark (VID_highhunkmark);
+ d_pzbuffer = NULL;
+ }
+
+ VID_highhunkmark = Hunk_HighMark ();
+
+ d_pzbuffer = Hunk_HighAllocName (tbuffersize, "video");
+
+ vid_surfcache = (byte *)d_pzbuffer +
+ width * height * sizeof (*d_pzbuffer);
+
+ return true;
+}
+
+
+void initFatalError(void)
+{
+ MGL_exit();
+ MGL_fatalError(MGL_errorMsg(MGL_result()));
+ exit(EXIT_FAILURE);
+}
+
+#if 0 //def NEW_SUSPEND
+
+int VID_Suspend (MGLDC *dc, int flags)
+{
+ int i;
+ if (flags & MGL_DEACTIVATE)
+ {
+ IN_RestoreOriginalMouseState ();
+ CDAudio_Pause ();
+
+ // keep WM_PAINT from trying to redraw
+ in_mode_set = true;
+ block_drawing = true;
+ }
+ else if (flags & MGL_REACTIVATE)
+ {
+ IN_SetQuakeMouseState ();
+ // fix the leftover Alt from any Alt-Tab or the like that switched us away
+ ClearAllStates ();
+ CDAudio_Resume ();
+ in_mode_set = false;
+
+ block_drawing = false;
+// vid.recalc_refdef = 1;
+ force_mode_set = 1;
+ i = msg_suppress_1;
+ msg_suppress_1 = 1;
+ VID_Fullscreen_f();
+ msg_suppress_1 = i;
+ force_mode_set = 0;
+ }
+
+ return 1;
+}
+
+#else
+
+int VID_Suspend (MGLDC *dc, int flags)
+{
+
+ if (flags & MGL_DEACTIVATE)
+ {
+ // FIXME: this doesn't currently work on NT
+ if (block_switch.value && !WinNT)
+ {
+ return MGL_NO_DEACTIVATE;
+ }
+
+ S_BlockSound ();
+ S_ClearBuffer ();
+
+ IN_RestoreOriginalMouseState ();
+ CDAudio_Pause ();
+
+ // keep WM_PAINT from trying to redraw
+ in_mode_set = true;
+
+ block_drawing = true; // so we don't try to draw while switched away
+
+ return MGL_NO_SUSPEND_APP;
+ }
+ else if (flags & MGL_REACTIVATE)
+ {
+ IN_SetQuakeMouseState ();
+ // fix the leftover Alt from any Alt-Tab or the like that switched us away
+ ClearAllStates ();
+ CDAudio_Resume ();
+ S_UnblockSound ();
+
+ in_mode_set = false;
+
+ vid.recalc_refdef = 1;
+
+ block_drawing = false;
+
+ return MGL_NO_SUSPEND_APP;
+ }
+
+}
+#endif
+
+
+void registerAllDispDrivers(void)
+{
+ /* Event though these driver require WinDirect, we register
+ * them so that they will still be available even if DirectDraw
+ * is present and the user has disable the high performance
+ * WinDirect modes.
+ */
+ MGL_registerDriver(MGL_VGA8NAME,VGA8_driver);
+// MGL_registerDriver(MGL_VGAXNAME,VGAX_driver);
+
+ /* Register display drivers */
+ if (useWinDirect)
+ {
+//we don't want VESA 1.X drivers MGL_registerDriver(MGL_SVGA8NAME,SVGA8_driver);
+ MGL_registerDriver(MGL_LINEAR8NAME,LINEAR8_driver);
+
+ if (!COM_CheckParm ("-novbeaf"))
+ MGL_registerDriver(MGL_ACCEL8NAME,ACCEL8_driver);
+ }
+
+ if (useDirectDraw)
+ {
+ MGL_registerDriver(MGL_DDRAW8NAME,DDRAW8_driver);
+ }
+}
+
+
+void registerAllMemDrivers(void)
+{
+ /* Register memory context drivers */
+ MGL_registerDriver(MGL_PACKED8NAME,PACKED8_driver);
+}
+
+
+void VID_InitMGLFull (HINSTANCE hInstance)
+{
+ int i, xRes, yRes, bits, vMode, lowres, curmode, temp;
+ int lowstretchedres, stretchedmode, lowstretched;
+ uchar *m;
+
+// FIXME: NT is checked for because MGL currently has a bug that causes it
+// to try to use WinDirect modes even on NT
+ if (COM_CheckParm("-nowindirect") ||
+ COM_CheckParm("-nowd") ||
+ COM_CheckParm("-novesa") ||
+ WinNT)
+ {
+ useWinDirect = false;
+ }
+
+ if (COM_CheckParm("-nodirectdraw") || COM_CheckParm("-noddraw") || COM_CheckParm("-nodd"))
+ useDirectDraw = false;
+
+ // Initialise the MGL
+ MGL_unregisterAllDrivers();
+ registerAllDispDrivers();
+ registerAllMemDrivers();
+ MGL_detectGraph(&driver,&mode);
+ m = MGL_availableModes();
+
+ if (m[0] != 0xFF)
+ {
+ lowres = lowstretchedres = 99999;
+ lowstretched = 0;
+ curmode = 0;
+
+ // find the lowest-res mode, or a mode we can stretch up to and get
+ // lowest-res that way
+ for (i = 0; m[i] != 0xFF; i++)
+ {
+ MGL_modeResolution(m[i], &xRes, &yRes,&bits);
+
+ if ((bits == 8) &&
+ (xRes <= MAXWIDTH) &&
+ (yRes <= MAXHEIGHT) &&
+ (curmode < MAX_MODE_LIST))
+ {
+ if (m[i] == grVGA_320x200x256)
+ is_mode0x13 = true;
+
+ if (!COM_CheckParm("-noforcevga"))
+ {
+ if (m[i] == grVGA_320x200x256)
+ {
+ mode = i;
+ break;
+ }
+ }
+
+ if (xRes < lowres)
+ {
+ lowres = xRes;
+ mode = i;
+ }
+
+ if ((xRes < lowstretchedres) && ((xRes >> 1) >= 320))
+ {
+ lowstretchedres = xRes >> 1;
+ stretchedmode = i;
+ }
+ }
+
+ curmode++;
+ }
+
+ // if there's a mode we can stretch by 2 up to, thereby effectively getting
+ // a lower-res mode than the lowest-res real but still at least 320x200, that
+ // will be our default mode
+ if (lowstretchedres < lowres)
+ {
+ mode = stretchedmode;
+ lowres = lowstretchedres;
+ lowstretched = 1;
+ }
+
+ // build the mode list, leaving room for the low-res stretched mode, if any
+ nummodes++; // leave room for default mode
+
+ for (i = 0; m[i] != 0xFF; i++)
+ {
+ MGL_modeResolution(m[i], &xRes, &yRes,&bits);
+
+ if ((bits == 8) &&
+ (xRes <= MAXWIDTH) &&
+ (yRes <= MAXHEIGHT) &&
+ (nummodes < MAX_MODE_LIST))
+ {
+ if (i == mode)
+ {
+ if (lowstretched)
+ {
+ stretchedmode = nummodes;
+ curmode = nummodes++;
+ }
+ else
+ {
+ curmode = MODE_FULLSCREEN_DEFAULT;
+ }
+ }
+ else
+ {
+ curmode = nummodes++;
+ }
+
+ modelist[curmode].type = MS_FULLSCREEN;
+ modelist[curmode].width = xRes;
+ modelist[curmode].height = yRes;
+ sprintf (modelist[curmode].modedesc, "%dx%d", xRes, yRes);
+
+ if (m[i] == grVGA_320x200x256)
+ modelist[curmode].mode13 = 1;
+ else
+ modelist[curmode].mode13 = 0;
+
+ modelist[curmode].modenum = m[i];
+ modelist[curmode].stretched = 0;
+ modelist[curmode].dib = 0;
+ modelist[curmode].fullscreen = 1;
+ modelist[curmode].halfscreen = 0;
+ modelist[curmode].bpp = 8;
+ }
+ }
+
+ if (lowstretched)
+ {
+ modelist[MODE_FULLSCREEN_DEFAULT] = modelist[stretchedmode];
+ modelist[MODE_FULLSCREEN_DEFAULT].stretched = 1;
+ modelist[MODE_FULLSCREEN_DEFAULT].width >>= 1;
+ modelist[MODE_FULLSCREEN_DEFAULT].height >>= 1;
+ sprintf (modelist[MODE_FULLSCREEN_DEFAULT].modedesc, "%dx%d",
+ modelist[MODE_FULLSCREEN_DEFAULT].width,
+ modelist[MODE_FULLSCREEN_DEFAULT].height);
+ }
+
+ vid_default = MODE_FULLSCREEN_DEFAULT;
+
+ temp = m[0];
+
+ if (!MGL_init(&driver, &temp, ""))
+ {
+ initFatalError();
+ }
+ }
+
+ MGL_setSuspendAppCallback(VID_Suspend);
+}
+
+
+MGLDC *createDisplayDC(int forcemem)
+/****************************************************************************
+*
+* Function: createDisplayDC
+* Returns: Pointer to the MGL device context to use for the application
+*
+* Description: Initialises the MGL and creates an appropriate display
+* device context to be used by the GUI. This creates and
+* apropriate device context depending on the system being
+* compile for, and should be the only place where system
+* specific code is required.
+*
+****************************************************************************/
+{
+ MGLDC *dc;
+ pixel_format_t pf;
+ int npages;
+
+ // Start the specified video mode
+ if (!MGL_changeDisplayMode(mode))
+ initFatalError();
+
+ npages = MGL_availablePages(mode);
+
+ if (npages > 3)
+ npages = 3;
+
+ if (!COM_CheckParm ("-notriplebuf"))
+ {
+ if (npages > 2)
+ {
+ npages = 2;
+ }
+ }
+
+ if ((dc = MGL_createDisplayDC(npages)) == NULL)
+ return NULL;
+
+ if (!forcemem && (MGL_surfaceAccessType(dc)) == MGL_LINEAR_ACCESS && (dc->mi.maxPage > 0))
+ {
+ MGL_makeCurrentDC(dc);
+ memdc = NULL;
+ }
+ else
+ {
+ // Set up for blitting from a memory buffer
+ memdc = MGL_createMemoryDC(MGL_sizex(dc)+1,MGL_sizey(dc)+1,8,&pf);
+ MGL_makeCurrentDC(memdc);
+ }
+
+ // Enable page flipping even for even for blitted surfaces
+ if (forcemem)
+ {
+ vid.numpages = 1;
+ }
+ else
+ {
+ vid.numpages = dc->mi.maxPage + 1;
+
+ if (vid.numpages > 1)
+ {
+ // Set up for page flipping
+ MGL_setActivePage(dc, aPage = 1);
+ MGL_setVisualPage(dc, vPage = 0, false);
+ }
+
+ if (vid.numpages > 3)
+ vid.numpages = 3;
+ }
+
+ if (vid.numpages == 2)
+ waitVRT = true;
+ else
+ waitVRT = false;
+
+ return dc;
+}
+
+
+void VID_InitMGLDIB (HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+ HDC hdc;
+ int i;
+
+ hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON2));
+
+ /* Register the frame class */
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = 0;
+ wc.hCursor = LoadCursor (NULL,IDC_ARROW);
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = "WinQuake";
+
+ if (!RegisterClass (&wc) )
+ Sys_Error ("Couldn't register window class");
+
+ /* Find the size for the DIB window */
+ /* Initialise the MGL for windowed operation */
+ MGL_setAppInstance(hInstance);
+ registerAllMemDrivers();
+ MGL_initWindowed("");
+
+ modelist[0].type = MS_WINDOWED;
+ modelist[0].width = 320;
+ modelist[0].height = 240;
+ strcpy (modelist[0].modedesc, "320x240");
+ modelist[0].mode13 = 0;
+ modelist[0].modenum = MODE_WINDOWED;
+ modelist[0].stretched = 0;
+ modelist[0].dib = 1;
+ modelist[0].fullscreen = 0;
+ modelist[0].halfscreen = 0;
+ modelist[0].bpp = 8;
+
+ modelist[1].type = MS_WINDOWED;
+ modelist[1].width = 640;
+ modelist[1].height = 480;
+ strcpy (modelist[1].modedesc, "640x480");
+ modelist[1].mode13 = 0;
+ modelist[1].modenum = MODE_WINDOWED + 1;
+ modelist[1].stretched = 1;
+ modelist[1].dib = 1;
+ modelist[1].fullscreen = 0;
+ modelist[1].halfscreen = 0;
+ modelist[1].bpp = 8;
+
+ modelist[2].type = MS_WINDOWED;
+ modelist[2].width = 800;
+ modelist[2].height = 600;
+ strcpy (modelist[2].modedesc, "800x600");
+ modelist[2].mode13 = 0;
+ modelist[2].modenum = MODE_WINDOWED + 2;
+ modelist[2].stretched = 1;
+ modelist[2].dib = 1;
+ modelist[2].fullscreen = 0;
+ modelist[2].halfscreen = 0;
+ modelist[2].bpp = 8;
+
+// automatically stretch the default mode up if > 640x480 desktop resolution
+ hdc = GetDC(NULL);
+
+ if ((GetDeviceCaps(hdc, HORZRES) > 640) && !COM_CheckParm("-noautostretch"))
+ {
+ vid_default = MODE_WINDOWED + 1;
+ }
+ else
+ {
+ vid_default = MODE_WINDOWED;
+ }
+
+ windowed_default = vid_default;
+
+ ReleaseDC(NULL,hdc);
+
+ nummodes = 3; // reserve space for windowed mode
+
+ DDActive = 0;
+}
+
+
+/*
+=================
+VID_InitFullDIB
+=================
+*/
+void VID_InitFullDIB (HINSTANCE hInstance)
+{
+ DEVMODE devmode;
+ int i, j, modenum, cmodes, existingmode, originalnummodes, lowestres;
+ int numlowresmodes, bpp, done;
+ int cstretch, istretch, mstretch;
+ BOOL stat;
+
+// enumerate 8 bpp modes
+ originalnummodes = nummodes;
+ modenum = 0;
+ lowestres = 99999;
+
+ do
+ {
+ stat = EnumDisplaySettings (NULL, modenum, &devmode);
+
+ if ((devmode.dmBitsPerPel == 8) &&
+ (devmode.dmPelsWidth <= MAXWIDTH) &&
+ (devmode.dmPelsHeight <= MAXHEIGHT) &&
+ (nummodes < MAX_MODE_LIST))
+ {
+ devmode.dmFields = DM_BITSPERPEL |
+ DM_PELSWIDTH |
+ DM_PELSHEIGHT;
+
+ if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
+ DISP_CHANGE_SUCCESSFUL)
+ {
+ modelist[nummodes].type = MS_FULLDIB;
+ modelist[nummodes].width = devmode.dmPelsWidth;
+ modelist[nummodes].height = devmode.dmPelsHeight;
+ modelist[nummodes].modenum = 0;
+ modelist[nummodes].mode13 = 0;
+ modelist[nummodes].stretched = 0;
+ modelist[nummodes].halfscreen = 0;
+ modelist[nummodes].dib = 1;
+ modelist[nummodes].fullscreen = 1;
+ modelist[nummodes].bpp = devmode.dmBitsPerPel;
+ sprintf (modelist[nummodes].modedesc, "%dx%d",
+ devmode.dmPelsWidth, devmode.dmPelsHeight);
+
+ // if the width is more than twice the height, reduce it by half because this
+ // is probably a dual-screen monitor
+ if (!COM_CheckParm("-noadjustaspect"))
+ {
+ if (modelist[nummodes].width > (modelist[nummodes].height << 1))
+ {
+ modelist[nummodes].width >>= 1;
+ modelist[nummodes].halfscreen = 1;
+ sprintf (modelist[nummodes].modedesc, "%dx%d",
+ modelist[nummodes].width,
+ modelist[nummodes].height);
+ }
+ }
+
+ for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
+ {
+ if ((modelist[nummodes].width == modelist[i].width) &&
+ (modelist[nummodes].height == modelist[i].height))
+ {
+ existingmode = 1;
+ break;
+ }
+ }
+
+ if (!existingmode)
+ {
+ if (modelist[nummodes].width < lowestres)
+ lowestres = modelist[nummodes].width;
+
+ nummodes++;
+ }
+ }
+ }
+
+ modenum++;
+ } while (stat);
+
+// see if any of them were actually settable; if so, this is our mode list,
+// else enumerate all modes; our mode list is whichever ones are settable
+// with > 8 bpp
+ if (nummodes == originalnummodes)
+ {
+ modenum = 0;
+ lowestres = 99999;
+
+ Con_SafePrintf ("No 8-bpp fullscreen DIB modes found\n");
+
+ do
+ {
+ stat = EnumDisplaySettings (NULL, modenum, &devmode);
+
+ if ((((devmode.dmPelsWidth <= MAXWIDTH) &&
+ (devmode.dmPelsHeight <= MAXHEIGHT)) ||
+ (!COM_CheckParm("-noadjustaspect") &&
+ (devmode.dmPelsWidth <= (MAXWIDTH*2)) &&
+ (devmode.dmPelsWidth > (devmode.dmPelsHeight*2)))) &&
+ (nummodes < MAX_MODE_LIST) &&
+ (devmode.dmBitsPerPel > 8))
+ {
+ devmode.dmFields = DM_BITSPERPEL |
+ DM_PELSWIDTH |
+ DM_PELSHEIGHT;
+
+ if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
+ DISP_CHANGE_SUCCESSFUL)
+ {
+ modelist[nummodes].type = MS_FULLDIB;
+ modelist[nummodes].width = devmode.dmPelsWidth;
+ modelist[nummodes].height = devmode.dmPelsHeight;
+ modelist[nummodes].modenum = 0;
+ modelist[nummodes].mode13 = 0;
+ modelist[nummodes].stretched = 0;
+ modelist[nummodes].halfscreen = 0;
+ modelist[nummodes].dib = 1;
+ modelist[nummodes].fullscreen = 1;
+ modelist[nummodes].bpp = devmode.dmBitsPerPel;
+ sprintf (modelist[nummodes].modedesc, "%dx%d",
+ devmode.dmPelsWidth, devmode.dmPelsHeight);
+
+ // if the width is more than twice the height, reduce it by half because this
+ // is probably a dual-screen monitor
+ if (!COM_CheckParm("-noadjustaspect"))
+ {
+ if (modelist[nummodes].width > (modelist[nummodes].height*2))
+ {
+ modelist[nummodes].width >>= 1;
+ modelist[nummodes].halfscreen = 1;
+ sprintf (modelist[nummodes].modedesc, "%dx%d",
+ modelist[nummodes].width,
+ modelist[nummodes].height);
+ }
+ }
+
+ for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
+ {
+ if ((modelist[nummodes].width == modelist[i].width) &&
+ (modelist[nummodes].height == modelist[i].height))
+ {
+ // pick the lowest available bpp
+ if (modelist[nummodes].bpp < modelist[i].bpp)
+ modelist[i] = modelist[nummodes];
+
+ existingmode = 1;
+ break;
+ }
+ }
+
+ if (!existingmode)
+ {
+ if (modelist[nummodes].width < lowestres)
+ lowestres = modelist[nummodes].width;
+
+ nummodes++;
+ }
+ }
+ }
+
+ modenum++;
+ } while (stat);
+ }
+
+// see if there are any low-res modes that aren't being reported
+ numlowresmodes = sizeof(lowresmodes) / sizeof(lowresmodes[0]);
+ bpp = 8;
+ done = 0;
+
+// first make sure the driver doesn't just answer yes to all tests
+ devmode.dmBitsPerPel = 8;
+ devmode.dmPelsWidth = 42;
+ devmode.dmPelsHeight = 37;
+ devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+
+ if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
+ DISP_CHANGE_SUCCESSFUL)
+ {
+ done = 1;
+ }
+
+ while (!done)
+ {
+ for (j=0 ; (j<numlowresmodes) && (nummodes < MAX_MODE_LIST) ; j++)
+ {
+ devmode.dmBitsPerPel = bpp;
+ devmode.dmPelsWidth = lowresmodes[j].width;
+ devmode.dmPelsHeight = lowresmodes[j].height;
+ devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+
+ if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
+ DISP_CHANGE_SUCCESSFUL)
+ {
+ modelist[nummodes].type = MS_FULLDIB;
+ modelist[nummodes].width = devmode.dmPelsWidth;
+ modelist[nummodes].height = devmode.dmPelsHeight;
+ modelist[nummodes].modenum = 0;
+ modelist[nummodes].mode13 = 0;
+ modelist[nummodes].stretched = 0;
+ modelist[nummodes].halfscreen = 0;
+ modelist[nummodes].dib = 1;
+ modelist[nummodes].fullscreen = 1;
+ modelist[nummodes].bpp = devmode.dmBitsPerPel;
+ sprintf (modelist[nummodes].modedesc, "%dx%d",
+ devmode.dmPelsWidth, devmode.dmPelsHeight);
+
+ // we only want the lowest-bpp version of each mode
+ for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
+ {
+ if ((modelist[nummodes].width == modelist[i].width) &&
+ (modelist[nummodes].height == modelist[i].height) &&
+ (modelist[nummodes].bpp >= modelist[i].bpp))
+ {
+ existingmode = 1;
+ break;
+ }
+ }
+
+ if (!existingmode)
+ {
+ if (modelist[nummodes].width < lowestres)
+ lowestres = modelist[nummodes].width;
+
+ nummodes++;
+ }
+ }
+ }
+
+ switch (bpp)
+ {
+ case 8:
+ bpp = 16;
+ break;
+
+ case 16:
+ bpp = 32;
+ break;
+
+ case 32:
+ done = 1;
+ break;
+ }
+ }
+
+// now add the lowest stretch-by-2 pseudo-modes between 320-wide
+// (inclusive) and lowest real res (not inclusive)
+// don't bother if we have a real VGA mode 0x13 mode
+ if (!is_mode0x13)
+ {
+ for (i=originalnummodes, cstretch=0 ; i<nummodes ; i++)
+ {
+ if (((modelist[i].width >> 1) < lowestres) &&
+ ((modelist[i].width >> 1) >= 320))
+ {
+ lowestres = modelist[i].width >> 1;
+ cstretch = 1;
+ mstretch = i;
+ }
+ }
+
+ if ((nummodes + cstretch) > MAX_MODE_LIST)
+ cstretch = MAX_MODE_LIST - nummodes;
+
+ if (cstretch > 0)
+ {
+ for (i=(nummodes-1) ; i>=originalnummodes ; i--)
+ modelist[i+cstretch] = modelist[i];
+
+ nummodes += cstretch;
+ istretch = originalnummodes;
+
+ modelist[istretch] = modelist[mstretch];
+ modelist[istretch].width >>= 1;
+ modelist[istretch].height >>= 1;
+ modelist[istretch].stretched = 1;
+ sprintf (modelist[istretch].modedesc, "%dx%d",
+ modelist[istretch].width, modelist[istretch].height);
+ }
+ }
+
+ if (nummodes != originalnummodes)
+ vid_default = MODE_FULLSCREEN_DEFAULT;
+ else
+ Con_SafePrintf ("No fullscreen DIB modes found\n");
+}
+
+
+/*
+=================
+VID_NumModes
+=================
+*/
+int VID_NumModes (void)
+{
+ return nummodes;
+}
+
+
+/*
+=================
+VID_GetModePtr
+=================
+*/
+vmode_t *VID_GetModePtr (int modenum)
+{
+
+ if ((modenum >= 0) && (modenum < nummodes))
+ return &modelist[modenum];
+ else
+ return &badmode;
+}
+
+
+/*
+=================
+VID_CheckModedescFixup
+=================
+*/
+void VID_CheckModedescFixup (int mode)
+{
+ int x, y, stretch;
+
+ if (mode == MODE_SETTABLE_WINDOW)
+ {
+ modelist[mode].stretched = (int)vid_stretch_by_2.value;
+ stretch = modelist[mode].stretched;
+
+ if (vid_config_x.value < (320 << stretch))
+ vid_config_x.value = 320 << stretch;
+
+ if (vid_config_y.value < (200 << stretch))
+ vid_config_y.value = 200 << stretch;
+
+ x = (int)vid_config_x.value;
+ y = (int)vid_config_y.value;
+ sprintf (modelist[mode].modedesc, "%dx%d", x, y);
+ modelist[mode].width = x;
+ modelist[mode].height = y;
+ }
+}
+
+
+/*
+=================
+VID_GetModeDescriptionMemCheck
+=================
+*/
+char *VID_GetModeDescriptionMemCheck (int mode)
+{
+ char *pinfo;
+ vmode_t *pv;
+
+ if ((mode < 0) || (mode >= nummodes))
+ return NULL;
+
+ VID_CheckModedescFixup (mode);
+
+ pv = VID_GetModePtr (mode);
+ pinfo = pv->modedesc;
+
+ if (VID_CheckAdequateMem (pv->width, pv->height))
+ {
+ return pinfo;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+
+/*
+=================
+VID_GetModeDescription
+=================
+*/
+char *VID_GetModeDescription (int mode)
+{
+ char *pinfo;
+ vmode_t *pv;
+
+ if ((mode < 0) || (mode >= nummodes))
+ return NULL;
+
+ VID_CheckModedescFixup (mode);
+
+ pv = VID_GetModePtr (mode);
+ pinfo = pv->modedesc;
+ return pinfo;
+}
+
+
+/*
+=================
+VID_GetModeDescription2
+
+Tacks on "windowed" or "fullscreen"
+=================
+*/
+char *VID_GetModeDescription2 (int mode)
+{
+ static char pinfo[40];
+ vmode_t *pv;
+
+ if ((mode < 0) || (mode >= nummodes))
+ return NULL;
+
+ VID_CheckModedescFixup (mode);
+
+ pv = VID_GetModePtr (mode);
+
+ if (modelist[mode].type == MS_FULLSCREEN)
+ {
+ sprintf(pinfo,"%s fullscreen", pv->modedesc);
+ }
+ else if (modelist[mode].type == MS_FULLDIB)
+ {
+ sprintf(pinfo,"%s fullscreen", pv->modedesc);
+ }
+ else
+ {
+ sprintf(pinfo, "%s windowed", pv->modedesc);
+ }
+
+ return pinfo;
+}
+
+
+// KJB: Added this to return the mode driver name in description for console
+
+char *VID_GetExtModeDescription (int mode)
+{
+ static char pinfo[40];
+ vmode_t *pv;
+
+ if ((mode < 0) || (mode >= nummodes))
+ return NULL;
+
+ VID_CheckModedescFixup (mode);
+
+ pv = VID_GetModePtr (mode);
+ if (modelist[mode].type == MS_FULLSCREEN)
+ {
+ sprintf(pinfo,"%s fullscreen %s",pv->modedesc,
+ MGL_modeDriverName(pv->modenum));
+ }
+ else if (modelist[mode].type == MS_FULLDIB)
+ {
+ sprintf(pinfo,"%s fullscreen DIB", pv->modedesc);
+ }
+ else
+ {
+ sprintf(pinfo, "%s windowed", pv->modedesc);
+ }
+
+ return pinfo;
+}
+
+
+void DestroyDIBWindow (void)
+{
+
+ if (modestate == MS_WINDOWED)
+ {
+ // destroy the associated MGL DC's; the window gets reused
+ if (windc)
+ MGL_destroyDC(windc);
+ if (dibdc)
+ MGL_destroyDC(dibdc);
+ windc = dibdc = NULL;
+ }
+}
+
+
+void DestroyFullscreenWindow (void)
+{
+
+ if (modestate == MS_FULLSCREEN)
+ {
+ // destroy the existing fullscreen mode and DC's
+ if (mgldc)
+ MGL_destroyDC (mgldc);
+ if (memdc)
+ MGL_destroyDC (memdc);
+ mgldc = memdc = NULL;
+ }
+}
+
+
+
+void DestroyFullDIBWindow (void)
+{
+ if (modestate == MS_FULLDIB)
+ {
+ ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
+
+ // Destroy the fullscreen DIB window and associated MGL DC's
+ if (windc)
+ MGL_destroyDC(windc);
+ if (dibdc)
+ MGL_destroyDC(dibdc);
+ windc = dibdc = NULL;
+ }
+}
+
+
+qboolean VID_SetWindowedMode (int modenum)
+{
+ HDC hdc;
+ pixel_format_t pf;
+ qboolean stretched;
+ int lastmodestate;
+ LONG wlong;
+
+ if (!windowed_mode_set)
+ {
+ if (COM_CheckParm ("-resetwinpos"))
+ {
+ Cvar_SetValue ("vid_window_x", 0.0);
+ Cvar_SetValue ("vid_window_y", 0.0);
+ }
+
+ windowed_mode_set;
+ }
+
+ VID_CheckModedescFixup (modenum);
+
+ DDActive = 0;
+ lastmodestate = modestate;
+
+ DestroyFullscreenWindow ();
+ DestroyFullDIBWindow ();
+
+ if (windc)
+ MGL_destroyDC(windc);
+ if (dibdc)
+ MGL_destroyDC(dibdc);
+ windc = dibdc = NULL;
+
+// KJB: Signal to the MGL that we are going back to windowed mode
+ if (!MGL_changeDisplayMode(grWINDOWED))
+ initFatalError();
+
+ WindowRect.top = WindowRect.left = 0;
+
+ WindowRect.right = modelist[modenum].width;
+ WindowRect.bottom = modelist[modenum].height;
+ stretched = modelist[modenum].stretched;
+
+ DIBWidth = modelist[modenum].width;
+ DIBHeight = modelist[modenum].height;
+
+ if (stretched)
+ {
+ DIBWidth >>= 1;
+ DIBHeight >>= 1;
+ }
+
+ WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU |
+ WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS |
+ WS_CLIPCHILDREN;
+ ExWindowStyle = 0;
+ AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
+
+// the first time we're called to set the mode, create the window we'll use
+// for the rest of the session
+ if (!vid_mode_set)
+ {
+ mainwindow = CreateWindowEx (
+ ExWindowStyle,
+ "WinQuake",
+ "WinQuake",
+ WindowStyle,
+ 0, 0,
+ WindowRect.right - WindowRect.left,
+ WindowRect.bottom - WindowRect.top,
+ NULL,
+ NULL,
+ global_hInstance,
+ NULL);
+
+ if (!mainwindow)
+ Sys_Error ("Couldn't create DIB window");
+
+ // tell MGL to use this window for fullscreen modes
+ MGL_registerFullScreenWindow (mainwindow);
+
+ vid_mode_set = true;
+ }
+ else
+ {
+ SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
+ SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle);
+ }
+
+ if (!SetWindowPos (mainwindow,
+ NULL,
+ 0, 0,
+ WindowRect.right - WindowRect.left,
+ WindowRect.bottom - WindowRect.top,
+ SWP_NOCOPYBITS | SWP_NOZORDER |
+ SWP_HIDEWINDOW))
+ {
+ Sys_Error ("Couldn't resize DIB window");
+ }
+
+ if (hide_window)
+ return true;
+
+// position and show the DIB window
+ VID_CheckWindowXY ();
+ SetWindowPos (mainwindow, NULL, (int)vid_window_x.value,
+ (int)vid_window_y.value, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
+
+ if (force_minimized)
+ ShowWindow (mainwindow, SW_MINIMIZE);
+ else
+ ShowWindow (mainwindow, SW_SHOWDEFAULT);
+
+ UpdateWindow (mainwindow);
+
+ modestate = MS_WINDOWED;
+ vid_fulldib_on_focus_mode = 0;
+
+// because we have set the background brush for the window to NULL
+// (to avoid flickering when re-sizing the window on the desktop),
+// we clear the window to black when created, otherwise it will be
+// empty while Quake starts up.
+ hdc = GetDC(mainwindow);
+ PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
+ ReleaseDC(mainwindow, hdc);
+
+ /* Create the MGL window DC and the MGL memory DC */
+ if ((windc = MGL_createWindowedDC(mainwindow)) == NULL)
+ MGL_fatalError("Unable to create Windowed DC!");
+
+ if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL)
+ MGL_fatalError("Unable to create Memory DC!");
+
+ MGL_makeCurrentDC(dibdc);
+
+ vid.buffer = vid.conbuffer = vid.direct = dibdc->surface;
+ vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine;
+ vid.numpages = 1;
+ vid.maxwarpwidth = WARP_WIDTH;
+ vid.maxwarpheight = WARP_HEIGHT;
+ vid.height = vid.conheight = DIBHeight;
+ vid.width = vid.conwidth = DIBWidth;
+ vid.aspect = ((float)vid.height / (float)vid.width) *
+ (320.0 / 240.0);
+
+ vid_stretched = stretched;
+
+ SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
+ SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
+
+ return true;
+}
+
+
+qboolean VID_SetFullscreenMode (int modenum)
+{
+
+ DDActive = 1;
+
+ DestroyDIBWindow ();
+ DestroyFullDIBWindow ();
+
+ mode = modelist[modenum].modenum;
+
+ // Destroy old DC's, resetting back to fullscreen mode
+ if (mgldc)
+ MGL_destroyDC (mgldc);
+ if (memdc)
+ MGL_destroyDC (memdc);
+ mgldc = memdc = NULL;
+
+ if ((mgldc = createDisplayDC (modelist[modenum].stretched ||
+ (int)vid_nopageflip.value)) == NULL)
+ {
+ return false;
+ }
+
+ modestate = MS_FULLSCREEN;
+ vid_fulldib_on_focus_mode = 0;
+
+ vid.buffer = vid.conbuffer = vid.direct = NULL;
+ vid.maxwarpwidth = WARP_WIDTH;
+ vid.maxwarpheight = WARP_HEIGHT;
+ DIBHeight = vid.height = vid.conheight = modelist[modenum].height;
+ DIBWidth = vid.width = vid.conwidth = modelist[modenum].width;
+ vid.aspect = ((float)vid.height / (float)vid.width) *
+ (320.0 / 240.0);
+
+ vid_stretched = modelist[modenum].stretched;
+
+// needed because we're not getting WM_MOVE messages fullscreen on NT
+ window_x = 0;
+ window_y = 0;
+
+// set the large icon, so the Quake icon will show up in the taskbar
+ SendMessage (mainwindow, WM_SETICON, (WPARAM)1, (LPARAM)hIcon);
+ SendMessage (mainwindow, WM_SETICON, (WPARAM)0, (LPARAM)hIcon);
+
+// shouldn't be needed, but Kendall needs to let us get the activation
+// message for this not to be needed on NT
+ AppActivate (true, false);
+
+ return true;
+}
+
+
+qboolean VID_SetFullDIBMode (int modenum)
+{
+ HDC hdc;
+ pixel_format_t pf;
+ int lastmodestate;
+
+ DDActive = 0;
+
+ DestroyFullscreenWindow ();
+ DestroyDIBWindow ();
+
+ if (windc)
+ MGL_destroyDC(windc);
+ if (dibdc)
+ MGL_destroyDC(dibdc);
+ windc = dibdc = NULL;
+
+ // KJB: Signal to the MGL that we are going back to windowed mode
+ if (!MGL_changeDisplayMode(grWINDOWED))
+ initFatalError();
+
+ gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+ gdevmode.dmBitsPerPel = modelist[modenum].bpp;
+ gdevmode.dmPelsWidth = modelist[modenum].width << modelist[modenum].stretched <<
+ modelist[modenum].halfscreen;
+ gdevmode.dmPelsHeight = modelist[modenum].height << modelist[modenum].stretched;
+ gdevmode.dmSize = sizeof (gdevmode);
+
+ if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
+ Sys_Error ("Couldn't set fullscreen DIB mode");
+
+ lastmodestate = modestate;
+ modestate = MS_FULLDIB;
+ vid_fulldib_on_focus_mode = modenum;
+
+ WindowRect.top = WindowRect.left = 0;
+
+ hdc = GetDC(NULL);
+
+ WindowRect.right = modelist[modenum].width << modelist[modenum].stretched;
+ WindowRect.bottom = modelist[modenum].height << modelist[modenum].stretched;
+
+ ReleaseDC(NULL,hdc);
+
+ DIBWidth = modelist[modenum].width;
+ DIBHeight = modelist[modenum].height;
+
+ WindowStyle = WS_POPUP | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+ ExWindowStyle = 0;
+ AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
+
+ SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
+ SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle);
+
+ if (!SetWindowPos (mainwindow,
+ NULL,
+ 0, 0,
+ WindowRect.right - WindowRect.left,
+ WindowRect.bottom - WindowRect.top,
+ SWP_NOCOPYBITS | SWP_NOZORDER))
+ {
+ Sys_Error ("Couldn't resize DIB window");
+ }
+
+// position and show the DIB window
+ SetWindowPos (mainwindow, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_SHOWWINDOW | SWP_DRAWFRAME);
+ ShowWindow (mainwindow, SW_SHOWDEFAULT);
+ UpdateWindow (mainwindow);
+
+ // Because we have set the background brush for the window to NULL
+ // (to avoid flickering when re-sizing the window on the desktop), we
+ // clear the window to black when created, otherwise it will be
+ // empty while Quake starts up.
+ hdc = GetDC(mainwindow);
+ PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS);
+ ReleaseDC(mainwindow, hdc);
+
+ /* Create the MGL window DC and the MGL memory DC */
+ if ((windc = MGL_createWindowedDC(mainwindow)) == NULL)
+ MGL_fatalError("Unable to create Fullscreen DIB DC!");
+
+ if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL)
+ MGL_fatalError("Unable to create Memory DC!");
+
+ MGL_makeCurrentDC(dibdc);
+
+ vid.buffer = vid.conbuffer = vid.direct = dibdc->surface;
+ vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine;
+ vid.numpages = 1;
+ vid.maxwarpwidth = WARP_WIDTH;
+ vid.maxwarpheight = WARP_HEIGHT;
+ vid.height = vid.conheight = DIBHeight;
+ vid.width = vid.conwidth = DIBWidth;
+ vid.aspect = ((float)vid.height / (float)vid.width) *
+ (320.0 / 240.0);
+
+ vid_stretched = modelist[modenum].stretched;
+
+// needed because we're not getting WM_MOVE messages fullscreen on NT
+ window_x = 0;
+ window_y = 0;
+
+ return true;
+}
+
+
+void VID_RestoreOldMode (int original_mode)
+{
+ static qboolean inerror = false;
+
+ if (inerror)
+ return;
+
+ in_mode_set = false;
+ inerror = true;
+
+// make sure mode set happens (video mode changes)
+ vid_modenum = original_mode - 1;
+
+ if (!VID_SetMode (original_mode, vid_curpal))
+ {
+ vid_modenum = MODE_WINDOWED - 1;
+
+ if (!VID_SetMode (windowed_default, vid_curpal))
+ Sys_Error ("Can't set any video mode");
+ }
+
+ inerror = false;
+}
+
+
+void VID_SetDefaultMode (void)
+{
+
+ if (vid_initialized)
+ VID_SetMode (0, vid_curpal);
+
+ IN_DeactivateMouse ();
+}
+
+
+int VID_SetMode (int modenum, unsigned char *palette)
+{
+ int original_mode, temp, dummy;
+ qboolean stat;
+ MSG msg;
+ HDC hdc;
+
+ while ((modenum >= nummodes) || (modenum < 0))
+ {
+ if (vid_modenum == NO_MODE)
+ {
+ if (modenum == vid_default)
+ {
+ modenum = windowed_default;
+ }
+ else
+ {
+ modenum = vid_default;
+ }
+
+ Cvar_SetValue ("vid_mode", (float)modenum);
+ }
+ else
+ {
+ Cvar_SetValue ("vid_mode", (float)vid_modenum);
+ return 0;
+ }
+ }
+
+ if (!force_mode_set && (modenum == vid_modenum))
+ return true;
+
+// so Con_Printfs don't mess us up by forcing vid and snd updates
+ temp = scr_disabled_for_loading;
+ scr_disabled_for_loading = true;
+ in_mode_set = true;
+
+ CDAudio_Pause ();
+ S_ClearBuffer ();
+
+ if (vid_modenum == NO_MODE)
+ original_mode = windowed_default;
+ else
+ original_mode = vid_modenum;
+
+ // Set either the fullscreen or windowed mode
+ if (modelist[modenum].type == MS_WINDOWED)
+ {
+ if (_windowed_mouse.value && key_dest == key_game)
+ {
+ stat = VID_SetWindowedMode(modenum);
+ IN_ActivateMouse ();
+ IN_HideMouse ();
+ }
+ else
+ {
+ IN_DeactivateMouse ();
+ IN_ShowMouse ();
+ stat = VID_SetWindowedMode(modenum);
+ }
+ }
+ else if (modelist[modenum].type == MS_FULLDIB)
+ {
+ stat = VID_SetFullDIBMode(modenum);
+ IN_ActivateMouse ();
+ IN_HideMouse ();
+ }
+ else
+ {
+ stat = VID_SetFullscreenMode(modenum);
+ IN_ActivateMouse ();
+ IN_HideMouse ();
+ }
+
+ window_width = vid.width << vid_stretched;
+ window_height = vid.height << vid_stretched;
+ VID_UpdateWindowStatus ();
+
+ CDAudio_Resume ();
+ scr_disabled_for_loading = temp;
+
+ if (!stat)
+ {
+ VID_RestoreOldMode (original_mode);
+ return false;
+ }
+
+ if (hide_window)
+ return true;
+
+// now we try to make sure we get the focus on the mode switch, because
+// sometimes in some systems we don't. We grab the foreground, then
+// finish setting up, pump all our messages, and sleep for a little while
+// to let messages finish bouncing around the system, then we put
+// ourselves at the top of the z order, then grab the foreground again,
+// Who knows if it helps, but it probably doesn't hurt
+ if (!force_minimized)
+ SetForegroundWindow (mainwindow);
+
+ hdc = GetDC(NULL);
+
+ if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
+ vid_palettized = true;
+ else
+ vid_palettized = false;
+
+ VID_SetPalette (palette);
+
+ ReleaseDC(NULL,hdc);
+
+ vid_modenum = modenum;
+ Cvar_SetValue ("vid_mode", (float)vid_modenum);
+
+ if (!VID_AllocBuffers (vid.width, vid.height))
+ {
+ // couldn't get memory for this mode; try to fall back to previous mode
+ VID_RestoreOldMode (original_mode);
+ return false;
+ }
+
+ D_InitCaches (vid_surfcache, vid_surfcachesize);
+
+ while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+
+ Sleep (100);
+
+ if (!force_minimized)
+ {
+ SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0,
+ SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
+ SWP_NOCOPYBITS);
+
+ SetForegroundWindow (mainwindow);
+ }
+
+// fix the leftover Alt from any Alt-Tab or the like that switched us away
+ ClearAllStates ();
+
+ if (!msg_suppress_1)
+ Con_SafePrintf ("Video mode %s initialized\n", VID_GetModeDescription (vid_modenum));
+
+ VID_SetPalette (palette);
+
+ in_mode_set = false;
+ vid.recalc_refdef = 1;
+
+ return true;
+}
+
+void VID_LockBuffer (void)
+{
+
+ if (dibdc)
+ return;
+
+ lockcount++;
+
+ if (lockcount > 1)
+ return;
+
+ MGL_beginDirectAccess();
+
+ if (memdc)
+ {
+ // Update surface pointer for linear access modes
+ vid.buffer = vid.conbuffer = vid.direct = memdc->surface;
+ vid.rowbytes = vid.conrowbytes = memdc->mi.bytesPerLine;
+ }
+ else if (mgldc)
+ {
+ // Update surface pointer for linear access modes
+ vid.buffer = vid.conbuffer = vid.direct = mgldc->surface;
+ vid.rowbytes = vid.conrowbytes = mgldc->mi.bytesPerLine;
+ }
+
+ if (r_dowarp)
+ d_viewbuffer = r_warpbuffer;
+ else
+ d_viewbuffer = (void *)(byte *)vid.buffer;
+
+ if (r_dowarp)
+ screenwidth = WARP_WIDTH;
+ else
+ screenwidth = vid.rowbytes;
+
+ if (lcd_x.value)
+ screenwidth <<= 1;
+}
+
+
+void VID_UnlockBuffer (void)
+{
+ if (dibdc)
+ return;
+
+ lockcount--;
+
+ if (lockcount > 0)
+ return;
+
+ if (lockcount < 0)
+ Sys_Error ("Unbalanced unlock");
+
+ MGL_endDirectAccess();
+
+// to turn up any unlocked accesses
+ vid.buffer = vid.conbuffer = vid.direct = d_viewbuffer = NULL;
+
+}
+
+
+int VID_ForceUnlockedAndReturnState (void)
+{
+ int lk;
+
+ if (!lockcount)
+ return 0;
+
+ lk = lockcount;
+
+ if (dibdc)
+ {
+ lockcount = 0;
+ }
+ else
+ {
+ lockcount = 1;
+ VID_UnlockBuffer ();
+ }
+
+ return lk;
+}
+
+
+void VID_ForceLockState (int lk)
+{
+
+ if (!dibdc && lk)
+ {
+ lockcount = 0;
+ VID_LockBuffer ();
+ }
+
+ lockcount = lk;
+}
+
+
+void VID_SetPalette (unsigned char *palette)
+{
+ INT i;
+ palette_t pal[256];
+ HDC hdc;
+
+ if (!Minimized)
+ {
+ palette_changed = true;
+
+ // make sure we have the static colors if we're the active app
+ hdc = GetDC(NULL);
+
+ if (vid_palettized && ActiveApp)
+ {
+ if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC)
+ {
+ // switch to SYSPAL_NOSTATIC and remap the colors
+ SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
+ syscolchg = true;
+ pal_is_nostatic = true;
+ }
+ }
+
+ ReleaseDC(NULL,hdc);
+
+ // Translate the palette values to an MGL palette array and
+ // set the values.
+ for (i = 0; i < 256; i++)
+ {
+ pal[i].red = palette[i*3];
+ pal[i].green = palette[i*3+1];
+ pal[i].blue = palette[i*3+2];
+ }
+
+ if (DDActive)
+ {
+ if (!mgldc)
+ return;
+
+ MGL_setPalette(mgldc,pal,256,0);
+ MGL_realizePalette(mgldc,256,0,false);
+ if (memdc)
+ MGL_setPalette(memdc,pal,256,0);
+ }
+ else
+ {
+ if (!windc)
+ return;
+
+ MGL_setPalette(windc,pal,256,0);
+ MGL_realizePalette(windc,256,0,false);
+ if (dibdc)
+ {
+ MGL_setPalette(dibdc,pal,256,0);
+ MGL_realizePalette(dibdc,256,0,false);
+ }
+ }
+ }
+
+ memcpy (vid_curpal, palette, sizeof(vid_curpal));
+
+ if (syscolchg)
+ {
+ PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
+ syscolchg = false;
+ }
+}
+
+
+void VID_ShiftPalette (unsigned char *palette)
+{
+ VID_SetPalette (palette);
+}
+
+
+/*
+=================
+VID_DescribeCurrentMode_f
+=================
+*/
+void VID_DescribeCurrentMode_f (void)
+{
+ Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum));
+}
+
+
+/*
+=================
+VID_NumModes_f
+=================
+*/
+void VID_NumModes_f (void)
+{
+
+ if (nummodes == 1)
+ Con_Printf ("%d video mode is available\n", nummodes);
+ else
+ Con_Printf ("%d video modes are available\n", nummodes);
+}
+
+
+/*
+=================
+VID_DescribeMode_f
+=================
+*/
+void VID_DescribeMode_f (void)
+{
+ int modenum;
+
+ modenum = Q_atoi (Cmd_Argv(1));
+
+ Con_Printf ("%s\n", VID_GetExtModeDescription (modenum));
+}
+
+
+/*
+=================
+VID_DescribeModes_f
+=================
+*/
+void VID_DescribeModes_f (void)
+{
+ int i, lnummodes;
+ char *pinfo;
+ qboolean na;
+ vmode_t *pv;
+
+ na = false;
+
+ lnummodes = VID_NumModes ();
+
+ for (i=0 ; i<lnummodes ; i++)
+ {
+ pv = VID_GetModePtr (i);
+ pinfo = VID_GetExtModeDescription (i);
+
+ if (VID_CheckAdequateMem (pv->width, pv->height))
+ {
+ Con_Printf ("%2d: %s\n", i, pinfo);
+ }
+ else
+ {
+ Con_Printf ("**: %s\n", pinfo);
+ na = true;
+ }
+ }
+
+ if (na)
+ {
+ Con_Printf ("\n[**: not enough system RAM for mode]\n");
+ }
+}
+
+
+/*
+=================
+VID_TestMode_f
+=================
+*/
+void VID_TestMode_f (void)
+{
+ int modenum;
+ double testduration;
+
+ if (!vid_testingmode)
+ {
+ modenum = Q_atoi (Cmd_Argv(1));
+
+ if (VID_SetMode (modenum, vid_curpal))
+ {
+ vid_testingmode = 1;
+ testduration = Q_atof (Cmd_Argv(2));
+ if (testduration == 0)
+ testduration = 5.0;
+ vid_testendtime = realtime + testduration;
+ }
+ }
+}
+
+/*
+=================
+VID_Windowed_f
+=================
+*/
+void VID_Windowed_f (void)
+{
+
+ VID_SetMode ((int)vid_windowed_mode.value, vid_curpal);
+}
+
+
+/*
+=================
+VID_Fullscreen_f
+=================
+*/
+void VID_Fullscreen_f (void)
+{
+
+ VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal);
+}
+
+/*
+=================
+VID_Minimize_f
+=================
+*/
+void VID_Minimize_f (void)
+{
+
+// we only support minimizing windows; if you're fullscreen,
+// switch to windowed first
+ if (modestate == MS_WINDOWED)
+ ShowWindow (mainwindow, SW_MINIMIZE);
+}
+
+
+
+/*
+=================
+VID_ForceMode_f
+=================
+*/
+void VID_ForceMode_f (void)
+{
+ int modenum;
+ double testduration;
+
+ if (!vid_testingmode)
+ {
+ modenum = Q_atoi (Cmd_Argv(1));
+
+ force_mode_set = 1;
+ VID_SetMode (modenum, vid_curpal);
+ force_mode_set = 0;
+ }
+}
+
+
+void VID_Init (unsigned char *palette)
+{
+ int i, bestmatch, bestmatchmetric, t, dr, dg, db;
+ int basenummodes;
+ byte *ptmp;
+
+ Cvar_RegisterVariable (&vid_mode);
+ Cvar_RegisterVariable (&vid_wait);
+ Cvar_RegisterVariable (&vid_nopageflip);
+ Cvar_RegisterVariable (&_vid_wait_override);
+ Cvar_RegisterVariable (&_vid_default_mode);
+ Cvar_RegisterVariable (&_vid_default_mode_win);
+ Cvar_RegisterVariable (&vid_config_x);
+ Cvar_RegisterVariable (&vid_config_y);
+ Cvar_RegisterVariable (&vid_stretch_by_2);
+ Cvar_RegisterVariable (&_windowed_mouse);
+ Cvar_RegisterVariable (&vid_fullscreen_mode);
+ Cvar_RegisterVariable (&vid_windowed_mode);
+ Cvar_RegisterVariable (&block_switch);
+ Cvar_RegisterVariable (&vid_window_x);
+ Cvar_RegisterVariable (&vid_window_y);
+
+ Cmd_AddCommand ("vid_testmode", VID_TestMode_f);
+ Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
+ Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
+ Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
+ Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
+ Cmd_AddCommand ("vid_forcemode", VID_ForceMode_f);
+ Cmd_AddCommand ("vid_windowed", VID_Windowed_f);
+ Cmd_AddCommand ("vid_fullscreen", VID_Fullscreen_f);
+ Cmd_AddCommand ("vid_minimize", VID_Minimize_f);
+
+ if (COM_CheckParm ("-dibonly"))
+ dibonly = true;
+
+ VID_InitMGLDIB (global_hInstance);
+
+ basenummodes = nummodes;
+
+ if (!dibonly)
+ VID_InitMGLFull (global_hInstance);
+
+// if there are no non-windowed modes, or only windowed and mode 0x13, then use
+// fullscreen DIBs as well
+ if (((nummodes == basenummodes) ||
+ ((nummodes == (basenummodes + 1)) && is_mode0x13)) &&
+ !COM_CheckParm ("-nofulldib"))
+
+ {
+ VID_InitFullDIB (global_hInstance);
+ }
+
+ vid.maxwarpwidth = WARP_WIDTH;
+ vid.maxwarpheight = WARP_HEIGHT;
+ vid.colormap = host_colormap;
+ vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
+ vid_testingmode = 0;
+
+// GDI doesn't let us remap palette index 0, so we'll remap color
+// mappings from that black to another one
+ bestmatchmetric = 256*256*3;
+
+ for (i=1 ; i<256 ; i++)
+ {
+ dr = palette[0] - palette[i*3];
+ dg = palette[1] - palette[i*3+1];
+ db = palette[2] - palette[i*3+2];
+
+ t = (dr * dr) + (dg * dg) + (db * db);
+
+ if (t < bestmatchmetric)
+ {
+ bestmatchmetric = t;
+ bestmatch = i;
+
+ if (t == 0)
+ break;
+ }
+ }
+
+ for (i=0, ptmp = vid.colormap ; i<(1<<(VID_CBITS+8)) ; i++, ptmp++)
+ {
+ if (*ptmp == 0)
+ *ptmp = bestmatch;
+ }
+
+ if (COM_CheckParm("-startwindowed"))
+ {
+ startwindowed = 1;
+ vid_default = windowed_default;
+ }
+
+ if (hwnd_dialog)
+ DestroyWindow (hwnd_dialog);
+
+// sound initialization has to go here, preceded by a windowed mode set,
+// so there's a window for DirectSound to work with but we're not yet
+// fullscreen so the "hardware already in use" dialog is visible if it
+// gets displayed
+
+// keep the window minimized until we're ready for the first real mode set
+ hide_window = true;
+ VID_SetMode (MODE_WINDOWED, palette);
+ hide_window = false;
+ S_Init ();
+
+ vid_initialized = true;
+
+ force_mode_set = true;
+ VID_SetMode (vid_default, palette);
+ force_mode_set = false;
+
+ vid_realmode = vid_modenum;
+
+ VID_SetPalette (palette);
+
+ vid_menudrawfn = VID_MenuDraw;
+ vid_menukeyfn = VID_MenuKey;
+
+ strcpy (badmode.modedesc, "Bad mode");
+}
+
+
+void VID_Shutdown (void)
+{
+ HDC hdc;
+ int dummy;
+
+ if (vid_initialized)
+ {
+ if (modestate == MS_FULLDIB)
+ ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
+
+ PostMessage (HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)mainwindow, (LPARAM)0);
+ PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
+
+ AppActivate(false, false);
+ DestroyDIBWindow ();
+ DestroyFullscreenWindow ();
+ DestroyFullDIBWindow ();
+
+ if (hwnd_dialog)
+ DestroyWindow (hwnd_dialog);
+
+ if (mainwindow)
+ DestroyWindow(mainwindow);
+
+ MGL_exit();
+
+ vid_testingmode = 0;
+ vid_initialized = 0;
+ }
+}
+
+
+/*
+================
+FlipScreen
+================
+*/
+void FlipScreen(vrect_t *rects)
+{
+ HRESULT ddrval;
+
+ // Flip the surfaces
+
+ if (DDActive)
+ {
+ if (mgldc)
+ {
+ if (memdc)
+ {
+ while (rects)
+ {
+ if (vid_stretched)
+ {
+ MGL_stretchBltCoord(mgldc, memdc,
+ rects->x,
+ rects->y,
+ rects->x + rects->width,
+ rects->y + rects->height,
+ rects->x << 1,
+ rects->y << 1,
+ (rects->x + rects->width) << 1,
+ (rects->y + rects->height) << 1);
+ }
+ else
+ {
+ MGL_bitBltCoord(mgldc, memdc,
+ rects->x, rects->y,
+ (rects->x + rects->width),
+ (rects->y + rects->height),
+ rects->x, rects->y, MGL_REPLACE_MODE);
+ }
+
+ rects = rects->pnext;
+ }
+ }
+
+ if (vid.numpages > 1)
+ {
+ // We have a flipping surface, so do a hard page flip
+ aPage = (aPage+1) % vid.numpages;
+ vPage = (vPage+1) % vid.numpages;
+ MGL_setActivePage(mgldc,aPage);
+ MGL_setVisualPage(mgldc,vPage,waitVRT);
+ }
+ }
+ }
+ else
+ {
+ HDC hdcScreen;
+
+ hdcScreen = GetDC(mainwindow);
+
+ if (windc && dibdc)
+ {
+ MGL_setWinDC(windc,hdcScreen);
+
+ while (rects)
+ {
+ if (vid_stretched)
+ {
+ MGL_stretchBltCoord(windc,dibdc,
+ rects->x, rects->y,
+ rects->x + rects->width, rects->y + rects->height,
+ rects->x << 1, rects->y << 1,
+ (rects->x + rects->width) << 1,
+ (rects->y + rects->height) << 1);
+ }
+ else
+ {
+ MGL_bitBltCoord(windc,dibdc,
+ rects->x, rects->y,
+ rects->x + rects->width, rects->y + rects->height,
+ rects->x, rects->y, MGL_REPLACE_MODE);
+ }
+
+ rects = rects->pnext;
+ }
+ }
+
+ ReleaseDC(mainwindow, hdcScreen);
+ }
+}
+
+
+void VID_Update (vrect_t *rects)
+{
+ vrect_t rect;
+ RECT trect;
+
+ if (!vid_palettized && palette_changed)
+ {
+ palette_changed = false;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = vid.width;
+ rect.height = vid.height;
+ rect.pnext = NULL;
+ rects = &rect;
+ }
+
+ if (firstupdate)
+ {
+ if (modestate == MS_WINDOWED)
+ {
+ GetWindowRect (mainwindow, &trect);
+
+ if ((trect.left != (int)vid_window_x.value) ||
+ (trect.top != (int)vid_window_y.value))
+ {
+ if (COM_CheckParm ("-resetwinpos"))
+ {
+ Cvar_SetValue ("vid_window_x", 0.0);
+ Cvar_SetValue ("vid_window_y", 0.0);
+ }
+
+ VID_CheckWindowXY ();
+ SetWindowPos (mainwindow, NULL, (int)vid_window_x.value,
+ (int)vid_window_y.value, 0, 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
+ }
+ }
+
+ if ((_vid_default_mode_win.value != vid_default) &&
+ (!startwindowed || (_vid_default_mode_win.value < MODE_FULLSCREEN_DEFAULT)))
+ {
+ firstupdate = 0;
+
+ if (COM_CheckParm ("-resetwinpos"))
+ {
+ Cvar_SetValue ("vid_window_x", 0.0);
+ Cvar_SetValue ("vid_window_y", 0.0);
+ }
+
+ if ((_vid_default_mode_win.value < 0) ||
+ (_vid_default_mode_win.value >= nummodes))
+ {
+ Cvar_SetValue ("_vid_default_mode_win", windowed_default);
+ }
+
+ Cvar_SetValue ("vid_mode", _vid_default_mode_win.value);
+ }
+ }
+
+ // We've drawn the frame; copy it to the screen
+ FlipScreen (rects);
+
+ if (vid_testingmode)
+ {
+ if (realtime >= vid_testendtime)
+ {
+ VID_SetMode (vid_realmode, vid_curpal);
+ vid_testingmode = 0;
+ }
+ }
+ else
+ {
+ if ((int)vid_mode.value != vid_realmode)
+ {
+ VID_SetMode ((int)vid_mode.value, vid_curpal);
+ Cvar_SetValue ("vid_mode", (float)vid_modenum);
+ // so if mode set fails, we don't keep on
+ // trying to set that mode
+ vid_realmode = vid_modenum;
+ }
+ }
+
+// handle the mouse state when windowed if that's changed
+ if (modestate == MS_WINDOWED)
+ {
+ if (!_windowed_mouse.value) {
+ if (windowed_mouse) {
+ IN_DeactivateMouse ();
+ IN_ShowMouse ();
+ }
+ windowed_mouse = false;
+ } else {
+ windowed_mouse = true;
+ if (key_dest == key_game && !mouseactive && ActiveApp) {
+ IN_ActivateMouse ();
+ IN_HideMouse ();
+ } else if (mouseactive && key_dest != key_game) {
+ IN_DeactivateMouse ();
+ IN_ShowMouse ();
+ }
+ }
+ }
+}
+
+
+/*
+================
+D_BeginDirectRect
+================
+*/
+void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
+{
+ int i, j, reps, repshift;
+ vrect_t rect;
+
+ if (!vid_initialized)
+ return;
+
+ if (vid.aspect > 1.5)
+ {
+ reps = 2;
+ repshift = 1;
+ }
+ else
+ {
+ reps = 1;
+ repshift = 0;
+ }
+
+ if (vid.numpages == 1)
+ {
+ VID_LockBuffer ();
+
+ if (!vid.direct)
+ Sys_Error ("NULL vid.direct pointer");
+
+ for (i=0 ; i<(height << repshift) ; i += reps)
+ {
+ for (j=0 ; j<reps ; j++)
+ {
+ memcpy (&backingbuf[(i + j) * 24],
+ vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
+ width);
+ memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
+ &pbitmap[(i >> repshift) * width],
+ width);
+ }
+ }
+
+ VID_UnlockBuffer ();
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height << repshift;
+ rect.pnext = NULL;
+
+ FlipScreen (&rect);
+ }
+ else
+ {
+ // unlock if locked
+ if (lockcount > 0)
+ MGL_endDirectAccess();
+
+ // set the active page to the displayed page
+ MGL_setActivePage (mgldc, vPage);
+
+ // lock the screen
+ MGL_beginDirectAccess ();
+
+ // save from and draw to screen
+ for (i=0 ; i<(height << repshift) ; i += reps)
+ {
+ for (j=0 ; j<reps ; j++)
+ {
+ memcpy (&backingbuf[(i + j) * 24],
+ (byte *)mgldc->surface + x +
+ ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
+ width);
+ memcpy ((byte *)mgldc->surface + x +
+ ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
+ &pbitmap[(i >> repshift) * width],
+ width);
+ }
+ }
+
+ // unlock the screen
+ MGL_endDirectAccess ();
+
+ // restore the original active page
+ MGL_setActivePage (mgldc, aPage);
+
+ // relock the screen if it was locked
+ if (lockcount > 0)
+ MGL_beginDirectAccess();
+ }
+}
+
+
+/*
+================
+D_EndDirectRect
+================
+*/
+void D_EndDirectRect (int x, int y, int width, int height)
+{
+ int i, j, reps, repshift;
+ vrect_t rect;
+
+ if (!vid_initialized)
+ return;
+
+ if (vid.aspect > 1.5)
+ {
+ reps = 2;
+ repshift = 1;
+ }
+ else
+ {
+ reps = 1;
+ repshift = 0;
+ }
+
+ if (vid.numpages == 1)
+ {
+ VID_LockBuffer ();
+
+ if (!vid.direct)
+ Sys_Error ("NULL vid.direct pointer");
+
+ for (i=0 ; i<(height << repshift) ; i += reps)
+ {
+ for (j=0 ; j<reps ; j++)
+ {
+ memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
+ &backingbuf[(i + j) * 24],
+ width);
+ }
+ }
+
+ VID_UnlockBuffer ();
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height << repshift;
+ rect.pnext = NULL;
+
+ FlipScreen (&rect);
+ }
+ else
+ {
+ // unlock if locked
+ if (lockcount > 0)
+ MGL_endDirectAccess();
+
+ // set the active page to the displayed page
+ MGL_setActivePage (mgldc, vPage);
+
+ // lock the screen
+ MGL_beginDirectAccess ();
+
+ // restore to the screen
+ for (i=0 ; i<(height << repshift) ; i += reps)
+ {
+ for (j=0 ; j<reps ; j++)
+ {
+ memcpy ((byte *)mgldc->surface + x +
+ ((y << repshift) + i + j) * mgldc->mi.bytesPerLine,
+ &backingbuf[(i + j) * 24],
+ width);
+ }
+ }
+
+ // unlock the screen
+ MGL_endDirectAccess ();
+
+ // restore the original active page
+ MGL_setActivePage (mgldc, aPage);
+
+ // relock the screen if it was locked
+ if (lockcount > 0)
+ MGL_beginDirectAccess();
+ }
+}
+
+
+//==========================================================================
+
+byte scantokey[128] =
+ {
+// 0 1 2 3 4 5 6 7
+// 8 9 A B C D E F
+ 0 , 27, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2
+ 'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*',
+ K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
+ K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME,
+ K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4
+ K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
+ K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
+};
+
+/*
+=======
+MapKey
+
+Map from windows to quake keynums
+=======
+*/
+int MapKey (int key)
+{
+ key = (key>>16)&255;
+ if (key > 127)
+ return 0;
+
+ return scantokey[key];
+}
+
+void AppActivate(BOOL fActive, BOOL minimize)
+/****************************************************************************
+*
+* Function: AppActivate
+* Parameters: fActive - True if app is activating
+*
+* Description: If the application is activating, then swap the system
+* into SYSPAL_NOSTATIC mode so that our palettes will display
+* correctly.
+*
+****************************************************************************/
+{
+ HDC hdc;
+ int i, t;
+ static BOOL sound_active;
+
+ ActiveApp = fActive;
+
+// messy, but it seems to work
+ if (vid_fulldib_on_focus_mode)
+ {
+ Minimized = minimize;
+
+ if (Minimized)
+ ActiveApp = false;
+ }
+
+ MGL_appActivate(windc, ActiveApp);
+
+ if (vid_initialized)
+ {
+ // yield the palette if we're losing the focus
+ hdc = GetDC(NULL);
+
+ if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
+ {
+ if (ActiveApp)
+ {
+ if ((modestate == MS_WINDOWED) || (modestate == MS_FULLDIB))
+ {
+ if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC)
+ {
+ // switch to SYSPAL_NOSTATIC and remap the colors
+ SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
+ syscolchg = true;
+ pal_is_nostatic = true;
+ }
+ }
+ }
+ else if (pal_is_nostatic)
+ {
+ if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC)
+ {
+ // switch back to SYSPAL_STATIC and the old mapping
+ SetSystemPaletteUse(hdc, SYSPAL_STATIC);
+ syscolchg = true;
+ }
+
+ pal_is_nostatic = false;
+ }
+ }
+
+ if (!Minimized)
+ VID_SetPalette (vid_curpal);
+
+ scr_fullupdate = 0;
+
+ ReleaseDC(NULL,hdc);
+ }
+
+// enable/disable sound on focus gain/loss
+ if (!ActiveApp && sound_active)
+ {
+ S_BlockSound ();
+ S_ClearBuffer ();
+ sound_active = false;
+ }
+ else if (ActiveApp && !sound_active)
+ {
+ S_UnblockSound ();
+ S_ClearBuffer ();
+ sound_active = true;
+ }
+
+// minimize/restore fulldib windows/mouse-capture normal windows on demand
+ if (!in_mode_set)
+ {
+ if (ActiveApp)
+ {
+ if (vid_fulldib_on_focus_mode)
+ {
+ if (vid_initialized)
+ {
+ msg_suppress_1 = true; // don't want to see normal mode set message
+ VID_SetMode (vid_fulldib_on_focus_mode, vid_curpal);
+ msg_suppress_1 = false;
+
+ t = in_mode_set;
+ in_mode_set = true;
+ AppActivate (true, false);
+ in_mode_set = t;
+ }
+
+ IN_ActivateMouse ();
+ IN_HideMouse ();
+ }
+ else if ((modestate == MS_WINDOWED) && _windowed_mouse.value && key_dest == key_game)
+ {
+ IN_ActivateMouse ();
+ IN_HideMouse ();
+ }
+ }
+
+ if (!ActiveApp)
+ {
+ if (modestate == MS_FULLDIB)
+ {
+ if (vid_initialized)
+ {
+ force_minimized = true;
+ i = vid_fulldib_on_focus_mode;
+ msg_suppress_1 = true; // don't want to see normal mode set message
+ VID_SetMode (windowed_default, vid_curpal);
+ msg_suppress_1 = false;
+ vid_fulldib_on_focus_mode = i;
+ force_minimized = false;
+
+ // we never seem to get WM_ACTIVATE inactive from this mode set, so we'll
+ // do it manually
+ t = in_mode_set;
+ in_mode_set = true;
+ AppActivate (false, true);
+ in_mode_set = t;
+ }
+
+ IN_DeactivateMouse ();
+ IN_ShowMouse ();
+ }
+ else if ((modestate == MS_WINDOWED) && _windowed_mouse.value /* && mouseactive */)
+ {
+ IN_DeactivateMouse ();
+ IN_ShowMouse ();
+ }
+ }
+ }
+}
+
+
+/*
+================
+VID_HandlePause
+================
+*/
+void VID_HandlePause (qboolean pause)
+{
+#if 0
+ if ((modestate == MS_WINDOWED) && _windowed_mouse.value)
+ {
+ if (pause)
+ {
+ IN_DeactivateMouse ();
+ IN_ShowMouse ();
+ }
+ else
+ {
+ IN_ActivateMouse ();
+ IN_HideMouse ();
+ }
+ }
+#endif
+}
+
+
+/*
+===================================================================
+
+MAIN WINDOW
+
+===================================================================
+*/
+
+LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+/* main window procedure */
+LONG WINAPI MainWndProc (
+ HWND hWnd,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ LONG lRet = 0;
+ int fwKeys, xPos, yPos, fActive, fMinimized, temp;
+ HDC hdc;
+ PAINTSTRUCT ps;
+ extern unsigned int uiWheelMessage;
+ static int recursiveflag;
+
+ if ( uMsg == uiWheelMessage ) {
+ uMsg = WM_MOUSEWHEEL;
+ wParam <<= 16;
+ }
+
+
+ switch (uMsg)
+ {
+ case WM_CREATE:
+ break;
+
+ case WM_SYSCOMMAND:
+
+ // Check for maximize being hit
+ switch (wParam & ~0x0F)
+ {
+ case SC_MAXIMIZE:
+ // if minimized, bring up as a window before going fullscreen,
+ // so MGL will have the right state to restore
+ if (Minimized)
+ {
+ force_mode_set = true;
+ VID_SetMode (vid_modenum, vid_curpal);
+ force_mode_set = false;
+ }
+
+ VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal);
+ break;
+
+ case SC_SCREENSAVE:
+ case SC_MONITORPOWER:
+ if (modestate != MS_WINDOWED)
+ {
+ // don't call DefWindowProc() because we don't want to start
+ // the screen saver fullscreen
+ break;
+ }
+
+ // fall through windowed and allow the screen saver to start
+
+ default:
+ if (!in_mode_set)
+ {
+ S_BlockSound ();
+ S_ClearBuffer ();
+ }
+
+ lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
+
+ if (!in_mode_set)
+ {
+ S_UnblockSound ();
+ }
+ }
+ break;
+
+ case WM_MOVE:
+ window_x = (int) LOWORD(lParam);
+ window_y = (int) HIWORD(lParam);
+ VID_UpdateWindowStatus ();
+
+ if ((modestate == MS_WINDOWED) && !in_mode_set && !Minimized)
+ VID_RememberWindowPos ();
+
+ break;
+
+ case WM_SIZE:
+ Minimized = false;
+
+ if (!(wParam & SIZE_RESTORED))
+ {
+ if (wParam & SIZE_MINIMIZED)
+ Minimized = true;
+ }
+ break;
+
+ case WM_SYSCHAR:
+ // keep Alt-Space from happening
+ break;
+
+ case WM_ACTIVATE:
+ fActive = LOWORD(wParam);
+ fMinimized = (BOOL) HIWORD(wParam);
+ AppActivate(!(fActive == WA_INACTIVE), fMinimized);
+
+ // fix the leftover Alt from any Alt-Tab or the like that switched us away
+ ClearAllStates ();
+
+ if (!in_mode_set)
+ {
+ if (windc)
+ MGL_activatePalette(windc,true);
+
+ VID_SetPalette(vid_curpal);
+ }
+
+ break;
+
+ case WM_PAINT:
+ hdc = BeginPaint(hWnd, &ps);
+
+ if (!in_mode_set && host_initialized)
+ SCR_UpdateWholeScreen ();
+
+ EndPaint(hWnd, &ps);
+ break;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ if (!in_mode_set)
+ Key_Event (MapKey(lParam), true);
+ break;
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ if (!in_mode_set)
+ Key_Event (MapKey(lParam), false);
+ break;
+
+ // this is complicated because Win32 seems to pack multiple mouse events into
+ // one update sometimes, so we always check all states and look for events
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_MOUSEMOVE:
+ if (!in_mode_set)
+ {
+ temp = 0;
+
+ if (wParam & MK_LBUTTON)
+ temp |= 1;
+
+ if (wParam & MK_RBUTTON)
+ temp |= 2;
+
+ if (wParam & MK_MBUTTON)
+ temp |= 4;
+
+ IN_MouseEvent (temp);
+ }
+ break;
+ // JACK: This is the mouse wheel with the Intellimouse
+ // Its delta is either positive or neg, and we generate the proper
+ // Event.
+ case WM_MOUSEWHEEL:
+ if ((short) HIWORD(wParam) > 0) {
+ Key_Event(K_MWHEELUP, true);
+ Key_Event(K_MWHEELUP, false);
+ } else {
+ Key_Event(K_MWHEELDOWN, true);
+ Key_Event(K_MWHEELDOWN, false);
+ }
+ break;
+ // KJB: Added these new palette functions
+ case WM_PALETTECHANGED:
+ if ((HWND)wParam == hWnd)
+ break;
+ /* Fall through to WM_QUERYNEWPALETTE */
+ case WM_QUERYNEWPALETTE:
+ hdc = GetDC(NULL);
+
+ if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
+ vid_palettized = true;
+ else
+ vid_palettized = false;
+
+ ReleaseDC(NULL,hdc);
+
+ scr_fullupdate = 0;
+
+ if (vid_initialized && !in_mode_set && windc && MGL_activatePalette(windc,false) && !Minimized)
+ {
+ VID_SetPalette (vid_curpal);
+ InvalidateRect (mainwindow, NULL, false);
+
+ // specifically required if WM_QUERYNEWPALETTE realizes a new palette
+ lRet = TRUE;
+ }
+ break;
+
+ case WM_DISPLAYCHANGE:
+ if (!in_mode_set && (modestate == MS_WINDOWED) && !vid_fulldib_on_focus_mode)
+ {
+ force_mode_set = true;
+ VID_SetMode (vid_modenum, vid_curpal);
+ force_mode_set = false;
+ }
+ break;
+
+ case WM_CLOSE:
+ // this causes Close in the right-click task bar menu not to work, but right
+ // now bad things happen if Close is handled in that case (garbage and a
+ // crash on Win95)
+ if (!in_mode_set)
+ {
+ if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit",
+ MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
+ {
+ Sys_Quit ();
+ }
+ }
+ break;
+
+ case MM_MCINOTIFY:
+ lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
+ break;
+
+ default:
+ /* pass all unhandled messages to DefWindowProc */
+ lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
+ break;
+ }
+
+ /* return 0 if handled message, 1 if not */
+ return lRet;
+}
+
+
+extern void M_Menu_Options_f (void);
+extern void M_Print (int cx, int cy, char *str);
+extern void M_PrintWhite (int cx, int cy, char *str);
+extern void M_DrawCharacter (int cx, int line, int num);
+extern void M_DrawTransPic (int x, int y, qpic_t *pic);
+extern void M_DrawPic (int x, int y, qpic_t *pic);
+
+static int vid_line, vid_wmodes;
+
+typedef struct
+{
+ int modenum;
+ char *desc;
+ int iscur;
+ int ismode13;
+ int width;
+} modedesc_t;
+
+#define MAX_COLUMN_SIZE 5
+#define MODE_AREA_HEIGHT (MAX_COLUMN_SIZE + 6)
+#define MAX_MODEDESCS (MAX_COLUMN_SIZE*3)
+
+static modedesc_t modedescs[MAX_MODEDESCS];
+
+/*
+================
+VID_MenuDraw
+================
+*/
+void VID_MenuDraw (void)
+{
+ qpic_t *p;
+ char *ptr;
+ int lnummodes, i, j, k, column, row, dup, dupmode;
+ char temp[100];
+ vmode_t *pv;
+ modedesc_t tmodedesc;
+
+ p = Draw_CachePic ("gfx/vidmodes.lmp");
+ M_DrawPic ( (320-p->width)/2, 4, p);
+
+ for (i=0 ; i<3 ; i++)
+ {
+ ptr = VID_GetModeDescriptionMemCheck (i);
+ modedescs[i].modenum = modelist[i].modenum;
+ modedescs[i].desc = ptr;
+ modedescs[i].ismode13 = 0;
+ modedescs[i].iscur = 0;
+
+ if (vid_modenum == i)
+ modedescs[i].iscur = 1;
+ }
+
+ vid_wmodes = 3;
+ lnummodes = VID_NumModes ();
+
+ for (i=3 ; i<lnummodes ; i++)
+ {
+ ptr = VID_GetModeDescriptionMemCheck (i);
+ pv = VID_GetModePtr (i);
+
+ // we only have room for 15 fullscreen modes, so don't allow
+ // 360-wide modes, because if there are 5 320-wide modes and
+ // 5 360-wide modes, we'll run out of space
+ if (ptr && ((pv->width != 360) || COM_CheckParm("-allow360")))
+ {
+ dup = 0;
+
+ for (j=3 ; j<vid_wmodes ; j++)
+ {
+ if (!strcmp (modedescs[j].desc, ptr))
+ {
+ dup = 1;
+ dupmode = j;
+ break;
+ }
+ }
+
+ if (dup || (vid_wmodes < MAX_MODEDESCS))
+ {
+ if (!dup || !modedescs[dupmode].ismode13 || COM_CheckParm("-noforcevga"))
+ {
+ if (dup)
+ {
+ k = dupmode;
+ }
+ else
+ {
+ k = vid_wmodes;
+ }
+
+ modedescs[k].modenum = i;
+ modedescs[k].desc = ptr;
+ modedescs[k].ismode13 = pv->mode13;
+ modedescs[k].iscur = 0;
+ modedescs[k].width = pv->width;
+
+ if (i == vid_modenum)
+ modedescs[k].iscur = 1;
+
+ if (!dup)
+ vid_wmodes++;
+ }
+ }
+ }
+ }
+
+// sort the modes on width (to handle picking up oddball dibonly modes
+// after all the others)
+ for (i=3 ; i<(vid_wmodes-1) ; i++)
+ {
+ for (j=(i+1) ; j<vid_wmodes ; j++)
+ {
+ if (modedescs[i].width > modedescs[j].width)
+ {
+ tmodedesc = modedescs[i];
+ modedescs[i] = modedescs[j];
+ modedescs[j] = tmodedesc;
+ }
+ }
+ }
+
+
+ M_Print (13*8, 36, "Windowed Modes");
+
+ column = 16;
+ row = 36+2*8;
+
+ for (i=0 ; i<3; i++)
+ {
+ if (modedescs[i].iscur)
+ M_PrintWhite (column, row, modedescs[i].desc);
+ else
+ M_Print (column, row, modedescs[i].desc);
+
+ column += 13*8;
+ }
+
+ if (vid_wmodes > 3)
+ {
+ M_Print (12*8, 36+4*8, "Fullscreen Modes");
+
+ column = 16;
+ row = 36+6*8;
+
+ for (i=3 ; i<vid_wmodes ; i++)
+ {
+ if (modedescs[i].iscur)
+ M_PrintWhite (column, row, modedescs[i].desc);
+ else
+ M_Print (column, row, modedescs[i].desc);
+
+ column += 13*8;
+
+ if (((i - 3) % VID_ROW_SIZE) == (VID_ROW_SIZE - 1))
+ {
+ column = 16;
+ row += 8;
+ }
+ }
+ }
+
+// line cursor
+ if (vid_testingmode)
+ {
+ sprintf (temp, "TESTING %s",
+ modedescs[vid_line].desc);
+ M_Print (13*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, temp);
+ M_Print (9*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6,
+ "Please wait 5 seconds...");
+ }
+ else
+ {
+ M_Print (9*8, 36 + MODE_AREA_HEIGHT * 8 + 8,
+ "Press Enter to set mode");
+ M_Print (6*8, 36 + MODE_AREA_HEIGHT * 8 + 8*3,
+ "T to test mode for 5 seconds");
+ ptr = VID_GetModeDescription2 (vid_modenum);
+
+ if (ptr)
+ {
+ sprintf (temp, "D to set default: %s", ptr);
+ M_Print (2*8, 36 + MODE_AREA_HEIGHT * 8 + 8*5, temp);
+ }
+
+ ptr = VID_GetModeDescription2 ((int)_vid_default_mode_win.value);
+
+ if (ptr)
+ {
+ sprintf (temp, "Current default: %s", ptr);
+ M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, temp);
+ }
+
+ M_Print (15*8, 36 + MODE_AREA_HEIGHT * 8 + 8*8,
+ "Esc to exit");
+
+ row = 36 + 2*8 + (vid_line / VID_ROW_SIZE) * 8;
+ column = 8 + (vid_line % VID_ROW_SIZE) * 13*8;
+
+ if (vid_line >= 3)
+ row += 3*8;
+
+ M_DrawCharacter (column, row, 12+((int)(realtime*4)&1));
+ }
+}
+
+
+/*
+================
+VID_MenuKey
+================
+*/
+void VID_MenuKey (int key)
+{
+ if (vid_testingmode)
+ return;
+
+ switch (key)
+ {
+ case K_ESCAPE:
+ S_LocalSound ("misc/menu1.wav");
+ M_Menu_Options_f ();
+ break;
+
+ case K_LEFTARROW:
+
+ S_LocalSound ("misc/menu1.wav");
+ vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) +
+ ((vid_line + 2) % VID_ROW_SIZE);
+
+ if (vid_line >= vid_wmodes)
+ vid_line = vid_wmodes - 1;
+ break;
+
+ case K_RIGHTARROW:
+ S_LocalSound ("misc/menu1.wav");
+ vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) +
+ ((vid_line + 4) % VID_ROW_SIZE);
+
+ if (vid_line >= vid_wmodes)
+ vid_line = (vid_line / VID_ROW_SIZE) * VID_ROW_SIZE;
+ break;
+
+ case K_UPARROW:
+ S_LocalSound ("misc/menu1.wav");
+ vid_line -= VID_ROW_SIZE;
+
+ if (vid_line < 0)
+ {
+ vid_line += ((vid_wmodes + (VID_ROW_SIZE - 1)) /
+ VID_ROW_SIZE) * VID_ROW_SIZE;
+
+ while (vid_line >= vid_wmodes)
+ vid_line -= VID_ROW_SIZE;
+ }
+ break;
+
+ case K_DOWNARROW:
+ S_LocalSound ("misc/menu1.wav");
+ vid_line += VID_ROW_SIZE;
+
+ if (vid_line >= vid_wmodes)
+ {
+ vid_line -= ((vid_wmodes + (VID_ROW_SIZE - 1)) /
+ VID_ROW_SIZE) * VID_ROW_SIZE;
+
+ while (vid_line < 0)
+ vid_line += VID_ROW_SIZE;
+ }
+ break;
+
+ case K_ENTER:
+ S_LocalSound ("misc/menu1.wav");
+ VID_SetMode (modedescs[vid_line].modenum, vid_curpal);
+ break;
+
+ case 'T':
+ case 't':
+ S_LocalSound ("misc/menu1.wav");
+ // have to set this before setting the mode because WM_PAINT
+ // happens during the mode set and does a VID_Update, which
+ // checks vid_testingmode
+ vid_testingmode = 1;
+ vid_testendtime = realtime + 5.0;
+
+ if (!VID_SetMode (modedescs[vid_line].modenum, vid_curpal))
+ {
+ vid_testingmode = 0;
+ }
+ break;
+
+ case 'D':
+ case 'd':
+ S_LocalSound ("misc/menu1.wav");
+ firstupdate = 0;
+ Cvar_SetValue ("_vid_default_mode_win", vid_modenum);
+ break;
+
+ default:
+ break;
+ }
+}