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:
Ykkrosh 2012-04-08 15:55:06 +00:00
parent 8a0e47fdd6
commit b7888aea52
36 changed files with 754 additions and 366 deletions

View 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>

View 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>

View 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>

View 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>

View file

@ -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;

View file

@ -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

View file

@ -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>

View file

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

View file

@ -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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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

View file

@ -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;

View file

@ -20,6 +20,7 @@
#include <map>
#include "Material.h"
#include "lib/file/vfs/vfs_path.h"
class CMaterialManager
{

View file

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

View file

@ -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>;

View file

@ -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

View file

@ -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();

View file

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

View file

@ -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;

View file

@ -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)

View file

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

View file

@ -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

View file

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

View file

@ -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

View file

@ -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;

View file

@ -51,6 +51,11 @@ public:
*/
const char* c_str() const;
/**
* Returns length of string in bytes.
*/
size_t length() const;
/**
* Returns as std::string.
*/

View file

@ -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());

View file

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

View file

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

View file

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

View file

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

View file

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