summaryrefslogtreecommitdiff
path: root/shaders/warsow/10.shader_test
diff options
context:
space:
mode:
Diffstat (limited to 'shaders/warsow/10.shader_test')
-rw-r--r--shaders/warsow/10.shader_test1968
1 files changed, 1471 insertions, 497 deletions
diff --git a/shaders/warsow/10.shader_test b/shaders/warsow/10.shader_test
index de4bd35..93aaa73 100644
--- a/shaders/warsow/10.shader_test
+++ b/shaders/warsow/10.shader_test
@@ -1,695 +1,1669 @@
[require]
GLSL >= 1.10
-[fragment shader]
-#define FRAGMENT_SHADER
-#define APPLY_LIGHTSTYLE0
-#define APPLY_FBLIGHTMAP
-#define APPLY_SPECULAR
-#define APPLY_AMBIENT_COMPENSATION
-// Warsow GLSL shader
-
-#if !defined(__GLSL_CG_DATA_TYPES)
+[vertex shader]
+#version 130
+#extension GL_ARB_draw_instanced : enable
+#define QF_GLSL_VERSION 130
+#define VERTEX_SHADER
+#if !defined(myhalf)
+//#if !defined(__GLSL_CG_DATA_TYPES)
#define myhalf float
#define myhalf2 vec2
#define myhalf3 vec3
#define myhalf4 vec4
+//#else
+//#define myhalf half
+//#define myhalf2 half2
+//#define myhalf3 half3
+//#define myhalf4 half4
+//#endif
+#endif
+
+#if QF_GLSL_VERSION >= 130
+ precision highp float;
+
+# ifdef VERTEX_SHADER
+ out myhalf4 qf_FrontColor;
+# define qf_varying out
+# define qf_attribute in
+# endif
+# ifdef FRAGMENT_SHADER
+ in myhalf4 qf_FrontColor;
+ out myhalf4 qf_FragColor;
+# define qf_varying in
+# define qf_attribute in
+# endif
+
+# define qf_texture texture
+# define qf_textureCube texture
+# define qf_textureLod textureLod
+# define qf_textureOffset(a,b,c,d) textureOffset(a,b,ivec2(c,d))
+# define qf_shadow texture
#else
-#define myhalf half
-#define myhalf2 half2
-#define myhalf3 half3
-#define myhalf4 half4
+# ifdef VERTEX_SHADER
+# define qf_FrontColor gl_FrontColor
+# define qf_varying varying
+# define qf_attribute attribute
+# endif
+
+# ifdef FRAGMENT_SHADER
+# define qf_FrontColor gl_Color
+# define qf_FragColor gl_FragColor
+# define qf_varying varying
+# define qf_attribute attribute
+# endif
+# define qf_texture texture2D
+# define qf_textureLod texture2DLod
+# define qf_textureCube textureCube
+# define qf_textureOffset(a,b,c,d) texture2DOffset(a,b,ivec2(c,d))
+# define qf_shadow shadow2D
#endif
-varying vec2 TexCoord;
-#ifdef APPLY_LIGHTSTYLE0
-varying vec4 LightmapTexCoord01;
-#ifdef APPLY_LIGHTSTYLE2
-varying vec4 LightmapTexCoord23;
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_TWOPI
+#define M_TWOPI 6.28318530717958647692
#endif
+
+#ifndef MAX_UNIFORM_BONES
+#define MAX_UNIFORM_BONES 100
#endif
-#if defined(APPLY_SPECULAR) || defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-varying vec3 EyeVector;
+#ifndef MAX_UNIFORM_INSTANCES
+#define MAX_UNIFORM_INSTANCES 40
#endif
+uniform vec3 u_QF_ViewOrigin;
+uniform mat3 u_QF_ViewAxis;
+uniform float u_QF_MirrorSide;
+uniform vec3 u_QF_EntityOrigin;
+uniform float u_QF_ShaderTime;
-#ifdef APPLY_DIRECTIONAL_LIGHT
-varying vec3 LightVector;
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_TWOPI
+#define M_TWOPI 6.28318530717958647692
#endif
-varying mat3 strMatrix; // directions of S/T/R texcoords (tangent, binormal, normal)
+#ifndef WAVE_SIN
+float QF_WaveFunc_Sin(float x)
+{
+x -= floor(x);
+return sin(x * M_TWOPI);
+}
+float QF_WaveFunc_Triangle(float x)
+{
+x -= floor(x);
+return step(x, 0.25) * x * 4.0 + (2.0 - 4.0 * step(0.25, x) * step(x, 0.75) * x) + ((step(0.75, x) * x - 0.75) * 4.0 - 1.0);
+}
+float QF_WaveFunc_Square(float x)
+{
+x -= floor(x);
+return step(x, 0.5) * 2.0 - 1.0;
+}
+float QF_WaveFunc_Sawtooth(float x)
+{
+x -= floor(x);
+return x;
+}
+float QF_QF_WaveFunc_InverseSawtooth(float x)
+{
+x -= floor(x);
+return 1.0 - x;
+}
+
+#define WAVE_SIN(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Sin((phase)+(time)*(freq))))
+#define WAVE_TRIANGLE(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Triangle((phase)+(time)*(freq))))
+#define WAVE_SQUARE(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Square((phase)+(time)*(freq))))
+#define WAVE_SAWTOOTH(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Sawtooth((phase)+(time)*(freq))))
+#define WAVE_INVERSESAWTOOTH(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_QF_WaveFunc_InverseSawtooth((phase)+(time)*(freq))))
+#endif
#ifdef VERTEX_SHADER
-// Vertex shader
+attribute vec4 a_BonesIndices;
+attribute vec4 a_BonesWeights;
-uniform vec3 EyeOrigin;
+uniform vec4 u_QF_DualQuats[MAX_UNIFORM_BONES*2];
-#ifdef APPLY_DIRECTIONAL_LIGHT
-uniform vec3 LightDir;
+#if defined(DUAL_QUAT_TRANSFORM_NORMALS)
+#if defined(DUAL_QUAT_TRANSFORM_TANGENT)
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal, inout vec3 Tangent)
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal)
+#endif
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position)
#endif
+{
+int index;
+vec4 Indices = a_BonesIndices;
+vec4 Weights = a_BonesWeights;
+vec4 Indices_2 = Indices * 2.0;
+vec4 DQReal, DQDual;
-void main()
+index = int(Indices_2.x);
+DQReal = u_QF_DualQuats[index+0];
+DQDual = u_QF_DualQuats[index+1];
+
+if (numWeights > 1)
{
-gl_FrontColor = gl_Color;
+DQReal *= Weights.x;
+DQDual *= Weights.x;
-TexCoord = vec2 (gl_TextureMatrix[0] * gl_MultiTexCoord0);
+vec4 DQReal1, DQDual1;
+float scale;
-#ifdef APPLY_LIGHTSTYLE0
-LightmapTexCoord01.st = gl_MultiTexCoord4.st;
-#ifdef APPLY_LIGHTSTYLE1
-LightmapTexCoord01.pq = gl_MultiTexCoord5.st;
-#ifdef APPLY_LIGHTSTYLE2
-LightmapTexCoord23.st = gl_MultiTexCoord6.st;
-#ifdef APPLY_LIGHTSTYLE3
-LightmapTexCoord23.pq = gl_MultiTexCoord7.st;
-#endif
-#endif
-#endif
-#endif
+index = int(Indices_2.y);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.y;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 2)
+{
+index = int(Indices_2.z);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.z;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 3)
+{
+index = int(Indices_2.w);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.w;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+}
+}
+}
+
+float len = length(DQReal);
+DQReal /= len;
+DQDual /= len;
-strMatrix[0] = gl_MultiTexCoord1.xyz;
-strMatrix[2] = gl_Normal.xyz;
-strMatrix[1] = gl_MultiTexCoord1.w * cross (strMatrix[2], strMatrix[0]);
+Position.xyz = (cross(DQReal.xyz, cross(DQReal.xyz, Position.xyz) + Position.xyz*DQReal.w + DQDual.xyz) + DQDual.xyz*DQReal.w - DQReal.xyz*DQDual.w)*2.0 + Position.xyz;
-#if defined(APPLY_SPECULAR) || defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-vec3 EyeVectorWorld = EyeOrigin - gl_Vertex.xyz;
-EyeVector = EyeVectorWorld * strMatrix;
+#ifdef DUAL_QUAT_TRANSFORM_NORMALS
+Normal = cross(DQReal.xyz, cross(DQReal.xyz, Normal) + Normal*DQReal.w)*2.0 + Normal;
#endif
-#ifdef APPLY_DIRECTIONAL_LIGHT
-LightVector = LightDir * strMatrix;
+#ifdef DUAL_QUAT_TRANSFORM_TANGENT
+Tangent = cross(DQReal.xyz, cross(DQReal.xyz, Tangent) + Tangent*DQReal.w)*2.0 + Tangent;
#endif
+}
+
+// use defines to overload the transform function
-gl_Position = ftransform ();
-#ifdef APPLY_CLIPPING
-#ifdef __GLSL_CG_DATA_TYPES
-gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+#define DUAL_QUAT_TRANSFORM_NORMALS
+#if defined(DUAL_QUAT_TRANSFORM_NORMALS)
+#if defined(DUAL_QUAT_TRANSFORM_TANGENT)
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal, inout vec3 Tangent)
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal)
#endif
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position)
#endif
-}
+{
+int index;
+vec4 Indices = a_BonesIndices;
+vec4 Weights = a_BonesWeights;
+vec4 Indices_2 = Indices * 2.0;
+vec4 DQReal, DQDual;
-#endif // VERTEX_SHADER
+index = int(Indices_2.x);
+DQReal = u_QF_DualQuats[index+0];
+DQDual = u_QF_DualQuats[index+1];
+if (numWeights > 1)
+{
+DQReal *= Weights.x;
+DQDual *= Weights.x;
-#ifdef FRAGMENT_SHADER
-// Fragment shader
+vec4 DQReal1, DQDual1;
+float scale;
-#ifdef APPLY_LIGHTSTYLE0
-uniform sampler2D LightmapTexture0;
-uniform float DeluxemapOffset0; // s-offset for LightmapTexCoord
-uniform myhalf3 lsColor0; // lightstyle color
+index = int(Indices_2.y);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.y;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
-#ifdef APPLY_LIGHTSTYLE1
-uniform sampler2D LightmapTexture1;
-uniform float DeluxemapOffset1;
-uniform myhalf3 lsColor1;
+if (numWeights > 2)
+{
+index = int(Indices_2.z);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.z;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 3)
+{
+index = int(Indices_2.w);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.w;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+}
+}
+}
-#ifdef APPLY_LIGHTSTYLE2
-uniform sampler2D LightmapTexture2;
-uniform float DeluxemapOffset2;
-uniform myhalf3 lsColor2;
+float len = length(DQReal);
+DQReal /= len;
+DQDual /= len;
-#ifdef APPLY_LIGHTSTYLE3
-uniform sampler2D LightmapTexture3;
-uniform float DeluxemapOffset3;
-uniform myhalf3 lsColor3;
+Position.xyz = (cross(DQReal.xyz, cross(DQReal.xyz, Position.xyz) + Position.xyz*DQReal.w + DQDual.xyz) + DQDual.xyz*DQReal.w - DQReal.xyz*DQDual.w)*2.0 + Position.xyz;
+#ifdef DUAL_QUAT_TRANSFORM_NORMALS
+Normal = cross(DQReal.xyz, cross(DQReal.xyz, Normal) + Normal*DQReal.w)*2.0 + Normal;
#endif
+
+#ifdef DUAL_QUAT_TRANSFORM_TANGENT
+Tangent = cross(DQReal.xyz, cross(DQReal.xyz, Tangent) + Tangent*DQReal.w)*2.0 + Tangent;
#endif
+}
+
+#define DUAL_QUAT_TRANSFORM_TANGENT
+#if defined(DUAL_QUAT_TRANSFORM_NORMALS)
+#if defined(DUAL_QUAT_TRANSFORM_TANGENT)
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal, inout vec3 Tangent)
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal)
#endif
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position)
#endif
+{
+int index;
+vec4 Indices = a_BonesIndices;
+vec4 Weights = a_BonesWeights;
+vec4 Indices_2 = Indices * 2.0;
+vec4 DQReal, DQDual;
-uniform sampler2D BaseTexture;
-uniform sampler2D NormalmapTexture;
-uniform sampler2D GlossTexture;
-#ifdef APPLY_DECAL
-uniform sampler2D DecalTexture;
-#endif
+index = int(Indices_2.x);
+DQReal = u_QF_DualQuats[index+0];
+DQDual = u_QF_DualQuats[index+1];
-#if defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-uniform float OffsetMappingScale;
-#endif
+if (numWeights > 1)
+{
+DQReal *= Weights.x;
+DQDual *= Weights.x;
-uniform myhalf3 LightAmbient;
-#ifdef APPLY_DIRECTIONAL_LIGHT
-uniform myhalf3 LightDiffuse;
-#endif
+vec4 DQReal1, DQDual1;
+float scale;
-uniform myhalf GlossIntensity; // gloss scaling factor
-uniform myhalf GlossExponent; // gloss exponent factor
+index = int(Indices_2.y);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.y;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
-#if defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-// The following reliefmapping and offsetmapping routine was taken from DarkPlaces
-// The credit goes to LordHavoc (as always)
-vec2 OffsetMapping(vec2 TexCoord)
+if (numWeights > 2)
{
-#ifdef APPLY_RELIEFMAPPING
-// 14 sample relief mapping: linear search and then binary search
-// this basically steps forward a small amount repeatedly until it finds
-// itself inside solid, then jitters forward and back using decreasing
-// amounts to find the impact
-//vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMappingScale) * vec2(-1, 1), -1);
-//vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMappingScale * vec2(-1, 1), -1);
-vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMappingScale * vec2(-1, 1), -1);
-vec3 RT = vec3(TexCoord, 1);
-OffsetVector *= 0.1;
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) - 0.5);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.5 - 0.25);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.25 - 0.125);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.125 - 0.0625);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.0625 - 0.03125);
-return RT.xy;
-#else
-// 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)
-// this basically moves forward the full distance, and then backs up based
-// on height of samples
-//vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMappingScale) * vec2(-1, 1));
-//vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMappingScale * vec2(-1, 1));
-vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMappingScale * vec2(-1, 1));
-TexCoord += OffsetVector;
-OffsetVector *= 0.5;
-TexCoord -= OffsetVector * texture2D(NormalmapTexture, TexCoord).a;
-TexCoord -= OffsetVector * texture2D(NormalmapTexture, TexCoord).a;
-return TexCoord;
-#endif
+index = int(Indices_2.z);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.z;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 3)
+{
+index = int(Indices_2.w);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.w;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+}
+}
}
+
+float len = length(DQReal);
+DQReal /= len;
+DQDual /= len;
+
+Position.xyz = (cross(DQReal.xyz, cross(DQReal.xyz, Position.xyz) + Position.xyz*DQReal.w + DQDual.xyz) + DQDual.xyz*DQReal.w - DQReal.xyz*DQDual.w)*2.0 + Position.xyz;
+
+#ifdef DUAL_QUAT_TRANSFORM_NORMALS
+Normal = cross(DQReal.xyz, cross(DQReal.xyz, Normal) + Normal*DQReal.w)*2.0 + Normal;
#endif
-void main()
-{
-#if defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-// apply offsetmapping
-vec2 TexCoordOffset = OffsetMapping(TexCoord);
-#define TexCoord TexCoordOffset
+#ifdef DUAL_QUAT_TRANSFORM_TANGENT
+Tangent = cross(DQReal.xyz, cross(DQReal.xyz, Tangent) + Tangent*DQReal.w)*2.0 + Tangent;
#endif
-myhalf3 surfaceNormal;
-myhalf3 diffuseNormalModelspace;
-myhalf3 diffuseNormal = myhalf3 (0.0, 0.0, -1.0);
-float diffuseProduct;
-#ifdef APPLY_CELLSHADING
-int lightcell;
-float diffuseProductPositive;
-float diffuseProductNegative;
-float hardShadow;
+}
+
#endif
+#ifdef VERTEX_SHADER
+#ifdef APPLY_INSTANCED_ATTRIB_TRASNFORMS
+attribute vec4 a_InstanceQuat;
+attribute vec4 a_InstancePosAndScale;
+#elif defined(GL_ARB_draw_instanced)
-myhalf3 weightedDiffuseNormal;
-myhalf3 specularNormal;
-float specularProduct;
+uniform vec4 u_QF_InstancePoints[MAX_UNIFORM_INSTANCES*2];
-#if !defined(APPLY_DIRECTIONAL_LIGHT) && !defined(APPLY_LIGHTSTYLE0)
-myhalf4 color = myhalf4 (1.0, 1.0, 1.0, 1.0);
+#define a_InstanceQuat u_QF_InstancePoints[gl_InstanceID*2]
+#define a_InstancePosAndScale u_QF_InstancePoints[gl_InstanceID*2+1]
#else
-myhalf4 color = myhalf4 (0.0, 0.0, 0.0, 1.0);
+uniform vec4 u_QF_InstancePoints[2];
+#define a_InstanceQuat u_QF_InstancePoints[0]
+#define a_InstancePosAndScale u_QF_InstancePoints[1]
#endif
-// get the surface normal
-surfaceNormal = normalize (myhalf3 (texture2D (NormalmapTexture, TexCoord)) - myhalf3 (0.5));
+void QF_InstancedTransform(inout vec4 Position, inout vec3 Normal)
+{
+Position.xyz = (cross(a_InstanceQuat.xyz, cross(a_InstanceQuat.xyz, Position.xyz) + Position.xyz*a_InstanceQuat.w)*2.0 + Position.xyz) *
+ a_InstancePosAndScale.w + a_InstancePosAndScale.xyz;
+Normal = cross(a_InstanceQuat.xyz, cross(a_InstanceQuat.xyz, Normal) + Normal*a_InstanceQuat.w)*2.0 + Normal;
+}
+
+#endif
+#define QF_LatLong2Norm(ll) vec3(cos((ll).y) * sin((ll).x), sin((ll).y) * sin((ll).x), cos((ll).x))
-#ifdef APPLY_DIRECTIONAL_LIGHT
-diffuseNormal = myhalf3 (LightVector);
-weightedDiffuseNormal = diffuseNormal;
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-#ifdef APPLY_CELLSHADING
-hardShadow = 0.0;
-diffuseProductPositive = max (diffuseProduct, 0.0);
-diffuseProductNegative = (-min (diffuseProduct, 0.0) - 0.3);
-// smooth the hard shadow edge
-lightcell = int(max(diffuseProduct + 0.1, 0.0) * 2.0);
-hardShadow += float(lightcell);
+#define DRAWFLAT_NORMAL_STEP 0.5 // floor or ceiling if < abs(normal.z)
+uniform mat4 u_ModelViewMatrix;
+uniform mat4 u_ModelViewProjectionMatrix;
-lightcell = int(max(diffuseProduct + 0.055, 0.0) * 2.0);
-hardShadow += float(lightcell);
+uniform float u_ShaderTime;
-lightcell = int(diffuseProductPositive * 2.0);
-hardShadow += float(lightcell);
+uniform vec3 u_ViewOrigin;
+uniform mat3 u_ViewAxis;
-color.rgb += myhalf(0.6 + hardShadow * 0.3333333333 * 0.27 + diffuseProductPositive * 0.14);
+uniform vec3 u_EntityDist;
+uniform vec3 u_EntityOrigin;
+uniform myhalf4 u_EntityColor;
-// backlight
-lightcell = int (diffuseProductNegative * 2.0);
-color.rgb += myhalf (float(lightcell) * 0.085 + diffuseProductNegative * 0.085);
-#else
-color.rgb += LightDiffuse.rgb * myhalf(max (diffuseProduct, 0.0)) + LightAmbient.rgb;
-#endif
+uniform myhalf4 u_ConstColor;
+uniform myhalf4 u_RGBGenFuncArgs, u_AlphaGenFuncArgs;
+uniform myhalf3 u_LightstyleColor[4]; // lightstyle colors
-#endif
+uniform myhalf3 u_LightAmbient;
+uniform myhalf3 u_LightDiffuse;
+uniform vec3 u_LightDir;
-// deluxemapping using light vectors in modelspace
+uniform myhalf2 u_BlendMix;
-#ifdef APPLY_LIGHTSTYLE0
+uniform vec2 u_TextureMatrix[3];
+#define TextureMatrix2x3Mul(m2x3,tc) vec2(dot((m2x3)[0],(tc)) + (m2x3)[2][0], dot((m2x3)[1],(tc)) + (m2x3)[2][1])
-// get light normal
-diffuseNormalModelspace = myhalf3 (texture2D(LightmapTexture0, vec2(LightmapTexCoord01.s+DeluxemapOffset0,LightmapTexCoord01.t))) - myhalf3 (0.5);
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-// calculate directional shading
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
+uniform float u_MirrorSide;
-#ifdef APPLY_FBLIGHTMAP
-weightedDiffuseNormal = diffuseNormal;
-// apply lightmap color
-color.rgb += myhalf3 (max (diffuseProduct, 0.0) * myhalf3 (texture2D (LightmapTexture0, LightmapTexCoord01.st)));
-#else
+uniform float u_ZNear, u_ZFar;
-#define NORMALIZE_DIFFUSE_NORMAL
+uniform ivec4 u_Viewport; // x, y, width, height
-weightedDiffuseNormal = lsColor0 * diffuseNormal;
-// apply lightmap color
-color.rgb += lsColor0 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture0, LightmapTexCoord01.st));
-#endif
+uniform vec4 u_TextureParams;
-#ifdef APPLY_AMBIENT_COMPENSATION
-// compensate for ambient lighting
-color.rgb += myhalf((1.0 - max (diffuseProduct, 0.0))) * LightAmbient;
+uniform myhalf u_SoftParticlesScale;
+#ifndef decodedepthmacro
+// Lifted from Darkplaces shader program
+#define decodedepthmacro(d) dot((d).rgb, vec3(1.0, 255.0 / 65536.0, 255.0 / 16777215.0))
+#define encodedepthmacro(d) (vec4(d, d*256.0, d*65536.0, 0.0) - floor(vec4(d, d*256.0, d*65536.0, 0.0)))
#endif
-#ifdef APPLY_LIGHTSTYLE1
-diffuseNormalModelspace = myhalf3 (texture2D (LightmapTexture1, vec2(LightmapTexCoord01.p+DeluxemapOffset1,LightmapTexCoord01.q))) - myhalf3 (0.5);
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-weightedDiffuseNormal += lsColor1 * diffuseNormal;
-color.rgb += lsColor1 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture1, LightmapTexCoord01.pq));
-#ifdef APPLY_LIGHTSTYLE2
-diffuseNormalModelspace = myhalf3 (texture2D (LightmapTexture2, vec2(LightmapTexCoord23.s+DeluxemapOffset2,LightmapTexCoord23.t))) - myhalf3 (0.5);
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-weightedDiffuseNormal += lsColor2 * diffuseNormal;
-color.rgb += lsColor2 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture2, LightmapTexCoord23.st));
+#ifndef NUM_SHADOWS
+#define NUM_SHADOWS 1
+#endif
-#ifdef APPLY_LIGHTSTYLE3
-diffuseNormalModelspace = myhalf3 (texture2D (LightmapTexture3, vec2(LightmapTexCoord23.p+DeluxemapOffset3,LightmapTexCoord23.q))) - myhalf3 (0.5);;
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-weightedDiffuseNormal += lsColor3 * diffuseNormal;
-color.rgb += lsColor3 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture3, LightmapTexCoord23.pq));
+qf_varying vec4 v_ShadowProjVector[NUM_SHADOWS];
-#endif
-#endif
-#endif
+#ifdef VERTEX_SHADER
+#ifdef VERTEX_SHADER
+qf_attribute vec4 a_Position;
+qf_attribute vec4 a_SVector;
+qf_attribute vec4 a_Normal;
+qf_attribute vec4 a_Color;
+qf_attribute vec2 a_TexCoord;
+qf_attribute vec2 a_LightmapCoord0, a_LightmapCoord1, a_LightmapCoord2, a_LightmapCoord3;
+#endif
+void TransformVerts(inout vec4 Position, inout vec3 Normal, inout vec2 TexCoord)
+{
+#ifdef NUM_BONE_INFLUENCES
+ QF_VertexDualQuatsTransform(NUM_BONE_INFLUENCES, Position, Normal);
#endif
-#ifdef APPLY_SPECULAR
+#ifdef APPLY_DEFORMVERTS
+ QF_DeformVerts(Position, Normal, TexCoord);
+#endif
-#ifdef NORMALIZE_DIFFUSE_NORMAL
-specularNormal = normalize (myhalf3 (normalize (weightedDiffuseNormal)) + myhalf3 (normalize (EyeVector)));
-#else
-specularNormal = normalize (weightedDiffuseNormal + myhalf3 (normalize (EyeVector)));
+#ifdef APPLY_INSTANCED_TRANSFORMS
+ QF_InstancedTransform(Position, Normal);
#endif
+}
-specularProduct = float (dot (surfaceNormal, specularNormal));
-color.rgb += (myhalf3(texture2D(GlossTexture, TexCoord)) * GlossIntensity) * pow(myhalf(max(specularProduct, 0.0)), GlossExponent);
+void TransformVerts(inout vec4 Position, inout vec3 Normal, inout vec3 Tangent, inout vec2 TexCoord)
+{
+#ifdef NUM_BONE_INFLUENCES
+ QF_VertexDualQuatsTransform(NUM_BONE_INFLUENCES, Position, Normal, Tangent);
#endif
-#ifdef APPLY_BASETEX_ALPHA_ONLY
-color = min(color, myhalf4(texture2D(BaseTexture, TexCoord).a));
-#else
-#ifdef APPLY_COLOR_CLAMPING
-color = min(color, myhalf4(1.0));
+#ifdef APPLY_DEFORMVERTS
+ QF_DeformVerts(Position, Normal, TexCoord);
#endif
-color = color * myhalf4(texture2D(BaseTexture, TexCoord));
+
+#ifdef APPLY_INSTANCED_TRANSFORMS
+ QF_InstancedTransform(Position, Normal);
#endif
+}
-#ifdef APPLY_DECAL
-#ifdef APPLY_DECAL_ADD
-myhalf3 decal = myhalf3(gl_Color.rgb) * myhalf3(texture2D(DecalTexture, TexCoord));
-color.rgb = decal.rgb + color.rgb;
-color.a = color.a * myhalf(gl_Color.a);
-#else
-myhalf4 decal = myhalf4(gl_Color.rgba);
-if (decal.a > 0.0)
+
+uniform mat4 u_ShadowmapMatrix[NUM_SHADOWS];
+
+void main(void)
{
-decal = decal * myhalf4(texture2D(DecalTexture, TexCoord));
-color.rgb = decal.rgb * decal.a + color.rgb * (1.0-decal.a);
+ vec4 Position = a_Position;
+ vec3 Normal = a_Normal.xyz;
+ vec2 TexCoord = a_TexCoord;
+
+ TransformVerts(Position, Normal, TexCoord);
+
+ gl_Position = u_ModelViewProjectionMatrix * Position;
+
+ for (int i = 0; i < NUM_SHADOWS; i++)
+ {
+ v_ShadowProjVector[i] = u_ShadowmapMatrix[i] * Position;
+ // a trick whish allows us not to perform the
+ // 'shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5)'
+ // computation in the fragment shader
+ v_ShadowProjVector[i].xyz = (v_ShadowProjVector[i].xyz + vec3(v_ShadowProjVector[i].w)) * 0.5;
+ }
}
-#endif
-#else
-color = color * myhalf4(gl_Color.rgba);
-#endif
-#ifdef APPLY_GRAYSCALE
-float grey = dot(color, myhalf3(0.299, 0.587, 0.114));
-gl_FragColor = vec4(vec3(grey),color.a);
+#endif // VERTEX_SHADER
+
+
+#ifdef FRAGMENT_SHADER
+// Fragment shader
+
+#ifdef APPLY_RGB_SHADOW
+uniform sampler2D u_ShadowmapTexture[NUM_SHADOWS];
+# define dshadow2D(t,v) step(v.z, decodedepthmacro(qf_texture(t, v.xy)))
#else
-gl_FragColor = vec4(color);
+uniform sampler2DShadow u_ShadowmapTexture[NUM_SHADOWS];
+# define dshadow2D(t,v) float(qf_shadow(t,v))
#endif
+
+uniform float u_ShadowAlpha;
+uniform float u_ShadowProjDistance[NUM_SHADOWS];
+uniform vec4 u_ShadowmapTextureParams[NUM_SHADOWS];
+
+void main(void)
+{
+ float finalcolor = 1.0;
+
+#if NUM_SHADOWS >= 1
+#define SHADOW_INDEX 0
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+#if NUM_SHADOWS >= 2
+#define SHADOW_INDEX 1
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+#if NUM_SHADOWS >= 3
+#define SHADOW_INDEX 2
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+#if NUM_SHADOWS >= 4
+#define SHADOW_INDEX 3
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+ qf_FragColor = vec4(vec3(finalcolor),1.0);
}
#endif // FRAGMENT_SHADER
-[vertex shader]
-#define VERTEX_SHADER
-#define APPLY_LIGHTSTYLE0
-#define APPLY_FBLIGHTMAP
-#define APPLY_SPECULAR
-#define APPLY_AMBIENT_COMPENSATION
-// Warsow GLSL shader
+[fragment shader]
+#version 130
-#if !defined(__GLSL_CG_DATA_TYPES)
+#define QF_GLSL_VERSION 130
+#define FRAGMENT_SHADER
+#if !defined(myhalf)
+//#if !defined(__GLSL_CG_DATA_TYPES)
#define myhalf float
#define myhalf2 vec2
#define myhalf3 vec3
#define myhalf4 vec4
+//#else
+//#define myhalf half
+//#define myhalf2 half2
+//#define myhalf3 half3
+//#define myhalf4 half4
+//#endif
+#endif
+
+#if QF_GLSL_VERSION >= 130
+ precision highp float;
+
+# ifdef VERTEX_SHADER
+ out myhalf4 qf_FrontColor;
+# define qf_varying out
+# define qf_attribute in
+# endif
+# ifdef FRAGMENT_SHADER
+ in myhalf4 qf_FrontColor;
+ out myhalf4 qf_FragColor;
+# define qf_varying in
+# define qf_attribute in
+# endif
+
+# define qf_texture texture
+# define qf_textureCube texture
+# define qf_textureLod textureLod
+# define qf_textureOffset(a,b,c,d) textureOffset(a,b,ivec2(c,d))
+# define qf_shadow texture
#else
-#define myhalf half
-#define myhalf2 half2
-#define myhalf3 half3
-#define myhalf4 half4
+# ifdef VERTEX_SHADER
+# define qf_FrontColor gl_FrontColor
+# define qf_varying varying
+# define qf_attribute attribute
+# endif
+
+# ifdef FRAGMENT_SHADER
+# define qf_FrontColor gl_Color
+# define qf_FragColor gl_FragColor
+# define qf_varying varying
+# define qf_attribute attribute
+# endif
+# define qf_texture texture2D
+# define qf_textureLod texture2DLod
+# define qf_textureCube textureCube
+# define qf_textureOffset(a,b,c,d) texture2DOffset(a,b,ivec2(c,d))
+# define qf_shadow shadow2D
#endif
-varying vec2 TexCoord;
-#ifdef APPLY_LIGHTSTYLE0
-varying vec4 LightmapTexCoord01;
-#ifdef APPLY_LIGHTSTYLE2
-varying vec4 LightmapTexCoord23;
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_TWOPI
+#define M_TWOPI 6.28318530717958647692
#endif
+
+#ifndef MAX_UNIFORM_BONES
+#define MAX_UNIFORM_BONES 100
#endif
-#if defined(APPLY_SPECULAR) || defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-varying vec3 EyeVector;
+#ifndef MAX_UNIFORM_INSTANCES
+#define MAX_UNIFORM_INSTANCES 40
#endif
+uniform vec3 u_QF_ViewOrigin;
+uniform mat3 u_QF_ViewAxis;
+uniform float u_QF_MirrorSide;
+uniform vec3 u_QF_EntityOrigin;
+uniform float u_QF_ShaderTime;
-#ifdef APPLY_DIRECTIONAL_LIGHT
-varying vec3 LightVector;
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
#endif
+#ifndef M_TWOPI
+#define M_TWOPI 6.28318530717958647692
+#endif
+
+#ifndef WAVE_SIN
+float QF_WaveFunc_Sin(float x)
+{
+x -= floor(x);
+return sin(x * M_TWOPI);
+}
+float QF_WaveFunc_Triangle(float x)
+{
+x -= floor(x);
+return step(x, 0.25) * x * 4.0 + (2.0 - 4.0 * step(0.25, x) * step(x, 0.75) * x) + ((step(0.75, x) * x - 0.75) * 4.0 - 1.0);
+}
+float QF_WaveFunc_Square(float x)
+{
+x -= floor(x);
+return step(x, 0.5) * 2.0 - 1.0;
+}
+float QF_WaveFunc_Sawtooth(float x)
+{
+x -= floor(x);
+return x;
+}
+float QF_QF_WaveFunc_InverseSawtooth(float x)
+{
+x -= floor(x);
+return 1.0 - x;
+}
-varying mat3 strMatrix; // directions of S/T/R texcoords (tangent, binormal, normal)
+#define WAVE_SIN(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Sin((phase)+(time)*(freq))))
+#define WAVE_TRIANGLE(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Triangle((phase)+(time)*(freq))))
+#define WAVE_SQUARE(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Square((phase)+(time)*(freq))))
+#define WAVE_SAWTOOTH(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_WaveFunc_Sawtooth((phase)+(time)*(freq))))
+#define WAVE_INVERSESAWTOOTH(time,base,amplitude,phase,freq) (((base)+(amplitude)*QF_QF_WaveFunc_InverseSawtooth((phase)+(time)*(freq))))
+#endif
#ifdef VERTEX_SHADER
-// Vertex shader
+attribute vec4 a_BonesIndices;
+attribute vec4 a_BonesWeights;
-uniform vec3 EyeOrigin;
+uniform vec4 u_QF_DualQuats[MAX_UNIFORM_BONES*2];
-#ifdef APPLY_DIRECTIONAL_LIGHT
-uniform vec3 LightDir;
+#if defined(DUAL_QUAT_TRANSFORM_NORMALS)
+#if defined(DUAL_QUAT_TRANSFORM_TANGENT)
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal, inout vec3 Tangent)
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal)
#endif
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position)
+#endif
+{
+int index;
+vec4 Indices = a_BonesIndices;
+vec4 Weights = a_BonesWeights;
+vec4 Indices_2 = Indices * 2.0;
+vec4 DQReal, DQDual;
+
+index = int(Indices_2.x);
+DQReal = u_QF_DualQuats[index+0];
+DQDual = u_QF_DualQuats[index+1];
-void main()
+if (numWeights > 1)
{
-gl_FrontColor = gl_Color;
+DQReal *= Weights.x;
+DQDual *= Weights.x;
-TexCoord = vec2 (gl_TextureMatrix[0] * gl_MultiTexCoord0);
+vec4 DQReal1, DQDual1;
+float scale;
-#ifdef APPLY_LIGHTSTYLE0
-LightmapTexCoord01.st = gl_MultiTexCoord4.st;
-#ifdef APPLY_LIGHTSTYLE1
-LightmapTexCoord01.pq = gl_MultiTexCoord5.st;
-#ifdef APPLY_LIGHTSTYLE2
-LightmapTexCoord23.st = gl_MultiTexCoord6.st;
-#ifdef APPLY_LIGHTSTYLE3
-LightmapTexCoord23.pq = gl_MultiTexCoord7.st;
-#endif
-#endif
-#endif
-#endif
+index = int(Indices_2.y);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.y;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 2)
+{
+index = int(Indices_2.z);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.z;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 3)
+{
+index = int(Indices_2.w);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.w;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+}
+}
+}
-strMatrix[0] = gl_MultiTexCoord1.xyz;
-strMatrix[2] = gl_Normal.xyz;
-strMatrix[1] = gl_MultiTexCoord1.w * cross (strMatrix[2], strMatrix[0]);
+float len = length(DQReal);
+DQReal /= len;
+DQDual /= len;
-#if defined(APPLY_SPECULAR) || defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-vec3 EyeVectorWorld = EyeOrigin - gl_Vertex.xyz;
-EyeVector = EyeVectorWorld * strMatrix;
+Position.xyz = (cross(DQReal.xyz, cross(DQReal.xyz, Position.xyz) + Position.xyz*DQReal.w + DQDual.xyz) + DQDual.xyz*DQReal.w - DQReal.xyz*DQDual.w)*2.0 + Position.xyz;
+
+#ifdef DUAL_QUAT_TRANSFORM_NORMALS
+Normal = cross(DQReal.xyz, cross(DQReal.xyz, Normal) + Normal*DQReal.w)*2.0 + Normal;
#endif
-#ifdef APPLY_DIRECTIONAL_LIGHT
-LightVector = LightDir * strMatrix;
+#ifdef DUAL_QUAT_TRANSFORM_TANGENT
+Tangent = cross(DQReal.xyz, cross(DQReal.xyz, Tangent) + Tangent*DQReal.w)*2.0 + Tangent;
#endif
+}
-gl_Position = ftransform ();
-#ifdef APPLY_CLIPPING
-#ifdef __GLSL_CG_DATA_TYPES
-gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+// use defines to overload the transform function
+
+#define DUAL_QUAT_TRANSFORM_NORMALS
+#if defined(DUAL_QUAT_TRANSFORM_NORMALS)
+#if defined(DUAL_QUAT_TRANSFORM_TANGENT)
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal, inout vec3 Tangent)
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal)
#endif
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position)
#endif
-}
+{
+int index;
+vec4 Indices = a_BonesIndices;
+vec4 Weights = a_BonesWeights;
+vec4 Indices_2 = Indices * 2.0;
+vec4 DQReal, DQDual;
-#endif // VERTEX_SHADER
+index = int(Indices_2.x);
+DQReal = u_QF_DualQuats[index+0];
+DQDual = u_QF_DualQuats[index+1];
+if (numWeights > 1)
+{
+DQReal *= Weights.x;
+DQDual *= Weights.x;
-#ifdef FRAGMENT_SHADER
-// Fragment shader
+vec4 DQReal1, DQDual1;
+float scale;
-#ifdef APPLY_LIGHTSTYLE0
-uniform sampler2D LightmapTexture0;
-uniform float DeluxemapOffset0; // s-offset for LightmapTexCoord
-uniform myhalf3 lsColor0; // lightstyle color
+index = int(Indices_2.y);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.y;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
-#ifdef APPLY_LIGHTSTYLE1
-uniform sampler2D LightmapTexture1;
-uniform float DeluxemapOffset1;
-uniform myhalf3 lsColor1;
+if (numWeights > 2)
+{
+index = int(Indices_2.z);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.z;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 3)
+{
+index = int(Indices_2.w);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.w;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+}
+}
+}
-#ifdef APPLY_LIGHTSTYLE2
-uniform sampler2D LightmapTexture2;
-uniform float DeluxemapOffset2;
-uniform myhalf3 lsColor2;
+float len = length(DQReal);
+DQReal /= len;
+DQDual /= len;
-#ifdef APPLY_LIGHTSTYLE3
-uniform sampler2D LightmapTexture3;
-uniform float DeluxemapOffset3;
-uniform myhalf3 lsColor3;
+Position.xyz = (cross(DQReal.xyz, cross(DQReal.xyz, Position.xyz) + Position.xyz*DQReal.w + DQDual.xyz) + DQDual.xyz*DQReal.w - DQReal.xyz*DQDual.w)*2.0 + Position.xyz;
+#ifdef DUAL_QUAT_TRANSFORM_NORMALS
+Normal = cross(DQReal.xyz, cross(DQReal.xyz, Normal) + Normal*DQReal.w)*2.0 + Normal;
#endif
+
+#ifdef DUAL_QUAT_TRANSFORM_TANGENT
+Tangent = cross(DQReal.xyz, cross(DQReal.xyz, Tangent) + Tangent*DQReal.w)*2.0 + Tangent;
#endif
+}
+
+#define DUAL_QUAT_TRANSFORM_TANGENT
+#if defined(DUAL_QUAT_TRANSFORM_NORMALS)
+#if defined(DUAL_QUAT_TRANSFORM_TANGENT)
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal, inout vec3 Tangent)
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position, inout vec3 Normal)
#endif
+#else
+void QF_VertexDualQuatsTransform(const int numWeights, inout vec4 Position)
#endif
+{
+int index;
+vec4 Indices = a_BonesIndices;
+vec4 Weights = a_BonesWeights;
+vec4 Indices_2 = Indices * 2.0;
+vec4 DQReal, DQDual;
-uniform sampler2D BaseTexture;
-uniform sampler2D NormalmapTexture;
-uniform sampler2D GlossTexture;
-#ifdef APPLY_DECAL
-uniform sampler2D DecalTexture;
-#endif
+index = int(Indices_2.x);
+DQReal = u_QF_DualQuats[index+0];
+DQDual = u_QF_DualQuats[index+1];
-#if defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-uniform float OffsetMappingScale;
-#endif
+if (numWeights > 1)
+{
+DQReal *= Weights.x;
+DQDual *= Weights.x;
-uniform myhalf3 LightAmbient;
-#ifdef APPLY_DIRECTIONAL_LIGHT
-uniform myhalf3 LightDiffuse;
-#endif
+vec4 DQReal1, DQDual1;
+float scale;
-uniform myhalf GlossIntensity; // gloss scaling factor
-uniform myhalf GlossExponent; // gloss exponent factor
+index = int(Indices_2.y);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.y;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
-#if defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-// The following reliefmapping and offsetmapping routine was taken from DarkPlaces
-// The credit goes to LordHavoc (as always)
-vec2 OffsetMapping(vec2 TexCoord)
+if (numWeights > 2)
{
-#ifdef APPLY_RELIEFMAPPING
-// 14 sample relief mapping: linear search and then binary search
-// this basically steps forward a small amount repeatedly until it finds
-// itself inside solid, then jitters forward and back using decreasing
-// amounts to find the impact
-//vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMappingScale) * vec2(-1, 1), -1);
-//vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMappingScale * vec2(-1, 1), -1);
-vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMappingScale * vec2(-1, 1), -1);
-vec3 RT = vec3(TexCoord, 1);
-OffsetVector *= 0.1;
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * step(texture2D(NormalmapTexture, RT.xy).a, RT.z);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) - 0.5);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.5 - 0.25);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.25 - 0.125);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.125 - 0.0625);
-RT += OffsetVector * (step(texture2D(NormalmapTexture, RT.xy).a, RT.z) * 0.0625 - 0.03125);
-return RT.xy;
-#else
-// 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)
-// this basically moves forward the full distance, and then backs up based
-// on height of samples
-//vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMappingScale) * vec2(-1, 1));
-//vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMappingScale * vec2(-1, 1));
-vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMappingScale * vec2(-1, 1));
-TexCoord += OffsetVector;
-OffsetVector *= 0.5;
-TexCoord -= OffsetVector * texture2D(NormalmapTexture, TexCoord).a;
-TexCoord -= OffsetVector * texture2D(NormalmapTexture, TexCoord).a;
-return TexCoord;
-#endif
+index = int(Indices_2.z);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.z;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+
+if (numWeights > 3)
+{
+index = int(Indices_2.w);
+DQReal1 = u_QF_DualQuats[index+0];
+DQDual1 = u_QF_DualQuats[index+1];
+// antipodality handling
+scale = (dot(DQReal1, DQReal) < 0.0 ? -1.0 : 1.0) * Weights.w;
+DQReal += DQReal1 * scale;
+DQDual += DQDual1 * scale;
+}
}
+}
+
+float len = length(DQReal);
+DQReal /= len;
+DQDual /= len;
+
+Position.xyz = (cross(DQReal.xyz, cross(DQReal.xyz, Position.xyz) + Position.xyz*DQReal.w + DQDual.xyz) + DQDual.xyz*DQReal.w - DQReal.xyz*DQDual.w)*2.0 + Position.xyz;
+
+#ifdef DUAL_QUAT_TRANSFORM_NORMALS
+Normal = cross(DQReal.xyz, cross(DQReal.xyz, Normal) + Normal*DQReal.w)*2.0 + Normal;
#endif
-void main()
-{
-#if defined(APPLY_OFFSETMAPPING) || defined(APPLY_RELIEFMAPPING)
-// apply offsetmapping
-vec2 TexCoordOffset = OffsetMapping(TexCoord);
-#define TexCoord TexCoordOffset
+#ifdef DUAL_QUAT_TRANSFORM_TANGENT
+Tangent = cross(DQReal.xyz, cross(DQReal.xyz, Tangent) + Tangent*DQReal.w)*2.0 + Tangent;
#endif
-myhalf3 surfaceNormal;
-myhalf3 diffuseNormalModelspace;
-myhalf3 diffuseNormal = myhalf3 (0.0, 0.0, -1.0);
-float diffuseProduct;
-#ifdef APPLY_CELLSHADING
-int lightcell;
-float diffuseProductPositive;
-float diffuseProductNegative;
-float hardShadow;
+}
+
#endif
+#ifdef VERTEX_SHADER
+#ifdef APPLY_INSTANCED_ATTRIB_TRASNFORMS
+attribute vec4 a_InstanceQuat;
+attribute vec4 a_InstancePosAndScale;
+#elif defined(GL_ARB_draw_instanced)
-myhalf3 weightedDiffuseNormal;
-myhalf3 specularNormal;
-float specularProduct;
+uniform vec4 u_QF_InstancePoints[MAX_UNIFORM_INSTANCES*2];
-#if !defined(APPLY_DIRECTIONAL_LIGHT) && !defined(APPLY_LIGHTSTYLE0)
-myhalf4 color = myhalf4 (1.0, 1.0, 1.0, 1.0);
+#define a_InstanceQuat u_QF_InstancePoints[gl_InstanceID*2]
+#define a_InstancePosAndScale u_QF_InstancePoints[gl_InstanceID*2+1]
#else
-myhalf4 color = myhalf4 (0.0, 0.0, 0.0, 1.0);
+uniform vec4 u_QF_InstancePoints[2];
+#define a_InstanceQuat u_QF_InstancePoints[0]
+#define a_InstancePosAndScale u_QF_InstancePoints[1]
#endif
-// get the surface normal
-surfaceNormal = normalize (myhalf3 (texture2D (NormalmapTexture, TexCoord)) - myhalf3 (0.5));
+void QF_InstancedTransform(inout vec4 Position, inout vec3 Normal)
+{
+Position.xyz = (cross(a_InstanceQuat.xyz, cross(a_InstanceQuat.xyz, Position.xyz) + Position.xyz*a_InstanceQuat.w)*2.0 + Position.xyz) *
+ a_InstancePosAndScale.w + a_InstancePosAndScale.xyz;
+Normal = cross(a_InstanceQuat.xyz, cross(a_InstanceQuat.xyz, Normal) + Normal*a_InstanceQuat.w)*2.0 + Normal;
+}
-#ifdef APPLY_DIRECTIONAL_LIGHT
-diffuseNormal = myhalf3 (LightVector);
-weightedDiffuseNormal = diffuseNormal;
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-#ifdef APPLY_CELLSHADING
-hardShadow = 0.0;
-diffuseProductPositive = max (diffuseProduct, 0.0);
-diffuseProductNegative = (-min (diffuseProduct, 0.0) - 0.3);
+#endif
+#define QF_LatLong2Norm(ll) vec3(cos((ll).y) * sin((ll).x), sin((ll).y) * sin((ll).x), cos((ll).x))
-// smooth the hard shadow edge
-lightcell = int(max(diffuseProduct + 0.1, 0.0) * 2.0);
-hardShadow += float(lightcell);
-lightcell = int(max(diffuseProduct + 0.055, 0.0) * 2.0);
-hardShadow += float(lightcell);
+#define DRAWFLAT_NORMAL_STEP 0.5 // floor or ceiling if < abs(normal.z)
+uniform mat4 u_ModelViewMatrix;
+uniform mat4 u_ModelViewProjectionMatrix;
-lightcell = int(diffuseProductPositive * 2.0);
-hardShadow += float(lightcell);
+uniform float u_ShaderTime;
-color.rgb += myhalf(0.6 + hardShadow * 0.3333333333 * 0.27 + diffuseProductPositive * 0.14);
+uniform vec3 u_ViewOrigin;
+uniform mat3 u_ViewAxis;
-// backlight
-lightcell = int (diffuseProductNegative * 2.0);
-color.rgb += myhalf (float(lightcell) * 0.085 + diffuseProductNegative * 0.085);
-#else
-color.rgb += LightDiffuse.rgb * myhalf(max (diffuseProduct, 0.0)) + LightAmbient.rgb;
-#endif
+uniform vec3 u_EntityDist;
+uniform vec3 u_EntityOrigin;
+uniform myhalf4 u_EntityColor;
-#endif
+uniform myhalf4 u_ConstColor;
+uniform myhalf4 u_RGBGenFuncArgs, u_AlphaGenFuncArgs;
+uniform myhalf3 u_LightstyleColor[4]; // lightstyle colors
-// deluxemapping using light vectors in modelspace
+uniform myhalf3 u_LightAmbient;
+uniform myhalf3 u_LightDiffuse;
+uniform vec3 u_LightDir;
-#ifdef APPLY_LIGHTSTYLE0
+uniform myhalf2 u_BlendMix;
-// get light normal
-diffuseNormalModelspace = myhalf3 (texture2D(LightmapTexture0, vec2(LightmapTexCoord01.s+DeluxemapOffset0,LightmapTexCoord01.t))) - myhalf3 (0.5);
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-// calculate directional shading
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
+uniform vec2 u_TextureMatrix[3];
+#define TextureMatrix2x3Mul(m2x3,tc) vec2(dot((m2x3)[0],(tc)) + (m2x3)[2][0], dot((m2x3)[1],(tc)) + (m2x3)[2][1])
-#ifdef APPLY_FBLIGHTMAP
-weightedDiffuseNormal = diffuseNormal;
-// apply lightmap color
-color.rgb += myhalf3 (max (diffuseProduct, 0.0) * myhalf3 (texture2D (LightmapTexture0, LightmapTexCoord01.st)));
-#else
+uniform float u_MirrorSide;
-#define NORMALIZE_DIFFUSE_NORMAL
+uniform float u_ZNear, u_ZFar;
-weightedDiffuseNormal = lsColor0 * diffuseNormal;
-// apply lightmap color
-color.rgb += lsColor0 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture0, LightmapTexCoord01.st));
-#endif
+uniform ivec4 u_Viewport; // x, y, width, height
-#ifdef APPLY_AMBIENT_COMPENSATION
-// compensate for ambient lighting
-color.rgb += myhalf((1.0 - max (diffuseProduct, 0.0))) * LightAmbient;
+uniform vec4 u_TextureParams;
+
+uniform myhalf u_SoftParticlesScale;
+#ifndef decodedepthmacro
+// Lifted from Darkplaces shader program
+#define decodedepthmacro(d) dot((d).rgb, vec3(1.0, 255.0 / 65536.0, 255.0 / 16777215.0))
+#define encodedepthmacro(d) (vec4(d, d*256.0, d*65536.0, 0.0) - floor(vec4(d, d*256.0, d*65536.0, 0.0)))
#endif
-#ifdef APPLY_LIGHTSTYLE1
-diffuseNormalModelspace = myhalf3 (texture2D (LightmapTexture1, vec2(LightmapTexCoord01.p+DeluxemapOffset1,LightmapTexCoord01.q))) - myhalf3 (0.5);
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-weightedDiffuseNormal += lsColor1 * diffuseNormal;
-color.rgb += lsColor1 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture1, LightmapTexCoord01.pq));
-#ifdef APPLY_LIGHTSTYLE2
-diffuseNormalModelspace = myhalf3 (texture2D (LightmapTexture2, vec2(LightmapTexCoord23.s+DeluxemapOffset2,LightmapTexCoord23.t))) - myhalf3 (0.5);
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-weightedDiffuseNormal += lsColor2 * diffuseNormal;
-color.rgb += lsColor2 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture2, LightmapTexCoord23.st));
+#ifndef NUM_SHADOWS
+#define NUM_SHADOWS 1
+#endif
-#ifdef APPLY_LIGHTSTYLE3
-diffuseNormalModelspace = myhalf3 (texture2D (LightmapTexture3, vec2(LightmapTexCoord23.p+DeluxemapOffset3,LightmapTexCoord23.q))) - myhalf3 (0.5);;
-diffuseNormal = normalize (myhalf3(dot(diffuseNormalModelspace,myhalf3(strMatrix[0])),dot(diffuseNormalModelspace,myhalf3(strMatrix[1])),dot(diffuseNormalModelspace,myhalf3(strMatrix[2]))));
-diffuseProduct = float (dot (surfaceNormal, diffuseNormal));
-weightedDiffuseNormal += lsColor3 * diffuseNormal;
-color.rgb += lsColor3 * myhalf(max (diffuseProduct, 0.0)) * myhalf3 (texture2D (LightmapTexture3, LightmapTexCoord23.pq));
+qf_varying vec4 v_ShadowProjVector[NUM_SHADOWS];
-#endif
-#endif
-#endif
+#ifdef VERTEX_SHADER
+#ifdef VERTEX_SHADER
+qf_attribute vec4 a_Position;
+qf_attribute vec4 a_SVector;
+qf_attribute vec4 a_Normal;
+qf_attribute vec4 a_Color;
+qf_attribute vec2 a_TexCoord;
+qf_attribute vec2 a_LightmapCoord0, a_LightmapCoord1, a_LightmapCoord2, a_LightmapCoord3;
+#endif
+void TransformVerts(inout vec4 Position, inout vec3 Normal, inout vec2 TexCoord)
+{
+#ifdef NUM_BONE_INFLUENCES
+ QF_VertexDualQuatsTransform(NUM_BONE_INFLUENCES, Position, Normal);
#endif
-#ifdef APPLY_SPECULAR
+#ifdef APPLY_DEFORMVERTS
+ QF_DeformVerts(Position, Normal, TexCoord);
+#endif
-#ifdef NORMALIZE_DIFFUSE_NORMAL
-specularNormal = normalize (myhalf3 (normalize (weightedDiffuseNormal)) + myhalf3 (normalize (EyeVector)));
-#else
-specularNormal = normalize (weightedDiffuseNormal + myhalf3 (normalize (EyeVector)));
+#ifdef APPLY_INSTANCED_TRANSFORMS
+ QF_InstancedTransform(Position, Normal);
#endif
+}
-specularProduct = float (dot (surfaceNormal, specularNormal));
-color.rgb += (myhalf3(texture2D(GlossTexture, TexCoord)) * GlossIntensity) * pow(myhalf(max(specularProduct, 0.0)), GlossExponent);
+void TransformVerts(inout vec4 Position, inout vec3 Normal, inout vec3 Tangent, inout vec2 TexCoord)
+{
+#ifdef NUM_BONE_INFLUENCES
+ QF_VertexDualQuatsTransform(NUM_BONE_INFLUENCES, Position, Normal, Tangent);
#endif
-#ifdef APPLY_BASETEX_ALPHA_ONLY
-color = min(color, myhalf4(texture2D(BaseTexture, TexCoord).a));
-#else
-#ifdef APPLY_COLOR_CLAMPING
-color = min(color, myhalf4(1.0));
+#ifdef APPLY_DEFORMVERTS
+ QF_DeformVerts(Position, Normal, TexCoord);
#endif
-color = color * myhalf4(texture2D(BaseTexture, TexCoord));
+
+#ifdef APPLY_INSTANCED_TRANSFORMS
+ QF_InstancedTransform(Position, Normal);
#endif
+}
-#ifdef APPLY_DECAL
-#ifdef APPLY_DECAL_ADD
-myhalf3 decal = myhalf3(gl_Color.rgb) * myhalf3(texture2D(DecalTexture, TexCoord));
-color.rgb = decal.rgb + color.rgb;
-color.a = color.a * myhalf(gl_Color.a);
-#else
-myhalf4 decal = myhalf4(gl_Color.rgba);
-if (decal.a > 0.0)
+
+uniform mat4 u_ShadowmapMatrix[NUM_SHADOWS];
+
+void main(void)
{
-decal = decal * myhalf4(texture2D(DecalTexture, TexCoord));
-color.rgb = decal.rgb * decal.a + color.rgb * (1.0-decal.a);
+ vec4 Position = a_Position;
+ vec3 Normal = a_Normal.xyz;
+ vec2 TexCoord = a_TexCoord;
+
+ TransformVerts(Position, Normal, TexCoord);
+
+ gl_Position = u_ModelViewProjectionMatrix * Position;
+
+ for (int i = 0; i < NUM_SHADOWS; i++)
+ {
+ v_ShadowProjVector[i] = u_ShadowmapMatrix[i] * Position;
+ // a trick whish allows us not to perform the
+ // 'shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5)'
+ // computation in the fragment shader
+ v_ShadowProjVector[i].xyz = (v_ShadowProjVector[i].xyz + vec3(v_ShadowProjVector[i].w)) * 0.5;
+ }
}
-#endif
-#else
-color = color * myhalf4(gl_Color.rgba);
-#endif
-#ifdef APPLY_GRAYSCALE
-float grey = dot(color, myhalf3(0.299, 0.587, 0.114));
-gl_FragColor = vec4(vec3(grey),color.a);
+#endif // VERTEX_SHADER
+
+
+#ifdef FRAGMENT_SHADER
+// Fragment shader
+
+#ifdef APPLY_RGB_SHADOW
+uniform sampler2D u_ShadowmapTexture[NUM_SHADOWS];
+# define dshadow2D(t,v) step(v.z, decodedepthmacro(qf_texture(t, v.xy)))
#else
-gl_FragColor = vec4(color);
+uniform sampler2DShadow u_ShadowmapTexture[NUM_SHADOWS];
+# define dshadow2D(t,v) float(qf_shadow(t,v))
#endif
+
+uniform float u_ShadowAlpha;
+uniform float u_ShadowProjDistance[NUM_SHADOWS];
+uniform vec4 u_ShadowmapTextureParams[NUM_SHADOWS];
+
+void main(void)
+{
+ float finalcolor = 1.0;
+
+#if NUM_SHADOWS >= 1
+#define SHADOW_INDEX 0
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+#if NUM_SHADOWS >= 2
+#define SHADOW_INDEX 1
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+#if NUM_SHADOWS >= 3
+#define SHADOW_INDEX 2
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+#if NUM_SHADOWS >= 4
+#define SHADOW_INDEX 3
+ {
+ vec3 shadowmaptc = vec3(v_ShadowProjVector[SHADOW_INDEX].xyz / v_ShadowProjVector[SHADOW_INDEX].w);
+
+ // this keeps shadows from appearing on surfaces behind frustum's nearplane
+ float d = step(v_ShadowProjVector[SHADOW_INDEX].w, 0.0);
+
+ //shadowmaptc = (shadowmaptc + vec3 (1.0)) * vec3 (0.5);
+ shadowmaptc.xy = shadowmaptc.xy * u_ShadowmapTextureParams[SHADOW_INDEX].xy; // .x - texture width
+ shadowmaptc.z = clamp(shadowmaptc.z, 0.0, 1.0);
+ shadowmaptc.xy = vec2(clamp(shadowmaptc.x, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].x), clamp(shadowmaptc.y, 0.0, u_ShadowmapTextureParams[SHADOW_INDEX].y));
+
+ vec2 ShadowMap_TextureScale = u_ShadowmapTextureParams[SHADOW_INDEX].zw;
+
+ float f;
+
+ #ifdef APPLY_DITHER
+
+ # ifdef APPLY_PCF
+ # define texval(x, y) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(center + vec2(x, y)*ShadowMap_TextureScale, shadowmaptc.z))
+
+ // this method can be described as a 'dithered pinwheel' (4 texture lookups)
+ // which is a combination of the 'pinwheel' filter suggested by eihrul and dithered 4x4 PCF,
+ // described here: http://http.developer.nvidia.com/GPUGems/gpugems_ch11.html
+
+ vec2 offset_dither = mod(floor(gl_FragCoord.xy), 2.0);
+ offset_dither.y += offset_dither.x; // y ^= x in floating point
+ offset_dither.y *= step(offset_dither.y, 1.1);
+
+ vec2 center = (shadowmaptc.xy + offset_dither.xy) * ShadowMap_TextureScale;
+ float group1 = texval(-0.4, 1.0);
+ float group2 = texval(-1.0, -0.4);
+ float group3 = texval( 0.4, -1.0);
+ float group4 = texval( 1.0, 0.4);
+
+ f = dot(vec4(0.25), vec4(group1, group2, group3, group4));
+ # else
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy*ShadowMap_TextureScale, shadowmaptc.z));
+ # endif // APPLY_PCF
+
+ #else
+ // an essay by eihrul:
+ // now think of bilinear filtering as a 1x1 weighted box filter
+ // that is, it's sampling over a 2x2 area, but only collecting the portion of each pixel it actually steps on
+ // with a linear shadowmap filter, you are getting that, like normal bilinear sampling
+ // only its doing the shadowmap test on each pixel first, to generate a new little 2x2 area, then its doing
+ // the bilinear filtering on that
+ // so now if you consider your 2x2 filter you have
+ // each of those taps is actually using linear filtering as you've configured it
+ // so you are literally sampling almost 16 pixels as is and all you are getting for it is 2x2
+ // the trick is to realize that in essence you could instead be sampling a 4x4 area of pixels
+ // and running a 3x3 weighted box filter on it
+ // but you would need some way to get the shadowmap to simply return the 4 pixels covered by each
+ // tap, rather than the filtered result
+ // which is what the ARB_texture_gather extension is for
+ // NOTE: we're using emulation of texture_gather now
+
+ # ifdef APPLY_PCF
+ # define texval(off) dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(off,shadowmaptc.z))
+
+ vec2 offset = fract(shadowmaptc.xy - 0.5);
+ vec4 size = vec4(offset + 1.0, 2.0 - offset), weight = (vec4(2.0 - 1.0 / size.xy, 1.0 / size.zw - 1.0) + (shadowmaptc.xy - offset).xyxy)*ShadowMap_TextureScale.xyxy;
+ f = (1.0/9.0)*dot(size.zxzx*size.wwyy, vec4(texval(weight.zw), texval(weight.xw), texval(weight.zy), texval(weight.xy)));
+
+ #else
+
+ f = dshadow2D(u_ShadowmapTexture[SHADOW_INDEX], vec3(shadowmaptc.xy * ShadowMap_TextureScale, shadowmaptc.z));
+
+ #endif // APPLY_PCF
+
+ #endif // APPLY_DITHER
+
+ finalcolor *= clamp(max(max(f, d), u_ShadowAlpha), 0.0, 1.0);
+ }
+
+#undef SHADOW_INDEX
+#endif
+
+ qf_FragColor = vec4(vec3(finalcolor),1.0);
}
#endif // FRAGMENT_SHADER