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