diff --git a/src/gpu/rendercontext.cpp b/src/gpu/rendercontext.cpp index 00399d6e..d271c26b 100644 --- a/src/gpu/rendercontext.cpp +++ b/src/gpu/rendercontext.cpp @@ -57,6 +57,9 @@ private: TrackedState m_clear_color; TrackedState m_clear_depth; TrackedState m_alpha_blend; + TrackedState m_blend_src; + TrackedState m_blend_dst; + TrackedState m_alpha_test; TrackedState m_depth_test; TrackedState m_face_culling; }; @@ -73,9 +76,22 @@ RenderContext::RenderContext() RenderContext::~RenderContext() { + if (m_data->m_clear_color.HasChanged()) + g_renderer->SetClearColor(m_data->m_clear_color.GetValue()); + + if (m_data->m_clear_depth.HasChanged()) + g_renderer->SetClearDepth(m_data->m_clear_depth.GetValue()); + if (m_data->m_alpha_blend.HasChanged()) g_renderer->SetAlphaBlend(m_data->m_alpha_blend.GetValue()); + if (m_data->m_blend_src.HasChanged()) + g_renderer->SetBlendFunc(m_data->m_blend_src.GetValue(), + m_data->m_blend_dst.GetValue()); + + if (m_data->m_alpha_test.HasChanged()) + g_renderer->SetAlphaTest(m_data->m_alpha_test.GetValue()); + if (m_data->m_depth_test.HasChanged()) g_renderer->SetDepthTest(m_data->m_depth_test.GetValue()); @@ -109,6 +125,24 @@ void RenderContext::SetAlphaBlend(bool set) g_renderer->SetAlphaBlend(set); } +void RenderContext::SetBlendFunc(BlendFactor src, BlendFactor dst) +{ + if (!m_data->m_blend_src.HasChanged()) + m_data->m_blend_src.TrackValue(g_renderer->GetBlendFuncSrc()); + if (!m_data->m_blend_dst.HasChanged()) + m_data->m_blend_dst.TrackValue(g_renderer->GetBlendFuncDst()); + + g_renderer->SetBlendFunc(src, dst); +} + +void RenderContext::SetAlphaTest(bool set) +{ + if (!m_data->m_alpha_test.HasChanged()) + m_data->m_alpha_test.TrackValue(g_renderer->GetAlphaTest()); + + g_renderer->SetAlphaTest(set); +} + void RenderContext::SetDepthTest(bool set) { if (!m_data->m_depth_test.HasChanged()) diff --git a/src/gpu/renderer.cpp b/src/gpu/renderer.cpp index edd34334..86250c18 100644 --- a/src/gpu/renderer.cpp +++ b/src/gpu/renderer.cpp @@ -49,7 +49,8 @@ class RendererData private: vec4 m_clear_color; float m_clear_depth; - bool m_blend, m_depth_test, m_face_culling; + BlendFactor m_blend_src, m_blend_dst; + bool m_alpha_blend, m_alpha_test, m_depth_test, m_face_culling; }; /* @@ -80,9 +81,16 @@ Renderer::Renderer() m_data->m_clear_depth = -1.f; SetClearDepth(1.f); - m_data->m_blend = false; + m_data->m_alpha_blend = false; SetAlphaBlend(true); + m_data->m_alpha_test = true; + SetAlphaTest(false); + + m_data->m_blend_src = BlendFactor::Zero; + m_data->m_blend_dst = BlendFactor::Zero; + SetBlendFunc(BlendFactor::SrcAlpha, BlendFactor::OneMinusSrcAlpha); + m_data->m_depth_test = false; SetDepthTest(true); @@ -152,13 +160,11 @@ float Renderer::GetClearDepth() const void Renderer::SetAlphaBlend(bool set) { - if (m_data->m_blend == set) + if (m_data->m_alpha_blend == set) return; #if defined USE_D3D9 || defined _XBOX -# define STR0(x) #x -# define STR(x) STR0(x) -# pragma message(__FILE__ "(" STR(__LINE__) "): warning: Renderer::SetAlphaBlend() not implemented") + m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHABLENDENABLE, set ? 1 : 0); #else if (set) glEnable(GL_BLEND); @@ -166,12 +172,149 @@ void Renderer::SetAlphaBlend(bool set) glDisable(GL_BLEND); #endif - m_data->m_blend = set; + m_data->m_alpha_blend = set; } bool Renderer::GetAlphaBlend() const { - return m_data->m_blend; + return m_data->m_alpha_blend; +} + +/* + * Blend function + */ + +void Renderer::SetBlendFunc(BlendFactor src, BlendFactor dst) +{ + if (m_data->m_blend_src == src && m_data->m_blend_dst == dst) + return; + +#if defined USE_D3D9 || defined _XBOX + enum D3DBLEND s1[2] = { D3DBLEND_ONE, D3DBLEND_ZERO }; + BlendFactor s2[2] = { src, dst }; + + for (int i = 0; i < 2; ++i) + { + switch (s2[i]) + { + case BlendFactor::Zero: + s1[i] = D3DBLEND_ZERO; break; + case BlendFactor::One: + s1[i] = D3DBLEND_ONE; break; + case BlendFactor::SrcColor: + s1[i] = D3DBLEND_SRCCOLOR; break; + case BlendFactor::OneMinusSrcColor: + s1[i] = D3DBLEND_INVSRCCOLOR; break; + case BlendFactor::DstColor: + s1[i] = D3DBLEND_DESTCOLOR; break; + case BlendFactor::OneMinusDstColor: + s1[i] = D3DBLEND_INVDESTCOLOR; break; + case BlendFactor::SrcAlpha: + s1[i] = D3DBLEND_SRCALPHA; break; + case BlendFactor::OneMinusSrcAlpha: + s1[i] = D3DBLEND_INVSRCALPHA; break; + case BlendFactor::DstAlpha: + s1[i] = D3DBLEND_DESTALPHA; break; + case BlendFactor::OneMinusDstAlpha: + s1[i] = D3DBLEND_INVDESTALPHA; break; + /* FiXME: these can be supported using D3DPBLENDCAPS_BLENDFACTOR */ + case BlendFactor::ConstantColor: + assert(0, "BlendFactor::ConstantColor not supported"); + break; + case BlendFactor::OneMinusConstantColor: + assert(0, "BlendFactor::OneMinusConstantColor not supported"); + break; + case BlendFactor::ConstantAlpha: + assert(0, "BlendFactor::ConstantAlpha not supported"); + break; + case BlendFactor::OneMinusConstantAlpha: + assert(0, "BlendFactor::OneMinusConstantAlpha not supported"); + break; + } + } + + m_data->m_d3d_dev->SetRenderState(D3DRS_SRCBLEND, s1[0]); + m_data->m_d3d_dev->SetRenderState(D3DRS_DESTBLEND, s1[1]); +#else + GLenum s1[2] = { GL_ONE, GL_ZERO }; + BlendFactor s2[2] = { src, dst }; + + for (int i = 0; i < 2; ++i) + { + switch (s2[i]) + { + case BlendFactor::Zero: + s1[i] = GL_ZERO; break; + case BlendFactor::One: + s1[i] = GL_ONE; break; + case BlendFactor::SrcColor: + s1[i] = GL_SRC_COLOR; break; + case BlendFactor::OneMinusSrcColor: + s1[i] = GL_ONE_MINUS_SRC_COLOR; break; + case BlendFactor::DstColor: + s1[i] = GL_DST_COLOR; break; + case BlendFactor::OneMinusDstColor: + s1[i] = GL_ONE_MINUS_DST_COLOR; break; + case BlendFactor::SrcAlpha: + s1[i] = GL_SRC_ALPHA; break; + case BlendFactor::OneMinusSrcAlpha: + s1[i] = GL_ONE_MINUS_SRC_ALPHA; break; + case BlendFactor::DstAlpha: + s1[i] = GL_DST_ALPHA; break; + case BlendFactor::OneMinusDstAlpha: + s1[i] = GL_ONE_MINUS_DST_ALPHA; break; + case BlendFactor::ConstantColor: + s1[i] = GL_CONSTANT_COLOR; break; + case BlendFactor::OneMinusConstantColor: + s1[i] = GL_ONE_MINUS_CONSTANT_COLOR; break; + case BlendFactor::ConstantAlpha: + s1[i] = GL_CONSTANT_ALPHA; break; + case BlendFactor::OneMinusConstantAlpha: + s1[i] = GL_ONE_MINUS_CONSTANT_ALPHA; break; + } + } + + glBlendFunc(s1[0], s1[1]); +#endif + + m_data->m_blend_src = src; + m_data->m_blend_dst = dst; +} + +BlendFactor Renderer::GetBlendFuncSrc() const +{ + return m_data->m_blend_src; +} + +BlendFactor Renderer::GetBlendFuncDst() const +{ + return m_data->m_blend_dst; +} + +/* + * Alpha testing + */ + +void Renderer::SetAlphaTest(bool set) +{ + if (m_data->m_alpha_test == set) + return; + +#if defined USE_D3D9 || defined _XBOX + m_data->m_d3d_dev->SetRenderState(D3DRS_ALPHATESTENABLE, set ? 1 : 0); +#else + if (set) + glEnable(GL_ALPHA_TEST); + else + glDisable(GL_ALPHA_TEST); +#endif + + m_data->m_alpha_test = set; +} + +bool Renderer::GetAlphaTest() const +{ + return m_data->m_alpha_test; } /* diff --git a/src/gpu/vertexbuffer.cpp b/src/gpu/vertexbuffer.cpp index 10884022..7303bbc6 100644 --- a/src/gpu/vertexbuffer.cpp +++ b/src/gpu/vertexbuffer.cpp @@ -127,9 +127,6 @@ void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count) return; #if defined _XBOX || defined USE_D3D9 - g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1); - g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW))) Abort(); switch (type) @@ -163,7 +160,6 @@ void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count) #else /* FIXME: this has nothing to do here! */ glFrontFace(GL_CCW); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); switch (type) { @@ -194,9 +190,6 @@ void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase, return; #if defined _XBOX || defined USE_D3D9 - g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1); - g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW))) Abort(); switch (type) @@ -233,7 +226,6 @@ void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase, #else /* FIXME: this has nothing to do here! */ glFrontFace(GL_CCW); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); switch (type) { diff --git a/src/lol/gpu/rendercontext.h b/src/lol/gpu/rendercontext.h index 6f4acda1..19ae0041 100644 --- a/src/lol/gpu/rendercontext.h +++ b/src/lol/gpu/rendercontext.h @@ -30,6 +30,8 @@ public: void SetClearColor(vec4 color); void SetClearDepth(float depth); void SetAlphaBlend(bool set); + void SetBlendFunc(BlendFactor src, BlendFactor dst); + void SetAlphaTest(bool set); void SetDepthTest(bool set); void SetFaceCulling(bool set); diff --git a/src/lol/gpu/renderer.h b/src/lol/gpu/renderer.h index b1dafcbe..6086a4f3 100644 --- a/src/lol/gpu/renderer.h +++ b/src/lol/gpu/renderer.h @@ -21,6 +21,33 @@ namespace lol class RendererData; +/* A safe enum to indicate the blending factors. */ +struct BlendFactor +{ + enum Value + { + Zero, + One, + SrcColor, + OneMinusSrcColor, + DstColor, + OneMinusDstColor, + SrcAlpha, + OneMinusSrcAlpha, + DstAlpha, + OneMinusDstAlpha, + ConstantColor, + OneMinusConstantColor, + ConstantAlpha, + OneMinusConstantAlpha, + } + m_value; + + inline BlendFactor() : m_value(Zero) {} + inline BlendFactor(Value v) : m_value(v) {} + inline operator Value() { return m_value; } +}; + class Renderer { private: @@ -40,6 +67,13 @@ public: void SetAlphaBlend(bool set); bool GetAlphaBlend() const; + void SetBlendFunc(BlendFactor src, BlendFactor dst); + BlendFactor GetBlendFuncSrc() const; + BlendFactor GetBlendFuncDst() const; + + void SetAlphaTest(bool set); + bool GetAlphaTest() const; + void SetDepthTest(bool set); bool GetDepthTest() const; diff --git a/src/scene.cpp b/src/scene.cpp index 2223cc28..1ad30a51 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -194,6 +194,7 @@ void Scene::Render() // XXX: rename to Blit() RenderContext rc; rc.SetDepthTest(true); rc.SetAlphaBlend(true); + rc.SetBlendFunc(BlendFactor::SrcAlpha, BlendFactor::OneMinusSrcAlpha); #if defined USE_D3D9 || defined _XBOX #else @@ -202,7 +203,6 @@ void Scene::Render() // XXX: rename to Blit() glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.01f); #endif - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif /* Early test if nothing needs to be rendered */