00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <assert.h>
00038 #include "../renderer/tr_local.h"
00039 #include "../qcommon/qcommon.h"
00040 #include "resource.h"
00041 #include "glw_win.h"
00042 #include "win_local.h"
00043
00044 extern void WG_CheckHardwareGamma( void );
00045 extern void WG_RestoreGamma( void );
00046
00047 typedef enum {
00048 RSERR_OK,
00049
00050 RSERR_INVALID_FULLSCREEN,
00051 RSERR_INVALID_MODE,
00052
00053 RSERR_UNKNOWN
00054 } rserr_t;
00055
00056 #define TRY_PFD_SUCCESS 0
00057 #define TRY_PFD_FAIL_SOFT 1
00058 #define TRY_PFD_FAIL_HARD 2
00059
00060 #define WINDOW_CLASS_NAME "Quake 3: Arena"
00061
00062 static void GLW_InitExtensions( void );
00063 static rserr_t GLW_SetMode( const char *drivername,
00064 int mode,
00065 int colorbits,
00066 qboolean cdsFullscreen );
00067
00068 static qboolean s_classRegistered = qfalse;
00069
00070
00071
00072
00073 void QGL_EnableLogging( qboolean enable );
00074 qboolean QGL_Init( const char *dllname );
00075 void QGL_Shutdown( void );
00076
00077
00078
00079
00080 glwstate_t glw_state;
00081
00082 cvar_t *r_allowSoftwareGL;
00083 cvar_t *r_maskMinidriver;
00084
00085
00086
00087
00088
00089
00090 static qboolean GLW_StartDriverAndSetMode( const char *drivername,
00091 int mode,
00092 int colorbits,
00093 qboolean cdsFullscreen )
00094 {
00095 rserr_t err;
00096
00097 err = GLW_SetMode( drivername, r_mode->integer, colorbits, cdsFullscreen );
00098
00099 switch ( err )
00100 {
00101 case RSERR_INVALID_FULLSCREEN:
00102 ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" );
00103 return qfalse;
00104 case RSERR_INVALID_MODE:
00105 ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode );
00106 return qfalse;
00107 default:
00108 break;
00109 }
00110 return qtrue;
00111 }
00112
00113
00114
00115
00116
00117
00118 #define MAX_PFDS 256
00119
00120 static int GLW_ChoosePFD( HDC hDC, PIXELFORMATDESCRIPTOR *pPFD )
00121 {
00122 PIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1];
00123 int maxPFD = 0;
00124 int i;
00125 int bestMatch = 0;
00126
00127 ri.Printf( PRINT_ALL, "...GLW_ChoosePFD( %d, %d, %d )\n", ( int ) pPFD->cColorBits, ( int ) pPFD->cDepthBits, ( int ) pPFD->cStencilBits );
00128
00129
00130 if ( glConfig.driverType > GLDRV_ICD )
00131 {
00132 maxPFD = qwglDescribePixelFormat( hDC, 1, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[0] );
00133 }
00134 else
00135 {
00136 maxPFD = DescribePixelFormat( hDC, 1, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[0] );
00137 }
00138 if ( maxPFD > MAX_PFDS )
00139 {
00140 ri.Printf( PRINT_WARNING, "...numPFDs > MAX_PFDS (%d > %d)\n", maxPFD, MAX_PFDS );
00141 maxPFD = MAX_PFDS;
00142 }
00143
00144 ri.Printf( PRINT_ALL, "...%d PFDs found\n", maxPFD - 1 );
00145
00146
00147 for ( i = 1; i <= maxPFD; i++ )
00148 {
00149 if ( glConfig.driverType > GLDRV_ICD )
00150 {
00151 qwglDescribePixelFormat( hDC, i, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[i] );
00152 }
00153 else
00154 {
00155 DescribePixelFormat( hDC, i, sizeof( PIXELFORMATDESCRIPTOR ), &pfds[i] );
00156 }
00157 }
00158
00159
00160 for ( i = 1; i <= maxPFD; i++ )
00161 {
00162
00163
00164
00165 if ( ( pfds[i].dwFlags & PFD_GENERIC_FORMAT ) != 0 )
00166 {
00167 if ( !r_allowSoftwareGL->integer )
00168 {
00169 if ( r_verbose->integer )
00170 {
00171 ri.Printf( PRINT_ALL, "...PFD %d rejected, software acceleration\n", i );
00172 }
00173 continue;
00174 }
00175 }
00176
00177
00178 if ( pfds[i].iPixelType != PFD_TYPE_RGBA )
00179 {
00180 if ( r_verbose->integer )
00181 {
00182 ri.Printf( PRINT_ALL, "...PFD %d rejected, not RGBA\n", i );
00183 }
00184 continue;
00185 }
00186
00187
00188 if ( ( ( pfds[i].dwFlags & pPFD->dwFlags ) & pPFD->dwFlags ) != pPFD->dwFlags )
00189 {
00190 if ( r_verbose->integer )
00191 {
00192 ri.Printf( PRINT_ALL, "...PFD %d rejected, improper flags (%x instead of %x)\n", i, pfds[i].dwFlags, pPFD->dwFlags );
00193 }
00194 continue;
00195 }
00196
00197
00198 if ( pfds[i].cDepthBits < 15 )
00199 {
00200 continue;
00201 }
00202 if ( ( pfds[i].cStencilBits < 4 ) && ( pPFD->cStencilBits > 0 ) )
00203 {
00204 continue;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 if ( bestMatch )
00216 {
00217
00218 if ( ( pfds[i].dwFlags & PFD_STEREO ) && ( !( pfds[bestMatch].dwFlags & PFD_STEREO ) ) && ( pPFD->dwFlags & PFD_STEREO ) )
00219 {
00220 bestMatch = i;
00221 continue;
00222 }
00223
00224 if ( !( pfds[i].dwFlags & PFD_STEREO ) && ( pfds[bestMatch].dwFlags & PFD_STEREO ) && ( pPFD->dwFlags & PFD_STEREO ) )
00225 {
00226 bestMatch = i;
00227 continue;
00228 }
00229
00230
00231 if ( pfds[bestMatch].cColorBits != pPFD->cColorBits )
00232 {
00233
00234 if ( pfds[i].cColorBits == pPFD->cColorBits )
00235 {
00236 bestMatch = i;
00237 continue;
00238 }
00239
00240 else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits )
00241 {
00242 bestMatch = i;
00243 continue;
00244 }
00245 }
00246
00247
00248 if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits )
00249 {
00250
00251 if ( pfds[i].cDepthBits == pPFD->cDepthBits )
00252 {
00253 bestMatch = i;
00254 continue;
00255 }
00256
00257 else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits )
00258 {
00259 bestMatch = i;
00260 continue;
00261 }
00262 }
00263
00264
00265 if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits )
00266 {
00267
00268 if ( pfds[i].cStencilBits == pPFD->cStencilBits )
00269 {
00270 bestMatch = i;
00271 continue;
00272 }
00273
00274 else if ( ( pfds[i].cStencilBits > pfds[bestMatch].cStencilBits ) &&
00275 ( pPFD->cStencilBits > 0 ) )
00276 {
00277 bestMatch = i;
00278 continue;
00279 }
00280 }
00281 }
00282 else
00283 {
00284 bestMatch = i;
00285 }
00286 }
00287
00288 if ( !bestMatch )
00289 return 0;
00290
00291 if ( ( pfds[bestMatch].dwFlags & PFD_GENERIC_FORMAT ) != 0 )
00292 {
00293 if ( !r_allowSoftwareGL->integer )
00294 {
00295 ri.Printf( PRINT_ALL, "...no hardware acceleration found\n" );
00296 return 0;
00297 }
00298 else
00299 {
00300 ri.Printf( PRINT_ALL, "...using software emulation\n" );
00301 }
00302 }
00303 else if ( pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED )
00304 {
00305 ri.Printf( PRINT_ALL, "...MCD acceleration found\n" );
00306 }
00307 else
00308 {
00309 ri.Printf( PRINT_ALL, "...hardware acceleration found\n" );
00310 }
00311
00312 *pPFD = pfds[bestMatch];
00313
00314 return bestMatch;
00315 }
00316
00317
00318
00319
00320
00321
00322 static void GLW_CreatePFD( PIXELFORMATDESCRIPTOR *pPFD, int colorbits, int depthbits, int stencilbits, qboolean stereo )
00323 {
00324 PIXELFORMATDESCRIPTOR src =
00325 {
00326 sizeof(PIXELFORMATDESCRIPTOR),
00327 1,
00328 PFD_DRAW_TO_WINDOW |
00329 PFD_SUPPORT_OPENGL |
00330 PFD_DOUBLEBUFFER,
00331 PFD_TYPE_RGBA,
00332 24,
00333 0, 0, 0, 0, 0, 0,
00334 0,
00335 0,
00336 0,
00337 0, 0, 0, 0,
00338 24,
00339 8,
00340 0,
00341 PFD_MAIN_PLANE,
00342 0,
00343 0, 0, 0
00344 };
00345
00346 src.cColorBits = colorbits;
00347 src.cDepthBits = depthbits;
00348 src.cStencilBits = stencilbits;
00349
00350 if ( stereo )
00351 {
00352 ri.Printf( PRINT_ALL, "...attempting to use stereo\n" );
00353 src.dwFlags |= PFD_STEREO;
00354 glConfig.stereoEnabled = qtrue;
00355 }
00356 else
00357 {
00358 glConfig.stereoEnabled = qfalse;
00359 }
00360
00361 *pPFD = src;
00362 }
00363
00364
00365
00366
00367 static int GLW_MakeContext( PIXELFORMATDESCRIPTOR *pPFD )
00368 {
00369 int pixelformat;
00370
00371
00372
00373
00374
00375 if ( !glw_state.pixelFormatSet )
00376 {
00377
00378
00379
00380
00381
00382 if ( ( pixelformat = GLW_ChoosePFD( glw_state.hDC, pPFD ) ) == 0 )
00383 {
00384 ri.Printf( PRINT_ALL, "...GLW_ChoosePFD failed\n");
00385 return TRY_PFD_FAIL_SOFT;
00386 }
00387 ri.Printf( PRINT_ALL, "...PIXELFORMAT %d selected\n", pixelformat );
00388
00389 if ( glConfig.driverType > GLDRV_ICD )
00390 {
00391 qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( *pPFD ), pPFD );
00392 if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, pPFD ) == FALSE )
00393 {
00394 ri.Printf ( PRINT_ALL, "...qwglSetPixelFormat failed\n");
00395 return TRY_PFD_FAIL_SOFT;
00396 }
00397 }
00398 else
00399 {
00400 DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( *pPFD ), pPFD );
00401
00402 if ( SetPixelFormat( glw_state.hDC, pixelformat, pPFD ) == FALSE )
00403 {
00404 ri.Printf (PRINT_ALL, "...SetPixelFormat failed\n", glw_state.hDC );
00405 return TRY_PFD_FAIL_SOFT;
00406 }
00407 }
00408
00409 glw_state.pixelFormatSet = qtrue;
00410 }
00411
00412
00413
00414
00415 if ( !glw_state.hGLRC )
00416 {
00417 ri.Printf( PRINT_ALL, "...creating GL context: " );
00418 if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
00419 {
00420 ri.Printf (PRINT_ALL, "failed\n");
00421
00422 return TRY_PFD_FAIL_HARD;
00423 }
00424 ri.Printf( PRINT_ALL, "succeeded\n" );
00425
00426 ri.Printf( PRINT_ALL, "...making context current: " );
00427 if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
00428 {
00429 qwglDeleteContext( glw_state.hGLRC );
00430 glw_state.hGLRC = NULL;
00431 ri.Printf (PRINT_ALL, "failed\n");
00432 return TRY_PFD_FAIL_HARD;
00433 }
00434 ri.Printf( PRINT_ALL, "succeeded\n" );
00435 }
00436
00437 return TRY_PFD_SUCCESS;
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447 static qboolean GLW_InitDriver( const char *drivername, int colorbits )
00448 {
00449 int tpfd;
00450 int depthbits, stencilbits;
00451 static PIXELFORMATDESCRIPTOR pfd;
00452
00453 ri.Printf( PRINT_ALL, "Initializing OpenGL driver\n" );
00454
00455
00456
00457
00458 if ( glw_state.hDC == NULL )
00459 {
00460 ri.Printf( PRINT_ALL, "...getting DC: " );
00461
00462 if ( ( glw_state.hDC = GetDC( g_wv.hWnd ) ) == NULL )
00463 {
00464 ri.Printf( PRINT_ALL, "failed\n" );
00465 return qfalse;
00466 }
00467 ri.Printf( PRINT_ALL, "succeeded\n" );
00468 }
00469
00470 if ( colorbits == 0 )
00471 {
00472 colorbits = glw_state.desktopBitsPixel;
00473 }
00474
00475
00476
00477
00478 if ( r_depthbits->integer == 0 ) {
00479 if ( colorbits > 16 ) {
00480 depthbits = 24;
00481 } else {
00482 depthbits = 16;
00483 }
00484 } else {
00485 depthbits = r_depthbits->integer;
00486 }
00487
00488
00489
00490
00491 stencilbits = r_stencilbits->integer;
00492 if ( depthbits < 24 )
00493 {
00494 stencilbits = 0;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504 if ( !glw_state.pixelFormatSet )
00505 {
00506 GLW_CreatePFD( &pfd, colorbits, depthbits, stencilbits, r_stereo->integer );
00507 if ( ( tpfd = GLW_MakeContext( &pfd ) ) != TRY_PFD_SUCCESS )
00508 {
00509 if ( tpfd == TRY_PFD_FAIL_HARD )
00510 {
00511 ri.Printf( PRINT_WARNING, "...failed hard\n" );
00512 return qfalse;
00513 }
00514
00515
00516
00517
00518 if ( ( r_colorbits->integer == glw_state.desktopBitsPixel ) &&
00519 ( stencilbits == 0 ) )
00520 {
00521 ReleaseDC( g_wv.hWnd, glw_state.hDC );
00522 glw_state.hDC = NULL;
00523
00524 ri.Printf( PRINT_ALL, "...failed to find an appropriate PIXELFORMAT\n" );
00525
00526 return qfalse;
00527 }
00528
00529
00530
00531
00532 if ( colorbits > glw_state.desktopBitsPixel )
00533 {
00534 colorbits = glw_state.desktopBitsPixel;
00535 }
00536 GLW_CreatePFD( &pfd, colorbits, depthbits, 0, r_stereo->integer );
00537 if ( GLW_MakeContext( &pfd ) != TRY_PFD_SUCCESS )
00538 {
00539 if ( glw_state.hDC )
00540 {
00541 ReleaseDC( g_wv.hWnd, glw_state.hDC );
00542 glw_state.hDC = NULL;
00543 }
00544
00545 ri.Printf( PRINT_ALL, "...failed to find an appropriate PIXELFORMAT\n" );
00546
00547 return qfalse;
00548 }
00549 }
00550
00551
00552
00553
00554 if ( !( pfd.dwFlags & PFD_STEREO ) && ( r_stereo->integer != 0 ) )
00555 {
00556 ri.Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
00557 glConfig.stereoEnabled = qfalse;
00558 }
00559 }
00560
00561
00562
00563
00564 glConfig.colorBits = ( int ) pfd.cColorBits;
00565 glConfig.depthBits = ( int ) pfd.cDepthBits;
00566 glConfig.stencilBits = ( int ) pfd.cStencilBits;
00567
00568 return qtrue;
00569 }
00570
00571
00572
00573
00574
00575
00576 #define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE)
00577 static qboolean GLW_CreateWindow( const char *drivername, int width, int height, int colorbits, qboolean cdsFullscreen )
00578 {
00579 RECT r;
00580 cvar_t *vid_xpos, *vid_ypos;
00581 int stylebits;
00582 int x, y, w, h;
00583 int exstyle;
00584
00585
00586
00587
00588 if ( !s_classRegistered )
00589 {
00590 WNDCLASS wc;
00591
00592 memset( &wc, 0, sizeof( wc ) );
00593
00594 wc.style = 0;
00595 wc.lpfnWndProc = (WNDPROC) glw_state.wndproc;
00596 wc.cbClsExtra = 0;
00597 wc.cbWndExtra = 0;
00598 wc.hInstance = g_wv.hInstance;
00599 wc.hIcon = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1));
00600 wc.hCursor = LoadCursor (NULL,IDC_ARROW);
00601 wc.hbrBackground = (void *)COLOR_GRAYTEXT;
00602 wc.lpszMenuName = 0;
00603 wc.lpszClassName = WINDOW_CLASS_NAME;
00604
00605 if ( !RegisterClass( &wc ) )
00606 {
00607 ri.Error( ERR_FATAL, "GLW_CreateWindow: could not register window class" );
00608 }
00609 s_classRegistered = qtrue;
00610 ri.Printf( PRINT_ALL, "...registered window class\n" );
00611 }
00612
00613
00614
00615
00616 if ( !g_wv.hWnd )
00617 {
00618
00619
00620
00621 r.left = 0;
00622 r.top = 0;
00623 r.right = width;
00624 r.bottom = height;
00625
00626 if ( cdsFullscreen || !Q_stricmp( _3DFX_DRIVER_NAME, drivername ) )
00627 {
00628 exstyle = WS_EX_TOPMOST;
00629 stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
00630 }
00631 else
00632 {
00633 exstyle = 0;
00634 stylebits = WINDOW_STYLE|WS_SYSMENU;
00635 AdjustWindowRect (&r, stylebits, FALSE);
00636 }
00637
00638 w = r.right - r.left;
00639 h = r.bottom - r.top;
00640
00641 if ( cdsFullscreen || !Q_stricmp( _3DFX_DRIVER_NAME, drivername ) )
00642 {
00643 x = 0;
00644 y = 0;
00645 }
00646 else
00647 {
00648 vid_xpos = ri.Cvar_Get ("vid_xpos", "", 0);
00649 vid_ypos = ri.Cvar_Get ("vid_ypos", "", 0);
00650 x = vid_xpos->integer;
00651 y = vid_ypos->integer;
00652
00653
00654
00655 if ( x < 0 )
00656 x = 0;
00657 if ( y < 0 )
00658 y = 0;
00659
00660 if ( w < glw_state.desktopWidth &&
00661 h < glw_state.desktopHeight )
00662 {
00663 if ( x + w > glw_state.desktopWidth )
00664 x = ( glw_state.desktopWidth - w );
00665 if ( y + h > glw_state.desktopHeight )
00666 y = ( glw_state.desktopHeight - h );
00667 }
00668 }
00669
00670 g_wv.hWnd = CreateWindowEx (
00671 exstyle,
00672 WINDOW_CLASS_NAME,
00673 "Quake 3: Arena",
00674 stylebits,
00675 x, y, w, h,
00676 NULL,
00677 NULL,
00678 g_wv.hInstance,
00679 NULL);
00680
00681 if ( !g_wv.hWnd )
00682 {
00683 ri.Error (ERR_FATAL, "GLW_CreateWindow() - Couldn't create window");
00684 }
00685
00686 ShowWindow( g_wv.hWnd, SW_SHOW );
00687 UpdateWindow( g_wv.hWnd );
00688 ri.Printf( PRINT_ALL, "...created window@%d,%d (%dx%d)\n", x, y, w, h );
00689 }
00690 else
00691 {
00692 ri.Printf( PRINT_ALL, "...window already present, CreateWindowEx skipped\n" );
00693 }
00694
00695 if ( !GLW_InitDriver( drivername, colorbits ) )
00696 {
00697 ShowWindow( g_wv.hWnd, SW_HIDE );
00698 DestroyWindow( g_wv.hWnd );
00699 g_wv.hWnd = NULL;
00700
00701 return qfalse;
00702 }
00703
00704 SetForegroundWindow( g_wv.hWnd );
00705 SetFocus( g_wv.hWnd );
00706
00707 return qtrue;
00708 }
00709
00710 static void PrintCDSError( int value )
00711 {
00712 switch ( value )
00713 {
00714 case DISP_CHANGE_RESTART:
00715 ri.Printf( PRINT_ALL, "restart required\n" );
00716 break;
00717 case DISP_CHANGE_BADPARAM:
00718 ri.Printf( PRINT_ALL, "bad param\n" );
00719 break;
00720 case DISP_CHANGE_BADFLAGS:
00721 ri.Printf( PRINT_ALL, "bad flags\n" );
00722 break;
00723 case DISP_CHANGE_FAILED:
00724 ri.Printf( PRINT_ALL, "DISP_CHANGE_FAILED\n" );
00725 break;
00726 case DISP_CHANGE_BADMODE:
00727 ri.Printf( PRINT_ALL, "bad mode\n" );
00728 break;
00729 case DISP_CHANGE_NOTUPDATED:
00730 ri.Printf( PRINT_ALL, "not updated\n" );
00731 break;
00732 default:
00733 ri.Printf( PRINT_ALL, "unknown error %d\n", value );
00734 break;
00735 }
00736 }
00737
00738
00739
00740
00741 static rserr_t GLW_SetMode( const char *drivername,
00742 int mode,
00743 int colorbits,
00744 qboolean cdsFullscreen )
00745 {
00746 HDC hDC;
00747 const char *win_fs[] = { "W", "FS" };
00748 int cdsRet;
00749 DEVMODE dm;
00750
00751
00752
00753
00754 ri.Printf( PRINT_ALL, "...setting mode %d:", mode );
00755 if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) )
00756 {
00757 ri.Printf( PRINT_ALL, " invalid mode\n" );
00758 return RSERR_INVALID_MODE;
00759 }
00760 ri.Printf( PRINT_ALL, " %d %d %s\n", glConfig.vidWidth, glConfig.vidHeight, win_fs[cdsFullscreen] );
00761
00762
00763
00764
00765 hDC = GetDC( GetDesktopWindow() );
00766 glw_state.desktopBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
00767 glw_state.desktopWidth = GetDeviceCaps( hDC, HORZRES );
00768 glw_state.desktopHeight = GetDeviceCaps( hDC, VERTRES );
00769 ReleaseDC( GetDesktopWindow(), hDC );
00770
00771
00772
00773
00774 if ( glConfig.driverType != GLDRV_VOODOO )
00775 {
00776 if ( glw_state.desktopBitsPixel < 15 || glw_state.desktopBitsPixel == 24 )
00777 {
00778 if ( colorbits == 0 || ( !cdsFullscreen && colorbits >= 15 ) )
00779 {
00780 if ( MessageBox( NULL,
00781 "It is highly unlikely that a correct\n"
00782 "windowed display can be initialized with\n"
00783 "the current desktop display depth. Select\n"
00784 "'OK' to try anyway. Press 'Cancel' if you\n"
00785 "have a 3Dfx Voodoo, Voodoo-2, or Voodoo Rush\n"
00786 "3D accelerator installed, or if you otherwise\n"
00787 "wish to quit.",
00788 "Low Desktop Color Depth",
00789 MB_OKCANCEL | MB_ICONEXCLAMATION ) != IDOK )
00790 {
00791 return RSERR_INVALID_MODE;
00792 }
00793 }
00794 }
00795 }
00796
00797
00798 if ( cdsFullscreen )
00799 {
00800 memset( &dm, 0, sizeof( dm ) );
00801
00802 dm.dmSize = sizeof( dm );
00803
00804 dm.dmPelsWidth = glConfig.vidWidth;
00805 dm.dmPelsHeight = glConfig.vidHeight;
00806 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
00807
00808 if ( r_displayRefresh->integer != 0 )
00809 {
00810 dm.dmDisplayFrequency = r_displayRefresh->integer;
00811 dm.dmFields |= DM_DISPLAYFREQUENCY;
00812 }
00813
00814
00815 if ( colorbits != 0 )
00816 {
00817 if ( glw_state.allowdisplaydepthchange )
00818 {
00819 dm.dmBitsPerPel = colorbits;
00820 dm.dmFields |= DM_BITSPERPEL;
00821 ri.Printf( PRINT_ALL, "...using colorsbits of %d\n", colorbits );
00822 }
00823 else
00824 {
00825 ri.Printf( PRINT_ALL, "WARNING:...changing depth not supported on Win95 < pre-OSR 2.x\n" );
00826 }
00827 }
00828 else
00829 {
00830 ri.Printf( PRINT_ALL, "...using desktop display depth of %d\n", glw_state.desktopBitsPixel );
00831 }
00832
00833
00834
00835
00836 if ( glw_state.cdsFullscreen )
00837 {
00838 ri.Printf( PRINT_ALL, "...already fullscreen, avoiding redundant CDS\n" );
00839
00840 if ( !GLW_CreateWindow ( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qtrue ) )
00841 {
00842 ri.Printf( PRINT_ALL, "...restoring display settings\n" );
00843 ChangeDisplaySettings( 0, 0 );
00844 return RSERR_INVALID_MODE;
00845 }
00846 }
00847
00848
00849
00850 else
00851 {
00852 ri.Printf( PRINT_ALL, "...calling CDS: " );
00853
00854
00855
00856 if ( ( cdsRet = ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL )
00857 {
00858 ri.Printf( PRINT_ALL, "ok\n" );
00859
00860 if ( !GLW_CreateWindow ( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qtrue) )
00861 {
00862 ri.Printf( PRINT_ALL, "...restoring display settings\n" );
00863 ChangeDisplaySettings( 0, 0 );
00864 return RSERR_INVALID_MODE;
00865 }
00866
00867 glw_state.cdsFullscreen = qtrue;
00868 }
00869 else
00870 {
00871
00872
00873
00874 DEVMODE devmode;
00875 int modeNum;
00876
00877 ri.Printf( PRINT_ALL, "failed, " );
00878
00879 PrintCDSError( cdsRet );
00880
00881 ri.Printf( PRINT_ALL, "...trying next higher resolution:" );
00882
00883
00884 for ( modeNum = 0 ; ; modeNum++ ) {
00885 if ( !EnumDisplaySettings( NULL, modeNum, &devmode ) ) {
00886 modeNum = -1;
00887 break;
00888 }
00889 if ( devmode.dmPelsWidth >= glConfig.vidWidth
00890 && devmode.dmPelsHeight >= glConfig.vidHeight
00891 && devmode.dmBitsPerPel >= 15 ) {
00892 break;
00893 }
00894 }
00895
00896 if ( modeNum != -1 && ( cdsRet = ChangeDisplaySettings( &devmode, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL )
00897 {
00898 ri.Printf( PRINT_ALL, " ok\n" );
00899 if ( !GLW_CreateWindow( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qtrue) )
00900 {
00901 ri.Printf( PRINT_ALL, "...restoring display settings\n" );
00902 ChangeDisplaySettings( 0, 0 );
00903 return RSERR_INVALID_MODE;
00904 }
00905
00906 glw_state.cdsFullscreen = qtrue;
00907 }
00908 else
00909 {
00910 ri.Printf( PRINT_ALL, " failed, " );
00911
00912 PrintCDSError( cdsRet );
00913
00914 ri.Printf( PRINT_ALL, "...restoring display settings\n" );
00915 ChangeDisplaySettings( 0, 0 );
00916
00917 glw_state.cdsFullscreen = qfalse;
00918 glConfig.isFullscreen = qfalse;
00919 if ( !GLW_CreateWindow( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qfalse) )
00920 {
00921 return RSERR_INVALID_MODE;
00922 }
00923 return RSERR_INVALID_FULLSCREEN;
00924 }
00925 }
00926 }
00927 }
00928 else
00929 {
00930 if ( glw_state.cdsFullscreen )
00931 {
00932 ChangeDisplaySettings( 0, 0 );
00933 }
00934
00935 glw_state.cdsFullscreen = qfalse;
00936 if ( !GLW_CreateWindow( drivername, glConfig.vidWidth, glConfig.vidHeight, colorbits, qfalse ) )
00937 {
00938 return RSERR_INVALID_MODE;
00939 }
00940 }
00941
00942
00943
00944
00945 memset( &dm, 0, sizeof( dm ) );
00946 dm.dmSize = sizeof( dm );
00947 if ( EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, &dm ) )
00948 {
00949 glConfig.displayFrequency = dm.dmDisplayFrequency;
00950 }
00951
00952
00953 glConfig.isFullscreen = cdsFullscreen;
00954
00955 return RSERR_OK;
00956 }
00957
00958
00959
00960
00961 static void GLW_InitExtensions( void )
00962 {
00963 if ( !r_allowExtensions->integer )
00964 {
00965 ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" );
00966 return;
00967 }
00968
00969 ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" );
00970
00971
00972 glConfig.textureCompression = TC_NONE;
00973 if ( strstr( glConfig.extensions_string, "GL_S3_s3tc" ) )
00974 {
00975 if ( r_ext_compressed_textures->integer )
00976 {
00977 glConfig.textureCompression = TC_S3TC;
00978 ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" );
00979 }
00980 else
00981 {
00982 glConfig.textureCompression = TC_NONE;
00983 ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" );
00984 }
00985 }
00986 else
00987 {
00988 ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" );
00989 }
00990
00991
00992 glConfig.textureEnvAddAvailable = qfalse;
00993 if ( strstr( glConfig.extensions_string, "EXT_texture_env_add" ) )
00994 {
00995 if ( r_ext_texture_env_add->integer )
00996 {
00997 glConfig.textureEnvAddAvailable = qtrue;
00998 ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" );
00999 }
01000 else
01001 {
01002 glConfig.textureEnvAddAvailable = qfalse;
01003 ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" );
01004 }
01005 }
01006 else
01007 {
01008 ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" );
01009 }
01010
01011
01012 qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" );
01013 if ( qwglSwapIntervalEXT )
01014 {
01015 ri.Printf( PRINT_ALL, "...using WGL_EXT_swap_control\n" );
01016 r_swapInterval->modified = qtrue;
01017 }
01018 else
01019 {
01020 ri.Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" );
01021 }
01022
01023
01024 qglMultiTexCoord2fARB = NULL;
01025 qglActiveTextureARB = NULL;
01026 qglClientActiveTextureARB = NULL;
01027 if ( strstr( glConfig.extensions_string, "GL_ARB_multitexture" ) )
01028 {
01029 if ( r_ext_multitexture->integer )
01030 {
01031 qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) qwglGetProcAddress( "glMultiTexCoord2fARB" );
01032 qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) qwglGetProcAddress( "glActiveTextureARB" );
01033 qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) qwglGetProcAddress( "glClientActiveTextureARB" );
01034
01035 if ( qglActiveTextureARB )
01036 {
01037 qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures );
01038
01039 if ( glConfig.maxActiveTextures > 1 )
01040 {
01041 ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" );
01042 }
01043 else
01044 {
01045 qglMultiTexCoord2fARB = NULL;
01046 qglActiveTextureARB = NULL;
01047 qglClientActiveTextureARB = NULL;
01048 ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" );
01049 }
01050 }
01051 }
01052 else
01053 {
01054 ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" );
01055 }
01056 }
01057 else
01058 {
01059 ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" );
01060 }
01061
01062
01063 qglLockArraysEXT = NULL;
01064 qglUnlockArraysEXT = NULL;
01065 if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) && ( glConfig.hardwareType != GLHW_RIVA128 ) )
01066 {
01067 if ( r_ext_compiled_vertex_array->integer )
01068 {
01069 ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" );
01070 qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) qwglGetProcAddress( "glLockArraysEXT" );
01071 qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) qwglGetProcAddress( "glUnlockArraysEXT" );
01072 if (!qglLockArraysEXT || !qglUnlockArraysEXT) {
01073 ri.Error (ERR_FATAL, "bad getprocaddress");
01074 }
01075 }
01076 else
01077 {
01078 ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" );
01079 }
01080 }
01081 else
01082 {
01083 ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" );
01084 }
01085
01086
01087 qwglGetDeviceGammaRamp3DFX = NULL;
01088 qwglSetDeviceGammaRamp3DFX = NULL;
01089
01090 if ( strstr( glConfig.extensions_string, "WGL_3DFX_gamma_control" ) )
01091 {
01092 if ( !r_ignorehwgamma->integer && r_ext_gamma_control->integer )
01093 {
01094 qwglGetDeviceGammaRamp3DFX = ( BOOL ( WINAPI * )( HDC, LPVOID ) ) qwglGetProcAddress( "wglGetDeviceGammaRamp3DFX" );
01095 qwglSetDeviceGammaRamp3DFX = ( BOOL ( WINAPI * )( HDC, LPVOID ) ) qwglGetProcAddress( "wglSetDeviceGammaRamp3DFX" );
01096
01097 if ( qwglGetDeviceGammaRamp3DFX && qwglSetDeviceGammaRamp3DFX )
01098 {
01099 ri.Printf( PRINT_ALL, "...using WGL_3DFX_gamma_control\n" );
01100 }
01101 else
01102 {
01103 qwglGetDeviceGammaRamp3DFX = NULL;
01104 qwglSetDeviceGammaRamp3DFX = NULL;
01105 }
01106 }
01107 else
01108 {
01109 ri.Printf( PRINT_ALL, "...ignoring WGL_3DFX_gamma_control\n" );
01110 }
01111 }
01112 else
01113 {
01114 ri.Printf( PRINT_ALL, "...WGL_3DFX_gamma_control not found\n" );
01115 }
01116 }
01117
01118
01119
01120
01121 static qboolean GLW_CheckOSVersion( void )
01122 {
01123 #define OSR2_BUILD_NUMBER 1111
01124
01125 OSVERSIONINFO vinfo;
01126
01127 vinfo.dwOSVersionInfoSize = sizeof(vinfo);
01128
01129 glw_state.allowdisplaydepthchange = qfalse;
01130
01131 if ( GetVersionEx( &vinfo) )
01132 {
01133 if ( vinfo.dwMajorVersion > 4 )
01134 {
01135 glw_state.allowdisplaydepthchange = qtrue;
01136 }
01137 else if ( vinfo.dwMajorVersion == 4 )
01138 {
01139 if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
01140 {
01141 glw_state.allowdisplaydepthchange = qtrue;
01142 }
01143 else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
01144 {
01145 if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
01146 {
01147 glw_state.allowdisplaydepthchange = qtrue;
01148 }
01149 }
01150 }
01151 }
01152 else
01153 {
01154 ri.Printf( PRINT_ALL, "GLW_CheckOSVersion() - GetVersionEx failed\n" );
01155 return qfalse;
01156 }
01157
01158 return qtrue;
01159 }
01160
01161
01162
01163
01164
01165
01166
01167 static qboolean GLW_LoadOpenGL( const char *drivername )
01168 {
01169 char buffer[1024];
01170 qboolean cdsFullscreen;
01171
01172 Q_strncpyz( buffer, drivername, sizeof(buffer) );
01173 Q_strlwr(buffer);
01174
01175
01176
01177
01178 if ( strstr( buffer, "opengl32" ) != 0 || r_maskMinidriver->integer )
01179 {
01180 glConfig.driverType = GLDRV_ICD;
01181 }
01182 else
01183 {
01184 glConfig.driverType = GLDRV_STANDALONE;
01185
01186 ri.Printf( PRINT_ALL, "...assuming '%s' is a standalone driver\n", drivername );
01187
01188 if ( strstr( buffer, _3DFX_DRIVER_NAME ) )
01189 {
01190 glConfig.driverType = GLDRV_VOODOO;
01191 }
01192 }
01193
01194
01195 _putenv("FX_GLIDE_NO_SPLASH=0");
01196
01197
01198
01199
01200 if ( QGL_Init( buffer ) )
01201 {
01202 cdsFullscreen = r_fullscreen->integer;
01203
01204
01205 if ( !GLW_StartDriverAndSetMode( drivername, r_mode->integer, r_colorbits->integer, cdsFullscreen ) )
01206 {
01207
01208
01209 if ( glConfig.driverType == GLDRV_ICD )
01210 {
01211 if ( r_colorbits->integer != 16 ||
01212 cdsFullscreen != qtrue ||
01213 r_mode->integer != 3 )
01214 {
01215 if ( !GLW_StartDriverAndSetMode( drivername, 3, 16, qtrue ) )
01216 {
01217 goto fail;
01218 }
01219 }
01220 }
01221 else
01222 {
01223 goto fail;
01224 }
01225 }
01226
01227 if ( glConfig.driverType == GLDRV_VOODOO )
01228 {
01229 glConfig.isFullscreen = qtrue;
01230 }
01231
01232 return qtrue;
01233 }
01234 fail:
01235
01236 QGL_Shutdown();
01237
01238 return qfalse;
01239 }
01240
01241
01242
01243
01244 void GLimp_EndFrame (void)
01245 {
01246
01247
01248
01249 if ( r_swapInterval->modified ) {
01250 r_swapInterval->modified = qfalse;
01251
01252 if ( !glConfig.stereoEnabled ) {
01253 if ( qwglSwapIntervalEXT ) {
01254 qwglSwapIntervalEXT( r_swapInterval->integer );
01255 }
01256 }
01257 }
01258
01259
01260
01261 if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 )
01262 {
01263 if ( glConfig.driverType > GLDRV_ICD )
01264 {
01265 if ( !qwglSwapBuffers( glw_state.hDC ) )
01266 {
01267 ri.Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n" );
01268 }
01269 }
01270 else
01271 {
01272 SwapBuffers( glw_state.hDC );
01273 }
01274 }
01275
01276
01277 QGL_EnableLogging( r_logFile->integer );
01278 }
01279
01280 static void GLW_StartOpenGL( void )
01281 {
01282 qboolean attemptedOpenGL32 = qfalse;
01283 qboolean attempted3Dfx = qfalse;
01284
01285
01286
01287
01288 if ( !GLW_LoadOpenGL( r_glDriver->string ) )
01289 {
01290 if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) )
01291 {
01292 attemptedOpenGL32 = qtrue;
01293 }
01294 else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) )
01295 {
01296 attempted3Dfx = qtrue;
01297 }
01298
01299 if ( !attempted3Dfx )
01300 {
01301 attempted3Dfx = qtrue;
01302 if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) )
01303 {
01304 ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME );
01305 r_glDriver->modified = qfalse;
01306 }
01307 else
01308 {
01309 if ( !attemptedOpenGL32 )
01310 {
01311 if ( !GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
01312 {
01313 ri.Error( ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem\n" );
01314 }
01315 ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
01316 r_glDriver->modified = qfalse;
01317 }
01318 else
01319 {
01320 ri.Error( ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem\n" );
01321 }
01322 }
01323 }
01324 else if ( !attemptedOpenGL32 )
01325 {
01326 attemptedOpenGL32 = qtrue;
01327 if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) )
01328 {
01329 ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME );
01330 r_glDriver->modified = qfalse;
01331 }
01332 else
01333 {
01334 ri.Error( ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem\n" );
01335 }
01336 }
01337 }
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350 void GLimp_Init( void )
01351 {
01352 char buf[1024];
01353 cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE );
01354 cvar_t *cv;
01355
01356 ri.Printf( PRINT_ALL, "Initializing OpenGL subsystem\n" );
01357
01358
01359
01360
01361 if ( !GLW_CheckOSVersion() )
01362 {
01363 ri.Error( ERR_FATAL, "GLimp_Init() - incorrect operating system\n" );
01364 }
01365
01366
01367 cv = ri.Cvar_Get( "win_hinstance", "", 0 );
01368 sscanf( cv->string, "%i", (int *)&g_wv.hInstance );
01369
01370 cv = ri.Cvar_Get( "win_wndproc", "", 0 );
01371 sscanf( cv->string, "%i", (int *)&glw_state.wndproc );
01372
01373 r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH );
01374 r_maskMinidriver = ri.Cvar_Get( "r_maskMinidriver", "0", CVAR_LATCH );
01375
01376
01377 GLW_StartOpenGL();
01378
01379
01380 Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) );
01381 Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) );
01382 Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) );
01383 Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) );
01384
01385
01386
01387
01388 Q_strncpyz( buf, glConfig.renderer_string, sizeof(buf) );
01389 Q_strlwr( buf );
01390
01391
01392
01393
01394
01395
01396 if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) )
01397 {
01398 glConfig.hardwareType = GLHW_GENERIC;
01399
01400 ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" );
01401
01402
01403 if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) )
01404 {
01405 ri.Cvar_Set( "r_picmip", "2" );
01406 ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH );
01407 }
01408 else
01409 {
01410 ri.Cvar_Set( "r_picmip", "1" );
01411
01412 if ( strstr( buf, "rage 128" ) || strstr( buf, "rage128" ) )
01413 {
01414 ri.Cvar_Set( "r_finish", "0" );
01415 }
01416
01417 else if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) )
01418 {
01419 ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
01420 }
01421 }
01422 }
01423
01424
01425
01426
01427
01428 if ( strstr( buf, "banshee" ) || strstr( buf, "voodoo3" ) )
01429 {
01430 glConfig.hardwareType = GLHW_3DFX_2D3D;
01431 }
01432
01433 else if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) )
01434 {
01435 }
01436 else if ( strstr( buf, "glzicd" ) )
01437 {
01438 }
01439 else if ( strstr( buf, "rage pro" ) || strstr( buf, "Rage Pro" ) || strstr( buf, "ragepro" ) )
01440 {
01441 glConfig.hardwareType = GLHW_RAGEPRO;
01442 }
01443 else if ( strstr( buf, "rage 128" ) )
01444 {
01445 }
01446 else if ( strstr( buf, "permedia2" ) )
01447 {
01448 glConfig.hardwareType = GLHW_PERMEDIA2;
01449 }
01450 else if ( strstr( buf, "riva 128" ) )
01451 {
01452 glConfig.hardwareType = GLHW_RIVA128;
01453 }
01454 else if ( strstr( buf, "riva tnt " ) )
01455 {
01456 }
01457
01458 ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string );
01459
01460 GLW_InitExtensions();
01461 WG_CheckHardwareGamma();
01462 }
01463
01464
01465
01466
01467
01468
01469
01470 void GLimp_Shutdown( void )
01471 {
01472
01473 const char *success[] = { "failed", "success" };
01474 int retVal;
01475
01476
01477 if ( !qwglMakeCurrent ) {
01478 return;
01479 }
01480
01481 ri.Printf