diff options
author | Kenneth Graunke <kenneth@whitecape.org> | 2014-07-09 17:38:57 -0700 |
---|---|---|
committer | Kenneth Graunke <kenneth@whitecape.org> | 2014-07-13 23:31:11 -0700 |
commit | 24e97e5ba02d49555cd02774186114e616750762 (patch) | |
tree | 07df12b5930845d53ac8cf4f48c5aa0544f051be /shaders/warsow/10.shader_test | |
parent | a45fe61c16a31ecefc50ceb4db451a3e0c6f5d81 (diff) |
Update Warsow shaders to 1.5.0.
$ warsow +timedemo 1 +cg_showFPS 1 +cl_checkForUpdate 0 \
+demo pts1 +next "quit"
Diffstat (limited to 'shaders/warsow/10.shader_test')
-rw-r--r-- | shaders/warsow/10.shader_test | 1968 |
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 |