Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

win_glimp.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 /*
00023 ** WIN_GLIMP.C
00024 **
00025 ** This file contains ALL Win32 specific stuff having to do with the
00026 ** OpenGL refresh.  When a port is being made the following functions
00027 ** must be implemented by the port:
00028 **
00029 ** GLimp_EndFrame
00030 ** GLimp_Init
00031 ** GLimp_LogComment
00032 ** GLimp_Shutdown
00033 **
00034 ** Note that the GLW_xxx functions are Windows specific GL-subsystem
00035 ** related functions that are relevant ONLY to win_glimp.c
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 // function declaration
00072 //
00073 void     QGL_EnableLogging( qboolean enable );
00074 qboolean QGL_Init( const char *dllname );
00075 void     QGL_Shutdown( void );
00076 
00077 //
00078 // variable declarations
00079 //
00080 glwstate_t glw_state;
00081 
00082 cvar_t  *r_allowSoftwareGL;     // don't abort out if the pixelformat claims software
00083 cvar_t  *r_maskMinidriver;      // allow a different dll name to be treated as if it were opengl32.dll
00084 
00085 
00086 
00087 /*
00088 ** GLW_StartDriverAndSetMode
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 ** ChoosePFD
00115 **
00116 ** Helper function that replaces ChoosePixelFormat.
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     // count number of PFDs
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     // grab information
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     // look for a best match
00160     for ( i = 1; i <= maxPFD; i++ )
00161     {
00162         //
00163         // make sure this has hardware acceleration
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         // verify pixel type
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         // verify proper flags
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         // verify enough bits
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         // selection criteria (in order of priority):
00209         // 
00210         //  PFD_STEREO
00211         //  colorBits
00212         //  depthBits
00213         //  stencilBits
00214         //
00215         if ( bestMatch )
00216         {
00217             // check stereo
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             // check color
00231             if ( pfds[bestMatch].cColorBits != pPFD->cColorBits )
00232             {
00233                 // prefer perfect match
00234                 if ( pfds[i].cColorBits == pPFD->cColorBits )
00235                 {
00236                     bestMatch = i;
00237                     continue;
00238                 }
00239                 // otherwise if this PFD has more bits than our best, use it
00240                 else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits )
00241                 {
00242                     bestMatch = i;
00243                     continue;
00244                 }
00245             }
00246 
00247             // check depth
00248             if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits )
00249             {
00250                 // prefer perfect match
00251                 if ( pfds[i].cDepthBits == pPFD->cDepthBits )
00252                 {
00253                     bestMatch = i;
00254                     continue;
00255                 }
00256                 // otherwise if this PFD has more bits than our best, use it
00257                 else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits )
00258                 {
00259                     bestMatch = i;
00260                     continue;
00261                 }
00262             }
00263 
00264             // check stencil
00265             if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits )
00266             {
00267                 // prefer perfect match
00268                 if ( pfds[i].cStencilBits == pPFD->cStencilBits )
00269                 {
00270                     bestMatch = i;
00271                     continue;
00272                 }
00273                 // otherwise if this PFD has more bits than our best, use it
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 ** void GLW_CreatePFD
00319 **
00320 ** Helper function zeros out then fills in a PFD
00321 */
00322 static void GLW_CreatePFD( PIXELFORMATDESCRIPTOR *pPFD, int colorbits, int depthbits, int stencilbits, qboolean stereo )
00323 {
00324     PIXELFORMATDESCRIPTOR src = 
00325     {
00326         sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
00327         1,                              // version number
00328         PFD_DRAW_TO_WINDOW |            // support window
00329         PFD_SUPPORT_OPENGL |            // support OpenGL
00330         PFD_DOUBLEBUFFER,               // double buffered
00331         PFD_TYPE_RGBA,                  // RGBA type
00332         24,                             // 24-bit color depth
00333         0, 0, 0, 0, 0, 0,               // color bits ignored
00334         0,                              // no alpha buffer
00335         0,                              // shift bit ignored
00336         0,                              // no accumulation buffer
00337         0, 0, 0, 0,                     // accum bits ignored
00338         24,                             // 24-bit z-buffer  
00339         8,                              // 8-bit stencil buffer
00340         0,                              // no auxiliary buffer
00341         PFD_MAIN_PLANE,                 // main layer
00342         0,                              // reserved
00343         0, 0, 0                         // layer masks ignored
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 ** GLW_MakeContext
00366 */
00367 static int GLW_MakeContext( PIXELFORMATDESCRIPTOR *pPFD )
00368 {
00369     int pixelformat;
00370 
00371     //
00372     // don't putz around with pixelformat if it's already set (e.g. this is a soft
00373     // reset of the graphics system)
00374     //
00375     if ( !glw_state.pixelFormatSet )
00376     {
00377         //
00378         // choose, set, and describe our desired pixel format.  If we're
00379         // using a minidriver then we need to bypass the GDI functions,
00380         // otherwise use the GDI functions.
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     // startup the OpenGL subsystem by creating a context and making it current
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 ** GLW_InitDriver
00443 **
00444 ** - get a DC if one doesn't exist
00445 ** - create an HGLRC if one doesn't exist
00446 */
00447 static qboolean GLW_InitDriver( const char *drivername, int colorbits )
00448 {
00449     int     tpfd;
00450     int     depthbits, stencilbits;
00451     static PIXELFORMATDESCRIPTOR pfd;       // save between frames since 'tr' gets cleared
00452 
00453     ri.Printf( PRINT_ALL, "Initializing OpenGL driver\n" );
00454 
00455     //
00456     // get a DC for our window if we don't already have one allocated
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     // implicitly assume Z-buffer depth == desktop color depth
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     // do not allow stencil if Z-buffer depth likely won't contain it
00490     //
00491     stencilbits = r_stencilbits->integer;
00492     if ( depthbits < 24 )
00493     {
00494         stencilbits = 0;
00495     }
00496 
00497     //
00498     // make two attempts to set the PIXELFORMAT
00499     //
00500 
00501     //
00502     // first attempt: r_colorbits, depthbits, and r_stencilbits
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             // punt if we've already tried the desktop bit depth and no stencil bits
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             // second attempt: desktop's color bits and no stencil
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         ** report if stereo is desired but unavailable
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     ** store PFD specifics 
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 ** GLW_CreateWindow
00573 **
00574 ** Responsible for creating the Win32 window and initializing the OpenGL driver.
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     // register the window class if necessary
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     // create the HWND if one does not already exist
00615     //
00616     if ( !g_wv.hWnd )
00617     {
00618         //
00619         // compute width and height
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             // adjust window coordinates if necessary 
00654             // so that the window is completely on screen
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 ** GLW_SetMode
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     // print out informational messages
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     // check our desktop attributes
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     // verify desktop bit depth
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     // do a CDS if needed
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         // try to change color depth if possible
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         // if we're already in fullscreen then just create the window
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         // need to call CDS
00849         //
00850         else
00851         {
00852             ri.Printf( PRINT_ALL, "...calling CDS: " );
00853             
00854             // try setting the exact mode requested, because some drivers don't report
00855             // the low res modes in EnumDisplaySettings, but still work
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                 // the exact mode failed, so scan EnumDisplaySettings for the next largest mode
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                 // we could do a better matching job here...
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     // success, now check display frequency, although this won't be valid on Voodoo(2)
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     // NOTE: this is overridden later on standalone 3Dfx drivers
00953     glConfig.isFullscreen = cdsFullscreen;
00954 
00955     return RSERR_OK;
00956 }
00957 
00958 /*
00959 ** GLW_InitExtensions
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     // GL_S3_s3tc
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     // GL_EXT_texture_env_add
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     // WGL_EXT_swap_control
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;   // force a set next frame
01017     }
01018     else
01019     {
01020         ri.Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" );
01021     }
01022 
01023     // GL_ARB_multitexture
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     // GL_EXT_compiled_vertex_array
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     // WGL_3DFX_gamma_control
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 ** GLW_CheckOSVersion
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 ** GLW_LoadOpenGL
01163 **
01164 ** GLimp_win.c internal function that attempts to load and use 
01165 ** a specific OpenGL DLL.
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     // determine if we're on a standalone driver
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     // disable the 3Dfx splash screen
01195     _putenv("FX_GLIDE_NO_SPLASH=0");
01196 
01197     //
01198     // load the driver and bind our function pointers to it
01199     // 
01200     if ( QGL_Init( buffer ) ) 
01201     {
01202         cdsFullscreen = r_fullscreen->integer;
01203 
01204         // create the window and set up the context
01205         if ( !GLW_StartDriverAndSetMode( drivername, r_mode->integer, r_colorbits->integer, cdsFullscreen ) )
01206         {
01207             // if we're on a 24/32-bit desktop and we're going fullscreen on an ICD,
01208             // try it again but with a 16-bit desktop
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 ** GLimp_EndFrame
01243 */
01244 void GLimp_EndFrame (void)
01245 {
01246     //
01247     // swapinterval stuff
01248     //
01249     if ( r_swapInterval->modified ) {
01250         r_swapInterval->modified = qfalse;
01251 
01252         if ( !glConfig.stereoEnabled ) {    // why?
01253             if ( qwglSwapIntervalEXT ) {
01254                 qwglSwapIntervalEXT( r_swapInterval->integer );
01255             }
01256         }
01257     }
01258 
01259 
01260     // don't flip if drawing to front buffer
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     // check logging
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     // load and initialize the specific OpenGL driver
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 ** GLimp_Init
01342 **
01343 ** This is the platform specific OpenGL initialization function.  It
01344 ** is responsible for loading OpenGL, initializing it, setting
01345 ** extensions, creating a window of the appropriate size, doing
01346 ** fullscreen manipulations, etc.  Its overall responsibility is
01347 ** to make sure that a functional OpenGL subsystem is operating
01348 ** when it returns to the ref.
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     // check OS version to see if we can do fullscreen display changes
01360     //
01361     if ( !GLW_CheckOSVersion() )
01362     {
01363         ri.Error( ERR_FATAL, "GLimp_Init() - incorrect operating system\n" );
01364     }
01365 
01366     // save off hInstance and wndproc
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     // load appropriate DLL and initialize subsystem
01377     GLW_StartOpenGL();
01378 
01379     // get our config strings
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     // chipset specific configuration
01387     //
01388     Q_strncpyz( buf, glConfig.renderer_string, sizeof(buf) );
01389     Q_strlwr( buf );
01390 
01391     //
01392     // NOTE: if changing cvars, do it within this block.  This allows them
01393     // to be overridden when testing driver fixes, etc. but only sets
01394     // them to their default state when the hardware is first installed/run.
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         // VOODOO GRAPHICS w/ 2MB
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             // Savage3D and Savage4 should always have trilinear enabled
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     // this is where hardware specific workarounds that should be
01426     // detected/initialized every startup should go.
01427     //
01428     if ( strstr( buf, "banshee" ) || strstr( buf, "voodoo3" ) )
01429     {
01430         glConfig.hardwareType = GLHW_3DFX_2D3D;
01431     }
01432     // VOODOO GRAPHICS w/ 2MB
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 ** GLimp_Shutdown
01466 **
01467 ** This routine does all OS specific shutdown procedures for the OpenGL
01468 ** subsystem.
01469 */
01470 void GLimp_Shutdown( void )
01471 {
01472 //  const char *strings[] = { "soft", "hard" };
01473     const char *success[] = { "failed", "success" };
01474     int retVal;
01475 
01476     // FIXME: Brian, we need better fallbacks from partially initialized failures
01477     if ( !qwglMakeCurrent ) {
01478         return;
01479     }
01480 
01481     ri.Printf