|
|
1.1 ! root 1: /* ! 2: ** GLW_IMP.C ! 3: ** ! 4: ** This file contains ALL Win32 specific stuff having to do with the ! 5: ** OpenGL refresh. When a port is being made the following functions ! 6: ** must be implemented by the port: ! 7: ** ! 8: ** GLimp_EndFrame ! 9: ** GLimp_Init ! 10: ** GLimp_Shutdown ! 11: ** GLimp_SwitchFullscreen ! 12: ** ! 13: */ ! 14: #include <assert.h> ! 15: #include <windows.h> ! 16: #include "../ref_gl/gl_local.h" ! 17: #include "glw_win.h" ! 18: #include "winquake.h" ! 19: ! 20: static qboolean GLimp_SwitchFullscreen( int width, int height ); ! 21: qboolean GLimp_InitGL (void); ! 22: ! 23: glwstate_t glw_state; ! 24: ! 25: extern cvar_t *vid_fullscreen; ! 26: extern cvar_t *vid_ref; ! 27: ! 28: static qboolean VerifyDriver( void ) ! 29: { ! 30: char buffer[1024]; ! 31: ! 32: strcpy( buffer, qglGetString( GL_RENDERER ) ); ! 33: strlwr( buffer ); ! 34: if ( strcmp( buffer, "gdi generic" ) == 0 ) ! 35: if ( !glw_state.mcd_accelerated ) ! 36: return false; ! 37: return true; ! 38: } ! 39: ! 40: /* ! 41: ** VID_CreateWindow ! 42: */ ! 43: #define WINDOW_CLASS_NAME "Quake 2" ! 44: ! 45: qboolean VID_CreateWindow( int width, int height, qboolean fullscreen ) ! 46: { ! 47: WNDCLASS wc; ! 48: RECT r; ! 49: cvar_t *vid_xpos, *vid_ypos; ! 50: int stylebits; ! 51: int x, y, w, h; ! 52: int exstyle; ! 53: ! 54: /* Register the frame class */ ! 55: wc.style = 0; ! 56: wc.lpfnWndProc = (WNDPROC)glw_state.wndproc; ! 57: wc.cbClsExtra = 0; ! 58: wc.cbWndExtra = 0; ! 59: wc.hInstance = glw_state.hInstance; ! 60: wc.hIcon = 0; ! 61: wc.hCursor = LoadCursor (NULL,IDC_ARROW); ! 62: wc.hbrBackground = (void *)COLOR_GRAYTEXT; ! 63: wc.lpszMenuName = 0; ! 64: wc.lpszClassName = WINDOW_CLASS_NAME; ! 65: ! 66: if (!RegisterClass (&wc) ) ! 67: ri.Sys_Error (ERR_FATAL, "Couldn't register window class"); ! 68: ! 69: if (fullscreen) ! 70: { ! 71: exstyle = WS_EX_TOPMOST; ! 72: stylebits = WS_POPUP|WS_VISIBLE; ! 73: } ! 74: else ! 75: { ! 76: exstyle = 0; ! 77: stylebits = WINDOW_STYLE; ! 78: } ! 79: ! 80: r.left = 0; ! 81: r.top = 0; ! 82: r.right = width; ! 83: r.bottom = height; ! 84: ! 85: AdjustWindowRect (&r, stylebits, FALSE); ! 86: ! 87: w = r.right - r.left; ! 88: h = r.bottom - r.top; ! 89: ! 90: if (fullscreen) ! 91: { ! 92: x = 0; ! 93: y = 0; ! 94: } ! 95: else ! 96: { ! 97: vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0); ! 98: vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0); ! 99: x = vid_xpos->value; ! 100: y = vid_ypos->value; ! 101: } ! 102: ! 103: glw_state.hWnd = CreateWindowEx ( ! 104: exstyle, ! 105: WINDOW_CLASS_NAME, ! 106: "Quake 2", ! 107: stylebits, ! 108: x, y, w, h, ! 109: NULL, ! 110: NULL, ! 111: glw_state.hInstance, ! 112: NULL); ! 113: ! 114: if (!glw_state.hWnd) ! 115: ri.Sys_Error (ERR_FATAL, "Couldn't create window"); ! 116: ! 117: ShowWindow( glw_state.hWnd, SW_SHOW ); ! 118: UpdateWindow( glw_state.hWnd ); ! 119: ! 120: // init all the gl stuff for the window ! 121: if (!GLimp_InitGL ()) ! 122: { ! 123: ri.Con_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n"); ! 124: return false; ! 125: } ! 126: ! 127: SetForegroundWindow( glw_state.hWnd ); ! 128: SetFocus( glw_state.hWnd ); ! 129: ! 130: // let the sound and input subsystems know about the new window ! 131: ri.Vid_NewWindow (width, height); ! 132: ! 133: return true; ! 134: } ! 135: ! 136: ! 137: /* ! 138: ** GLimp_SetMode ! 139: */ ! 140: rserr_t GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen ) ! 141: { ! 142: int width, height; ! 143: const char *win_fs[] = { "W", "FS" }; ! 144: ! 145: ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n"); ! 146: ! 147: ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode ); ! 148: ! 149: if ( !ri.Vid_GetModeInfo( &width, &height, mode ) ) ! 150: { ! 151: ri.Con_Printf( PRINT_ALL, " invalid mode\n" ); ! 152: return rserr_invalid_mode; ! 153: } ! 154: ! 155: ri.Con_Printf( PRINT_ALL, " %d %d %s\n", width, height, win_fs[fullscreen] ); ! 156: ! 157: // destroy the existing window ! 158: if (glw_state.hWnd) ! 159: { ! 160: GLimp_Shutdown (); ! 161: } ! 162: ! 163: // do a CDS if needed ! 164: if ( fullscreen ) ! 165: { ! 166: DEVMODE dm; ! 167: ! 168: ri.Con_Printf( PRINT_ALL, "...attempting fullscreen\n" ); ! 169: ! 170: memset( &dm, 0, sizeof( dm ) ); ! 171: ! 172: dm.dmSize = sizeof( dm ); ! 173: ! 174: dm.dmPelsWidth = width; ! 175: dm.dmPelsHeight = height; ! 176: dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; ! 177: ! 178: if ( gl_bitdepth->value != 0 ) ! 179: { ! 180: dm.dmBitsPerPel = gl_bitdepth->value; ! 181: dm.dmFields |= DM_BITSPERPEL; ! 182: ri.Con_Printf( PRINT_ALL, "...using gl_bitdepth of %d\n", ( int ) gl_bitdepth->value ); ! 183: } ! 184: else ! 185: { ! 186: HDC hdc = GetDC( NULL ); ! 187: int bitspixel = GetDeviceCaps( hdc, BITSPIXEL ); ! 188: ! 189: ri.Con_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel ); ! 190: ! 191: ReleaseDC( 0, hdc ); ! 192: } ! 193: ! 194: ri.Con_Printf( PRINT_ALL, "...calling CDS: " ); ! 195: if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL ) ! 196: { ! 197: *pwidth = width; ! 198: *pheight = height; ! 199: ! 200: gl_state.fullscreen = true; ! 201: ! 202: ri.Con_Printf( PRINT_ALL, "ok\n" ); ! 203: ! 204: if ( !VID_CreateWindow (width, height, true) ) ! 205: return rserr_invalid_mode; ! 206: ! 207: return rserr_ok; ! 208: } ! 209: else ! 210: { ! 211: *pwidth = width; ! 212: *pheight = height; ! 213: ! 214: ri.Con_Printf( PRINT_ALL, "failed\n" ); ! 215: ! 216: ri.Con_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" ); ! 217: ! 218: dm.dmPelsWidth = width * 2; ! 219: dm.dmPelsHeight = height; ! 220: dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; ! 221: ! 222: if ( gl_bitdepth->value != 0 ) ! 223: { ! 224: dm.dmBitsPerPel = gl_bitdepth->value; ! 225: dm.dmFields |= DM_BITSPERPEL; ! 226: } ! 227: ! 228: /* ! 229: ** our first CDS failed, so maybe we're running on some weird dual monitor ! 230: ** system ! 231: */ ! 232: if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL ) ! 233: { ! 234: ri.Con_Printf( PRINT_ALL, " failed\n" ); ! 235: ! 236: ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" ); ! 237: ! 238: ChangeDisplaySettings( 0, 0 ); ! 239: ! 240: *pwidth = width; ! 241: *pheight = height; ! 242: gl_state.fullscreen = false; ! 243: if ( !VID_CreateWindow (width, height, false) ) ! 244: return rserr_invalid_mode; ! 245: return rserr_invalid_fullscreen; ! 246: } ! 247: else ! 248: { ! 249: ri.Con_Printf( PRINT_ALL, " ok\n" ); ! 250: if ( !VID_CreateWindow (width, height, true) ) ! 251: return rserr_invalid_mode; ! 252: ! 253: gl_state.fullscreen = true; ! 254: return rserr_ok; ! 255: } ! 256: } ! 257: } ! 258: else ! 259: { ! 260: ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" ); ! 261: ! 262: ChangeDisplaySettings( 0, 0 ); ! 263: ! 264: *pwidth = width; ! 265: *pheight = height; ! 266: gl_state.fullscreen = false; ! 267: if ( !VID_CreateWindow (width, height, false) ) ! 268: return rserr_invalid_mode; ! 269: } ! 270: ! 271: return rserr_ok; ! 272: } ! 273: ! 274: /* ! 275: ** GLimp_Shutdown ! 276: ** ! 277: ** This routine does all OS specific shutdown procedures for the OpenGL ! 278: ** subsystem. Under OpenGL this means NULLing out the current DC and ! 279: ** HGLRC, deleting the rendering context, and releasing the DC acquired ! 280: ** for the window. The state structure is also nulled out. ! 281: ** ! 282: */ ! 283: void GLimp_Shutdown( void ) ! 284: { ! 285: if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) ) ! 286: ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n"); ! 287: if ( glw_state.hGLRC ) ! 288: { ! 289: if ( qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) ) ! 290: ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n"); ! 291: glw_state.hGLRC = NULL; ! 292: } ! 293: if (glw_state.hDC) ! 294: { ! 295: if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) ) ! 296: ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" ); ! 297: glw_state.hDC = NULL; ! 298: } ! 299: if (glw_state.hWnd) ! 300: { ! 301: DestroyWindow ( glw_state.hWnd ); ! 302: glw_state.hWnd = NULL; ! 303: } ! 304: ! 305: if ( glw_state.log_fp ) ! 306: { ! 307: fclose( glw_state.log_fp ); ! 308: glw_state.log_fp = 0; ! 309: } ! 310: ! 311: UnregisterClass (WINDOW_CLASS_NAME, glw_state.hInstance); ! 312: ! 313: if ( gl_state.fullscreen ) ! 314: { ! 315: ChangeDisplaySettings( 0, 0 ); ! 316: gl_state.fullscreen = false; ! 317: } ! 318: } ! 319: ! 320: ! 321: /* ! 322: ** GLimp_Init ! 323: ** ! 324: ** This routine is responsible for initializing the OS specific portions ! 325: ** of OpenGL. Under Win32 this means dealing with the pixelformats and ! 326: ** doing the wgl interface stuff. ! 327: */ ! 328: qboolean GLimp_Init( void *hinstance, void *wndproc ) ! 329: { ! 330: #define OSR2_BUILD_NUMBER 1111 ! 331: ! 332: OSVERSIONINFO vinfo; ! 333: ! 334: vinfo.dwOSVersionInfoSize = sizeof(vinfo); ! 335: ! 336: glw_state.allowdisplaydepthchange = false; ! 337: ! 338: if ( GetVersionEx( &vinfo) ) ! 339: { ! 340: if ( vinfo.dwMajorVersion > 4 ) ! 341: { ! 342: glw_state.allowdisplaydepthchange = true; ! 343: } ! 344: else if ( vinfo.dwMajorVersion == 4 ) ! 345: { ! 346: if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) ! 347: { ! 348: glw_state.allowdisplaydepthchange = true; ! 349: } ! 350: else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) ! 351: { ! 352: if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER ) ! 353: { ! 354: glw_state.allowdisplaydepthchange = true; ! 355: } ! 356: } ! 357: } ! 358: } ! 359: else ! 360: { ! 361: ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" ); ! 362: return false; ! 363: } ! 364: ! 365: glw_state.hInstance = ( HINSTANCE ) hinstance; ! 366: glw_state.wndproc = wndproc; ! 367: ! 368: return true; ! 369: } ! 370: ! 371: qboolean GLimp_InitGL (void) ! 372: { ! 373: PIXELFORMATDESCRIPTOR pfd = ! 374: { ! 375: sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd ! 376: 1, // version number ! 377: PFD_DRAW_TO_WINDOW | // support window ! 378: PFD_SUPPORT_OPENGL | // support OpenGL ! 379: PFD_DOUBLEBUFFER, // double buffered ! 380: PFD_TYPE_RGBA, // RGBA type ! 381: 24, // 24-bit color depth ! 382: 0, 0, 0, 0, 0, 0, // color bits ignored ! 383: 0, // no alpha buffer ! 384: 0, // shift bit ignored ! 385: 0, // no accumulation buffer ! 386: 0, 0, 0, 0, // accum bits ignored ! 387: 32, // 32-bit z-buffer ! 388: 0, // no stencil buffer ! 389: 0, // no auxiliary buffer ! 390: PFD_MAIN_PLANE, // main layer ! 391: 0, // reserved ! 392: 0, 0, 0 // layer masks ignored ! 393: }; ! 394: int pixelformat; ! 395: cvar_t *stereo; ! 396: ! 397: stereo = ri.Cvar_Get( "cl_stereo", "0", 0 ); ! 398: ! 399: /* ! 400: ** set PFD_STEREO if necessary ! 401: */ ! 402: if ( stereo->value != 0 ) ! 403: { ! 404: ri.Con_Printf( PRINT_ALL, "...attempting to use stereo\n" ); ! 405: pfd.dwFlags |= PFD_STEREO; ! 406: gl_state.stereo_enabled = true; ! 407: } ! 408: else ! 409: { ! 410: gl_state.stereo_enabled = false; ! 411: } ! 412: ! 413: /* ! 414: ** figure out if we're running on a minidriver or not ! 415: */ ! 416: if ( strstr( gl_driver->string, "opengl32" ) != 0 ) ! 417: glw_state.minidriver = false; ! 418: else ! 419: glw_state.minidriver = true; ! 420: ! 421: /* ! 422: ** Get a DC for the specified window ! 423: */ ! 424: if ( glw_state.hDC != NULL ) ! 425: ri.Con_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" ); ! 426: ! 427: if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL ) ! 428: { ! 429: ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" ); ! 430: return false; ! 431: } ! 432: ! 433: if ( glw_state.minidriver ) ! 434: { ! 435: if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 ) ! 436: { ! 437: ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n"); ! 438: return false; ! 439: } ! 440: if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE ) ! 441: { ! 442: ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n"); ! 443: return false; ! 444: } ! 445: qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd ); ! 446: } ! 447: else ! 448: { ! 449: if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 ) ! 450: { ! 451: ri.Con_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n"); ! 452: return false; ! 453: } ! 454: if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE ) ! 455: { ! 456: ri.Con_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n"); ! 457: return false; ! 458: } ! 459: DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd ); ! 460: ! 461: if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) ) ! 462: { ! 463: extern cvar_t *gl_allow_software; ! 464: ! 465: if ( gl_allow_software->value ) ! 466: glw_state.mcd_accelerated = true; ! 467: else ! 468: glw_state.mcd_accelerated = false; ! 469: } ! 470: else ! 471: { ! 472: glw_state.mcd_accelerated = true; ! 473: } ! 474: } ! 475: ! 476: /* ! 477: ** report if stereo is desired but unavailable ! 478: */ ! 479: if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) ) ! 480: { ! 481: ri.Con_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" ); ! 482: ri.Cvar_SetValue( "cl_stereo", 0 ); ! 483: gl_state.stereo_enabled = false; ! 484: } ! 485: ! 486: /* ! 487: ** startup the OpenGL subsystem by creating a context and making ! 488: ** it current ! 489: */ ! 490: if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 ) ! 491: { ! 492: ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n"); ! 493: ! 494: goto fail; ! 495: } ! 496: ! 497: if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) ! 498: { ! 499: ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n"); ! 500: ! 501: goto fail; ! 502: } ! 503: ! 504: if ( !VerifyDriver() ) ! 505: { ! 506: ri.Con_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected\n" ); ! 507: goto fail; ! 508: } ! 509: ! 510: /* ! 511: ** print out PFD specifics ! 512: */ ! 513: ri.Con_Printf( PRINT_ALL, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits ); ! 514: ! 515: return true; ! 516: ! 517: fail: ! 518: if ( glw_state.hGLRC ) ! 519: { ! 520: qwglDeleteContext( glw_state.hGLRC ); ! 521: glw_state.hGLRC = NULL; ! 522: } ! 523: ! 524: if ( glw_state.hDC ) ! 525: { ! 526: ReleaseDC( glw_state.hWnd, glw_state.hDC ); ! 527: glw_state.hDC = NULL; ! 528: } ! 529: return false; ! 530: } ! 531: ! 532: /* ! 533: ** GLimp_BeginFrame ! 534: */ ! 535: void GLimp_BeginFrame( float camera_separation ) ! 536: { ! 537: if ( gl_bitdepth->modified ) ! 538: { ! 539: if ( gl_bitdepth->value != 0 && !glw_state.allowdisplaydepthchange ) ! 540: { ! 541: ri.Cvar_SetValue( "gl_bitdepth", 0 ); ! 542: ri.Con_Printf( PRINT_ALL, "gl_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" ); ! 543: } ! 544: gl_bitdepth->modified = false; ! 545: } ! 546: ! 547: if ( camera_separation < 0 && gl_state.stereo_enabled ) ! 548: { ! 549: qglDrawBuffer( GL_BACK_LEFT ); ! 550: } ! 551: else if ( camera_separation > 0 && gl_state.stereo_enabled ) ! 552: { ! 553: qglDrawBuffer( GL_BACK_RIGHT ); ! 554: } ! 555: else ! 556: { ! 557: qglDrawBuffer( GL_BACK ); ! 558: } ! 559: } ! 560: ! 561: /* ! 562: ** GLimp_EndFrame ! 563: ** ! 564: ** Responsible for doing a swapbuffers and possibly for other stuff ! 565: ** as yet to be determined. Probably better not to make this a GLimp ! 566: ** function and instead do a call to GLimp_SwapBuffers. ! 567: */ ! 568: void GLimp_EndFrame (void) ! 569: { ! 570: int err; ! 571: ! 572: err = qglGetError(); ! 573: assert( err == GL_NO_ERROR ); ! 574: ! 575: if ( stricmp( gl_drawbuffer->string, "GL_BACK" ) == 0 ) ! 576: { ! 577: if ( !qwglSwapBuffers( glw_state.hDC ) ) ! 578: ri.Sys_Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n" ); ! 579: } ! 580: } ! 581: ! 582: /* ! 583: ** GLimp_AppActivate ! 584: */ ! 585: void GLimp_AppActivate( qboolean active ) ! 586: { ! 587: if ( active ) ! 588: { ! 589: SetForegroundWindow( glw_state.hWnd ); ! 590: ShowWindow( glw_state.hWnd, SW_RESTORE ); ! 591: } ! 592: else ! 593: { ! 594: if ( vid_fullscreen->value ) ! 595: ShowWindow( glw_state.hWnd, SW_MINIMIZE ); ! 596: } ! 597: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.