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