diff --git a/binaries/data/mods/public/shaders/effects/particle.xml b/binaries/data/mods/public/shaders/effects/particle.xml
new file mode 100644
index 0000000000..40218af804
--- /dev/null
+++ b/binaries/data/mods/public/shaders/effects/particle.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/binaries/data/mods/public/shaders/effects/particle_solid.xml b/binaries/data/mods/public/shaders/effects/particle_solid.xml
new file mode 100644
index 0000000000..5c5ff245a0
--- /dev/null
+++ b/binaries/data/mods/public/shaders/effects/particle_solid.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/binaries/data/mods/public/shaders/glsl/model_common.fs b/binaries/data/mods/public/shaders/glsl/model_common.fs
index 00e1c97209..826017d12f 100644
--- a/binaries/data/mods/public/shaders/glsl/model_common.fs
+++ b/binaries/data/mods/public/shaders/glsl/model_common.fs
@@ -1,10 +1,16 @@
#version 110
uniform sampler2D baseTex;
-#ifdef USE_SHADOW
-uniform sampler2DShadow shadowTex;
-#endif
uniform sampler2D losTex;
+
+#ifdef USE_SHADOW
+ #ifdef USE_SHADOW_SAMPLER
+ uniform sampler2DShadow shadowTex;
+ #else
+ uniform sampler2D shadowTex;
+ #endif
+#endif
+
uniform vec3 objectColor;
uniform vec3 shadingColor;
uniform vec3 ambient;
@@ -16,6 +22,39 @@ varying vec2 v_tex;
varying vec4 v_shadow;
varying vec2 v_los;
+float get_shadow()
+{
+ #ifdef USE_SHADOW
+ #ifdef USE_SHADOW_SAMPLER
+ #ifdef 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 +
+ shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.xy, v_shadow.z)).a +
+ shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.zw, v_shadow.z)).a
+ );
+ #else
+ return shadow2D(shadowTex, v_shadow.xyz).a;
+ #endif
+ #else
+ if (v_shadow.z >= 1.0)
+ return 1.0;
+ #ifdef 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) +
+ (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.xy).x ? 0.25 : 0.0) +
+ (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.zw).x ? 0.25 : 0.0)
+ );
+ #else
+ return (v_shadow.z <= texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0);
+ #endif
+ #endif
+ #else
+ return 1.0;
+ #endif
+}
+
void main()
{
vec4 tex = texture2D(baseTex, v_tex);
@@ -38,22 +77,7 @@ void main()
color *= mix(objectColor, vec3(1.0, 1.0, 1.0), tex.a);
#endif
- #ifdef USE_SHADOW
- #ifdef USE_SHADOW_PCF
- float shadow = (
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.xy, v_shadow.z)).a +
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.zw, v_shadow.z)).a +
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.xy, v_shadow.z)).a +
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.zw, v_shadow.z)).a
- ) * 0.25;
- #else
- float shadow = shadow2D(shadowTex, v_shadow.xyz).a;
- #endif
- #else
- float shadow = 1.0;
- #endif
-
- color *= v_lighting * shadow + ambient;
+ color *= v_lighting * get_shadow() + ambient;
color *= texture2D(losTex, v_los).a;
diff --git a/binaries/data/mods/public/shaders/glsl/particle.fs b/binaries/data/mods/public/shaders/glsl/particle.fs
new file mode 100644
index 0000000000..dc5e78e4ea
--- /dev/null
+++ b/binaries/data/mods/public/shaders/glsl/particle.fs
@@ -0,0 +1,11 @@
+#version 110
+
+uniform sampler2D baseTex;
+
+varying vec2 v_tex;
+varying vec4 v_color;
+
+void main()
+{
+ gl_FragColor = texture2D(baseTex, v_tex) * v_color;
+}
diff --git a/binaries/data/mods/public/shaders/glsl/particle.vs b/binaries/data/mods/public/shaders/glsl/particle.vs
new file mode 100644
index 0000000000..40a5a795f4
--- /dev/null
+++ b/binaries/data/mods/public/shaders/glsl/particle.vs
@@ -0,0 +1,25 @@
+#version 110
+
+uniform mat4 transform;
+
+varying vec2 v_tex;
+varying vec4 v_color;
+
+attribute vec3 a_vertex;
+attribute vec4 a_color;
+attribute vec2 a_uv0;
+attribute vec2 a_uv1;
+
+void main()
+{
+ vec3 axis1 = vec3(transform[0][0], transform[1][0], transform[2][0]);
+ vec3 axis2 = vec3(transform[0][1], transform[1][1], transform[2][1]);
+ vec2 offset = a_uv1;
+
+ vec3 position = axis1*offset.x + axis1*offset.y + axis2*offset.x + axis2*-offset.y + a_vertex;
+
+ gl_Position = transform * vec4(position, 1.0);
+
+ v_tex = a_uv0;
+ v_color = a_color;
+}
diff --git a/binaries/data/mods/public/shaders/glsl/particle.xml b/binaries/data/mods/public/shaders/glsl/particle.xml
new file mode 100644
index 0000000000..74189ae809
--- /dev/null
+++ b/binaries/data/mods/public/shaders/glsl/particle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/binaries/data/mods/public/shaders/glsl/particle_solid.xml b/binaries/data/mods/public/shaders/glsl/particle_solid.xml
new file mode 100644
index 0000000000..74189ae809
--- /dev/null
+++ b/binaries/data/mods/public/shaders/glsl/particle_solid.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/binaries/data/mods/public/shaders/glsl/terrain_common.fs b/binaries/data/mods/public/shaders/glsl/terrain_common.fs
index 4f86c6089e..0ace856c14 100644
--- a/binaries/data/mods/public/shaders/glsl/terrain_common.fs
+++ b/binaries/data/mods/public/shaders/glsl/terrain_common.fs
@@ -2,10 +2,16 @@
uniform sampler2D baseTex;
uniform sampler2D blendTex;
-#ifdef USE_SHADOW
-uniform sampler2DShadow shadowTex;
-#endif
uniform sampler2D losTex;
+
+#ifdef USE_SHADOW
+ #ifdef USE_SHADOW_SAMPLER
+ uniform sampler2DShadow shadowTex;
+ #else
+ uniform sampler2D shadowTex;
+ #endif
+#endif
+
uniform vec3 shadingColor;
uniform vec3 ambient;
uniform vec4 shadowOffsets1;
@@ -17,9 +23,41 @@ varying vec4 v_shadow;
varying vec2 v_los;
varying vec2 v_blend;
+float get_shadow()
+{
+ #ifdef USE_SHADOW
+ #ifdef USE_SHADOW_SAMPLER
+ #ifdef 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 +
+ shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.xy, v_shadow.z)).a +
+ shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.zw, v_shadow.z)).a
+ );
+ #else
+ return shadow2D(shadowTex, v_shadow.xyz).a;
+ #endif
+ #else
+ if (v_shadow.z >= 1.0)
+ return 1.0;
+ #ifdef 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) +
+ (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.xy).x ? 0.25 : 0.0) +
+ (v_shadow.z <= texture2D(shadowTex, v_shadow.xy + shadowOffsets2.zw).x ? 0.25 : 0.0)
+ );
+ #else
+ return (v_shadow.z <= texture2D(shadowTex, v_shadow.xy).x ? 1.0 : 0.0);
+ #endif
+ #endif
+ #else
+ return 1.0;
+ #endif
+}
+
void main()
{
-
#ifdef BLEND
// Use alpha from blend texture
gl_FragColor.a = 1.0 - texture2D(blendTex, v_blend).a;
@@ -33,22 +71,7 @@ void main()
gl_FragColor.a = color.a;
#endif
- #ifdef USE_SHADOW
- #ifdef USE_SHADOW_PCF
- float shadow = (
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.xy, v_shadow.z)).a +
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets1.zw, v_shadow.z)).a +
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.xy, v_shadow.z)).a +
- shadow2D(shadowTex, vec3(v_shadow.xy + shadowOffsets2.zw, v_shadow.z)).a
- ) * 0.25;
- #else
- float shadow = shadow2D(shadowTex, v_shadow.xyz).a;
- #endif
- #else
- float shadow = 1.0;
- #endif
-
- color.rgb *= v_lighting * shadow + ambient;
+ color.rgb *= v_lighting * get_shadow() + ambient;
color *= texture2D(losTex, v_los).a;
diff --git a/binaries/data/mods/public/shaders/glsl/terrain_common.vs b/binaries/data/mods/public/shaders/glsl/terrain_common.vs
index 807b3dbaaa..38463cd34a 100644
--- a/binaries/data/mods/public/shaders/glsl/terrain_common.vs
+++ b/binaries/data/mods/public/shaders/glsl/terrain_common.vs
@@ -30,6 +30,9 @@ void main()
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);
+
+ // XXX: Ugly hack to hide some precision issues in GLES
+ v_tex = mod(v_tex, vec2(9.0, 9.0));
#endif
#ifdef BLEND
diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp
index 034d683643..f0d26e29d7 100644
--- a/source/graphics/ParticleEmitter.cpp
+++ b/source/graphics/ParticleEmitter.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011 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
@@ -28,6 +28,7 @@
CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
m_Type(type), m_Active(true), m_NextParticleIdx(0), m_EmissionRoundingError(0.f),
m_LastUpdateTime(type->m_Manager.GetCurrentTime()),
+ m_IndexArray(GL_DYNAMIC_DRAW),
m_VertexArray(GL_DYNAMIC_DRAW)
{
// If we should start with particles fully emitted, pretend that we
@@ -60,6 +61,21 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
m_VertexArray.SetNumVertices(m_Type->m_MaxParticles * 4);
m_VertexArray.Layout();
+
+ m_IndexArray.SetNumVertices(m_Type->m_MaxParticles * 6);
+ m_IndexArray.Layout();
+ VertexArrayIterator index = m_IndexArray.GetIterator();
+ for (size_t i = 0; i < m_Type->m_MaxParticles; ++i)
+ {
+ *index++ = i*4 + 0;
+ *index++ = i*4 + 1;
+ *index++ = i*4 + 2;
+ *index++ = i*4 + 2;
+ *index++ = i*4 + 3;
+ *index++ = i*4 + 0;
+ }
+ m_IndexArray.Upload();
+ m_IndexArray.FreeBackingStore();
}
void CParticleEmitter::UpdateArrayData()
@@ -153,13 +169,14 @@ void CParticleEmitter::Bind()
glBlendFunc(m_Type->m_BlendFuncSrc, m_Type->m_BlendFuncDst);
}
-void CParticleEmitter::RenderArray(CShaderProgramPtr& shader)
+void CParticleEmitter::RenderArray(const CShaderProgramPtr& shader)
{
// Some drivers apparently don't like count=0 in glDrawArrays here,
// so skip all drawing in that case
if (m_Particles.empty())
return;
+ u8* indexBase = m_IndexArray.Bind();
u8* base = m_VertexArray.Bind();
GLsizei stride = (GLsizei)m_VertexArray.GetStride();
@@ -174,11 +191,7 @@ void CParticleEmitter::RenderArray(CShaderProgramPtr& shader)
shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset);
shader->AssertPointersBound();
-#if CONFIG2_GLES
-#warning TODO: change CParticleEmitter to use (indexed?) triangles instead of quads, for GLES
-#else
- glDrawArrays(GL_QUADS, 0, m_Particles.size()*4);
-#endif
+ glDrawElements(GL_TRIANGLES, (GLsizei)(m_Particles.size() * 6), GL_UNSIGNED_SHORT, indexBase);
g_Renderer.GetStats().m_DrawCalls++;
g_Renderer.GetStats().m_Particles += m_Particles.size();
diff --git a/source/graphics/ParticleEmitter.h b/source/graphics/ParticleEmitter.h
index 295ab155da..8d370b8962 100644
--- a/source/graphics/ParticleEmitter.h
+++ b/source/graphics/ParticleEmitter.h
@@ -103,7 +103,7 @@ public:
/**
* Draw the vertex array.
*/
- void RenderArray(CShaderProgramPtr& shader);
+ void RenderArray(const CShaderProgramPtr& shader);
/**
* Stop this emitter emitting new particles, and pass responsibility for rendering
@@ -135,6 +135,8 @@ private:
/// Bounding box of the current particle center points
CBoundingBoxAligned m_ParticleBounds;
+ VertexIndexArray m_IndexArray;
+
VertexArray m_VertexArray;
VertexArray::Attribute m_AttributePos;
VertexArray::Attribute m_AttributeAxis;
diff --git a/source/lib/res/graphics/ogl_tex.cpp b/source/lib/res/graphics/ogl_tex.cpp
index 49564ccd1c..ddab4c60bc 100644
--- a/source/lib/res/graphics/ogl_tex.cpp
+++ b/source/lib/res/graphics/ogl_tex.cpp
@@ -1075,7 +1075,9 @@ Status ogl_tex_bind(Handle ht, size_t unit)
// we therefore complain so this one can be ruled out.
ENSURE(ot->id != 0);
+#if !CONFIG2_GLES
glEnable(GL_TEXTURE_2D);
+#endif
glBindTexture(GL_TEXTURE_2D, ot->id);
return INFO::OK;
}
diff --git a/source/renderer/ParticleRenderer.cpp b/source/renderer/ParticleRenderer.cpp
index 11b5cc5df3..88db5f96e7 100644
--- a/source/renderer/ParticleRenderer.cpp
+++ b/source/renderer/ParticleRenderer.cpp
@@ -27,8 +27,8 @@
struct ParticleRendererInternals
{
- CShaderProgramPtr shader;
- CShaderProgramPtr shaderSolid;
+ CShaderTechniquePtr shader;
+ CShaderTechniquePtr shaderSolid;
std::vector emitters;
};
@@ -78,11 +78,6 @@ void ParticleRenderer::PrepareForRendering()
{
PROFILE3("prepare particles");
-#if CONFIG2_GLES
-#warning TODO: implement particles for GLES
- return;
-#endif
-
// Can't load the shader in the constructor because it's called before the
// renderer initialisation is complete, so load it the first time through here
if (!m->shader)
@@ -91,8 +86,8 @@ void ParticleRenderer::PrepareForRendering()
// RenderParticles will never be called so it's safe to leave the shaders as null
if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
{
- m->shader = g_Renderer.GetShaderManager().LoadProgram("particle");
- m->shaderSolid = g_Renderer.GetShaderManager().LoadProgram("particle_solid");
+ m->shader = g_Renderer.GetShaderManager().LoadEffect("particle");
+ m->shaderSolid = g_Renderer.GetShaderManager().LoadEffect("particle_solid");
}
}
@@ -118,14 +113,11 @@ void ParticleRenderer::PrepareForRendering()
void ParticleRenderer::RenderParticles(bool solidColor)
{
-#if CONFIG2_GLES
-#warning TODO: implement particles for GLES
- return;
-#endif
+ CShaderTechniquePtr shader = solidColor ? m->shaderSolid : m->shader;
- CShaderProgramPtr shader = solidColor ? m->shaderSolid : m->shader;
+ shader->BeginPass();
- shader->Bind();
+ shader->GetShader()->Uniform("transform", g_Renderer.GetViewCamera().GetViewProjection());
if (!solidColor)
glEnable(GL_BLEND);
@@ -136,7 +128,7 @@ void ParticleRenderer::RenderParticles(bool solidColor)
CParticleEmitter* emitter = m->emitters[i];
emitter->Bind();
- emitter->RenderArray(shader);
+ emitter->RenderArray(shader->GetShader());
}
CVertexBuffer::Unbind();
@@ -147,7 +139,7 @@ void ParticleRenderer::RenderParticles(bool solidColor)
glDisable(GL_BLEND);
glDepthMask(1);
- shader->Unbind();
+ shader->EndPass();
}
void ParticleRenderer::RenderBounds(CShaderProgramPtr& shader)
diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp
index 0ed339921b..c47a7f7eb5 100644
--- a/source/renderer/PatchRData.cpp
+++ b/source/renderer/PatchRData.cpp
@@ -746,7 +746,7 @@ void CPatchRData::RenderBases(const std::vector& patches, const CS
{
if (itt->first)
{
- itt->first->GetTexture()->Bind();
+ shader->BindTexture("baseTex", itt->first->GetTexture());
#if !CONFIG2_GLES
if (isDummyShader)
@@ -765,7 +765,7 @@ void CPatchRData::RenderBases(const std::vector& patches, const CS
}
else
{
- g_Renderer.GetTextureManager().GetErrorTexture()->Bind();
+ shader->BindTexture("baseTex", g_Renderer.GetTextureManager().GetErrorTexture());
}
for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv)
@@ -931,7 +931,7 @@ void CPatchRData::RenderBlends(const std::vector& patches, const C
{
if (itt->m_Texture)
{
- itt->m_Texture->GetTexture()->Bind();
+ shader->BindTexture("baseTex", itt->m_Texture->GetTexture());
#if !CONFIG2_GLES
if (isDummyShader)
@@ -951,7 +951,7 @@ void CPatchRData::RenderBlends(const std::vector& patches, const C
}
else
{
- g_Renderer.GetTextureManager().GetErrorTexture()->Bind();
+ shader->BindTexture("baseTex", g_Renderer.GetTextureManager().GetErrorTexture());
}
for (VertexBufferBatches::iterator itv = itt->m_Batches.begin(); itv != itt->m_Batches.end(); ++itv)
diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp
index 7dfce3c5a3..277298c7f3 100644
--- a/source/renderer/Renderer.cpp
+++ b/source/renderer/Renderer.cpp
@@ -541,11 +541,15 @@ void CRenderer::EnumCaps()
m_Caps.m_FragmentShader = true;
}
+#if CONFIG2_GLES
+ m_Caps.m_Shadows = true;
+#else
if (0 == ogl_HaveExtensions(0, "GL_ARB_shadow", "GL_ARB_depth_texture", "GL_EXT_framebuffer_object", NULL))
{
if (ogl_max_tex_units >= 4)
m_Caps.m_Shadows = true;
}
+#endif
}
void CRenderer::ReloadShaders()
@@ -562,6 +566,9 @@ void CRenderer::ReloadShaders()
defBasic["USE_FP_SHADOW"] = "1";
if (m_Options.m_ShadowPCF)
defBasic["USE_SHADOW_PCF"] = "1";
+#if !CONFIG2_GLES
+ defBasic["USE_SHADOW_SAMPLER"] = "1";
+#endif
}
if (m_LightEnv)
@@ -958,6 +965,8 @@ void CRenderer::RenderShadowMap()
#endif
m->shadow->EndRender();
+
+ m->SetOpenGLCamera(m_ViewCamera);
}
void CRenderer::RenderPatches(const CFrustum* frustum)
@@ -1223,7 +1232,7 @@ SScreenRect CRenderer::RenderReflections(const CBoundingBoxAligned& scissor)
glEnable(GL_SCISSOR_TEST);
glScissor(screenScissor.x1, screenScissor.y1, screenScissor.x2 - screenScissor.x1, screenScissor.y2 - screenScissor.y1);
- glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glFrontFace(GL_CW);
@@ -1608,7 +1617,8 @@ void CRenderer::RenderSubmissions()
if (m_DisplayFrustum)
{
DisplayFrustum();
- m->shadow->RenderDebugDisplay();
+ m->shadow->RenderDebugBounds();
+ m->shadow->RenderDebugTexture();
ogl_WarnIfError();
}
@@ -1802,16 +1812,18 @@ Scene& CRenderer::GetScene()
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BindTexture: bind a GL texture object to current active unit
-void CRenderer::BindTexture(int unit,GLuint tex)
+void CRenderer::BindTexture(int unit, GLuint tex)
{
pglActiveTextureARB(GL_TEXTURE0+unit);
- glBindTexture(GL_TEXTURE_2D,tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+#if !CONFIG2_GLES
if (tex) {
glEnable(GL_TEXTURE_2D);
} else {
glDisable(GL_TEXTURE_2D);
}
+#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h
index 74e6d464ff..337bc9f5a2 100644
--- a/source/renderer/Renderer.h
+++ b/source/renderer/Renderer.h
@@ -239,6 +239,9 @@ public:
// return the current view camera
const CCamera& GetViewCamera() const { return m_ViewCamera; }
+ // replace the current view camera
+ void SetViewCamera(const CCamera& camera) { m_ViewCamera = camera; }
+
// return the current cull camera
const CCamera& GetCullCamera() const { return m_CullCamera; }
diff --git a/source/renderer/ShadowMap.cpp b/source/renderer/ShadowMap.cpp
index 779366da03..72d9d5590f 100644
--- a/source/renderer/ShadowMap.cpp
+++ b/source/renderer/ShadowMap.cpp
@@ -21,6 +21,7 @@
#include "precompiled.h"
+#include "gui/GUIutil.h"
#include "lib/bits.h"
#include "lib/ogl.h"
#include "ps/CLogger.h"
@@ -79,6 +80,10 @@ struct ShadowMapInternals
// alpha texture which is attached to the FBO as a workaround.
GLuint DummyTexture;
+ // Copy of renderer's standard view camera, saved between
+ // BeginRender and EndRender while we replace it with the shadow camera
+ CCamera SavedViewCamera;
+
float FilterOffsets[8];
// Helper functions
@@ -233,7 +238,7 @@ void ShadowMapInternals::CalcShadowMatrices()
// minimum Z bound must not be clipped too much, because objects that lie outside
// the shadow bounds cannot cast shadows either
- // the 2.0 is rather arbitrary: it should be big enough so that we won't accidently miss
+ // the 2.0 is rather arbitrary: it should be big enough so that we won't accidentally miss
// a shadow generator, and small enough not to affect Z precision
ShadowBound[0].Z = minZ - 2.0;
@@ -317,9 +322,8 @@ void ShadowMapInternals::CreateTexture()
}
else
{
- // get shadow map size as next power of two up from view width and height
- Width = (int)round_up_to_pow2((unsigned)g_Renderer.GetWidth());
- Height = (int)round_up_to_pow2((unsigned)g_Renderer.GetHeight());
+ // get shadow map size as next power of two up from view width/height
+ Width = Height = (int)round_up_to_pow2((unsigned)std::max(g_Renderer.GetWidth(), g_Renderer.GetHeight()));
}
// Clamp to the maximum texture size
Width = std::min(Width, (int)ogl_max_tex_size);
@@ -359,31 +363,42 @@ void ShadowMapInternals::CreateTexture()
GLenum format;
- switch(DepthTextureBits)
+#if CONFIG2_GLES
+ format = GL_DEPTH_COMPONENT;
+#else
+ switch (DepthTextureBits)
{
case 16: format = GL_DEPTH_COMPONENT16; break;
-#if !CONFIG2_GLES
case 24: format = GL_DEPTH_COMPONENT24; break;
case 32: format = GL_DEPTH_COMPONENT32; break;
-#endif
default: format = GL_DEPTH_COMPONENT; break;
}
-
- glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
-
-#if CONFIG2_GLES
-#warning TODO: implement shadows with non-depth textures and explicit comparisons in the GLSL
-#else
- glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
+ // GLES requires type == UNSIGNED_SHORT or UNSIGNED_INT
+
// set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+#if CONFIG2_GLES
+ // GLES doesn't do depth comparisons, so treat it as a
+ // basic unfiltered depth texture
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+#else
+ // Enable automatic depth comparisons
+ glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+
+ // Use GL_LINEAR to trigger automatic PCF on some devices
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+#endif
+
+ ogl_WarnIfError();
// bind to framebuffer object
glBindTexture(GL_TEXTURE_2D, 0);
@@ -408,6 +423,8 @@ void ShadowMapInternals::CreateTexture()
glReadBuffer(GL_NONE);
#endif
+ ogl_WarnIfError();
+
GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
@@ -452,22 +469,27 @@ void ShadowMap::BeginRender()
// clear buffers
{
PROFILE("clear depth texture");
- glClear(GL_DEPTH_BUFFER_BIT);
+ // In case we used m_ShadowAlphaFix, we ought to clear the unused
+ // color buffer too, else Mali 400 drivers get confused.
+ // Might as well clear stencil too for completeness.
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glColorMask(0,0,0,0);
}
// setup viewport
glViewport(0, 0, m->EffectiveWidth, m->EffectiveHeight);
-#if CONFIG2_GLES
-#warning TODO: implement ShdaowMap::BeginRender GLES
-#else
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(&m->LightProjection._11);
+ m->SavedViewCamera = g_Renderer.GetViewCamera();
+ CCamera c = m->SavedViewCamera;
+ c.SetProjection(m->LightProjection);
+ c.GetOrientation() = m->InvLightTransform;
+ g_Renderer.SetViewCamera(c);
+
+#if !CONFIG2_GLES
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(&m->LightProjection._11);
glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
glLoadMatrixf(&m->LightTransform._11);
#endif
@@ -482,6 +504,8 @@ void ShadowMap::EndRender()
{
glDisable(GL_SCISSOR_TEST);
+ g_Renderer.SetViewCamera(m->SavedViewCamera);
+
{
PROFILE("unbind framebuffer");
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
@@ -490,14 +514,6 @@ void ShadowMap::EndRender()
glViewport(0, 0, g_Renderer.GetWidth(), g_Renderer.GetHeight());
glColorMask(1,1,1,1);
-
-#if !CONFIG2_GLES
- // restore matrix stack
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
-#endif
}
@@ -542,9 +558,8 @@ const float* ShadowMap::GetFilterOffsets() const
}
//////////////////////////////////////////////////////////////////////////////
-// RenderDebugDisplay: debug visualizations
-// - blue: objects in shadow
-void ShadowMap::RenderDebugDisplay()
+
+void ShadowMap::RenderDebugBounds()
{
CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect("gui_solid");
shaderTech->BeginPass();
@@ -617,36 +632,48 @@ void ShadowMap::RenderDebugDisplay()
glPopMatrix();
#endif
- // Render the shadow map
-#if CONFIG2_GLES
-#warning TODO: implement ShadowMap::RenderDebugDisplay for GLES
-#else
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
+ glEnable(GL_CULL_FACE);
+ glDepthMask(1);
+}
+
+void ShadowMap::RenderDebugTexture()
+{
+ glDepthMask(0);
glDisable(GL_DEPTH_TEST);
+
+#if !CONFIG2_GLES
g_Renderer.BindTexture(0, m->Texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
- glColor3f(1.0f, 1.0f, 1.0f);
- glBegin(GL_QUADS);
- glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
- glTexCoord2f(1.0f, 0.0f); glVertex2f(0.2f, 0.0f);
- glTexCoord2f(1.0f, 1.0f); glVertex2f(0.2f, 0.2f);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 0.2f);
- glEnd();
+#endif
+
+ CShaderTechniquePtr texTech = g_Renderer.GetShaderManager().LoadEffect("gui_basic");
+ texTech->BeginPass();
+ CShaderProgramPtr texShader = texTech->GetShader();
+
+ texShader->Uniform("transform", GetDefaultGuiMatrix());
+ texShader->BindTexture("tex", m->Texture);
+
+ float s = 256.f;
+ float boxVerts[] = {
+ 0,0, 0,s, s,0,
+ s,0, 0,s, s,s
+ };
+ float boxUV[] = {
+ 0,0, 0,1, 1,0,
+ 1,0, 0,1, 1,1
+ };
+
+ texShader->VertexPointer(2, GL_FLOAT, 0, boxVerts);
+ texShader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, boxUV);
+ texShader->AssertPointersBound();
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ texTech->EndPass();
+
+#if !CONFIG2_GLES
+ g_Renderer.BindTexture(0, m->Texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
-
- glEnable(GL_CULL_FACE);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
#endif
glEnable(GL_DEPTH_TEST);
diff --git a/source/renderer/ShadowMap.h b/source/renderer/ShadowMap.h
index 2480747c6f..577422e796 100644
--- a/source/renderer/ShadowMap.h
+++ b/source/renderer/ShadowMap.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
@@ -113,10 +113,15 @@ public:
const CMatrix3D& GetTextureMatrix() const;
/**
- * RenderDebugDisplay: Visualize shadow mapping calculations to help in
+ * Visualize shadow mapping calculations to help in
* debugging and optimal shadow map usage.
*/
- void RenderDebugDisplay();
+ void RenderDebugBounds();
+
+ /**
+ * Visualize shadow map texture to help in debugging.
+ */
+ void RenderDebugTexture();
/**
* Get offsets for PCF filtering.
diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp
index ddcb0a5c78..afc1ff3be6 100644
--- a/source/renderer/TerrainRenderer.cpp
+++ b/source/renderer/TerrainRenderer.cpp
@@ -408,6 +408,8 @@ void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap*
shader->Uniform("ambient", lightEnv.m_TerrainAmbientColor);
shader->Uniform("sunColor", lightEnv.m_SunColor);
+
+ shader->BindTexture("blendTex", g_Renderer.m_hCompositeAlphaMap);
}
void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow, bool filtered)
@@ -430,6 +432,9 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow, bool filtered)
defBasic["USE_FP_SHADOW"] = "1";
if (g_Renderer.m_Options.m_ShadowPCF)
defBasic["USE_SHADOW_PCF"] = "1";
+#if !CONFIG2_GLES
+ defBasic["USE_SHADOW_SAMPLER"] = "1";
+#endif
}
defBasic["LIGHTING_MODEL_" + g_Renderer.GetLightEnv().GetLightingModel()] = "1";
@@ -466,9 +471,6 @@ void TerrainRenderer::RenderTerrainShader(ShadowMap* shadow, bool filtered)
techBlend->BeginPass();
PrepareShader(techBlend->GetShader(), shadow);
- // switch on the composite alpha map texture
- (void)ogl_tex_bind(g_Renderer.m_hCompositeAlphaMap, 1);
-
// switch on blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);