static const char *builtinshaderstring =
"// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
"// written by Forest 'LordHavoc' Hale\n"
+"\n"
+"// enable various extensions depending on permutation:\n"
+"\n"
"#ifdef USESHADOWMAPRECT\n"
-"#extension GL_ARB_texture_rectangle : enable\n"
-"# ifdef HASTEXTUREGATHER\n"
+"# extension GL_ARB_texture_rectangle : enable\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef GL_EXT_gpu_shader4\n"
+"# extension GL_EXT_gpu_shader4 : enable\n"
+"# endif\n"
+"# ifdef GL_ARB_texture_gather\n"
"# extension GL_ARB_texture_gather : enable\n"
"# else\n"
-"# ifdef HASTEXTURE4\n"
+"# ifdef GL_AMD_texture_texture4\n"
"# extension GL_AMD_texture_texture4 : enable\n"
-"# define textureGather texture4\n"
"# endif\n"
"# endif\n"
"#endif\n"
"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# extension GL_EXT_gpu_shader4 : enable\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWSAMPLER\n"
+"# extension GL_ARB_shadow : enable\n"
+"#endif\n"
+"\n"
"// common definitions between vertex shader and fragment shader:\n"
"\n"
"//#ifdef __GLSL_CG_DATA_TYPES\n"
"# else\n"
"uniform sampler2DRect Texture_ShadowMapRect;\n"
"# endif\n"
+"#endif\n"
"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform sampler2DShadow Texture_ShadowMap2D;\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPVSDCT\n"
"uniform samplerCube Texture_CubeProjection;\n"
"#endif\n"
"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# ifdef USESHADOWSAMPLER\n"
+"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
+"# else\n"
+"uniform samplerCube Texture_ShadowMapCube;\n"
+"# endif\n"
+"#endif\n"
+"\n"
"uniform myhalf3 LightColor;\n"
"uniform myhalf3 AmbientColor;\n"
"uniform myhalf3 DiffuseColor;\n"
"}\n"
"#endif // USEOFFSETMAPPING\n"
"\n"
-"#ifdef USESHADOWMAPRECT \n"
-"uniform vec4 ShadowMap_TextureScale;\n"
-"#if 0\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
+"uniform vec2 ShadowMap_TextureScale;\n"
"uniform vec4 ShadowMap_Parameters;\n"
"#endif\n"
"\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
"vec3 GetShadowMapTC2D(vec3 dir)\n"
"{\n"
" vec3 adir = abs(dir);\n"
-"# if 0\n"
+"# ifndef USESHADOWMAPVSDCT\n"
" vec2 tc;\n"
" vec2 offset;\n"
" float ma;\n"
" if (adir.x > adir.y)\n"
" {\n"
-" if (adir.x > adir.z)\n"
+" if (adir.x > adir.z) // X\n"
" {\n"
" ma = adir.x;\n"
-" if (dir.x >= 0.0)\n"
-" {\n"
-" // +X\n"
-" tc = vec2(-dir.z, -dir.y);\n"
-" offset = vec2(0.5, 0.5);\n"
-" }\n"
-" else\n"
-" {\n"
-" // -X\n"
-" tc = vec2( dir.z, -dir.y);\n"
-" offset = vec2(1.5, 0.5);\n"
-" }\n"
+" tc = dir.zy;\n"
+" offset = vec2(mix(0.5, 1.5, dir.x < 0.0), 0.5);\n"
" }\n"
-" else\n"
+" else // Z\n"
" {\n"
-" ma = adir.z;\n"
-" if (dir.z >= 0.0)\n"
-" {\n"
-" // +Z\n"
-" tc = vec2( dir.x, -dir.y);\n"
-" offset = vec2(0.5, 2.5);\n"
-" }\n"
-" else\n"
-" {\n"
-" // -Z\n"
-" tc = vec2(-dir.x, -dir.y);\n"
-" offset = vec2(1.5, 2.5);\n"
-" }\n"
+" ma = adir.z;\n"
+" tc = dir.xy;\n"
+" offset = vec2(mix(0.5, 1.5, dir.z < 0.0), 2.5);\n"
" }\n"
" }\n"
" else\n"
" {\n"
-" if (adir.y > adir.z)\n"
+" if (adir.y > adir.z) // Y\n"
" {\n"
-" ma = adir.y;\n"
-" if (dir.y >= 0.0)\n"
-" {\n"
-" // +Y\n"
-" tc = vec2( dir.x, dir.z);\n"
-" offset = vec2(0.5, 1.5);\n"
-" }\n"
-" else\n"
-" {\n"
-" // -Y\n"
-" tc = vec2( dir.x, -dir.z);\n"
-" offset = vec2(1.5, 1.5);\n"
-" }\n"
+" ma = adir.y;\n"
+" tc = dir.xz;\n"
+" offset = vec2(mix(0.5, 1.5, dir.y < 0.0), 1.5);\n"
" }\n"
-" else\n"
+" else // Z\n"
" {\n"
-" ma = adir.z;\n"
-" if (dir.z >= 0.0)\n"
-" {\n"
-" // +Z\n"
-" tc = vec2(dir.x, -dir.y);\n"
-" offset = vec2(0.5, 2.5);\n"
-" }\n"
-" else\n"
-" {\n"
-" // -Z\n"
-" tc = vec2(-dir.x, -dir.y);\n"
-" offset = vec2(1.5, 2.5);\n"
-" }\n"
+" ma = adir.z;\n"
+" tc = dir.xy;\n"
+" offset = vec2(mix(0.5, 1.5, dir.z < 0.0), 2.5);\n"
" }\n"
" }\n"
"\n"
-" return vec3(tc * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma + vec3(offset * ShadowMap_Parameters.y, ShadowMap_Parameters.z);\n"
+" vec3 stc = vec3(tc * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
+" stc.xy += offset * ShadowMap_Parameters.y;\n"
+" stc.z += ShadowMap_Parameters.z;\n"
+"# if showshadowmap\n"
+" stc.xy *= ShadowMap_TextureScale;\n"
+"# endif\n"
+" return stc;\n"
"# else\n"
-" return vec3(textureCube(Texture_CubeProjection, dir.xyz).ra * ShadowMap_TextureScale.xy, ShadowMap_TextureScale.z + ShadowMap_TextureScale.w / max(max(adir.x, adir.y), adir.z));\n"
+" vec4 proj = textureCube(Texture_CubeProjection, dir);\n"
+" float ma = max(max(adir.x, adir.y), adir.z);\n"
+" vec3 stc = vec3(mix(dir.xy, dir.zz, proj.xy) * ShadowMap_Parameters.x, ShadowMap_Parameters.w) / ma;\n"
+" stc.xy += proj.zw * ShadowMap_Parameters.y;\n"
+" stc.z += ShadowMap_Parameters.z;\n"
+"# if showshadowmap\n"
+" stc.xy *= ShadowMap_TextureScale;\n"
+"# endif\n"
+" return stc;\n"
"# endif\n"
"}\n"
+"#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
"\n"
-"#endif // USESHADOWMAPRECT\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"vec4 GetShadowMapTCCube(vec3 dir)\n"
+"{\n"
+" vec3 adir = abs(dir);\n"
+" return vec4(dir, ShadowMap_Parameters.z + ShadowMap_Parameters.w / max(max(adir.x, adir.y), adir.z));\n"
+"}\n"
+"#endif\n"
"\n"
"#if !showshadowmap\n"
"# ifdef USESHADOWMAPRECT\n"
"# ifdef USESHADOWSAMPLER\n"
"\n"
"# ifdef USESHADOWMAPPCF\n"
-" f = dot(vec4(0.25),\n"
-" vec4(shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3(-0.4, 1.0, 0.0)).r,\n"
-" shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3(-1.0, -0.4, 0.0)).r,\n"
-" shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3( 0.4, -1.0, 0.0)).r,\n"
-" shadow2DRect(Texture_ShadowMapRect, shadowmaptc.xyz + vec3( 1.0, 0.4, 0.0)).r));\n"
+"# define texval(x, y) shadow2DRect(Texture_ShadowMapRect, shadowmaptc + vec3(x, y, 0.0)).r\n"
+" f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
"# else\n"
" f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).r;\n"
"# endif\n"
"# else\n"
"\n"
"# ifdef USESHADOWMAPPCF\n"
-"# if defined(HASTEXTUREGATHER) || defined(HASTEXTURE4)\n"
-" vec2 offset = fract(shadowmaptc.xy - 0.5);\n"
-" vec4 group1 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0, -1.0))),\n"
-" group2 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0, -1.0))),\n"
-" group3 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0, 1.0))),\n"
-" group4 = step(shadowmaptc.z, textureGather(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0, 1.0))),\n"
-" cols = vec4(group1.ab, group2.ab) + vec4(group3.rg, group4.rg) +\n"
-" mix(vec4(group1.rg, group2.rg), vec4(group3.ab, group4.ab), offset.y);\n"
-" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
-"# elif 1\n"
+"# if USESHADOWMAPPCF > 1\n"
+"# define texval(x, y) texture2DRect(Texture_ShadowMapRect, center + vec2(x, y)).r\n"
" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
-" vec4 row1 = step(shadowmaptc.z,\n"
-" vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0, -1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 0.0, -1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0, -1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0, -1.0)).r)),\n"
-" row2 = step(shadowmaptc.z,\n"
-" vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0, 0.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0, 0.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0, 0.0)).r)),\n"
-" row3 = step(shadowmaptc.z,\n"
-" vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0, 1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 0.0, 1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0, 1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0, 1.0)).r)),\n"
-" row4 = step(shadowmaptc.z,\n"
-" vec4(texture2DRect(Texture_ShadowMapRect, center + vec2(-1.0, 2.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 0.0, 2.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 1.0, 2.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, center + vec2( 2.0, 2.0)).r)),\n"
-" cols = row2 + row3 + mix(row1, row4, offset.y);\n"
+" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+" vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0)));\n"
+" vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0)));\n"
+" vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0)));\n"
+" vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
"# else\n"
+"# define texval(x, y) texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(x, y)).r\n"
" vec2 offset = fract(shadowmaptc.xy);\n"
-" vec3 row1 = step(shadowmaptc.z,\n"
-" vec3(texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0, -1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 0.0, -1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0, -1.0)).r)),\n"
-" row2 = step(shadowmaptc.z,\n"
-" vec3(texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0, 0.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r,\n"
-" texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0, 0.0)).r)),\n"
-" row3 = step(shadowmaptc.z,\n"
-" vec3(texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2(-1.0, 1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 0.0, 1.0)).r,\n"
-" texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy + vec2( 1.0, 1.0)).r)),\n"
-" cols = row2 + mix(row1, row3, offset.y);\n"
+" vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+" vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)));\n"
+" vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0)));\n"
+" vec3 cols = row2 + mix(row1, row3, offset.y);\n"
" f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
"# endif\n"
"# else\n"
"}\n"
"# endif\n"
"\n"
-"#endif\n"
+"# ifdef USESHADOWMAP2D\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+" vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
+" float f;\n"
+"\n"
+"# ifdef USESHADOWSAMPLER\n"
+"# ifdef USESHADOWMAPPCF\n"
+"# define texval(x, y) shadow2D(Texture_ShadowMap2D, vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z)).r \n"
+" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale;\n"
+" f = dot(vec4(0.25), vec4(texval(-0.4, 1.0), texval(-1.0, -0.4), texval(0.4, -1.0), texval(1.0, 0.4)));\n"
+"# else\n"
+" f = shadow2D(Texture_ShadowMap2D, vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z)).r;\n"
+"# endif\n"
+"# else\n"
+"# ifdef USESHADOWMAPPCF\n"
+"# if defined(GL_ARB_texture_gather) || defined(GL_AMD_texture_texture4)\n"
+"# ifdef GL_ARB_texture_gather\n"
+"# define texval(x, y) textureGatherOffset(Texture_ShadowMap2D, center, ivec(x, y))\n"
+"# else\n"
+"# define texval(x, y) texture4(Texture_ShadowMap2D, center + vec2(x,y)*ShadowMap_TextureScale)\n"
+"# endif\n"
+" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+" center *= ShadowMap_TextureScale;\n"
+" vec4 group1 = step(shadowmaptc.z, texval(-1.0, -1.0));\n"
+" vec4 group2 = step(shadowmaptc.z, texval( 1.0, -1.0));\n"
+" vec4 group3 = step(shadowmaptc.z, texval(-1.0, 1.0));\n"
+" vec4 group4 = step(shadowmaptc.z, texval( 1.0, 1.0));\n"
+" vec4 cols = vec4(group1.rg, group2.rg) + vec4(group3.ab, group4.ab) +\n"
+" mix(vec4(group1.ab, group2.ab), vec4(group3.rg, group4.rg), offset.y);\n"
+" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"# else\n"
+"# ifdef GL_EXT_gpu_shader4\n"
+"# define texval(x, y) texture2DOffset(Texture_ShadowMap2D, center, ivec2(x, y)).r\n"
+"# else\n"
+"# define texval(x, y) texture2D(Texture_ShadowMap2D, center + vec2(x, y)*ShadowMap_TextureScale).r \n"
+"# endif\n"
+"# if USESHADOWMAPPCF > 1\n"
+" vec2 center = shadowmaptc.xy - 0.5, offset = fract(center);\n"
+" center *= ShadowMap_TextureScale;\n"
+" vec4 row1 = step(shadowmaptc.z, vec4(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0), texval( 2.0, -1.0)));\n"
+" vec4 row2 = step(shadowmaptc.z, vec4(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0), texval( 2.0, 0.0)));\n"
+" vec4 row3 = step(shadowmaptc.z, vec4(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0), texval( 2.0, 1.0)));\n"
+" vec4 row4 = step(shadowmaptc.z, vec4(texval(-1.0, 2.0), texval( 0.0, 2.0), texval( 1.0, 2.0), texval( 2.0, 2.0)));\n"
+" vec4 cols = row2 + row3 + mix(row1, row4, offset.y);\n"
+" f = dot(mix(cols.xyz, cols.yzw, offset.x), vec3(1.0/9.0));\n"
+"# else\n"
+" vec2 center = shadowmaptc.xy*ShadowMap_TextureScale, offset = fract(shadowmaptc.xy);\n"
+" vec3 row1 = step(shadowmaptc.z, vec3(texval(-1.0, -1.0), texval( 0.0, -1.0), texval( 1.0, -1.0)));\n"
+" vec3 row2 = step(shadowmaptc.z, vec3(texval(-1.0, 0.0), texval( 0.0, 0.0), texval( 1.0, 0.0)));\n"
+" vec3 row3 = step(shadowmaptc.z, vec3(texval(-1.0, 1.0), texval( 0.0, 1.0), texval( 1.0, 1.0)));\n"
+" vec3 cols = row2 + mix(row1, row3, offset.y);\n"
+" f = dot(mix(cols.xy, cols.yz, offset.x), vec2(0.25));\n"
+"# endif\n"
+"# endif\n"
+"# else\n"
+" f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy*ShadowMap_TextureScale).r);\n"
+"# endif\n"
+"# endif\n"
+" return f;\n"
+"}\n"
+"# endif\n"
"\n"
+"# ifdef USESHADOWMAPCUBE\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+" // apply depth texture cubemap as light filter\n"
+" vec4 shadowmaptc = GetShadowMapTCCube(dir);\n"
+" float f;\n"
+"# ifdef USESHADOWSAMPLER\n"
+" f = shadowCube(Texture_ShadowMapCube, shadowmaptc).r;\n"
+"# else\n"
+" f = step(shadowmaptc.w, textureCube(Texture_ShadowMapCube, shadowmaptc.xyz).r);\n"
+"# endif\n"
+" return f;\n"
+"}\n"
+"# endif\n"
+"#endif\n"
"\n"
"#ifdef MODE_WATER\n"
"\n"
"# endif\n"
"# endif\n"
"\n"
-"#ifdef USESHADOWMAPRECT\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
"#if !showshadowmap\n"
-" color.rgb *= ShadowMapCompare(CubeVector);\n"
+" color.rgb *= ShadowMapCompare(CubeVector);\n"
"#endif\n"
"#endif\n"
"\n"
" gl_FragColor = texture2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xy);\n"
"# endif\n"
"# endif\n"
+"# ifdef USESHADOWMAP2D\n"
+"# ifdef USESHADOWSAMPLER\n"
+" gl_FragColor = shadow2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xyz);\n"
+"# else\n"
+" gl_FragColor = texture2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xy);\n"
+"# endif\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAPCUBE\n"
+"# ifdef USESHADOWSAMPLER\n"
+" gl_FragColor = shadowCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector));\n"
+"# else\n"
+" gl_FragColor = textureCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector).xyz);\n"
+"# endif\n"
+"# endif\n"
"#endif\n"
"}\n"
"#endif // !MODE_REFRACTION\n"
SHADERPERMUTATION_OFFSETMAPPING = 1<<9, ///< adjust texcoords to roughly simulate a displacement mapped surface
SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<10, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
SHADERPERMUTATION_SHADOWMAPRECT = 1<<11, ///< (lightsource) use shadowmap rectangle texture as light filter
- SHADERPERMUTATION_SHADOWMAPPCF = 1<<12, //< (lightsource) use percentage closer filtering on shadowmap test results
- SHADERPERMUTATION_SHADOWSAMPLER = 1<<13, //< (lightsource) use hardware shadowmap test
- SHADERPERMUTATION_LIMIT = 1<<14, ///< size of permutations array
- SHADERPERMUTATION_COUNT = 14 ///< size of shaderpermutationinfo array
+ SHADERPERMUTATION_SHADOWMAPCUBE = 1<<12, ///< (lightsource) use shadowmap cubemap texture as light filter
+ SHADERPERMUTATION_SHADOWMAP2D = 1<<13, ///< (lightsource) use shadowmap rectangle texture as light filter
+ SHADERPERMUTATION_SHADOWMAPPCF = 1<<14, //< (lightsource) use percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWMAPPCF2 = 1<<15, //< (lightsource) use higher quality percentage closer filtering on shadowmap test results
+ SHADERPERMUTATION_SHADOWSAMPLER = 1<<16, //< (lightsource) use hardware shadowmap test
+ SHADERPERMUTATION_SHADOWMAPVSDCT = 1<<17, //< (lightsource) use virtual shadow depth cube texture for shadowmap indexing
+ SHADERPERMUTATION_LIMIT = 1<<18, ///< size of permutations array
+ SHADERPERMUTATION_COUNT = 18 ///< size of shaderpermutationinfo array
}
shaderpermutation_t;
{"#define USEOFFSETMAPPING\n", " offsetmapping"},
{"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
{"#define USESHADOWMAPRECT\n", " shadowmaprect"},
- {"#define USESHADOWMAPPCF\n", " shadowmappcf"},
+ {"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
+ {"#define USESHADOWMAP2D\n", " shadowmap2d"},
+ {"#define USESHADOWMAPPCF 1\n", " shadowmappcf"},
+ {"#define USESHADOWMAPPCF 2\n", " shadowmappcf2"},
{"#define USESHADOWSAMPLER\n", " shadowsampler"},
+ {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"},
};
/// this enum is multiplied by SHADERPERMUTATION_MODEBASE
{"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
};
+struct r_glsl_permutation_s;
typedef struct r_glsl_permutation_s
{
+ /// hash lookup data
+ struct r_glsl_permutation_s *hashnext;
+ unsigned int mode;
+ unsigned int permutation;
+
/// indicates if we have tried compiling this permutation already
qboolean compiled;
/// 0 if compilation failed
int loc_Texture_Refraction;
int loc_Texture_Reflection;
int loc_Texture_ShadowMapRect;
+ int loc_Texture_ShadowMapCube;
+ int loc_Texture_ShadowMap2D;
int loc_Texture_CubeProjection;
int loc_FogColor;
int loc_LightPosition;
}
r_glsl_permutation_t;
+#define SHADERPERMUTATION_HASHSIZE 4096
+
/// information about each possible shader permutation
-r_glsl_permutation_t r_glsl_permutations[SHADERMODE_COUNT][SHADERPERMUTATION_LIMIT];
+r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
/// currently selected permutation
r_glsl_permutation_t *r_glsl_permutation;
+/// storage for permutations linked in the hash table
+memexpandablearray_t r_glsl_permutationarray;
+
+static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, unsigned int permutation)
+{
+ //unsigned int hashdepth = 0;
+ unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
+ r_glsl_permutation_t *p;
+ for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
+ {
+ if (p->mode == mode && p->permutation == permutation)
+ {
+ //if (hashdepth > 10)
+ // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+ return p;
+ }
+ //hashdepth++;
+ }
+ p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
+ p->mode = mode;
+ p->permutation = permutation;
+ p->hashnext = r_glsl_permutationhash[mode][hashindex];
+ r_glsl_permutationhash[mode][hashindex] = p;
+ //if (hashdepth > 10)
+ // Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
+ return p;
+}
static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
{
return shaderstring;
}
-static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutation)
+static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, unsigned int permutation)
{
int i;
shadermodeinfo_t *modeinfo = shadermodeinfo + mode;
- r_glsl_permutation_t *p = &r_glsl_permutations[mode][permutation];
int vertstrings_count = 0;
int geomstrings_count = 0;
int fragstrings_count = 0;
p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
p->loc_Texture_Cube = qglGetUniformLocationARB(p->program, "Texture_Cube");
p->loc_Texture_ShadowMapRect = qglGetUniformLocationARB(p->program, "Texture_ShadowMapRect");
+ p->loc_Texture_ShadowMapCube = qglGetUniformLocationARB(p->program, "Texture_ShadowMapCube");
+ p->loc_Texture_ShadowMap2D = qglGetUniformLocationARB(p->program, "Texture_ShadowMap2D");
p->loc_Texture_CubeProjection = qglGetUniformLocationARB(p->program, "Texture_CubeProjection");
p->loc_FogColor = qglGetUniformLocationARB(p->program, "FogColor");
p->loc_LightPosition = qglGetUniformLocationARB(p->program, "LightPosition");
if (p->loc_Texture_Refraction >= 0) qglUniform1iARB(p->loc_Texture_Refraction , GL20TU_REFRACTION);
if (p->loc_Texture_Reflection >= 0) qglUniform1iARB(p->loc_Texture_Reflection , GL20TU_REFLECTION);
if (p->loc_Texture_ShadowMapRect >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapRect , GL20TU_SHADOWMAPRECT);
+ if (p->loc_Texture_ShadowMapCube >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapCube , GL20TU_SHADOWMAPCUBE);
+ if (p->loc_Texture_ShadowMap2D >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D , GL20TU_SHADOWMAP2D);
if (p->loc_Texture_CubeProjection >= 0) qglUniform1iARB(p->loc_Texture_CubeProjection , GL20TU_CUBEPROJECTION);
CHECKGLERROR
if (developer.integer)
void R_GLSL_Restart_f(void)
{
- unsigned int mode;
- unsigned int permutation;
- for (mode = 0;mode < SHADERMODE_COUNT;mode++)
- for (permutation = 0;permutation < SHADERPERMUTATION_LIMIT;permutation++)
- if (r_glsl_permutations[mode][permutation].program)
- GL_Backend_FreeProgram(r_glsl_permutations[mode][permutation].program);
- memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
+ unsigned int i, limit;
+ r_glsl_permutation_t *p;
+ limit = Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
+ for (i = 0;i < limit;i++)
+ {
+ if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
+ {
+ GL_Backend_FreeProgram(p->program);
+ Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
+ }
+ }
+ memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
}
void R_GLSL_DumpShader_f(void)
void R_SetupShader_SetPermutation(unsigned int mode, unsigned int permutation)
{
- r_glsl_permutation_t *perm = &r_glsl_permutations[mode][permutation];
+ r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
if (r_glsl_permutation != perm)
{
r_glsl_permutation = perm;
if (!r_glsl_permutation->program)
{
if (!r_glsl_permutation->compiled)
- R_GLSL_CompilePermutation(mode, permutation);
+ R_GLSL_CompilePermutation(perm, mode, permutation);
if (!r_glsl_permutation->program)
{
// remove features until we find a valid permutation
if (!(permutation & j))
continue;
permutation -= j;
- r_glsl_permutation = &r_glsl_permutations[mode][permutation];
+ r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
if (!r_glsl_permutation->compiled)
- R_GLSL_CompilePermutation(mode, permutation);
+ R_GLSL_CompilePermutation(perm, mode, permutation);
if (r_glsl_permutation->program)
break;
}
extern rtexture_t *r_shadow_attenuationgradienttexture;
extern rtexture_t *r_shadow_attenuation2dtexture;
extern rtexture_t *r_shadow_attenuation3dtexture;
-extern float r_shadow_shadowmap_bias;
-extern float r_shadow_shadowmap_texturescale[4];
+extern qboolean r_shadow_usingshadowmaprect;
+extern qboolean r_shadow_usingshadowmapcube;
+extern qboolean r_shadow_usingshadowmap2d;
+extern float r_shadow_shadowmap_texturescale[2];
extern float r_shadow_shadowmap_parameters[4];
-extern int r_shadow_shadowmode;
-extern int r_shadow_shadowmapfilter;
+extern qboolean r_shadow_shadowmapvsdct;
+extern qboolean r_shadow_shadowmapsampler;
+extern int r_shadow_shadowmappcf;
void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
{
// select a permutation of the lighting shader appropriate to this
permutation |= SHADERPERMUTATION_FOG;
if (rsurface.texture->colormapping)
permutation |= SHADERPERMUTATION_COLORMAPPING;
- if (r_shadow_shadowmode)
- permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
- if (r_shadow_shadowmapfilter == 3)
- permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
- else if (r_shadow_shadowmapfilter == 2)
- permutation |= SHADERPERMUTATION_SHADOWMAPPCF | SHADERPERMUTATION_SHADOWSAMPLER;
- else if (r_shadow_shadowmapfilter == 1)
- permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+ if (r_shadow_usingshadowmaprect || r_shadow_usingshadowmap2d || r_shadow_usingshadowmapcube)
+ {
+ if (r_shadow_usingshadowmaprect)
+ permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+ if (r_shadow_usingshadowmap2d)
+ permutation |= SHADERPERMUTATION_SHADOWMAP2D;
+ if (r_shadow_usingshadowmapcube)
+ permutation |= SHADERPERMUTATION_SHADOWMAPCUBE;
+ else if(r_shadow_shadowmapvsdct)
+ permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
+
+ if (r_shadow_shadowmapsampler)
+ permutation |= SHADERPERMUTATION_SHADOWSAMPLER;
+ if (r_shadow_shadowmappcf > 1)
+ permutation |= SHADERPERMUTATION_SHADOWMAPPCF2;
+ else if (r_shadow_shadowmappcf)
+ permutation |= SHADERPERMUTATION_SHADOWMAPPCF;
+ }
}
else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
{
// additive passes are only darkened by fog, not tinted
if (r_glsl_permutation->loc_FogColor >= 0)
qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
- if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1], r_shadow_shadowmap_texturescale[2], r_shadow_shadowmap_texturescale[3]);
+ if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
}
else
//r_texture_fogintensity = NULL;
memset(&r_bloomstate, 0, sizeof(r_bloomstate));
memset(&r_waterstate, 0, sizeof(r_waterstate));
- memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
+ memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
+ Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
memset(&r_svbsp, 0, sizeof (r_svbsp));
r_refdef.fogmasktable_density = 0;
}
// allocate textures as needed
- if (r_waterstate.waterwidth != waterwidth || r_waterstate.waterheight != waterheight || r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
+ if (r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
{
r_waterstate.maxwaterplanes = MAX_WATERPLANES;
for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
p->texture_reflection = NULL;
}
memset(&r_waterstate, 0, sizeof(r_waterstate));
- r_waterstate.waterwidth = waterwidth;
- r_waterstate.waterheight = waterheight;
r_waterstate.texturewidth = texturewidth;
r_waterstate.textureheight = textureheight;
}
- // when doing a reduced render (HDR) we want to use a smaller area
- waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
- waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
-
- if (r_waterstate.waterwidth)
+ if (r_waterstate.texturewidth)
{
r_waterstate.enabled = true;
+ // when doing a reduced render (HDR) we want to use a smaller area
+ r_waterstate.waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
+ r_waterstate.waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
+
// set up variables that will be used in shader setup
- r_waterstate.screenscale[0] = 0.5f * (float)waterwidth / (float)texturewidth;
- r_waterstate.screenscale[1] = 0.5f * (float)waterheight / (float)textureheight;
- r_waterstate.screencenter[0] = 0.5f * (float)waterwidth / (float)texturewidth;
- r_waterstate.screencenter[1] = 0.5f * (float)waterheight / (float)textureheight;
+ r_waterstate.screenscale[0] = 0.5f * (float)r_waterstate.waterwidth / (float)r_waterstate.texturewidth;
+ r_waterstate.screenscale[1] = 0.5f * (float)r_waterstate.waterheight / (float)r_waterstate.textureheight;
+ r_waterstate.screencenter[0] = 0.5f * (float)r_waterstate.waterwidth / (float)r_waterstate.texturewidth;
+ r_waterstate.screencenter[1] = 0.5f * (float)r_waterstate.waterheight / (float)r_waterstate.textureheight;
}
r_waterstate.maxwaterplanes = MAX_WATERPLANES;
return;
}
- if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0/* || !r_refdef.scene.worldmodel*/)
+ if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer/* || !r_refdef.scene.worldmodel*/)
return; //Host_Error ("R_RenderView: NULL worldmodel");
r_refdef.view.colorscale = r_hdr_scenebrightness.value;