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);
}