static qboolean GLimp_CheckForVersionExtension(const char *ext, int coresince, qboolean required, cvar_t *var) { qboolean result = qfalse; if ((coresince >= 0 && coresince <= glConfig2.contextCombined) || GL_CheckForExtension(ext)) { if (var && var->integer) { result = qtrue; } else if (!var) { result = qtrue; } } if (required && !result) { Ren_Fatal(MSG_ERR_OLD_VIDEO_DRIVER "\nYour GL driver is missing support for: %s\n", ext); } if (result) { Com_Printf("...found OpenGL extension - %s\n", ext); } else { if (var) { Com_Printf("...ignoring %s\n", ext); } else { Com_Printf("...%s not found\n", ext); } } return result; }
static void GLimp_InitExtensions( void ) { if ( !r_allowExtensions->integer ) { Com_Printf ("*** IGNORING OPENGL EXTENSIONS ***\n" ); g_bDynamicGlowSupported = false; ri->Cvar_Set( "r_DynamicGlow","0" ); return; } Com_Printf ("Initializing OpenGL extensions\n" ); // Select our tc scheme GLW_InitTextureCompression(); // GL_EXT_texture_env_add glConfig.textureEnvAddAvailable = qfalse; if ( GL_CheckForExtension( "EXT_texture_env_add" ) ) { if ( r_ext_texture_env_add->integer ) { glConfig.textureEnvAddAvailable = qtrue; Com_Printf ("...using GL_EXT_texture_env_add\n" ); } else { glConfig.textureEnvAddAvailable = qfalse; Com_Printf ("...ignoring GL_EXT_texture_env_add\n" ); } } else { Com_Printf ("...GL_EXT_texture_env_add not found\n" ); } // GL_EXT_texture_filter_anisotropic glConfig.maxTextureFilterAnisotropy = 0; if ( GL_CheckForExtension( "EXT_texture_filter_anisotropic" ) ) { #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF //can't include glext.h here ... sigh qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureFilterAnisotropy ); Com_Printf ("...GL_EXT_texture_filter_anisotropic available\n" ); if ( r_ext_texture_filter_anisotropic->integer > 1 ) { Com_Printf ("...using GL_EXT_texture_filter_anisotropic\n" ); } else { Com_Printf ("...ignoring GL_EXT_texture_filter_anisotropic\n" ); } ri->Cvar_SetValue( "r_ext_texture_filter_anisotropic_avail", glConfig.maxTextureFilterAnisotropy ); if ( r_ext_texture_filter_anisotropic->value > glConfig.maxTextureFilterAnisotropy ) { ri->Cvar_SetValue( "r_ext_texture_filter_anisotropic_avail", glConfig.maxTextureFilterAnisotropy ); } } else { Com_Printf ("...GL_EXT_texture_filter_anisotropic not found\n" ); ri->Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); } // GL_EXT_clamp_to_edge glConfig.clampToEdgeAvailable = qtrue; Com_Printf ("...using GL_EXT_texture_edge_clamp\n" ); // GL_ARB_multitexture qglMultiTexCoord2fARB = NULL; qglActiveTextureARB = NULL; qglClientActiveTextureARB = NULL; if ( GL_CheckForExtension( "GL_ARB_multitexture" ) ) { if ( r_ext_multitexture->integer ) { qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" ); qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glActiveTextureARB" ); qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) SDL_GL_GetProcAddress( "glClientActiveTextureARB" ); if ( qglActiveTextureARB ) { qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures ); if ( glConfig.maxActiveTextures > 1 ) { Com_Printf ("...using GL_ARB_multitexture\n" ); } else { qglMultiTexCoord2fARB = NULL; qglActiveTextureARB = NULL; qglClientActiveTextureARB = NULL; Com_Printf ("...not using GL_ARB_multitexture, < 2 texture units\n" ); } } } else { Com_Printf ("...ignoring GL_ARB_multitexture\n" ); } } else { Com_Printf ("...GL_ARB_multitexture not found\n" ); } // GL_EXT_compiled_vertex_array qglLockArraysEXT = NULL; qglUnlockArraysEXT = NULL; if ( GL_CheckForExtension( "GL_EXT_compiled_vertex_array" ) ) { if ( r_ext_compiled_vertex_array->integer ) { Com_Printf ("...using GL_EXT_compiled_vertex_array\n" ); qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" ); qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" ); if (!qglLockArraysEXT || !qglUnlockArraysEXT) { Com_Error (ERR_FATAL, "bad getprocaddress"); } } else { Com_Printf ("...ignoring GL_EXT_compiled_vertex_array\n" ); } } else { Com_Printf ("...GL_EXT_compiled_vertex_array not found\n" ); } qglPointParameterfEXT = NULL; qglPointParameterfvEXT = NULL; //3d textures -rww qglTexImage3DEXT = NULL; qglTexSubImage3DEXT = NULL; if ( GL_CheckForExtension( "GL_EXT_point_parameters" ) ) { if ( r_ext_compiled_vertex_array->integer ) { Com_Printf ("...using GL_EXT_point_parameters\n" ); qglPointParameterfEXT = ( void ( APIENTRY * )( GLenum, GLfloat) ) SDL_GL_GetProcAddress( "glPointParameterfEXT" ); qglPointParameterfvEXT = ( void ( APIENTRY * )( GLenum, GLfloat *) ) SDL_GL_GetProcAddress( "glPointParameterfvEXT" ); //3d textures -rww qglTexImage3DEXT = (void ( APIENTRY * ) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *) ) SDL_GL_GetProcAddress( "glTexImage3DEXT" ); qglTexSubImage3DEXT = (void ( APIENTRY * ) (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *) ) SDL_GL_GetProcAddress( "glTexSubImage3DEXT" ); if (!qglPointParameterfEXT || !qglPointParameterfvEXT) { Com_Error (ERR_FATAL, "bad getprocaddress"); } } else { Com_Printf ("...ignoring GL_EXT_point_parameters\n" ); } } else { Com_Printf ("...GL_EXT_point_parameters not found\n" ); } bool bNVRegisterCombiners = false; // Register Combiners. if ( GL_CheckForExtension( "GL_NV_register_combiners" ) ) { // NOTE: This extension requires multitexture support (over 2 units). if ( glConfig.maxActiveTextures >= 2 ) { bNVRegisterCombiners = true; // Register Combiners function pointer address load. - AReis // NOTE: VV guys will _definetly_ not be able to use regcoms. Pixel Shaders are just as good though :-) // NOTE: Also, this is an nVidia specific extension (of course), so fragment shaders would serve the same purpose // if we needed some kind of fragment/pixel manipulation support. qglCombinerParameterfvNV = (PFNGLCOMBINERPARAMETERFVNVPROC)SDL_GL_GetProcAddress( "glCombinerParameterfvNV" ); qglCombinerParameterivNV = (PFNGLCOMBINERPARAMETERIVNVPROC)SDL_GL_GetProcAddress( "glCombinerParameterivNV" ); qglCombinerParameterfNV = (PFNGLCOMBINERPARAMETERFNVPROC)SDL_GL_GetProcAddress( "glCombinerParameterfNV" ); qglCombinerParameteriNV = (PFNGLCOMBINERPARAMETERINVPROC)SDL_GL_GetProcAddress( "glCombinerParameteriNV" ); qglCombinerInputNV = (PFNGLCOMBINERINPUTNVPROC)SDL_GL_GetProcAddress( "glCombinerInputNV" ); qglCombinerOutputNV = (PFNGLCOMBINEROUTPUTNVPROC)SDL_GL_GetProcAddress( "glCombinerOutputNV" ); qglFinalCombinerInputNV = (PFNGLFINALCOMBINERINPUTNVPROC)SDL_GL_GetProcAddress( "glFinalCombinerInputNV" ); qglGetCombinerInputParameterfvNV = (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)SDL_GL_GetProcAddress( "glGetCombinerInputParameterfvNV" ); qglGetCombinerInputParameterivNV = (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)SDL_GL_GetProcAddress( "glGetCombinerInputParameterivNV" ); qglGetCombinerOutputParameterfvNV = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)SDL_GL_GetProcAddress( "glGetCombinerOutputParameterfvNV" ); qglGetCombinerOutputParameterivNV = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)SDL_GL_GetProcAddress( "glGetCombinerOutputParameterivNV" ); qglGetFinalCombinerInputParameterfvNV = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)SDL_GL_GetProcAddress( "glGetFinalCombinerInputParameterfvNV" ); qglGetFinalCombinerInputParameterivNV = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)SDL_GL_GetProcAddress( "glGetFinalCombinerInputParameterivNV" ); // Validate the functions we need. if ( !qglCombinerParameterfvNV || !qglCombinerParameterivNV || !qglCombinerParameterfNV || !qglCombinerParameteriNV || !qglCombinerInputNV || !qglCombinerOutputNV || !qglFinalCombinerInputNV || !qglGetCombinerInputParameterfvNV || !qglGetCombinerInputParameterivNV || !qglGetCombinerOutputParameterfvNV || !qglGetCombinerOutputParameterivNV || !qglGetFinalCombinerInputParameterfvNV || !qglGetFinalCombinerInputParameterivNV ) { bNVRegisterCombiners = false; qglCombinerParameterfvNV = NULL; qglCombinerParameteriNV = NULL; Com_Printf ("...GL_NV_register_combiners failed\n" ); } } else { bNVRegisterCombiners = false; Com_Printf ("...ignoring GL_NV_register_combiners\n" ); } } else { bNVRegisterCombiners = false; Com_Printf ("...GL_NV_register_combiners not found\n" ); } // NOTE: Vertex and Fragment Programs are very dependant on each other - this is actually a // good thing! So, just check to see which we support (one or the other) and load the shared // function pointers. ARB rocks! // Vertex Programs. bool bARBVertexProgram = false; if ( GL_CheckForExtension( "GL_ARB_vertex_program" ) ) { bARBVertexProgram = true; } else { bARBVertexProgram = false; Com_Printf ("...GL_ARB_vertex_program not found\n" ); } // Fragment Programs. bool bARBFragmentProgram = false; if ( GL_CheckForExtension( "GL_ARB_fragment_program" ) ) { bARBFragmentProgram = true; } else { bARBFragmentProgram = false; Com_Printf ("...GL_ARB_fragment_program not found\n" ); } // If we support one or the other, load the shared function pointers. if ( bARBVertexProgram || bARBFragmentProgram ) { qglProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) SDL_GL_GetProcAddress("glProgramStringARB"); qglBindProgramARB = (PFNGLBINDPROGRAMARBPROC) SDL_GL_GetProcAddress("glBindProgramARB"); qglDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) SDL_GL_GetProcAddress("glDeleteProgramsARB"); qglGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) SDL_GL_GetProcAddress("glGenProgramsARB"); qglProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4dARB"); qglProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4dvARB"); qglProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4fARB"); qglProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) SDL_GL_GetProcAddress("glProgramEnvParameter4fvARB"); qglProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4dARB"); qglProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4dvARB"); qglProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4fARB"); qglProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) SDL_GL_GetProcAddress("glProgramLocalParameter4fvARB"); qglGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) SDL_GL_GetProcAddress("glGetProgramEnvParameterdvARB"); qglGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetProgramEnvParameterfvARB"); qglGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) SDL_GL_GetProcAddress("glGetProgramLocalParameterdvARB"); qglGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) SDL_GL_GetProcAddress("glGetProgramLocalParameterfvARB"); qglGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) SDL_GL_GetProcAddress("glGetProgramivARB"); qglGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) SDL_GL_GetProcAddress("glGetProgramStringARB"); qglIsProgramARB = (PFNGLISPROGRAMARBPROC) SDL_GL_GetProcAddress("glIsProgramARB"); // Validate the functions we need. if ( !qglProgramStringARB || !qglBindProgramARB || !qglDeleteProgramsARB || !qglGenProgramsARB || !qglProgramEnvParameter4dARB || !qglProgramEnvParameter4dvARB || !qglProgramEnvParameter4fARB || !qglProgramEnvParameter4fvARB || !qglProgramLocalParameter4dARB || !qglProgramLocalParameter4dvARB || !qglProgramLocalParameter4fARB || !qglProgramLocalParameter4fvARB || !qglGetProgramEnvParameterdvARB || !qglGetProgramEnvParameterfvARB || !qglGetProgramLocalParameterdvARB || !qglGetProgramLocalParameterfvARB || !qglGetProgramivARB || !qglGetProgramStringARB || !qglIsProgramARB ) { bARBVertexProgram = false; bARBFragmentProgram = false; qglGenProgramsARB = NULL; //clear ptrs that get checked qglProgramEnvParameter4fARB = NULL; Com_Printf ("...ignoring GL_ARB_vertex_program\n" ); Com_Printf ("...ignoring GL_ARB_fragment_program\n" ); } } // Figure out which texture rectangle extension to use. bool bTexRectSupported = false; if ( Q_stricmpn( glConfig.vendor_string, "ATI Technologies",16 )==0 && Q_stricmpn( glConfig.version_string, "1.3.3",5 )==0 && glConfig.version_string[5] < '9' ) //1.3.34 and 1.3.37 and 1.3.38 are broken for sure, 1.3.39 is not { g_bTextureRectangleHack = true; } if ( GL_CheckForExtension( "GL_NV_texture_rectangle" ) || GL_CheckForExtension( "GL_EXT_texture_rectangle" ) ) { bTexRectSupported = true; } // Find out how many general combiners they have. #define GL_MAX_GENERAL_COMBINERS_NV 0x854D GLint iNumGeneralCombiners = 0; if(bNVRegisterCombiners) qglGetIntegerv( GL_MAX_GENERAL_COMBINERS_NV, &iNumGeneralCombiners ); // Only allow dynamic glows/flares if they have the hardware if ( bTexRectSupported && bARBVertexProgram && qglActiveTextureARB && glConfig.maxActiveTextures >= 4 && ( ( bNVRegisterCombiners && iNumGeneralCombiners >= 2 ) || bARBFragmentProgram ) ) { g_bDynamicGlowSupported = true; // this would overwrite any achived setting gwg // Cvar_Set( "r_DynamicGlow", "1" ); } else { g_bDynamicGlowSupported = false; ri->Cvar_Set( "r_DynamicGlow","0" ); } }
static void GLW_InitTextureCompression( void ) { bool newer_tc, old_tc; // Check for available tc methods. newer_tc = GL_CheckForExtension("ARB_texture_compression") && GL_CheckForExtension("EXT_texture_compression_s3tc"); old_tc = GL_CheckForExtension("GL_S3_s3tc"); if ( old_tc ) { Com_Printf ("...GL_S3_s3tc available\n" ); } if ( newer_tc ) { Com_Printf ("...GL_EXT_texture_compression_s3tc available\n" ); } if ( !r_ext_compressed_textures->value ) { // Compressed textures are off glConfig.textureCompression = TC_NONE; Com_Printf ("...ignoring texture compression\n" ); } else if ( !old_tc && !newer_tc ) { // Requesting texture compression, but no method found glConfig.textureCompression = TC_NONE; Com_Printf ("...no supported texture compression method found\n" ); Com_Printf (".....ignoring texture compression\n" ); } else { // some form of supported texture compression is avaiable, so see if the user has a preference if ( r_ext_preferred_tc_method->integer == TC_NONE ) { // No preference, so pick the best if ( newer_tc ) { Com_Printf ("...no tc preference specified\n" ); Com_Printf (".....using GL_EXT_texture_compression_s3tc\n" ); glConfig.textureCompression = TC_S3TC_DXT; } else { Com_Printf ("...no tc preference specified\n" ); Com_Printf (".....using GL_S3_s3tc\n" ); glConfig.textureCompression = TC_S3TC; } } else { // User has specified a preference, now see if this request can be honored if ( old_tc && newer_tc ) { // both are avaiable, so we can use the desired tc method if ( r_ext_preferred_tc_method->integer == TC_S3TC ) { Com_Printf ("...using preferred tc method, GL_S3_s3tc\n" ); glConfig.textureCompression = TC_S3TC; } else { Com_Printf ("...using preferred tc method, GL_EXT_texture_compression_s3tc\n" ); glConfig.textureCompression = TC_S3TC_DXT; } } else { // Both methods are not available, so this gets trickier if ( r_ext_preferred_tc_method->integer == TC_S3TC ) { // Preferring to user older compression if ( old_tc ) { Com_Printf ("...using GL_S3_s3tc\n" ); glConfig.textureCompression = TC_S3TC; } else { // Drat, preference can't be honored Com_Printf ("...preferred tc method, GL_S3_s3tc not available\n" ); Com_Printf (".....falling back to GL_EXT_texture_compression_s3tc\n" ); glConfig.textureCompression = TC_S3TC_DXT; } } else { // Preferring to user newer compression if ( newer_tc ) { Com_Printf ("...using GL_EXT_texture_compression_s3tc\n" ); glConfig.textureCompression = TC_S3TC_DXT; } else { // Drat, preference can't be honored Com_Printf ("...preferred tc method, GL_EXT_texture_compression_s3tc not available\n" ); Com_Printf (".....falling back to GL_S3_s3tc\n" ); glConfig.textureCompression = TC_S3TC; } } } } } }