/* | |
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 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; | |
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); | |
} | |
int VID_Suspend (MGLDC *dc,m_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; | |
} | |
} | |
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) | |
{ | |
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 ("%s\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 = ▭ | |
} | |
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 ((int)_windowed_mouse.value != windowed_mouse) | |
{ | |
if (_windowed_mouse.value) | |
{ | |
IN_ActivateMouse (); | |
IN_HideMouse (); | |
} | |
else | |
{ | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
} | |
windowed_mouse = (int)_windowed_mouse.value; | |
} | |
} | |
} | |
/* | |
================ | |
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) | |
{ | |
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) | |
{ | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
} | |
} | |
} | |
} | |
/* | |
================ | |
VID_HandlePause | |
================ | |
*/ | |
void VID_HandlePause (qboolean pause) | |
{ | |
if ((modestate == MS_WINDOWED) && _windowed_mouse.value) | |
{ | |
if (pause) | |
{ | |
IN_DeactivateMouse (); | |
IN_ShowMouse (); | |
} | |
else | |
{ | |
IN_ActivateMouse (); | |
IN_HideMouse (); | |
} | |
} | |
} | |
/* | |
=================================================================== | |
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; | |
static int recursiveflag; | |
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; | |
} | |
} |