diff --git a/binaries/data/mods/public/art/materials/basic_spec.xml b/binaries/data/mods/public/art/materials/basic_spec.xml new file mode 100644 index 0000000000..7a74779522 --- /dev/null +++ b/binaries/data/mods/public/art/materials/basic_spec.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/binaries/data/mods/public/art/materials/blend_spec.xml b/binaries/data/mods/public/art/materials/blend_spec.xml new file mode 100644 index 0000000000..6e455fc48e --- /dev/null +++ b/binaries/data/mods/public/art/materials/blend_spec.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/binaries/data/mods/public/art/materials/objectcolor_spec.xml b/binaries/data/mods/public/art/materials/objectcolor_spec.xml new file mode 100644 index 0000000000..9e4f90ab37 --- /dev/null +++ b/binaries/data/mods/public/art/materials/objectcolor_spec.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/binaries/data/mods/public/art/materials/playercolor_spec.xml b/binaries/data/mods/public/art/materials/playercolor_spec.xml new file mode 100644 index 0000000000..2cb7f77736 --- /dev/null +++ b/binaries/data/mods/public/art/materials/playercolor_spec.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/binaries/data/mods/public/shaders/arb/model_common.fp b/binaries/data/mods/public/shaders/arb/model_common.fp index d7cdc4a6ba..911b4db560 100644 --- a/binaries/data/mods/public/shaders/arb/model_common.fp +++ b/binaries/data/mods/public/shaders/arb/model_common.fp @@ -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; diff --git a/binaries/data/mods/public/shaders/arb/model_common.vp b/binaries/data/mods/public/shaders/arb/model_common.vp index 797f5d1286..a348b031de 100644 --- a/binaries/data/mods/public/shaders/arb/model_common.vp +++ b/binaries/data/mods/public/shaders/arb/model_common.vp @@ -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 diff --git a/binaries/data/mods/public/shaders/arb/model_common.xml b/binaries/data/mods/public/shaders/arb/model_common.xml index cafaf0c769..5a49f878c8 100644 --- a/binaries/data/mods/public/shaders/arb/model_common.xml +++ b/binaries/data/mods/public/shaders/arb/model_common.xml @@ -2,11 +2,12 @@ - - - - - + + + + + + @@ -23,6 +24,8 @@ + + diff --git a/binaries/data/mods/public/shaders/glsl/model_common.fs b/binaries/data/mods/public/shaders/glsl/model_common.fs index 1003d0f3f8..498a84311f 100644 --- a/binaries/data/mods/public/shaders/glsl/model_common.fs +++ b/binaries/data/mods/public/shaders/glsl/model_common.fs @@ -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; } diff --git a/binaries/data/mods/public/shaders/glsl/model_common.vs b/binaries/data/mods/public/shaders/glsl/model_common.vs index f13ba6ca50..d8c87c2ec5 100644 --- a/binaries/data/mods/public/shaders/glsl/model_common.vs +++ b/binaries/data/mods/public/shaders/glsl/model_common.vs @@ -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; diff --git a/binaries/data/mods/public/shaders/glsl/terrain_common.fs b/binaries/data/mods/public/shaders/glsl/terrain_common.fs index 0ace856c14..54e1a90646 100644 --- a/binaries/data/mods/public/shaders/glsl/terrain_common.fs +++ b/binaries/data/mods/public/shaders/glsl/terrain_common.fs @@ -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; } diff --git a/binaries/data/mods/public/shaders/glsl/terrain_common.vs b/binaries/data/mods/public/shaders/glsl/terrain_common.vs index 8a0a570ebc..a24d62d73f 100644 --- a/binaries/data/mods/public/shaders/glsl/terrain_common.vs +++ b/binaries/data/mods/public/shaders/glsl/terrain_common.vs @@ -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; } diff --git a/source/graphics/Camera.cpp b/source/graphics/Camera.cpp index a330b613fd..ea96ffc003 100644 --- a/source/graphics/Camera.cpp +++ b/source/graphics/Camera.cpp @@ -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(); } diff --git a/source/graphics/CinemaTrack.cpp b/source/graphics/CinemaTrack.cpp index 8885903db8..ed79f283b8 100644 --- a/source/graphics/CinemaTrack.cpp +++ b/source/graphics/CinemaTrack.cpp @@ -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); diff --git a/source/graphics/Material.cpp b/source/graphics/Material.cpp index c8e87dfd44..fbf5cc6371 100644 --- a/source/graphics/Material.cpp +++ b/source/graphics/Material.cpp @@ -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); +} diff --git a/source/graphics/Material.h b/source/graphics/Material.h index 85a7c14325..01e1c5fdee 100644 --- a/source/graphics/Material.h +++ b/source/graphics/Material.h @@ -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 diff --git a/source/graphics/MaterialManager.cpp b/source/graphics/MaterialManager.cpp index a78614c774..2bc095985a 100644 --- a/source/graphics/MaterialManager.cpp +++ b/source/graphics/MaterialManager.cpp @@ -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; diff --git a/source/graphics/MaterialManager.h b/source/graphics/MaterialManager.h index 14fbfeb783..e2fe2b73b6 100644 --- a/source/graphics/MaterialManager.h +++ b/source/graphics/MaterialManager.h @@ -20,6 +20,7 @@ #include #include "Material.h" +#include "lib/file/vfs/vfs_path.h" class CMaterialManager { diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index 7095adc9ed..c745484d7e 100644 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -119,7 +119,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& 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); diff --git a/source/graphics/ShaderDefines.cpp b/source/graphics/ShaderDefines.cpp index 52c87f8476..19e178038c 100644 --- a/source/graphics/ShaderDefines.cpp +++ b/source/graphics/ShaderDefines.cpp @@ -19,70 +19,101 @@ #include "ShaderDefines.h" +#include "maths/Vector4D.h" #include "ps/ThreadUtil.h" -#include +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::SItems& items) { return items.hash; } -bool operator==(const CShaderDefines::SItems& a, const CShaderDefines::SItems& b) +size_t hash_value(const CShaderParams::SItems& items) +{ + return items.hash; +} + +bool operator==(const CShaderParams::SItems& a, const CShaderParams::SItems& b) { return a.items == b.items; } +bool operator==(const CShaderParams::SItems& a, const CShaderParams::SItems& b) +{ + return a.items == b.items; +} + +template 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::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 struct ItemNameGeq { - bool operator()(const CShaderDefines::SItems::Item& a, const CShaderDefines::SItems::Item& b) const + typedef typename CShaderParams::SItems::Item Item; + + bool operator()(const Item& a, const Item& b) const { return !(b.first < a.first); } }; -typedef boost::unordered_map > InternedItems_t; -static InternedItems_t g_InternedItems; - -CShaderDefines::SItems* CShaderDefines::GetInterned(const SItems& items) +template +typename CShaderParams::SItems* CShaderParams::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())) == items.items.end()); + typedef ItemNameCmp Cmp; + ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate(Cmp())) == items.items.end()); shared_ptr 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 +CShaderParams::CShaderParams() { SItems items; items.RecalcHash(); m_Items = GetInterned(items); } -void CShaderDefines::Add(const char* name, const char* value) +template +void CShaderParams::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::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 +void CShaderParams::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()); items.RecalcHash(); m_Items = GetInterned(items); } -std::map CShaderDefines::GetMap() const +template +std::map CShaderParams::GetMap() const { - std::map ret; + std::map 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 +size_t CShaderParams::GetHash() const +{ + return m_Items->hash; +} + +template +void CShaderParams::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& 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::SItems, shared_ptr::SItems> > CShaderParams::s_InternedItems; +boost::unordered_map::SItems, shared_ptr::SItems> > CShaderParams::s_InternedItems; + +template class CShaderParams; +template class CShaderParams; diff --git a/source/graphics/ShaderDefines.h b/source/graphics/ShaderDefines.h index 925f6d4926..0f58e04fd0 100644 --- a/source/graphics/ShaderDefines.h +++ b/source/graphics/ShaderDefines.h @@ -18,47 +18,48 @@ #ifndef INCLUDED_SHADERDEFINES #define INCLUDED_SHADERDEFINES +#include "graphics/ShaderProgram.h" #include "ps/CStr.h" #include "ps/CStrIntern.h" +#include + +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 +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 GetMap() const; + std::map 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 Item; + typedef std::pair Item; // Sorted by name; no duplicated names std::vector items; @@ -96,9 +105,13 @@ public: void RecalcHash(); }; -private: +protected: SItems* m_Items; // interned value +private: + typedef boost::unordered_map > 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 +{ +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 +{ +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 diff --git a/source/graphics/ShaderManager.cpp b/source/graphics/ShaderManager.cpp index 35ea693fb8..cda4bcb327 100644 --- a/source/graphics/ShaderManager.cpp +++ b/source/graphics/ShaderManager.cpp @@ -192,8 +192,8 @@ bool CShaderManager::NewProgram(const char* name, const CShaderDefines& baseDefi #undef EL CPreprocessor preprocessor; - std::map baseDefinesMap = baseDefines.GetMap(); - for (std::map::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it) + std::map baseDefinesMap = baseDefines.GetMap(); + for (std::map::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 vertexUniforms; - std::map fragmentUniforms; - std::map vertexAttribs; + std::map vertexUniforms; + std::map fragmentUniforms; + std::map 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 baseDefinesMap = baseDefines.GetMap(); - for (std::map::const_iterator it = baseDefinesMap.begin(); it != baseDefinesMap.end(); ++it) + std::map baseDefinesMap = baseDefines.GetMap(); + for (std::map::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(); diff --git a/source/graphics/ShaderProgram.cpp b/source/graphics/ShaderProgram.cpp index 621304a92e..9fed47dd85 100644 --- a/source/graphics/ShaderProgram.cpp +++ b/source/graphics/ShaderProgram.cpp @@ -36,7 +36,7 @@ class CShaderProgramARB : public CShaderProgram public: CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, + const std::map& vertexIndexes, const std::map& fragmentIndexes, int streamflags) : CShaderProgram(streamflags), m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), @@ -95,8 +95,8 @@ public: return; CPreprocessor preprocessor; - std::map definesMap = m_Defines.GetMap(); - for (std::map::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it) + std::map definesMap = m_Defines.GetMap(); + for (std::map::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::iterator it = m_VertexIndexes.find(id); + std::map::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::iterator it = m_FragmentIndexes.find(id); + std::map::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 m_VertexIndexes; - std::map m_FragmentIndexes; + std::map m_VertexIndexes; + std::map 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& vertexAttribs, + const std::map& 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::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) + for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglBindAttribLocationARB(m_Program, it->second, it->first.c_str()); pglLinkProgramARB(m_Program); @@ -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 definesMap = m_Defines.GetMap(); - for (std::map::const_iterator it = definesMap.begin(); it != definesMap.end(); ++it) + std::map definesMap = m_Defines.GetMap(); + for (std::map::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::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) + for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) pglEnableVertexAttribArrayARB(it->second); } @@ -481,23 +490,15 @@ public: { pglUseProgramObjectARB(0); - for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) + for (std::map::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::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 >::iterator it = m_Samplers.find(id); + std::map >::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 >::iterator it = m_Samplers.find(id); + std::map >::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 >::iterator it = m_Samplers.find(id); + std::map >::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 >::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 >::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 m_VertexAttribs; + std::map m_VertexAttribs; GLhandleARB m_Program; GLhandleARB m_VertexShader; GLhandleARB m_FragmentShader; - std::map m_UniformTypes; - std::map m_UniformLocations; - std::map > m_Samplers; // texture target & unit chosen for each uniform sampler + std::map > m_Uniforms; + std::map > 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& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes), + const std::map& UNUSED(vertexIndexes), const std::map& 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& vertexIndexes, const std::map& fragmentIndexes, + const std::map& vertexIndexes, const std::map& 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& vertexAttribs, + const std::map& vertexAttribs, int streamflags) { return new CShaderProgramGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamflags); diff --git a/source/graphics/ShaderProgram.h b/source/graphics/ShaderProgram.h index c24dcb523b..3456e8079c 100644 --- a/source/graphics/ShaderProgram.h +++ b/source/graphics/ShaderProgram.h @@ -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& vertexIndexes, const std::map& fragmentIndexes, + const std::map& vertexIndexes, const std::map& fragmentIndexes, int streamflags); /** @@ -77,7 +78,7 @@ public: */ static CShaderProgram* ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, const CShaderDefines& defines, - const std::map& vertexAttribs, + const std::map& 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; diff --git a/source/graphics/ShaderProgramFFP.cpp b/source/graphics/ShaderProgramFFP.cpp index a57ffcc5b2..622408a1fe 100644 --- a/source/graphics/ShaderProgramFFP.cpp +++ b/source/graphics/ShaderProgramFFP.cpp @@ -56,9 +56,9 @@ public: m_IsValid = true; } - int GetUniformIndex(uniform_id_t id) + int GetUniformIndex(CStrIntern id) { - std::map::iterator it = m_UniformIndexes.find(id); + std::map::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 m_UniformIndexes; + std::map 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) diff --git a/source/graphics/tests/test_ShaderManager.h b/source/graphics/tests/test_ShaderManager.h index 5ca0600117..060e98564d 100644 --- a/source/graphics/tests/test_ShaderManager.h +++ b/source/graphics/tests/test_ShaderManager.h @@ -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); + } }; diff --git a/source/maths/Matrix3D.h b/source/maths/Matrix3D.h index 26de3d7071..ed8abe2e34 100644 --- a/source/maths/Matrix3D.h +++ b/source/maths/Matrix3D.h @@ -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 diff --git a/source/maths/Plane.h b/source/maths/Plane.h index 6d623c668a..c8ec217a32 100644 --- a/source/maths/Plane.h +++ b/source/maths/Plane.h @@ -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); diff --git a/source/maths/Vector4D.h b/source/maths/Vector4D.h index f03d8dbd6c..e37f78a12d 100644 --- a/source/maths/Vector4D.h +++ b/source/maths/Vector4D.h @@ -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 -/////////////////////////////////////////////////////////////////////////////// -// 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 diff --git a/source/ps/CStrIntern.cpp b/source/ps/CStrIntern.cpp index 3167ea4d64..12994be2a1 100644 --- a/source/ps/CStrIntern.cpp +++ b/source/ps/CStrIntern.cpp @@ -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; diff --git a/source/ps/CStrIntern.h b/source/ps/CStrIntern.h index 10f63405e4..87e4adbf53 100644 --- a/source/ps/CStrIntern.h +++ b/source/ps/CStrIntern.h @@ -51,6 +51,11 @@ public: */ const char* c_str() const; + /** + * Returns length of string in bytes. + */ + size_t length() const; + /** * Returns as std::string. */ diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index 94c9f6e6c3..b020071a18 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -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(model->GetRenderData()); diff --git a/source/renderer/RenderModifiers.cpp b/source/renderer/RenderModifiers.cpp index ef976d3008..b371316d43 100644 --- a/source/renderer/RenderModifiers.cpp +++ b/source/renderer/RenderModifiers.cpp @@ -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())); } diff --git a/source/renderer/RenderModifiers.h b/source/renderer/RenderModifiers.h index 76008cecc5..103f3b8516 100644 --- a/source/renderer/RenderModifiers.h +++ b/source/renderer/RenderModifiers.h @@ -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; }; diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index a17f7290cb..7cfc169107 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -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); diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index 737601212c..b1a9da20f4 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -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); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp index 0bdc8ff9f0..b91bdb300e 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Environment/Environment.cpp @@ -252,7 +252,6 @@ void EnvironmentSidebar::OnFirstDisplay() std::vector lightingModels; - lightingModels.push_back(L"old"); lightingModels.push_back(L"standard"); m_LightingModelList->SetChoices(lightingModels);