vid_win.cpp revision 9fd67c44777b350dc56f3e70c88963b0d966ffc7
1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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 30qboolean dibonly; 31 32extern int Minimized; 33 34HWND mainwindow; 35 36HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); 37 38int DIBWidth, DIBHeight; 39qboolean DDActive; 40RECT WindowRect; 41DWORD WindowStyle, ExWindowStyle; 42 43int window_center_x, window_center_y, window_x, window_y, window_width, window_height; 44RECT window_rect; 45 46static DEVMODE gdevmode; 47static qboolean startwindowed = 0, windowed_mode_set; 48static int firstupdate = 1; 49static qboolean vid_initialized = false, vid_palettized; 50static int lockcount; 51static int vid_fulldib_on_focus_mode; 52static qboolean force_minimized, in_mode_set, is_mode0x13, force_mode_set; 53static int vid_stretched, windowed_mouse; 54static qboolean palette_changed, syscolchg, vid_mode_set, hide_window, pal_is_nostatic; 55static HICON hIcon; 56 57viddef_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 65cvar_t vid_mode = {"vid_mode","0", false}; 66// Note that 0 is MODE_WINDOWED 67cvar_t _vid_default_mode = {"_vid_default_mode","0", true}; 68// Note that 3 is MODE_FULLSCREEN_DEFAULT 69cvar_t _vid_default_mode_win = {"_vid_default_mode_win","3", true}; 70cvar_t vid_wait = {"vid_wait","0"}; 71cvar_t vid_nopageflip = {"vid_nopageflip","0", true}; 72cvar_t _vid_wait_override = {"_vid_wait_override", "0", true}; 73cvar_t vid_config_x = {"vid_config_x","800", true}; 74cvar_t vid_config_y = {"vid_config_y","600", true}; 75cvar_t vid_stretch_by_2 = {"vid_stretch_by_2","1", true}; 76cvar_t _windowed_mouse = {"_windowed_mouse","0", true}; 77cvar_t vid_fullscreen_mode = {"vid_fullscreen_mode","3", true}; 78cvar_t vid_windowed_mode = {"vid_windowed_mode","0", true}; 79cvar_t block_switch = {"block_switch","0", true}; 80cvar_t vid_window_x = {"vid_window_x", "0", true}; 81cvar_t vid_window_y = {"vid_window_y", "0", true}; 82 83typedef struct { 84 int width; 85 int height; 86} lmode_t; 87 88lmode_t lowresmodes[] = { 89 {320, 200}, 90 {320, 240}, 91 {400, 300}, 92 {512, 384}, 93}; 94 95int vid_modenum = NO_MODE; 96int vid_testingmode, vid_realmode; 97double vid_testendtime; 98int vid_default = MODE_WINDOWED; 99static int windowed_default; 100 101modestate_t modestate = MS_UNINIT; 102 103static byte *vid_surfcache; 104static int vid_surfcachesize; 105static int VID_highhunkmark; 106 107unsigned char vid_curpal[256*3]; 108 109unsigned short d_8to16table[256]; 110unsigned d_8to24table[256]; 111 112int driver = grDETECT,mode; 113bool useWinDirect = true, useDirectDraw = true; 114MGLDC *mgldc = NULL,*memdc = NULL,*dibdc = NULL,*windc = NULL; 115 116typedef 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 130static vmode_t modelist[MAX_MODE_LIST]; 131static int nummodes; 132static vmode_t *pcurrentmode; 133 134int aPage; // Current active display page 135int vPage; // Current visible display page 136int waitVRT = true; // True to wait for retrace on flip 137 138static vmode_t badmode; 139 140static byte backingbuf[48*24]; 141 142void VID_MenuDraw (void); 143void VID_MenuKey (int key); 144 145LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 146void AppActivate(BOOL fActive, BOOL minimize); 147 148 149/* 150================ 151VID_RememberWindowPos 152================ 153*/ 154void 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================ 174VID_CheckWindowXY 175================ 176*/ 177void 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================ 193VID_UpdateWindowStatus 194================ 195*/ 196void 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================ 212ClearAllStates 213================ 214*/ 215void 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================ 232VID_CheckAdequateMem 233================ 234*/ 235qboolean 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================ 257VID_AllocBuffers 258================ 259*/ 260qboolean 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 299void initFatalError(void) 300{ 301 MGL_exit(); 302 MGL_fatalError(MGL_errorMsg(MGL_result())); 303 exit(EXIT_FAILURE); 304} 305 306 307int 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 351void 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 378void registerAllMemDrivers(void) 379{ 380 /* Register memory context drivers */ 381 MGL_registerDriver(MGL_PACKED8NAME,PACKED8_driver); 382} 383 384 385void 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 539MGLDC *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 618void 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================= 707VID_InitFullDIB 708================= 709*/ 710void 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================= 998VID_NumModes 999================= 1000*/ 1001int VID_NumModes (void) 1002{ 1003 return nummodes; 1004} 1005 1006 1007/* 1008================= 1009VID_GetModePtr 1010================= 1011*/ 1012vmode_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================= 1024VID_CheckModedescFixup 1025================= 1026*/ 1027void 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================= 1053VID_GetModeDescriptionMemCheck 1054================= 1055*/ 1056char *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================= 1082VID_GetModeDescription 1083================= 1084*/ 1085char *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================= 1103VID_GetModeDescription2 1104 1105Tacks on "windowed" or "fullscreen" 1106================= 1107*/ 1108char *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 1139char *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 1168void 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 1183void 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 1199void 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 1215qboolean 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 1370qboolean 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 1422qboolean 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 1529void 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 1554void VID_SetDefaultMode (void) 1555{ 1556 1557 if (vid_initialized) 1558 VID_SetMode (0, vid_curpal); 1559 1560 IN_DeactivateMouse (); 1561} 1562 1563 1564int 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 1717void 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 1758void 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 1779int 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 1802void 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 1815void 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 1885void VID_ShiftPalette (unsigned char *palette) 1886{ 1887 VID_SetPalette (palette); 1888} 1889 1890 1891/* 1892================= 1893VID_DescribeCurrentMode_f 1894================= 1895*/ 1896void VID_DescribeCurrentMode_f (void) 1897{ 1898 Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum)); 1899} 1900 1901 1902/* 1903================= 1904VID_NumModes_f 1905================= 1906*/ 1907void 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================= 1919VID_DescribeMode_f 1920================= 1921*/ 1922void 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================= 1934VID_DescribeModes_f 1935================= 1936*/ 1937void 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================= 1973VID_TestMode_f 1974================= 1975*/ 1976void 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================= 1999VID_Windowed_f 2000================= 2001*/ 2002void VID_Windowed_f (void) 2003{ 2004 2005 VID_SetMode ((int)vid_windowed_mode.value, vid_curpal); 2006} 2007 2008 2009/* 2010================= 2011VID_Fullscreen_f 2012================= 2013*/ 2014void VID_Fullscreen_f (void) 2015{ 2016 2017 VID_SetMode ((int)vid_fullscreen_mode.value, vid_curpal); 2018} 2019 2020 2021/* 2022================= 2023VID_Minimize_f 2024================= 2025*/ 2026void 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================= 2039VID_ForceMode_f 2040================= 2041*/ 2042void 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 2058void 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 2181void 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================ 2215FlipScreen 2216================ 2217*/ 2218void 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 2305void 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================ 2411D_BeginDirectRect 2412================ 2413*/ 2414void 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================ 2506D_EndDirectRect 2507================ 2508*/ 2509void 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 2594byte 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======= 2618MapKey 2619 2620Map from windows to quake keynums 2621======= 2622*/ 2623int MapKey (int key) 2624{ 2625 key = (key>>16)&255; 2626 if (key > 127) 2627 return 0; 2628 2629 return scantokey[key]; 2630} 2631 2632void 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================ 2782VID_HandlePause 2783================ 2784*/ 2785void 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 2807MAIN WINDOW 2808 2809=================================================================== 2810*/ 2811 2812LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 2813 2814/* main window procedure */ 2815LONG 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 3043extern void M_Menu_Options_f (void); 3044extern void M_Print (int cx, int cy, char *str); 3045extern void M_PrintWhite (int cx, int cy, char *str); 3046extern void M_DrawCharacter (int cx, int line, int num); 3047extern void M_DrawTransPic (int x, int y, qpic_t *pic); 3048extern void M_DrawPic (int x, int y, qpic_t *pic); 3049 3050static int vid_line, vid_wmodes; 3051 3052typedef 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 3065static modedesc_t modedescs[MAX_MODEDESCS]; 3066 3067/* 3068================ 3069VID_MenuDraw 3070================ 3071*/ 3072void 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================ 3252VID_MenuKey 3253================ 3254*/ 3255void 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