Index: ps/trunk/binaries/data/mods/public/shaders/glsl/common/fog.h =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/common/fog.h (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/common/fog.h (revision 24598) @@ -0,0 +1,29 @@ +#ifndef INCLUDED_FOG +#define INCLUDED_FOG + +#if USE_FOG +uniform vec3 fogColor; +uniform vec2 fogParams; +#endif + +vec3 applyFog(vec3 color) +{ +#if USE_FOG + float density = fogParams.x; + float maxFog = fogParams.y; + + const float LOG2 = 1.442695; + float z = gl_FragCoord.z / gl_FragCoord.w; + float fogFactor = exp2(-density * density * z * z * LOG2); + + fogFactor = fogFactor * (1.0 - maxFog) + maxFog; + + fogFactor = clamp(fogFactor, 0.0, 1.0); + + return mix(fogColor, color, fogFactor); +#else + return color; +#endif +} + +#endif // INCLUDED_FOG Property changes on: ps/trunk/binaries/data/mods/public/shaders/glsl/common/fog.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_fragment.h =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_fragment.h (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_fragment.h (revision 24598) @@ -0,0 +1,44 @@ +#ifndef INCLUDED_SHADOWS_FRAGMENT +#define INCLUDED_SHADOWS_FRAGMENT + +#if USE_SHADOW + varying vec4 v_shadow; + #if USE_SHADOW_SAMPLER + uniform sampler2DShadow shadowTex; + #if USE_SHADOW_PCF + uniform vec4 shadowScale; + #endif + #else + uniform sampler2D shadowTex; + #endif +#endif + +float get_shadow() +{ + float shadowBias = 0.003; + #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS + float biasedShdwZ = v_shadow.z - shadowBias; + #if USE_SHADOW_SAMPLER + #if USE_SHADOW_PCF + vec2 offset = fract(v_shadow.xy - 0.5); + vec4 size = vec4(offset + 1.0, 2.0 - offset); + vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (v_shadow.xy - 0.5*offset).xyxy) * shadowScale.zwzw; + return (1.0/9.0)*dot(size.zxzx*size.wwyy, + vec4(shadow2D(shadowTex, vec3(weight.zw, biasedShdwZ)).r, + shadow2D(shadowTex, vec3(weight.xw, biasedShdwZ)).r, + shadow2D(shadowTex, vec3(weight.zy, biasedShdwZ)).r, + shadow2D(shadowTex, vec3(weight.xy, biasedShdwZ)).r)); + #else + return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r; + #endif + #else + if (biasedShdwZ >= 1.0) + return 1.0; + return (biasedShdwZ < texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0); + #endif + #else + return 1.0; + #endif +} + +#endif // INCLUDED_SHADOWS_FRAGMENT Property changes on: ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_fragment.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_vertex.h =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_vertex.h (nonexistent) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_vertex.h (revision 24598) @@ -0,0 +1,22 @@ +#ifndef INCLUDED_SHADOWS_VERTEX +#define INCLUDED_SHADOWS_VERTEX + +#if USE_SHADOW +uniform mat4 shadowTransform; +varying vec4 v_shadow; +#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF + uniform vec4 shadowScale; +#endif +#endif + +void calculatePositionInShadowSpace(vec4 position) +{ +#if USE_SHADOW + v_shadow = shadowTransform * position; +#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF + v_shadow.xy *= shadowScale.xy; +#endif +#endif +} + +#endif // INCLUDED_SHADOWS_VERTEX Property changes on: ps/trunk/binaries/data/mods/public/shaders/glsl/common/shadows_vertex.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.fs (revision 24598) @@ -1,241 +1,183 @@ #version 120 +#include "common/fog.h" +#include "common/shadows_fragment.h" + uniform sampler2D baseTex; uniform sampler2D losTex; uniform sampler2D aoTex; uniform sampler2D normTex; uniform sampler2D specTex; -#if USE_SHADOW - varying vec4 v_shadow; - #if USE_SHADOW_SAMPLER - uniform sampler2DShadow shadowTex; - #if USE_SHADOW_PCF - uniform vec4 shadowScale; - #endif - #else - uniform sampler2D shadowTex; - #endif -#endif - #if USE_OBJECTCOLOR uniform vec3 objectColor; #else #if USE_PLAYERCOLOR uniform vec3 playerColor; #endif #endif uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; -uniform vec3 fogColor; -uniform vec2 fogParams; - varying vec4 v_lighting; varying vec2 v_tex; varying vec2 v_los; #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO varying vec2 v_tex2; #endif #if USE_SPECULAR uniform float specularPower; uniform vec3 specularColor; #endif #if USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX || USE_AO uniform vec4 effectSettings; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX varying vec4 v_normal; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX) varying vec4 v_tangent; //varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX varying vec3 v_eyeVec; #endif #endif -float get_shadow() -{ - float shadowBias = 0.003; - #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS - float biasedShdwZ = v_shadow.z - shadowBias; - #if USE_SHADOW_SAMPLER - #if USE_SHADOW_PCF - vec2 offset = fract(v_shadow.xy - 0.5); - vec4 size = vec4(offset + 1.0, 2.0 - offset); - vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (v_shadow.xy - 0.5*offset).xyxy) * shadowScale.zwzw; - return (1.0/9.0)*dot(size.zxzx*size.wwyy, - vec4(shadow2D(shadowTex, vec3(weight.zw, biasedShdwZ)).r, - shadow2D(shadowTex, vec3(weight.xw, biasedShdwZ)).r, - shadow2D(shadowTex, vec3(weight.zy, biasedShdwZ)).r, - shadow2D(shadowTex, vec3(weight.xy, biasedShdwZ)).r)); - #else - return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r; - #endif - #else - if (biasedShdwZ >= 1.0) - return 1.0; - return (biasedShdwZ < texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0); - #endif - #else - return 1.0; - #endif -} - -vec3 get_fog(vec3 color) -{ - float density = fogParams.x; - float maxFog = fogParams.y; - - const float LOG2 = 1.442695; - float z = gl_FragCoord.z / gl_FragCoord.w; - float fogFactor = exp2(-density * density * z * z * LOG2); - - fogFactor = fogFactor * (1.0 - maxFog) + maxFog; - - fogFactor = clamp(fogFactor, 0.0, 1.0); - - return mix(fogColor, color, fogFactor); -} - void main() { vec2 coord = v_tex; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_PARALLAX || USE_NORMAL_MAP) vec3 bitangent = vec3(v_normal.w, v_tangent.w, v_lighting.w); mat3 tbn = mat3(v_tangent.xyz, bitangent, v_normal.xyz); #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX { float h = texture2D(normTex, coord).a; vec3 eyeDir = normalize(v_eyeVec * tbn); float dist = length(v_eyeVec); vec2 move; float height = 1.0; float scale = effectSettings.z; int iter = int(min(20.0, 25.0 - dist/10.0)); if (iter > 0) { float s = 1.0/float(iter); float t = s; move = vec2(-eyeDir.x, eyeDir.y) * scale / (eyeDir.z * float(iter)); vec2 nil = vec2(0.0); for (int i = 0; i < iter; ++i) { height -= t; t = (h < height) ? s : 0.0; vec2 temp = (h < height) ? move : nil; coord += temp; h = texture2D(normTex, coord).a; } // Move back to where we collided with the surface. // This assumes the surface is linear between the sample point before we // intersect the surface and after we intersect the surface float hp = texture2D(normTex, coord - move).a; coord -= move * ((h - height) / (s + h - hp)); } } #endif vec4 tex = texture2D(baseTex, coord); // Alpha-test as early as possible #ifdef REQUIRE_ALPHA_GEQUAL if (tex.a < REQUIRE_ALPHA_GEQUAL) discard; #endif #if USE_TRANSPARENT gl_FragColor.a = tex.a; #else gl_FragColor.a = 1.0; #endif vec3 texdiffuse = tex.rgb; // Apply-coloring based on texture alpha #if USE_OBJECTCOLOR texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a); #else #if USE_PLAYERCOLOR texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), tex.a); #endif #endif #if USE_SPECULAR || USE_SPECULAR_MAP || USE_NORMAL_MAP vec3 normal = v_normal.xyz; #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_NORMAL_MAP vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0; ntex.y = -ntex.y; normal = normalize(tbn * ntex); vec3 bumplight = max(dot(-sunDir, normal), 0.0) * sunColor; vec3 sundiffuse = (bumplight - v_lighting.rgb) * effectSettings.x + v_lighting.rgb; #else vec3 sundiffuse = v_lighting.rgb; #endif vec4 specular = vec4(0.0); #if USE_SPECULAR || USE_SPECULAR_MAP vec3 specCol; float specPow; #if USE_SPECULAR_MAP vec4 s = texture2D(specTex, coord); specCol = s.rgb; specular.a = s.a; specPow = effectSettings.y; #else specCol = specularColor; specPow = specularPower; #endif specular.rgb = sunColor * specCol * pow(max(0.0, dot(normalize(normal), v_half)), specPow); #endif vec3 color = (texdiffuse * sundiffuse + specular.rgb) * get_shadow(); vec3 ambColor = texdiffuse * ambient; #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO vec3 ao = texture2D(aoTex, v_tex2).rrr; ao = mix(vec3(1.0), ao * 2.0, effectSettings.w); ambColor *= ao; #endif color += ambColor; #if USE_SPECULAR_MAP && USE_SELF_LIGHT color = mix(texdiffuse, color, specular.a); #endif - #if USE_FOG - color = get_fog(color); - #endif + color = applyFog(color); #if !IGNORE_LOS float los = texture2D(losTex, v_los).a; los = los < 0.03 ? 0.0 : los; color *= los; #endif color *= shadingColor; gl_FragColor.rgb = color; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_common.vs (revision 24598) @@ -1,184 +1,172 @@ #version 120 +#include "common/shadows_vertex.h" + uniform mat4 transform; uniform vec3 cameraPos; #ifdef GL_ES uniform mediump vec3 sunDir; uniform mediump vec3 sunColor; #else uniform vec3 sunDir; uniform vec3 sunColor; #endif uniform vec2 losTransform; -uniform mat4 shadowTransform; uniform mat4 instancingTransform; -#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - uniform vec4 shadowScale; -#endif - #if USE_WIND uniform vec4 sim_time; uniform vec4 windData; #endif varying vec4 v_lighting; varying vec2 v_tex; varying vec2 v_los; -#if USE_SHADOW - varying vec4 v_shadow; -#endif - #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO varying vec2 v_tex2; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX varying vec4 v_normal; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX) varying vec4 v_tangent; //varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX varying vec3 v_eyeVec; #endif #endif attribute vec3 a_vertex; attribute vec3 a_normal; #if (USE_INSTANCING || USE_GPU_SKINNING) attribute vec4 a_tangent; #endif attribute vec2 a_uv0; attribute vec2 a_uv1; #if USE_GPU_SKINNING const int MAX_INFLUENCES = 4; const int MAX_BONES = 64; uniform mat4 skinBlendMatrices[MAX_BONES]; attribute vec4 a_skinJoints; attribute vec4 a_skinWeights; #endif vec4 fakeCos(vec4 x) { vec4 tri = abs(fract(x + 0.5) * 2.0 - 1.0); return tri * tri *(3.0 - 2.0 * tri); } void main() { #if USE_GPU_SKINNING vec3 p = vec3(0.0); vec3 n = vec3(0.0); for (int i = 0; i < MAX_INFLUENCES; ++i) { int joint = int(a_skinJoints[i]); if (joint != 0xff) { mat4 m = skinBlendMatrices[joint]; p += vec3(m * vec4(a_vertex, 1.0)) * a_skinWeights[i]; n += vec3(m * vec4(a_normal, 0.0)) * a_skinWeights[i]; } } vec4 position = instancingTransform * vec4(p, 1.0); mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); vec3 normal = normalMatrix * normalize(n); #if (USE_NORMAL_MAP || USE_PARALLAX) vec3 tangent = normalMatrix * a_tangent.xyz; #endif #else #if (USE_INSTANCING) vec4 position = instancingTransform * vec4(a_vertex, 1.0); mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); vec3 normal = normalMatrix * a_normal; #if (USE_NORMAL_MAP || USE_PARALLAX) vec3 tangent = normalMatrix * a_tangent.xyz; #endif #else vec4 position = vec4(a_vertex, 1.0); vec3 normal = a_normal; #endif #endif #if USE_WIND vec2 wind = windData.xy; // fractional part of model position, clamped to >.4 vec4 modelPos = instancingTransform[3]; modelPos = fract(modelPos); modelPos = clamp(modelPos, 0.4, 1.0); // crude measure of wind intensity float abswind = abs(wind.x) + abs(wind.y); vec4 cosVec; // these determine the speed of the wind's "cosine" waves. cosVec.w = 0.0; cosVec.x = sim_time.x * modelPos[0] + position.x; cosVec.y = sim_time.x * modelPos[2] / 3.0 + instancingTransform[3][0]; cosVec.z = sim_time.x * abswind / 4.0 + position.z; // calculate "cosines" in parallel, using a smoothed triangle wave cosVec = fakeCos(cosVec); float limit = clamp((a_vertex.x * a_vertex.z * a_vertex.y) / 3000.0, 0.0, 0.2); float diff = cosVec.x * limit; float diff2 = cosVec.y * clamp(a_vertex.y / 60.0, 0.0, 0.25); // fluttering of model parts based on distance from model center (ie longer branches) position.xyz += cosVec.z * limit * clamp(abswind, 1.2, 1.7); // swaying of trunk based on distance from ground (higher parts sway more) position.xz += diff + diff2 * wind; #endif gl_Position = transform * position; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX v_normal.xyz = normal; #if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX) v_tangent.xyz = tangent; vec3 bitangent = cross(v_normal.xyz, v_tangent.xyz) * a_tangent.w; v_normal.w = bitangent.x; v_tangent.w = bitangent.y; v_lighting.w = bitangent.z; #endif #if USE_SPECULAR || USE_SPECULAR_MAP || USE_PARALLAX vec3 eyeVec = cameraPos.xyz - position.xyz; #if USE_SPECULAR || USE_SPECULAR_MAP vec3 sunVec = -sunDir; v_half = normalize(sunVec + normalize(eyeVec)); #endif #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX v_eyeVec = eyeVec; #endif #endif #endif v_lighting.xyz = max(0.0, dot(normal, -sunDir)) * sunColor; v_tex = a_uv0; #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO v_tex2 = a_uv1; #endif - #if USE_SHADOW - v_shadow = shadowTransform * position; - #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - v_shadow.xy *= shadowScale.xy; - #endif - #endif + calculatePositionInShadowSpace(position); v_los = position.xz * losTransform.x + losTransform.y; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.fs (revision 24598) @@ -1,148 +1,109 @@ #version 120 +#include "common/shadows_fragment.h" + uniform sampler2D baseTex; uniform sampler2D losTex; uniform sampler2D aoTex; uniform sampler2D normTex; uniform sampler2D specTex; uniform sampler2D waterTex; uniform samplerCube skyCube; -#if USE_SHADOW - #if USE_SHADOW_SAMPLER - uniform sampler2DShadow shadowTex; - #if USE_SHADOW_PCF - uniform vec4 shadowScale; - #endif - #else - uniform sampler2D shadowTex; - #endif -#endif - #if USE_OBJECTCOLOR uniform vec3 objectColor; #else #if USE_PLAYERCOLOR uniform vec3 playerColor; #endif #endif uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; uniform vec3 cameraPos; uniform float specularStrength; uniform float waviness; uniform vec3 waterTint; uniform float murkiness; uniform vec3 reflectionTint; uniform float reflectionTintStrength; - float waterDepth = 4.0; float fullDepth = 5.0; // Depth at which to use full murkiness (shallower water will be clearer) - varying vec4 worldPos; varying vec4 v_tex; varying vec4 v_shadow; varying vec2 v_los; - -float get_shadow(vec4 coords) -{ - #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS - #if USE_SHADOW_SAMPLER - #if USE_SHADOW_PCF - vec2 offset = fract(coords.xy - 0.5); - vec4 size = vec4(offset + 1.0, 2.0 - offset); - vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (coords.xy - 0.5*offset).xyxy) * shadowScale.zwzw; - return (1.0/9.0)*dot(size.zxzx*size.wwyy, - vec4(shadow2D(shadowTex, vec3(weight.zw, coords.z)).r, - shadow2D(shadowTex, vec3(weight.xw, coords.z)).r, - shadow2D(shadowTex, vec3(weight.zy, coords.z)).r, - shadow2D(shadowTex, vec3(weight.xy, coords.z)).r)); - #else - return shadow2D(shadowTex, coords.xyz).r; - #endif - #else - if (coords.z >= 1.0) - return 1.0; - return (coords.z <= texture2D(shadowTex, coords.xy).x ? 1.0 : 0.0); - #endif - #else - return 1.0; - #endif -} - - void main() { vec3 n, l, h, v; // Normal, light vector, half-vector and view vector (vector to eye) float ndotl, ndoth, ndotv; float fresnel; float t; // Temporary variable vec2 reflCoords, refrCoords; vec3 reflColor, refrColor, specular; float losMod; //vec4 wtex = textureGrad(waterTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); vec4 wtex = texture2D(waterTex, fract(v_tex.xy)); n = normalize(wtex.xzy - vec3(0.5, 0.5, 0.5)); l = -sunDir; v = normalize(cameraPos - worldPos.xyz); h = normalize(l + v); ndotl = dot(n, l); ndoth = dot(n, h); ndotv = dot(n, v); fresnel = pow(1.0 - ndotv, 0.8); // A rather random Fresnel approximation //refrCoords = (0.5*gl_TexCoord[2].xy - 0.8*waviness*n.xz) / gl_TexCoord[2].w + 0.5; // Unbias texture coords //reflCoords = (0.5*gl_TexCoord[1].xy + waviness*n.xz) / gl_TexCoord[1].w + 0.5; // Unbias texture coords //vec3 dir = normalize(v + vec3(waviness*n.x, 0.0, waviness*n.z)); vec3 eye = reflect(v, n); vec3 tex = textureCube(skyCube, eye).rgb; reflColor = mix(tex, sunColor * reflectionTint, reflectionTintStrength); //waterDepth = 4.0 + 2.0 * dot(abs(v_tex.zw - 0.5), vec2(0.5)); waterDepth = 4.0; //refrColor = (0.5 + 0.5*ndotl) * mix(texture2D(refractionMap, refrCoords).rgb, sunColor * tint, refrColor = (0.5 + 0.5*ndotl) * mix(vec3(0.3), sunColor * waterTint, murkiness * clamp(waterDepth / fullDepth, 0.0, 1.0)); // Murkiness and tint at this pixel (tweaked based on lighting and depth) specular = pow(max(0.0, ndoth), 150.0f) * sunColor * specularStrength; losMod = texture2D(losTex, v_los).a; #if USE_SHADOW float shadow = get_shadow(vec4(v_shadow.xy - 8*waviness*n.xz, v_shadow.zw)); float fresShadow = mix(fresnel, fresnel*shadow, dot(sunColor, vec3(0.16666))); #else float fresShadow = fresnel; #endif vec3 color = mix(refrColor + 0.3*specular, reflColor + specular, fresShadow); gl_FragColor.rgb = color * losMod; //gl_FragColor.rgb = mix(refrColor + 0.3*specular, reflColor + specular, fresnel) * losMod; // Make alpha vary based on both depth (so it blends with the shore) and view angle (make it // become opaque faster at lower view angles so we can't look "underneath" the water plane) t = 18.0 * max(0.0, 0.7 - v.y); gl_FragColor.a = 0.15 * waterDepth * (1.2 + t + fresnel); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_water.vs (revision 24598) @@ -1,74 +1,59 @@ #if USE_GPU_SKINNING // Skinning requires GLSL 1.30 for ivec4 vertex attributes #version 130 #else #version 120 #endif +#include "common/shadows_vertex.h" + uniform mat4 transform; uniform vec3 cameraPos; uniform vec3 sunDir; uniform vec3 sunColor; uniform vec2 losTransform; -uniform mat4 shadowTransform; uniform mat4 instancingTransform; uniform float sim_time; uniform vec2 translation; -#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - uniform vec4 shadowScale; -#endif - - attribute vec3 a_vertex; attribute vec3 a_normal; #if USE_INSTANCING attribute vec4 a_tangent; #endif attribute vec2 a_uv0; attribute vec2 a_uv1; #if USE_GPU_SKINNING const int MAX_INFLUENCES = 4; const int MAX_BONES = 64; uniform mat4 skinBlendMatrices[MAX_BONES]; attribute ivec4 a_skinJoints; attribute vec4 a_skinWeights; #endif - varying vec4 worldPos; varying vec4 v_tex; -varying vec4 v_shadow; varying vec2 v_los; - vec4 fakeCos(vec4 x) { vec4 tri = abs(fract(x + 0.5) * 2.0 - 1.0); return tri * tri *(3.0 - 2.0 * tri); } - - void main() { worldPos = instancingTransform * vec4(a_vertex, 1.0); v_tex.xy = (a_uv0 + worldPos.xz) / 5.0 + sim_time * translation; v_tex.zw = a_uv0; - #if USE_SHADOW - v_shadow = shadowTransform * worldPos; - #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - v_shadow.xy *= shadowScale.xy; - #endif - #endif + calculatePositionInShadowSpace(worldPos); v_los = worldPos.xz * losTransform.x + losTransform.y; gl_Position = transform * worldPos; } - Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.fs (revision 24598) @@ -1,88 +1,49 @@ #version 120 +#include "common/shadows_fragment.h" + uniform sampler2D baseTex; uniform sampler2D losTex; - -#if USE_SHADOW - #if USE_SHADOW_SAMPLER - uniform sampler2DShadow shadowTex; - #if USE_SHADOW_PCF - uniform vec4 shadowScale; - #endif - #else - uniform sampler2D shadowTex; - #endif -#endif - uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; uniform vec3 cameraPos; - uniform float specularPower; uniform vec3 specularColor; - varying vec4 v_tex; varying vec4 v_shadow; varying vec2 v_los; varying vec3 v_half; varying vec3 v_normal; varying float v_transp; varying vec3 v_lighting; -float get_shadow() -{ - #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS - #if USE_SHADOW_SAMPLER - #if USE_SHADOW_PCF - vec2 offset = fract(v_shadow.xy - 0.5); - vec4 size = vec4(offset + 1.0, 2.0 - offset); - vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (v_shadow.xy - 0.5*offset).xyxy) * shadowScale.zwzw; - return (1.0/9.0)*dot(size.zxzx*size.wwyy, - vec4(shadow2D(shadowTex, vec3(weight.zw, v_shadow.z)).r, - shadow2D(shadowTex, vec3(weight.xw, v_shadow.z)).r, - shadow2D(shadowTex, vec3(weight.zy, v_shadow.z)).r, - shadow2D(shadowTex, vec3(weight.xy, v_shadow.z)).r)); - #else - return shadow2D(shadowTex, v_shadow.xyz).r; - #endif - #else - if (v_shadow.z >= 1.0) - return 1.0; - return (v_shadow.z <= texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0); - #endif - #else - return 1.0; - #endif -} - - void main() { //vec4 texdiffuse = textureGrad(baseTex, vec3(fract(v_tex.xy), v_tex.z), dFdx(v_tex.xy), dFdy(v_tex.xy)); vec4 texdiffuse = texture2D(baseTex, fract(v_tex.xy)); if (texdiffuse.a < 0.25) discard; texdiffuse.a *= v_transp; vec3 specular = sunColor * specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower); vec3 color = (texdiffuse.rgb * v_lighting + specular) * get_shadow(); color += texdiffuse.rgb * ambient; #if !IGNORE_LOS float los = texture2D(losTex, v_los).a; los = los < 0.03 ? 0.0 : los; color *= los; #endif gl_FragColor.rgb = color; gl_FragColor.a = texdiffuse.a; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/model_waterfall.vs (revision 24598) @@ -1,65 +1,54 @@ #if USE_GPU_SKINNING // Skinning requires GLSL 1.30 for ivec4 vertex attributes #version 130 #else #version 120 #endif +#include "common/shadows_vertex.h" + uniform mat4 transform; uniform vec3 cameraPos; uniform vec3 sunDir; uniform vec3 sunColor; uniform vec2 losTransform; -uniform mat4 shadowTransform; uniform mat4 instancingTransform; uniform float sim_time; uniform vec2 translation; -#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - uniform vec4 shadowScale; -#endif - - attribute vec3 a_vertex; attribute vec3 a_normal; attribute vec2 a_uv0; attribute vec2 a_uv1; varying vec4 worldPos; varying vec4 v_tex; -varying vec4 v_shadow; varying vec2 v_los; varying vec3 v_half; varying vec3 v_normal; varying float v_transp; varying vec3 v_lighting; - void main() { worldPos = instancingTransform * vec4(a_vertex, 1.0); v_tex.xy = a_uv0 + sim_time * translation; v_transp = a_uv1.x; - #if USE_SHADOW - v_shadow = shadowTransform * worldPos; - #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - v_shadow.xy *= shadowScale.xy; - #endif - #endif + calculatePositionInShadowSpace(worldPos); v_los = worldPos.xz * losTransform.x + losTransform.y; vec3 eyeVec = cameraPos.xyz - worldPos.xyz; vec3 sunVec = -sunDir; v_half = normalize(sunVec + normalize(eyeVec)); mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz); v_normal = normalMatrix * a_normal; v_lighting = max(0.0, dot(v_normal, -sunDir)) * sunColor; gl_Position = transform * worldPos; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/particle.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/particle.fs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/particle.fs (revision 24598) @@ -1,43 +1,25 @@ #version 110 +#include "common/fog.h" + uniform sampler2D baseTex; uniform sampler2D losTex; varying vec2 v_tex; varying vec2 v_los; varying vec4 v_color; uniform vec3 sunColor; -uniform vec3 fogColor; -uniform vec2 fogParams; - -vec4 get_fog(vec4 color) -{ - float density = fogParams.x; - float maxFog = fogParams.y; - - const float LOG2 = 1.442695; - float z = gl_FragCoord.z / gl_FragCoord.w; - float fogFactor = exp2(-density * density * z * z * LOG2); - - fogFactor = fogFactor * (1.0 - maxFog) + maxFog; - - fogFactor = clamp(fogFactor, 0.0, 1.0); - - return vec4(mix(fogColor, color.rgb, fogFactor),color.a); -} void main() { vec4 color = texture2D(baseTex, v_tex) * vec4((v_color.rgb + sunColor)/2.0,v_color.a); float los = texture2D(losTex, v_los).a; los = los < 0.03 ? 0.0 : los; color.rgb *= los; -#if USE_FOG - color = get_fog(color); -#endif + color.rgb = applyFog(color.rgb); gl_FragColor = color; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/solid_player.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/solid_player.fs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/solid_player.fs (revision 24598) @@ -1,30 +1,10 @@ #version 110 -uniform vec4 playerColor; -uniform vec3 fogColor; -uniform vec2 fogParams; - -vec3 get_fog(vec3 color) -{ - float density = fogParams.x; - float maxFog = fogParams.y; - - const float LOG2 = 1.442695; - float z = gl_FragCoord.z / gl_FragCoord.w; - float fogFactor = exp2(-density * density * z * z * LOG2); +#include "common/fog.h" - fogFactor = fogFactor * (1.0 - maxFog) + maxFog; - - fogFactor = clamp(fogFactor, 0.0, 1.0); - - return mix(fogColor, color, fogFactor); -} +uniform vec4 playerColor; void main() { -#if USE_FOG - gl_FragColor = vec4(get_fog(playerColor.rgb), playerColor.a); -#else - gl_FragColor = vec4(playerColor.rgb, playerColor.a); -#endif + gl_FragColor = vec4(applyFog(playerColor.rgb), playerColor.a); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.fs (revision 24598) @@ -1,256 +1,194 @@ #version 120 +#include "common/fog.h" +#include "common/shadows_fragment.h" + uniform sampler2D baseTex; uniform sampler2D blendTex; uniform sampler2D losTex; uniform sampler2D normTex; uniform sampler2D specTex; -#if USE_SHADOW - uniform float shadowAngle; - #if USE_SHADOW_SAMPLER - uniform sampler2DShadow shadowTex; - #if USE_SHADOW_PCF - uniform vec4 shadowScale; - #endif - #else - uniform sampler2D shadowTex; - #endif -#endif - uniform vec3 shadingColor; uniform vec3 ambient; uniform vec3 sunColor; uniform vec3 sunDir; -uniform vec3 fogColor; -uniform vec2 fogParams; - uniform vec2 textureTransform; varying vec3 v_lighting; -#if USE_SHADOW - varying vec4 v_shadow; -#endif - varying vec2 v_los; varying vec2 v_blend; #if USE_TRIPLANAR varying vec3 v_tex; #else varying vec2 v_tex; #endif #if USE_SPECULAR uniform float specularPower; uniform vec3 specularColor; #endif #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_AO uniform vec4 effectSettings; #endif varying vec3 v_normal; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP #if USE_NORMAL_MAP varying vec4 v_tangent; varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #endif -float get_shadow() -{ - float shadowBias = 0.0005; - #if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS - float biasedShdwZ = v_shadow.z - shadowBias; - #if USE_SHADOW_SAMPLER - #if USE_SHADOW_PCF - vec2 offset = fract(v_shadow.xy - 0.5); - vec4 size = vec4(offset + 1.0, 2.0 - offset); - vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (v_shadow.xy - 0.5*offset).xyxy) * shadowScale.zwzw; - return (1.0/9.0)*dot(size.zxzx*size.wwyy, - vec4(shadow2D(shadowTex, vec3(weight.zw, biasedShdwZ)).r, - shadow2D(shadowTex, vec3(weight.xw, biasedShdwZ)).r, - shadow2D(shadowTex, vec3(weight.zy, biasedShdwZ)).r, - shadow2D(shadowTex, vec3(weight.xy, biasedShdwZ)).r)); - #else - return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r; - #endif - #else - if (biasedShdwZ >= 1.0) - return 1.0; - return (biasedShdwZ < texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0); - #endif - #else - return 1.0; - #endif -} - #if USE_TRIPLANAR vec4 triplanar(sampler2D sampler, vec3 wpos) { float tighten = 0.4679; vec3 blending = abs(normalize(v_normal)) - tighten; blending = max(blending, 0.0); blending /= vec3(blending.x + blending.y + blending.z); vec3 signedBlending = sign(v_normal) * blending; vec3 coords = wpos; coords.xyz /= 32.0; // Ugh. vec4 col1 = texture2D(sampler, coords.yz); vec4 col2 = texture2D(sampler, coords.zx); vec4 col3 = texture2D(sampler, coords.yx); vec4 colBlended = col1 * blending.x + col2 * blending.y + col3 * blending.z; return colBlended; } vec4 triplanarNormals(sampler2D sampler, vec3 wpos) { float tighten = 0.4679; vec3 blending = abs(normalize(v_normal)) - tighten; blending = max(blending, 0.0); blending /= vec3(blending.x + blending.y + blending.z); vec3 signedBlending = sign(v_normal) * blending; vec3 coords = wpos; coords.xyz /= 32.0; // Ugh. vec4 col1 = texture2D(sampler, coords.yz).xyzw; col1.y = 1.0 - col1.y; vec4 col2 = texture2D(sampler, coords.zx).yxzw; col2.y = 1.0 - col2.y; vec4 col3 = texture2D(sampler, coords.yx).yxzw; col3.y = 1.0 - col3.y; vec4 colBlended = col1 * blending.x + col2 * blending.y + col3 * blending.z; return colBlended; } #endif -vec3 get_fog(vec3 color) -{ - float density = fogParams.x; - float maxFog = fogParams.y; - - const float LOG2 = 1.442695; - float z = gl_FragCoord.z / gl_FragCoord.w; - float fogFactor = exp2(-density * density * z * z * LOG2); - - fogFactor = fogFactor * (1.0 - maxFog) + maxFog; - - fogFactor = clamp(fogFactor, 0.0, 1.0); - - return mix(fogColor, color, fogFactor); -} - void main() { #if BLEND // Use alpha from blend texture gl_FragColor.a = 1.0 - texture2D(blendTex, v_blend).a; #if USE_GRASS if (gl_FragColor.a < LAYER / 10.0) discard; #endif #else gl_FragColor.a = 1.0; #endif #if USE_TRIPLANAR vec4 tex = triplanar(baseTex, v_tex); #else vec4 tex = texture2D(baseTex, v_tex.xy); #endif #if USE_GRASS && LAYER if (tex.a < 0.05) discard; #endif #if DECAL // Use alpha from main texture gl_FragColor.a = tex.a; #endif vec3 texdiffuse = tex.rgb; #if USE_SPECULAR || USE_SPECULAR_MAP || USE_NORMAL_MAP vec3 normal = v_normal; #endif #if USE_NORMAL_MAP float sign = v_tangent.w; mat3 tbn = mat3(v_tangent.xyz, v_bitangent * -sign, v_normal); #if USE_TRIPLANAR vec3 ntex = triplanarNormals(normTex, v_tex).rgb * 2.0 - 1.0; #else vec3 ntex = texture2D(normTex, v_tex).rgb * 2.0 - 1.0; #endif normal = normalize(tbn * ntex); vec3 bumplight = max(dot(-sunDir, normal), 0.0) * sunColor; vec3 sundiffuse = (bumplight - v_lighting.rgb) * effectSettings.x + v_lighting.rgb; #else vec3 sundiffuse = v_lighting; #endif vec4 specular = vec4(0.0); #if USE_SPECULAR || USE_SPECULAR_MAP vec3 specCol; float specPow; #if USE_SPECULAR_MAP #if USE_TRIPLANAR vec4 s = triplanar(specTex, v_tex); #else vec4 s = texture2D(specTex, v_tex); #endif specCol = s.rgb; specular.a = s.a; specPow = effectSettings.y; #else specCol = specularColor; specPow = specularPower; #endif specular.rgb = sunColor * specCol * pow(max(0.0, dot(normalize(normal), v_half)), specPow); #endif vec3 color = (texdiffuse * sundiffuse + specular.rgb) * get_shadow() + texdiffuse * ambient; #if USE_SPECULAR_MAP && USE_SELF_LIGHT color = mix(texdiffuse, color, specular.a); #endif - #if USE_FOG - color = get_fog(color); - #endif + color = applyFog(color); float los = texture2D(losTex, v_los).a; los = los < 0.03 ? 0.0 : los; color *= los; #if DECAL color *= shadingColor; #endif gl_FragColor.rgb = color; #if USE_GRASS gl_FragColor.a = tex.a; #endif } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.vs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/terrain_common.vs (revision 24598) @@ -1,119 +1,106 @@ #version 120 +#include "common/shadows_vertex.h" + uniform mat4 transform; uniform vec3 cameraPos; #ifdef GL_ES uniform mediump vec3 sunDir; uniform mediump vec3 sunColor; #else uniform vec3 sunDir; uniform vec3 sunColor; #endif uniform vec2 textureTransform; uniform vec2 losTransform; -uniform mat4 shadowTransform; - -#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - uniform vec4 shadowScale; -#endif varying vec3 v_lighting; -#if USE_SHADOW - varying vec4 v_shadow; -#endif - varying vec2 v_los; varying vec2 v_blend; #if USE_TRIPLANAR varying vec3 v_tex; #else varying vec2 v_tex; #endif varying vec3 v_normal; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP #if USE_NORMAL_MAP varying vec4 v_tangent; varying vec3 v_bitangent; #endif #if USE_SPECULAR || USE_SPECULAR_MAP varying vec3 v_half; #endif #endif - attribute vec3 a_vertex; attribute vec3 a_normal; attribute vec2 a_uv0; attribute vec2 a_uv1; void main() { vec4 position = vec4(a_vertex, 1.0); #if USE_GRASS && LAYER position.y = a_vertex.y + (a_normal.y * 0.015 * LAYER); #endif gl_Position = transform * position; v_lighting = clamp(-dot(a_normal, sunDir), 0.0, 1.0) * sunColor; #if DECAL v_tex.xy = a_uv0; #else #if USE_TRIPLANAR v_tex = a_vertex; #else // Compute texcoords from position and terrain-texture-dependent transform float c = textureTransform.x; float s = -textureTransform.y; v_tex = vec2(a_vertex.x * c + a_vertex.z * -s, a_vertex.x * -s + a_vertex.z * -c); #endif #if GL_ES // XXX: Ugly hack to hide some precision issues in GLES #if USE_TRIPLANAR v_tex = mod(v_tex, vec3(9.0, 9.0, 9.0)); #else v_tex = mod(v_tex, vec2(9.0, 9.0)); #endif #endif #endif #if BLEND v_blend = a_uv1; #endif - #if USE_SHADOW - v_shadow = shadowTransform * vec4(a_vertex, 1.0); - #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - v_shadow.xy *= shadowScale.xy; - #endif - #endif + calculatePositionInShadowSpace(vec4(a_vertex, 1.0)); v_normal = a_normal; #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_TRIPLANAR #if USE_NORMAL_MAP vec3 t = vec3(1.0, 0.0, 0.0); t = normalize(t - v_normal * dot(v_normal, t)); v_tangent = vec4(t, -1.0); v_bitangent = cross(v_normal, t); #endif #if USE_SPECULAR || USE_SPECULAR_MAP vec3 eyeVec = cameraPos.xyz - position.xyz; #if USE_SPECULAR || USE_SPECULAR_MAP vec3 sunVec = -sunDir; v_half = normalize(sunVec + normalize(eyeVec)); #endif #endif #endif v_los = a_vertex.xz * losTransform.x + losTransform.yy; } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.fs (revision 24598) @@ -1,389 +1,337 @@ #version 110 +#include "common/fog.h" + +#if USE_SHADOWS_ON_WATER +#include "common/shadows_fragment.h" +#endif + // Environment settings uniform vec3 ambient; uniform vec3 sunDir; uniform vec3 sunColor; uniform mat4 skyBoxRot; uniform vec3 cameraPos; uniform sampler2D losTex; uniform float waviness; // "Wildness" of the reflections and refractions; choose based on texture uniform vec3 color; // color of the water uniform vec3 tint; // Tint for refraction (used to simulate particles in water) uniform float murkiness; // Amount of tint to blend in with the refracted color uniform float windAngle; varying vec2 WindCosSin; -uniform vec3 fogColor; -uniform vec2 fogParams; - uniform vec2 screenSize; varying float moddedTime; varying vec3 worldPos; varying float waterDepth; varying vec2 waterInfo; varying vec3 v_eyeVec; varying vec4 normalCoords; #if USE_REFLECTION varying vec3 reflectionCoords; #endif #if USE_REFRACTION varying vec3 refractionCoords; #endif varying vec2 losCoords; varying float fwaviness; uniform samplerCube skyCube; uniform sampler2D normalMap; uniform sampler2D normalMap2; #if USE_FANCY_EFFECTS uniform sampler2D waterEffectsTex; #endif uniform vec4 waveParams1; // wavyEffect, BaseScale, Flattenism, Basebump uniform vec4 waveParams2; // Smallintensity, Smallbase, Bigmovement, Smallmovement #if USE_REFLECTION uniform sampler2D reflectionMap; #endif #if USE_REFRACTION uniform sampler2D refractionMap; #if USE_REAL_DEPTH uniform sampler2D depthTex; uniform mat4 projInvTransform; uniform mat4 viewInvTransform; #endif #endif -#if USE_SHADOWS_ON_WATER && USE_SHADOW - varying vec4 v_shadow; - #if USE_SHADOW_SAMPLER - uniform sampler2DShadow shadowTex; - #if USE_SHADOW_PCF - uniform vec4 shadowScale; - #endif - #else - uniform sampler2D shadowTex; - #endif - float get_shadow(vec4 coords) - { - #if USE_SHADOWS_ON_WATER && !DISABLE_RECEIVE_SHADOWS - #if USE_SHADOW_SAMPLER - #if USE_SHADOW_PCF - vec2 offset = fract(coords.xy - 0.5); - vec4 size = vec4(offset + 1.0, 2.0 - offset); - vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (coords.xy - 0.5 * offset).xyxy) * shadowScale.zwzw; - return (1.0 / 9.0) * dot(size.zxzx * size.wwyy, - vec4(shadow2D(shadowTex, vec3(weight.zw, coords.z)).r, - shadow2D(shadowTex, vec3(weight.xw, coords.z)).r, - shadow2D(shadowTex, vec3(weight.zy, coords.z)).r, - shadow2D(shadowTex, vec3(weight.xy, coords.z)).r)); - #else - return shadow2D(shadowTex, coords.xyz).r; - #endif - #else - if (coords.z >= 1.0) - return 1.0; - return (coords.z <= texture2D(shadowTex, coords.xy).x ? 1.0 : 0.0); - #endif - #else - return 1.0; - #endif - } -#endif - // TODO: convert this to something not only for AABBs struct Ray { vec3 Origin; vec3 Direction; }; float IntersectBox (in Ray ray, in vec3 minimum, in vec3 maximum) { vec3 OMIN = ( minimum - ray.Origin ) / ray.Direction; vec3 OMAX = ( maximum - ray.Origin ) / ray.Direction; vec3 MAX = max ( OMAX, OMIN ); return min ( MAX.x, min ( MAX.y, MAX.z ) ); } -vec3 get_fog(vec3 color) -{ - float density = fogParams.x; - float maxFog = fogParams.y; - - const float LOG2 = 1.442695; - float z = gl_FragCoord.z / gl_FragCoord.w; - float fogFactor = exp2(-density * density * z * z * LOG2); - - fogFactor = fogFactor * (1.0 - maxFog) + maxFog; - - fogFactor = clamp(fogFactor, 0.0, 1.0); - - return mix(fogColor, color, fogFactor); -} - vec3 getNormal(vec4 fancyeffects) { float wavyEffect = waveParams1.r; float baseScale = waveParams1.g; float flattenism = waveParams1.b; float baseBump = waveParams1.a; float BigMovement = waveParams2.b; // This method uses 60 animated water frames. We're blending between each two frames // Scale the normal textures by waviness so that big waviness means bigger waves. vec3 ww1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; vec3 ww2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; vec3 wwInterp = mix(ww1, ww2, moddedTime) - vec3(0.5, 0.0, 0.5); ww1.x = wwInterp.x * WindCosSin.x - wwInterp.z * WindCosSin.y; ww1.z = wwInterp.x * WindCosSin.y + wwInterp.z * WindCosSin.x; ww1.y = wwInterp.y; // Flatten them based on waviness. vec3 normal = normalize(mix(vec3(0.0, 1.0, 0.0), ww1, clamp(baseBump + fwaviness / flattenism, 0.0, 1.0))); #if USE_FANCY_EFFECTS normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); normal.xz = mix(normal.xz, fancyeffects.rb, fancyeffects.a / 2.0); #else normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); #endif return vec3(-normal.x, normal.y, -normal.z); } vec3 getSpecular(vec3 normal, vec3 eyeVec) { // Specular lighting vectors vec3 specularVector = reflect(sunDir, normal); // pow is undefined for null or negative values, except on intel it seems. float specularIntensity = pow(max(dot(specularVector, eyeVec), 0.0), 100.0); // Workaround to fix too flattened water. specularIntensity = smoothstep(0.6, 1.0, specularIntensity) * 1.2; return clamp(specularIntensity * sunColor, 0.0, 1.0); } vec4 getReflection(vec3 normal, vec3 eyeVec) { // Reflections // 3 level of settings: // -If a player has refraction and reflection disabled, we return a gradient of blue based on the Y component. // -If a player has refraction OR reflection, we return a reflection of the actual skybox used. // -If a player has reflection enabled, we also return a reflection of actual entities where applicable. // reflMod reduces the intensity of reflections somewhat since they kind of wash refractions out otherwise. float reflMod = 0.75; vec3 eye = reflect(eyeVec, normal); #if USE_REFLECTION float refVY = clamp(eyeVec.y * 2.0, 0.05, 1.0); // Distort the reflection coords based on waves. vec2 reflCoords = (0.5 * reflectionCoords.xy - 15.0 * normal.zx / refVY) / reflectionCoords.z + 0.5; vec4 refTex = texture2D(reflectionMap, reflCoords); vec3 reflColor = refTex.rgb; // Interpolate between the sky color and nearby objects. // Only do this when alpha is rather low, or transparent leaves show up as extremely white. if (refTex.a < 0.4) reflColor = mix(textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb, refTex.rgb, refTex.a); // Let actual objects be reflected fully. reflMod = max(refTex.a, 0.75); #elif USE_REFRACTION vec3 reflColor = textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb; #else // !USE_REFLECTION && !USE_REFRACTION // Simplest case for reflection, return a gradient of blue based on Y component. vec3 reflColor = mix(vec3(0.76, 0.84, 0.92), vec3(0.24, 0.43, 0.71), -eye.y); #endif return vec4(reflColor, reflMod); } #if USE_REFRACTION && USE_REAL_DEPTH vec3 getWorldPositionFromRefractionDepth(vec2 uv) { float depth = texture2D(depthTex, uv).x; vec4 viewPosition = projInvTransform * (vec4((uv - vec2(0.5)) * 2.0, depth * 2.0 - 1.0, 1.0)); viewPosition /= viewPosition.w; vec3 refrWorldPos = (viewInvTransform * viewPosition).xyz; // Depth buffer precision errors can give heights above the water. refrWorldPos.y = min(refrWorldPos.y, worldPos.y); return refrWorldPos; } #endif vec4 getRefraction(vec3 normal, vec3 eyeVec, float depthLimit) { #if USE_REFRACTION && USE_REAL_DEPTH // Compute real depth at the target point. vec2 coords = (0.5 * refractionCoords.xy) / refractionCoords.z + 0.5; vec3 refrWorldPos = getWorldPositionFromRefractionDepth(coords); // Set depth to the depth at the undistorted point. float depth = distance(refrWorldPos, worldPos); #else // fake depth computation: take the value at the vertex, add some if we are looking at a more oblique angle. float depth = waterDepth / (min(0.5, eyeVec.y) * 1.5 * min(0.5, eyeVec.y) * 2.0); #endif #if USE_REFRACTION // for refraction we want to distort more as depth goes down. // 1) compute a distortion based on depth at the pixel. // 2) Re-sample the depth at the target point // 3) Sample refraction texture // distoFactor controls the amount of distortion relative to wave normals. float distoFactor = 0.5 + clamp(depth / 2.0, 0.0, 7.0); #if USE_REAL_DEPTH // Distort the texture coords under where the water is to simulate refraction. vec2 shiftedCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; vec3 refrWorldPos2 = getWorldPositionFromRefractionDepth(shiftedCoords); float newDepth = distance(refrWorldPos2, worldPos); // try to correct for fish. In general they'd look weirder without this fix. if (depth > newDepth + 3.0) distoFactor /= 2.0; // this in general will not fall on the fish but still look distorted. else depth = newDepth; #endif #if USE_FANCY_EFFECTS depth = max(depth, depthLimit); if (waterDepth < 0.0) depth = 0.0; #endif // Distort the texture coords under where the water is to simulate refraction. vec2 refrCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; vec3 refColor = texture2D(refractionMap, refrCoords).rgb; // Note, the refraction map is cleared using (255, 0, 0), so pixels outside of the water plane are pure red. // If we get a pure red fragment, use an undistorted/less distorted coord instead. // blur the refraction map, distoring using normal so that it looks more random than it really is // and thus looks much better. float blur = (0.1 + clamp(normal.x, -0.1, 0.1)) / refractionCoords.z; vec4 blurColor = vec4(refColor, 1.0); vec4 tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.x, blur + normal.z)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(-blur, blur + normal.z)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(-blur, -blur + normal.x)); blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.z, -blur)); blurColor += vec4(tex.rgb * tex.a, tex.a); blurColor /= blurColor.a; float blurFactor = (distoFactor / 7.0); refColor = (refColor + blurColor.rgb * blurFactor) / (1.0 + blurFactor); #else // !USE_REFRACTION #if USE_FANCY_EFFECTS depth = max(depth, depthLimit); #endif vec3 refColor = color; #endif // for refraction, we want to adjust the value by v.y slightly otherwise it gets too different between "from above" and "from the sides". // And it looks weird (again, we are not used to seeing water from above). float fixedVy = max(eyeVec.y, 0.01); float murky = mix(200.0, 0.1, pow(murkiness, 0.25)); // Apply water tint and murk color. float extFact = max(0.0, 1.0 - (depth * fixedVy / murky)); float ColextFact = max(0.0, 1.0 - (depth * fixedVy / murky)); vec3 colll = mix(refColor * tint, refColor, ColextFact); vec3 refrColor = mix(color, colll, extFact); float alpha = clamp(depth, 0.0, 1.0); #if !USE_REFRACTION alpha = (1.4 - extFact) * alpha; #endif return vec4(refrColor, alpha); } vec4 getFoam(vec4 fancyeffects, float shadow) { #if USE_FANCY_EFFECTS float wavyEffect = waveParams1.r; float baseScale = waveParams1.g; float BigMovement = waveParams2.b; vec3 foam1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; vec3 foam2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; vec3 foam3 = texture2D(normalMap, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; vec3 foam4 = texture2D(normalMap2, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; vec3 foaminterp = mix(foam1, foam2, moddedTime); foaminterp *= mix(foam3, foam4, moddedTime); foam1.x = abs(foaminterp.x * WindCosSin.x) + abs(foaminterp.z * WindCosSin.y); float alpha = (fancyeffects.g + pow(foam1.x * (3.0 + waviness), 2.6 - waviness / 5.5)) * 2.0; return vec4(sunColor * shadow + ambient, clamp(alpha, 0.0, 1.0)); #else return vec4(0.0); #endif } void main() { #if USE_FANCY_EFFECTS vec4 fancyeffects = texture2D(waterEffectsTex, gl_FragCoord.xy / screenSize); #else vec4 fancyeffects = vec4(0.0); #endif vec3 eyeVec = normalize(v_eyeVec); vec3 normal = getNormal(fancyeffects); vec4 refrColor = getRefraction(normal, eyeVec, fancyeffects.a); vec4 reflColor = getReflection(normal, eyeVec); // How perpendicular to the normal our view is. Used for fresnel. float ndotv = clamp(dot(normal, eyeVec), 0.0, 1.0); // Fresnel for "how much reflection vs how much refraction". float fresnel = clamp(((pow(1.1 - ndotv, 2.0)) * 1.5), 0.1, 0.75); // Approximation. I'm using 1.1 and not 1.0 because it causes artifacts, see #1714 vec3 specular = getSpecular(normal, eyeVec); #if USE_SHADOWS_ON_WATER && USE_SHADOW - float shadow = get_shadow(vec4(v_shadow.xy, v_shadow.zw)); + float shadow = get_shadow(); float fresShadow = mix(fresnel, fresnel * shadow, 0.05 + murkiness * 0.2); vec3 color = mix(refrColor.rgb, reflColor.rgb, fresShadow * reflColor.a); color += shadow * specular; vec4 foam = getFoam(fancyeffects, shadow); #else vec3 color = mix(refrColor.rgb, reflColor.rgb, fresnel * reflColor.a); color += specular; vec4 foam = getFoam(fancyeffects, 1.0); #endif color = clamp(mix(color, foam.rgb, foam.a), 0.0, 1.0); -#if USE_FOG - color = get_fog(color); -#endif + color = applyFog(color); float alpha = refrColor.a; float losMod = texture2D(losTex, losCoords.st).a; losMod = losMod < 0.03 ? 0.0 : losMod; gl_FragColor = vec4(color * losMod, alpha); } Index: ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.vs =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.vs (revision 24597) +++ ps/trunk/binaries/data/mods/public/shaders/glsl/water_high.vs (revision 24598) @@ -1,87 +1,79 @@ #version 110 +#if USE_SHADOWS_ON_WATER +#include "common/shadows_vertex.h" +#endif + uniform mat4 reflectionMatrix; uniform mat4 refractionMatrix; uniform mat4 losMatrix; -uniform mat4 shadowTransform; uniform float repeatScale; uniform float windAngle; // "Wildness" of the reflections and refractions; choose based on texture uniform float waviness; uniform vec3 sunDir; -#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - uniform vec4 shadowScale; -#endif - uniform float time; uniform mat4 transform; uniform vec3 cameraPos; varying float moddedTime; varying vec3 worldPos; varying float waterDepth; varying vec2 waterInfo; varying vec3 v_eyeVec; varying vec4 normalCoords; #if USE_REFLECTION varying vec3 reflectionCoords; #endif #if USE_REFRACTION varying vec3 refractionCoords; #endif varying vec2 losCoords; varying float fwaviness; varying vec2 WindCosSin; -#if USE_SHADOW && USE_SHADOWS_ON_WATER - varying vec4 v_shadow; -#endif - attribute vec3 a_vertex; attribute vec2 a_waterInfo; attribute vec3 a_otherPosition; void main() { worldPos = a_vertex; waterInfo = a_waterInfo; waterDepth = a_waterInfo.g; WindCosSin = vec2(cos(-windAngle), sin(-windAngle)); float newX = a_vertex.x * WindCosSin.x - a_vertex.z * WindCosSin.y; float newY = a_vertex.x * WindCosSin.y + a_vertex.z * WindCosSin.x; normalCoords = vec4(newX, newY, time, 0.0); normalCoords.xy *= repeatScale; // Projective texturing #if USE_REFLECTION reflectionCoords = (reflectionMatrix * vec4(a_vertex, 1.0)).rga; #endif #if USE_REFRACTION refractionCoords = (refractionMatrix * vec4(a_vertex, 1.0)).rga; #endif losCoords = (losMatrix * vec4(a_vertex, 1.0)).rg; -#if USE_SHADOW && USE_SHADOWS_ON_WATER - v_shadow = shadowTransform * vec4(a_vertex, 1.0); -#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF - v_shadow.xy *= shadowScale.xy; -#endif +#if USE_SHADOWS_ON_WATER + calculatePositionInShadowSpace(vec4(a_vertex, 1.0)); #endif v_eyeVec = normalize(cameraPos - worldPos); moddedTime = mod(time * 60.0, 8.0) / 8.0; // Fix the waviness for local wind strength fwaviness = waviness * (0.15 + a_waterInfo.r / 1.15); gl_Position = transform * vec4(a_vertex, 1.0); } Index: ps/trunk/source/graphics/ShaderProgram.cpp =================================================================== --- ps/trunk/source/graphics/ShaderProgram.cpp (revision 24597) +++ ps/trunk/source/graphics/ShaderProgram.cpp (revision 24598) @@ -1,917 +1,914 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "ShaderProgram.h" #include "graphics/Color.h" #include "graphics/PreprocessorWrapper.h" #include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" #include "lib/timer.h" #include "lib/res/graphics/ogl_tex.h" #include "maths/Matrix3D.h" #include "maths/Vector3D.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #if !CONFIG2_GLES class CShaderProgramARB : public CShaderProgram { public: CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexIndexes, const std::map& fragmentIndexes, int streamflags) : CShaderProgram(streamflags), m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), m_Defines(defines), m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes) { pglGenProgramsARB(1, &m_VertexProgram); pglGenProgramsARB(1, &m_FragmentProgram); } ~CShaderProgramARB() { Unload(); pglDeleteProgramsARB(1, &m_VertexProgram); pglDeleteProgramsARB(1, &m_FragmentProgram); } bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code) { ogl_WarnIfError(); pglBindProgramARB(target, program); ogl_WarnIfError(); pglProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str()); if (ogl_SquelchError(GL_INVALID_OPERATION)) { GLint errPos = 0; glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1; char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB); LOGERROR("Failed to compile %s program '%s' (line %d):\n%s", targetName, file.string8(), errLine, errStr); return false; } pglBindProgramARB(target, 0); ogl_WarnIfError(); return true; } virtual void Reload() { Unload(); CVFSFile vertexFile; if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) return; CVFSFile fragmentFile; if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) return; CPreprocessorWrapper preprocessor; preprocessor.AddDefines(m_Defines); CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); -// printf(">>>\n%s<<<\n", vertexCode.c_str()); -// printf(">>>\n%s<<<\n", fragmentCode.c_str()); - if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode)) return; if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode)) return; m_IsValid = true; } void Unload() { m_IsValid = false; } virtual void Bind() { glEnable(GL_VERTEX_PROGRAM_ARB); glEnable(GL_FRAGMENT_PROGRAM_ARB); pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram); pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram); BindClientStates(); } virtual void Unbind() { glDisable(GL_VERTEX_PROGRAM_ARB); glDisable(GL_FRAGMENT_PROGRAM_ARB); pglBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); pglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); UnbindClientStates(); // TODO: should unbind textures, probably } int GetUniformVertexIndex(CStrIntern id) { std::map::iterator it = m_VertexIndexes.find(id); if (it == m_VertexIndexes.end()) return -1; return it->second; } frag_index_pair_t GetUniformFragmentIndex(CStrIntern id) { std::map::iterator it = m_FragmentIndexes.find(id); if (it == m_FragmentIndexes.end()) return std::make_pair(-1, 0); return it->second; } virtual Binding GetTextureBinding(texture_id_t id) { frag_index_pair_t fPair = GetUniformFragmentIndex(id); int index = fPair.first; if (index == -1) return Binding(); else return Binding((int)fPair.second, index); } virtual void BindTexture(texture_id_t id, Handle tex) { frag_index_pair_t fPair = GetUniformFragmentIndex(id); int index = fPair.first; if (index != -1) { GLuint h; ogl_tex_get_texture_id(tex, &h); pglActiveTextureARB(GL_TEXTURE0+index); glBindTexture(fPair.second, h); } } virtual void BindTexture(texture_id_t id, GLuint tex) { frag_index_pair_t fPair = GetUniformFragmentIndex(id); int index = fPair.first; if (index != -1) { pglActiveTextureARB(GL_TEXTURE0+index); glBindTexture(fPair.second, tex); } } virtual void BindTexture(Binding id, Handle tex) { int index = id.second; if (index != -1) ogl_tex_bind(tex, index); } virtual Binding GetUniformBinding(uniform_id_t id) { return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id).first); } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.first != -1) pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3); if (id.second != -1) pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3); } virtual void Uniform(Binding id, const CMatrix3D& v) { if (id.first != -1) { pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+0, v._11, v._12, v._13, v._14); pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+1, v._21, v._22, v._23, v._24); pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+2, v._31, v._32, v._33, v._34); pglProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+3, v._41, v._42, v._43, v._44); } if (id.second != -1) { pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+0, v._11, v._12, v._13, v._14); pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+1, v._21, v._22, v._23, v._24); pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+2, v._31, v._32, v._33, v._34); pglProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+3, v._41, v._42, v._43, v._44); } } virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) { ENSURE(count == 1); Uniform(id, v[0]); } virtual std::vector GetFileDependencies() const override { return {m_VertexFile, m_FragmentFile}; } private: VfsPath m_VertexFile; VfsPath m_FragmentFile; CShaderDefines m_Defines; GLuint m_VertexProgram; GLuint m_FragmentProgram; std::map m_VertexIndexes; // pair contains std::map m_FragmentIndexes; }; #endif // #if !CONFIG2_GLES ////////////////////////////////////////////////////////////////////////// TIMER_ADD_CLIENT(tc_ShaderGLSLCompile); TIMER_ADD_CLIENT(tc_ShaderGLSLLink); class CShaderProgramGLSL : public CShaderProgram { public: CShaderProgramGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexAttribs, int streamflags) : CShaderProgram(streamflags), m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), m_Defines(defines), m_VertexAttribs(vertexAttribs) { m_Program = 0; m_VertexShader = pglCreateShaderObjectARB(GL_VERTEX_SHADER); m_FragmentShader = pglCreateShaderObjectARB(GL_FRAGMENT_SHADER); m_FileDependencies = {m_VertexFile, m_FragmentFile}; } ~CShaderProgramGLSL() { Unload(); pglDeleteShader(m_VertexShader); pglDeleteShader(m_FragmentShader); } bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code) { TIMER_ACCRUE(tc_ShaderGLSLCompile); ogl_WarnIfError(); const char* code_string = code.c_str(); GLint code_length = code.length(); pglShaderSourceARB(shader, 1, &code_string, &code_length); pglCompileShaderARB(shader); GLint ok = 0; pglGetShaderiv(shader, GL_COMPILE_STATUS, &ok); GLint length = 0; pglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); // Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0 // (http://code.google.com/p/android/issues/detail?id=9953) if (!ok && length == 0) length = 4096; if (length > 1) { char* infolog = new char[length]; pglGetShaderInfoLog(shader, length, NULL, infolog); if (ok) LOGMESSAGE("Info when compiling shader '%s':\n%s", file.string8(), infolog); else LOGERROR("Failed to compile shader '%s':\n%s", file.string8(), infolog); delete[] infolog; } ogl_WarnIfError(); return (ok ? true : false); } bool Link() { TIMER_ACCRUE(tc_ShaderGLSLLink); ENSURE(!m_Program); m_Program = pglCreateProgramObjectARB(); pglAttachObjectARB(m_Program, m_VertexShader); ogl_WarnIfError(); pglAttachObjectARB(m_Program, m_FragmentShader); ogl_WarnIfError(); // Set up the attribute bindings explicitly, since apparently drivers // don't always pick the most efficient bindings automatically, // and also this lets us hardcode indexes into VertexPointer etc for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglBindAttribLocationARB(m_Program, it->second, it->first.c_str()); pglLinkProgramARB(m_Program); GLint ok = 0; pglGetProgramiv(m_Program, GL_LINK_STATUS, &ok); GLint length = 0; pglGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length); if (!ok && length == 0) length = 4096; if (length > 1) { char* infolog = new char[length]; pglGetProgramInfoLog(m_Program, length, NULL, infolog); if (ok) LOGMESSAGE("Info when linking program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); else LOGERROR("Failed to link program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); delete[] infolog; } ogl_WarnIfError(); if (!ok) return false; m_Uniforms.clear(); m_Samplers.clear(); Bind(); ogl_WarnIfError(); GLint numUniforms = 0; pglGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms); ogl_WarnIfError(); for (GLint i = 0; i < numUniforms; ++i) { char name[256] = {0}; GLsizei nameLength = 0; GLint size = 0; GLenum type = 0; pglGetActiveUniformARB(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name); ogl_WarnIfError(); GLint loc = pglGetUniformLocationARB(m_Program, name); CStrIntern nameIntern(name); m_Uniforms[nameIntern] = std::make_pair(loc, type); // Assign sampler uniforms to sequential texture units if (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE #if !CONFIG2_GLES || type == GL_SAMPLER_2D_SHADOW #endif ) { int unit = (int)m_Samplers.size(); m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); m_Samplers[nameIntern].second = unit; pglUniform1iARB(loc, unit); // link uniform to unit ogl_WarnIfError(); } } // TODO: verify that we're not using more samplers than is supported Unbind(); ogl_WarnIfError(); return true; } virtual void Reload() { Unload(); CVFSFile vertexFile; if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) return; CVFSFile fragmentFile; if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) return; std::vector newFileDependencies = {m_VertexFile, m_FragmentFile}; CPreprocessorWrapper preprocessor([&newFileDependencies](const CStr& includePath, CStr& out) -> bool { const VfsPath includeFilePath(L"shaders/glsl/" + wstring_from_utf8(includePath)); CVFSFile includeFile; if (includeFile.Load(g_VFS, includeFilePath) != PSRETURN_OK) return false; out = includeFile.GetAsString(); newFileDependencies.push_back(includeFilePath); return true; }); preprocessor.AddDefines(m_Defines); #if CONFIG2_GLES // GLES defines the macro "GL_ES" in its GLSL preprocessor, // but since we run our own preprocessor first, we need to explicitly // define it here preprocessor.AddDefine("GL_ES", "1"); #endif CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); m_FileDependencies = std::move(newFileDependencies); #if CONFIG2_GLES // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00, // and also to set default float precision for fragment shaders vertexCode.Replace("#version 110\n", "#version 100\n"); vertexCode.Replace("#version 110\r\n", "#version 100\n"); vertexCode.Replace("#version 120\n", "#version 100\n"); vertexCode.Replace("#version 120\r\n", "#version 100\n"); fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n"); fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n"); fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n"); fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n"); #endif if (!Compile(m_VertexShader, m_VertexFile, vertexCode)) return; if (!Compile(m_FragmentShader, m_FragmentFile, fragmentCode)) return; if (!Link()) return; m_IsValid = true; } void Unload() { m_IsValid = false; if (m_Program) pglDeleteProgram(m_Program); m_Program = 0; // The shader objects can be reused and don't need to be deleted here } virtual void Bind() { pglUseProgramObjectARB(m_Program); for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglEnableVertexAttribArrayARB(it->second); } virtual void Unbind() { pglUseProgramObjectARB(0); for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglDisableVertexAttribArrayARB(it->second); // TODO: should unbind textures, probably } virtual Binding GetTextureBinding(texture_id_t id) { std::map >::iterator it = m_Samplers.find(CStrIntern(id)); if (it == m_Samplers.end()) return Binding(); else return Binding((int)it->second.first, it->second.second); } virtual void BindTexture(texture_id_t id, Handle tex) { std::map >::iterator it = m_Samplers.find(CStrIntern(id)); if (it == m_Samplers.end()) return; GLuint h; ogl_tex_get_texture_id(tex, &h); pglActiveTextureARB(GL_TEXTURE0 + it->second.second); glBindTexture(it->second.first, h); } virtual void BindTexture(texture_id_t id, GLuint tex) { std::map >::iterator it = m_Samplers.find(CStrIntern(id)); if (it == m_Samplers.end()) return; pglActiveTextureARB(GL_TEXTURE0 + it->second.second); glBindTexture(it->second.first, tex); } virtual void BindTexture(Binding id, Handle tex) { if (id.second == -1) return; GLuint h; ogl_tex_get_texture_id(tex, &h); pglActiveTextureARB(GL_TEXTURE0 + id.second); glBindTexture(id.first, h); } virtual Binding GetUniformBinding(uniform_id_t id) { std::map >::iterator it = m_Uniforms.find(id); if (it == m_Uniforms.end()) return Binding(); else return Binding(it->second.first, (int)it->second.second); } virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) { if (id.first != -1) { if (id.second == GL_FLOAT) pglUniform1fARB(id.first, v0); else if (id.second == GL_FLOAT_VEC2) pglUniform2fARB(id.first, v0, v1); else if (id.second == GL_FLOAT_VEC3) pglUniform3fARB(id.first, v0, v1, v2); else if (id.second == GL_FLOAT_VEC4) pglUniform4fARB(id.first, v0, v1, v2, v3); else LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float, vec2, vec3, vec4)"); } } virtual void Uniform(Binding id, const CMatrix3D& v) { if (id.first != -1) { if (id.second == GL_FLOAT_MAT4) pglUniformMatrix4fvARB(id.first, 1, GL_FALSE, &v._11); else LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); } } virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) { if (id.first != -1) { if (id.second == GL_FLOAT_MAT4) pglUniformMatrix4fvARB(id.first, count, GL_FALSE, &v->_11); else LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); } } // Map the various fixed-function Pointer functions onto generic vertex attributes // (matching the attribute indexes from ShaderManager's ParseAttribSemantics): virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) { pglVertexAttribPointerARB(0, size, type, GL_FALSE, stride, pointer); m_ValidStreams |= STREAM_POS; } virtual void NormalPointer(GLenum type, GLsizei stride, const void* pointer) { pglVertexAttribPointerARB(2, 3, type, GL_TRUE, stride, pointer); m_ValidStreams |= STREAM_NORMAL; } virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) { pglVertexAttribPointerARB(3, size, type, GL_TRUE, stride, pointer); m_ValidStreams |= STREAM_COLOR; } virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const void* pointer) { pglVertexAttribPointerARB(8 + texture - GL_TEXTURE0, size, type, GL_FALSE, stride, pointer); m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); } virtual void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) { std::map::iterator it = m_VertexAttribs.find(id); if (it != m_VertexAttribs.end()) { pglVertexAttribPointerARB(it->second, size, type, normalized, stride, pointer); } } virtual void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, const void* pointer) { std::map::iterator it = m_VertexAttribs.find(id); if (it != m_VertexAttribs.end()) { #if CONFIG2_GLES debug_warn(L"glVertexAttribIPointer not supported on GLES"); #else pglVertexAttribIPointerEXT(it->second, size, type, stride, pointer); #endif } } virtual std::vector GetFileDependencies() const { return m_FileDependencies; } private: VfsPath m_VertexFile; VfsPath m_FragmentFile; std::vector m_FileDependencies; CShaderDefines m_Defines; std::map m_VertexAttribs; GLhandleARB m_Program; GLhandleARB m_VertexShader; GLhandleARB m_FragmentShader; std::map > m_Uniforms; std::map > m_Samplers; // texture target & unit chosen for each uniform sampler }; ////////////////////////////////////////////////////////////////////////// CShaderProgram::CShaderProgram(int streamflags) : m_IsValid(false), m_StreamFlags(streamflags), m_ValidStreams(0) { } #if CONFIG2_GLES /*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& UNUSED(defines), const std::map& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes), int UNUSED(streamflags)) { LOGERROR("CShaderProgram::ConstructARB: '%s'+'%s': ARB shaders not supported on this device", vertexFile.string8(), fragmentFile.string8()); return NULL; } #else /*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexIndexes, const std::map& fragmentIndexes, int streamflags) { return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags); } #endif /*static*/ CShaderProgram* CShaderProgram::ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, const std::map& vertexAttribs, int streamflags) { return new CShaderProgramGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamflags); } bool CShaderProgram::IsValid() const { return m_IsValid; } int CShaderProgram::GetStreamFlags() const { return m_StreamFlags; } void CShaderProgram::BindTexture(texture_id_t id, CTexturePtr tex) { BindTexture(id, tex->GetHandle()); } void CShaderProgram::Uniform(Binding id, int v) { Uniform(id, (float)v, (float)v, (float)v, (float)v); } void CShaderProgram::Uniform(Binding id, float v) { Uniform(id, v, v, v, v); } void CShaderProgram::Uniform(Binding id, float v0, float v1) { Uniform(id, v0, v1, 0.0f, 0.0f); } void CShaderProgram::Uniform(Binding id, const CVector3D& v) { Uniform(id, v.X, v.Y, v.Z, 0.0f); } void CShaderProgram::Uniform(Binding id, const CColor& v) { Uniform(id, v.r, v.g, v.b, v.a); } void CShaderProgram::Uniform(uniform_id_t id, int v) { Uniform(GetUniformBinding(id), (float)v, (float)v, (float)v, (float)v); } void CShaderProgram::Uniform(uniform_id_t id, float v) { Uniform(GetUniformBinding(id), v, v, v, v); } void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1) { Uniform(GetUniformBinding(id), v0, v1, 0.0f, 0.0f); } void CShaderProgram::Uniform(uniform_id_t id, const CVector3D& v) { Uniform(GetUniformBinding(id), v.X, v.Y, v.Z, 0.0f); } void CShaderProgram::Uniform(uniform_id_t id, const CColor& v) { Uniform(GetUniformBinding(id), v.r, v.g, v.b, v.a); } void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1, float v2, float v3) { Uniform(GetUniformBinding(id), v0, v1, v2, v3); } void CShaderProgram::Uniform(uniform_id_t id, const CMatrix3D& v) { Uniform(GetUniformBinding(id), v); } void CShaderProgram::Uniform(uniform_id_t id, size_t count, const CMatrix3D* v) { Uniform(GetUniformBinding(id), count, v); } // These should all be overridden by CShaderProgramGLSL, and not used // if a non-GLSL shader was loaded instead: void CShaderProgram::VertexAttribPointer(attrib_id_t UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type), GLboolean UNUSED(normalized), GLsizei UNUSED(stride), const void* UNUSED(pointer)) { debug_warn("Shader type doesn't support VertexAttribPointer"); } void CShaderProgram::VertexAttribIPointer(attrib_id_t UNUSED(id), GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) { debug_warn("Shader type doesn't support VertexAttribIPointer"); } #if CONFIG2_GLES // These should all be overridden by CShaderProgramGLSL // (GLES doesn't support any other types of shader program): void CShaderProgram::VertexPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) { debug_warn("CShaderProgram::VertexPointer should be overridden"); } void CShaderProgram::NormalPointer(GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) { debug_warn("CShaderProgram::NormalPointer should be overridden"); } void CShaderProgram::ColorPointer(GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) { debug_warn("CShaderProgram::ColorPointer should be overridden"); } void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), GLint UNUSED(size), GLenum UNUSED(type), GLsizei UNUSED(stride), const void* UNUSED(pointer)) { debug_warn("CShaderProgram::TexCoordPointer should be overridden"); } #else // These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders // both use the fixed-function vertex attribute pointers so we'll share their // definitions here: void CShaderProgram::VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) { glVertexPointer(size, type, stride, pointer); m_ValidStreams |= STREAM_POS; } void CShaderProgram::NormalPointer(GLenum type, GLsizei stride, const void* pointer) { glNormalPointer(type, stride, pointer); m_ValidStreams |= STREAM_NORMAL; } void CShaderProgram::ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) { glColorPointer(size, type, stride, pointer); m_ValidStreams |= STREAM_COLOR; } void CShaderProgram::TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const void* pointer) { pglClientActiveTextureARB(texture); glTexCoordPointer(size, type, stride, pointer); pglClientActiveTextureARB(GL_TEXTURE0); m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); } void CShaderProgram::BindClientStates() { ENSURE(m_StreamFlags == (m_StreamFlags & (STREAM_POS|STREAM_NORMAL|STREAM_COLOR|STREAM_UV0|STREAM_UV1))); // Enable all the desired client states for non-GLSL rendering if (m_StreamFlags & STREAM_POS) glEnableClientState(GL_VERTEX_ARRAY); if (m_StreamFlags & STREAM_NORMAL) glEnableClientState(GL_NORMAL_ARRAY); if (m_StreamFlags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY); if (m_StreamFlags & STREAM_UV0) { pglClientActiveTextureARB(GL_TEXTURE0); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } if (m_StreamFlags & STREAM_UV1) { pglClientActiveTextureARB(GL_TEXTURE1); glEnableClientState(GL_TEXTURE_COORD_ARRAY); pglClientActiveTextureARB(GL_TEXTURE0); } // Rendering code must subsequently call VertexPointer etc for all of the streams // that were activated in this function, else AssertPointersBound will complain // that some arrays were unspecified m_ValidStreams = 0; } void CShaderProgram::UnbindClientStates() { if (m_StreamFlags & STREAM_POS) glDisableClientState(GL_VERTEX_ARRAY); if (m_StreamFlags & STREAM_NORMAL) glDisableClientState(GL_NORMAL_ARRAY); if (m_StreamFlags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY); if (m_StreamFlags & STREAM_UV0) { pglClientActiveTextureARB(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } if (m_StreamFlags & STREAM_UV1) { pglClientActiveTextureARB(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); pglClientActiveTextureARB(GL_TEXTURE0); } } #endif // !CONFIG2_GLES void CShaderProgram::AssertPointersBound() { ENSURE((m_StreamFlags & ~m_ValidStreams) == 0); }