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