From: havoc Date: Mon, 15 Oct 2007 12:07:28 +0000 (+0000) Subject: implemented MATERIALFLAG_REFRACTION X-Git-Tag: xonotic-v0.1.0preview~2846 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=commitdiff_plain;h=fa51486e1120ae0e01f9bc83db6021ac3ad5ce0b implemented MATERIALFLAG_REFRACTION changed syntax of dp_refract, dp_reflect, added dp_water moved SHADERPERMUTATION and friends to gl_rmain.c eliminated SHADERPERMUTATION_MASK by separating out SHADERTYPE_USES other cleanup git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7634 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/gl_rmain.c b/gl_rmain.c index e7e47502..8b0aec62 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -188,11 +188,6 @@ rtexture_t *r_texture_normalizationcube; rtexture_t *r_texture_fogattenuation; //rtexture_t *r_texture_fogintensity; -// information about each possible shader permutation -r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_MAX]; -// currently selected permutation -r_glsl_permutation_t *r_glsl_permutation; - char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH]; skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD]; @@ -452,8 +447,12 @@ static const char *builtinshaderstring = "//#ifdef USEWATER\n" "varying vec4 ModelViewProjectionPosition;\n" "//#else\n" -"//# ifdef USEREFLECTION\n" +"//# ifdef USEREFRACTION\n" +"//varying vec4 ModelViewProjectionPosition;\n" +"//# else\n" +"//# ifdef USEREFLECTION\n" "//varying vec4 ModelViewProjectionPosition;\n" +"//# endif\n" "//# endif\n" "//#endif\n" "\n" @@ -529,8 +528,12 @@ static const char *builtinshaderstring = "#ifdef USEWATER\n" " ModelViewProjectionPosition = gl_Position;\n" "#else\n" -"# ifdef USEREFLECTION\n" +"# ifdef USEWATER\n" +" ModelViewProjectionPosition = gl_Position;\n" +"# else\n" +"# ifdef USEREFLECTION\n" " ModelViewProjectionPosition = gl_Position;\n" +"# endif\n" "# endif\n" "#endif\n" "}\n" @@ -570,8 +573,8 @@ static const char *builtinshaderstring = "uniform vec4 DistortScaleRefractReflect;\n" "uniform vec4 ScreenScaleRefractReflect;\n" "uniform vec4 ScreenCenterRefractReflect;\n" -"uniform myhvec3 RefractColor;\n" -"uniform myhvec3 ReflectColor;\n" +"uniform myhvec4 RefractColor;\n" +"uniform myhvec4 ReflectColor;\n" "uniform myhalf ReflectFactor;\n" "uniform myhalf ReflectOffset;\n" "//#else\n" @@ -776,20 +779,28 @@ static const char *builtinshaderstring = "# ifdef USEWATER\n" " color.rgb *= color.a;\n" "# endif\n" +"# ifdef USEREFRACTION\n" +" color.rgb *= color.a;\n" +"# endif\n" "#else\n" "# ifdef USEWATER\n" " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n" " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n" " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n" " myhalf Fresnel = myhalf(pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0)) * ReflectFactor + ReflectOffset;\n" -" color.rgb = mix(mix(myhvec3(texture2D(Texture_Refraction, ScreenTexCoord.xy)) * RefractColor, myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor, Fresnel), color.rgb, color.a);\n" -"# else\n" -"# ifdef USEREFLECTION\n" +" color.rgb = mix(mix(myhvec3(texture2D(Texture_Refraction, ScreenTexCoord.xy)) * RefractColor.rgb, myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, Fresnel), color.rgb, color.a);\n" +"# endif\n" +"# ifdef USEREFRACTION\n" " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n" " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n" " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n" -" color.rgb += myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor;\n" -"# endif\n" +" color.rgb = mix(myhvec3(texture2D(Texture_Refraction, ScreenTexCoord.xy)) * RefractColor.rgb, color.rgb, color.a);\n" +"# endif\n" +"# ifdef USEREFLECTION\n" +" vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n" +" //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n" +" vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n" +" color.rgb = mix(color.rgb, myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, ReflectColor.a);\n" "# endif\n" "#endif\n" "\n" @@ -814,6 +825,27 @@ static const char *builtinshaderstring = "#endif // FRAGMENT_SHADER\n" ; +#define SHADERPERMUTATION_MODE_LIGHTMAP (1<<0) // (lightmap) use directional pixel shading from fixed light direction (q3bsp) +#define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE (1<<1) // (lightmap) use directional pixel shading from texture containing modelspace light directions (deluxemap) +#define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE (1<<2) // (lightmap) use directional pixel shading from texture containing tangentspace light directions (deluxemap) +#define SHADERPERMUTATION_MODE_LIGHTDIRECTION (1<<3) // (lightmap) use directional pixel shading from fixed light direction (q3bsp) +#define SHADERPERMUTATION_MODE_LIGHTSOURCE (1<<4) // (lightsource) use directional pixel shading from light source (rtlight) +#define SHADERPERMUTATION_WATER (1<<5) // normalmap-perturbed refraction of the background, performed behind the surface (the texture or material must be transparent to see it) +#define SHADERPERMUTATION_REFRACTION (1<<6) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface +#define SHADERPERMUTATION_REFLECTION (1<<7) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface +#define SHADERPERMUTATION_GLOW (1<<8) // (lightmap) blend in an additive glow texture +#define SHADERPERMUTATION_FOG (1<<9) // tint the color by fog color or black if using additive blend mode +#define SHADERPERMUTATION_COLORMAPPING (1<<10) // indicates this is a colormapped skin +#define SHADERPERMUTATION_DIFFUSE (1<<11) // (lightsource) whether to use directional shading +#define SHADERPERMUTATION_CONTRASTBOOST (1<<12) // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma) +#define SHADERPERMUTATION_SPECULAR (1<<13) // (lightsource or deluxemapping) render specular effects +#define SHADERPERMUTATION_CUBEFILTER (1<<14) // (lightsource) use cubemap light filter +#define SHADERPERMUTATION_OFFSETMAPPING (1<<15) // adjust texcoords to roughly simulate a displacement mapped surface +#define SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING (1<<16) // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!) + +#define SHADERPERMUTATION_INDICES (1<<17) // how many permutations are possible +#define SHADERPERMUTATION_MASK (SHADERPERMUTATION_INDICES - 1) // mask of valid indexing bits for r_glsl_permutations[] array + // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES! const char *permutationinfo[][2] = { @@ -823,6 +855,7 @@ const char *permutationinfo[][2] = {"#define MODE_LIGHTDIRECTION\n", " lightdirection"}, {"#define MODE_LIGHTSOURCE\n", " lightsource"}, {"#define USEWATER\n", " water"}, + {"#define USEREFRACTION\n", " refraction"}, {"#define USEREFLECTION\n", " reflection"}, {"#define USEGLOW\n", " glow"}, {"#define USEFOG\n", " fog"}, @@ -836,11 +869,70 @@ const char *permutationinfo[][2] = {NULL, NULL} }; -void R_GLSL_CompilePermutation(const char *filename, int permutation) +typedef struct r_glsl_permutation_s +{ + // indicates if we have tried compiling this permutation already + qboolean compiled; + // 0 if compilation failed + int program; + // locations of detected uniforms in program object, or -1 if not found + int loc_Texture_Normal; + int loc_Texture_Color; + int loc_Texture_Gloss; + int loc_Texture_Cube; + int loc_Texture_Attenuation; + int loc_Texture_FogMask; + int loc_Texture_Pants; + int loc_Texture_Shirt; + int loc_Texture_Lightmap; + int loc_Texture_Deluxemap; + int loc_Texture_Glow; + int loc_Texture_Refraction; + int loc_Texture_Reflection; + int loc_FogColor; + int loc_LightPosition; + int loc_EyePosition; + int loc_LightColor; + int loc_Color_Pants; + int loc_Color_Shirt; + int loc_FogRangeRecip; + int loc_AmbientScale; + int loc_DiffuseScale; + int loc_SpecularScale; + int loc_SpecularPower; + int loc_GlowScale; + int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost + int loc_OffsetMapping_Scale; + int loc_AmbientColor; + int loc_DiffuseColor; + int loc_SpecularColor; + int loc_LightDir; + int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost + int loc_DistortScaleRefractReflect; + int loc_ScreenScaleRefractReflect; + int loc_ScreenCenterRefractReflect; + int loc_RefractColor; + int loc_ReflectColor; + int loc_ReflectFactor; + int loc_ReflectOffset; +} +r_glsl_permutation_t; + +// information about each possible shader permutation +r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_INDICES]; +// currently selected permutation +r_glsl_permutation_t *r_glsl_permutation; + +// these are additional flags used only by R_GLSL_CompilePermutation +#define SHADERTYPE_USES_VERTEXSHADER (1<<0) +#define SHADERTYPE_USES_GEOMETRYSHADER (1<<1) +#define SHADERTYPE_USES_FRAGMENTSHADER (1<<2) + +static void R_GLSL_CompilePermutation(const char *filename, int permutation, int shadertype) { int i; qboolean shaderfound; - r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK); + r_glsl_permutation_t *p = r_glsl_permutations + permutation; int vertstrings_count; int geomstrings_count; int fragstrings_count; @@ -881,7 +973,7 @@ void R_GLSL_CompilePermutation(const char *filename, int permutation) shaderfound = false; if (shaderstring) { - Con_DPrintf("GLSL shader text for \"%s\" loaded from disk\n", filename); + Con_DPrint("from disk... "); vertstrings_list[vertstrings_count++] = shaderstring; geomstrings_list[geomstrings_count++] = shaderstring; fragstrings_list[fragstrings_count++] = shaderstring; @@ -889,18 +981,17 @@ void R_GLSL_CompilePermutation(const char *filename, int permutation) } else if (!strcmp(filename, "glsl/default.glsl")) { - Con_DPrintf("GLSL shader text for \"%s\" loaded from engine\n", filename); vertstrings_list[vertstrings_count++] = builtinshaderstring; geomstrings_list[geomstrings_count++] = builtinshaderstring; fragstrings_list[fragstrings_count++] = builtinshaderstring; shaderfound = true; } // clear any lists that are not needed by this shader - if (!(permutation & SHADERPERMUTATION_USES_VERTEXSHADER)) + if (!(shadertype & SHADERTYPE_USES_VERTEXSHADER)) vertstrings_count = 0; - if (!(permutation & SHADERPERMUTATION_USES_GEOMETRYSHADER)) + if (!(shadertype & SHADERTYPE_USES_GEOMETRYSHADER)) geomstrings_count = 0; - if (!(permutation & SHADERPERMUTATION_USES_FRAGMENTSHADER)) + if (!(shadertype & SHADERTYPE_USES_FRAGMENTSHADER)) fragstrings_count = 0; // compile the shader program if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count) @@ -966,9 +1057,16 @@ void R_GLSL_CompilePermutation(const char *filename, int permutation) if (p->loc_Texture_Reflection >= 0) qglUniform1iARB(p->loc_Texture_Reflection, 12); CHECKGLERROR qglUseProgramObjectARB(0);CHECKGLERROR + if (developer.integer) + Con_Printf("GLSL shader %s :%s compiled.\n", filename, permutationname); } else - Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, filename); + { + if (developer.integer) + Con_Printf("GLSL shader %s :%s failed! source code line offset for above errors is %i.\n", permutationname, filename, -(vertstrings_count - 1)); + else + Con_Printf("GLSL shader %s :%s failed! some features may not work properly.\n", permutationname, filename); + } if (shaderstring) Mem_Free(shaderstring); } @@ -976,7 +1074,7 @@ void R_GLSL_CompilePermutation(const char *filename, int permutation) void R_GLSL_Restart_f(void) { int i; - for (i = 0;i < SHADERPERMUTATION_MAX;i++) + for (i = 0;i < SHADERPERMUTATION_INDICES;i++) if (r_glsl_permutations[i].program) GL_Backend_FreeProgram(r_glsl_permutations[i].program); memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations)); @@ -1015,14 +1113,16 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl // fragment shader on features that are not being used const char *shaderfilename = NULL; unsigned int permutation = 0; + unsigned int shadertype = 0; rtexture_t *nmap; r_glsl_permutation = NULL; + shaderfilename = "glsl/default.glsl"; + shadertype = SHADERTYPE_USES_VERTEXSHADER | SHADERTYPE_USES_FRAGMENTSHADER; // TODO: implement geometry-shader based shadow volumes someday if (rsurface.rtlight) { // light source - shaderfilename = "glsl/default.glsl"; - permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE | SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; + permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE; if (rsurface.rtlight->currentcubemap != r_texture_whitecube) permutation |= SHADERPERMUTATION_CUBEFILTER; if (diffusescale > 0) @@ -1049,8 +1149,6 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) { // bright unshaded geometry - shaderfilename = "glsl/default.glsl"; - permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; permutation |= SHADERPERMUTATION_MODE_LIGHTMAP; if (rsurface.texture->currentskinframe->glow) permutation |= SHADERPERMUTATION_GLOW; @@ -1074,8 +1172,6 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl else if (modellighting) { // directional model lighting - shaderfilename = "glsl/default.glsl"; - permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION; if (rsurface.texture->currentskinframe->glow) permutation |= SHADERPERMUTATION_GLOW; @@ -1101,8 +1197,6 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl else { // lightmapped wall - shaderfilename = "glsl/default.glsl"; - permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping) { // deluxemapping (light direction texture) @@ -1144,15 +1238,15 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) permutation |= SHADERPERMUTATION_REFLECTION; } - if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program) + if (!r_glsl_permutations[permutation].program) { - if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled) - R_GLSL_CompilePermutation(shaderfilename, permutation); - if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program) + if (!r_glsl_permutations[permutation].compiled) + R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype); + if (!r_glsl_permutations[permutation].program) { // remove features until we find a valid permutation unsigned int i; - for (i = (SHADERPERMUTATION_MAX >> 1);;i>>=1) + for (i = (SHADERPERMUTATION_INDICES >> 1);;i>>=1) { if (!i) { @@ -1164,14 +1258,14 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl if (!(permutation & i)) continue; permutation &= ~i; - if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled) - R_GLSL_CompilePermutation(shaderfilename, permutation); - if (r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program) + if (!r_glsl_permutations[permutation].compiled) + R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype); + if (r_glsl_permutations[permutation].program) break; } } } - r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK); + r_glsl_permutation = r_glsl_permutations + permutation; CHECKGLERROR qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix); @@ -1218,7 +1312,7 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(nmap)); if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture)); if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture)); - //if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); + //if (r_glsl_permutation->loc_Texture_Cube >= 0 && rsurface.rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap)); if (r_glsl_permutation->loc_Texture_Attenuation >= 0) R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture)); if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation)); if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants)); @@ -1271,28 +1365,17 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, fl if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip); if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower); if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value); - if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value, r_water_reflectdistort.value); + if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_refractdistort.value * rsurface.texture->refractfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor, r_water_reflectdistort.value * rsurface.texture->reflectfactor); if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screenscale[0], r_waterstate.screenscale[1]); if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4fARB(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_waterstate.screencenter[0], r_waterstate.screencenter[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]); - if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform3fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor); - if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform3fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor); - if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->refractmax - rsurface.texture->refractmin); - if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, 1 - rsurface.texture->refractmax); + if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f); + if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f); + if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin); + if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin); CHECKGLERROR return permutation; } -void R_SwitchSurfaceShader(int permutation) -{ - if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK)) - { - r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK); - CHECKGLERROR - qglUseProgramObjectARB(r_glsl_permutation->program); - CHECKGLERROR - } -} - #define SKINFRAME_HASH 1024 struct @@ -2550,7 +2633,7 @@ static void R_Water_AddWaterPlane(msurface_t *surface) // merge this surface's materialflags into the waterplane p->materialflags |= surface->texture->currentframe->currentmaterialflags; // merge this surface's PVS into the waterplane - if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION) && r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS) + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS) { r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_view.origin, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid); p->pvsvalid = true; @@ -2568,7 +2651,7 @@ static void R_Water_ProcessPlanes(void) // make sure enough textures are allocated for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++) { - if (p->materialflags & MATERIALFLAG_WATERSHADER) + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) { if (!p->texture_refraction) p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_refraction", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL); @@ -2596,7 +2679,7 @@ static void R_Water_ProcessPlanes(void) // render the normal view scene and copy into texture // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted) - if (p->materialflags & MATERIALFLAG_WATERSHADER) + if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) { r_view.clipplane = p->plane; VectorNegate(r_view.clipplane.normal, r_view.clipplane.normal); @@ -3831,10 +3914,7 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) */ } if(!r_waterstate.enabled) - { - t->currentmaterialflags &= ~MATERIALFLAG_WATERSHADER; - t->currentmaterialflags &= ~MATERIALFLAG_REFLECTION; - } + t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION); if (!(ent->flags & RENDER_LIGHT)) t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT; if (ent->effects & EF_ADDITIVE) @@ -5735,7 +5815,7 @@ void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surf if (addwaterplanes) { for (i = 0;i < numsurfaces;i++) - if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) + if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) R_Water_AddWaterPlane(surfacelist[i]); return; } @@ -6014,7 +6094,7 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep } R_UpdateAllTextureInfo(r_refdef.worldentity); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL)); + flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL)); if (debug) { @@ -6101,7 +6181,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr } R_UpdateAllTextureInfo(ent); - flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL)); + flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL)); if (debug) { diff --git a/model_brush.c b/model_brush.c index c67e9568..0b1293ae 100644 --- a/model_brush.c +++ b/model_brush.c @@ -1394,6 +1394,14 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags; } tx->currentframe = tx; + + // clear water settings + tx->reflectmin = 0; + tx->reflectmax = 1; + tx->refractfactor = 1; + Vector4Set(tx->refractcolor4f, 1, 1, 1, 1); + tx->reflectfactor = 1; + Vector4Set(tx->reflectcolor4f, 1, 1, 1, 1); } if (!m) @@ -1553,14 +1561,7 @@ static void Mod_Q1BSP_LoadTextures(lump_t *l) if (strncmp(tx->name,"*lava",5) && strncmp(tx->name,"*teleport",9) && strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture - { tx->basematerialflags |= MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW | MATERIALFLAG_WATERSHADER; - VectorSet(tx->reflectcolor, 1, 1, 1); - VectorSet(tx->refractcolor, 1, 1, 1); - tx->refractmin = 0; - tx->refractmax = 1; - tx->refractfactor = 1; - } tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW; } else if (!strncmp(tx->name, "sky", 3)) @@ -3686,7 +3687,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend) // we only need to have a drawsky function if it is used(usually only on world model) if (surface->texture->basematerialflags & MATERIALFLAG_SKY) mod->DrawSky = R_Q1BSP_DrawSky; - if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) + if (surface->texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; // calculate bounding shapes for (k = 0, vec = (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex);k < surface->num_vertices;k++, vec += 3) @@ -5790,7 +5791,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer, void *bufferend) mod->DrawSky = NULL; for (j = 0;j < mod->nummodelsurfaces;j++) - if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) + if (mod->data_surfaces[j + mod->firstmodelsurface].texture->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)) break; if (j < mod->nummodelsurfaces) mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes; diff --git a/model_brush.h b/model_brush.h index b4cce7b7..cd46206e 100644 --- a/model_brush.h +++ b/model_brush.h @@ -98,12 +98,16 @@ mplane_t; #define MATERIALFLAG_NOCULLFACE 65536 // render with a very short depth range (like 10% of normal), this causes entities to appear infront of most of the scene #define MATERIALFLAG_SHORTDEPTHRANGE 131072 -// render refraction and reflection (note: this is always opaque, the shader does the alpha effect) +// render water, comprising refraction and reflection (note: this is always opaque, the shader does the alpha effect) #define MATERIALFLAG_WATERSHADER 262144 -// render reflection only -#define MATERIALFLAG_REFLECTION 524288 +// render refraction (note: this is just a way to distort the background, otherwise useless) +#define MATERIALFLAG_REFRACTION 524288 +// render reflection +#define MATERIALFLAG_REFLECTION 1048576 +// render water, comprising refraction and reflection (note: this is always opaque, the shader does the alpha effect) +#define MATERIALFLAG_SORTTRANSPARENT 2097152 // combined mask of all attributes that require depth sorted rendering -#define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST) +#define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_SORTTRANSPARENT | MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST) typedef struct medge_s { diff --git a/model_shared.c b/model_shared.c index 880d5f3f..4db8ee98 100644 --- a/model_shared.c +++ b/model_shared.c @@ -1135,11 +1135,12 @@ void Mod_LoadQ3Shaders(void) shader = q3shaders_shaders + q3shaders_numshaders++; memset(shader, 0, sizeof(*shader)); - VectorSet(shader->reflectcolor, 1, 1, 1); - VectorSet(shader->refractcolor, 1, 1, 1); - shader->refractmin = 0; - shader->refractmax = 1; + shader->reflectmin = 0; + shader->reflectmax = 1; shader->refractfactor = 1; + Vector4Set(shader->refractcolor4f, 1, 1, 1, 1); + shader->reflectfactor = 1; + Vector4Set(shader->reflectcolor4f, 1, 1, 1, 1); strlcpy(shader->name, com_token, sizeof(shader->name)); if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{")) @@ -1500,27 +1501,27 @@ void Mod_LoadQ3Shaders(void) shader->textureflags |= Q3TEXTUREFLAG_NOPICMIP; else if (!strcasecmp(parameter[0], "polygonoffset")) shader->textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET; - else if (!strcasecmp(parameter[0], "dp_reflect")) + else if (!strcasecmp(parameter[0], "dp_refract") && numparameters >= 5) + { + shader->textureflags |= Q3TEXTUREFLAG_REFRACTION; + shader->refractfactor = atof(parameter[1]); + Vector4Set(shader->refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1); + } + else if (!strcasecmp(parameter[0], "dp_reflect") && numparameters >= 6) { shader->textureflags |= Q3TEXTUREFLAG_REFLECTION; - if(numparameters >= 2) - VectorSet(shader->reflectcolor, atof(parameter[1]), atof(parameter[1]), atof(parameter[1])); // grey - if(numparameters >= 4) - VectorSet(shader->reflectcolor, atof(parameter[1]), atof(parameter[2]), atof(parameter[3])); + shader->reflectfactor = atof(parameter[1]); + Vector4Set(shader->reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5])); } - else if (!strcasecmp(parameter[0], "dp_refract")) + else if (!strcasecmp(parameter[0], "dp_water") && numparameters >= 11) { shader->textureflags |= Q3TEXTUREFLAG_WATERSHADER; - if(numparameters >= 2) - shader->refractmin = atof(parameter[1]); - if(numparameters >= 3) - shader->refractmax = atof(parameter[2]); - if(numparameters >= 4) - shader->refractfactor = atof(parameter[3]); - if(numparameters >= 5) - VectorSet(shader->refractcolor, atof(parameter[4]), atof(parameter[4]), atof(parameter[4])); // grey - if(numparameters >= 7) - VectorSet(shader->refractcolor, atof(parameter[4]), atof(parameter[5]), atof(parameter[6])); + shader->reflectmin = atof(parameter[1]); + shader->reflectmax = atof(parameter[2]); + shader->refractfactor = atof(parameter[3]); + shader->reflectfactor = atof(parameter[4]); + Vector4Set(shader->refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1); + Vector4Set(shader->reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1); } else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2) { @@ -1584,7 +1585,7 @@ void Mod_LoadQ3Shaders(void) } // fix up multiple reflection types if(shader->textureflags & Q3TEXTUREFLAG_WATERSHADER) - shader->textureflags &= ~Q3TEXTUREFLAG_REFLECTION; + shader->textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION); } Mem_Free(f); } @@ -1640,6 +1641,8 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE; if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET) texture->basepolygonoffset -= 2; + if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION) + texture->basematerialflags |= MATERIALFLAG_REFRACTION; if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION) texture->basematerialflags |= MATERIALFLAG_REFLECTION; if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER) @@ -1725,11 +1728,12 @@ nothing GL_ZERO GL_ONE } } memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms)); - texture->refractmin = shader->refractmin; - texture->refractmax = shader->refractmax; + texture->reflectmin = shader->reflectmin; + texture->reflectmax = shader->reflectmax; texture->refractfactor = shader->refractfactor; - VectorCopy(shader->reflectcolor, texture->reflectcolor); - VectorCopy(shader->refractcolor, texture->refractcolor); + Vector4Copy(shader->refractcolor4f, texture->refractcolor4f); + texture->reflectfactor = shader->reflectfactor; + Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f); } else if (!strcmp(texture->name, "noshader")) { diff --git a/model_shared.h b/model_shared.h index 058073fd..7c81f0a0 100644 --- a/model_shared.h +++ b/model_shared.h @@ -187,8 +187,9 @@ shadowmesh_t; #define Q3TEXTUREFLAG_TWOSIDED 1 #define Q3TEXTUREFLAG_NOPICMIP 16 #define Q3TEXTUREFLAG_POLYGONOFFSET 32 -#define Q3TEXTUREFLAG_REFLECTION 256 -#define Q3TEXTUREFLAG_WATERSHADER 512 +#define Q3TEXTUREFLAG_REFRACTION 256 +#define Q3TEXTUREFLAG_REFLECTION 512 +#define Q3TEXTUREFLAG_WATERSHADER 1024 #define Q3PATHLENGTH 64 #define TEXTURE_MAXFRAMES 64 @@ -365,10 +366,12 @@ typedef struct q3shaderinfo_s char skyboxname[Q3PATHLENGTH]; q3shaderinfo_deform_t deforms[Q3MAXDEFORMS]; - vec3_t reflectcolor, refractcolor; - float refractmin; // when refraction is used, minimum amount of reflection (when looking straight down) - float refractmax; // when refraction is used, maximum amount of reflection (when looking parallel to water) - float refractfactor; // amount of refraction distort (1.0 = like the cvar specifies; note that reflection distort is not configurable because that's what the bumpmap should do) + float reflectmin; // when refraction is used, minimum amount of reflection (when looking straight down) + float reflectmax; // when refraction is used, maximum amount of reflection (when looking parallel to water) + float refractfactor; // amount of refraction distort (1.0 = like the cvar specifies) + vec4_t refractcolor4f; // color tint of refraction (including alpha factor) + float reflectfactor; // amount of reflection distort (1.0 = like the cvar specifies) + vec4_t reflectcolor4f; // color tint of reflection (including alpha factor) } q3shaderinfo_t; @@ -483,10 +486,12 @@ typedef struct texture_s int textureflags; // reflection - vec3_t reflectcolor, refractcolor; - float refractmin; // when refraction is used, minimum amount of reflection (when looking straight down) - float refractmax; // when refraction is used, maximum amount of reflection (when looking parallel to water) - float refractfactor; // amount of refraction distort (1.0 = like the cvar specifies; note that reflection distort is not configurable because that's what the bumpmap should do) + float reflectmin; // when refraction is used, minimum amount of reflection (when looking straight down) + float reflectmax; // when refraction is used, maximum amount of reflection (when looking parallel to water) + float refractfactor; // amount of refraction distort (1.0 = like the cvar specifies) + vec4_t refractcolor4f; // color tint of refraction (including alpha factor) + float reflectfactor; // amount of reflection distort (1.0 = like the cvar specifies) + vec4_t reflectcolor4f; // color tint of reflection (including alpha factor) } texture_t; diff --git a/render.h b/render.h index 35e52c2e..a1105ac4 100644 --- a/render.h +++ b/render.h @@ -359,87 +359,7 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist); void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist); -#define SHADERPERMUTATION_MODE_LIGHTMAP (1<<0) // (lightmap) use directional pixel shading from fixed light direction (q3bsp) -#define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE (1<<1) // (lightmap) use directional pixel shading from texture containing modelspace light directions (deluxemap) -#define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE (1<<2) // (lightmap) use directional pixel shading from texture containing tangentspace light directions (deluxemap) -#define SHADERPERMUTATION_MODE_LIGHTDIRECTION (1<<3) // (lightmap) use directional pixel shading from fixed light direction (q3bsp) -#define SHADERPERMUTATION_MODE_LIGHTSOURCE (1<<4) // (lightsource) use directional pixel shading from light source (rtlight) -#define SHADERPERMUTATION_WATER (1<<5) // normalmap-perturbed refraction of the background, performed behind the surface (the texture or material must be transparent to see it) -#define SHADERPERMUTATION_REFLECTION (1<<6) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface -#define SHADERPERMUTATION_GLOW (1<<7) // (lightmap) blend in an additive glow texture -#define SHADERPERMUTATION_FOG (1<<8) // tint the color by fog color or black if using additive blend mode -#define SHADERPERMUTATION_COLORMAPPING (1<<9) // indicates this is a colormapped skin -#define SHADERPERMUTATION_DIFFUSE (1<<10) // (lightsource) whether to use directional shading -#define SHADERPERMUTATION_CONTRASTBOOST (1<<11) // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma) -#define SHADERPERMUTATION_SPECULAR (1<<12) // (lightsource or deluxemapping) render specular effects -#define SHADERPERMUTATION_CUBEFILTER (1<<13) // (lightsource) use cubemap light filter -#define SHADERPERMUTATION_OFFSETMAPPING (1<<14) // adjust texcoords to roughly simulate a displacement mapped surface -#define SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING (1<<15) // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!) - -#define SHADERPERMUTATION_MAX (1<<16) // how many permutations are possible -#define SHADERPERMUTATION_MASK (SHADERPERMUTATION_MAX - 1) // mask of valid indexing bits for r_glsl_permutations[] array - -// these are additional flags used only by R_GLSL_CompilePermutation -#define SHADERPERMUTATION_USES_VERTEXSHADER (1<<29) -#define SHADERPERMUTATION_USES_GEOMETRYSHADER (1<<30) -#define SHADERPERMUTATION_USES_FRAGMENTSHADER (1<<31) - -typedef struct r_glsl_permutation_s -{ - // indicates if we have tried compiling this permutation already - qboolean compiled; - // 0 if compilation failed - int program; - int loc_Texture_Normal; - int loc_Texture_Color; - int loc_Texture_Gloss; - int loc_Texture_Cube; - int loc_Texture_Attenuation; - int loc_Texture_FogMask; - int loc_Texture_Pants; - int loc_Texture_Shirt; - int loc_Texture_Lightmap; - int loc_Texture_Deluxemap; - int loc_Texture_Glow; - int loc_Texture_Refraction; - int loc_Texture_Reflection; - int loc_FogColor; - int loc_LightPosition; - int loc_EyePosition; - int loc_LightColor; - int loc_Color_Pants; - int loc_Color_Shirt; - int loc_FogRangeRecip; - int loc_AmbientScale; - int loc_DiffuseScale; - int loc_SpecularScale; - int loc_SpecularPower; - int loc_GlowScale; - int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost - int loc_OffsetMapping_Scale; - int loc_AmbientColor; - int loc_DiffuseColor; - int loc_SpecularColor; - int loc_LightDir; - int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost - int loc_DistortScaleRefractReflect; - int loc_ScreenScaleRefractReflect; - int loc_ScreenCenterRefractReflect; - int loc_RefractColor; - int loc_ReflectColor; - int loc_ReflectFactor; - int loc_ReflectOffset; -} -r_glsl_permutation_t; - -// information about each possible shader permutation -extern r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_MAX]; -// currently selected permutation -extern r_glsl_permutation_t *r_glsl_permutation; - -void R_GLSL_CompilePermutation(const char *shaderfilename, int permutation); int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale); -void R_SwitchSurfaceShader(int permutation); #endif