@@ -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 */ | ||||