mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Add support for specular materials.
Let materials specify shader uniform values. Use interned strings for shader uniform/attribute names. Remove confusing float* cast operator on CVector4D. Simplify and clean up CVector4D. Remove non-supported 'old' lighting model. This was SVN commit r11453.
This commit is contained in:
parent
8a0e47fdd6
commit
b7888aea52
36 changed files with 754 additions and 366 deletions
8
binaries/data/mods/public/art/materials/basic_spec.xml
Normal file
8
binaries/data/mods/public/art/materials/basic_spec.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<material>
|
||||
<shader effect="model"/>
|
||||
|
||||
<define name="USE_SPECULAR" value="1"/>
|
||||
<uniform name="specularPower" value="16.0"/>
|
||||
<uniform name="specularColor" value="1.0 1.0 1.0"/>
|
||||
</material>
|
||||
11
binaries/data/mods/public/art/materials/blend_spec.xml
Normal file
11
binaries/data/mods/public/art/materials/blend_spec.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<material>
|
||||
<shader effect="model_transparent"/>
|
||||
|
||||
<alpha_blending/>
|
||||
<define name="USE_TRANSPARENT" value="1"/>
|
||||
|
||||
<define name="USE_SPECULAR" value="1"/>
|
||||
<uniform name="specularPower" value="16.0"/>
|
||||
<uniform name="specularColor" value="1.0 1.0 1.0"/>
|
||||
</material>
|
||||
10
binaries/data/mods/public/art/materials/objectcolor_spec.xml
Normal file
10
binaries/data/mods/public/art/materials/objectcolor_spec.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<material>
|
||||
<shader effect="model"/>
|
||||
|
||||
<define name="USE_OBJECTCOLOR" value="1"/>
|
||||
|
||||
<define name="USE_SPECULAR" value="1"/>
|
||||
<uniform name="specularPower" value="16.0"/>
|
||||
<uniform name="specularColor" value="1.0 1.0 1.0"/>
|
||||
</material>
|
||||
10
binaries/data/mods/public/art/materials/playercolor_spec.xml
Normal file
10
binaries/data/mods/public/art/materials/playercolor_spec.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<material>
|
||||
<shader effect="model"/>
|
||||
|
||||
<define name="USE_PLAYERCOLOR" value="1"/>
|
||||
|
||||
<define name="USE_SPECULAR" value="1"/>
|
||||
<uniform name="specularPower" value="16.0"/>
|
||||
<uniform name="specularColor" value="1.0 1.0 1.0"/>
|
||||
</material>
|
||||
|
|
@ -1,22 +1,16 @@
|
|||
!!ARBfp1.0
|
||||
#ifdef USE_FP_SHADOW
|
||||
#if USE_FP_SHADOW
|
||||
OPTION ARB_fragment_program_shadow;
|
||||
#endif
|
||||
|
||||
#ifdef LIGHTING_MODEL_old
|
||||
#define CLAMP_LIGHTING
|
||||
#endif
|
||||
ATTRIB v_tex = fragment.texcoord[0];
|
||||
ATTRIB v_shadow = fragment.texcoord[1];
|
||||
ATTRIB v_los = fragment.texcoord[2];
|
||||
|
||||
#ifdef CLAMP_LIGHTING // for compat with old scenarios that expect clamped lighting
|
||||
#define MAD_MAYBE_SAT MAD_SAT
|
||||
#else
|
||||
#define MAD_MAYBE_SAT MAD
|
||||
#endif
|
||||
|
||||
#ifdef USE_OBJECTCOLOR
|
||||
#if USE_OBJECTCOLOR
|
||||
PARAM objectColor = program.local[0];
|
||||
#else
|
||||
#ifdef USE_PLAYERCOLOR
|
||||
#if USE_PLAYERCOLOR
|
||||
PARAM playerColor = program.local[0];
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -24,73 +18,106 @@
|
|||
PARAM shadingColor = program.local[1];
|
||||
PARAM ambient = program.local[2];
|
||||
|
||||
#ifdef USE_SHADOW_PCF
|
||||
#if USE_SHADOW_PCF
|
||||
PARAM shadowOffsets1 = program.local[3];
|
||||
PARAM shadowOffsets2 = program.local[4];
|
||||
TEMP offset;
|
||||
#endif
|
||||
|
||||
TEMP tex;
|
||||
TEMP temp;
|
||||
TEMP diffuse;
|
||||
TEMP color;
|
||||
#if USE_SPECULAR
|
||||
ATTRIB v_normal = fragment.texcoord[3];
|
||||
ATTRIB v_half = fragment.texcoord[4];
|
||||
PARAM specularPower = program.local[5];
|
||||
PARAM specularColor = program.local[6];
|
||||
#endif
|
||||
|
||||
TEX tex, fragment.texcoord[0], texture[0], 2D;
|
||||
#ifdef USE_TRANSPARENT
|
||||
TEMP tex;
|
||||
TEMP texdiffuse;
|
||||
TEMP sundiffuse;
|
||||
TEMP temp;
|
||||
TEMP color;
|
||||
TEMP shadow;
|
||||
|
||||
TEX tex, v_tex, texture[0], 2D;
|
||||
#if USE_TRANSPARENT
|
||||
MOV result.color.a, tex;
|
||||
#endif
|
||||
|
||||
// Apply coloring based on texture alpha
|
||||
#ifdef USE_OBJECTCOLOR
|
||||
#if USE_OBJECTCOLOR
|
||||
LRP temp.rgb, objectColor, 1.0, tex.a;
|
||||
MUL color.rgb, tex, temp;
|
||||
MUL texdiffuse.rgb, tex, temp;
|
||||
#else
|
||||
#ifdef USE_PLAYERCOLOR
|
||||
#if USE_PLAYERCOLOR
|
||||
LRP temp.rgb, playerColor, 1.0, tex.a;
|
||||
MUL color.rgb, tex, temp;
|
||||
MUL texdiffuse.rgb, tex, temp;
|
||||
#else
|
||||
MOV color.rgb, tex;
|
||||
MOV texdiffuse.rgb, tex;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Compute color = texture * (ambient + diffuse*shadow)
|
||||
// (diffuse is 2*fragment.color due to clamp-avoidance in the vertex program)
|
||||
#ifdef USE_SHADOW
|
||||
#ifdef USE_FP_SHADOW
|
||||
#ifdef USE_SHADOW_PCF
|
||||
MOV offset.zw, fragment.texcoord[1];
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets1;
|
||||
#if USE_SPECULAR
|
||||
// specular = specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower);
|
||||
TEMP specular;
|
||||
TEMP normal;
|
||||
DP3 normal.w, v_normal, v_normal;
|
||||
RSQ normal.w, normal.w;
|
||||
MUL normal.xyz, v_normal, normal.w;
|
||||
DP3_SAT temp.y, normal, v_half;
|
||||
// temp^p = (2^lg2(temp))^p = 2^(lg2(temp)*p)
|
||||
LG2 temp.y, temp.y;
|
||||
MUL temp.y, temp.y, specularPower.x;
|
||||
EX2 temp.y, temp.y;
|
||||
MUL specular.rgb, specularColor, temp.y;
|
||||
#endif
|
||||
|
||||
// color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient;
|
||||
// (sundiffuse is 2*fragment.color due to clamp-avoidance in the vertex program)
|
||||
#if USE_SHADOW
|
||||
#if USE_FP_SHADOW
|
||||
#if USE_SHADOW_PCF
|
||||
MOV offset.zw, v_shadow;
|
||||
ADD offset.xy, v_shadow, shadowOffsets1;
|
||||
TEX temp.x, offset, texture[1], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets1.zwzw;
|
||||
ADD offset.xy, v_shadow, shadowOffsets1.zwzw;
|
||||
TEX temp.y, offset, texture[1], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets2;
|
||||
ADD offset.xy, v_shadow, shadowOffsets2;
|
||||
TEX temp.z, offset, texture[1], SHADOW2D;
|
||||
ADD offset.xy, fragment.texcoord[1], shadowOffsets2.zwzw;
|
||||
ADD offset.xy, v_shadow, shadowOffsets2.zwzw;
|
||||
TEX temp.w, offset, texture[1], SHADOW2D;
|
||||
DP4 temp, temp, 0.25;
|
||||
DP4 shadow, temp, 0.25;
|
||||
#else
|
||||
TEX temp, fragment.texcoord[1], texture[1], SHADOW2D;
|
||||
TEX shadow, v_shadow, texture[1], SHADOW2D;
|
||||
#endif
|
||||
#else
|
||||
TEX tex, fragment.texcoord[1], texture[1], 2D;
|
||||
MOV_SAT temp.z, fragment.texcoord[1].z;
|
||||
SGE temp, tex.x, temp.z;
|
||||
TEX tex, v_shadow, texture[1], 2D;
|
||||
MOV_SAT temp.z, v_shadow.z;
|
||||
SGE shadow, tex.x, temp.z;
|
||||
#endif
|
||||
#ifdef CLAMP_LIGHTING
|
||||
MAD_SAT diffuse.rgb, fragment.color, 2.0, ambient;
|
||||
LRP temp.rgb, temp, diffuse, ambient;
|
||||
|
||||
MUL sundiffuse.rgb, fragment.color, 2.0;
|
||||
|
||||
#if USE_SPECULAR
|
||||
MAD color.rgb, texdiffuse, sundiffuse, specular;
|
||||
MUL temp.rgb, texdiffuse, ambient;
|
||||
MAD color.rgb, color, shadow, temp;
|
||||
#else
|
||||
MUL diffuse.rgb, fragment.color, 2.0;
|
||||
MAD temp.rgb, diffuse, temp, ambient;
|
||||
MAD temp.rgb, sundiffuse, shadow, ambient;
|
||||
MUL color.rgb, texdiffuse, temp;
|
||||
#endif
|
||||
MUL color.rgb, color, temp;
|
||||
|
||||
#else
|
||||
MAD_MAYBE_SAT temp.rgb, fragment.color, 2.0, ambient;
|
||||
MUL color.rgb, color, temp;
|
||||
#if USE_SPECULAR
|
||||
MAD temp.rgb, fragment.color, 2.0, ambient;
|
||||
MAD color.rgb, texdiffuse, temp, specular;
|
||||
#else
|
||||
MAD temp.rgb, fragment.color, 2.0, ambient;
|
||||
MUL color.rgb, texdiffuse, temp;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Multiply everything by the LOS texture
|
||||
TEX tex.a, fragment.texcoord[2], texture[2], 2D;
|
||||
TEX tex.a, v_los, texture[2], 2D;
|
||||
MUL color.rgb, color, tex.a;
|
||||
|
||||
MUL result.color.rgb, color, shadingColor;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,28 @@
|
|||
!!ARBvp1.0
|
||||
PARAM sunDir = program.local[0];
|
||||
PARAM sunColor = program.local[1];
|
||||
PARAM losTransform = program.local[2];
|
||||
PARAM shadowTransform[4] = { program.local[3..6] };
|
||||
|
||||
PARAM cameraPos = program.local[0];
|
||||
PARAM sunDir = program.local[1];
|
||||
PARAM sunColor = program.local[2];
|
||||
PARAM losTransform = program.local[3];
|
||||
PARAM shadowTransform[4] = { program.local[4..7] };
|
||||
#if USE_INSTANCING
|
||||
PARAM instancingTransform[4] = { program.local[8..11] };
|
||||
#endif
|
||||
|
||||
TEMP temp;
|
||||
TEMP lighting;
|
||||
|
||||
OUTPUT v_tex = result.texcoord[0];
|
||||
OUTPUT v_shadow = result.texcoord[1];
|
||||
OUTPUT v_los = result.texcoord[2];
|
||||
#if USE_SPECULAR
|
||||
OUTPUT v_normal = result.texcoord[3];
|
||||
OUTPUT v_half = result.texcoord[4];
|
||||
#endif
|
||||
|
||||
//// Compute position and normal:
|
||||
|
||||
#ifdef USE_INSTANCING
|
||||
PARAM instancingTransform[4] = { program.local[7..10] };
|
||||
#if USE_INSTANCING
|
||||
TEMP position;
|
||||
TEMP normal;
|
||||
DP4 position.x, instancingTransform[0], vertex.position;
|
||||
|
|
@ -38,17 +52,35 @@ MUL lighting, lighting, 0.5;
|
|||
// Apply light colour
|
||||
MUL result.color, lighting, sunColor;
|
||||
|
||||
//// Texture coordinates:
|
||||
#if USE_SPECULAR
|
||||
// eyeVec = normalize(cameraPos - position);
|
||||
TEMP eyeVec;
|
||||
SUB eyeVec.xyz, cameraPos, position;
|
||||
DP3 eyeVec.w, eyeVec, eyeVec;
|
||||
RSQ eyeVec.w, eyeVec.w;
|
||||
MUL eyeVec.xyz, eyeVec, eyeVec.w;
|
||||
|
||||
MOV result.texcoord[0], vertex.texcoord[0];
|
||||
// v_half = normalize(-sunDir + eyeVec);
|
||||
TEMP half;
|
||||
SUB half.xyz, eyeVec, sunDir;
|
||||
DP3 half.w, half, half;
|
||||
RSQ half.w, half.w;
|
||||
MUL v_half.xyz, half, half.w;
|
||||
|
||||
#ifdef USE_SHADOW
|
||||
DP4 result.texcoord[1].x, shadowTransform[0], position;
|
||||
DP4 result.texcoord[1].y, shadowTransform[1], position;
|
||||
DP4 result.texcoord[1].z, shadowTransform[2], position;
|
||||
DP4 result.texcoord[1].w, shadowTransform[3], position;
|
||||
MOV v_normal, normal;
|
||||
#endif
|
||||
|
||||
MAD result.texcoord[2], position.xzzz, losTransform.x, losTransform.y;
|
||||
//// Texture coordinates:
|
||||
|
||||
MOV v_tex, vertex.texcoord[0];
|
||||
|
||||
#if USE_SHADOW
|
||||
DP4 v_shadow.x, shadowTransform[0], position;
|
||||
DP4 v_shadow.y, shadowTransform[1], position;
|
||||
DP4 v_shadow.z, shadowTransform[2], position;
|
||||
DP4 v_shadow.w, shadowTransform[3], position;
|
||||
#endif
|
||||
|
||||
MAD v_los, position.xzzz, losTransform.x, losTransform.y;
|
||||
|
||||
END
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
<program type="arb">
|
||||
|
||||
<vertex file="arb/model_common.vp">
|
||||
<uniform name="sunDir" loc="0" type="vec3"/>
|
||||
<uniform name="sunColor" loc="1" type="vec3"/>
|
||||
<uniform name="losTransform" loc="2" type="vec2"/>
|
||||
<uniform name="shadowTransform" loc="3" type="mat4"/>
|
||||
<uniform if="USE_INSTANCING" name="instancingTransform" loc="7" type="mat4"/>
|
||||
<uniform name="cameraPos" loc="0" type="vec3"/>
|
||||
<uniform name="sunDir" loc="1" type="vec3"/>
|
||||
<uniform name="sunColor" loc="2" type="vec3"/>
|
||||
<uniform name="losTransform" loc="3" type="vec2"/>
|
||||
<uniform name="shadowTransform" loc="4" type="mat4"/>
|
||||
<uniform if="USE_INSTANCING" name="instancingTransform" loc="8" type="mat4"/>
|
||||
<stream name="pos"/>
|
||||
<stream name="normal"/>
|
||||
<stream name="uv0"/>
|
||||
|
|
@ -23,6 +24,8 @@
|
|||
<uniform name="ambient" loc="2" type="vec3"/>
|
||||
<uniform name="shadowOffsets1" loc="3" type="vec4"/>
|
||||
<uniform name="shadowOffsets2" loc="4" type="vec4"/>
|
||||
<uniform name="specularPower" loc="5" type="float"/>
|
||||
<uniform name="specularColor" loc="6" type="vec3"/>
|
||||
</fragment>
|
||||
|
||||
</program>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
#version 110
|
||||
#version 120
|
||||
|
||||
uniform sampler2D baseTex;
|
||||
uniform sampler2D losTex;
|
||||
|
||||
#ifdef USE_SHADOW
|
||||
#ifdef USE_SHADOW_SAMPLER
|
||||
#if USE_SHADOW
|
||||
#if USE_SHADOW_SAMPLER
|
||||
uniform sampler2DShadow shadowTex;
|
||||
#else
|
||||
uniform sampler2D shadowTex;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_OBJECTCOLOR
|
||||
#if USE_OBJECTCOLOR
|
||||
uniform vec3 objectColor;
|
||||
#else
|
||||
#ifdef USE_PLAYERCOLOR
|
||||
#if USE_PLAYERCOLOR
|
||||
uniform vec3 playerColor;
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -29,11 +29,18 @@ varying vec2 v_tex;
|
|||
varying vec4 v_shadow;
|
||||
varying vec2 v_los;
|
||||
|
||||
#if USE_SPECULAR
|
||||
uniform float specularPower;
|
||||
uniform vec3 specularColor;
|
||||
varying vec3 v_normal;
|
||||
varying vec3 v_half;
|
||||
#endif
|
||||
|
||||
float get_shadow()
|
||||
{
|
||||
#ifdef USE_SHADOW
|
||||
#ifdef USE_SHADOW_SAMPLER
|
||||
#ifdef USE_SHADOW_PCF
|
||||
#if USE_SHADOW
|
||||
#if USE_SHADOW_SAMPLER
|
||||
#if USE_SHADOW_PCF
|
||||
return 0.25 * (
|
||||
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.xy, v_shadow.z)).a +
|
||||
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.zw, v_shadow.z)).a +
|
||||
|
|
@ -46,7 +53,7 @@ float get_shadow()
|
|||
#else
|
||||
if (v_shadow.z >= 1.0)
|
||||
return 1.0;
|
||||
#ifdef USE_SHADOW_PCF
|
||||
#if USE_SHADOW_PCF
|
||||
return (
|
||||
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.xy).x ? 0.25 : 0.0) +
|
||||
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.zw).x ? 0.25 : 0.0) +
|
||||
|
|
@ -66,7 +73,7 @@ void main()
|
|||
{
|
||||
vec4 tex = texture2D(baseTex, v_tex);
|
||||
|
||||
#ifdef USE_TRANSPARENT
|
||||
#if USE_TRANSPARENT
|
||||
gl_FragColor.a = tex.a;
|
||||
#else
|
||||
gl_FragColor.a = 1.0;
|
||||
|
|
@ -77,22 +84,34 @@ void main()
|
|||
discard;
|
||||
#endif
|
||||
|
||||
vec3 color = tex.rgb;
|
||||
vec3 texdiffuse = tex.rgb;
|
||||
|
||||
// Apply-coloring based on texture alpha
|
||||
#ifdef USE_OBJECTCOLOR
|
||||
color *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a);
|
||||
#if USE_OBJECTCOLOR
|
||||
texdiffuse *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a);
|
||||
#else
|
||||
#ifdef USE_PLAYERCOLOR
|
||||
color *= mix(playerColor, vec3(1.0, 1.0, 1.0), tex.a);
|
||||
#if USE_PLAYERCOLOR
|
||||
texdiffuse *= mix(playerColor, vec3(1.0, 1.0, 1.0), tex.a);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
color *= v_lighting * get_shadow() + ambient;
|
||||
|
||||
color *= texture2D(losTex, v_los).a;
|
||||
vec3 sundiffuse = v_lighting;
|
||||
|
||||
#if USE_SPECULAR
|
||||
// Interpolated v_normal needs to be re-normalized since it varies
|
||||
// significantly between adjacent vertexes;
|
||||
// v_half changes very gradually so don't bother normalizing that
|
||||
vec3 specular = specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower);
|
||||
#else
|
||||
vec3 specular = vec3(0.0);
|
||||
#endif
|
||||
|
||||
vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient;
|
||||
|
||||
float los = texture2D(losTex, v_los).a;
|
||||
color *= los;
|
||||
|
||||
color *= shadingColor;
|
||||
|
||||
|
||||
gl_FragColor.rgb = color;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#version 110
|
||||
#version 120
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform vec3 cameraPos;
|
||||
uniform vec3 sunDir;
|
||||
uniform vec3 sunColor;
|
||||
uniform vec2 losTransform;
|
||||
|
|
@ -12,15 +13,20 @@ varying vec2 v_tex;
|
|||
varying vec4 v_shadow;
|
||||
varying vec2 v_los;
|
||||
|
||||
#if USE_SPECULAR
|
||||
varying vec3 v_normal;
|
||||
varying vec3 v_half;
|
||||
#endif
|
||||
|
||||
attribute vec3 a_vertex;
|
||||
attribute vec3 a_normal;
|
||||
attribute vec2 a_uv0;
|
||||
|
||||
void main()
|
||||
{
|
||||
#ifdef USE_INSTANCING
|
||||
#if USE_INSTANCING
|
||||
vec4 position = instancingTransform * vec4(a_vertex, 1.0);
|
||||
vec3 normal = (instancingTransform * vec4(a_normal, 0.0)).xyz;
|
||||
vec3 normal = mat3(instancingTransform) * a_normal;
|
||||
#else
|
||||
vec4 position = vec4(a_vertex, 1.0);
|
||||
vec3 normal = a_normal;
|
||||
|
|
@ -28,6 +34,13 @@ void main()
|
|||
|
||||
gl_Position = transform * position;
|
||||
|
||||
#if USE_SPECULAR
|
||||
vec3 eyeVec = normalize(cameraPos.xyz - position.xyz);
|
||||
vec3 sunVec = -sunDir;
|
||||
v_half = normalize(sunVec + eyeVec);
|
||||
v_normal = normal;
|
||||
#endif
|
||||
|
||||
v_lighting = max(0.0, dot(normal, -sunDir)) * sunColor;
|
||||
v_tex = a_uv0;
|
||||
v_shadow = shadowTransform * position;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#version 110
|
||||
#version 120
|
||||
|
||||
uniform sampler2D baseTex;
|
||||
uniform sampler2D blendTex;
|
||||
uniform sampler2D losTex;
|
||||
|
||||
#ifdef USE_SHADOW
|
||||
#ifdef USE_SHADOW_SAMPLER
|
||||
#if USE_SHADOW
|
||||
#if USE_SHADOW_SAMPLER
|
||||
uniform sampler2DShadow shadowTex;
|
||||
#else
|
||||
uniform sampler2D shadowTex;
|
||||
|
|
@ -23,11 +23,18 @@ varying vec4 v_shadow;
|
|||
varying vec2 v_los;
|
||||
varying vec2 v_blend;
|
||||
|
||||
#if USE_SPECULAR
|
||||
uniform float specularPower;
|
||||
uniform vec3 specularColor;
|
||||
varying vec3 v_normal;
|
||||
varying vec3 v_half;
|
||||
#endif
|
||||
|
||||
float get_shadow()
|
||||
{
|
||||
#ifdef USE_SHADOW
|
||||
#ifdef USE_SHADOW_SAMPLER
|
||||
#ifdef USE_SHADOW_PCF
|
||||
#if USE_SHADOW
|
||||
#if USE_SHADOW_SAMPLER
|
||||
#if USE_SHADOW_PCF
|
||||
return 0.25 * (
|
||||
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.xy, v_shadow.z)).a +
|
||||
shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.zw, v_shadow.z)).a +
|
||||
|
|
@ -40,7 +47,7 @@ float get_shadow()
|
|||
#else
|
||||
if (v_shadow.z >= 1.0)
|
||||
return 1.0;
|
||||
#ifdef USE_SHADOW_PCF
|
||||
#if USE_SHADOW_PCF
|
||||
return (
|
||||
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.xy).x ? 0.25 : 0.0) +
|
||||
(v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets1.zw).x ? 0.25 : 0.0) +
|
||||
|
|
@ -58,26 +65,38 @@ float get_shadow()
|
|||
|
||||
void main()
|
||||
{
|
||||
#ifdef BLEND
|
||||
#if BLEND
|
||||
// Use alpha from blend texture
|
||||
gl_FragColor.a = 1.0 - texture2D(blendTex, v_blend).a;
|
||||
#endif
|
||||
|
||||
// Load diffuse colour
|
||||
vec4 color = texture2D(baseTex, v_tex);
|
||||
vec4 tex = texture2D(baseTex, v_tex);
|
||||
|
||||
#ifdef DECAL
|
||||
#if DECAL
|
||||
// Use alpha from main texture
|
||||
gl_FragColor.a = color.a;
|
||||
gl_FragColor.a = tex.a;
|
||||
#endif
|
||||
|
||||
color.rgb *= v_lighting * get_shadow() + ambient;
|
||||
|
||||
color *= texture2D(losTex, v_los).a;
|
||||
vec3 texdiffuse = tex.rgb;
|
||||
vec3 sundiffuse = v_lighting;
|
||||
|
||||
#ifdef DECAL
|
||||
color.rgb *= shadingColor;
|
||||
#if USE_SPECULAR
|
||||
// Interpolated v_normal needs to be re-normalized since it varies
|
||||
// significantly between adjacenent vertexes;
|
||||
// v_half changes very gradually so don't bother normalizing that
|
||||
vec3 specular = specularColor * pow(max(0.0, dot(normalize(v_normal), v_half)), specularPower);
|
||||
#else
|
||||
vec3 specular = vec3(0.0);
|
||||
#endif
|
||||
|
||||
gl_FragColor.rgb = color.rgb;
|
||||
vec3 color = (texdiffuse * sundiffuse + specular) * get_shadow() + texdiffuse * ambient;
|
||||
|
||||
float los = texture2D(losTex, v_los).a;
|
||||
color *= los;
|
||||
|
||||
#if DECAL
|
||||
color *= shadingColor;
|
||||
#endif
|
||||
|
||||
gl_FragColor.rgb = color;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#version 110
|
||||
#version 120
|
||||
|
||||
uniform mat4 transform;
|
||||
uniform vec3 cameraPos;
|
||||
uniform vec3 sunDir;
|
||||
uniform vec3 sunColor;
|
||||
uniform vec2 textureTransform;
|
||||
uniform vec2 losTransform;
|
||||
|
|
@ -12,6 +14,11 @@ varying vec4 v_shadow;
|
|||
varying vec2 v_los;
|
||||
varying vec2 v_blend;
|
||||
|
||||
#if USE_SPECULAR
|
||||
varying vec3 v_normal;
|
||||
varying vec3 v_half;
|
||||
#endif
|
||||
|
||||
attribute vec3 a_vertex;
|
||||
attribute vec3 a_color;
|
||||
attribute vec2 a_uv0;
|
||||
|
|
@ -19,31 +26,44 @@ attribute vec2 a_uv1;
|
|||
|
||||
void main()
|
||||
{
|
||||
gl_Position = transform * vec4(a_vertex, 1.0);
|
||||
vec4 position = vec4(a_vertex, 1.0);
|
||||
|
||||
gl_Position = transform * position;
|
||||
|
||||
v_lighting = a_color * sunColor;
|
||||
|
||||
#ifdef DECAL
|
||||
v_tex = a_uv0;
|
||||
#else
|
||||
// Compute texcoords from position and terrain-texture-dependent transform
|
||||
float c = textureTransform.x;
|
||||
float s = -textureTransform.y;
|
||||
v_tex = vec2(a_vertex.x * c + a_vertex.z * -s, a_vertex.x * -s + a_vertex.z * -c);
|
||||
#if DECAL
|
||||
v_tex = a_uv0;
|
||||
#else
|
||||
// Compute texcoords from position and terrain-texture-dependent transform
|
||||
float c = textureTransform.x;
|
||||
float s = -textureTransform.y;
|
||||
v_tex = vec2(a_vertex.x * c + a_vertex.z * -s, a_vertex.x * -s + a_vertex.z * -c);
|
||||
|
||||
#ifdef GL_ES
|
||||
// XXX: Ugly hack to hide some precision issues in GLES
|
||||
v_tex = mod(v_tex, vec2(9.0, 9.0));
|
||||
#endif
|
||||
#endif
|
||||
#if GL_ES
|
||||
// XXX: Ugly hack to hide some precision issues in GLES
|
||||
v_tex = mod(v_tex, vec2(9.0, 9.0));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BLEND
|
||||
v_blend = a_uv1;
|
||||
#endif
|
||||
#if BLEND
|
||||
v_blend = a_uv1;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SHADOW
|
||||
v_shadow = shadowTransform * vec4(a_vertex, 1.0);
|
||||
#endif
|
||||
#if USE_SHADOW
|
||||
v_shadow = shadowTransform * vec4(a_vertex, 1.0);
|
||||
#endif
|
||||
|
||||
#if USE_SPECULAR
|
||||
// TODO: for proper specular terrain, we need to provide vertex normals.
|
||||
// But we don't have that yet, so do something wrong instead.
|
||||
vec3 normal = vec3(0, 1, 0);
|
||||
|
||||
vec3 eyeVec = normalize(cameraPos.xyz - position.xyz);
|
||||
vec3 sunVec = -sunDir;
|
||||
v_half = normalize(sunVec + eyeVec);
|
||||
v_normal = normal;
|
||||
#endif
|
||||
|
||||
v_los = a_vertex.xz * losTransform.x + losTransform.yy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,8 +195,8 @@ void CCamera::GetScreenCoordinates(const CVector3D& world, float& x, float& y) c
|
|||
|
||||
CVector4D screenspace = transform.Transform(CVector4D(world.X, world.Y, world.Z, 1.0f));
|
||||
|
||||
x = screenspace.m_X / screenspace.m_W;
|
||||
y = screenspace.m_Y / screenspace.m_W;
|
||||
x = screenspace.X / screenspace.W;
|
||||
y = screenspace.Y / screenspace.W;
|
||||
x = (x + 1) * 0.5f * g_Renderer.GetWidth();
|
||||
y = (1 - y) * 0.5f * g_Renderer.GetHeight();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ void CCinemaPath::DrawSpline(const CVector4D& RGBA, int smoothness, bool lines)
|
|||
#warning TODO: do something about CCinemaPath on GLES
|
||||
#else
|
||||
|
||||
glColor4f( RGBA.m_X, RGBA.m_Y, RGBA.m_Z, RGBA.m_W );
|
||||
glColor4f( RGBA.X, RGBA.Y, RGBA.Z, RGBA.W );
|
||||
if ( lines )
|
||||
{
|
||||
glLineWidth(1.8f);
|
||||
|
|
|
|||
|
|
@ -23,16 +23,10 @@ static CColor BrokenColor(0.3f, 0.3f, 0.3f, 1.0f);
|
|||
|
||||
CMaterial::CMaterial() :
|
||||
m_AlphaBlending(false),
|
||||
m_PlayerID(INVALID_PLAYER),
|
||||
m_ObjectColor(BrokenColor)
|
||||
m_PlayerID(INVALID_PLAYER)
|
||||
{
|
||||
}
|
||||
|
||||
void CMaterial::SetObjectColor(const CColor& colour)
|
||||
{
|
||||
m_ObjectColor = colour;
|
||||
}
|
||||
|
||||
void CMaterial::SetDiffuseTexture(const CTexturePtr& texture)
|
||||
{
|
||||
m_DiffuseTexture = texture;
|
||||
|
|
@ -47,3 +41,8 @@ void CMaterial::AddShaderDefine(const char* key, const char* value)
|
|||
{
|
||||
m_ShaderDefines.Add(key, value);
|
||||
}
|
||||
|
||||
void CMaterial::AddStaticUniform(const char* key, const CVector4D& value)
|
||||
{
|
||||
m_StaticUniforms.Add(key, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,11 +36,6 @@ public:
|
|||
void SetUsesAlphaBlending(bool flag) { m_AlphaBlending = flag; }
|
||||
bool UsesAlphaBlending() { return m_AlphaBlending; }
|
||||
|
||||
// Color used for "objectColor" in shaders when USE_OBJECTCOLOR is set,
|
||||
// to allow e.g. variations in horse colorings
|
||||
void SetObjectColor(const CColor &colour);
|
||||
CColor GetObjectColor() { return m_ObjectColor; }
|
||||
|
||||
void SetDiffuseTexture(const CTexturePtr& texture);
|
||||
const CTexturePtr& GetDiffuseTexture() const { return m_DiffuseTexture; }
|
||||
|
||||
|
|
@ -50,15 +45,18 @@ public:
|
|||
void AddShaderDefine(const char* key, const char* value);
|
||||
const CShaderDefines& GetShaderDefines() const { return m_ShaderDefines; }
|
||||
|
||||
void AddStaticUniform(const char* key, const CVector4D& value);
|
||||
const CShaderUniforms& GetStaticUniforms() const { return m_StaticUniforms; }
|
||||
|
||||
private:
|
||||
CTexturePtr m_DiffuseTexture;
|
||||
CStrIntern m_ShaderEffect;
|
||||
CShaderDefines m_ShaderDefines;
|
||||
CShaderUniforms m_StaticUniforms;
|
||||
|
||||
bool m_AlphaBlending;
|
||||
|
||||
player_id_t m_PlayerID;
|
||||
CColor m_ObjectColor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,10 +16,13 @@
|
|||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "MaterialManager.h"
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "maths/Vector4D.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "MaterialManager.h"
|
||||
|
||||
CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname)
|
||||
{
|
||||
|
|
@ -39,6 +42,7 @@ CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname)
|
|||
EL(alpha_blending);
|
||||
EL(define);
|
||||
EL(shader);
|
||||
EL(uniform);
|
||||
AT(effect);
|
||||
AT(name);
|
||||
AT(value);
|
||||
|
|
@ -66,6 +70,13 @@ CMaterial CMaterialManager::LoadMaterial(const VfsPath& pathname)
|
|||
{
|
||||
material.AddShaderDefine(attrs.GetNamedItem(at_name).c_str(), attrs.GetNamedItem(at_value).c_str());
|
||||
}
|
||||
else if (token == el_uniform)
|
||||
{
|
||||
std::stringstream str(attrs.GetNamedItem(at_value));
|
||||
CVector4D vec;
|
||||
str >> vec.X >> vec.Y >> vec.Z >> vec.W;
|
||||
material.AddStaticUniform(attrs.GetNamedItem(at_name).c_str(), vec);
|
||||
}
|
||||
}
|
||||
|
||||
m_Materials[pathname] = material;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <map>
|
||||
#include "Material.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
|
||||
class CMaterialManager
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ bool CObjectEntry::BuildVariation(const std::vector<std::set<CStr> >& selections
|
|||
delete m_Model;
|
||||
m_Model = model;
|
||||
model->SetMaterial(g_Renderer.GetMaterialManager().LoadMaterial(m_Base->m_Material));
|
||||
model->GetMaterial().SetObjectColor(m_Color);
|
||||
model->GetMaterial().AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a));
|
||||
model->InitModel(modeldef);
|
||||
|
||||
CTextureProperties textureProps(m_TextureName);
|
||||
|
|
|
|||
|
|
@ -19,70 +19,101 @@
|
|||
|
||||
#include "ShaderDefines.h"
|
||||
|
||||
#include "maths/Vector4D.h"
|
||||
#include "ps/ThreadUtil.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
size_t hash_value(const CStrIntern& v)
|
||||
{
|
||||
return v.GetHash();
|
||||
}
|
||||
|
||||
size_t hash_value(const CShaderDefines::SItems& items)
|
||||
size_t hash_value(const CVector4D& v)
|
||||
{
|
||||
size_t hash = 0;
|
||||
boost::hash_combine(hash, v.X);
|
||||
boost::hash_combine(hash, v.Y);
|
||||
boost::hash_combine(hash, v.Z);
|
||||
boost::hash_combine(hash, v.W);
|
||||
return hash;
|
||||
}
|
||||
|
||||
size_t hash_value(const CShaderParams<CStrIntern>::SItems& items)
|
||||
{
|
||||
return items.hash;
|
||||
}
|
||||
|
||||
bool operator==(const CShaderDefines::SItems& a, const CShaderDefines::SItems& b)
|
||||
size_t hash_value(const CShaderParams<CVector4D>::SItems& items)
|
||||
{
|
||||
return items.hash;
|
||||
}
|
||||
|
||||
bool operator==(const CShaderParams<CStrIntern>::SItems& a, const CShaderParams<CStrIntern>::SItems& b)
|
||||
{
|
||||
return a.items == b.items;
|
||||
}
|
||||
|
||||
bool operator==(const CShaderParams<CVector4D>::SItems& a, const CShaderParams<CVector4D>::SItems& b)
|
||||
{
|
||||
return a.items == b.items;
|
||||
}
|
||||
|
||||
template<typename value_t>
|
||||
struct ItemNameCmp
|
||||
{
|
||||
typedef CShaderDefines::SItems::Item first_argument_type;
|
||||
typedef CShaderDefines::SItems::Item second_argument_type;
|
||||
bool operator()(const CShaderDefines::SItems::Item& a, const CShaderDefines::SItems::Item& b) const
|
||||
typedef typename CShaderParams<value_t>::SItems::Item Item;
|
||||
|
||||
typedef Item first_argument_type;
|
||||
typedef Item second_argument_type;
|
||||
bool operator()(const Item& a, const Item& b) const
|
||||
{
|
||||
return a.first < b.first;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename value_t>
|
||||
struct ItemNameGeq
|
||||
{
|
||||
bool operator()(const CShaderDefines::SItems::Item& a, const CShaderDefines::SItems::Item& b) const
|
||||
typedef typename CShaderParams<value_t>::SItems::Item Item;
|
||||
|
||||
bool operator()(const Item& a, const Item& b) const
|
||||
{
|
||||
return !(b.first < a.first);
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::unordered_map<CShaderDefines::SItems, shared_ptr<CShaderDefines::SItems> > InternedItems_t;
|
||||
static InternedItems_t g_InternedItems;
|
||||
|
||||
CShaderDefines::SItems* CShaderDefines::GetInterned(const SItems& items)
|
||||
template<typename value_t>
|
||||
typename CShaderParams<value_t>::SItems* CShaderParams<value_t>::GetInterned(const SItems& items)
|
||||
{
|
||||
ENSURE(ThreadUtil::IsMainThread()); // g_InternedItems is not thread-safe
|
||||
ENSURE(ThreadUtil::IsMainThread()); // s_InternedItems is not thread-safe
|
||||
|
||||
InternedItems_t::iterator it = g_InternedItems.find(items);
|
||||
if (it != g_InternedItems.end())
|
||||
InternedItems_t::iterator it = s_InternedItems.find(items);
|
||||
if (it != s_InternedItems.end())
|
||||
return it->second.get();
|
||||
|
||||
// Sanity test: the items list is meant to be sorted by name.
|
||||
// This is a reasonable place to verify that, since this will be called once per distinct SItems.
|
||||
ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate<ItemNameCmp>(ItemNameCmp())) == items.items.end());
|
||||
typedef ItemNameCmp<value_t> Cmp;
|
||||
ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate<Cmp>(Cmp())) == items.items.end());
|
||||
|
||||
shared_ptr<SItems> ptr(new SItems(items));
|
||||
g_InternedItems.insert(std::make_pair(items, ptr));
|
||||
s_InternedItems.insert(std::make_pair(items, ptr));
|
||||
return ptr.get();
|
||||
}
|
||||
|
||||
CShaderDefines::CShaderDefines()
|
||||
template<typename value_t>
|
||||
CShaderParams<value_t>::CShaderParams()
|
||||
{
|
||||
SItems items;
|
||||
items.RecalcHash();
|
||||
m_Items = GetInterned(items);
|
||||
}
|
||||
|
||||
void CShaderDefines::Add(const char* name, const char* value)
|
||||
template<typename value_t>
|
||||
void CShaderParams<value_t>::Set(CStrIntern name, const value_t& value)
|
||||
{
|
||||
SItems items = *m_Items;
|
||||
|
||||
SItems::Item addedItem = std::make_pair(CStrIntern(name), CStrIntern(value));
|
||||
SItems::Item addedItem = std::make_pair(name, value);
|
||||
|
||||
// Add the new item in a way that preserves the sortedness and uniqueness of item names
|
||||
for (std::vector<SItems::Item>::iterator it = items.items.begin(); ; ++it)
|
||||
|
|
@ -103,29 +134,55 @@ void CShaderDefines::Add(const char* name, const char* value)
|
|||
m_Items = GetInterned(items);
|
||||
}
|
||||
|
||||
void CShaderDefines::Add(const CShaderDefines& defines)
|
||||
template<typename value_t>
|
||||
void CShaderParams<value_t>::SetMany(const CShaderParams& params)
|
||||
{
|
||||
SItems items;
|
||||
// set_union merges the two sorted lists into a new sorted list;
|
||||
// if two items are equivalent (i.e. equal names, possibly different values)
|
||||
// then the one from the first list is kept
|
||||
std::set_union(
|
||||
defines.m_Items->items.begin(), defines.m_Items->items.end(),
|
||||
params.m_Items->items.begin(), params.m_Items->items.end(),
|
||||
m_Items->items.begin(), m_Items->items.end(),
|
||||
std::inserter(items.items, items.items.begin()),
|
||||
ItemNameCmp());
|
||||
ItemNameCmp<value_t>());
|
||||
items.RecalcHash();
|
||||
m_Items = GetInterned(items);
|
||||
}
|
||||
|
||||
std::map<CStr, CStr> CShaderDefines::GetMap() const
|
||||
template<typename value_t>
|
||||
std::map<CStrIntern, value_t> CShaderParams<value_t>::GetMap() const
|
||||
{
|
||||
std::map<CStr, CStr> ret;
|
||||
std::map<CStrIntern, value_t> ret;
|
||||
for (size_t i = 0; i < m_Items->items.size(); ++i)
|
||||
ret[m_Items->items[i].first.string()] = m_Items->items[i].second.string();
|
||||
ret[m_Items->items[i].first] = m_Items->items[i].second;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename value_t>
|
||||
size_t CShaderParams<value_t>::GetHash() const
|
||||
{
|
||||
return m_Items->hash;
|
||||
}
|
||||
|
||||
template<typename value_t>
|
||||
void CShaderParams<value_t>::SItems::RecalcHash()
|
||||
{
|
||||
size_t h = 0;
|
||||
for (size_t i = 0; i < items.size(); ++i)
|
||||
{
|
||||
boost::hash_combine(h, items[i].first);
|
||||
boost::hash_combine(h, items[i].second);
|
||||
}
|
||||
hash = h;
|
||||
}
|
||||
|
||||
|
||||
void CShaderDefines::Add(const char* name, const char* value)
|
||||
{
|
||||
Set(CStrIntern(name), CStrIntern(value));
|
||||
}
|
||||
|
||||
int CShaderDefines::GetInt(const char* name) const
|
||||
{
|
||||
CStrIntern nameIntern(name);
|
||||
|
|
@ -142,18 +199,43 @@ int CShaderDefines::GetInt(const char* name) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
size_t CShaderDefines::GetHash() const
|
||||
|
||||
void CShaderUniforms::Add(const char* name, const CVector4D& value)
|
||||
{
|
||||
return m_Items->hash;
|
||||
Set(CStrIntern(name), value);
|
||||
}
|
||||
|
||||
void CShaderDefines::SItems::RecalcHash()
|
||||
CVector4D CShaderUniforms::GetVector(const char* name) const
|
||||
{
|
||||
size_t h = 0;
|
||||
CStrIntern nameIntern(name);
|
||||
for (size_t i = 0; i < m_Items->items.size(); ++i)
|
||||
{
|
||||
if (m_Items->items[i].first == nameIntern)
|
||||
{
|
||||
return m_Items->items[i].second;
|
||||
}
|
||||
}
|
||||
return CVector4D();
|
||||
}
|
||||
|
||||
void CShaderUniforms::BindUniforms(const CShaderProgramPtr& shader) const
|
||||
{
|
||||
const std::vector<SItems::Item>& items = m_Items->items;
|
||||
for (size_t i = 0; i < items.size(); ++i)
|
||||
{
|
||||
boost::hash_combine(h, items[i].first.GetHash());
|
||||
boost::hash_combine(h, items[i].second.GetHash());
|
||||
CShaderProgram::Binding binding = shader->GetUniformBinding(items[i].first);
|
||||
if (binding.Active())
|
||||
{
|
||||
CVector4D v = items[i].second;
|
||||
shader->Uniform(binding, v.X, v.Y, v.Z, v.W);
|
||||
}
|
||||
}
|
||||
hash = h;
|
||||
}
|
||||
|
||||
// Explicit instantiations:
|
||||
|
||||
boost::unordered_map<CShaderParams<CStrIntern>::SItems, shared_ptr<CShaderParams<CStrIntern>::SItems> > CShaderParams<CStrIntern>::s_InternedItems;
|
||||
boost::unordered_map<CShaderParams<CVector4D>::SItems, shared_ptr<CShaderParams<CVector4D>::SItems> > CShaderParams<CVector4D>::s_InternedItems;
|
||||
|
||||
template class CShaderParams<CStrIntern>;
|
||||
template class CShaderParams<CVector4D>;
|
||||
|
|
|
|||
|
|
@ -18,47 +18,48 @@
|
|||
#ifndef INCLUDED_SHADERDEFINES
|
||||
#define INCLUDED_SHADERDEFINES
|
||||
|
||||
#include "graphics/ShaderProgram.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "ps/CStrIntern.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
class CVector4D;
|
||||
|
||||
/**
|
||||
* Represents a mapping of name to value strings, for use with
|
||||
* \#if and \#ifdef and similar conditionals in shaders.
|
||||
* Represents a mapping of name strings to value, for use with
|
||||
* CShaderDefines (values are strings) and CShaderUniforms (values are vec4s).
|
||||
*
|
||||
* Stored as interned vectors of string-pairs, to support high performance
|
||||
* Stored as interned vectors of name-value pairs, to support high performance
|
||||
* comparison operators.
|
||||
*
|
||||
* Not thread-safe - must only be used from the main thread.
|
||||
*/
|
||||
class CShaderDefines
|
||||
template<typename value_t>
|
||||
class CShaderParams
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create an empty map of defines.
|
||||
*/
|
||||
CShaderDefines();
|
||||
CShaderParams();
|
||||
|
||||
/**
|
||||
* Add a name and associated value to the map of defines.
|
||||
* Add a name and associated value to the map of parameters.
|
||||
* If the name is already defined, its value will be replaced.
|
||||
*/
|
||||
void Add(const char* name, const char* value);
|
||||
|
||||
/**
|
||||
* Add all the names and values from another set of defines.
|
||||
* If any name is already defined in this object, its value will be replaced.
|
||||
*/
|
||||
void Add(const CShaderDefines& defines);
|
||||
void Set(CStrIntern name, const value_t& value);
|
||||
|
||||
/**
|
||||
* Return the value for the given name as an integer, or 0 if not defined.
|
||||
* Add all the names and values from another set of parameters.
|
||||
* If any name is already defined in this object, its value will be replaced.
|
||||
*/
|
||||
int GetInt(const char* name) const;
|
||||
void SetMany(const CShaderParams& params);
|
||||
|
||||
/**
|
||||
* Return a copy of the current name/value mapping.
|
||||
*/
|
||||
std::map<CStr, CStr> GetMap() const;
|
||||
std::map<CStrIntern, value_t> GetMap() const;
|
||||
|
||||
/**
|
||||
* Return a hash of the current mapping.
|
||||
|
|
@ -70,23 +71,31 @@ public:
|
|||
* The order may be different each time the application is run
|
||||
* (it is based on interned memory addresses).
|
||||
*/
|
||||
bool operator<(const CShaderDefines& b) const
|
||||
bool operator<(const CShaderParams& b) const
|
||||
{
|
||||
return m_Items < b.m_Items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality comparison.
|
||||
* Fast equality comparison.
|
||||
*/
|
||||
bool operator==(const CShaderDefines& b) const
|
||||
bool operator==(const CShaderParams& b) const
|
||||
{
|
||||
return m_Items == b.m_Items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast inequality comparison.
|
||||
*/
|
||||
bool operator!=(const CShaderParams& b) const
|
||||
{
|
||||
return m_Items != b.m_Items;
|
||||
}
|
||||
|
||||
struct SItems
|
||||
{
|
||||
// Name/value pair
|
||||
typedef std::pair<CStrIntern, CStrIntern> Item;
|
||||
typedef std::pair<CStrIntern, value_t> Item;
|
||||
|
||||
// Sorted by name; no duplicated names
|
||||
std::vector<Item> items;
|
||||
|
|
@ -96,9 +105,13 @@ public:
|
|||
void RecalcHash();
|
||||
};
|
||||
|
||||
private:
|
||||
protected:
|
||||
SItems* m_Items; // interned value
|
||||
|
||||
private:
|
||||
typedef boost::unordered_map<SItems, shared_ptr<SItems> > InternedItems_t;
|
||||
static InternedItems_t s_InternedItems;
|
||||
|
||||
/**
|
||||
* Returns a pointer to an SItems equal to @p items.
|
||||
* The pointer will be valid forever, and the same pointer will be returned
|
||||
|
|
@ -107,4 +120,51 @@ private:
|
|||
static SItems* GetInterned(const SItems& items);
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a mapping of name strings to value strings, for use with
|
||||
* \#if and \#ifdef and similar conditionals in shaders.
|
||||
*
|
||||
* Not thread-safe - must only be used from the main thread.
|
||||
*/
|
||||
class CShaderDefines : public CShaderParams<CStrIntern>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Add a name and associated value to the map of defines.
|
||||
* If the name is already defined, its value will be replaced.
|
||||
*/
|
||||
void Add(const char* name, const char* value);
|
||||
|
||||
/**
|
||||
* Return the value for the given name as an integer, or 0 if not defined.
|
||||
*/
|
||||
int GetInt(const char* name) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a mapping of name strings to value CVector4Ds, for use with
|
||||
* uniforms in shaders.
|
||||
*
|
||||
* Not thread-safe - must only be used from the main thread.
|
||||
*/
|
||||
class CShaderUniforms : public CShaderParams<CVector4D>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Add a name and associated value to the map of uniforms.
|
||||
* If the name is already defined, its value will be replaced.
|
||||
*/
|
||||
void Add(const char* name, const CVector4D& value);
|
||||
|
||||
/**
|
||||
* Return the value for the given name, or (0,0,0,0) if not defined.
|
||||
*/
|
||||
CVector4D GetVector(const char* name) const;
|
||||
|
||||
/**
|
||||
* Bind the collection of uniforms onto the given shader.
|
||||
*/
|
||||
void BindUniforms(const CShaderProgramPtr& shader) const;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_SHADERDEFINES
|
||||
|
|
|
|||
|
|
@ -192,8 +192,8 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
|||
#undef EL
|
||||
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStr, CStr> baseDefinesMap = baseDefines.GetMap();
|
||||
for (std::map<CStr, CStr>::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
|
||||
std::map<CStrIntern, CStrIntern> baseDefinesMap = baseDefines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
|
||||
XMBElement Root = XeroFile.GetRoot();
|
||||
|
|
@ -202,9 +202,9 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
|||
VfsPath vertexFile;
|
||||
VfsPath fragmentFile;
|
||||
CShaderDefines defines = baseDefines;
|
||||
std::map<CStr, int> vertexUniforms;
|
||||
std::map<CStr, int> fragmentUniforms;
|
||||
std::map<CStr, int> vertexAttribs;
|
||||
std::map<CStrIntern, int> vertexUniforms;
|
||||
std::map<CStrIntern, int> fragmentUniforms;
|
||||
std::map<CStrIntern, int> vertexAttribs;
|
||||
int streamFlags = 0;
|
||||
|
||||
XERO_ITER_EL(Root, Child)
|
||||
|
|
@ -227,7 +227,7 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
|||
|
||||
if (Param.GetNodeName() == el_uniform)
|
||||
{
|
||||
vertexUniforms[Attrs.GetNamedItem(at_name)] = Attrs.GetNamedItem(at_loc).ToInt();
|
||||
vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt();
|
||||
}
|
||||
else if (Param.GetNodeName() == el_stream)
|
||||
{
|
||||
|
|
@ -250,7 +250,7 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
|||
else if (Param.GetNodeName() == el_attrib)
|
||||
{
|
||||
int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics));
|
||||
vertexAttribs[Attrs.GetNamedItem(at_name)] = attribLoc;
|
||||
vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -268,7 +268,7 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi
|
|||
|
||||
if (Param.GetNodeName() == el_uniform)
|
||||
{
|
||||
fragmentUniforms[Attrs.GetNamedItem(at_name)] = Attrs.GetNamedItem(at_loc).ToInt();
|
||||
fragmentUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -377,7 +377,7 @@ CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDef
|
|||
|
||||
// Merge the two sets of defines, so NewEffect doesn't have to care about the split
|
||||
CShaderDefines defines(defines1);
|
||||
defines.Add(defines2);
|
||||
defines.SetMany(defines2);
|
||||
|
||||
CShaderTechniquePtr tech(new CShaderTechnique());
|
||||
if (!NewEffect(name.c_str(), defines, tech))
|
||||
|
|
@ -444,8 +444,8 @@ bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefin
|
|||
|
||||
// Prepare the preprocessor for conditional tests
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStr, CStr> baseDefinesMap = baseDefines.GetMap();
|
||||
for (std::map<CStr, CStr>::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
|
||||
std::map<CStrIntern, CStrIntern> baseDefinesMap = baseDefines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
|
||||
XMBElement Root = XeroFile.GetRoot();
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class CShaderProgramARB : public CShaderProgram
|
|||
public:
|
||||
CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const CShaderDefines& defines,
|
||||
const std::map<CStr, int>& vertexIndexes, const std::map<CStr, int>& fragmentIndexes,
|
||||
const std::map<CStrIntern, int>& vertexIndexes, const std::map<CStrIntern, int>& fragmentIndexes,
|
||||
int streamflags) :
|
||||
CShaderProgram(streamflags),
|
||||
m_VertexFile(vertexFile), m_FragmentFile(fragmentFile),
|
||||
|
|
@ -95,8 +95,8 @@ public:
|
|||
return;
|
||||
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStr, CStr> definesMap = m_Defines.GetMap();
|
||||
for (std::map<CStr, CStr>::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
|
||||
std::map<CStrIntern, CStrIntern> definesMap = m_Defines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
|
||||
CStr vertexCode = Preprocess(preprocessor, vertexFile.GetAsString());
|
||||
|
|
@ -141,17 +141,17 @@ public:
|
|||
// TODO: should unbind textures, probably
|
||||
}
|
||||
|
||||
int GetUniformVertexIndex(uniform_id_t id)
|
||||
int GetUniformVertexIndex(CStrIntern id)
|
||||
{
|
||||
std::map<CStr, int>::iterator it = m_VertexIndexes.find(id);
|
||||
std::map<CStrIntern, int>::iterator it = m_VertexIndexes.find(id);
|
||||
if (it == m_VertexIndexes.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
int GetUniformFragmentIndex(uniform_id_t id)
|
||||
int GetUniformFragmentIndex(CStrIntern id)
|
||||
{
|
||||
std::map<CStr, int>::iterator it = m_FragmentIndexes.find(id);
|
||||
std::map<CStrIntern, int>::iterator it = m_FragmentIndexes.find(id);
|
||||
if (it == m_FragmentIndexes.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
|
|
@ -159,7 +159,7 @@ public:
|
|||
|
||||
virtual Binding GetTextureBinding(texture_id_t id)
|
||||
{
|
||||
int index = GetUniformFragmentIndex(id);
|
||||
int index = GetUniformFragmentIndex(CStrIntern(id));
|
||||
if (index == -1)
|
||||
return Binding();
|
||||
else
|
||||
|
|
@ -168,7 +168,7 @@ public:
|
|||
|
||||
virtual void BindTexture(texture_id_t id, Handle tex)
|
||||
{
|
||||
int index = GetUniformFragmentIndex(id);
|
||||
int index = GetUniformFragmentIndex(CStrIntern(id));
|
||||
if (index != -1)
|
||||
{
|
||||
GLuint h;
|
||||
|
|
@ -180,7 +180,7 @@ public:
|
|||
|
||||
virtual void BindTexture(texture_id_t id, GLuint tex)
|
||||
{
|
||||
int index = GetUniformFragmentIndex(id);
|
||||
int index = GetUniformFragmentIndex(CStrIntern(id));
|
||||
if (index != -1)
|
||||
{
|
||||
pglActiveTextureARB(GL_TEXTURE0+index);
|
||||
|
|
@ -196,6 +196,12 @@ public:
|
|||
}
|
||||
|
||||
virtual Binding GetUniformBinding(uniform_id_t id)
|
||||
{
|
||||
CStrIntern idIntern(id);
|
||||
return Binding(GetUniformVertexIndex(idIntern), GetUniformFragmentIndex(idIntern));
|
||||
}
|
||||
|
||||
virtual Binding GetUniformBinding(CStrIntern id)
|
||||
{
|
||||
return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id));
|
||||
}
|
||||
|
|
@ -236,8 +242,8 @@ private:
|
|||
GLuint m_VertexProgram;
|
||||
GLuint m_FragmentProgram;
|
||||
|
||||
std::map<CStr, int> m_VertexIndexes;
|
||||
std::map<CStr, int> m_FragmentIndexes;
|
||||
std::map<CStrIntern, int> m_VertexIndexes;
|
||||
std::map<CStrIntern, int> m_FragmentIndexes;
|
||||
};
|
||||
|
||||
#endif // #if !CONFIG2_GLES
|
||||
|
|
@ -252,7 +258,7 @@ class CShaderProgramGLSL : public CShaderProgram
|
|||
public:
|
||||
CShaderProgramGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const CShaderDefines& defines,
|
||||
const std::map<CStr, int>& vertexAttribs,
|
||||
const std::map<CStrIntern, int>& vertexAttribs,
|
||||
int streamflags) :
|
||||
CShaderProgram(streamflags),
|
||||
m_VertexFile(vertexFile), m_FragmentFile(fragmentFile),
|
||||
|
|
@ -328,7 +334,7 @@ public:
|
|||
// Set up the attribute bindings explicitly, since apparently drivers
|
||||
// don't always pick the most efficient bindings automatically,
|
||||
// and also this lets us hardcode indexes into VertexPointer etc
|
||||
for (std::map<CStr, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
|
||||
for (std::map<CStrIntern, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
|
||||
pglBindAttribLocationARB(m_Program, it->second, it->first.c_str());
|
||||
|
||||
pglLinkProgramARB(m_Program);
|
||||
|
|
@ -360,8 +366,7 @@ public:
|
|||
if (!ok)
|
||||
return false;
|
||||
|
||||
m_UniformLocations.clear();
|
||||
m_UniformTypes.clear();
|
||||
m_Uniforms.clear();
|
||||
m_Samplers.clear();
|
||||
|
||||
Bind();
|
||||
|
|
@ -382,8 +387,8 @@ public:
|
|||
|
||||
GLint loc = pglGetUniformLocationARB(m_Program, name);
|
||||
|
||||
m_UniformLocations[name] = loc;
|
||||
m_UniformTypes[name] = type;
|
||||
CStrIntern nameIntern(name);
|
||||
m_Uniforms[nameIntern] = std::make_pair(loc, type);
|
||||
|
||||
// Assign sampler uniforms to sequential texture units
|
||||
if (type == GL_SAMPLER_2D
|
||||
|
|
@ -394,8 +399,8 @@ public:
|
|||
)
|
||||
{
|
||||
int unit = (int)m_Samplers.size();
|
||||
m_Samplers[name].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
|
||||
m_Samplers[name].second = unit;
|
||||
m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D);
|
||||
m_Samplers[nameIntern].second = unit;
|
||||
pglUniform1iARB(loc, unit); // link uniform to unit
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
|
|
@ -423,8 +428,8 @@ public:
|
|||
return;
|
||||
|
||||
CPreprocessor preprocessor;
|
||||
std::map<CStr, CStr> definesMap = m_Defines.GetMap();
|
||||
for (std::map<CStr, CStr>::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
|
||||
std::map<CStrIntern, CStrIntern> definesMap = m_Defines.GetMap();
|
||||
for (std::map<CStrIntern, CStrIntern>::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it)
|
||||
preprocessor.Define(it->first.c_str(), it->first.length(), it->second.c_str(), it->second.length());
|
||||
|
||||
#if CONFIG2_GLES
|
||||
|
|
@ -438,12 +443,16 @@ public:
|
|||
CStr fragmentCode = Preprocess(preprocessor, fragmentFile.GetAsString());
|
||||
|
||||
#if CONFIG2_GLES
|
||||
// Ugly hack to replace desktop GLSL 1.10 with GLSL ES 1.00,
|
||||
// Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00,
|
||||
// and also to set default float precision for fragment shaders
|
||||
vertexCode.Replace("#version 110\n", "#version 100\n");
|
||||
vertexCode.Replace("#version 110\r\n", "#version 100\n");
|
||||
vertexCode.Replace("#version 120\n", "#version 100\n");
|
||||
vertexCode.Replace("#version 120\r\n", "#version 100\n");
|
||||
fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n");
|
||||
fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n");
|
||||
fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n");
|
||||
fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n");
|
||||
#endif
|
||||
|
||||
if (!Compile(m_VertexShader, m_VertexFile, vertexCode))
|
||||
|
|
@ -473,7 +482,7 @@ public:
|
|||
{
|
||||
pglUseProgramObjectARB(m_Program);
|
||||
|
||||
for (std::map<CStr, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
|
||||
for (std::map<CStrIntern, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
|
||||
pglEnableVertexAttribArrayARB(it->second);
|
||||
}
|
||||
|
||||
|
|
@ -481,23 +490,15 @@ public:
|
|||
{
|
||||
pglUseProgramObjectARB(0);
|
||||
|
||||
for (std::map<CStr, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
|
||||
for (std::map<CStrIntern, int>::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it)
|
||||
pglDisableVertexAttribArrayARB(it->second);
|
||||
|
||||
// TODO: should unbind textures, probably
|
||||
}
|
||||
|
||||
int GetUniformLocation(uniform_id_t id)
|
||||
{
|
||||
std::map<CStr, int>::iterator it = m_UniformLocations.find(id);
|
||||
if (it == m_UniformLocations.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
virtual Binding GetTextureBinding(texture_id_t id)
|
||||
{
|
||||
std::map<CStr, std::pair<GLenum, int> >::iterator it = m_Samplers.find(id);
|
||||
std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
|
||||
if (it == m_Samplers.end())
|
||||
return Binding();
|
||||
else
|
||||
|
|
@ -506,7 +507,7 @@ public:
|
|||
|
||||
virtual void BindTexture(texture_id_t id, Handle tex)
|
||||
{
|
||||
std::map<CStr, std::pair<GLenum, int> >::iterator it = m_Samplers.find(id);
|
||||
std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
|
||||
if (it == m_Samplers.end())
|
||||
return;
|
||||
|
||||
|
|
@ -518,7 +519,7 @@ public:
|
|||
|
||||
virtual void BindTexture(texture_id_t id, GLuint tex)
|
||||
{
|
||||
std::map<CStr, std::pair<GLenum, int> >::iterator it = m_Samplers.find(id);
|
||||
std::map<CStrIntern, std::pair<GLenum, int> >::iterator it = m_Samplers.find(CStrIntern(id));
|
||||
if (it == m_Samplers.end())
|
||||
return;
|
||||
|
||||
|
|
@ -539,11 +540,20 @@ public:
|
|||
|
||||
virtual Binding GetUniformBinding(uniform_id_t id)
|
||||
{
|
||||
int loc = GetUniformLocation(id);
|
||||
if (loc == -1)
|
||||
std::map<CStrIntern, std::pair<int, GLenum> >::iterator it = m_Uniforms.find(CStrIntern(id));
|
||||
if (it == m_Uniforms.end())
|
||||
return Binding();
|
||||
else
|
||||
return Binding(loc, m_UniformTypes[id]);
|
||||
return Binding(it->second.first, (int)it->second.second);
|
||||
}
|
||||
|
||||
virtual Binding GetUniformBinding(CStrIntern id)
|
||||
{
|
||||
std::map<CStrIntern, std::pair<int, GLenum> >::iterator it = m_Uniforms.find(id);
|
||||
if (it == m_Uniforms.end())
|
||||
return Binding();
|
||||
else
|
||||
return Binding(it->second.first, (int)it->second.second);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
|
||||
|
|
@ -605,15 +615,14 @@ private:
|
|||
VfsPath m_VertexFile;
|
||||
VfsPath m_FragmentFile;
|
||||
CShaderDefines m_Defines;
|
||||
std::map<CStr, int> m_VertexAttribs;
|
||||
std::map<CStrIntern, int> m_VertexAttribs;
|
||||
|
||||
GLhandleARB m_Program;
|
||||
GLhandleARB m_VertexShader;
|
||||
GLhandleARB m_FragmentShader;
|
||||
|
||||
std::map<CStr, GLenum> m_UniformTypes;
|
||||
std::map<CStr, int> m_UniformLocations;
|
||||
std::map<CStr, std::pair<GLenum, int> > m_Samplers; // texture target & unit chosen for each uniform sampler
|
||||
std::map<CStrIntern, std::pair<int, GLenum> > m_Uniforms;
|
||||
std::map<CStrIntern, std::pair<GLenum, int> > m_Samplers; // texture target & unit chosen for each uniform sampler
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -626,7 +635,7 @@ CShaderProgram::CShaderProgram(int streamflags)
|
|||
#if CONFIG2_GLES
|
||||
/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const CShaderDefines& UNUSED(defines),
|
||||
const std::map<CStr, int>& UNUSED(vertexIndexes), const std::map<CStr, int>& UNUSED(fragmentIndexes),
|
||||
const std::map<CStrIntern, int>& UNUSED(vertexIndexes), const std::map<CStrIntern, int>& UNUSED(fragmentIndexes),
|
||||
int UNUSED(streamflags))
|
||||
{
|
||||
LOGERROR(L"CShaderProgram::ConstructARB: '%ls'+'%ls': ARB shaders not supported on this device",
|
||||
|
|
@ -636,7 +645,7 @@ CShaderProgram::CShaderProgram(int streamflags)
|
|||
#else
|
||||
/*static*/ CShaderProgram* CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const CShaderDefines& defines,
|
||||
const std::map<CStr, int>& vertexIndexes, const std::map<CStr, int>& fragmentIndexes,
|
||||
const std::map<CStrIntern, int>& vertexIndexes, const std::map<CStrIntern, int>& fragmentIndexes,
|
||||
int streamflags)
|
||||
{
|
||||
return new CShaderProgramARB(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags);
|
||||
|
|
@ -645,7 +654,7 @@ CShaderProgram::CShaderProgram(int streamflags)
|
|||
|
||||
/*static*/ CShaderProgram* CShaderProgram::ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const CShaderDefines& defines,
|
||||
const std::map<CStr, int>& vertexAttribs,
|
||||
const std::map<CStrIntern, int>& vertexAttribs,
|
||||
int streamflags)
|
||||
{
|
||||
return new CShaderProgramGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamflags);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class CMatrix3D;
|
|||
class CVector3D;
|
||||
class CPreprocessor;
|
||||
class CShaderDefines;
|
||||
class CStrIntern;
|
||||
|
||||
// Vertex data stream flags
|
||||
enum
|
||||
|
|
@ -69,7 +70,7 @@ public:
|
|||
*/
|
||||
static CShaderProgram* ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const CShaderDefines& defines,
|
||||
const std::map<CStr, int>& vertexIndexes, const std::map<CStr, int>& fragmentIndexes,
|
||||
const std::map<CStrIntern, int>& vertexIndexes, const std::map<CStrIntern, int>& fragmentIndexes,
|
||||
int streamflags);
|
||||
|
||||
/**
|
||||
|
|
@ -77,7 +78,7 @@ public:
|
|||
*/
|
||||
static CShaderProgram* ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
|
||||
const CShaderDefines& defines,
|
||||
const std::map<CStr, int>& vertexAttribs,
|
||||
const std::map<CStrIntern, int>& vertexAttribs,
|
||||
int streamflags);
|
||||
|
||||
/**
|
||||
|
|
@ -154,6 +155,7 @@ public:
|
|||
|
||||
|
||||
virtual Binding GetUniformBinding(uniform_id_t id) = 0;
|
||||
virtual Binding GetUniformBinding(CStrIntern id) = 0;
|
||||
|
||||
// Uniform-setting methods that subclasses must define:
|
||||
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) = 0;
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ public:
|
|||
m_IsValid = true;
|
||||
}
|
||||
|
||||
int GetUniformIndex(uniform_id_t id)
|
||||
int GetUniformIndex(CStrIntern id)
|
||||
{
|
||||
std::map<CStr, int>::iterator it = m_UniformIndexes.find(id);
|
||||
std::map<CStrIntern, int>::iterator it = m_UniformIndexes.find(id);
|
||||
if (it == m_UniformIndexes.end())
|
||||
return -1;
|
||||
return it->second;
|
||||
|
|
@ -66,7 +66,7 @@ public:
|
|||
|
||||
virtual Binding GetTextureBinding(uniform_id_t id)
|
||||
{
|
||||
int index = GetUniformIndex(id);
|
||||
int index = GetUniformIndex(CStrIntern(id));
|
||||
if (index == -1)
|
||||
return Binding();
|
||||
else
|
||||
|
|
@ -75,14 +75,14 @@ public:
|
|||
|
||||
virtual void BindTexture(texture_id_t id, Handle tex)
|
||||
{
|
||||
int index = GetUniformIndex(id);
|
||||
int index = GetUniformIndex(CStrIntern(id));
|
||||
if (index != -1)
|
||||
ogl_tex_bind(tex, index);
|
||||
}
|
||||
|
||||
virtual void BindTexture(texture_id_t id, GLuint tex)
|
||||
{
|
||||
int index = GetUniformIndex(id);
|
||||
int index = GetUniformIndex(CStrIntern(id));
|
||||
if (index != -1)
|
||||
{
|
||||
pglActiveTextureARB((int)(GL_TEXTURE0+index));
|
||||
|
|
@ -98,6 +98,11 @@ public:
|
|||
}
|
||||
|
||||
virtual Binding GetUniformBinding(uniform_id_t id)
|
||||
{
|
||||
return Binding(-1, GetUniformIndex(CStrIntern(id)));
|
||||
}
|
||||
|
||||
virtual Binding GetUniformBinding(CStrIntern id)
|
||||
{
|
||||
return Binding(-1, GetUniformIndex(id));
|
||||
}
|
||||
|
|
@ -111,7 +116,12 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
std::map<CStr, int> m_UniformIndexes;
|
||||
std::map<CStrIntern, int> m_UniformIndexes;
|
||||
|
||||
void SetUniformIndex(const char* id, int value)
|
||||
{
|
||||
m_UniformIndexes[CStrIntern(id)] = value;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -128,7 +138,7 @@ public:
|
|||
CShaderProgramFFP(0)
|
||||
{
|
||||
// Texture units, for when this shader is used with terrain:
|
||||
m_UniformIndexes["baseTex"] = 0;
|
||||
SetUniformIndex("baseTex", 0);
|
||||
}
|
||||
|
||||
virtual void Bind()
|
||||
|
|
@ -159,13 +169,13 @@ public:
|
|||
CShaderProgramFFP_OverlayLine(const CShaderDefines& defines) :
|
||||
CShaderProgramFFP(STREAM_POS | STREAM_UV0 | STREAM_UV1)
|
||||
{
|
||||
m_UniformIndexes["losTransform"] = ID_losTransform;
|
||||
m_UniformIndexes["objectColor"] = ID_objectColor;
|
||||
SetUniformIndex("losTransform", ID_losTransform);
|
||||
SetUniformIndex("objectColor", ID_objectColor);
|
||||
|
||||
// Texture units:
|
||||
m_UniformIndexes["baseTex"] = 0;
|
||||
m_UniformIndexes["maskTex"] = 1;
|
||||
m_UniformIndexes["losTex"] = 2;
|
||||
SetUniformIndex("baseTex", 0);
|
||||
SetUniformIndex("maskTex", 1);
|
||||
SetUniformIndex("losTex", 2);
|
||||
|
||||
m_IgnoreLos = (defines.GetInt("IGNORE_LOS") != 0);
|
||||
}
|
||||
|
|
@ -319,11 +329,11 @@ public:
|
|||
CShaderProgramFFP_GuiText() :
|
||||
CShaderProgramFFP(STREAM_POS | STREAM_UV0)
|
||||
{
|
||||
m_UniformIndexes["transform"] = ID_transform;
|
||||
m_UniformIndexes["colorMul"] = ID_colorMul;
|
||||
SetUniformIndex("transform", ID_transform);
|
||||
SetUniformIndex("colorMul", ID_colorMul);
|
||||
|
||||
// Texture units:
|
||||
m_UniformIndexes["tex"] = 0;
|
||||
SetUniformIndex("tex", 0);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, float v0, float v1, float v2, float v3)
|
||||
|
|
@ -383,11 +393,11 @@ public:
|
|||
CShaderProgramFFP_Gui_Base(int streamflags) :
|
||||
CShaderProgramFFP(streamflags)
|
||||
{
|
||||
m_UniformIndexes["transform"] = ID_transform;
|
||||
m_UniformIndexes["color"] = ID_color;
|
||||
SetUniformIndex("transform", ID_transform);
|
||||
SetUniformIndex("color", ID_color);
|
||||
|
||||
// Texture units:
|
||||
m_UniformIndexes["tex"] = 0;
|
||||
SetUniformIndex("tex", 0);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, const CMatrix3D& v)
|
||||
|
|
@ -658,16 +668,16 @@ public:
|
|||
CShaderProgramFFP_Model_Base(const CShaderDefines& defines, int streamflags)
|
||||
: CShaderProgramFFP(streamflags)
|
||||
{
|
||||
m_UniformIndexes["transform"] = ID_transform;
|
||||
SetUniformIndex("transform", ID_transform);
|
||||
|
||||
if (defines.GetInt("USE_OBJECTCOLOR"))
|
||||
m_UniformIndexes["objectColor"] = ID_objectColor;
|
||||
SetUniformIndex("objectColor", ID_objectColor);
|
||||
|
||||
if (defines.GetInt("USE_PLAYERCOLOR"))
|
||||
m_UniformIndexes["playerColor"] = ID_playerColor;
|
||||
SetUniformIndex("playerColor", ID_playerColor);
|
||||
|
||||
// Texture units:
|
||||
m_UniformIndexes["baseTex"] = 0;
|
||||
SetUniformIndex("baseTex", 0);
|
||||
}
|
||||
|
||||
virtual void Uniform(Binding id, const CMatrix3D& v)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include "graphics/ShaderManager.h"
|
||||
|
||||
#include "maths/Vector4D.h"
|
||||
|
||||
class TestShaderManager : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
|
|
@ -79,11 +81,34 @@ public:
|
|||
|
||||
TS_ASSERT(defines1 == defines2);
|
||||
|
||||
defines2.Add(defines1);
|
||||
defines2.SetMany(defines1);
|
||||
TS_ASSERT(defines1 == defines2);
|
||||
|
||||
CShaderDefines defines3;
|
||||
defines3.Add(defines1);
|
||||
defines3.SetMany(defines1);
|
||||
TS_ASSERT(defines1 == defines3);
|
||||
}
|
||||
|
||||
void test_uniforms()
|
||||
{
|
||||
CShaderUniforms uniforms1;
|
||||
CShaderUniforms uniforms2;
|
||||
CShaderUniforms uniforms3;
|
||||
TS_ASSERT(uniforms1 == uniforms1);
|
||||
|
||||
uniforms1.Add("FOO", CVector4D(1.0f, 0.0f, 0.0f, 0.0f));
|
||||
|
||||
TS_ASSERT_EQUALS(uniforms1.GetVector("FOO"), CVector4D(1.0f, 0.0f, 0.0f, 0.0f));
|
||||
TS_ASSERT_EQUALS(uniforms2.GetVector("FOO"), CVector4D(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
|
||||
TS_ASSERT(!(uniforms1 == uniforms2));
|
||||
|
||||
uniforms2.Add("FOO", CVector4D(0.0f, 1.0f, 0.0f, 0.0f));
|
||||
|
||||
TS_ASSERT(!(uniforms1 == uniforms2));
|
||||
|
||||
uniforms2.Add("FOO", CVector4D(1.0f, 0.0f, 0.0f, 0.0f)); // override old value
|
||||
|
||||
TS_ASSERT(uniforms1 == uniforms2);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -293,10 +293,10 @@ public:
|
|||
|
||||
void Transform(const CVector4D& vector, CVector4D& result) const
|
||||
{
|
||||
result[0] = _11*vector[0] + _12*vector[1] + _13*vector[2] + _14*vector[3];
|
||||
result[1] = _21*vector[0] + _22*vector[1] + _23*vector[2] + _24*vector[3];
|
||||
result[2] = _31*vector[0] + _32*vector[1] + _33*vector[2] + _34*vector[3];
|
||||
result[3] = _41*vector[0] + _42*vector[1] + _43*vector[2] + _44*vector[3];
|
||||
result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14*vector.W;
|
||||
result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24*vector.W;
|
||||
result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34*vector.W;
|
||||
result.W = _41*vector.X + _42*vector.Y + _43*vector.Z + _44*vector.W;
|
||||
}
|
||||
|
||||
// rotate a vector by this matrix
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class CPlane
|
|||
{
|
||||
public:
|
||||
CPlane ();
|
||||
CPlane (const CVector4D& coeffs) : m_Norm(coeffs[0], coeffs[1], coeffs[2]), m_Dist(coeffs[3]) { }
|
||||
CPlane (const CVector4D& coeffs) : m_Norm(coeffs.X, coeffs.Y, coeffs.Z), m_Dist(coeffs.W) { }
|
||||
|
||||
//sets the plane equation from 3 points on that plane
|
||||
void Set (const CVector3D &p1, const CVector3D &p2, const CVector3D &p3);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
|
|
@ -23,116 +23,109 @@
|
|||
#ifndef INCLUDED_VECTOR4D
|
||||
#define INCLUDED_VECTOR4D
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CVector4D:
|
||||
class CVector4D
|
||||
{
|
||||
public:
|
||||
CVector4D() {}
|
||||
CVector4D(const float f[4]) { m_X=f[0]; m_Y=f[1]; m_Z=f[2]; m_W=f[3]; }
|
||||
CVector4D(float x,float y,float z,float w) { m_X=x; m_Y=y; m_Z=z; m_W=w; }
|
||||
CVector4D(const CVector4D& p) { m_X=p.m_X; m_Y=p.m_Y; m_Z=p.m_Z; m_W=p.m_W; }
|
||||
CVector4D() : X(0.0f), Y(0.0f), Z(0.0f), W(0.0f) { }
|
||||
|
||||
operator float*()
|
||||
CVector4D(float x, float y, float z, float w) : X(x), Y(y), Z(z), W(w) { }
|
||||
|
||||
bool operator==(const CVector4D& t) const
|
||||
{
|
||||
return &m_X;
|
||||
return (X == t.X && Y == t.Y && Z == t.Z && W == t.W);
|
||||
}
|
||||
|
||||
operator const float*() const
|
||||
bool operator!=(const CVector4D& t) const
|
||||
{
|
||||
return &m_X;
|
||||
return !(*this == t);
|
||||
}
|
||||
|
||||
CVector4D operator-() const
|
||||
{
|
||||
return CVector4D(-m_X,-m_Y,-m_Z,-m_W);
|
||||
return CVector4D(-X, -Y, -Z, -W);
|
||||
}
|
||||
|
||||
CVector4D operator+(const CVector4D& t) const
|
||||
CVector4D operator+(const CVector4D& t) const
|
||||
{
|
||||
return CVector4D(m_X+t.m_X,m_Y+t.m_Y,m_Z+t.m_Z,m_W+t.m_W);
|
||||
return CVector4D(X+t.X, Y+t.Y, Z+t.Z, W+t.W);
|
||||
}
|
||||
|
||||
CVector4D operator-(const CVector4D& t) const
|
||||
{
|
||||
return CVector4D(m_X-t.m_X,m_Y-t.m_Y,m_Z-t.m_Z,m_W-t.m_W);
|
||||
return CVector4D(X-t.X, Y-t.Y, Z-t.Z, W-t.W);
|
||||
}
|
||||
|
||||
CVector4D operator*(const CVector4D& t) const
|
||||
CVector4D operator*(const CVector4D& t) const
|
||||
{
|
||||
return CVector4D(m_X*t.m_X,m_Y*t.m_Y,m_Z*t.m_Z,m_W*t.m_W);
|
||||
return CVector4D(X*t.X, Y*t.Y, Z*t.Z, W*t.W);
|
||||
}
|
||||
|
||||
CVector4D operator*(float f) const
|
||||
{
|
||||
return CVector4D(m_X*f,m_Y*f,m_Z*f,m_W*f);
|
||||
return CVector4D(X*f, Y*f, Z*f, W*f);
|
||||
}
|
||||
|
||||
CVector4D operator/(float f) const
|
||||
{
|
||||
float inv_f = 1.0f/f;
|
||||
return CVector4D(m_X*inv_f,m_Y*inv_f,m_Z*inv_f,m_W*inv_f);
|
||||
float inv_f = 1.0f / f;
|
||||
return CVector4D(X*inv_f, Y*inv_f, Z*inv_f, W*inv_f);
|
||||
}
|
||||
|
||||
CVector4D& operator+=(const CVector4D& t)
|
||||
{
|
||||
m_X += t.m_X; m_Y += t.m_Y; m_Z += t.m_Z; m_W += t.m_W;
|
||||
return *this;
|
||||
X += t.X;
|
||||
Y += t.Y;
|
||||
Z += t.Z;
|
||||
W += t.W;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator-=(const CVector4D& t)
|
||||
{
|
||||
m_X -= t.m_X; m_Y -= t.m_Y; m_Z -= t.m_Z; m_W -= t.m_W;
|
||||
return *this;
|
||||
X -= t.X;
|
||||
Y -= t.Y;
|
||||
Z -= t.Z;
|
||||
W -= t.W;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator*=(const CVector4D& t)
|
||||
{
|
||||
m_X *= t.m_X; m_Y *= t.m_Y; m_Z *= t.m_Z; m_W *= t.m_W;
|
||||
X *= t.X;
|
||||
Y *= t.Y;
|
||||
Z *= t.Z;
|
||||
W *= t.W;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator*=(float f)
|
||||
{
|
||||
m_X *= f; m_Y *= f; m_Z *= f; m_W *= f;
|
||||
return *this;
|
||||
X *= f;
|
||||
Y *= f;
|
||||
Z *= f;
|
||||
W *= f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector4D& operator/=(float f)
|
||||
{
|
||||
float inv_f = 1.0f / f;
|
||||
m_X *= inv_f; m_Y *= inv_f; m_Z *= inv_f; m_W *= inv_f;
|
||||
return *this;
|
||||
X *= inv_f;
|
||||
Y *= inv_f;
|
||||
Z *= inv_f;
|
||||
W *= inv_f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float Dot(const CVector4D& a) const
|
||||
float Dot(const CVector4D& a) const
|
||||
{
|
||||
return m_X*a.m_X + m_Y*a.m_Y + m_Z*a.m_Z + m_W*a.m_W;
|
||||
return X*a.X + Y*a.Y + Z*a.Z + W*a.W;
|
||||
}
|
||||
|
||||
float LengthSquared() const
|
||||
{
|
||||
return Dot(*this);
|
||||
}
|
||||
|
||||
float Length() const
|
||||
{
|
||||
return sqrtf(LengthSquared());
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
const float inv_mag = 1.0f / Length();
|
||||
m_X *= inv_mag; m_Y *= inv_mag; m_Z *= inv_mag; m_W *= inv_mag;
|
||||
}
|
||||
|
||||
public:
|
||||
float m_X, m_Y, m_Z, m_W;
|
||||
float X, Y, Z, W;
|
||||
};
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -137,6 +137,11 @@ const char* CStrIntern::c_str() const
|
|||
return m->data.c_str();
|
||||
}
|
||||
|
||||
size_t CStrIntern::length() const
|
||||
{
|
||||
return m->data.length();
|
||||
}
|
||||
|
||||
const std::string& CStrIntern::string() const
|
||||
{
|
||||
return m->data;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@ public:
|
|||
*/
|
||||
const char* c_str() const;
|
||||
|
||||
/**
|
||||
* Returns length of string in bytes.
|
||||
*/
|
||||
size_t length() const;
|
||||
|
||||
/**
|
||||
* Returns as std::string.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ struct SMRBatchModel
|
|||
if (b->GetMaterial().GetDiffuseTexture() < a->GetMaterial().GetDiffuseTexture())
|
||||
return false;
|
||||
|
||||
return false;
|
||||
return a->GetMaterial().GetStaticUniforms() < b->GetMaterial().GetStaticUniforms();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -359,15 +359,17 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade
|
|||
* The data we need to render a model is:
|
||||
* - CShaderTechnique
|
||||
* - CTexture
|
||||
* - CShaderUniforms
|
||||
* - CModelDef (mesh data)
|
||||
* - CModel (model instance data)
|
||||
*
|
||||
* For efficient rendering, we need to batch the draw calls to minimise state changes.
|
||||
* (Texture changes are assumed to be cheaper than binding new mesh data,
|
||||
* (Uniform and texture changes are assumed to be cheaper than binding new mesh data,
|
||||
* and shader changes are assumed to be most expensive.)
|
||||
* First, group all models that share a technique to render them together.
|
||||
* Within those groups, sub-group by CModelDef.
|
||||
* Within those sub-groups, sub-sub-group by CTexture.
|
||||
* Within those sub-sub-groups, sub-sub-sub-group by CShaderUniforms.
|
||||
*
|
||||
* Alpha-blended models have to be sorted by distance from camera,
|
||||
* then we can batch as long as the order is preserved.
|
||||
|
|
@ -386,7 +388,7 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade
|
|||
* For each material bucket we then look up the appropriate shader technique.
|
||||
* If the technique requires sort-by-distance, the model is added to the
|
||||
* 'sortByDistItems' list with its computed distance.
|
||||
* Otherwise, the bucket's list of models is sorted by modeldef+texture,
|
||||
* Otherwise, the bucket's list of models is sorted by modeldef+texture+uniforms,
|
||||
* then the technique and model list is added to 'techBuckets'.
|
||||
*
|
||||
* 'techBuckets' is then sorted by technique, to improve batching when multiple
|
||||
|
|
@ -434,6 +436,11 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade
|
|||
for (MaterialBuckets_t::iterator it = materialBuckets.begin(); it != materialBuckets.end(); ++it)
|
||||
{
|
||||
CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(it->first.effect, context, it->first.defines);
|
||||
|
||||
// Skip invalid techniques (e.g. from data file errors)
|
||||
if (!tech)
|
||||
continue;
|
||||
|
||||
if (tech->GetSortByDistance())
|
||||
{
|
||||
// Add the tech into a vector so we can index it
|
||||
|
|
@ -551,6 +558,7 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade
|
|||
|
||||
CTexture* currentTex = NULL;
|
||||
CModelDef* currentModeldef = NULL;
|
||||
CShaderUniforms currentStaticUniforms;
|
||||
// (Texture needs to be rebound after binding a new shader, so we
|
||||
// can't move currentTex outside of this loop to reduce state changes)
|
||||
|
||||
|
|
@ -581,6 +589,14 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade
|
|||
m->vertexRenderer->PrepareModelDef(shader, streamflags, *currentModeldef);
|
||||
}
|
||||
|
||||
// Bind all uniforms when any change
|
||||
CShaderUniforms newStaticUniforms = model->GetMaterial().GetStaticUniforms();
|
||||
if (newStaticUniforms != currentStaticUniforms)
|
||||
{
|
||||
currentStaticUniforms = newStaticUniforms;
|
||||
currentStaticUniforms.BindUniforms(shader);
|
||||
}
|
||||
|
||||
modifier->PrepareModel(shader, model);
|
||||
|
||||
CModelRData* rdata = static_cast<CModelRData*>(model->GetRenderData());
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ ShaderRenderModifier::ShaderRenderModifier()
|
|||
void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader)
|
||||
{
|
||||
shader->Uniform("transform", g_Renderer.GetViewCamera().GetViewProjection());
|
||||
shader->Uniform("cameraPos", g_Renderer.GetViewCamera().GetOrientation().GetTranslation());
|
||||
|
||||
if (GetShadowMap() && shader->GetTextureBinding("shadowTex").Active())
|
||||
{
|
||||
|
|
@ -102,7 +103,6 @@ void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader)
|
|||
|
||||
m_BindingInstancingTransform = shader->GetUniformBinding("instancingTransform");
|
||||
m_BindingShadingColor = shader->GetUniformBinding("shadingColor");
|
||||
m_BindingObjectColor = shader->GetUniformBinding("objectColor");
|
||||
m_BindingPlayerColor = shader->GetUniformBinding("playerColor");
|
||||
m_BindingBaseTex = shader->GetTextureBinding("baseTex");
|
||||
}
|
||||
|
|
@ -121,9 +121,6 @@ void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel*
|
|||
if (m_BindingShadingColor.Active())
|
||||
shader->Uniform(m_BindingShadingColor, model->GetShadingColor());
|
||||
|
||||
if (m_BindingObjectColor.Active())
|
||||
shader->Uniform(m_BindingObjectColor, model->GetMaterial().GetObjectColor());
|
||||
|
||||
if (m_BindingPlayerColor.Active())
|
||||
shader->Uniform(m_BindingPlayerColor, g_Game->GetPlayerColour(model->GetPlayerID()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,6 @@ public:
|
|||
private:
|
||||
CShaderProgram::Binding m_BindingInstancingTransform;
|
||||
CShaderProgram::Binding m_BindingShadingColor;
|
||||
CShaderProgram::Binding m_BindingObjectColor;
|
||||
CShaderProgram::Binding m_BindingPlayerColor;
|
||||
CShaderProgram::Binding m_BindingBaseTex;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -971,19 +971,19 @@ void CRenderer::SetObliqueFrustumClipping(const CVector4D& worldPlane)
|
|||
// by the inverse of the projection matrix
|
||||
|
||||
CVector4D q;
|
||||
q.m_X = (sgn(camPlane.m_X) - matrix[8]/matrix[11]) / matrix[0];
|
||||
q.m_Y = (sgn(camPlane.m_Y) - matrix[9]/matrix[11]) / matrix[5];
|
||||
q.m_Z = 1.0f/matrix[11];
|
||||
q.m_W = (1.0f - matrix[10]/matrix[11]) / matrix[14];
|
||||
q.X = (sgn(camPlane.X) - matrix[8]/matrix[11]) / matrix[0];
|
||||
q.Y = (sgn(camPlane.Y) - matrix[9]/matrix[11]) / matrix[5];
|
||||
q.Z = 1.0f/matrix[11];
|
||||
q.W = (1.0f - matrix[10]/matrix[11]) / matrix[14];
|
||||
|
||||
// Calculate the scaled plane vector
|
||||
CVector4D c = camPlane * (2.0f * matrix[11] / camPlane.Dot(q));
|
||||
|
||||
// Replace the third row of the projection matrix
|
||||
matrix[2] = c.m_X;
|
||||
matrix[6] = c.m_Y;
|
||||
matrix[10] = c.m_Z - matrix[11];
|
||||
matrix[14] = c.m_W;
|
||||
matrix[2] = c.X;
|
||||
matrix[6] = c.Y;
|
||||
matrix[10] = c.Z - matrix[11];
|
||||
matrix[14] = c.W;
|
||||
|
||||
// Load it back into the camera
|
||||
m_ViewCamera.SetProjection(matrix);
|
||||
|
|
|
|||
|
|
@ -395,6 +395,7 @@ void TerrainRenderer::RenderTerrain(bool filtered)
|
|||
void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow)
|
||||
{
|
||||
shader->Uniform("transform", g_Renderer.GetViewCamera().GetViewProjection());
|
||||
shader->Uniform("cameraPos", g_Renderer.GetViewCamera().GetOrientation().GetTranslation());
|
||||
|
||||
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
|
||||
|
||||
|
|
@ -408,6 +409,10 @@ void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap*
|
|||
shader->Uniform("shadowOffsets2", offsets[4], offsets[5], offsets[6], offsets[7]);
|
||||
}
|
||||
|
||||
shader->Uniform("ambient", lightEnv.m_UnitsAmbientColor);
|
||||
shader->Uniform("sunDir", lightEnv.GetSunDir());
|
||||
shader->Uniform("sunColor", lightEnv.m_SunColor);
|
||||
|
||||
CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
|
||||
shader->BindTexture("losTex", los.GetTexture());
|
||||
shader->Uniform("losTransform", los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
|
||||
|
|
@ -562,25 +567,25 @@ CBoundingBoxAligned TerrainRenderer::ScissorWater(const CMatrix3D &viewproj)
|
|||
CVector4D v4 = viewproj.Transform(CVector4D(waterBounds[1].X, waterBounds[1].Y, waterBounds[1].Z, 1.0f));
|
||||
CBoundingBoxAligned screenBounds;
|
||||
#define ADDBOUND(v1, v2, v3, v4) \
|
||||
if (v1[2] >= -v1[3]) \
|
||||
screenBounds += CVector3D(v1[0], v1[1], v1[2]) * (1.0f / v1[3]); \
|
||||
if (v1.Z >= -v1.W) \
|
||||
screenBounds += CVector3D(v1.X, v1.Y, v1.Z) * (1.0f / v1.W); \
|
||||
else \
|
||||
{ \
|
||||
float t = v1[2] + v1[3]; \
|
||||
if (v2[2] > -v2[3]) \
|
||||
float t = v1.Z + v1.W; \
|
||||
if (v2.Z > -v2.W) \
|
||||
{ \
|
||||
CVector4D c2 = v1 + (v2 - v1) * (t / (t - (v2[2] + v2[3]))); \
|
||||
screenBounds += CVector3D(c2[0], c2[1], c2[2]) * (1.0f / c2[3]); \
|
||||
CVector4D c2 = v1 + (v2 - v1) * (t / (t - (v2.Z + v2.W))); \
|
||||
screenBounds += CVector3D(c2.X, c2.Y, c2.Z) * (1.0f / c2.W); \
|
||||
} \
|
||||
if (v3[2] > -v3[3]) \
|
||||
if (v3.Z > -v3.W) \
|
||||
{ \
|
||||
CVector4D c3 = v1 + (v3 - v1) * (t / (t - (v3[2] + v3[3]))); \
|
||||
screenBounds += CVector3D(c3[0], c3[1], c3[2]) * (1.0f / c3[3]); \
|
||||
CVector4D c3 = v1 + (v3 - v1) * (t / (t - (v3.Z + v3.W))); \
|
||||
screenBounds += CVector3D(c3.X, c3.Y, c3.Z) * (1.0f / c3.W); \
|
||||
} \
|
||||
if (v4[2] > -v4[3]) \
|
||||
if (v4.Z > -v4.W) \
|
||||
{ \
|
||||
CVector4D c4 = v1 + (v4 - v1) * (t / (t - (v4[2] + v4[3]))); \
|
||||
screenBounds += CVector3D(c4[0], c4[1], c4[2]) * (1.0f / c4[3]); \
|
||||
CVector4D c4 = v1 + (v4 - v1) * (t / (t - (v4.Z + v4.W))); \
|
||||
screenBounds += CVector3D(c4.X, c4.Y, c4.Z) * (1.0f / c4.W); \
|
||||
} \
|
||||
}
|
||||
ADDBOUND(v1, v2, v3, v4);
|
||||
|
|
|
|||
|
|
@ -252,7 +252,6 @@ void EnvironmentSidebar::OnFirstDisplay()
|
|||
|
||||
|
||||
std::vector<std::wstring> lightingModels;
|
||||
lightingModels.push_back(L"old");
|
||||
lightingModels.push_back(L"standard");
|
||||
m_LightingModelList->SetChoices(lightingModels);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue