1 /*
2  * vid_win.c -- Win32 video driver
3  * $Id: vid_win.c 6029 2018-04-04 05:56:12Z sezero $
4  *
5  * Adapted from Quake2 and from an initial work by MH with many
6  * modifications to make it work in Hexen II: Hammer of Thyrion.
7  * Uses only DIB sections/GDI.
8  *
9  * - TODO: Add back more low resolutions.
10  * - TODO: Add DDRAW (see Quake2)
11  * - TODO: Better video mode management?
12  *
13  * Copyright (C) 1996-1997  Id Software, Inc.
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or (at
18  * your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23  *
24  * See the GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, write to the Free Software Foundation, Inc.,
28  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
29  */
30 
31 #include "quakedef.h"
32 #include "bgmusic.h"
33 #include "cdaudio.h"
34 #include "cfgfile.h"
35 #include "winquake.h"
36 #include <mmsystem.h>
37 #include "d_local.h"
38 #include "resource.h"
39 
40 #if defined(H2W)
41 #define WM_CLASSNAME	"HexenWorld"
42 #define WM_WINDOWNAME	"HexenWorld"
43 #else
44 #define WM_CLASSNAME	"HexenII"
45 #define WM_WINDOWNAME	"HexenII"
46 #endif
47 
48 #define MAX_MODE_LIST	64
49 #define MAX_DESC	13
50 #define VID_ROW_SIZE	3
51 
52 
53 byte		globalcolormap[VID_GRADES*256], lastglobalcolor = 0;
54 byte		*lastsourcecolormap = NULL;
55 
56 HWND		mainwindow;
57 qboolean	DDActive;
58 qboolean	msg_suppress_1 = false;
59 
60 static int	DIBWidth, DIBHeight;
61 static RECT	WindowRect;
62 static LONG	WindowStyle, ExWindowStyle;
63 
64 int		window_center_x, window_center_y, window_x, window_y, window_width, window_height;
65 RECT		window_rect;
66 
67 static DEVMODE	gdevmode;
68 static qboolean	startwindowed = false;
69 static qboolean	firstupdate = true;
70 static qboolean	vid_initialized = false, vid_palettized;
71 static int	vid_fulldib_on_focus_mode;
72 static qboolean	force_minimized, force_mode_set;
73 static int	enable_mouse;
74 static qboolean	palette_changed, vid_mode_set;
75 static HICON	hIcon;
76 
77 viddef_t	vid;		// global video state
78 qboolean	in_mode_set;
79 
80 // 0 is MODE_WINDOWED, 3 is MODE_FULLSCREEN_DEFAULT
81 static	cvar_t	vid_mode = {"vid_mode", "0", CVAR_NONE};
82 static	cvar_t	_vid_default_mode_win = {"_vid_default_mode_win", "3", CVAR_ARCHIVE};
83 // compatibility with dos version:
84 static	cvar_t	_vid_default_mode = {"_vid_default_mode", "0", CVAR_ARCHIVE};
85 
86 static	cvar_t	vid_config_x = {"vid_config_x", "800", CVAR_ARCHIVE};
87 static	cvar_t	vid_config_y = {"vid_config_y", "600", CVAR_ARCHIVE};
88 static	cvar_t	vid_fullscreen_mode = {"vid_fullscreen_mode", "3", CVAR_ARCHIVE};
89 static	cvar_t	vid_windowed_mode = {"vid_windowed_mode", "0", CVAR_ARCHIVE};
90 
91 cvar_t		_enable_mouse = {"_enable_mouse", "0", CVAR_ARCHIVE};
92 
93 static int	vid_modenum = NO_MODE;
94 static int	vid_testingmode, vid_realmode;
95 static double	vid_testendtime;
96 static int	vid_default = MODE_WINDOWED;
97 static int	windowed_default;
98 
99 modestate_t	modestate = MS_UNINIT;
100 
101 static byte		*vid_surfcache;
102 static int	vid_surfcachesize;
103 static int	VID_highhunkmark;
104 
105 static unsigned char	vid_curpal[256*3];	/* save for mode changes */
106 
107 unsigned short	d_8to16table[256];
108 unsigned int	d_8to24table[256];
109 
110 typedef struct {
111 	modestate_t	type;
112 	int			width;
113 	int			height;
114 	int			modenum;
115 	int			fullscreen;
116 	char		modedesc[MAX_DESC];
117 } vmode_t;
118 
119 static vmode_t	modelist[MAX_MODE_LIST];
120 static int		nummodes;
121 
122 static vmode_t	badmode;
123 
124 //static byte	backingbuf[48*24];
125 static byte	backingbuf[48*48];
126 
127 typedef union _dibinfo
128 {
129     struct {
130 	BITMAPINFOHEADER	header;
131 	RGBQUAD			acolors[256];
132     };
133     BITMAPINFO bi;
134 } dibinfo_t;
135 
136 static HGDIOBJ previously_selected_GDI_obj = NULL;
137 static HBITMAP hDIBSection;
138 static void *pDIBBase = NULL;
139 static HDC hdcDIBSection = NULL;
140 static HDC maindc = NULL;
141 
142 static void VID_MenuDraw (void);
143 static void VID_MenuKey (int key);
144 
145 static qboolean VID_SetMode (int modenum, const unsigned char *palette);
146 static void AppActivate(BOOL fActive, BOOL minimize);
147 static LRESULT WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
148 
149 
150 /*
151 ================
152 VID_UpdateWindowStatus
153 ================
154 */
VID_UpdateWindowStatus(void)155 static void VID_UpdateWindowStatus (void)
156 {
157 	window_rect.left = window_x;
158 	window_rect.top = window_y;
159 	window_rect.right = window_x + window_width;
160 	window_rect.bottom = window_y + window_height;
161 	window_center_x = (window_rect.left + window_rect.right) / 2;
162 	window_center_y = (window_rect.top + window_rect.bottom) / 2;
163 
164 	IN_UpdateClipCursor ();
165 }
166 
167 
168 /*
169 ================
170 ClearAllStates
171 ================
172 */
ClearAllStates(void)173 static void ClearAllStates (void)
174 {
175 	Key_ClearStates ();
176 	IN_ClearStates ();
177 }
178 
179 
180 /*
181 ================
182 VID_CheckAdequateMem
183 ================
184 */
VID_CheckAdequateMem(int width,int height)185 static qboolean VID_CheckAdequateMem (int width, int height)
186 {
187 	int		tbuffersize;
188 
189 	tbuffersize = width * height * sizeof (*d_pzbuffer);
190 
191 	tbuffersize += D_SurfaceCacheForRes (width, height);
192 
193 // see if there's enough memory, allowing for the normal mode 0x13 pixel,
194 // z, and surface buffers
195 	//if ((host_parms->memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
196 	//	 0x10000 * 3) < MINIMUM_MEMORY)
197 	// Pa3PyX: using hopefully better estimation now
198 	// Experimentation: the heap should have at least 12.0 megs
199 	// remaining (after init) after setting video mode, otherwise
200 	// it's Hunk_Alloc failures and cache thrashes upon level load
201 	if (host_parms->memsize < tbuffersize + 0x180000 + 0xC00000)
202 	{
203 		return false;		// not enough memory for mode
204 	}
205 
206 	return true;
207 }
208 
209 
210 /*
211 ================
212 VID_AllocBuffers
213 ================
214 */
VID_AllocBuffers(int width,int height)215 static qboolean VID_AllocBuffers (int width, int height)
216 {
217 	int		tsize, tbuffersize;
218 
219 	tbuffersize = width * height * sizeof (*d_pzbuffer);
220 
221 	tsize = D_SurfaceCacheForRes (width, height);
222 
223 	tbuffersize += tsize;
224 
225 // see if there's enough memory, allowing for the normal mode 0x13 pixel,
226 // z, and surface buffers
227 	//if ((host_parms->memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
228 	//	 0x10000 * 3) < MINIMUM_MEMORY)
229 	// Pa3PyX: using hopefully better estimation now
230 	// if total memory < needed surface cache + (minimum operational memory
231 	// less surface cache for 320x200 and typical hunk state after init)
232 	if (host_parms->memsize < tbuffersize + 0x180000 + 0xC00000)
233 	{
234 		Con_SafePrintf ("Not enough memory for video mode\n");
235 		return false;		// not enough memory for mode
236 	}
237 
238 	vid_surfcachesize = tsize;
239 
240 	if (d_pzbuffer)
241 	{
242 		D_FlushCaches ();
243 		Hunk_FreeToHighMark (VID_highhunkmark);
244 		d_pzbuffer = NULL;
245 	}
246 
247 	VID_highhunkmark = Hunk_HighMark ();
248 
249 	d_pzbuffer = (short *) Hunk_HighAllocName (tbuffersize, "video");
250 
251 	vid_surfcache = (byte *)d_pzbuffer +
252 			width * height * sizeof (*d_pzbuffer);
253 
254 	return true;
255 }
256 
257 
258 /*
259 =================
260 VID_Windowed_f
261 =================
262 */
VID_Windowed_f(void)263 static void VID_Windowed_f (void)
264 {
265 	VID_SetMode (vid_windowed_mode.integer, vid_curpal);
266 }
267 
268 
269 /*
270 =================
271 VID_Fullscreen_f
272 =================
273 */
VID_Fullscreen_f(void)274 static void VID_Fullscreen_f (void)
275 {
276 	VID_SetMode (vid_fullscreen_mode.integer, vid_curpal);
277 }
278 
279 
VID_ShutdownDIB(void)280 static void VID_ShutdownDIB (void)
281 {
282 	if (hdcDIBSection)
283 	{
284 		SelectObject (hdcDIBSection, previously_selected_GDI_obj);
285 		DeleteDC (hdcDIBSection);
286 		hdcDIBSection = NULL;
287 	}
288 
289 	if (hDIBSection)
290 	{
291 		DeleteObject (hDIBSection);
292 		hDIBSection = NULL;
293 		pDIBBase = NULL;
294 	}
295 
296 	if (maindc)
297 	{
298 		// if maindc exists mainwindow must also be valid
299 		ReleaseDC (mainwindow, maindc);
300 		maindc = NULL;
301 	}
302 }
303 
304 
VID_CreateDIB(int width,int height,const unsigned char * palette)305 static void VID_CreateDIB (int width, int height, const unsigned char *palette)
306 {
307 	dibinfo_t   dibheader;
308 	BITMAPINFO *pbmiDIB = &dibheader.bi;
309 	int i;
310 
311 	maindc = GetDC (mainwindow);
312 	memset (&dibheader, 0, sizeof (dibheader));
313 
314 	// fill in the bitmap info
315 	pbmiDIB->bmiHeader.biSize		= sizeof (BITMAPINFOHEADER);
316 	pbmiDIB->bmiHeader.biWidth		= width;
317 	pbmiDIB->bmiHeader.biHeight		= height;
318 	pbmiDIB->bmiHeader.biPlanes		= 1;
319 	pbmiDIB->bmiHeader.biBitCount		= 8;
320 	pbmiDIB->bmiHeader.biCompression	= BI_RGB;
321 	pbmiDIB->bmiHeader.biSizeImage		= 0;
322 	pbmiDIB->bmiHeader.biXPelsPerMeter	= 0;
323 	pbmiDIB->bmiHeader.biYPelsPerMeter	= 0;
324 	pbmiDIB->bmiHeader.biClrUsed		= 256;
325 	pbmiDIB->bmiHeader.biClrImportant	= 256;
326 
327 	// fill in the palette
328 	for (i = 0; i < 256; i++)
329 	{
330 	// d_8to24table isn't filled in yet, so this is just for testing
331 		dibheader.acolors[i].rgbRed   = palette[i * 3];
332 		dibheader.acolors[i].rgbGreen = palette[i * 3 + 1];
333 		dibheader.acolors[i].rgbBlue  = palette[i * 3 + 2];
334 	}
335 
336 	// create the DIB section
337 	hDIBSection = CreateDIBSection (maindc, pbmiDIB, DIB_RGB_COLORS,
338 					&pDIBBase, NULL, 0);
339 	if (hDIBSection == NULL)
340 		Sys_Error ("DIB_Init() - CreateDIBSection failed\n");
341 
342 	// set video buffers
343 	if (pbmiDIB->bmiHeader.biHeight > 0)
344 	{
345 		// bottom-up
346 		vid.buffer = (pixel_t *)pDIBBase + (height - 1) * width;
347 		vid.rowbytes = -width;
348 	}
349 	else
350 	{
351 		// top-down
352 		vid.buffer = (pixel_t *)pDIBBase;
353 		vid.rowbytes = vid.width;
354 	}
355 
356 	vid.conbuffer = vid.direct = vid.buffer;
357 	vid.conrowbytes = vid.rowbytes;
358 
359 	// clear the buffer
360 	if (height < 0)		// negative height was sent for top-down bitmap
361 		memset (pDIBBase, 0xff, width * -height);
362 	else	memset (pDIBBase, 0xff, width * height);
363 
364 	if ((hdcDIBSection = CreateCompatibleDC (maindc)) == NULL)
365 		Sys_Error ("DIB_Init() - CreateCompatibleDC failed\n");
366 
367 	if ((previously_selected_GDI_obj = SelectObject (hdcDIBSection, hDIBSection)) == NULL)
368 		Sys_Error ("DIB_Init() - SelectObject failed\n");
369 }
370 
371 
VID_RegisterWndClass(HINSTANCE hInstance)372 static void VID_RegisterWndClass (HINSTANCE hInstance)
373 {
374 	WNDCLASS	wc;
375 
376 	wc.style		= CS_OWNDC;
377 	wc.lpfnWndProc		= MainWndProc;
378 	wc.cbClsExtra		= 0;
379 	wc.cbWndExtra		= 0;
380 	wc.hInstance		= hInstance;
381 	wc.hIcon		= 0;
382 	wc.hCursor		= LoadCursor (NULL, IDC_ARROW);
383 	wc.hbrBackground	= NULL;
384 	wc.lpszMenuName		= 0;
385 	wc.lpszClassName	= WM_CLASSNAME;
386 
387 	if (!RegisterClass(&wc))
388 		Sys_Error ("Couldn't register main window class");
389 }
390 
VID_InitModes(HINSTANCE hInstance)391 static void VID_InitModes (HINSTANCE hInstance)
392 {
393 	HDC		hdc;
394 
395 	hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON2));
396 
397 	/* Register the frame class */
398 	VID_RegisterWndClass(hInstance);
399 
400 	modelist[0].type = MS_WINDOWED;
401 	modelist[0].width = 320;
402 	modelist[0].height = 240;
403 	q_strlcpy (modelist[0].modedesc, "320x240", MAX_DESC);
404 	modelist[0].modenum = MODE_WINDOWED;
405 	modelist[0].fullscreen = 0;
406 
407 	modelist[1].type = MS_WINDOWED;
408 	modelist[1].width = 640;
409 	modelist[1].height = 480;
410 	q_strlcpy (modelist[1].modedesc, "640x480", MAX_DESC);
411 	modelist[1].modenum = MODE_WINDOWED + 1;
412 	modelist[1].fullscreen = 0;
413 
414 	modelist[2].type = MS_WINDOWED;
415 	modelist[2].width = 800;
416 	modelist[2].height = 600;
417 	q_strlcpy (modelist[2].modedesc, "800x600", MAX_DESC);
418 	modelist[2].modenum = MODE_WINDOWED + 2;
419 	modelist[2].fullscreen = 0;
420 
421 // automatically stretch the default mode up if > 640x480 desktop resolution
422 	hdc = GetDC(NULL);
423 
424 	if ((GetDeviceCaps(hdc, HORZRES) > 800) && !COM_CheckParm("-noautostretch"))
425 	{
426 		vid_default = MODE_WINDOWED + 2;
427 	}
428 	else if ((GetDeviceCaps(hdc, HORZRES) > 640) && !COM_CheckParm("-noautostretch"))
429 	{
430 		vid_default = MODE_WINDOWED + 1;
431 	}
432 	else
433 	{
434 		vid_default = MODE_WINDOWED;
435 	}
436 
437 	windowed_default = vid_default;
438 
439 	ReleaseDC(NULL,hdc);
440 
441 	nummodes = 3;	// reserve space for windowed mode
442 }
443 
444 
445 /*
446 =================
447 VID_GetDisplayModes
448 =================
449 */
VID_GetDisplayModes(void)450 static void VID_GetDisplayModes (void)
451 {
452 	DEVMODE	devmode;
453 	int		i, modenum, existingmode, originalnummodes, lowestres;
454 	BOOL	status;
455 
456 // enumerate > 8 bpp modes
457 	originalnummodes = nummodes;
458 	modenum = 0;
459 	lowestres = 99999;
460 
461 	do
462 	{
463 		status = EnumDisplaySettings (NULL, modenum, &devmode);
464 
465 		if ((devmode.dmPelsWidth <= MAXWIDTH) &&
466 			(devmode.dmPelsHeight <= MAXHEIGHT) &&
467 			(devmode.dmPelsWidth >= 640) &&
468 			(devmode.dmPelsHeight >= 480) &&
469 			(nummodes < MAX_MODE_LIST))
470 		{
471 			devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
472 
473 			if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) ==
474 								DISP_CHANGE_SUCCESSFUL)
475 			{
476 				modelist[nummodes].type = MS_FULLDIB;
477 				modelist[nummodes].width = devmode.dmPelsWidth;
478 				modelist[nummodes].height = devmode.dmPelsHeight;
479 				modelist[nummodes].modenum = 0;
480 				modelist[nummodes].fullscreen = 1;
481 				q_snprintf (modelist[nummodes].modedesc, MAX_DESC, "%dx%d",
482 						(int)devmode.dmPelsWidth, (int)devmode.dmPelsHeight);
483 
484 				// see if the mode is already there
485 				// (same dimensions but different refresh rate)
486 				for (i = originalnummodes, existingmode = 0; i < nummodes; i++)
487 				{
488 					if ((modelist[nummodes].width == modelist[i].width) &&
489 						(modelist[nummodes].height == modelist[i].height))
490 					{
491 						existingmode = 1;
492 						break;
493 					}
494 				}
495 
496 				// if it's not add it to the list
497 				if (!existingmode)
498 				{
499 					if (modelist[nummodes].width < lowestres)
500 						lowestres = modelist[nummodes].width;
501 
502 					nummodes++;
503 				}
504 			}
505 		}
506 
507 		modenum++;
508 	} while (status);
509 
510 	if (nummodes != originalnummodes)
511 		vid_default = MODE_FULLSCREEN_DEFAULT;
512 	else
513 	{
514 		Cvar_SetValueQuick (&_vid_default_mode_win, vid_default);
515 		Con_SafePrintf ("No fullscreen DIB modes found\n");
516 	}
517 }
518 
519 
520 /*
521 =================
522 VID_NumModes
523 =================
524 */
VID_NumModes(void)525 static int VID_NumModes (void)
526 {
527 	return nummodes;
528 }
529 
530 
531 /*
532 =================
533 VID_GetModePtr
534 =================
535 */
VID_GetModePtr(int modenum)536 static vmode_t *VID_GetModePtr (int modenum)
537 {
538 
539 	if ((modenum >= 0) && (modenum < nummodes))
540 		return &modelist[modenum];
541 	else
542 		return &badmode;
543 }
544 
545 
546 /*
547 =================
548 VID_CheckModedescFixup
549 =================
550 */
VID_CheckModedescFixup(int modenum)551 static void VID_CheckModedescFixup (int modenum)
552 {
553 	int		x, y;
554 
555 	if (modenum == MODE_SETTABLE_WINDOW)
556 	{
557 		x = vid_config_x.integer;
558 		y = vid_config_y.integer;
559 		q_snprintf (modelist[modenum].modedesc, MAX_DESC, "%dx%d", x, y);
560 		modelist[modenum].width = x;
561 		modelist[modenum].height = y;
562 	}
563 }
564 
565 
566 /*
567 =================
568 VID_GetModeDescriptionMemCheck
569 =================
570 */
VID_GetModeDescriptionMemCheck(int modenum)571 static const char *VID_GetModeDescriptionMemCheck (int modenum)
572 {
573 	const char	*pinfo;
574 	vmode_t		*pv;
575 
576 	if ((modenum < 0) || (modenum >= nummodes))
577 		return NULL;
578 
579 	VID_CheckModedescFixup (modenum);
580 
581 	pv = VID_GetModePtr (modenum);
582 	pinfo = pv->modedesc;
583 
584 	if (VID_CheckAdequateMem (pv->width, pv->height))
585 	{
586 		return pinfo;
587 	}
588 	else
589 	{
590 		return NULL;
591 	}
592 }
593 
594 
595 /*
596 =================
597 VID_GetModeDescription
598 =================
599 */
VID_GetModeDescription(int modenum)600 static const char *VID_GetModeDescription (int modenum)
601 {
602 	const char	*pinfo;
603 	vmode_t		*pv;
604 
605 	if ((modenum < 0) || (modenum >= nummodes))
606 		return NULL;
607 
608 	VID_CheckModedescFixup (modenum);
609 
610 	pv = VID_GetModePtr (modenum);
611 	pinfo = pv->modedesc;
612 	return pinfo;
613 }
614 
615 
616 /*
617 =================
618 VID_GetModeDescription2
619 
620 Tacks on "windowed" or "fullscreen"
621 =================
622 */
VID_GetModeDescription2(int modenum)623 static const char *VID_GetModeDescription2 (int modenum)
624 {
625 	static char	pinfo[40];
626 	vmode_t		*pv;
627 
628 	if ((modenum < 0) || (modenum >= nummodes))
629 		return NULL;
630 
631 	VID_CheckModedescFixup (modenum);
632 
633 	pv = VID_GetModePtr (modenum);
634 
635 	if (modelist[modenum].type == MS_FULLSCREEN)
636 	{
637 		q_snprintf(pinfo, sizeof(pinfo), "%s fullscreen", pv->modedesc);
638 	}
639 	else if (modelist[modenum].type == MS_FULLDIB)
640 	{
641 		q_snprintf(pinfo, sizeof(pinfo), "%s fullscreen", pv->modedesc);
642 	}
643 	else
644 	{
645 		q_snprintf(pinfo, sizeof(pinfo), "%s windowed", pv->modedesc);
646 	}
647 
648 	return pinfo;
649 }
650 
651 
652 // KJB: Added this to return the mode driver name in description for console
653 
VID_GetExtModeDescription(int modenum)654 static const char *VID_GetExtModeDescription (int modenum)
655 {
656 	static char	pinfo[40];
657 	vmode_t		*pv;
658 
659 	if ((modenum < 0) || (modenum >= nummodes))
660 		return NULL;
661 
662 	VID_CheckModedescFixup (modenum);
663 
664 	pv = VID_GetModePtr (modenum);
665 	if (modelist[modenum].type == MS_FULLDIB)
666 	{
667 		q_snprintf(pinfo, sizeof(pinfo), "%s fullscreen", pv->modedesc);
668 	}
669 	else
670 	{
671 		q_snprintf(pinfo, sizeof(pinfo), "%s windowed", pv->modedesc);
672 	}
673 
674 	return pinfo;
675 }
676 
677 
VID_DestroyWindow(void)678 static void VID_DestroyWindow (void)
679 {
680 	if (modestate == MS_FULLDIB)
681 		ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
682 
683 	VID_ShutdownDIB ();
684 }
685 
686 
CenterWindow(HWND hWndCenter,int width,int height)687 static void CenterWindow (HWND hWndCenter, int width, int height)
688 {
689 	int	CenterX, CenterY;
690 
691 	CenterX = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
692 	CenterY = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
693 	if (CenterX > 2*CenterY)
694 		CenterX >>= 1;	// dual screen?
695 	if (CenterX < 0)
696 		CenterX = 0;
697 	if (CenterY < 0)
698 		CenterY = 0;
699 	SetWindowPos (hWndCenter, NULL, CenterX, CenterY, 0, 0,
700 			SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME);
701 }
702 
VID_SetWindowedMode(int modenum)703 static qboolean VID_SetWindowedMode (int modenum)
704 {
705 	int		lastmodestate;
706 
707 	VID_CheckModedescFixup (modenum);
708 
709 	lastmodestate = modestate;
710 
711 	VID_DestroyWindow ();
712 
713 	WindowRect.top = WindowRect.left = 0;
714 
715 	WindowRect.right = modelist[modenum].width;
716 	WindowRect.bottom = modelist[modenum].height;
717 
718 	DIBWidth = modelist[modenum].width;
719 	DIBHeight = modelist[modenum].height;
720 
721 	WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU |
722 			  WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
723 	ExWindowStyle = 0;
724 	AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
725 
726 // the first time we're called to set the mode, create the window we'll use
727 // for the rest of the session
728 	if (!vid_mode_set)
729 	{
730 		mainwindow = CreateWindowEx (
731 			 ExWindowStyle,
732 			 WM_CLASSNAME,
733 			 WM_WINDOWNAME,
734 			 WindowStyle,
735 			 0, 0,
736 			 WindowRect.right - WindowRect.left,
737 			 WindowRect.bottom - WindowRect.top,
738 			 NULL,
739 			 NULL,
740 			 global_hInstance,
741 			 NULL);
742 
743 		if (!mainwindow)
744 			Sys_Error ("Couldn't create DIB window");
745 
746 		vid_mode_set = true;
747 	}
748 	else
749 	{
750 		SetWindowLongPtr (mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
751 		SetWindowLongPtr (mainwindow, GWL_EXSTYLE, ExWindowStyle);
752 	}
753 
754 	if (!SetWindowPos (mainwindow,
755 				NULL,
756 				0, 0,
757 				WindowRect.right - WindowRect.left,
758 				WindowRect.bottom - WindowRect.top,
759 				SWP_NOCOPYBITS | SWP_NOZORDER | SWP_HIDEWINDOW))
760 	{
761 		Sys_Error ("Couldn't resize DIB window");
762 	}
763 
764 // position and show the DIB window
765 	CenterWindow(mainwindow, WindowRect.right - WindowRect.left,
766 				 WindowRect.bottom - WindowRect.top);
767 
768 	if (force_minimized)
769 		ShowWindow (mainwindow, SW_MINIMIZE);
770 	else
771 		ShowWindow (mainwindow, SW_SHOWDEFAULT);
772 
773 	UpdateWindow (mainwindow);
774 
775 	modestate = MS_WINDOWED;
776 	vid_fulldib_on_focus_mode = 0;
777 
778 	vid.numpages = 1;
779 	vid.maxwarpwidth = WARP_WIDTH;
780 	vid.maxwarpheight = WARP_HEIGHT;
781 	vid.height = vid.conheight = DIBHeight;
782 	vid.width = vid.conwidth = DIBWidth;
783 	vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
784 
785 	SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon);
786 	SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon);
787 
788 	return true;
789 }
790 
791 
VID_SetFullDIBMode(int modenum)792 static qboolean VID_SetFullDIBMode (int modenum)
793 {
794 	int		lastmodestate;
795 
796 	VID_DestroyWindow ();
797 
798 	gdevmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
799 	gdevmode.dmPelsWidth = modelist[modenum].width;
800 	gdevmode.dmPelsHeight = modelist[modenum].height;
801 	gdevmode.dmSize = sizeof (gdevmode);
802 
803 	if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
804 		Sys_Error ("Couldn't set fullscreen DIB mode");
805 
806 	lastmodestate = modestate;
807 	modestate = MS_FULLDIB;
808 	vid_fulldib_on_focus_mode = modenum;
809 
810 	WindowRect.top = WindowRect.left = 0;
811 
812 	WindowRect.right = modelist[modenum].width;
813 	WindowRect.bottom = modelist[modenum].height;
814 
815 	DIBWidth = modelist[modenum].width;
816 	DIBHeight = modelist[modenum].height;
817 
818 	WindowStyle = WS_POPUP | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
819 	ExWindowStyle = 0;
820 	AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0);
821 
822 	SetWindowLongPtr (mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE);
823 	SetWindowLongPtr (mainwindow, GWL_EXSTYLE, ExWindowStyle);
824 
825 	if (!SetWindowPos (mainwindow,
826 				NULL,
827 				0, 0,
828 				WindowRect.right - WindowRect.left,
829 				WindowRect.bottom - WindowRect.top,
830 				SWP_NOCOPYBITS | SWP_NOZORDER))
831 	{
832 		Sys_Error ("Couldn't resize DIB window");
833 	}
834 
835 // position and show the DIB window
836 	SetWindowPos (mainwindow, HWND_TOPMOST, 0, 0, 0, 0,
837 				  SWP_NOSIZE | SWP_SHOWWINDOW | SWP_DRAWFRAME);
838 	ShowWindow (mainwindow, SW_SHOWDEFAULT);
839 	UpdateWindow (mainwindow);
840 
841 	vid.numpages = 1;
842 	vid.maxwarpwidth = WARP_WIDTH;
843 	vid.maxwarpheight = WARP_HEIGHT;
844 	vid.height = vid.conheight = DIBHeight;
845 	vid.width = vid.conwidth = DIBWidth;
846 	vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
847 
848 // needed because we're not getting WM_MOVE messages fullscreen on NT
849 	window_x = 0;
850 	window_y = 0;
851 
852 	return true;
853 }
854 
855 
VID_RestoreOldMode(int original_mode)856 static void VID_RestoreOldMode (int original_mode)
857 {
858 	static qboolean	inerror = false;
859 
860 	if (inerror)
861 		return;
862 
863 	in_mode_set = false;
864 	inerror = true;
865 
866 // make sure mode set happens (video mode changes)
867 	vid_modenum = original_mode - 1;
868 
869 	if (!VID_SetMode (original_mode, vid_curpal))
870 	{
871 		vid_modenum = MODE_WINDOWED - 1;
872 
873 		if (!VID_SetMode (windowed_default, vid_curpal))
874 			Sys_Error ("Can't set any video mode");
875 	}
876 
877 	inerror = false;
878 }
879 
VID_SetMode(int modenum,const unsigned char * palette)880 static qboolean VID_SetMode (int modenum, const unsigned char *palette)
881 {
882 	int		original_mode, temp;
883 	qboolean	status;
884 	MSG		msg;
885 	HDC		hdc;
886 
887 	while ((modenum >= nummodes) || (modenum < 0))
888 	{
889 		if (vid_modenum == NO_MODE)
890 		{
891 			if (modenum == vid_default)
892 			{
893 				modenum = windowed_default;
894 			}
895 			else
896 			{
897 				modenum = vid_default;
898 			}
899 
900 			Cvar_SetValueQuick (&vid_mode, (float)modenum);
901 		}
902 		else
903 		{
904 			Cvar_SetValueQuick (&vid_mode, (float)vid_modenum);
905 			return false;
906 		}
907 	}
908 
909 	if (!force_mode_set && (modenum == vid_modenum))
910 		return true;
911 
912 // so Con_Printfs don't mess us up by forcing vid and snd updates
913 	temp = scr_disabled_for_loading;
914 	scr_disabled_for_loading = true;
915 	in_mode_set = true;
916 
917 	CDAudio_Pause ();
918 	S_ClearBuffer ();
919 
920 	if (vid_modenum == NO_MODE)
921 		original_mode = windowed_default;
922 	else
923 		original_mode = vid_modenum;
924 
925 	// Set either the fullscreen or windowed mode
926 	if (modelist[modenum].type == MS_WINDOWED)
927 	{
928 		if (_enable_mouse.integer)
929 		{
930 			status = VID_SetWindowedMode(modenum);
931 			IN_ActivateMouse ();
932 			IN_HideMouse ();
933 		}
934 		else
935 		{
936 			IN_DeactivateMouse ();
937 			IN_ShowMouse ();
938 			status = VID_SetWindowedMode(modenum);
939 		}
940 	}
941 	else
942 	{
943 		status = VID_SetFullDIBMode(modenum);
944 		IN_ActivateMouse ();
945 		IN_HideMouse ();
946 	}
947 
948 //	VID_CreateDIB(DIBWidth,-DIBHeight, palette);	// top-down
949 	VID_CreateDIB(DIBWidth, DIBHeight, palette);	// bottom-up
950 
951 	window_width = vid.width;
952 	window_height = vid.height;
953 	VID_UpdateWindowStatus ();
954 	CDAudio_Resume ();
955 	scr_disabled_for_loading = temp;
956 
957 	if (!status)
958 	{
959 		VID_RestoreOldMode (original_mode);
960 		return false;
961 	}
962 
963 // now we try to make sure we get the focus on the mode switch, because
964 // sometimes in some systems we don't.  We grab the foreground, then
965 // finish setting up, pump all our messages, and sleep for a little while
966 // to let messages finish bouncing around the system, then we put
967 // ourselves at the top of the z order, then grab the foreground again,
968 // Who knows if it helps, but it probably doesn't hurt
969 	if (!force_minimized)
970 		SetForegroundWindow (mainwindow);
971 
972 	hdc = GetDC(NULL);
973 
974 	if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
975 		vid_palettized = true;
976 	else
977 		vid_palettized = false;
978 
979 	VID_SetPalette (palette);
980 
981 	ReleaseDC(NULL,hdc);
982 
983 	vid_modenum = modenum;
984 	Cvar_SetValueQuick (&vid_mode, (float)vid_modenum);
985 
986 	if (!VID_AllocBuffers (vid.width, vid.height))
987 	{
988 	// couldn't get memory for this mode; try to fall back to previous mode
989 		VID_RestoreOldMode (original_mode);
990 		return false;
991 	}
992 
993 	D_InitCaches (vid_surfcache, vid_surfcachesize);
994 
995 	while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
996 	{
997 		TranslateMessage (&msg);
998 		DispatchMessage (&msg);
999 	}
1000 
1001 	Sleep (100);
1002 
1003 	if (!force_minimized)
1004 	{
1005 		SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0,
1006 				  SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW |
1007 				  SWP_NOCOPYBITS);
1008 
1009 		SetForegroundWindow (mainwindow);
1010 	}
1011 
1012 // fix the leftover Alt from any Alt-Tab or the like that switched us away
1013 	ClearAllStates ();
1014 
1015 	if (!msg_suppress_1)
1016 		Con_SafePrintf ("%s\n", VID_GetModeDescription (vid_modenum));
1017 
1018 	VID_SetPalette (palette);
1019 
1020 	in_mode_set = false;
1021 	vid.recalc_refdef = 1;
1022 
1023 	return true;
1024 }
1025 
VID_LockBuffer(void)1026 void VID_LockBuffer (void)
1027 {
1028 /* nothing. */
1029 }
1030 
VID_UnlockBuffer(void)1031 void VID_UnlockBuffer (void)
1032 {
1033 /* nothing. */
1034 }
1035 
1036 
VID_SetPalette(const unsigned char * palette)1037 void	VID_SetPalette (const unsigned char *palette)
1038 {
1039 	int		i;
1040 	RGBQUAD		colors[256];
1041 	const unsigned char *pal;
1042 
1043 	pal = palette;
1044 
1045 	if (!Minimized)
1046 	{
1047 		if (hdcDIBSection)
1048 		{
1049 			// incoming palette is 3 component
1050 			for (i = 0; i < 256; i++, pal += 3)
1051 			{
1052 				colors[i].rgbRed   = pal[0];
1053 				colors[i].rgbGreen = pal[1];
1054 				colors[i].rgbBlue  = pal[2];
1055 				colors[i].rgbReserved = 0;
1056 			}
1057 
1058 			colors[0].rgbRed = 0;
1059 			colors[0].rgbGreen = 0;
1060 			colors[0].rgbBlue = 0;
1061 			colors[255].rgbRed = 0xff;
1062 			colors[255].rgbGreen = 0xff;
1063 			colors[255].rgbBlue = 0xff;
1064 
1065 			if (SetDIBColorTable (hdcDIBSection, 0, 256, colors) == 0)
1066 			{
1067 				Con_SafePrintf ("DIB_SetPalette() - SetDIBColorTable failed\n");
1068 			}
1069 		}
1070 	}
1071 
1072 	if (palette != vid_curpal)
1073 		memcpy(vid_curpal, palette, sizeof (vid_curpal));
1074 }
1075 
1076 
VID_ShiftPalette(const unsigned char * palette)1077 void	VID_ShiftPalette (const unsigned char *palette)
1078 {
1079 	VID_SetPalette (palette);
1080 }
1081 
1082 
1083 /*
1084 =================
1085 VID_DescribeCurrentMode_f
1086 =================
1087 */
VID_DescribeCurrentMode_f(void)1088 static void VID_DescribeCurrentMode_f (void)
1089 {
1090 	Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum));
1091 }
1092 
1093 
1094 /*
1095 =================
1096 VID_NumModes_f
1097 =================
1098 */
VID_NumModes_f(void)1099 static void VID_NumModes_f (void)
1100 {
1101 	if (nummodes == 1)
1102 		Con_Printf ("%d video mode is available\n", nummodes);
1103 	else
1104 		Con_Printf ("%d video modes are available\n", nummodes);
1105 }
1106 
1107 
1108 /*
1109 =================
1110 VID_DescribeMode_f
1111 =================
1112 */
VID_DescribeMode_f(void)1113 static void VID_DescribeMode_f (void)
1114 {
1115 	int		modenum;
1116 
1117 	modenum = atoi (Cmd_Argv(1));
1118 
1119 	Con_Printf ("%s\n", VID_GetExtModeDescription (modenum));
1120 }
1121 
1122 
1123 /*
1124 =================
1125 VID_DescribeModes_f
1126 =================
1127 */
VID_DescribeModes_f(void)1128 static void VID_DescribeModes_f (void)
1129 {
1130 	int		i, lnummodes;
1131 	const char	*pinfo;
1132 	qboolean	na;
1133 	vmode_t		*pv;
1134 
1135 	na = false;
1136 
1137 	lnummodes = VID_NumModes ();
1138 
1139 	for (i = 0; i < lnummodes; i++)
1140 	{
1141 		pv = VID_GetModePtr (i);
1142 		pinfo = VID_GetExtModeDescription (i);
1143 
1144 		if (VID_CheckAdequateMem (pv->width, pv->height))
1145 		{
1146 			Con_Printf ("%2d: %s\n", i, pinfo);
1147 		}
1148 		else
1149 		{
1150 			Con_Printf ("**: %s\n", pinfo);
1151 			na = true;
1152 		}
1153 	}
1154 
1155 	if (na)
1156 	{
1157 		Con_Printf ("\n[**: not enough system RAM for mode]\n");
1158 	}
1159 }
1160 
1161 
1162 /*
1163 =================
1164 VID_TestMode_f
1165 =================
1166 */
VID_TestMode_f(void)1167 static void VID_TestMode_f (void)
1168 {
1169 	int		modenum;
1170 	double	testduration;
1171 
1172 	if (!vid_testingmode)
1173 	{
1174 		modenum = atoi (Cmd_Argv(1));
1175 
1176 		if (VID_SetMode (modenum, vid_curpal))
1177 		{
1178 			vid_testingmode = 1;
1179 			testduration = atof (Cmd_Argv(2));
1180 			if (testduration == 0)
1181 				testduration = 5.0;
1182 			vid_testendtime = realtime + testduration;
1183 		}
1184 	}
1185 }
1186 
1187 
1188 /*
1189 =================
1190 VID_Minimize_f
1191 =================
1192 */
VID_Minimize_f(void)1193 static void VID_Minimize_f (void)
1194 {
1195 // we only support minimizing windows; if you're fullscreen,
1196 // switch to windowed first
1197 	if (modestate == MS_WINDOWED)
1198 		ShowWindow (mainwindow, SW_MINIMIZE);
1199 }
1200 
1201 
1202 /*
1203 =================
1204 VID_ForceMode_f
1205 =================
1206 */
VID_ForceMode_f(void)1207 static void VID_ForceMode_f (void)
1208 {
1209 	int		modenum;
1210 
1211 	if (!vid_testingmode)
1212 	{
1213 		modenum = atoi (Cmd_Argv(1));
1214 
1215 		force_mode_set = true;
1216 		VID_SetMode (modenum, vid_curpal);
1217 		force_mode_set = false;
1218 	}
1219 }
1220 
1221 
VID_Init(const unsigned char * palette)1222 void	VID_Init (const unsigned char *palette)
1223 {
1224 	int		i, bestmatch, bestmatchmetric, t, dr, dg, db;
1225 	byte		*ptmp;
1226 	const char	*read_vars[] = {
1227 				"_vid_default_mode_win" };
1228 #define num_readvars	( sizeof(read_vars)/sizeof(read_vars[0]) )
1229 
1230 	Cvar_RegisterVariable (&vid_mode);
1231 	Cvar_RegisterVariable (&_vid_default_mode);
1232 	Cvar_RegisterVariable (&_vid_default_mode_win);
1233 	Cvar_RegisterVariable (&vid_config_x);
1234 	Cvar_RegisterVariable (&vid_config_y);
1235 	Cvar_RegisterVariable (&_enable_mouse);
1236 	Cvar_RegisterVariable (&vid_fullscreen_mode);
1237 	Cvar_RegisterVariable (&vid_windowed_mode);
1238 
1239 	Cmd_AddCommand ("vid_testmode", VID_TestMode_f);
1240 	Cmd_AddCommand ("vid_nummodes", VID_NumModes_f);
1241 	Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f);
1242 	Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f);
1243 	Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f);
1244 	Cmd_AddCommand ("vid_forcemode", VID_ForceMode_f);
1245 	Cmd_AddCommand ("vid_windowed", VID_Windowed_f);
1246 	Cmd_AddCommand ("vid_fullscreen", VID_Fullscreen_f);
1247 	Cmd_AddCommand ("vid_minimize", VID_Minimize_f);
1248 
1249 // perform an early read of config.cfg
1250 	CFG_ReadCvars (read_vars, num_readvars);
1251 
1252 	VID_InitModes (global_hInstance);
1253 	VID_GetDisplayModes ();
1254 
1255 	vid.maxwarpwidth = WARP_WIDTH;
1256 	vid.maxwarpheight = WARP_HEIGHT;
1257 	vid.colormap = host_colormap;
1258 	vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
1259 	vid_testingmode = 0;
1260 
1261 // GDI doesn't let us remap palette index 0, so we'll remap color
1262 // mappings from that black to another one
1263 	bestmatchmetric = 256*256*3;
1264 	bestmatch = 0;	// FIXME - uninitialized, guessing 0...
1265 
1266 	for (i = 1; i < 256; i++)
1267 	{
1268 		dr = palette[0] - palette[i*3];
1269 		dg = palette[1] - palette[i*3+1];
1270 		db = palette[2] - palette[i*3+2];
1271 
1272 		t = (dr * dr) + (dg * dg) + (db * db);
1273 
1274 		if (t < bestmatchmetric)
1275 		{
1276 			bestmatchmetric = t;
1277 			bestmatch = i;
1278 
1279 			if (t == 0)
1280 				break;
1281 		}
1282 	}
1283 
1284 	for (i = 0, ptmp = vid.colormap; i < (1 << (VID_CBITS + 8)); i++, ptmp++)
1285 	{
1286 		if (*ptmp == 0)
1287 			*ptmp = bestmatch;
1288 	}
1289 
1290 	if (COM_CheckParm("-startwindowed") || COM_CheckParm("-window") || COM_CheckParm("-w"))
1291 	{
1292 		startwindowed = true;
1293 		Cvar_SetValueQuick (&_vid_default_mode_win, windowed_default);
1294 		vid_default = windowed_default;
1295 	}
1296 
1297 	if (_vid_default_mode_win.integer < 0 || _vid_default_mode_win.integer >= nummodes)
1298 		Cvar_SetValueQuick (&_vid_default_mode_win, windowed_default);
1299 	Cvar_LockVar ("_vid_default_mode_win");	/* so that config.cfg doesn't break -window */
1300 
1301 #if !defined(NO_SPLASHES)
1302 	if (hwnd_dialog)
1303 	{
1304 		DestroyWindow (hwnd_dialog);
1305 		hwnd_dialog = NULL;
1306 	}
1307 #endif	/* ! NO_SPLASHES */
1308 
1309 	/* set default fullscreen mode only if
1310 	 * setting the windowed default fails: */
1311 	if (!VID_SetMode(MODE_WINDOWED, palette))
1312 	{
1313 		force_mode_set = true;
1314 		VID_SetMode(vid_default, palette);
1315 		force_mode_set = false;
1316 	}
1317 
1318 	vid_initialized = true;
1319 	vid_realmode = vid_modenum;
1320 	VID_SetPalette (palette);
1321 	vid_menudrawfn = VID_MenuDraw;
1322 	vid_menukeyfn = VID_MenuKey;
1323 	q_strlcpy (badmode.modedesc, "Bad mode", MAX_DESC);
1324 }
1325 
1326 
VID_Shutdown(void)1327 void	VID_Shutdown (void)
1328 {
1329 	if (vid_initialized)
1330 	{
1331 		if (modestate == MS_FULLDIB)
1332 			ChangeDisplaySettings (NULL, CDS_FULLSCREEN);
1333 
1334 		PostMessage (HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)mainwindow, (LPARAM)0);
1335 		PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
1336 
1337 		AppActivate(false, false);
1338 
1339 		VID_DestroyWindow ();
1340 
1341 #if !defined(NO_SPLASHES)
1342 		if (hwnd_dialog)
1343 		{
1344 			DestroyWindow (hwnd_dialog);
1345 			hwnd_dialog = NULL;
1346 		}
1347 #endif	/* ! NO_SPLASHES */
1348 
1349 		if (mainwindow)
1350 			DestroyWindow(mainwindow);
1351 
1352 		vid_testingmode = 0;
1353 		vid_initialized = 0;
1354 	}
1355 }
1356 
1357 
1358 /*
1359 ================
1360 FlipScreen
1361 ================
1362 */
FlipScreen(vrect_t * rects)1363 static void FlipScreen (vrect_t *rects)
1364 {
1365 	if (hdcDIBSection)
1366 	{
1367 		int numrects = 0;
1368 
1369 		while (rects)
1370 		{
1371 			BitBlt (maindc,
1372 				rects->x, rects->y,
1373 				rects->x + rects->width,
1374 				rects->y + rects->height,
1375 				hdcDIBSection,
1376 				rects->x, rects->y,
1377 				SRCCOPY);
1378 
1379 			numrects++;
1380 			rects = rects->pnext;
1381 		}
1382 	}
1383 }
1384 
1385 
VID_Update(vrect_t * rects)1386 void VID_Update (vrect_t *rects)
1387 {
1388 	vrect_t		rect;
1389 
1390 	if (!vid_palettized && palette_changed)
1391 	{
1392 		palette_changed = false;
1393 		rect.x = 0;
1394 		rect.y = 0;
1395 		rect.width = vid.width;
1396 		rect.height = vid.height;
1397 		rect.pnext = NULL;
1398 		rects = &rect;
1399 	}
1400 
1401 	if (firstupdate && host_initialized)
1402 	{
1403 		firstupdate = false;
1404 		Cvar_SetValueQuick (&vid_mode, _vid_default_mode_win.integer);
1405 	}
1406 
1407 	// We've drawn the frame; copy it to the screen
1408 	FlipScreen (rects);
1409 
1410 	if (vid_testingmode)
1411 	{
1412 		if (realtime >= vid_testendtime)
1413 		{
1414 			VID_SetMode (vid_realmode, vid_curpal);
1415 			vid_testingmode = 0;
1416 		}
1417 	}
1418 	else
1419 	{
1420 		if (vid_mode.integer != vid_realmode)
1421 		{
1422 			VID_SetMode (vid_mode.integer, vid_curpal);
1423 			Cvar_SetValueQuick (&vid_mode, vid_modenum);
1424 							// so if mode set fails, we don't keep on
1425 							//  trying to set it
1426 			vid_realmode = vid_modenum;
1427 		}
1428 	}
1429 
1430 // handle the mouse state when windowed if that's changed
1431 	if (modestate == MS_WINDOWED)
1432 	{
1433 		if (_enable_mouse.integer != enable_mouse)
1434 		{
1435 			if (_enable_mouse.integer)
1436 			{
1437 				IN_ActivateMouse ();
1438 				IN_HideMouse ();
1439 			}
1440 			else
1441 			{
1442 				IN_DeactivateMouse ();
1443 				IN_ShowMouse ();
1444 			}
1445 
1446 			enable_mouse = _enable_mouse.integer;
1447 		}
1448 	}
1449 }
1450 
1451 
1452 /*
1453 ================
1454 D_BeginDirectRect
1455 ================
1456 */
D_BeginDirectRect(int x,int y,byte * pbitmap,int width,int height)1457 void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)
1458 {
1459 	int		i, j, reps, repshift;
1460 	vrect_t		rect;
1461 
1462 	if (!vid_initialized)
1463 		return;
1464 
1465 	if (vid.aspect > 1.5)
1466 	{
1467 		reps = 2;
1468 		repshift = 1;
1469 	}
1470 	else
1471 	{
1472 		reps = 1;
1473 		repshift = 0;
1474 	}
1475 
1476 //	if (vid.numpages == 1)
1477 //	{
1478 		VID_LockBuffer ();
1479 
1480 		if (!vid.direct)
1481 			Sys_Error ("NULL vid.direct pointer");
1482 
1483 		for (i = 0; i < (height << repshift); i += reps)
1484 		{
1485 			for (j = 0; j < reps; j++)
1486 			{
1487 				memcpy (&backingbuf[(i + j) * width] /* &backingbuf[(i + j) * 24] */,
1488 						vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
1489 						width);
1490 				memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
1491 						&pbitmap[(i >> repshift) * width],
1492 						width);
1493 			}
1494 		}
1495 
1496 		VID_UnlockBuffer ();
1497 
1498 		rect.x = x;
1499 		rect.y = y;
1500 		rect.width = width;
1501 		rect.height = height << repshift;
1502 		rect.pnext = NULL;
1503 
1504 		FlipScreen (&rect);
1505 //	}
1506 //	else
1507 //	{
1508 //	}
1509 }
1510 
1511 
1512 #ifndef H2W
1513 /* unused in hexenworld */
D_ShowLoadingSize(void)1514 void D_ShowLoadingSize (void)
1515 {
1516 #if defined(DRAW_PROGRESSBARS)
1517 	static int prev_perc;
1518 	int		cur_perc;
1519 	vrect_t		rect;
1520 	viddef_t	save_vid;	/* global video state */
1521 
1522 	if (!vid_initialized)
1523 		return;
1524 
1525 	cur_perc = loading_stage * 100;
1526 	if (total_loading_size)
1527 		cur_perc += current_loading_size * 100 / total_loading_size;
1528 	if (cur_perc == prev_perc)
1529 		return;
1530 	prev_perc = cur_perc;
1531 
1532 	save_vid = vid;
1533 //	if (vid.numpages == 1)
1534 //	{
1535 		VID_LockBuffer ();
1536 
1537 		if (!vid.direct)
1538 			Sys_Error ("NULL vid.direct pointer");
1539 
1540 		vid.buffer = vid.direct;
1541 
1542 		SCR_DrawLoading();
1543 
1544 		VID_UnlockBuffer ();
1545 
1546 #if 1	/* original code */
1547 		rect.x = 0;
1548 		rect.y = 0;
1549 		rect.width = vid.width;
1550 #else	/* Pa3PyX: tweaking sizes - faster redraw */
1551 		rect.x = (vid.width >> 1) - 100;
1552 		rect.y = 0;
1553 		rect.width = 200;
1554 #endif
1555 		rect.height = 112;
1556 		rect.pnext = NULL;
1557 
1558 		FlipScreen (&rect);
1559 //	}
1560 //	else
1561 //	{
1562 //	}
1563 
1564 	vid = save_vid;
1565 #endif	/* !DRAW_PROGRESSBARS */
1566 }
1567 #endif	/* ! H2W */
1568 
1569 
1570 /*
1571 ================
1572 D_EndDirectRect
1573 ================
1574 */
D_EndDirectRect(int x,int y,int width,int height)1575 void D_EndDirectRect (int x, int y, int width, int height)
1576 {
1577 	int		i, j, reps, repshift;
1578 	vrect_t		rect;
1579 
1580 	if (!vid_initialized)
1581 		return;
1582 
1583 	if (vid.aspect > 1.5)
1584 	{
1585 		reps = 2;
1586 		repshift = 1;
1587 	}
1588 	else
1589 	{
1590 		reps = 1;
1591 		repshift = 0;
1592 	}
1593 
1594 //	if (vid.numpages == 1)
1595 //	{
1596 		VID_LockBuffer ();
1597 
1598 		if (!vid.direct)
1599 			Sys_Error ("NULL vid.direct pointer");
1600 
1601 		for (i = 0; i < (height << repshift); i += reps)
1602 		{
1603 			for (j = 0; j < reps; j++)
1604 			{
1605 				memcpy (vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
1606 						&backingbuf[(i + j) * width] /* &backingbuf[(i + j) * 24] */,
1607 						width);
1608 			}
1609 		}
1610 
1611 		VID_UnlockBuffer ();
1612 
1613 		rect.x = x;
1614 		rect.y = y;
1615 		rect.width = width;
1616 		rect.height = height << repshift;
1617 		rect.pnext = NULL;
1618 
1619 		FlipScreen (&rect);
1620 //	}
1621 //	else
1622 //	{
1623 //	}
1624 }
1625 
1626 
1627 //==========================================================================
1628 
1629 /*
1630 =======
1631 MapKey
1632 
1633 Map from windows to quake keynums
1634 =======
1635 */
1636 static byte scantokey[128] =
1637 {
1638 //	0        1       2       3       4       5       6       7
1639 //	8        9       A       B       C       D       E       F
1640 	0  ,    27,     '1',    '2',    '3',    '4',    '5',    '6',
1641 	'7',    '8',    '9',    '0',    '-',    '=', K_BACKSPACE, 9,	// 0
1642 	'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
1643 	'o',    'p',    '[',    ']',  K_ENTER, K_CTRL,  'a',    's',	// 1
1644 	'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
1645 	'\'',   '`',  K_SHIFT,  '\\',   'z',    'x',    'c',    'v',	// 2
1646 	'b',    'n',    'm',    ',',    '.',    '/',  K_SHIFT, K_KP_STAR,
1647 	K_ALT,  ' ',     0 ,    K_F1,   K_F2,   K_F3,   K_F4,  K_F5,	// 3
1648 	K_F6,  K_F7,   K_F8,    K_F9,  K_F10, K_PAUSE,   0 , K_HOME,
1649 	K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW,K_KP_PLUS,K_END,	// 4
1650 	K_DOWNARROW,K_PGDN,K_INS,K_DEL,   0 ,    0 ,     0 ,  K_F11,
1651 	K_F12,   0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,	// 5
1652 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,
1653 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,	// 6
1654 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,
1655 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0	// 7
1656 };
1657 
1658 #if 0	/* not used */
1659 static byte shiftscantokey[128] =
1660 {
1661 //	0       1       2       3       4       5       6       7
1662 //	8       9       A       B       C       D       E       F
1663 	0  ,    27,     '!',    '@',    '#',    '$',    '%',    '^',
1664 	'&',    '*',    '(',    ')',    '_',    '+', K_BACKSPACE, 9,	// 0
1665 	'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
1666 	'O',    'P',    '{',    '}',  K_ENTER, K_CTRL,  'A',    'S',	// 1
1667 	'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':',
1668 	'"' ,    '~', K_SHIFT,  '|',    'Z',    'X',    'C',    'V',	// 2
1669 	'B',    'N',    'M',    '<',    '>',    '?',  K_SHIFT, K_KP_STAR,
1670 	K_ALT,  ' ',     0 ,    K_F1,   K_F2,   K_F3,   K_F4,  K_F5,	// 3
1671 	K_F6,  K_F7,   K_F8,    K_F9,  K_F10, K_PAUSE,   0 , K_HOME,
1672 	K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW,K_KP_PLUS,K_END,	// 4
1673 	K_DOWNARROW,K_PGDN,K_INS,K_DEL,   0 ,    0 ,     0 ,  K_F11,
1674 	K_F12,   0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,	// 5
1675 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,
1676 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,	// 6
1677 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0 ,
1678 	0  ,     0 ,     0 ,     0 ,      0 ,    0 ,     0 ,     0	// 7
1679 };
1680 #endif
1681 
MapKey(int key)1682 static int MapKey (int key)
1683 {
1684 	int result = (key >> 16) & 255;
1685 
1686 	if (result > 127)
1687 		return 0;
1688 	result = scantokey[result];
1689 
1690 	if (key & (1 << 24)) /* extended */
1691 	{
1692 		switch (result)
1693 		{
1694 		case K_PAUSE:
1695 			return	(Key_IsGameKey()) ? K_KP_NUMLOCK : 0;
1696 		case K_ENTER:
1697 			return	(Key_IsGameKey()) ? K_KP_ENTER : K_ENTER;
1698 		case '/':
1699 			return	(Key_IsGameKey()) ? K_KP_SLASH : '/';
1700 		}
1701 	}
1702 	else /* standart */
1703 	{
1704 		switch (result)
1705 		{
1706 		case K_KP_STAR:
1707 			return	(Key_IsGameKey()) ? K_KP_STAR : '*';
1708 		case K_KP_PLUS:
1709 			return	(Key_IsGameKey()) ? K_KP_PLUS : '+';
1710 		case K_KP_MINUS:
1711 			return	(Key_IsGameKey()) ? K_KP_MINUS : '-';
1712 		case K_HOME:
1713 			return	(Key_IsGameKey()) ? K_KP_HOME :
1714 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '7' : K_HOME;
1715 		case K_UPARROW:
1716 			return	(Key_IsGameKey()) ? K_KP_UPARROW :
1717 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '8' : K_UPARROW;
1718 		case K_PGUP:
1719 			return	(Key_IsGameKey()) ? K_KP_PGUP :
1720 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '9' : K_PGUP;
1721 		case K_LEFTARROW:
1722 			return	(Key_IsGameKey()) ? K_KP_LEFTARROW :
1723 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '4' : K_LEFTARROW;
1724 		case K_KP_5:
1725 			return	(Key_IsGameKey()) ? K_KP_5 : '5';
1726 		case K_RIGHTARROW:
1727 			return	(Key_IsGameKey()) ? K_KP_RIGHTARROW :
1728 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '6' : K_RIGHTARROW;
1729 		case K_END:
1730 			return	(Key_IsGameKey()) ? K_KP_END :
1731 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '1' : K_END;
1732 		case K_DOWNARROW:
1733 			return	(Key_IsGameKey()) ? K_KP_DOWNARROW :
1734 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '2' : K_DOWNARROW;
1735 		case K_PGDN:
1736 			return	(Key_IsGameKey()) ? K_KP_PGDN :
1737 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '3' : K_PGDN;
1738 		case K_INS:
1739 			return	(Key_IsGameKey()) ? K_KP_INS :
1740 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '0' : K_INS;
1741 		case K_DEL:
1742 			return	(Key_IsGameKey()) ? K_KP_DEL :
1743 				(GetKeyState(VK_NUMLOCK) & 0x01) ? '.' : K_DEL;
1744 		}
1745 	}
1746 
1747 	return result;
1748 }
1749 
1750 
AppActivate(BOOL fActive,BOOL minimize)1751 static void AppActivate (BOOL fActive, BOOL minimize)
1752 /****************************************************************************
1753 *
1754 * Function:	AppActivate
1755 * Parameters:	fActive - True if app is activating
1756 *
1757 * Description:	If the application is activating, then swap the system
1758 *		into SYSPAL_NOSTATIC mode so that our palettes will display
1759 *		correctly.
1760 *
1761 ****************************************************************************/
1762 {
1763 	HDC			hdc;
1764 	int			i;
1765 	qboolean		t;
1766 	static qboolean	sound_active;
1767 
1768 	ActiveApp = fActive;
1769 
1770 // messy, but it seems to work
1771 	if (vid_fulldib_on_focus_mode)
1772 	{
1773 		Minimized = minimize;
1774 
1775 		if (Minimized)
1776 			ActiveApp = false;
1777 	}
1778 
1779 	if (vid_initialized)
1780 	{
1781 	// yield the palette if we're losing the focus
1782 		hdc = GetDC(NULL);
1783 
1784 		if (!Minimized)
1785 			VID_SetPalette (vid_curpal);
1786 
1787 		scr_fullupdate = 0;
1788 
1789 		ReleaseDC(NULL,hdc);
1790 	}
1791 
1792 // enable/disable sound on focus gain/loss
1793 	if (!ActiveApp && sound_active)
1794 	{
1795 		S_BlockSound ();
1796 		sound_active = false;
1797 	}
1798 	else if (ActiveApp && !sound_active)
1799 	{
1800 		S_UnblockSound ();
1801 		sound_active = true;
1802 	}
1803 
1804 // minimize/restore fulldib windows/mouse-capture normal windows on demand
1805 	if (!in_mode_set)
1806 	{
1807 		if (ActiveApp)
1808 		{
1809 			if (vid_fulldib_on_focus_mode)
1810 			{
1811 				if (vid_initialized)
1812 				{
1813 					msg_suppress_1 = true;	// don't want to see normal mode set message
1814 					VID_SetMode (vid_fulldib_on_focus_mode, vid_curpal);
1815 					msg_suppress_1 = false;
1816 
1817 					t = in_mode_set;
1818 					in_mode_set = true;
1819 					AppActivate (true, false);
1820 					in_mode_set = t;
1821 				}
1822 
1823 				IN_ActivateMouse ();
1824 				IN_HideMouse ();
1825 			}
1826 			else if (modestate == MS_WINDOWED && _enable_mouse.integer)
1827 			{
1828 			// with winmouse, we may fail having our
1829 			// window back from the iconified state. yuck...
1830 				if (dinput_init)
1831 				{
1832 					IN_ActivateMouse ();
1833 					IN_HideMouse ();
1834 				}
1835 			}
1836 		}
1837 
1838 		if (!ActiveApp)
1839 		{
1840 			if (modestate == MS_FULLDIB)
1841 			{
1842 				if (vid_initialized)
1843 				{
1844 					force_minimized = true;
1845 					i = vid_fulldib_on_focus_mode;
1846 					msg_suppress_1 = true;	// don't want to see normal mode set message
1847 					VID_SetMode (windowed_default, vid_curpal);
1848 					msg_suppress_1 = false;
1849 					vid_fulldib_on_focus_mode = i;
1850 					force_minimized = false;
1851 
1852 				// we never seem to get WM_ACTIVATE inactive from this mode set, so we'll
1853 				// do it manually
1854 					t = in_mode_set;
1855 					in_mode_set = true;
1856 					AppActivate (false, true);
1857 					in_mode_set = t;
1858 				}
1859 
1860 				IN_DeactivateMouse ();
1861 				IN_ShowMouse ();
1862 			}
1863 			else if (modestate == MS_WINDOWED && _enable_mouse.integer)
1864 			{
1865 				IN_DeactivateMouse ();
1866 				IN_ShowMouse ();
1867 			}
1868 		}
1869 	}
1870 }
1871 
1872 
1873 /*
1874 ================
1875 VID_HandlePause
1876 ================
1877 */
VID_HandlePause(qboolean paused)1878 void VID_HandlePause (qboolean paused)
1879 {
1880 	if (modestate == MS_WINDOWED && _enable_mouse.integer)
1881 	{
1882 		if (paused)
1883 		{
1884 			IN_DeactivateMouse ();
1885 			IN_ShowMouse ();
1886 		}
1887 		else
1888 		{
1889 			IN_ActivateMouse ();
1890 			IN_HideMouse ();
1891 		}
1892 	}
1893 }
1894 
1895 
VID_ToggleFullscreen(void)1896 void VID_ToggleFullscreen (void)
1897 {
1898 }
1899 
1900 
1901 /*
1902 ===================================================================
1903 
1904 MAIN WINDOW
1905 
1906 ===================================================================
1907 */
1908 
1909 static int	MWheelAccumulator;
1910 static UINT	uMSG_MOUSEWHEEL = 0;
1911 extern cvar_t	mwheelthreshold;
1912 
1913 /* main window procedure */
MainWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1914 static LRESULT WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1915 {
1916 	LRESULT	ret = 0;
1917 	int	fActive, fMinimized, temp;
1918 	HDC		hdc;
1919 	PAINTSTRUCT	ps;
1920 
1921 	if (uMSG_MOUSEWHEEL && uMsg == uMSG_MOUSEWHEEL)
1922 	{
1923 		/* Win95/WinNT-3.51 code using MSH_MOUSEWHEEL, see:
1924 		 * http://msdn.microsoft.com/en-us/library/ms645617.aspx */
1925 		if (mwheelthreshold.integer >= 1)
1926 		{
1927 			MWheelAccumulator += (int) wParam;
1928 			while (MWheelAccumulator >= mwheelthreshold.integer)
1929 			{
1930 				Key_Event(K_MWHEELUP, true);
1931 				Key_Event(K_MWHEELUP, false);
1932 				MWheelAccumulator -= mwheelthreshold.integer;
1933 			}
1934 			while (MWheelAccumulator <= -mwheelthreshold.integer)
1935 			{
1936 				Key_Event(K_MWHEELDOWN, true);
1937 				Key_Event(K_MWHEELDOWN, false);
1938 				MWheelAccumulator += mwheelthreshold.integer;
1939 			}
1940 		}
1941 		return DefWindowProc (hWnd, uMsg, wParam, lParam);
1942 	}
1943 
1944 	switch (uMsg)
1945 	{
1946 	case WM_CREATE:
1947 		if (Win95)
1948 		{
1949 			uMSG_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG");
1950 			if (!uMSG_MOUSEWHEEL)
1951 				Con_SafePrintf ("couldn't register mousewheel\n");
1952 		}
1953 		break;
1954 
1955 	case WM_SYSCOMMAND:
1956 		// Check for maximize being hit
1957 		switch (wParam & ~0x0F)
1958 		{
1959 		case SC_MAXIMIZE:
1960 		// if minimized, bring up as a window before going fullscreen,
1961 		// so MGL will have the right state to restore
1962 			if (Minimized)
1963 			{
1964 				force_mode_set = true;
1965 				VID_SetMode (vid_modenum, vid_curpal);
1966 				force_mode_set = false;
1967 			}
1968 			VID_SetMode (vid_fullscreen_mode.integer, vid_curpal);
1969 			break;
1970 
1971 		case SC_SCREENSAVE:
1972 		case SC_MONITORPOWER:
1973 			if (modestate != MS_WINDOWED)
1974 			{
1975 			// don't call DefWindowProc() because we don't want to start
1976 			// the screen saver fullscreen
1977 				break;
1978 			}
1979 		// fall through windowed and allow the screen saver to start
1980 		default:
1981 			if (!in_mode_set)
1982 				S_BlockSound ();
1983 			ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
1984 			if (!in_mode_set)
1985 				S_UnblockSound ();
1986 		}
1987 		break;
1988 
1989 	case WM_MOVE:
1990 		window_x = (short) LOWORD(lParam);
1991 		window_y = (short) HIWORD(lParam);
1992 		VID_UpdateWindowStatus ();
1993 		break;
1994 
1995 	case WM_SIZE:
1996 		Minimized = false;
1997 		if (!(wParam & SIZE_RESTORED))
1998 		{
1999 			if (wParam & SIZE_MINIMIZED)
2000 				Minimized = true;
2001 		}
2002 		break;
2003 
2004 	case WM_SYSCHAR:
2005 		// keep Alt-Space from happening
2006 		break;
2007 
2008 	case WM_ACTIVATE:
2009 		fActive = LOWORD(wParam);
2010 		fMinimized = (BOOL) HIWORD(wParam);
2011 		AppActivate(!(fActive == WA_INACTIVE), fMinimized);
2012 		// fix the leftover Alt from any Alt-Tab or the like that switched us away
2013 		ClearAllStates ();
2014 		if (!in_mode_set)
2015 			VID_SetPalette(vid_curpal);
2016 		break;
2017 
2018 	case WM_PAINT:
2019 		hdc = BeginPaint(hWnd, &ps);
2020 		if (!in_mode_set && host_initialized)
2021 			SCR_UpdateWholeScreen ();
2022 		EndPaint(hWnd, &ps);
2023 		break;
2024 
2025 	case WM_KEYDOWN:
2026 	case WM_SYSKEYDOWN:
2027 		if (in_mode_set)
2028 			break;
2029 		Key_Event (MapKey(lParam), true);
2030 		break;
2031 
2032 	case WM_KEYUP:
2033 	case WM_SYSKEYUP:
2034 		if (in_mode_set)
2035 			break;
2036 		Key_Event (MapKey(lParam), false);
2037 		break;
2038 
2039 	// this is complicated because Win32 seems to pack multiple mouse
2040 	// events into one update sometimes, so we always check all states
2041 	// and look for events
2042 	case WM_LBUTTONDOWN:
2043 	case WM_LBUTTONUP:
2044 	case WM_RBUTTONDOWN:
2045 	case WM_RBUTTONUP:
2046 	case WM_MBUTTONDOWN:
2047 	case WM_MBUTTONUP:
2048 	case WM_XBUTTONDOWN:
2049 	case WM_XBUTTONUP:
2050 	case WM_MOUSEMOVE:
2051 		if (in_mode_set)
2052 			break;
2053 
2054 		temp = 0;
2055 
2056 		if (wParam & MK_LBUTTON)
2057 			temp |= 1;
2058 
2059 		if (wParam & MK_RBUTTON)
2060 			temp |= 2;
2061 
2062 		if (wParam & MK_MBUTTON)
2063 			temp |= 4;
2064 
2065 		// intellimouse explorer
2066 		if (wParam & MK_XBUTTON1)
2067 			temp |= 8;
2068 
2069 		if (wParam & MK_XBUTTON2)
2070 			temp |= 16;
2071 
2072 		IN_MouseEvent (temp);
2073 
2074 		break;
2075 
2076 	case WM_MOUSEWHEEL:
2077 		if (in_mode_set)
2078 			return 0;
2079 		if ((short) HIWORD(wParam) > 0)
2080 		{
2081 			Key_Event(K_MWHEELUP, true);
2082 			Key_Event(K_MWHEELUP, false);
2083 		}
2084 		else
2085 		{
2086 			Key_Event(K_MWHEELDOWN, true);
2087 			Key_Event(K_MWHEELDOWN, false);
2088 		}
2089 		return 0;
2090 
2091 	case WM_DISPLAYCHANGE:
2092 		if (!in_mode_set && (modestate == MS_WINDOWED) && !vid_fulldib_on_focus_mode)
2093 		{
2094 			force_mode_set = true;
2095 			VID_SetMode (vid_modenum, vid_curpal);
2096 			force_mode_set = false;
2097 		}
2098 		break;
2099 
2100 	case WM_CLOSE:
2101 		if (in_mode_set)
2102 			break;
2103 		// this causes Close in the right-click task bar menu not to
2104 		// work, but right now bad things happen if Close is handled
2105 		// in that case (garbage and a crash on Win95)
2106 		if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit",
2107 					MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES)
2108 		{
2109 			Sys_Quit ();
2110 		}
2111 		break;
2112 
2113 	case MM_MCINOTIFY:
2114 #if !defined(_NO_CDAUDIO)
2115 		ret = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
2116 #endif	/* ! _NO_CDAUDIO */
2117 		break;
2118 
2119 	default:
2120 		/* pass all unhandled messages to DefWindowProc */
2121 		ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
2122 		break;
2123 	}
2124 
2125 	/* return 1 if handled message, 0 if not */
2126 	return ret;
2127 }
2128 
2129 
2130 //========================================================
2131 // Video menu stuff
2132 //========================================================
2133 
2134 static int	vid_line, vid_wmodes;
2135 
2136 typedef struct
2137 {
2138 	int		modenum;
2139 	const char	*desc;
2140 	int		iscur;
2141 	int		width;
2142 } modedesc_t;
2143 
2144 #define MAX_COLUMN_SIZE		5
2145 #define MODE_AREA_HEIGHT	(MAX_COLUMN_SIZE + 6)
2146 #define MAX_MODEDESCS		(MAX_COLUMN_SIZE * 3)
2147 
2148 static modedesc_t	modedescs[MAX_MODEDESCS];
2149 static const char	no_desc[] = "N/A";
2150 
2151 /*
2152 ================
2153 VID_MenuDraw
2154 ================
2155 */
VID_MenuDraw(void)2156 static void VID_MenuDraw (void)
2157 {
2158 	const char	*ptr;
2159 	int			lnummodes, i, j, k, column, row, dup, dupmode;
2160 	char		temp[100];
2161 	vmode_t		*pv;
2162 	modedesc_t	tmodedesc;
2163 
2164 	ScrollTitle("gfx/menu/title7.lmp");
2165 
2166 	for (i = 0; i < 3; i++)
2167 	{
2168 		ptr = VID_GetModeDescriptionMemCheck (i);
2169 		modedescs[i].modenum = modelist[i].modenum;
2170 		modedescs[i].desc = ptr ? ptr : no_desc;
2171 		modedescs[i].iscur = 0;
2172 
2173 		if (vid_modenum == i)
2174 			modedescs[i].iscur = 1;
2175 	}
2176 
2177 	vid_wmodes = 3;
2178 	lnummodes = VID_NumModes ();
2179 
2180 	for (i = 3; i < lnummodes; i++)
2181 	{
2182 		ptr = VID_GetModeDescriptionMemCheck (i);
2183 		pv = VID_GetModePtr (i);
2184 
2185 	// we only have room for 15 fullscreen modes, so don't allow
2186 	// 360-wide modes, because if there are 5 320-wide modes and
2187 	// 5 360-wide modes, we'll run out of space
2188 		if (ptr && ((pv->width != 360) || COM_CheckParm("-allow360")))
2189 		{
2190 			dup = 0;
2191 
2192 			for (j = 3; j < vid_wmodes; j++)
2193 			{
2194 				if (!strcmp (modedescs[j].desc, ptr))
2195 				{
2196 					dup = 1;
2197 					dupmode = j;
2198 					break;
2199 				}
2200 			}
2201 
2202 			if (dup || (vid_wmodes < MAX_MODEDESCS))
2203 			{
2204 				if (!dup || COM_CheckParm("-noforcevga"))
2205 				{
2206 					if (dup)
2207 					{
2208 						k = dupmode;
2209 					}
2210 					else
2211 					{
2212 						k = vid_wmodes;
2213 					}
2214 
2215 					modedescs[k].modenum = i;
2216 					modedescs[k].desc = ptr;
2217 					modedescs[k].iscur = 0;
2218 					modedescs[k].width = pv->width;
2219 
2220 					if (i == vid_modenum)
2221 						modedescs[k].iscur = 1;
2222 
2223 					if (!dup)
2224 						vid_wmodes++;
2225 				}
2226 			}
2227 		}
2228 	}
2229 
2230 // sort the modes on width (to handle picking up oddball dibonly modes
2231 // after all the others)
2232 	for (i = 3; i< (vid_wmodes-1); i++)
2233 	{
2234 		for (j = (i+1); j < vid_wmodes; j++)
2235 		{
2236 			if (modedescs[i].width > modedescs[j].width)
2237 			{
2238 				tmodedesc = modedescs[i];
2239 				modedescs[i] = modedescs[j];
2240 				modedescs[j] = tmodedesc;
2241 			}
2242 		}
2243 	}
2244 
2245 
2246 	M_Print (13*8, 60, "Windowed Modes");
2247 
2248 	column = 16;
2249 	row = 60+2*8;
2250 
2251 	for (i = 0; i < 3; i++)
2252 	{
2253 		if (modedescs[i].iscur)
2254 			M_PrintWhite (column, row, modedescs[i].desc);
2255 		else
2256 			M_Print (column, row, modedescs[i].desc);
2257 
2258 		column += 13*8;
2259 	}
2260 
2261 	if (vid_wmodes > 3)
2262 	{
2263 		M_Print (12*8, 60+4*8, "Fullscreen Modes");
2264 
2265 		column = 16;
2266 		row = 60+6*8;
2267 
2268 		for (i = 3; i < vid_wmodes; i++)
2269 		{
2270 			if (modedescs[i].iscur)
2271 				M_PrintWhite (column, row, modedescs[i].desc);
2272 			else
2273 				M_Print (column, row, modedescs[i].desc);
2274 
2275 			column += 13*8;
2276 
2277 			if (((i - 3) % VID_ROW_SIZE) == (VID_ROW_SIZE - 1))
2278 			{
2279 				column = 16;
2280 				row += 8;
2281 			}
2282 		}
2283 	}
2284 
2285 // line cursor
2286 	if (vid_testingmode)
2287 	{
2288 		q_snprintf (temp, sizeof(temp), "TESTING %s",
2289 				modedescs[vid_line].desc);
2290 		M_Print (13*8, 60 + MODE_AREA_HEIGHT * 8 + 8*4, temp);
2291 		M_Print (9*8, 60 + MODE_AREA_HEIGHT * 8 + 8*6,
2292 				"Please wait 5 seconds...");
2293 	}
2294 	else
2295 	{
2296 		M_Print (9*8, 60 + MODE_AREA_HEIGHT * 8,
2297 				"Press Enter to set mode");
2298 		M_Print (6*8, 60 + MODE_AREA_HEIGHT * 8 + 8*1,
2299 				"T to test mode for 5 seconds");
2300 		ptr = VID_GetModeDescription2 (vid_modenum);
2301 
2302 		if (ptr)
2303 		{
2304 			q_snprintf (temp, sizeof(temp), "D to set default: %s", ptr);
2305 			M_Print (2*8, 60 + MODE_AREA_HEIGHT * 8 + 8*2, temp);
2306 		}
2307 
2308 		ptr = VID_GetModeDescription2 (_vid_default_mode_win.integer);
2309 
2310 		if (ptr)
2311 		{
2312 			q_snprintf (temp, sizeof(temp), "Current default: %s", ptr);
2313 			M_Print (3*8, 60 + MODE_AREA_HEIGHT * 8 + 8*5, temp);
2314 		}
2315 
2316 		M_Print (15*8, 60 + MODE_AREA_HEIGHT * 8 + 8*6,
2317 				"Esc to exit");
2318 
2319 		row = 60 + 2*8 + (vid_line / VID_ROW_SIZE) * 8;
2320 		column = 8 + (vid_line % VID_ROW_SIZE) * 13*8;
2321 
2322 		if (vid_line >= 3)
2323 			row += 3*8;
2324 
2325 		M_DrawCharacter (column, row, 12+((int)(realtime*4)&1));
2326 	}
2327 }
2328 
2329 
2330 /*
2331 ================
2332 VID_MenuKey
2333 ================
2334 */
VID_MenuKey(int key)2335 static void VID_MenuKey (int key)
2336 {
2337 	if (vid_testingmode)
2338 		return;
2339 
2340 	switch (key)
2341 	{
2342 	case K_ESCAPE:
2343 		S_LocalSound ("raven/menu1.wav");
2344 		M_Menu_Options_f ();
2345 		break;
2346 
2347 	case K_LEFTARROW:
2348 		S_LocalSound ("raven/menu1.wav");
2349 		vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) + ((vid_line + 2) % VID_ROW_SIZE);
2350 		if (vid_line >= vid_wmodes)
2351 			vid_line = vid_wmodes - 1;
2352 		break;
2353 
2354 	case K_RIGHTARROW:
2355 		S_LocalSound ("raven/menu1.wav");
2356 		vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) + ((vid_line + 4) % VID_ROW_SIZE);
2357 		if (vid_line >= vid_wmodes)
2358 			vid_line = (vid_line / VID_ROW_SIZE) * VID_ROW_SIZE;
2359 		break;
2360 
2361 	case K_UPARROW:
2362 		S_LocalSound ("raven/menu1.wav");
2363 		vid_line -= VID_ROW_SIZE;
2364 		if (vid_line < 0)
2365 		{
2366 			vid_line += ((vid_wmodes + (VID_ROW_SIZE - 1)) / VID_ROW_SIZE) * VID_ROW_SIZE;
2367 			while (vid_line >= vid_wmodes)
2368 				vid_line -= VID_ROW_SIZE;
2369 		}
2370 		break;
2371 
2372 	case K_DOWNARROW:
2373 		S_LocalSound ("raven/menu1.wav");
2374 		vid_line += VID_ROW_SIZE;
2375 		if (vid_line >= vid_wmodes)
2376 		{
2377 			vid_line -= ((vid_wmodes + (VID_ROW_SIZE - 1)) / VID_ROW_SIZE) * VID_ROW_SIZE;
2378 			while (vid_line < 0)
2379 				vid_line += VID_ROW_SIZE;
2380 		}
2381 		break;
2382 
2383 	case K_ENTER:
2384 		S_LocalSound ("raven/menu1.wav");
2385 		VID_SetMode (modedescs[vid_line].modenum, vid_curpal);
2386 		break;
2387 
2388 	case 'T':
2389 	case 't':
2390 		S_LocalSound ("raven/menu1.wav");
2391 	// have to set this before setting the mode because WM_PAINT
2392 	// happens during the mode set and does a VID_Update, which
2393 	// checks vid_testingmode
2394 		vid_testingmode = 1;
2395 		vid_testendtime = realtime + 5.0;
2396 		if (!VID_SetMode (modedescs[vid_line].modenum, vid_curpal))
2397 			vid_testingmode = 0;
2398 		break;
2399 
2400 	case 'D':
2401 	case 'd':
2402 		S_LocalSound ("raven/menu1.wav");
2403 		firstupdate = false;
2404 		Cvar_SetValueQuick (&_vid_default_mode_win, vid_modenum);
2405 		break;
2406 
2407 	default:
2408 		break;
2409 	}
2410 }
2411 
2412