/* ================= GL_SelectTexture ================= */ void GL_SelectTexture( GLint tmu ) { if( !GL_Support( GL_ARB_MULTITEXTURE )) return; // don't allow negative texture units if( tmu < 0 ) return; if( tmu >= GL_MaxTextureUnits( )) { MsgDev( D_ERROR, "GL_SelectTexture: bad tmu state %i\n", tmu ); return; } if( glState.activeTMU == tmu ) return; glState.activeTMU = tmu; #ifndef XASH_NANOGL if( pglActiveTextureARB ) #endif { pglActiveTextureARB( tmu + GL_TEXTURE0_ARB ); if( tmu < glConfig.max_texture_coords ) pglClientActiveTextureARB( tmu + GL_TEXTURE0_ARB ); } #ifndef XASH_NANOGL else if( pglSelectTextureSGIS ) { pglSelectTextureSGIS( tmu + GL_TEXTURE0_SGIS ); } #endif }
/* ================= GL_CheckExtension ================= */ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cvarname, int r_ext ) { const dllfunc_t *func; convar_t *parm; MsgDev( D_NOTE, "GL_CheckExtension: %s ", name ); if( cvarname ) { // system config disable extensions parm = Cvar_Get( cvarname, "1", CVAR_GLCONFIG, va( "enable or disable %s", name )); if( parm->integer == 0 || ( gl_extensions->integer == 0 && r_ext != GL_OPENGL_110 )) { MsgDev( D_NOTE, "- disabled\n" ); GL_SetExtension( r_ext, 0 ); return; // nothing to process at } GL_SetExtension( r_ext, 1 ); } if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( glConfig.extensions_string, name )) { GL_SetExtension( r_ext, false ); // update render info MsgDev( D_NOTE, "- ^1failed\n" ); return; } GL_SetExtension( r_ext, true ); // predict extension state if( GL_Support( r_ext )) MsgDev( D_NOTE, "- ^2enabled\n" ); else MsgDev( D_NOTE, "- ^1failed\n" ); }
/* ================= GL_MaxTextureUnits ================= */ int GL_MaxTextureUnits( void ) { if( glConfig.max_texture_units_cached == -1 ) { if( GL_Support( GL_SHADER_GLSL100_EXT )) glConfig.max_texture_units_cached = min( max( glConfig.max_texture_coords, glConfig.max_teximage_units ), MAX_TEXTURE_UNITS ); else glConfig.max_texture_units_cached = glConfig.max_texture_units; } return glConfig.max_texture_units_cached; }
/* ================= GL_CheckExtension ================= */ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cvarname, int r_ext ) { const dllfunc_t *func; convar_t *parm; MsgDev( D_NOTE, "GL_CheckExtension: %s ", name ); if( cvarname ) { // system config disable extensions parm = Cvar_Get( cvarname, "1", CVAR_GLCONFIG, va( "enable or disable %s", name )); if( parm->integer == 0 || ( gl_extensions->integer == 0 && r_ext != GL_OPENGL_110 )) { MsgDev( D_NOTE, "- disabled\n" ); GL_SetExtension( r_ext, 0 ); return; // nothing to process at } GL_SetExtension( r_ext, 1 ); } if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( glConfig.extensions_string, name )) { GL_SetExtension( r_ext, false ); // update render info MsgDev( D_NOTE, "- ^1failed\n" ); return; } // clear exports for( func = funcs; func && func->name; func++ ) *func->func = NULL; GL_SetExtension( r_ext, true ); // predict extension state for( func = funcs; func && func->name != NULL; func++ ) { // functions are cleared before all the extensions are evaluated if(!(*func->func = (void *)GL_GetProcAddress( func->name ))) GL_SetExtension( r_ext, false ); // one or more functions are invalid, extension will be disabled } if( GL_Support( r_ext )) MsgDev( D_NOTE, "- ^2enabled\n" ); else MsgDev( D_NOTE, "- ^1failed\n" ); }
/* ================= R_Bloom_InitTextures ================= */ static void R_Bloom_InitTextures( void ) { if( GL_Support( R_ARB_TEXTURE_NPOT_EXT )) { screen_texture_width = glState.width; screen_texture_height = glState.height; } else { // find closer power of 2 to screen size for( screen_texture_width = 1; screen_texture_width < glState.width; screen_texture_width <<= 1 ); for( screen_texture_height = 1; screen_texture_height < glState.height; screen_texture_height <<= 1 ); } // disable blooms if we can't handle a texture of that size if( screen_texture_width > glConfig.max_2d_texture_size || screen_texture_height > glConfig.max_2d_texture_size ) { screen_texture_width = screen_texture_height = 0; CVAR_SET_FLOAT( "r_bloom", 0.0f ); ALERT( at_warning, "'R_InitBloomScreenTexture' too high resolution for light bloom, effect disabled\n" ); return; } r_bloomscreentexture = CREATE_TEXTURE( "*bloomscreentexture", screen_texture_width, screen_texture_height, NULL, TF_IMAGE ); // validate bloom size and init the bloom effect texture R_Bloom_InitEffectTexture(); // if screensize is more than 2x the bloom effect texture, set up for stepped downsampling r_bloomdownsamplingtexture = 0; r_screendownsamplingtexture_size = 0; if(( glState.width > (BLOOM_SIZE * 2) || glState.height > (BLOOM_SIZE * 2)) && !r_bloom_fast_sample->value ) { r_screendownsamplingtexture_size = (int)( BLOOM_SIZE * 2 ); r_bloomdownsamplingtexture = CREATE_TEXTURE( "*bloomdownsampletexture", r_screendownsamplingtexture_size, r_screendownsamplingtexture_size, NULL, TF_IMAGE ); } // init the screen backup texture if( r_screendownsamplingtexture_size ) R_Bloom_InitBackUpTexture( r_screendownsamplingtexture_size, r_screendownsamplingtexture_size ); else R_Bloom_InitBackUpTexture( BLOOM_SIZE, BLOOM_SIZE ); }
/* ============= R_UploadStretchRaw ============= */ void R_UploadStretchRaw( int texture, int cols, int rows, int width, int height, const byte *data ) { byte *raw = NULL; gltexture_t *tex; if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) { // check the dimensions width = NearestPOW( width, true ); height = NearestPOW( height, false ); } else { width = bound( 128, width, glConfig.max_2d_texture_size ); height = bound( 128, height, glConfig.max_2d_texture_size ); } if( cols != width || rows != height ) { raw = GL_ResampleTexture( data, cols, rows, width, height, false ); cols = width; rows = height; } else { raw = (byte *)data; } if( cols > glConfig.max_2d_texture_size ) Host_Error( "R_UploadStretchRaw: size %i exceeds hardware limits\n", cols ); if( rows > glConfig.max_2d_texture_size ) Host_Error( "R_UploadStretchRaw: size %i exceeds hardware limits\n", rows ); tex = R_GetTexture( texture ); GL_Bind( GL_TEXTURE0, texture ); tex->width = cols; tex->height = rows; pglTexImage2D( GL_TEXTURE_2D, 0, tex->format, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw ); GL_TexFilter( tex, false ); }
/* ================= R_Bloom_InitEffectTexture ================= */ static void R_Bloom_InitEffectTexture( void ) { int limit; if( r_bloom_sample_size->value < 32.0f ) CVAR_SET_FLOAT( "r_bloom_sample_size", 32.0f ); // make sure bloom size doesn't have stupid values limit = min( r_bloom_sample_size->value, min( screen_texture_width, screen_texture_height )); if( GL_Support( R_ARB_TEXTURE_NPOT_EXT )) { BLOOM_SIZE = limit; } else { // make sure bloom size is a power of 2 for( BLOOM_SIZE = 32; (BLOOM_SIZE<<1) <= limit; BLOOM_SIZE <<= 1 ); } if( BLOOM_SIZE != r_bloom_sample_size->value ) CVAR_SET_FLOAT( "r_bloom_sample_size", BLOOM_SIZE ); r_bloomeffecttexture = CREATE_TEXTURE( "*bloomeffecttexture", BLOOM_SIZE, BLOOM_SIZE, NULL, TF_IMAGE ); }
void GL_InitExtensions( void ) { // initialize gl extensions GL_CheckExtension( "OpenGL 1.1.0", opengl_110funcs, NULL, GL_OPENGL_110 ); // get our various GL strings glConfig.vendor_string = pglGetString( GL_VENDOR ); glConfig.renderer_string = pglGetString( GL_RENDERER ); glConfig.version_string = pglGetString( GL_VERSION ); glConfig.extensions_string = pglGetString( GL_EXTENSIONS ); MsgDev( D_INFO, "Video: %s\n", glConfig.renderer_string ); // initalize until base opengl functions loaded GL_CheckExtension( "glDrawRangeElements", drawrangeelementsfuncs, "gl_drawrangeelments", GL_DRAW_RANGEELEMENTS_EXT ); if( !GL_Support( GL_DRAW_RANGEELEMENTS_EXT )) GL_CheckExtension( "GL_EXT_draw_range_elements", drawrangeelementsextfuncs, "gl_drawrangeelments", GL_DRAW_RANGEELEMENTS_EXT ); // multitexture glConfig.max_texture_units = glConfig.max_texture_coords = glConfig.max_teximage_units = 1; GL_CheckExtension( "GL_ARB_multitexture", multitexturefuncs, "gl_arb_multitexture", GL_ARB_MULTITEXTURE ); if( GL_Support( GL_ARB_MULTITEXTURE )) { pglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glConfig.max_texture_units ); GL_CheckExtension( "GL_ARB_texture_env_combine", NULL, "gl_texture_env_combine", GL_ENV_COMBINE_EXT ); if( !GL_Support( GL_ENV_COMBINE_EXT )) GL_CheckExtension( "GL_EXT_texture_env_combine", NULL, "gl_texture_env_combine", GL_ENV_COMBINE_EXT ); if( GL_Support( GL_ENV_COMBINE_EXT )) GL_CheckExtension( "GL_ARB_texture_env_dot3", NULL, "gl_texture_env_dot3", GL_DOT3_ARB_EXT ); } else { GL_CheckExtension( "GL_SGIS_multitexture", sgis_multitexturefuncs, "gl_sgis_multitexture", GL_ARB_MULTITEXTURE ); if( GL_Support( GL_ARB_MULTITEXTURE )) glConfig.max_texture_units = 2; } if( glConfig.max_texture_units == 1 ) GL_SetExtension( GL_ARB_MULTITEXTURE, false ); // 3d texture support GL_CheckExtension( "GL_EXT_texture3D", texture3dextfuncs, "gl_texture_3d", GL_TEXTURE_3D_EXT ); if( GL_Support( GL_TEXTURE_3D_EXT )) { pglGetIntegerv( GL_MAX_3D_TEXTURE_SIZE, &glConfig.max_3d_texture_size ); if( glConfig.max_3d_texture_size < 32 ) { GL_SetExtension( GL_TEXTURE_3D_EXT, false ); MsgDev( D_ERROR, "GL_EXT_texture3D reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n" ); } } GL_CheckExtension( "GL_SGIS_generate_mipmap", NULL, "gl_sgis_generate_mipmaps", GL_SGIS_MIPMAPS_EXT ); // hardware cubemaps GL_CheckExtension( "GL_ARB_texture_cube_map", NULL, "gl_texture_cubemap", GL_TEXTURECUBEMAP_EXT ); if( GL_Support( GL_TEXTURECUBEMAP_EXT )) { pglGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig.max_cubemap_size ); // check for seamless cubemaps too GL_CheckExtension( "GL_ARB_seamless_cube_map", NULL, "gl_seamless_cubemap", GL_ARB_SEAMLESS_CUBEMAP ); } // point particles extension GL_CheckExtension( "GL_EXT_point_parameters", pointparametersfunc, NULL, GL_EXT_POINTPARAMETERS ); GL_CheckExtension( "GL_ARB_texture_non_power_of_two", NULL, "gl_texture_npot", GL_ARB_TEXTURE_NPOT_EXT ); GL_CheckExtension( "GL_ARB_texture_compression", texturecompressionfuncs, "gl_dds_hardware_support", GL_TEXTURE_COMPRESSION_EXT ); GL_CheckExtension( "GL_EXT_compiled_vertex_array", compiledvertexarrayfuncs, "gl_cva_support", GL_CUSTOM_VERTEX_ARRAY_EXT ); if( !GL_Support( GL_CUSTOM_VERTEX_ARRAY_EXT )) GL_CheckExtension( "GL_SGI_compiled_vertex_array", compiledvertexarrayfuncs, "gl_cva_support", GL_CUSTOM_VERTEX_ARRAY_EXT ); GL_CheckExtension( "GL_EXT_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT ); if( !GL_Support( GL_CLAMPTOEDGE_EXT )) GL_CheckExtension("GL_SGIS_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT ); glConfig.max_texture_anisotropy = 0.0f; GL_CheckExtension( "GL_EXT_texture_filter_anisotropic", NULL, "gl_ext_anisotropic_filter", GL_ANISOTROPY_EXT ); if( GL_Support( GL_ANISOTROPY_EXT )) pglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.max_texture_anisotropy ); GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, "gl_ext_texture_lodbias", GL_TEXTURE_LODBIAS ); if( GL_Support( GL_TEXTURE_LODBIAS )) pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lodbias ); GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, "gl_ext_texborder_clamp", GL_CLAMP_TEXBORDER_EXT ); GL_CheckExtension( "GL_EXT_blend_minmax", blendequationfuncs, "gl_ext_customblend", GL_BLEND_MINMAX_EXT ); GL_CheckExtension( "GL_EXT_blend_subtract", blendequationfuncs, "gl_ext_customblend", GL_BLEND_SUBTRACT_EXT ); GL_CheckExtension( "glStencilOpSeparate", gl2separatestencilfuncs, "gl_separate_stencil", GL_SEPARATESTENCIL_EXT ); if( !GL_Support( GL_SEPARATESTENCIL_EXT )) GL_CheckExtension("GL_ATI_separate_stencil", atiseparatestencilfuncs, "gl_separate_stencil", GL_SEPARATESTENCIL_EXT ); GL_CheckExtension( "GL_EXT_stencil_two_side", stenciltwosidefuncs, "gl_stenciltwoside", GL_STENCILTWOSIDE_EXT ); GL_CheckExtension( "GL_ARB_vertex_buffer_object", vbofuncs, "gl_vertex_buffer_object", GL_ARB_VERTEX_BUFFER_OBJECT_EXT ); // we don't care if it's an extension or not, they are identical functions, so keep it simple in the rendering code #ifndef __ANDROID__ if( pglDrawRangeElementsEXT == NULL ) pglDrawRangeElementsEXT = pglDrawRangeElements; #endif GL_CheckExtension( "GL_ARB_texture_env_add", NULL, "gl_texture_env_add", GL_TEXTURE_ENV_ADD_EXT ); // vp and fp shaders GL_CheckExtension( "GL_ARB_shader_objects", shaderobjectsfuncs, "gl_shaderobjects", GL_SHADER_OBJECTS_EXT ); GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_glslprogram", GL_SHADER_GLSL100_EXT ); GL_CheckExtension( "GL_ARB_vertex_shader", vertexshaderfuncs, "gl_vertexshader", GL_VERTEX_SHADER_EXT ); GL_CheckExtension( "GL_ARB_fragment_shader", NULL, "gl_pixelshader", GL_FRAGMENT_SHADER_EXT ); GL_CheckExtension( "GL_ARB_depth_texture", NULL, "gl_depthtexture", GL_DEPTH_TEXTURE ); GL_CheckExtension( "GL_ARB_shadow", NULL, "gl_arb_shadow", GL_SHADOW_EXT ); GL_CheckExtension( "GL_ARB_texture_float", NULL, "gl_arb_texture_float", GL_ARB_TEXTURE_FLOAT_EXT ); GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_arb_depth_float", GL_ARB_DEPTH_FLOAT_EXT ); // occlusion queries GL_CheckExtension( "GL_ARB_occlusion_query", occlusionfunc, "gl_occlusion_queries", GL_OCCLUSION_QUERIES_EXT ); if( GL_Support( GL_SHADER_GLSL100_EXT )) { pglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &glConfig.max_texture_coords ); pglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &glConfig.max_teximage_units ); } else { // just get from multitexturing glConfig.max_texture_coords = glConfig.max_teximage_units = glConfig.max_texture_units; } // rectangle textures support if( Q_strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" )) { glConfig.texRectangle = GL_TEXTURE_RECTANGLE_NV; pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, &glConfig.max_2d_rectangle_size ); } #ifndef __ANDROID__ else if( Q_strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" )) { glConfig.texRectangle = GL_TEXTURE_RECTANGLE_EXT; pglGetIntegerv( GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT, &glConfig.max_2d_rectangle_size ); } #endif else glConfig.texRectangle = glConfig.max_2d_rectangle_size = 0; // no rectangle glConfig.max_2d_texture_size = 0; pglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.max_2d_texture_size ); if( glConfig.max_2d_texture_size <= 0 ) glConfig.max_2d_texture_size = 256; Cvar_Get( "gl_max_texture_size", "0", CVAR_INIT, "opengl texture max dims" ); Cvar_Set( "gl_max_texture_size", va( "%i", glConfig.max_2d_texture_size )); pglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.max_vertex_uniforms ); pglGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.max_vertex_attribs ); // MCD has buffering issues if(Q_strstr( glConfig.renderer_string, "gdi" )) Cvar_SetFloat( "gl_finish", 1 ); Cvar_Set( "gl_anisotropy", va( "%f", bound( 0, gl_texture_anisotropy->value, glConfig.max_texture_anisotropy ))); // software mipmap generator does wrong result with NPOT textures ... if( !GL_Support( GL_SGIS_MIPMAPS_EXT )) GL_SetExtension( GL_ARB_TEXTURE_NPOT_EXT, false ); if( GL_Support( GL_TEXTURE_COMPRESSION_EXT )) Image_AddCmdFlags( IL_DDS_HARDWARE ); glw_state.initialized = true; tr.framecount = tr.visframecount = 1; }
/* ============= R_DrawStretchRaw ============= */ void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty ) { byte *raw = NULL; gltexture_t *tex; if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) { int width = 1, height = 1; // check the dimensions width = NearestPOW( cols, true ); height = NearestPOW( rows, false ); if( cols != width || rows != height ) { raw = GL_ResampleTexture( data, cols, rows, width, height, false ); cols = width; rows = height; } } else { raw = (byte *)data; } if( cols > glConfig.max_2d_texture_size ) Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", cols ); if( rows > glConfig.max_2d_texture_size ) Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", rows ); pglDisable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); tex = R_GetTexture( tr.cinTexture ); GL_Bind( GL_TEXTURE0, tr.cinTexture ); if( cols == tex->width && rows == tex->height ) { if( dirty ) { pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_BGRA, GL_UNSIGNED_BYTE, raw ); } } else { tex->width = cols; tex->height = rows; if( dirty ) { pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw ); } } pglBegin( GL_QUADS ); pglTexCoord2f( 0, 0 ); pglVertex2f( x, y ); pglTexCoord2f( 1, 0 ); pglVertex2f( x + w, y ); pglTexCoord2f( 1, 1 ); pglVertex2f( x + w, y + h ); pglTexCoord2f( 0, 1 ); pglVertex2f( x, y + h ); pglEnd(); }
/* ================ R_DrawMirrors Draw all viewpasess from mirror position Mirror textures will be drawn in normal pass ================ */ void R_DrawMirrors( void ) { ref_instance_t oldRI; mplane_t plane; msurface_t *surf, *surf2; int i, oldframecount; mextrasurf_t *es, *tmp, *mirrorchain; vec3_t forward, right, up; vec3_t origin, angles; matrix4x4 mirrormatrix; cl_entity_t *e; model_t *m; float d; if( !tr.num_mirror_entities ) return; // mo mirrors for this frame oldRI = RI; // make refinst backup oldframecount = tr.framecount; for( i = 0; i < tr.num_mirror_entities; i++ ) { mirrorchain = tr.mirror_entities[i].chain; for( es = mirrorchain; es != NULL; es = es->mirrorchain ) { RI.currententity = e = tr.mirror_entities[i].ent; RI.currentmodel = m = RI.currententity->model; surf = INFO_SURF( es, m ); ASSERT( RI.currententity != NULL ); ASSERT( RI.currentmodel != NULL ); // NOTE: copy mirrortexture and mirrormatrix from another surfaces // from this entity\world that has same planes and reduce number of viewpasses // make sure what we have one pass at least if( es != mirrorchain ) { for( tmp = mirrorchain; tmp != es; tmp = tmp->mirrorchain ) { surf2 = INFO_SURF( tmp, m ); if( !tmp->mirrortexturenum ) continue; // not filled? if( surf->plane->dist != surf2->plane->dist ) continue; if( !VectorCompare( surf->plane->normal, surf2->plane->normal )) continue; // found surface with same plane! break; } if( tmp != es && tmp && tmp->mirrortexturenum ) { // just copy reflection texture from surface with same plane Matrix4x4_Copy( es->mirrormatrix, tmp->mirrormatrix ); es->mirrortexturenum = tmp->mirrortexturenum; continue; // pass skiped } } R_PlaneForMirror( surf, &plane, mirrormatrix ); d = -2.0f * ( DotProduct( RI.vieworg, plane.normal ) - plane.dist ); VectorMA( RI.vieworg, d, plane.normal, origin ); d = -2.0f * DotProduct( RI.vforward, plane.normal ); VectorMA( RI.vforward, d, plane.normal, forward ); VectorNormalize( forward ); d = -2.0f * DotProduct( RI.vright, plane.normal ); VectorMA( RI.vright, d, plane.normal, right ); VectorNormalize( right ); d = -2.0f * DotProduct( RI.vup, plane.normal ); VectorMA( RI.vup, d, plane.normal, up ); VectorNormalize( up ); VectorsAngles( forward, right, up, angles ); angles[ROLL] = -angles[ROLL]; RI.params = RP_MIRRORVIEW|RP_CLIPPLANE|RP_OLDVIEWLEAF; RI.clipPlane = plane; RI.clipFlags |= ( 1<<5 ); RI.frustum[5] = plane; RI.frustum[5].signbits = SignbitsForPlane( RI.frustum[5].normal ); RI.frustum[5].type = PLANE_NONAXIAL; RI.refdef.viewangles[0] = anglemod( angles[0] ); RI.refdef.viewangles[1] = anglemod( angles[1] ); RI.refdef.viewangles[2] = anglemod( angles[2] ); VectorCopy( origin, RI.refdef.vieworg ); VectorCopy( origin, RI.cullorigin ); // put pvsorigin before the mirror plane to avoid get full visibility on world mirrors if( RI.currententity == clgame.entities ) { VectorMA( es->origin, 1.0f, plane.normal, origin ); } else { Matrix4x4_VectorTransform( mirrormatrix, es->origin, origin ); VectorMA( origin, 1.0f, plane.normal, origin ); } VectorCopy( origin, RI.pvsorigin ); // combine two leafs from client and mirror views r_viewleaf = Mod_PointInLeaf( oldRI.pvsorigin, cl.worldmodel->nodes ); r_viewleaf2 = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes ); if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) { // allow screen size RI.viewport[2] = bound( 96, RI.viewport[2], 1024 ); RI.viewport[3] = bound( 72, RI.viewport[3], 768 ); } else { RI.viewport[2] = NearestPOW( RI.viewport[2], true ); RI.viewport[3] = NearestPOW( RI.viewport[3], true ); RI.viewport[2] = bound( 128, RI.viewport[2], 1024 ); RI.viewport[3] = bound( 64, RI.viewport[3], 512 ); } tr.framecount++; R_RenderScene( &RI.refdef ); r_stats.c_mirror_passes++; es->mirrortexturenum = R_AllocateMirrorTexture(); // create personal projection matrix for mirror if( VectorIsNull( e->origin ) && VectorIsNull( e->angles )) { Matrix4x4_Copy( es->mirrormatrix, RI.worldviewProjectionMatrix ); } else { Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, mirrormatrix ); Matrix4x4_Concat( es->mirrormatrix, RI.projectionMatrix, RI.modelviewMatrix ); } RI = oldRI; // restore ref instance } // clear chain for this entity for( es = mirrorchain; es != NULL; ) { tmp = es->mirrorchain; es->mirrorchain = NULL; es = tmp; } tr.mirror_entities[i].chain = NULL; // done tr.mirror_entities[i].ent = NULL; } r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame tr.framecount = oldframecount; // restore real framecount tr.num_mirror_entities = 0; tr.num_mirrors_used = 0; }
void GL_InitExtensions( void ) { // initialize gl extensions GL_CheckExtension( "OpenGL 1.1.0", opengl_110funcs, NULL, GL_OPENGL_110 ); // get our various GL strings glConfig.vendor_string = pglGetString( GL_VENDOR ); glConfig.renderer_string = pglGetString( GL_RENDERER ); glConfig.version_string = pglGetString( GL_VERSION ); glConfig.extensions_string = pglGetString( GL_EXTENSIONS ); MsgDev( D_INFO, "Video: %s\n", glConfig.renderer_string ); // initalize until base opengl functions loaded GL_SetExtension( GL_DRAW_RANGEELEMENTS_EXT, false ); GL_SetExtension( GL_ARB_MULTITEXTURE, false ); GL_SetExtension( GL_ENV_COMBINE_EXT, false ); GL_SetExtension( GL_DOT3_ARB_EXT, false ); GL_SetExtension( GL_TEXTURE_3D_EXT, false ); GL_SetExtension( GL_SGIS_MIPMAPS_EXT, true ); // gles specs // hardware cubemaps GL_CheckExtension( "GL_OES_texture_cube_map", NULL, "gl_texture_cubemap", GL_TEXTURECUBEMAP_EXT ); if( GL_Support( GL_TEXTURECUBEMAP_EXT )) { pglGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig.max_cubemap_size ); } GL_SetExtension( GL_ARB_SEAMLESS_CUBEMAP, false ); GL_SetExtension( GL_EXT_POINTPARAMETERS, false ); GL_CheckExtension( "GL_OES_texture_npot", NULL, "gl_texture_npot", GL_ARB_TEXTURE_NPOT_EXT ); GL_SetExtension( GL_TEXTURE_COMPRESSION_EXT, false ); GL_SetExtension( GL_CUSTOM_VERTEX_ARRAY_EXT, false ); GL_SetExtension( GL_CLAMPTOEDGE_EXT, true ); // by gles1 specs GL_SetExtension( GL_ANISOTROPY_EXT, false ); GL_SetExtension( GL_TEXTURE_LODBIAS, false ); GL_SetExtension( GL_CLAMP_TEXBORDER_EXT, false ); GL_SetExtension( GL_BLEND_MINMAX_EXT, false ); GL_SetExtension( GL_BLEND_SUBTRACT_EXT, false ); GL_SetExtension( GL_SEPARATESTENCIL_EXT, false ); GL_SetExtension( GL_STENCILTWOSIDE_EXT, false ); GL_SetExtension( GL_ARB_VERTEX_BUFFER_OBJECT_EXT, false ); GL_SetExtension( GL_TEXTURE_ENV_ADD_EXT,false ); GL_SetExtension( GL_SHADER_OBJECTS_EXT, false ); GL_SetExtension( GL_SHADER_GLSL100_EXT, false ); GL_SetExtension( GL_VERTEX_SHADER_EXT,false ); GL_SetExtension( GL_FRAGMENT_SHADER_EXT, false ); GL_SetExtension( GL_SHADOW_EXT, false ); GL_SetExtension( GL_ARB_DEPTH_FLOAT_EXT, false ); GL_SetExtension( GL_OCCLUSION_QUERIES_EXT,false ); GL_CheckExtension( "GL_OES_depth_texture", NULL, "gl_depthtexture", GL_DEPTH_TEXTURE ); glConfig.texRectangle = glConfig.max_2d_rectangle_size = 0; // no rectangle glConfig.max_2d_texture_size = 0; pglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.max_2d_texture_size ); if( glConfig.max_2d_texture_size <= 0 ) glConfig.max_2d_texture_size = 256; Cvar_Get( "gl_max_texture_size", "0", CVAR_INIT, "opengl texture max dims" ); Cvar_Set( "gl_max_texture_size", va( "%i", glConfig.max_2d_texture_size )); pglGetIntegerv( GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig.max_vertex_uniforms ); pglGetIntegerv( GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig.max_vertex_attribs ); // MCD has buffering issues if(Q_strstr( glConfig.renderer_string, "gdi" )) Cvar_SetFloat( "gl_finish", 1 ); Cvar_Set( "gl_anisotropy", va( "%f", bound( 0, gl_texture_anisotropy->value, glConfig.max_texture_anisotropy ))); // software mipmap generator does wrong result with NPOT textures ... if( !GL_Support( GL_SGIS_MIPMAPS_EXT )) GL_SetExtension( GL_ARB_TEXTURE_NPOT_EXT, false ); if( GL_Support( GL_TEXTURE_COMPRESSION_EXT )) Image_AddCmdFlags( IL_DDS_HARDWARE ); glw_state.initialized = true; tr.framecount = tr.visframecount = 1; }
/* ================== R_NewMap Called always when map is changed or restarted ================== */ void R_NewMap( void ) { int i; // get the actual screen size glState.width = RENDER_GET_PARM( PARM_SCREEN_WIDTH, 0 ); glState.height = RENDER_GET_PARM( PARM_SCREEN_HEIGHT, 0 ); // release old mirror textures for( i = 0; i < MAX_MIRRORS; i++ ) { if( !tr.mirrorTextures[i] ) break; FREE_TEXTURE( tr.mirrorTextures[i] ); } for( i = 0; i < MAX_MIRRORS; i++ ) { if( !tr.portalTextures[i] ) break; FREE_TEXTURE( tr.portalTextures[i] ); } for( i = 0; i < MAX_MIRRORS; i++ ) { if( !tr.screenTextures[i] ) break; FREE_TEXTURE( tr.screenTextures[i] ); } for( i = 0; i < MAX_SHADOWS; i++ ) { if( !tr.shadowTextures[i] ) break; FREE_TEXTURE( tr.shadowTextures[i] ); } for( i = 0; i < tr.num_framebuffers; i++ ) { if( !tr.frame_buffers[i].init ) break; R_FreeFrameBuffer( i ); } CL_ClearPlights(); R_FreeCinematics(); // free old cinematics memset( tr.mirrorTextures, 0, sizeof( tr.mirrorTextures )); memset( tr.portalTextures, 0, sizeof( tr.portalTextures )); memset( tr.screenTextures, 0, sizeof( tr.screenTextures )); memset( tr.shadowTextures, 0, sizeof( tr.shadowTextures )); memset( tr.frame_buffers, 0, sizeof( tr.frame_buffers )); tr.num_framebuffers = 0; r_viewleaf = r_viewleaf2 = NULL; tr.framecount = tr.visframecount = 1; // no dlight cache if( GL_Support( R_FRAMEBUFFER_OBJECT )) { // allocate FBO's tr.fbo[FBO_MIRRORS] = R_AllocFrameBuffer(); tr.fbo[FBO_SCREENS] = R_AllocFrameBuffer(); tr.fbo[FBO_PORTALS] = R_AllocFrameBuffer(); } // setup the skybox sides for( i = 0; i < 6; i++ ) tr.skyboxTextures[i] = RENDER_GET_PARM( PARM_TEX_SKYBOX, i ); tr.skytexturenum = RENDER_GET_PARM( PARM_TEX_SKYTEXNUM, 0 ); // not a gl_texturenum! v_intermission_spot = NULL; R_InitCinematics(); R_InitBloomTextures(); if( Q_stricmp( worldmodel->name, tr.worldname )) { Q_strncpy( tr.worldname, worldmodel->name, sizeof( tr.worldname )); R_ParseGrassFile(); } }