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 = ▭
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