| @@ -57,6 +57,9 @@ private: | |||||
| TrackedState<vec4> m_clear_color; | TrackedState<vec4> m_clear_color; | ||||
| TrackedState<float> m_clear_depth; | TrackedState<float> m_clear_depth; | ||||
| TrackedState<bool> m_alpha_blend; | TrackedState<bool> m_alpha_blend; | ||||
| TrackedState<BlendFactor> m_blend_src; | |||||
| TrackedState<BlendFactor> m_blend_dst; | |||||
| TrackedState<bool> m_alpha_test; | |||||
| TrackedState<bool> m_depth_test; | TrackedState<bool> m_depth_test; | ||||
| TrackedState<bool> m_face_culling; | TrackedState<bool> m_face_culling; | ||||
| }; | }; | ||||
| @@ -73,9 +76,22 @@ RenderContext::RenderContext() | |||||
| 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()) | if (m_data->m_alpha_blend.HasChanged()) | ||||
| g_renderer->SetAlphaBlend(m_data->m_alpha_blend.GetValue()); | 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()) | if (m_data->m_depth_test.HasChanged()) | ||||
| g_renderer->SetDepthTest(m_data->m_depth_test.GetValue()); | g_renderer->SetDepthTest(m_data->m_depth_test.GetValue()); | ||||
| @@ -109,6 +125,24 @@ void RenderContext::SetAlphaBlend(bool set) | |||||
| g_renderer->SetAlphaBlend(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) | void RenderContext::SetDepthTest(bool set) | ||||
| { | { | ||||
| if (!m_data->m_depth_test.HasChanged()) | if (!m_data->m_depth_test.HasChanged()) | ||||
| @@ -49,7 +49,8 @@ class RendererData | |||||
| private: | private: | ||||
| vec4 m_clear_color; | vec4 m_clear_color; | ||||
| float m_clear_depth; | 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; | m_data->m_clear_depth = -1.f; | ||||
| SetClearDepth(1.f); | SetClearDepth(1.f); | ||||
| m_data->m_blend = false; | |||||
| m_data->m_alpha_blend = false; | |||||
| SetAlphaBlend(true); | 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; | m_data->m_depth_test = false; | ||||
| SetDepthTest(true); | SetDepthTest(true); | ||||
| @@ -152,13 +160,11 @@ float Renderer::GetClearDepth() const | |||||
| void Renderer::SetAlphaBlend(bool set) | void Renderer::SetAlphaBlend(bool set) | ||||
| { | { | ||||
| if (m_data->m_blend == set) | |||||
| if (m_data->m_alpha_blend == set) | |||||
| return; | return; | ||||
| #if defined USE_D3D9 || defined _XBOX | #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 | #else | ||||
| if (set) | if (set) | ||||
| glEnable(GL_BLEND); | glEnable(GL_BLEND); | ||||
| @@ -166,12 +172,149 @@ void Renderer::SetAlphaBlend(bool set) | |||||
| glDisable(GL_BLEND); | glDisable(GL_BLEND); | ||||
| #endif | #endif | ||||
| m_data->m_blend = set; | |||||
| m_data->m_alpha_blend = set; | |||||
| } | } | ||||
| bool Renderer::GetAlphaBlend() const | 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; | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -127,9 +127,6 @@ void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count) | |||||
| return; | return; | ||||
| #if defined _XBOX || defined USE_D3D9 | #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))) | if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW))) | ||||
| Abort(); | Abort(); | ||||
| switch (type) | switch (type) | ||||
| @@ -163,7 +160,6 @@ void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count) | |||||
| #else | #else | ||||
| /* FIXME: this has nothing to do here! */ | /* FIXME: this has nothing to do here! */ | ||||
| glFrontFace(GL_CCW); | glFrontFace(GL_CCW); | ||||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
| switch (type) | switch (type) | ||||
| { | { | ||||
| @@ -194,9 +190,6 @@ void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase, | |||||
| return; | return; | ||||
| #if defined _XBOX || defined USE_D3D9 | #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))) | if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW))) | ||||
| Abort(); | Abort(); | ||||
| switch (type) | switch (type) | ||||
| @@ -233,7 +226,6 @@ void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase, | |||||
| #else | #else | ||||
| /* FIXME: this has nothing to do here! */ | /* FIXME: this has nothing to do here! */ | ||||
| glFrontFace(GL_CCW); | glFrontFace(GL_CCW); | ||||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
| switch (type) | switch (type) | ||||
| { | { | ||||
| @@ -30,6 +30,8 @@ public: | |||||
| void SetClearColor(vec4 color); | void SetClearColor(vec4 color); | ||||
| void SetClearDepth(float depth); | void SetClearDepth(float depth); | ||||
| void SetAlphaBlend(bool set); | void SetAlphaBlend(bool set); | ||||
| void SetBlendFunc(BlendFactor src, BlendFactor dst); | |||||
| void SetAlphaTest(bool set); | |||||
| void SetDepthTest(bool set); | void SetDepthTest(bool set); | ||||
| void SetFaceCulling(bool set); | void SetFaceCulling(bool set); | ||||
| @@ -21,6 +21,33 @@ namespace lol | |||||
| class RendererData; | 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 | class Renderer | ||||
| { | { | ||||
| private: | private: | ||||
| @@ -40,6 +67,13 @@ public: | |||||
| void SetAlphaBlend(bool set); | void SetAlphaBlend(bool set); | ||||
| bool GetAlphaBlend() const; | 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); | void SetDepthTest(bool set); | ||||
| bool GetDepthTest() const; | bool GetDepthTest() const; | ||||
| @@ -194,6 +194,7 @@ void Scene::Render() // XXX: rename to Blit() | |||||
| RenderContext rc; | RenderContext rc; | ||||
| rc.SetDepthTest(true); | rc.SetDepthTest(true); | ||||
| rc.SetAlphaBlend(true); | rc.SetAlphaBlend(true); | ||||
| rc.SetBlendFunc(BlendFactor::SrcAlpha, BlendFactor::OneMinusSrcAlpha); | |||||
| #if defined USE_D3D9 || defined _XBOX | #if defined USE_D3D9 || defined _XBOX | ||||
| #else | #else | ||||
| @@ -202,7 +203,6 @@ void Scene::Render() // XXX: rename to Blit() | |||||
| glEnable(GL_ALPHA_TEST); | glEnable(GL_ALPHA_TEST); | ||||
| glAlphaFunc(GL_GEQUAL, 0.01f); | glAlphaFunc(GL_GEQUAL, 0.01f); | ||||
| #endif | #endif | ||||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
| #endif | #endif | ||||
| /* Early test if nothing needs to be rendered */ | /* Early test if nothing needs to be rendered */ | ||||