diff --git a/binaries/data/mods/official/shaders/instancing_lightp.vs b/binaries/data/mods/official/shaders/instancing_lightp.vs
new file mode 100644
index 0000000000..90d8f9db05
--- /dev/null
+++ b/binaries/data/mods/official/shaders/instancing_lightp.vs
@@ -0,0 +1,17 @@
+vec3 lighting(vec3 normal);
+
+vec3 InstancingNormal(vec3 normal);
+vec4 InstancingPosition(vec4 position);
+
+vec4 postouv1(vec4 pos);
+
+void main()
+{
+ vec3 normal = InstancingNormal(gl_Normal);
+ vec4 worldPos = InstancingPosition(gl_Vertex);
+
+ gl_FrontColor = vec4(lighting(normal),1.0) * gl_Color;
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_TexCoord[1] = postouv1(worldPos);
+ gl_Position = gl_ModelViewProjectionMatrix * worldPos;
+}
diff --git a/binaries/data/mods/official/shaders/instancing_lightp.xml b/binaries/data/mods/official/shaders/instancing_lightp.xml
new file mode 100644
index 0000000000..2f2b02cdbc
--- /dev/null
+++ b/binaries/data/mods/official/shaders/instancing_lightp.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ shaders/instancing_lightp.vs
+ shaders/instancing_base.vs
+ shaders/globallight.vs
+ shaders/postouv1.vs
+
+
diff --git a/binaries/data/mods/official/shaders/instancingp.vs b/binaries/data/mods/official/shaders/instancingp.vs
new file mode 100644
index 0000000000..78dc234a52
--- /dev/null
+++ b/binaries/data/mods/official/shaders/instancingp.vs
@@ -0,0 +1,12 @@
+vec4 InstancingPosition(vec4 position);
+vec4 postouv1(vec4 pos);
+
+void main()
+{
+ vec4 worldPos = InstancingPosition(gl_Vertex);
+
+ gl_FrontColor = gl_Color;
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_TexCoord[1] = postouv1(worldPos);
+ gl_Position = gl_ModelViewProjectionMatrix * worldPos;
+}
diff --git a/binaries/data/mods/official/shaders/instancingp.xml b/binaries/data/mods/official/shaders/instancingp.xml
new file mode 100644
index 0000000000..63c124cfbb
--- /dev/null
+++ b/binaries/data/mods/official/shaders/instancingp.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ shaders/instancingp.vs
+ shaders/instancing_base.vs
+ shaders/postouv1.vs
+
+
diff --git a/binaries/data/mods/official/shaders/model_lightp.vs b/binaries/data/mods/official/shaders/model_lightp.vs
new file mode 100644
index 0000000000..12c088fefb
--- /dev/null
+++ b/binaries/data/mods/official/shaders/model_lightp.vs
@@ -0,0 +1,10 @@
+vec3 lighting(vec3 normal);
+vec4 postouv1(vec4 pos);
+
+void main()
+{
+ gl_FrontColor = vec4(lighting(gl_Normal),1.0) * gl_Color;
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_TexCoord[1] = postouv1(gl_Vertex);
+ gl_Position = ftransform();
+}
diff --git a/binaries/data/mods/official/shaders/model_lightp.xml b/binaries/data/mods/official/shaders/model_lightp.xml
new file mode 100644
index 0000000000..dc9678c44f
--- /dev/null
+++ b/binaries/data/mods/official/shaders/model_lightp.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ shaders/model_lightp.vs
+ shaders/globallight.vs
+ shaders/postouv1.vs
+
+
diff --git a/binaries/data/mods/official/shaders/postouv1.vs b/binaries/data/mods/official/shaders/postouv1.vs
new file mode 100644
index 0000000000..5306059a09
--- /dev/null
+++ b/binaries/data/mods/official/shaders/postouv1.vs
@@ -0,0 +1,14 @@
+uniform vec4 TextureMatrix1;
+uniform vec4 TextureMatrix2;
+uniform vec4 TextureMatrix3;
+
+vec4 postouv1(vec4 pos)
+{
+ vec3 tmp;
+
+ tmp.x = dot(TextureMatrix1, pos);
+ tmp.y = dot(TextureMatrix2, pos);
+ tmp.z = dot(TextureMatrix3, pos);
+
+ return vec4(tmp, 1.0);
+}
diff --git a/source/renderer/FixedFunctionModelRenderer.cpp b/source/renderer/FixedFunctionModelRenderer.cpp
index 5819407f35..065e18d9d9 100644
--- a/source/renderer/FixedFunctionModelRenderer.cpp
+++ b/source/renderer/FixedFunctionModelRenderer.cpp
@@ -92,14 +92,18 @@ struct FixedFunctionModelRendererInternals
/// Previously prepared modeldef
FFModelDef* ffmodeldef;
+
+ /// If true, primary color will only contain the diffuse term
+ bool colorIsDiffuseOnly;
};
// Construction and Destruction
-FixedFunctionModelRenderer::FixedFunctionModelRenderer()
+FixedFunctionModelRenderer::FixedFunctionModelRenderer(bool colorIsDiffuseOnly)
{
m = new FixedFunctionModelRendererInternals;
m->ffmodeldef = 0;
+ m->colorIsDiffuseOnly = colorIsDiffuseOnly;
}
FixedFunctionModelRenderer::~FixedFunctionModelRenderer()
@@ -159,7 +163,7 @@ void FixedFunctionModelRenderer::UpdateModelData(CModel* model, void* data, u32
VertexArrayIterator Color = ffmodel->m_Color.GetIterator();
- ModelRenderer::BuildColor4ub(model, Normal, Color);
+ ModelRenderer::BuildColor4ub(model, Normal, Color, m->colorIsDiffuseOnly);
// upload everything to vertex buffer
ffmodel->m_Array.Upload();
@@ -178,12 +182,28 @@ void FixedFunctionModelRenderer::DestroyModelData(CModel* UNUSED(model), void* d
// Setup one rendering pass
-void FixedFunctionModelRenderer::BeginPass(uint streamflags)
+void FixedFunctionModelRenderer::BeginPass(uint streamflags, const CMatrix3D* texturematrix)
{
+ debug_assert(streamflags == streamflags & (STREAM_POS|STREAM_UV0|STREAM_COLOR|STREAM_TEXGENTOUV1));
+
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ pglActiveTextureARB(GL_TEXTURE1);
+ pglClientActiveTextureARB(GL_TEXTURE1);
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadMatrixf(&texturematrix->_11);
+ glMatrixMode(GL_MODELVIEW);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+ pglClientActiveTextureARB(GL_TEXTURE0);
+ }
}
@@ -192,6 +212,20 @@ void FixedFunctionModelRenderer::EndPass(uint streamflags)
{
if (streamflags & STREAM_UV0) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ pglActiveTextureARB(GL_TEXTURE1);
+ pglClientActiveTextureARB(GL_TEXTURE1);
+
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+ pglClientActiveTextureARB(GL_TEXTURE0);
+ }
glDisableClientState(GL_VERTEX_ARRAY);
}
@@ -226,6 +260,14 @@ void FixedFunctionModelRenderer::RenderModel(uint streamflags, CModel* model, vo
glVertexPointer(3, GL_FLOAT, stride, base + ffmodel->m_Position.offset);
if (streamflags & STREAM_COLOR)
glColorPointer(3, ffmodel->m_Color.type, stride, base + ffmodel->m_Color.offset);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ pglClientActiveTextureARB(GL_TEXTURE1);
+ pglActiveTextureARB(GL_TEXTURE1);
+ glTexCoordPointer(3, GL_FLOAT, stride, base + ffmodel->m_Position.offset);
+ pglClientActiveTextureARB(GL_TEXTURE0);
+ pglActiveTextureARB(GL_TEXTURE0);
+ }
// render the lot
size_t numFaces = mdldef->GetNumFaces();
diff --git a/source/renderer/FixedFunctionModelRenderer.h b/source/renderer/FixedFunctionModelRenderer.h
index 07407b69de..5745633c62 100644
--- a/source/renderer/FixedFunctionModelRenderer.h
+++ b/source/renderer/FixedFunctionModelRenderer.h
@@ -23,15 +23,21 @@ struct FixedFunctionModelRendererInternals;
class FixedFunctionModelRenderer : public ModelVertexRenderer
{
public:
- FixedFunctionModelRenderer();
+ /**
+ * FixedFunctionModelRenderer: Constructor.
+ *
+ * @param colorIsDiffuseOnly if true, the primary color sent to the fragment stage
+ * contains only the diffuse term, and not the ambient
+ */
+ FixedFunctionModelRenderer(bool colorIsDiffuseOnly);
~FixedFunctionModelRenderer();
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
-
- void BeginPass(uint streamflags);
+
+ void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
diff --git a/source/renderer/HWLightingModelRenderer.cpp b/source/renderer/HWLightingModelRenderer.cpp
index f1199fa1c7..21a5c28c00 100644
--- a/source/renderer/HWLightingModelRenderer.cpp
+++ b/source/renderer/HWLightingModelRenderer.cpp
@@ -76,14 +76,18 @@ struct HWLightingModelRendererInternals
/// Previously prepared modeldef
HWLModelDef* hwlmodeldef;
+
+ /// If true, primary color will only contain the diffuse term
+ bool colorIsDiffuseOnly;
};
// Construction and Destruction
-HWLightingModelRenderer::HWLightingModelRenderer()
+HWLightingModelRenderer::HWLightingModelRenderer(bool colorIsDiffuseOnly)
{
m = new HWLightingModelRendererInternals;
m->hwlmodeldef = 0;
+ m->colorIsDiffuseOnly = colorIsDiffuseOnly;
}
HWLightingModelRenderer::~HWLightingModelRenderer()
@@ -170,26 +174,76 @@ void HWLightingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* data
// Setup one rendering pass
-void HWLightingModelRenderer::BeginPass(uint streamflags)
+void HWLightingModelRenderer::BeginPass(uint streamflags, const CMatrix3D* texturematrix)
{
+ debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_UV0|STREAM_COLOR|STREAM_TEXGENTOUV1)));
+
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
+ RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
- int idx;
+ VS_GlobalLight* lightConfig;
- ogl_program_use(g_Renderer.m_VertexShader->m_ModelLight);
- idx = g_Renderer.m_VertexShader->m_ModelLight_Ambient;
- pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X);
- idx = g_Renderer.m_VertexShader->m_ModelLight_SunDir;
- pglUniform3fvARB(idx, 1, &lightEnv.GetSunDir().X);
- idx = g_Renderer.m_VertexShader->m_ModelLight_SunColor;
- pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ ogl_program_use(rpvs->m_ModelLightP);
+ lightConfig = &rpvs->m_ModelLightP_Light;
+
+ rpvs->m_ModelLightP_PosToUV1.SetMatrix(*texturematrix);
+ }
+ else
+ {
+ ogl_program_use(rpvs->m_ModelLight);
+ lightConfig = &rpvs->m_ModelLight_Light;
+ }
+
+ if (m->colorIsDiffuseOnly)
+ lightConfig->SetAmbient(RGBColor(0,0,0));
+ else
+ lightConfig->SetAmbient(lightEnv.m_UnitsAmbientColor);
+ lightConfig->SetSunDir(lightEnv.GetSunDir());
+ lightConfig->SetSunColor(lightEnv.m_SunColor);
glEnableClientState(GL_NORMAL_ARRAY);
}
+ else
+ {
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ pglActiveTextureARB(GL_TEXTURE1);
+
+ float tmp[4];
+
+ glEnable(GL_TEXTURE_GEN_S);
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ tmp[0] = texturematrix->_11;
+ tmp[1] = texturematrix->_12;
+ tmp[2] = texturematrix->_13;
+ tmp[3] = texturematrix->_14;
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, tmp);
+
+ glEnable(GL_TEXTURE_GEN_T);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ tmp[0] = texturematrix->_21;
+ tmp[1] = texturematrix->_22;
+ tmp[2] = texturematrix->_23;
+ tmp[3] = texturematrix->_24;
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, tmp);
+
+ glEnable(GL_TEXTURE_GEN_R);
+ glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ tmp[0] = texturematrix->_31;
+ tmp[1] = texturematrix->_32;
+ tmp[2] = texturematrix->_33;
+ tmp[3] = texturematrix->_34;
+ glTexGenfv(GL_R, GL_OBJECT_PLANE, tmp);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+ }
+ }
}
@@ -203,6 +257,19 @@ void HWLightingModelRenderer::EndPass(uint streamflags)
glDisableClientState(GL_NORMAL_ARRAY);
}
+ else
+ {
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ pglActiveTextureARB(GL_TEXTURE1);
+
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable(GL_TEXTURE_GEN_R);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+ }
+ }
glDisableClientState(GL_VERTEX_ARRAY);
}
diff --git a/source/renderer/HWLightingModelRenderer.h b/source/renderer/HWLightingModelRenderer.h
index 7a39f6d7e5..f188a907c5 100644
--- a/source/renderer/HWLightingModelRenderer.h
+++ b/source/renderer/HWLightingModelRenderer.h
@@ -19,22 +19,28 @@ struct HWLightingModelRendererInternals;
/**
* Class HWLightingModelRenderer: Render animated models using vertex
* shaders for lighting.
- *
+ *
* @note You should verify hardware capabilities using IsAvailable
* before creating this model renderer.
*/
class HWLightingModelRenderer : public ModelVertexRenderer
{
public:
- HWLightingModelRenderer();
+ /**
+ * HWLightingModelRenderer: Constructor.
+ *
+ * @param colorIsDiffuseOnly if true, the primary color sent to the fragment stage
+ * contains only the diffuse term, and not the ambient
+ */
+ HWLightingModelRenderer(bool colorIsDiffuseOnly);
~HWLightingModelRenderer();
-
+
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
-
- void BeginPass(uint streamflags);
+
+ void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
@@ -42,10 +48,10 @@ public:
/**
* IsAvailable: Determines whether this model renderer can be used
* given the OpenGL implementation specific limits.
- *
+ *
* @note Do not attempt to construct a HWLightingModelRenderer object
* when IsAvailable returns false.
- *
+ *
* @return true if the OpenGL implementation can support this
* model renderer.
*/
diff --git a/source/renderer/InstancingModelRenderer.cpp b/source/renderer/InstancingModelRenderer.cpp
index 8392f6087c..63737b4caa 100644
--- a/source/renderer/InstancingModelRenderer.cpp
+++ b/source/renderer/InstancingModelRenderer.cpp
@@ -96,14 +96,21 @@ struct InstancingModelRendererInternals
/// Previously prepared modeldef
IModelDef* imodeldef;
+
+ /// If true, primary color will only contain the diffuse term
+ bool colorIsDiffuseOnly;
+
+ /// After BeginPass, this points to the instancing matrix interface
+ VS_Instancing* instancingConfig;
};
// Construction and Destruction
-InstancingModelRenderer::InstancingModelRenderer()
+InstancingModelRenderer::InstancingModelRenderer(bool colorIsDiffuseOnly)
{
m = new InstancingModelRendererInternals;
m->imodeldef = 0;
+ m->colorIsDiffuseOnly = colorIsDiffuseOnly;
}
InstancingModelRenderer::~InstancingModelRenderer()
@@ -150,29 +157,58 @@ void InstancingModelRenderer::DestroyModelData(CModel* UNUSED(model), void* UNUS
// Setup one rendering pass.
-void InstancingModelRenderer::BeginPass(uint streamflags)
+void InstancingModelRenderer::BeginPass(uint streamflags, const CMatrix3D* texturematrix)
{
+ debug_assert(streamflags == (streamflags & (STREAM_POS|STREAM_UV0|STREAM_COLOR|STREAM_TEXGENTOUV1)));
+
+ RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
+
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (streamflags & STREAM_COLOR)
{
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
- int idx;
+ VS_GlobalLight* lightConfig;
- ogl_program_use(g_Renderer.m_VertexShader->m_InstancingLight);
- idx = g_Renderer.m_VertexShader->m_InstancingLight_Ambient;
- pglUniform3fvARB(idx, 1, &lightEnv.m_UnitsAmbientColor.X);
- idx = g_Renderer.m_VertexShader->m_InstancingLight_SunDir;
- pglUniform3fvARB(idx, 1, &lightEnv.GetSunDir().X);
- idx = g_Renderer.m_VertexShader->m_InstancingLight_SunColor;
- pglUniform3fvARB(idx, 1, &lightEnv.m_SunColor.X);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ ogl_program_use(rpvs->m_InstancingLightP);
+ lightConfig = &rpvs->m_InstancingLightP_Light;
+ m->instancingConfig = &rpvs->m_InstancingLightP_Instancing;
+
+ rpvs->m_InstancingLightP_PosToUV1.SetMatrix(*texturematrix);
+ }
+ else
+ {
+ ogl_program_use(rpvs->m_InstancingLight);
+ lightConfig = &rpvs->m_InstancingLight_Light;
+ m->instancingConfig = &rpvs->m_InstancingLight_Instancing;
+ }
+
+ if (m->colorIsDiffuseOnly)
+ lightConfig->SetAmbient(RGBColor(0,0,0));
+ else
+ lightConfig->SetAmbient(lightEnv.m_UnitsAmbientColor);
+ lightConfig->SetSunDir(lightEnv.GetSunDir());
+ lightConfig->SetSunColor(lightEnv.m_SunColor);
glEnableClientState(GL_NORMAL_ARRAY);
}
else
{
- ogl_program_use(g_Renderer.m_VertexShader->m_Instancing);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ {
+ ogl_program_use(rpvs->m_InstancingP);
+ m->instancingConfig = &rpvs->m_InstancingP_Instancing;
+
+ rpvs->m_InstancingP_PosToUV1.SetMatrix(*texturematrix);
+ }
+ else
+ {
+ ogl_program_use(rpvs->m_Instancing);
+ m->instancingConfig = &rpvs->m_Instancing_Instancing;
+ }
}
}
@@ -214,23 +250,14 @@ void InstancingModelRenderer::RenderModel(uint streamflags, CModel* model, void*
{
CModelDefPtr mdldef = model->GetModelDef();
const CMatrix3D& mat = model->GetTransform();
- RenderPathVertexShader* rpvs = g_Renderer.m_VertexShader;
if (streamflags & STREAM_COLOR)
{
CColor sc = model->GetShadingColor();
glColor3f(sc.r, sc.g, sc.b);
+ }
- pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing1, mat._11, mat._12, mat._13, mat._14);
- pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing2, mat._21, mat._22, mat._23, mat._24);
- pglVertexAttrib4fARB(rpvs->m_InstancingLight_Instancing3, mat._31, mat._32, mat._33, mat._34);
- }
- else
- {
- pglVertexAttrib4fARB(rpvs->m_Instancing_Instancing1, mat._11, mat._12, mat._13, mat._14);
- pglVertexAttrib4fARB(rpvs->m_Instancing_Instancing2, mat._21, mat._22, mat._23, mat._24);
- pglVertexAttrib4fARB(rpvs->m_Instancing_Instancing3, mat._31, mat._32, mat._33, mat._34);
- }
+ m->instancingConfig->SetMatrix(mat);
// render the lot
size_t numFaces = mdldef->GetNumFaces();
diff --git a/source/renderer/InstancingModelRenderer.h b/source/renderer/InstancingModelRenderer.h
index 00fd432dec..352dde075a 100644
--- a/source/renderer/InstancingModelRenderer.h
+++ b/source/renderer/InstancingModelRenderer.h
@@ -19,33 +19,39 @@ struct InstancingModelRendererInternals;
/**
* Class InstancingModelRenderer: Render non-animated (but potentially
* moving models) using vertex shaders and minimal state changes.
- *
+ *
* @note You should verify hardware capabilities using IsAvailable
* before creating this model renderer.
*/
class InstancingModelRenderer : public ModelVertexRenderer
{
public:
- InstancingModelRenderer();
+ /**
+ * InstancingModelRenderer: Constructor.
+ *
+ * @param colorIsDiffuseOnly if true, the primary color sent to the fragment stage
+ * contains only the diffuse term, and not the ambient
+ */
+ InstancingModelRenderer(bool colorIsDiffuseOnly);
~InstancingModelRenderer();
-
+
// Implementations
void* CreateModelData(CModel* model);
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
-
- void BeginPass(uint streamflags);
+
+ void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
-
+
/**
* IsAvailable: Determines whether this model renderer can be used
* given the OpenGL implementation specific limits.
- *
+ *
* @note Do not attempt to construct a InstancingModelRenderer object
* when IsAvailable returns false.
- *
+ *
* @return true if the OpenGL implementation can support this
* model renderer.
*/
diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp
index 8a9cb3e9ec..b92fba92b5 100644
--- a/source/renderer/ModelRenderer.cpp
+++ b/source/renderer/ModelRenderer.cpp
@@ -149,7 +149,8 @@ void ModelRenderer::BuildPositionAndNormals(
void ModelRenderer::BuildColor4ub(
CModel* model,
VertexArrayIterator Normal,
- VertexArrayIterator Color)
+ VertexArrayIterator Color,
+ bool onlyDiffuse)
{
PROFILE( "lighting vertices" );
@@ -159,13 +160,27 @@ void ModelRenderer::BuildColor4ub(
CColor shadingColor = model->GetShadingColor();
RGBColor tempcolor;
- for (uint j=0; jBeginPass(pass);
+ const CMatrix3D* texturematrix = 0;
- m->vertexRenderer->BeginPass(streamflags);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ texturematrix = modifier->GetTexGenMatrix(pass);
+
+ m->vertexRenderer->BeginPass(streamflags, texturematrix);
m->RenderAllModels(modifier, flags, pass, streamflags);
diff --git a/source/renderer/ModelRenderer.h b/source/renderer/ModelRenderer.h
index 878a5109a9..0290868a75 100644
--- a/source/renderer/ModelRenderer.h
+++ b/source/renderer/ModelRenderer.h
@@ -23,6 +23,9 @@
class RenderModifier;
typedef boost::shared_ptr RenderModifierPtr;
+class LitRenderModifier;
+typedef boost::shared_ptr LitRenderModifierPtr;
+
class ModelVertexRenderer;
typedef boost::shared_ptr ModelVertexRendererPtr;
@@ -199,11 +202,14 @@ public:
* @param Color Points to the array that will receive the lit vertex color.
* The array behind the iterator must large enough to hold
* model->GetModelDef()->GetNumVertices() vertices.
+ * @param onlyDiffuse if true, color will only contain the diffuse term (instead
+ * of both ambient and diffuse)
*/
static void BuildColor4ub(
CModel* model,
VertexArrayIterator Normal,
- VertexArrayIterator Color);
+ VertexArrayIterator Color,
+ bool onlyDiffuse);
/**
* BuildUV: Copy UV coordinates into the given vertex array.
diff --git a/source/renderer/ModelVertexRenderer.h b/source/renderer/ModelVertexRenderer.h
index ab400d105b..9b48caf8c6 100644
--- a/source/renderer/ModelVertexRenderer.h
+++ b/source/renderer/ModelVertexRenderer.h
@@ -20,7 +20,7 @@ class CModel;
* Class ModelVertexRenderer: Normal ModelRenderer implementations delegate
* vertex array management and vertex transformation to an implementation of
* ModelVertexRenderer.
- *
+ *
* ModelVertexRenderer implementations should be designed so that one
* instance of the implementation can be used with more than one ModelRenderer
* simultaneously.
@@ -29,14 +29,14 @@ class ModelVertexRenderer
{
public:
virtual ~ModelVertexRenderer() { }
-
-
+
+
/**
* CreateModelData: Create internal data for one model.
*
* ModelRenderer implementations must call this once for every
* model that will later be rendered.
- *
+ *
* ModelVertexRenderer implementations should use this function to
* create per-CModel and per-CModelDef data like vertex arrays.
*
@@ -58,11 +58,11 @@ public:
* value of updateflags will be zero.
* This implies that this function will also be called at least once
* between a call to CreateModelData and a call to RenderModel.
- *
+ *
* ModelVertexRenderer implementations should use this function to
* perform software vertex transforms and potentially other per-frame
* calculations.
- *
+ *
* @param model The model.
* @param data Private data as returned by CreateModelData.
* @param updateflags Flags indicating which data has changed during
@@ -71,7 +71,7 @@ public:
*/
virtual void UpdateModelData(CModel* model, void* data, u32 updateflags) = 0;
-
+
/**
* DestroyModelData: Release all per-model data that has been allocated
* by CreateModelData or UpdateModelData.
@@ -80,7 +80,7 @@ public:
* called exactly once for every call to CreateModelData. This can be
* achieved by deriving from CModelRData and calling DestroyModelData
* in the derived class' destructor.
- *
+ *
* ModelVertexRenderer implementations need not track the CModel
* instances for which per-model data has been created.
*
@@ -89,7 +89,7 @@ public:
*/
virtual void DestroyModelData(CModel* model, void* data) = 0;
-
+
/**
* BeginPass: Setup global OpenGL state for this ModelVertexRenderer.
*
@@ -103,12 +103,15 @@ public:
*
* Recursive calls to BeginPass are not allowed, and every BeginPass
* is matched by a corresponding call to EndPass.
- *
+ *
* @param streamflags Vertex streams required by the fragment stage.
+ * @param texturematrix if texgen is requested in streamflags, this points to the
+ * texture matrix that must be used to transform vertex positions into texture
+ * coordinates
*/
- virtual void BeginPass(uint streamflags) = 0;
+ virtual void BeginPass(uint streamflags, const CMatrix3D* texturematrix) = 0;
+
-
/**
* EndPass: Cleanup OpenGL state set up by BeginPass.
*
@@ -121,11 +124,11 @@ public:
*/
virtual void EndPass(uint streamflags) = 0;
-
+
/**
* PrepareModelDef: Setup OpenGL state for rendering of models that
* use the given CModelDef object as base.
- *
+ *
* ModelRenderer implementations must call this function before
* rendering a sequence of models based on the given CModelDef.
* When a ModelRenderer switches back and forth between CModelDefs,
@@ -141,7 +144,7 @@ public:
/**
* RenderModel: Invoke the rendering commands for the given model.
- *
+ *
* ModelRenderer implementations must call this function to perform
* the actual rendering.
*
diff --git a/source/renderer/PlayerRenderer.cpp b/source/renderer/PlayerRenderer.cpp
index e6bdc82665..939c4292c4 100644
--- a/source/renderer/PlayerRenderer.cpp
+++ b/source/renderer/PlayerRenderer.cpp
@@ -13,6 +13,9 @@
#include "renderer/Renderer.h"
#include "renderer/PlayerRenderer.h"
+#include "renderer/ShadowMap.h"
+
+#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "ps/CLogger.h"
@@ -40,14 +43,14 @@ bool FastPlayerColorRender::IsAvailable()
u32 FastPlayerColorRender::BeginPass(uint pass)
{
debug_assert(pass == 0);
-
- // Nice player color uses a single pass with three texture environments
+
+ // Fast player color uses a single pass with three texture environments
// Note: This uses ARB_texture_env_crossbar (which is checked in GameSetup)
//
// We calculate: Result = Color*Texture*(PlayerColor*(1-Texture.a) + 1.0*Texture.a)
// Algebra gives us:
// Result = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture*Color
-
+
// TexEnv #0
pglActiveTextureARB(GL_TEXTURE0);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@@ -56,7 +59,7 @@ u32 FastPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
-
+
// Don't care about alpha; set it to something harmless
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
@@ -76,7 +79,7 @@ u32 FastPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
-
+
// TexEnv #2
pglActiveTextureARB(GL_TEXTURE0+2);
glEnable(GL_TEXTURE_2D);
@@ -91,7 +94,7 @@ u32 FastPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
-
+
pglActiveTextureARB(GL_TEXTURE0);
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
@@ -106,7 +109,7 @@ bool FastPlayerColorRender::EndPass(uint UNUSED(pass))
pglActiveTextureARB(GL_TEXTURE2);
glDisable(GL_TEXTURE_2D);
pglActiveTextureARB(GL_TEXTURE0);
-
+
return true;
}
@@ -143,7 +146,7 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
{
// We calculate: Result = (Color*Texture)*Texture.a + (Color*Texture*PlayerColor)*(1-Texture.a)
// Modulation is done via texture environments, the final interpolation is done via blending
-
+
if (pass == 0)
{
// TexEnv #0
@@ -154,12 +157,12 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
-
+
// Don't care about alpha; set it to something harmless
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
-
+
// Render it!
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
}
@@ -172,12 +175,12 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
-
+
// Alpha = Opacity of non-player colored layer
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
-
+
// TexEnv #1
pglActiveTextureARB(GL_TEXTURE1);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
@@ -186,20 +189,20 @@ u32 SlowPlayerColorRender::BeginPass(uint pass)
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
-
+
// Pass alpha unchanged
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
pglActiveTextureARB(GL_TEXTURE0);
-
+
// Setup blending
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_LESS, 1.0);
glDepthMask(0);
-
+
// Render it!
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
}
@@ -217,7 +220,7 @@ bool SlowPlayerColorRender::EndPass(uint pass)
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glDepthMask(1);
-
+
return true;
}
@@ -242,3 +245,160 @@ void SlowPlayerColorRender::PrepareModel(uint pass, CModel* model)
}
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// LitPlayerColorRender
+
+LitPlayerColorRender::LitPlayerColorRender()
+{
+}
+
+LitPlayerColorRender::~LitPlayerColorRender()
+{
+}
+
+u32 LitPlayerColorRender::BeginPass(uint pass)
+{
+ debug_assert(GetShadowMap() && GetShadowMap()->GetUseDepthTexture());
+
+ if (pass == 0)
+ {
+ // First pass: Lay down the material color
+ // We calculate:
+ // Material = Texture*(PlayerColor*(1.0-Texture.a) + 1.0*Texture.a))
+ // = (1 - ((1 - PlayerColor) * (1 - Texture.a)))*Texture
+
+ // Incoming Color holds the player color
+ // Texture 0 holds the model's texture
+
+ // TexEnv #0
+ pglActiveTextureARB(GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
+
+ // Don't care about alpha; set it to something harmless
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ // TexEnv #1
+ pglActiveTextureARB(GL_TEXTURE0+1);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+
+ // Don't care about alpha; set it to something harmless
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+
+ return STREAM_POS|STREAM_UV0;
+ }
+ else
+ {
+ // Second pass: Multiply with lighting
+ //
+ // We calculate:
+ // Lighting = Ambient + Diffuse * Shadow
+ // and modulate with frame buffer contents
+ //
+ // Incoming color is diffuse
+ // Texture 1 is the shadow map
+
+ // TexEnv #0
+ pglActiveTextureARB(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ // TexEnv #1
+ pglActiveTextureARB(GL_TEXTURE1);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &GetLightEnv()->m_UnitsAmbientColor.X);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+
+ // Blending, Z settings
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_DST_COLOR, GL_ZERO);
+
+ glDepthMask(0);
+
+ return STREAM_POS|STREAM_COLOR|STREAM_TEXGENTOUV1;
+ }
+}
+
+
+bool LitPlayerColorRender::EndPass(uint pass)
+{
+ if (pass == 0)
+ {
+ return false;
+ }
+ else
+ {
+ // Restore state
+ pglActiveTextureARB(GL_TEXTURE1);
+ glDisable(GL_TEXTURE_2D);
+ pglActiveTextureARB(GL_TEXTURE0);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1);
+
+ return true;
+ }
+}
+
+const CMatrix3D* LitPlayerColorRender::GetTexGenMatrix(uint UNUSED(pass))
+{
+ return &GetShadowMap()->GetTextureMatrix();
+}
+
+void LitPlayerColorRender::PrepareTexture(uint pass, CTexture* texture)
+{
+ if (pass == 0)
+ g_Renderer.SetTexture(0, texture);
+}
+
+void LitPlayerColorRender::PrepareModel(uint pass, CModel* model)
+{
+ if (pass == 0)
+ {
+ // Get the player color
+ SMaterialColor colour = model->GetMaterial().GetPlayerColor();
+
+ // Send the player color
+ glColor3f(colour.r, colour.g, colour.b);
+ }
+}
+
+
diff --git a/source/renderer/PlayerRenderer.h b/source/renderer/PlayerRenderer.h
index a31d117bfc..cf9c72b46d 100644
--- a/source/renderer/PlayerRenderer.h
+++ b/source/renderer/PlayerRenderer.h
@@ -32,14 +32,14 @@ public:
bool EndPass(uint pass);
void PrepareTexture(uint pass, CTexture* texture);
void PrepareModel(uint pass, CModel* model);
-
+
/**
* IsAvailable: Determines whether this RenderModifier can be used
* given the OpenGL implementation specific limits.
- *
+ *
* @note Do not attempt to construct a FastPlayerColorRender object
* when IsAvailable returns false.
- *
+ *
* @return true if the OpenGL implementation can support this
* RenderModifier.
*/
@@ -50,7 +50,7 @@ public:
/**
* Class SlowPlayerColorRender: Render models fully textured and lit
* plus player color using multi-pass.
- *
+ *
* It has the same visual result as FastPlayerColorRender (except for
* potential precision issues due to the multi-passing).
*/
@@ -67,4 +67,27 @@ public:
void PrepareModel(uint pass, CModel* model);
};
+
+/**
+ * Class LitPlayerColorRender: Render models fully textured and lit including shadows
+ * and player color.
+ *
+ * @note Only use a LitPlayerColorRenderer instance when depth texture based shadows
+ * are supported by the OpenGL implementation (as verified by CRenderer::m_Caps::m_DepthTextureShadows).
+ */
+class LitPlayerColorRender : public LitRenderModifier
+{
+public:
+ LitPlayerColorRender();
+ ~LitPlayerColorRender();
+
+ // Implementation
+ u32 BeginPass(uint pass);
+ bool EndPass(uint pass);
+ const CMatrix3D* GetTexGenMatrix(uint pass);
+ void PrepareTexture(uint pass, CTexture* texture);
+ void PrepareModel(uint pass, CModel* model);
+};
+
+
#endif
diff --git a/source/renderer/RenderModifiers.cpp b/source/renderer/RenderModifiers.cpp
index 55d7f07b3b..344a7ad848 100644
--- a/source/renderer/RenderModifiers.cpp
+++ b/source/renderer/RenderModifiers.cpp
@@ -14,13 +14,17 @@
#include "Vector3D.h"
#include "Vector4D.h"
+#include "maths/Matrix3D.h"
+
#include "ps/CLogger.h"
#include "graphics/Color.h"
+#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "renderer/RenderModifiers.h"
#include "renderer/Renderer.h"
+#include "renderer/ShadowMap.h"
#define LOG_CATEGORY "graphics"
@@ -29,11 +33,42 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// RenderModifier implementation
+const CMatrix3D* RenderModifier::GetTexGenMatrix(uint UNUSED(pass))
+{
+ debug_warn("GetTexGenMatrix not implemented by a derived RenderModifier");
+ return 0;
+}
+
void RenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
{
}
+///////////////////////////////////////////////////////////////////////////////////////////////
+// LitRenderModifier implementation
+
+LitRenderModifier::LitRenderModifier()
+ : m_Shadow(0), m_LightEnv(0)
+{
+}
+
+LitRenderModifier::~LitRenderModifier()
+{
+}
+
+// Set the shadow map for subsequent rendering
+void LitRenderModifier::SetShadowMap(const ShadowMap* shadow)
+{
+ m_Shadow = shadow;
+}
+
+// Set the light environment for subsequent rendering
+void LitRenderModifier::SetLightEnv(const CLightEnv* lightenv)
+{
+ m_LightEnv = lightenv;
+}
+
+
///////////////////////////////////////////////////////////////////////////////////////////////
// PlainRenderModifier implementation
@@ -69,7 +104,7 @@ u32 PlainRenderModifier::BeginPass(uint pass)
float color[] = { 1.0, 1.0, 1.0, 1.0 };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
-
+
return STREAM_POS|STREAM_COLOR|STREAM_UV0;
}
@@ -77,7 +112,7 @@ bool PlainRenderModifier::EndPass(uint UNUSED(pass))
{
// We didn't modify blend state or higher texenvs, so we don't have
// to reset OpenGL state here.
-
+
return true;
}
@@ -86,10 +121,90 @@ void PlainRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
g_Renderer.SetTexture(0, texture);
}
-void PlainRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// PlainLitRenderModifier implementation
+
+PlainLitRenderModifier::PlainLitRenderModifier()
{
}
+PlainLitRenderModifier::~PlainLitRenderModifier()
+{
+}
+
+u32 PlainLitRenderModifier::BeginPass(uint pass)
+{
+ debug_assert(pass == 0);
+ debug_assert(GetShadowMap() && GetShadowMap()->GetUseDepthTexture());
+
+ // Ambient + Diffuse * Shadow
+ pglActiveTextureARB(GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ pglActiveTextureARB(GL_TEXTURE1);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &GetLightEnv()->m_UnitsAmbientColor.X);
+
+ // Incoming color is ambient + diffuse light
+ pglActiveTextureARB(GL_TEXTURE2);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+
+ return STREAM_POS|STREAM_COLOR|STREAM_UV0|STREAM_TEXGENTOUV1;
+}
+
+const CMatrix3D* PlainLitRenderModifier::GetTexGenMatrix(uint UNUSED(pass))
+{
+ return &GetShadowMap()->GetTextureMatrix();
+}
+
+bool PlainLitRenderModifier::EndPass(uint UNUSED(pass))
+{
+ g_Renderer.BindTexture(1, 0);
+ g_Renderer.BindTexture(2, 0);
+ pglActiveTextureARB(GL_TEXTURE0);
+ pglClientActiveTextureARB(GL_TEXTURE0);
+
+ return true;
+}
+
+void PlainLitRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
+{
+ g_Renderer.SetTexture(0, texture);
+}
+
+
///////////////////////////////////////////////////////////////////////////////////////////////
// WireframeRenderModifier implementation
@@ -106,7 +221,7 @@ WireframeRenderModifier::~WireframeRenderModifier()
u32 WireframeRenderModifier::BeginPass(uint pass)
{
debug_assert(pass == 0);
-
+
// first switch on wireframe
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -161,7 +276,7 @@ SolidColorRenderModifier::~SolidColorRenderModifier()
u32 SolidColorRenderModifier::BeginPass(uint UNUSED(pass))
{
g_Renderer.SetTexture(0,0);
-
+
return STREAM_POS;
}
diff --git a/source/renderer/RenderModifiers.h b/source/renderer/RenderModifiers.h
index 799a27aea4..ce7e60b30b 100644
--- a/source/renderer/RenderModifiers.h
+++ b/source/renderer/RenderModifiers.h
@@ -16,9 +16,11 @@
#include "ModelRenderer.h"
+class CLightEnv;
+class CMatrix3D;
class CModel;
class CTexture;
-
+class ShadowMap;
/**
* Class RenderModifier: Some ModelRenderer implementations provide vertex
@@ -45,6 +47,19 @@ public:
*/
virtual u32 BeginPass(uint pass) = 0;
+ /**
+ * GetTexGenMatrix: If BeginPass returns STREAM_TEXGENTOUVx, the caller must
+ * call this function to query the texture matrix that will be used to transform
+ * vertex positions into texture coordinates.
+ *
+ * Default implementation raises a runtime error.
+ *
+ * @param pass the current pass number (pass == 0 is the first pass)
+ *
+ * @return a pointer to the texture matrix for the given pass
+ */
+ virtual const CMatrix3D* GetTexGenMatrix(uint pass);
+
/**
* EndPass: Cleanup OpenGL state after the given pass. This function
* may indicate that additional passes are needed.
@@ -82,6 +97,45 @@ public:
};
+/**
+ * Class LitRenderModifier: Abstract base class for RenderModifiers that apply
+ * a shadow map.
+ * LitRenderModifiers expect the diffuse brightness in the primary color (instead of ambient + diffuse).
+ */
+class LitRenderModifier : public RenderModifier
+{
+public:
+ LitRenderModifier();
+ ~LitRenderModifier();
+
+ /**
+ * SetShadowMap: Set the shadow map that will be used for rendering.
+ * Must be called by the user of the RenderModifier.
+ *
+ * The shadow map must be non-null and use depth texturing, or subsequent rendering
+ * using this RenderModifier will fail.
+ *
+ * @param shadow the shadow map
+ */
+ void SetShadowMap(const ShadowMap* shadow);
+
+ /**
+ * SetLightEnv: Set the light environment that will be used for rendering.
+ * Must be called by the user of the RenderModifier.
+ *
+ * @param lightenv the light environment (must be non-null)
+ */
+ void SetLightEnv(const CLightEnv* lightenv);
+
+ const ShadowMap* GetShadowMap() const { return m_Shadow; }
+ const CLightEnv* GetLightEnv() const { return m_LightEnv; }
+
+private:
+ const ShadowMap* m_Shadow;
+ const CLightEnv* m_LightEnv;
+};
+
+
/**
* Class RenderModifierRenderer: Interface to a model renderer that can render
* its models via a RenderModifier that sets up fragment stages.
@@ -108,9 +162,28 @@ public:
u32 BeginPass(uint pass);
bool EndPass(uint pass);
void PrepareTexture(uint pass, CTexture* texture);
- void PrepareModel(uint pass, CModel* model);
};
+
+/**
+ * Class PlainLitRenderModifier: Use an opaque color texture for a lit object that is shadowed
+ * using a depth texture.
+ * Expects the diffuse brightness in the primary color.
+ */
+class PlainLitRenderModifier : public LitRenderModifier
+{
+public:
+ PlainLitRenderModifier();
+ ~PlainLitRenderModifier();
+
+ // Implementation
+ u32 BeginPass(uint pass);
+ const CMatrix3D* GetTexGenMatrix(uint pass);
+ bool EndPass(uint pass);
+ void PrepareTexture(uint pass, CTexture* texture);
+};
+
+
/**
* Class WireframeRenderModifier: RenderModifier that renders wireframe models.
*/
diff --git a/source/renderer/RenderPathVertexShader.cpp b/source/renderer/RenderPathVertexShader.cpp
index a6ab90a957..ec04e99be8 100644
--- a/source/renderer/RenderPathVertexShader.cpp
+++ b/source/renderer/RenderPathVertexShader.cpp
@@ -8,32 +8,44 @@
#define LOG_CATEGORY "graphics"
+void VS_GlobalLight::Init(Handle shader)
+{
+ m_Ambient = ogl_program_get_uniform_location(shader, "ambient");
+ m_SunDir = ogl_program_get_uniform_location(shader, "sunDir");
+ m_SunColor = ogl_program_get_uniform_location(shader, "sunColor");
+}
+
+void VS_Instancing::Init(Handle shader)
+{
+ m_Instancing1 = ogl_program_get_attrib_location(shader, "Instancing1");
+ m_Instancing2 = ogl_program_get_attrib_location(shader, "Instancing2");
+ m_Instancing3 = ogl_program_get_attrib_location(shader, "Instancing3");
+}
+
+void VS_PosToUV1::Init(Handle shader)
+{
+ m_TextureMatrix1 = ogl_program_get_uniform_location(shader, "TextureMatrix1");
+ debug_assert(m_TextureMatrix1 >= 0);
+ m_TextureMatrix2 = ogl_program_get_uniform_location(shader, "TextureMatrix2");
+ debug_assert(m_TextureMatrix2 >= 0);
+ m_TextureMatrix3 = ogl_program_get_uniform_location(shader, "TextureMatrix3");
+ debug_assert(m_TextureMatrix3 >= 0);
+}
RenderPathVertexShader::RenderPathVertexShader()
{
m_ModelLight = 0;
- m_ModelLight_Ambient = -1;
- m_ModelLight_SunDir = -1;
- m_ModelLight_SunColor = -1;
-
+ m_ModelLightP = 0;
m_InstancingLight = 0;
- m_InstancingLight_Ambient = -1;
- m_InstancingLight_SunDir = -1;
- m_InstancingLight_SunColor = -1;
- m_InstancingLight_Instancing1 = -1;
- m_InstancingLight_Instancing2 = -1;
- m_InstancingLight_Instancing3 = -1;
-
m_Instancing = 0;
- m_Instancing_Instancing1 = -1;
- m_Instancing_Instancing2 = -1;
- m_Instancing_Instancing3 = -1;
}
RenderPathVertexShader::~RenderPathVertexShader()
{
if (m_ModelLight)
ogl_program_free(m_ModelLight);
+ if (m_ModelLightP)
+ ogl_program_free(m_ModelLightP);
if (m_InstancingLight)
ogl_program_free(m_InstancingLight);
if (m_Instancing)
@@ -55,6 +67,13 @@ bool RenderPathVertexShader::Init()
return false;
}
+ m_ModelLightP = ogl_program_load("shaders/model_lightp.xml");
+ if (m_ModelLightP < 0)
+ {
+ LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/model_lightp.xml: %i\n", (int)m_ModelLightP);
+ return false;
+ }
+
m_InstancingLight = ogl_program_load("shaders/instancing_light.xml");
if (m_InstancingLight < 0)
{
@@ -62,6 +81,13 @@ bool RenderPathVertexShader::Init()
return false;
}
+ m_InstancingLightP = ogl_program_load("shaders/instancing_lightp.xml");
+ if (m_InstancingLightP < 0)
+ {
+ LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/instancing_lightp.xml: %i\n", (int)m_InstancingLightP);
+ return false;
+ }
+
m_Instancing = ogl_program_load("shaders/instancing.xml");
if (m_Instancing < 0)
{
@@ -69,6 +95,13 @@ bool RenderPathVertexShader::Init()
return false;
}
+ m_InstancingP = ogl_program_load("shaders/instancingp.xml");
+ if (m_InstancingP < 0)
+ {
+ LOG(WARNING, LOG_CATEGORY, "Failed to load shaders/instancingp.xml: %i\n", (int)m_InstancingP);
+ return false;
+ }
+
return true;
}
@@ -77,27 +110,20 @@ bool RenderPathVertexShader::Init()
// the uniform locations might have changed under us.
void RenderPathVertexShader::BeginFrame()
{
- m_ModelLight_Ambient = ogl_program_get_uniform_location(m_ModelLight, "ambient");
- m_ModelLight_SunDir = ogl_program_get_uniform_location(m_ModelLight, "sunDir");
- m_ModelLight_SunColor = ogl_program_get_uniform_location(m_ModelLight, "sunColor");
+ m_ModelLight_Light.Init(m_ModelLight);
- m_InstancingLight_Ambient = ogl_program_get_uniform_location(
- m_InstancingLight, "ambient");
- m_InstancingLight_SunDir = ogl_program_get_uniform_location(
- m_InstancingLight, "sunDir");
- m_InstancingLight_SunColor = ogl_program_get_uniform_location(
- m_InstancingLight, "sunColor");
- m_InstancingLight_Instancing1 = ogl_program_get_attrib_location(
- m_InstancingLight, "Instancing1");
- m_InstancingLight_Instancing2 = ogl_program_get_attrib_location(
- m_InstancingLight, "Instancing2");
- m_InstancingLight_Instancing3 = ogl_program_get_attrib_location(
- m_InstancingLight, "Instancing3");
+ m_ModelLightP_Light.Init(m_ModelLightP);
+ m_ModelLightP_PosToUV1.Init(m_ModelLightP);
- m_Instancing_Instancing1 = ogl_program_get_attrib_location(
- m_Instancing, "Instancing1");
- m_Instancing_Instancing2 = ogl_program_get_attrib_location(
- m_Instancing, "Instancing2");
- m_Instancing_Instancing3 = ogl_program_get_attrib_location(
- m_Instancing, "Instancing3");
+ m_InstancingLight_Light.Init(m_InstancingLight);
+ m_InstancingLight_Instancing.Init(m_InstancingLight);
+
+ m_InstancingLightP_Light.Init(m_InstancingLightP);
+ m_InstancingLightP_Instancing.Init(m_InstancingLightP);
+ m_InstancingLightP_PosToUV1.Init(m_InstancingLightP);
+
+ m_Instancing_Instancing.Init(m_Instancing);
+
+ m_InstancingP_Instancing.Init(m_InstancingP);
+ m_InstancingP_PosToUV1.Init(m_InstancingP);
}
diff --git a/source/renderer/RenderPathVertexShader.h b/source/renderer/RenderPathVertexShader.h
index 8662507997..3a068ab3de 100644
--- a/source/renderer/RenderPathVertexShader.h
+++ b/source/renderer/RenderPathVertexShader.h
@@ -1,6 +1,81 @@
#ifndef __RENDERPATHVERTEXSHADER_H__
#define __RENDERPATHVERTEXSHADER_H__
+#include "graphics/LightEnv.h"
+
+// Interface for globallight.vs
+struct VS_GlobalLight
+{
+public:
+ void Init(Handle shader);
+
+ void SetFromLightEnv(const CLightEnv& lightenv, bool units) const
+ {
+ SetAmbient(units ? lightenv.m_UnitsAmbientColor : lightenv.m_TerrainAmbientColor);
+ SetSunDir(lightenv.GetSunDir());
+ SetSunColor(lightenv.m_SunColor);
+ }
+
+ void SetAmbient(const RGBColor& color) const
+ {
+ pglUniform3fvARB(m_Ambient, 1, &color.X);
+ }
+
+ void SetSunDir(const CVector3D& sundir) const
+ {
+ pglUniform3fvARB(m_SunDir, 1, &sundir.X);
+ }
+
+ void SetSunColor(const RGBColor& color) const
+ {
+ pglUniform3fvARB(m_SunColor, 1, &color.X);
+ }
+
+private:
+ GLint m_Ambient;
+ GLint m_SunDir;
+ GLint m_SunColor;
+};
+
+// Interface for instancing_base.vs
+struct VS_Instancing
+{
+public:
+ void Init(Handle shader);
+
+ void SetMatrix(const CMatrix3D& mat) const
+ {
+ pglVertexAttrib4fARB(m_Instancing1, mat._11, mat._12, mat._13, mat._14);
+ pglVertexAttrib4fARB(m_Instancing2, mat._21, mat._22, mat._23, mat._24);
+ pglVertexAttrib4fARB(m_Instancing3, mat._31, mat._32, mat._33, mat._34);
+ }
+
+private:
+ GLint m_Instancing1;
+ GLint m_Instancing2;
+ GLint m_Instancing3;
+};
+
+
+// Interface for postouv1.vs
+struct VS_PosToUV1
+{
+public:
+ void Init(Handle shader);
+
+ void SetMatrix(const CMatrix3D& mat) const
+ {
+ pglUniform4fARB(m_TextureMatrix1, mat._11, mat._12, mat._13, mat._14);
+ pglUniform4fARB(m_TextureMatrix2, mat._21, mat._22, mat._23, mat._24);
+ pglUniform4fARB(m_TextureMatrix3, mat._31, mat._32, mat._33, mat._34);
+ }
+
+private:
+ GLint m_TextureMatrix1;
+ GLint m_TextureMatrix2;
+ GLint m_TextureMatrix3;
+};
+
class RenderPathVertexShader
{
public:
@@ -15,22 +90,27 @@ public:
public:
Handle m_ModelLight;
- GLint m_ModelLight_Ambient;
- GLint m_ModelLight_SunDir;
- GLint m_ModelLight_SunColor;
+ VS_GlobalLight m_ModelLight_Light;
+
+ Handle m_ModelLightP;
+ VS_GlobalLight m_ModelLightP_Light;
+ VS_PosToUV1 m_ModelLightP_PosToUV1;
Handle m_InstancingLight;
- GLint m_InstancingLight_Ambient;
- GLint m_InstancingLight_SunDir;
- GLint m_InstancingLight_SunColor;
- GLint m_InstancingLight_Instancing1; // matrix rows
- GLint m_InstancingLight_Instancing2;
- GLint m_InstancingLight_Instancing3;
+ VS_GlobalLight m_InstancingLight_Light;
+ VS_Instancing m_InstancingLight_Instancing;
+
+ Handle m_InstancingLightP;
+ VS_GlobalLight m_InstancingLightP_Light;
+ VS_Instancing m_InstancingLightP_Instancing;
+ VS_PosToUV1 m_InstancingLightP_PosToUV1;
Handle m_Instancing;
- GLint m_Instancing_Instancing1; // matrix rows
- GLint m_Instancing_Instancing2;
- GLint m_Instancing_Instancing3;
+ VS_Instancing m_Instancing_Instancing;
+
+ Handle m_InstancingP;
+ VS_Instancing m_InstancingP_Instancing;
+ VS_PosToUV1 m_InstancingP_PosToUV1;
};
#endif // __RENDERPATHVERTEXSHADER_H__
diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp
index 9ae1b70455..eb4a8553c1 100755
--- a/source/renderer/Renderer.cpp
+++ b/source/renderer/Renderer.cpp
@@ -185,6 +185,13 @@ AbstractProfileTable* CRendererStatsTable::GetChild(uint UNUSED(row))
///////////////////////////////////////////////////////////////////////////////////
// CRenderer implementation
+enum {
+ AmbientDiffuse = 0,
+ OnlyDiffuse,
+
+ NumVertexTypes
+};
+
/**
* Struct CRendererInternals: Truly hide data that is supposed to be hidden
* in this structure so it won't even appear in header files.
@@ -203,6 +210,55 @@ struct CRendererInternals
/// Shadow map
ShadowMap* shadow;
+ /// Various model renderers
+ struct Models {
+ // The following model renderers are aliases for the appropriate real_*
+ // model renderers (depending on hardware availability and current settings)
+ // and must be used for actual model submission and rendering
+ ModelRenderer* Normal;
+ ModelRenderer* NormalInstancing;
+ ModelRenderer* Player;
+ ModelRenderer* PlayerInstancing;
+ ModelRenderer* Transp;
+
+ // "Palette" of available ModelRenderers. Do not use these directly for
+ // rendering and submission; use the aliases above instead.
+ ModelRenderer* pal_NormalFF[NumVertexTypes];
+ ModelRenderer* pal_PlayerFF[NumVertexTypes];
+ ModelRenderer* pal_NormalHWLit[NumVertexTypes];
+ ModelRenderer* pal_PlayerHWLit[NumVertexTypes];
+ ModelRenderer* pal_NormalInstancing[NumVertexTypes];
+ ModelRenderer* pal_PlayerInstancing[NumVertexTypes];
+ ModelRenderer* pal_TranspFF[NumVertexTypes];
+ ModelRenderer* pal_TranspHWLit[NumVertexTypes];
+ ModelRenderer* pal_TranspSortAll;
+
+ ModelVertexRendererPtr VertexFF[NumVertexTypes];
+ ModelVertexRendererPtr VertexHWLit[NumVertexTypes];
+ ModelVertexRendererPtr VertexInstancing[NumVertexTypes];
+ ModelVertexRendererPtr VertexPolygonSort;
+
+ // generic RenderModifiers that are supposed to be used directly
+ RenderModifierPtr ModWireframe;
+ RenderModifierPtr ModSolidColor;
+ RenderModifierPtr ModTransparentShadow;
+ RenderModifierPtr ModTransparentDepthShadow;
+
+ // RenderModifiers that are selected from the palette below
+ RenderModifierPtr ModNormal;
+ RenderModifierPtr ModPlayer;
+ RenderModifierPtr ModTransparent;
+
+ // Palette of available RenderModifiers
+ RenderModifierPtr ModPlain;
+ LitRenderModifierPtr ModPlainLit;
+ RenderModifierPtr ModPlayerUnlit;
+ LitRenderModifierPtr ModPlayerLit;
+ RenderModifierPtr ModTransparentUnlit;
+ LitRenderModifierPtr ModTransparentLit;
+ } Model;
+
+
CRendererInternals()
: profileTable(g_Renderer.m_Stats)
{
@@ -263,47 +319,61 @@ CRenderer::CRenderer()
}
// model rendering
- m_Models.VertexFF = ModelVertexRendererPtr(new FixedFunctionModelRenderer);
+ m->Model.VertexFF[AmbientDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(false));
+ m->Model.VertexFF[OnlyDiffuse] = ModelVertexRendererPtr(new FixedFunctionModelRenderer(true));
if (HWLightingModelRenderer::IsAvailable())
- m_Models.VertexHWLit = ModelVertexRendererPtr(new HWLightingModelRenderer);
+ {
+ m->Model.VertexHWLit[AmbientDiffuse] = ModelVertexRendererPtr(new HWLightingModelRenderer(false));
+ m->Model.VertexHWLit[OnlyDiffuse] = ModelVertexRendererPtr(new HWLightingModelRenderer(true));
+ }
if (InstancingModelRenderer::IsAvailable())
- m_Models.VertexInstancing = ModelVertexRendererPtr(new InstancingModelRenderer);
- m_Models.VertexPolygonSort = ModelVertexRendererPtr(new PolygonSortModelRenderer);
+ {
+ m->Model.VertexInstancing[AmbientDiffuse] = ModelVertexRendererPtr(new InstancingModelRenderer(false));
+ m->Model.VertexInstancing[OnlyDiffuse] = ModelVertexRendererPtr(new InstancingModelRenderer(true));
+ }
+ m->Model.VertexPolygonSort = ModelVertexRendererPtr(new PolygonSortModelRenderer);
- m_Models.NormalFF = new BatchModelRenderer(m_Models.VertexFF);
- m_Models.PlayerFF = new BatchModelRenderer(m_Models.VertexFF);
- m_Models.TranspFF = new SortModelRenderer(m_Models.VertexFF);
- if (m_Models.VertexHWLit)
+ for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
{
- m_Models.NormalHWLit = new BatchModelRenderer(m_Models.VertexHWLit);
- m_Models.PlayerHWLit = new BatchModelRenderer(m_Models.VertexHWLit);
- m_Models.TranspHWLit = new SortModelRenderer(m_Models.VertexHWLit);
+ m->Model.pal_NormalFF[vertexType] = new BatchModelRenderer(m->Model.VertexFF[vertexType]);
+ m->Model.pal_PlayerFF[vertexType] = new BatchModelRenderer(m->Model.VertexFF[vertexType]);
+ m->Model.pal_TranspFF[vertexType] = new SortModelRenderer(m->Model.VertexFF[vertexType]);
+ if (m->Model.VertexHWLit[vertexType])
+ {
+ m->Model.pal_NormalHWLit[vertexType] = new BatchModelRenderer(m->Model.VertexHWLit[vertexType]);
+ m->Model.pal_PlayerHWLit[vertexType] = new BatchModelRenderer(m->Model.VertexHWLit[vertexType]);
+ m->Model.pal_TranspHWLit[vertexType] = new SortModelRenderer(m->Model.VertexHWLit[vertexType]);
+ }
+ else
+ {
+ m->Model.pal_NormalHWLit[vertexType] = NULL;
+ m->Model.pal_PlayerHWLit[vertexType] = NULL;
+ m->Model.pal_TranspHWLit[vertexType] = NULL;
+ }
+ if (m->Model.VertexInstancing[vertexType])
+ {
+ m->Model.pal_NormalInstancing[vertexType] = new BatchModelRenderer(m->Model.VertexInstancing[vertexType]);
+ m->Model.pal_PlayerInstancing[vertexType] = new BatchModelRenderer(m->Model.VertexInstancing[vertexType]);
+ }
+ else
+ {
+ m->Model.pal_NormalInstancing[vertexType] = NULL;
+ m->Model.pal_PlayerInstancing[vertexType] = NULL;
+ }
}
- else
- {
- m_Models.NormalHWLit = NULL;
- m_Models.PlayerHWLit = NULL;
- m_Models.TranspHWLit = NULL;
- }
- if (m_Models.VertexInstancing)
- {
- m_Models.NormalInstancing = new BatchModelRenderer(m_Models.VertexInstancing);
- m_Models.PlayerInstancing = new BatchModelRenderer(m_Models.VertexInstancing);
- }
- else
- {
- m_Models.NormalInstancing = NULL;
- m_Models.PlayerInstancing = NULL;
- }
- m_Models.TranspSortAll = new SortModelRenderer(m_Models.VertexPolygonSort);
- m_Models.ModWireframe = RenderModifierPtr(new WireframeRenderModifier);
- m_Models.ModPlain = RenderModifierPtr(new PlainRenderModifier);
+ m->Model.pal_TranspSortAll = new SortModelRenderer(m->Model.VertexPolygonSort);
+
+ m->Model.ModWireframe = RenderModifierPtr(new WireframeRenderModifier);
+ m->Model.ModPlain = RenderModifierPtr(new PlainRenderModifier);
+ m->Model.ModPlainLit = LitRenderModifierPtr(new PlainLitRenderModifier);
SetFastPlayerColor(true);
- m_Models.ModSolidColor = RenderModifierPtr(new SolidColorRenderModifier);
- m_Models.ModTransparent = RenderModifierPtr(new TransparentRenderModifier);
- m_Models.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier);
- m_Models.ModTransparentDepthShadow = RenderModifierPtr(new TransparentDepthShadowModifier);
+ m->Model.ModPlayerLit = LitRenderModifierPtr(new LitPlayerColorRender);
+ m->Model.ModSolidColor = RenderModifierPtr(new SolidColorRenderModifier);
+ m->Model.ModTransparentUnlit = RenderModifierPtr(new TransparentRenderModifier);
+ m->Model.ModTransparentLit = LitRenderModifierPtr(new LitTransparentRenderModifier);
+ m->Model.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier);
+ m->Model.ModTransparentDepthShadow = RenderModifierPtr(new TransparentDepthShadowModifier);
m_ShadowZBias = 0.001f;
@@ -319,15 +389,18 @@ CRenderer::CRenderer()
CRenderer::~CRenderer()
{
// model rendering
- delete m_Models.NormalFF;
- delete m_Models.PlayerFF;
- delete m_Models.TranspFF;
- delete m_Models.NormalHWLit;
- delete m_Models.PlayerHWLit;
- delete m_Models.TranspHWLit;
- delete m_Models.NormalInstancing;
- delete m_Models.PlayerInstancing;
- delete m_Models.TranspSortAll;
+ for(int vertexType = 0; vertexType < NumVertexTypes; ++vertexType)
+ {
+ delete m->Model.pal_NormalFF[vertexType];
+ delete m->Model.pal_PlayerFF[vertexType];
+ delete m->Model.pal_TranspFF[vertexType];
+ delete m->Model.pal_NormalHWLit[vertexType];
+ delete m->Model.pal_PlayerHWLit[vertexType];
+ delete m->Model.pal_TranspHWLit[vertexType];
+ delete m->Model.pal_NormalInstancing[vertexType];
+ delete m->Model.pal_PlayerInstancing[vertexType];
+ }
+ delete m->Model.pal_TranspSortAll;
// general
delete m_VertexShader;
@@ -514,7 +587,7 @@ void CRenderer::SetRenderPath(RenderPath rp)
{
if (rp == RP_DEFAULT)
{
- if (m_Models.NormalHWLit && m_Models.PlayerHWLit)
+ if (m->Model.pal_NormalHWLit && m->Model.pal_PlayerHWLit)
rp = RP_VERTEXSHADER;
else
rp = RP_FIXED;
@@ -522,7 +595,7 @@ void CRenderer::SetRenderPath(RenderPath rp)
if (rp == RP_VERTEXSHADER)
{
- if (!m_Models.NormalHWLit || !m_Models.PlayerHWLit)
+ if (!m->Model.pal_NormalHWLit || !m->Model.pal_PlayerHWLit)
{
LOG(WARNING, LOG_CATEGORY, "Falling back to fixed function\n");
rp = RP_FIXED;
@@ -573,9 +646,9 @@ void CRenderer::SetFastPlayerColor(bool fast)
}
if (m_FastPlayerColor)
- m_Models.ModPlayer = RenderModifierPtr(new FastPlayerColorRender);
+ m->Model.ModPlayerUnlit = RenderModifierPtr(new FastPlayerColorRender);
else
- m_Models.ModPlayer = RenderModifierPtr(new SlowPlayerColorRender);
+ m->Model.ModPlayerUnlit = RenderModifierPtr(new SlowPlayerColorRender);
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -598,8 +671,65 @@ void CRenderer::BeginFrame()
// init per frame stuff
m->shadow->SetupFrame(m_CullCamera, m_LightEnv->GetSunDir());
+
+ // choose model renderers for this frame
+ int vertexType;
+
+ if (m_Options.m_Shadows && m->shadow->GetUseDepthTexture())
+ {
+ vertexType = OnlyDiffuse;
+ m->Model.ModNormal = m->Model.ModPlainLit;
+ m->Model.ModPlainLit->SetShadowMap(m->shadow);
+ m->Model.ModPlainLit->SetLightEnv(m_LightEnv);
+
+ m->Model.ModPlayer = m->Model.ModPlayerLit;
+ m->Model.ModPlayerLit->SetShadowMap(m->shadow);
+ m->Model.ModPlayerLit->SetLightEnv(m_LightEnv);
+
+ m->Model.ModTransparent = m->Model.ModTransparentLit;
+ m->Model.ModTransparentLit->SetShadowMap(m->shadow);
+ m->Model.ModTransparentLit->SetLightEnv(m_LightEnv);
+ }
+ else
+ {
+ vertexType = AmbientDiffuse;
+ m->Model.ModNormal = m->Model.ModPlain;
+ m->Model.ModPlayer = m->Model.ModPlayerUnlit;
+ m->Model.ModTransparent = m->Model.ModTransparentUnlit;
+ }
+
+ if (m_Options.m_RenderPath == RP_VERTEXSHADER)
+ {
+ if (m->Model.pal_NormalInstancing)
+ m->Model.NormalInstancing = m->Model.pal_NormalInstancing[vertexType];
+ else
+ m->Model.NormalInstancing = m->Model.pal_NormalHWLit[vertexType];
+ m->Model.Normal = m->Model.pal_NormalHWLit[vertexType];
+
+ if (m->Model.pal_PlayerInstancing)
+ m->Model.PlayerInstancing = m->Model.pal_PlayerInstancing[vertexType];
+ else
+ m->Model.PlayerInstancing = m->Model.pal_PlayerHWLit[vertexType];
+ m->Model.Player = m->Model.pal_PlayerHWLit[vertexType];
+ }
+ else
+ {
+ m->Model.NormalInstancing = m->Model.pal_NormalFF[vertexType];
+ m->Model.Normal = m->Model.pal_NormalFF[vertexType];
+
+ m->Model.PlayerInstancing = m->Model.pal_PlayerFF[vertexType];
+ m->Model.Player = m->Model.pal_PlayerFF[vertexType];
+ }
+
+ if (m_SortAllTransparent)
+ m->Model.Transp = m->Model.pal_TranspSortAll;
+ else if (m_Options.m_RenderPath == RP_VERTEXSHADER)
+ m->Model.Transp = m->Model.pal_TranspHWLit[vertexType];
+ else
+ m->Model.Transp = m->Model.pal_TranspFF[vertexType];
}
+
//////////////////////////////////////////////////////////////////////////////////////////
// SetClearColor: set color used to clear screen in BeginFrame()
void CRenderer::SetClearColor(u32 color)
@@ -620,10 +750,10 @@ void CRenderer::RenderShadowMap()
glColor3f(shadowTransp, shadowTransp, shadowTransp);
// Figure out transparent rendering strategy
- RenderModifierPtr transparentShadows = m_Models.ModTransparentShadow;
+ RenderModifierPtr transparentShadows = m->Model.ModTransparentShadow;
if (m->shadow->GetUseDepthTexture())
- transparentShadows = m_Models.ModTransparentDepthShadow;
+ transparentShadows = m->Model.ModTransparentDepthShadow;
// Render all closed models (i.e. models where rendering back faces will produce
// the correct result)
@@ -637,22 +767,14 @@ void CRenderer::RenderShadowMap()
// Render models that aren't closed
glDisable(GL_CULL_FACE);
- m_Models.NormalFF->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
- m_Models.PlayerFF->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
- if (m_Models.NormalHWLit)
- m_Models.NormalHWLit->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
- if (m_Models.PlayerHWLit)
- m_Models.PlayerHWLit->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
- if (m_Models.NormalInstancing)
- m_Models.NormalInstancing->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
- if (m_Models.PlayerInstancing)
- m_Models.PlayerInstancing->Render(m_Models.ModSolidColor, MODELFLAG_CASTSHADOWS);
+ m->Model.Normal->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
+ if (m->Model.Normal != m->Model.NormalInstancing)
+ m->Model.NormalInstancing->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
+ m->Model.Player->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
+ if (m->Model.Player != m->Model.PlayerInstancing)
+ m->Model.PlayerInstancing->Render(m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS);
-
- m_Models.TranspFF->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
- if (m_Models.TranspHWLit)
- m_Models.TranspHWLit->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
- m_Models.TranspSortAll->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
+ m->Model.Transp->Render(transparentShadows, MODELFLAG_CASTSHADOWS);
glEnable(GL_CULL_FACE);
@@ -722,31 +844,23 @@ void CRenderer::RenderModels()
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
- m_Models.NormalFF->Render(m_Models.ModPlain, 0);
- m_Models.PlayerFF->Render(m_Models.ModPlayer, 0);
- if (m_Models.NormalHWLit)
- m_Models.NormalHWLit->Render(m_Models.ModPlain, 0);
- if (m_Models.PlayerHWLit)
- m_Models.PlayerHWLit->Render(m_Models.ModPlayer, 0);
- if (m_Models.NormalInstancing)
- m_Models.NormalInstancing->Render(m_Models.ModPlain, 0);
- if (m_Models.PlayerInstancing)
- m_Models.PlayerInstancing->Render(m_Models.ModPlayer, 0);
+ m->Model.Normal->Render(m->Model.ModNormal, 0);
+ m->Model.Player->Render(m->Model.ModPlayer, 0);
+ if (m->Model.Normal != m->Model.NormalInstancing)
+ m->Model.NormalInstancing->Render(m->Model.ModNormal, 0);
+ if (m->Model.Player != m->Model.PlayerInstancing)
+ m->Model.PlayerInstancing->Render(m->Model.ModPlayer, 0);
if (m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (m_ModelRenderMode==EDGED_FACES) {
- m_Models.NormalFF->Render(m_Models.ModWireframe, 0);
- m_Models.PlayerFF->Render(m_Models.ModWireframe, 0);
- if (m_Models.NormalHWLit)
- m_Models.NormalHWLit->Render(m_Models.ModWireframe, 0);
- if (m_Models.PlayerHWLit)
- m_Models.PlayerHWLit->Render(m_Models.ModWireframe, 0);
- if (m_Models.NormalInstancing)
- m_Models.NormalInstancing->Render(m_Models.ModWireframe, 0);
- if (m_Models.PlayerInstancing)
- m_Models.PlayerInstancing->Render(m_Models.ModWireframe, 0);
+ m->Model.Normal->Render(m->Model.ModWireframe, 0);
+ m->Model.Player->Render(m->Model.ModWireframe, 0);
+ if (m->Model.Normal != m->Model.NormalInstancing)
+ m->Model.NormalInstancing->Render(m->Model.ModWireframe, 0);
+ if (m->Model.Player != m->Model.PlayerInstancing)
+ m->Model.PlayerInstancing->Render(m->Model.ModWireframe, 0);
}
}
@@ -759,19 +873,13 @@ void CRenderer::RenderTransparentModels()
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
}
- m_Models.TranspFF->Render(m_Models.ModTransparent, 0);
- if (m_Models.TranspHWLit)
- m_Models.TranspHWLit->Render(m_Models.ModTransparent, 0);
- m_Models.TranspSortAll->Render(m_Models.ModTransparent, 0);
+ m->Model.Transp->Render(m->Model.ModTransparent, 0);
if (m_ModelRenderMode==WIREFRAME) {
// switch wireframe off again
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
} else if (m_ModelRenderMode==EDGED_FACES) {
- m_Models.TranspFF->Render(m_Models.ModWireframe, 0);
- if (m_Models.TranspHWLit)
- m_Models.TranspHWLit->Render(m_Models.ModWireframe, 0);
- m_Models.TranspSortAll->Render(m_Models.ModWireframe, 0);
+ m->Model.Transp->Render(m->Model.ModWireframe, 0);
}
}
@@ -788,20 +896,13 @@ void CRenderer::FlushFrame()
// Prepare model renderers
PROFILE_START("prepare models");
- m_Models.NormalFF->PrepareModels();
- m_Models.PlayerFF->PrepareModels();
- m_Models.TranspFF->PrepareModels();
- if (m_Models.NormalHWLit)
- m_Models.NormalHWLit->PrepareModels();
- if (m_Models.PlayerHWLit)
- m_Models.PlayerHWLit->PrepareModels();
- if (m_Models.TranspHWLit)
- m_Models.TranspHWLit->PrepareModels();
- if (m_Models.NormalInstancing)
- m_Models.NormalInstancing->PrepareModels();
- if (m_Models.PlayerInstancing)
- m_Models.PlayerInstancing->PrepareModels();
- m_Models.TranspSortAll->PrepareModels();
+ m->Model.Normal->PrepareModels();
+ m->Model.Player->PrepareModels();
+ if (m->Model.Normal != m->Model.NormalInstancing)
+ m->Model.NormalInstancing->PrepareModels();
+ if (m->Model.Player != m->Model.PlayerInstancing)
+ m->Model.PlayerInstancing->PrepareModels();
+ m->Model.Transp->PrepareModels();
PROFILE_END("prepare models");
PROFILE_START("prepare terrain");
@@ -862,20 +963,13 @@ void CRenderer::FlushFrame()
m->terrainRenderer->EndFrame();
// Finish model renderers
- m_Models.NormalFF->EndFrame();
- m_Models.PlayerFF->EndFrame();
- m_Models.TranspFF->EndFrame();
- if (m_Models.NormalHWLit)
- m_Models.NormalHWLit->EndFrame();
- if (m_Models.PlayerHWLit)
- m_Models.PlayerHWLit->EndFrame();
- if (m_Models.TranspHWLit)
- m_Models.TranspHWLit->EndFrame();
- if (m_Models.NormalInstancing)
- m_Models.NormalInstancing->EndFrame();
- if (m_Models.PlayerInstancing)
- m_Models.PlayerInstancing->EndFrame();
- m_Models.TranspSortAll->EndFrame();
+ m->Model.Normal->EndFrame();
+ m->Model.Player->EndFrame();
+ if (m->Model.Normal != m->Model.NormalInstancing)
+ m->Model.NormalInstancing->EndFrame();
+ if (m->Model.Player != m->Model.PlayerInstancing)
+ m->Model.PlayerInstancing->EndFrame();
+ m->Model.Transp->EndFrame();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -968,36 +1062,21 @@ void CRenderer::Submit(CModel* model)
if (model->GetMaterial().IsPlayer())
{
- if (m_Options.m_RenderPath == RP_VERTEXSHADER)
- {
- if (canUseInstancing && m_Models.PlayerInstancing)
- m_Models.PlayerInstancing->Submit(model);
- else
- m_Models.PlayerHWLit->Submit(model);
- }
+ if (canUseInstancing)
+ m->Model.PlayerInstancing->Submit(model);
else
- m_Models.PlayerFF->Submit(model);
+ m->Model.Player->Submit(model);
}
else if (model->GetMaterial().UsesAlpha())
{
- if (m_SortAllTransparent)
- m_Models.TranspSortAll->Submit(model);
- else if (m_Options.m_RenderPath == RP_VERTEXSHADER)
- m_Models.TranspHWLit->Submit(model);
- else
- m_Models.TranspFF->Submit(model);
+ m->Model.Transp->Submit(model);
}
else
{
- if (m_Options.m_RenderPath == RP_VERTEXSHADER)
- {
- if (canUseInstancing && m_Models.NormalInstancing)
- m_Models.NormalInstancing->Submit(model);
- else
- m_Models.NormalHWLit->Submit(model);
- }
+ if (canUseInstancing)
+ m->Model.NormalInstancing->Submit(model);
else
- m_Models.NormalFF->Submit(model);
+ m->Model.Normal->Submit(model);
}
}
diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h
index c2ba084091..7d9a31a8cc 100755
--- a/source/renderer/Renderer.h
+++ b/source/renderer/Renderer.h
@@ -53,6 +53,7 @@ enum ERenderMode { WIREFRAME, SOLID, EDGED_FACES };
#define STREAM_UV2 0x20
#define STREAM_UV3 0x40
#define STREAM_POSTOUV0 0x80
+#define STREAM_TEXGENTOUV1 0x100
//////////////////////////////////////////////////////////////////////////////////////////
// SVertex3D: simple 3D vertex declaration
@@ -429,33 +430,6 @@ protected:
*/
bool m_DisableCopyShadow;
- // Various model renderers
- struct Models {
- ModelRenderer* NormalFF;
- ModelRenderer* PlayerFF;
- ModelRenderer* NormalHWLit;
- ModelRenderer* PlayerHWLit;
- ModelRenderer* NormalInstancing;
- ModelRenderer* PlayerInstancing;
-
- ModelRenderer* TranspFF;
- ModelRenderer* TranspHWLit;
- ModelRenderer* TranspSortAll;
-
- ModelVertexRendererPtr VertexFF;
- ModelVertexRendererPtr VertexHWLit;
- ModelVertexRendererPtr VertexInstancing;
- ModelVertexRendererPtr VertexPolygonSort;
-
- RenderModifierPtr ModWireframe;
- RenderModifierPtr ModPlain;
- RenderModifierPtr ModPlayer;
- RenderModifierPtr ModSolidColor;
- RenderModifierPtr ModTransparent;
- RenderModifierPtr ModTransparentShadow;
- RenderModifierPtr ModTransparentDepthShadow;
- } m_Models;
-
public:
/**
* m_ShadowZBias: Z bias used when rendering shadows into a depth texture.
diff --git a/source/renderer/ShadowMap.cpp b/source/renderer/ShadowMap.cpp
index 926b5a1172..fb3313ec2b 100644
--- a/source/renderer/ShadowMap.cpp
+++ b/source/renderer/ShadowMap.cpp
@@ -346,12 +346,12 @@ void ShadowMap::EndRender()
///////////////////////////////////////////////////////////////////////////////////////////////////
// Retrieve the texture handle and texture matrix for shadowing
-GLuint ShadowMap::GetTexture()
+GLuint ShadowMap::GetTexture() const
{
return m->Texture;
}
-const CMatrix3D& ShadowMap::GetTextureMatrix()
+const CMatrix3D& ShadowMap::GetTextureMatrix() const
{
return m->TextureMatrix;
}
@@ -359,7 +359,7 @@ const CMatrix3D& ShadowMap::GetTextureMatrix()
///////////////////////////////////////////////////////////////////////////////////////////////////
// Using depth textures vs. a simple luminance map
-bool ShadowMap::GetUseDepthTexture()
+bool ShadowMap::GetUseDepthTexture() const
{
return m->UseDepthTexture;
}
diff --git a/source/renderer/ShadowMap.h b/source/renderer/ShadowMap.h
index c85e90641e..7df8a77f6b 100644
--- a/source/renderer/ShadowMap.h
+++ b/source/renderer/ShadowMap.h
@@ -45,7 +45,7 @@ public:
*
* @return whether shadow rendering uses depth textures
*/
- bool GetUseDepthTexture();
+ bool GetUseDepthTexture() const;
/**
* SetUseDepthTexture: Set whether shadowing should use depth textures.
@@ -109,7 +109,7 @@ public:
*
* @return the texture name of the shadow map texture
*/
- GLuint GetTexture();
+ GLuint GetTexture() const;
/**
* GetTextureMatrix: Retrieve the world-space to shadow map texture coordinates
@@ -118,7 +118,7 @@ public:
* @return the matrix that transforms world-space coordinates into homogenous
* shadow map texture coordinates
*/
- const CMatrix3D& GetTextureMatrix();
+ const CMatrix3D& GetTextureMatrix() const;
/**
* RenderDebugDisplay: Visualize shadow mapping calculations to help in
diff --git a/source/renderer/TransparencyRenderer.cpp b/source/renderer/TransparencyRenderer.cpp
index 2a62757f68..e191000f12 100755
--- a/source/renderer/TransparencyRenderer.cpp
+++ b/source/renderer/TransparencyRenderer.cpp
@@ -21,12 +21,14 @@
#include "Vector3D.h"
#include "Vector4D.h"
+#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
#include "ps/Profile.h"
#include "renderer/Renderer.h"
+#include "renderer/ShadowMap.h"
#include "renderer/TransparencyRenderer.h"
#include "renderer/VertexArray.h"
@@ -235,7 +237,7 @@ void PolygonSortModelRenderer::UpdateModelData(CModel* model, void* data, u32 up
VertexArrayIterator Color = psmdl->m_Color.GetIterator();
- ModelRenderer::BuildColor4ub(model, Normal, Color);
+ ModelRenderer::BuildColor4ub(model, Normal, Color, false);
// upload everything to vertex buffer
psmdl->m_Array.Upload();
@@ -266,8 +268,10 @@ void PolygonSortModelRenderer::DestroyModelData(CModel* UNUSED(model), void* dat
// Prepare for one rendering pass
-void PolygonSortModelRenderer::BeginPass(uint streamflags)
+void PolygonSortModelRenderer::BeginPass(uint streamflags, const CMatrix3D* UNUSED(texturematrix))
{
+ debug_assert(streamflags == streamflags & (STREAM_POS|STREAM_COLOR|STREAM_UV0));
+
glEnableClientState(GL_VERTEX_ARRAY);
if (streamflags & STREAM_UV0) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -477,10 +481,14 @@ void SortModelRenderer::Render(RenderModifierPtr modifier, u32 flags)
do
{
u32 streamflags = modifier->BeginPass(pass);
+ const CMatrix3D* texturematrix = 0;
CModelDefPtr lastmdef;
CTexture* lasttex = 0;
- m->vertexRenderer->BeginPass(streamflags);
+ if (streamflags & STREAM_TEXGENTOUV1)
+ texturematrix = modifier->GetTexGenMatrix(pass);
+
+ m->vertexRenderer->BeginPass(streamflags, texturematrix);
for(std::vector::iterator it = m->models.begin(); it != m->models.end(); ++it)
{
@@ -608,6 +616,143 @@ void TransparentRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(m
}
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// LitTransparentRenderModifier implementation
+
+LitTransparentRenderModifier::LitTransparentRenderModifier()
+{
+}
+
+LitTransparentRenderModifier::~LitTransparentRenderModifier()
+{
+}
+
+u32 LitTransparentRenderModifier::BeginPass(uint pass)
+{
+ debug_assert(GetShadowMap() && GetShadowMap()->GetUseDepthTexture());
+
+ if (pass == 0)
+ {
+ // First pass: Put down Z for opaque parts of the model,
+ // don't touch the color buffer.
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+
+ // just pass through texture's alpha
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ // Set the proper LOD bias
+ glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
+
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_GREATER,0.975f);
+
+ // render everything with color writes off to setup depth buffer correctly
+ glColorMask(0,0,0,0);
+
+ return STREAM_POS|STREAM_UV0;
+ }
+ else
+ {
+ // Second pass: Put down color, disable Z write
+ glColorMask(1,1,1,1);
+
+ glDepthMask(0);
+
+ // Ambient + Diffuse * Shadow
+ pglActiveTextureARB(GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE1);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ pglActiveTextureARB(GL_TEXTURE1);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, &GetLightEnv()->m_UnitsAmbientColor.X);
+
+ // Incoming color is ambient + diffuse light
+ pglActiveTextureARB(GL_TEXTURE2);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, GetShadowMap()->GetTexture());
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ pglActiveTextureARB(GL_TEXTURE0);
+
+ glAlphaFunc(GL_GREATER,0);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+ // Set the proper LOD bias
+ glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, g_Renderer.m_Options.m_LodBias);
+
+ return STREAM_POS|STREAM_COLOR|STREAM_UV0|STREAM_TEXGENTOUV1;
+ }
+}
+
+bool LitTransparentRenderModifier::EndPass(uint pass)
+{
+ if (pass == 0)
+ return false; // multi-pass
+
+ pglActiveTextureARB(GL_TEXTURE1);
+ glDisable(GL_TEXTURE_2D);
+ pglActiveTextureARB(GL_TEXTURE2);
+ glDisable(GL_TEXTURE_2D);
+ pglActiveTextureARB(GL_TEXTURE0);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_ALPHA_TEST);
+ glDepthMask(1);
+
+ return true;
+}
+
+const CMatrix3D* LitTransparentRenderModifier::GetTexGenMatrix(uint UNUSED(pass))
+{
+ return &GetShadowMap()->GetTextureMatrix();
+}
+
+void LitTransparentRenderModifier::PrepareTexture(uint UNUSED(pass), CTexture* texture)
+{
+ g_Renderer.SetTexture(0, texture);
+}
+
+void LitTransparentRenderModifier::PrepareModel(uint UNUSED(pass), CModel* UNUSED(model))
+{
+ // No per-model setup necessary
+}
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////
// TransparentShadowRenderModifier implementation
diff --git a/source/renderer/TransparencyRenderer.h b/source/renderer/TransparencyRenderer.h
index f3a80cd2f1..3b163f411e 100755
--- a/source/renderer/TransparencyRenderer.h
+++ b/source/renderer/TransparencyRenderer.h
@@ -40,7 +40,7 @@ public:
void UpdateModelData(CModel* model, void* data, u32 updateflags);
void DestroyModelData(CModel* model, void* data);
- void BeginPass(uint streamflags);
+ void BeginPass(uint streamflags, const CMatrix3D* texturematrix);
void EndPass(uint streamflags);
void PrepareModelDef(uint streamflags, CModelDefPtr def);
void RenderModel(uint streamflags, CModel* model, void* data);
@@ -100,6 +100,30 @@ public:
};
+
+/**
+ * Class LitTransparentRenderModifier: Modifier for transparent models,
+ * including alpha blending and shadowed lighting.
+ *
+ * @note Use only when depth textures are used for shadows and thus supported by the OpenGL
+ * implementation.
+ */
+class LitTransparentRenderModifier : public LitRenderModifier
+{
+public:
+ LitTransparentRenderModifier();
+ ~LitTransparentRenderModifier();
+
+ // Implementation
+ u32 BeginPass(uint pass);
+ bool EndPass(uint pass);
+ const CMatrix3D* GetTexGenMatrix(uint pass);
+ void PrepareTexture(uint pass, CTexture* texture);
+ void PrepareModel(uint pass, CModel* model);
+
+};
+
+
/**
* Class TransparentShadowRenderModifier: Use to render shadow data for
* transparent models into a luminance map.