From e2bbd9a6545f2b0af9aeccd3fb38f31171304170 Mon Sep 17 00:00:00 2001 From: prefect Date: Sun, 26 Mar 2006 00:54:20 +0000 Subject: [PATCH] #Models receive shadows now, including self-shadows. This is a huge patch, including: * add a LitRenderModifier abstract base class for RenderModifiers with shadow+light * add LitRenderModifiers for all types of models * add STREAM_TEXGENTOUV1 to request generation of shadow map texcoords for models * create facilities to pass the texture matrix from the RenderModifier (fragment stage) to the ModelRenderer (vertex stage) * split ambient and diffuse terms of lighting until further down in the pipeline; this is necessary since shadowed regions receive only ambient light * small improvement in how RenderPathVertexShader scales to a greater number of vertex shaders This was SVN commit r3690. --- .../official/shaders/instancing_lightp.vs | 17 + .../official/shaders/instancing_lightp.xml | 10 + .../data/mods/official/shaders/instancingp.vs | 12 + .../mods/official/shaders/instancingp.xml | 9 + .../mods/official/shaders/model_lightp.vs | 10 + .../mods/official/shaders/model_lightp.xml | 9 + .../data/mods/official/shaders/postouv1.vs | 14 + .../renderer/FixedFunctionModelRenderer.cpp | 48 ++- source/renderer/FixedFunctionModelRenderer.h | 12 +- source/renderer/HWLightingModelRenderer.cpp | 87 ++++- source/renderer/HWLightingModelRenderer.h | 20 +- source/renderer/InstancingModelRenderer.cpp | 71 ++-- source/renderer/InstancingModelRenderer.h | 22 +- source/renderer/ModelRenderer.cpp | 35 +- source/renderer/ModelRenderer.h | 8 +- source/renderer/ModelVertexRenderer.h | 33 +- source/renderer/PlayerRenderer.cpp | 192 ++++++++- source/renderer/PlayerRenderer.h | 31 +- source/renderer/RenderModifiers.cpp | 125 +++++- source/renderer/RenderModifiers.h | 77 +++- source/renderer/RenderPathVertexShader.cpp | 96 +++-- source/renderer/RenderPathVertexShader.h | 104 ++++- source/renderer/Renderer.cpp | 363 +++++++++++------- source/renderer/Renderer.h | 28 +- source/renderer/ShadowMap.cpp | 6 +- source/renderer/ShadowMap.h | 6 +- source/renderer/TransparencyRenderer.cpp | 151 +++++++- source/renderer/TransparencyRenderer.h | 26 +- 28 files changed, 1292 insertions(+), 330 deletions(-) create mode 100644 binaries/data/mods/official/shaders/instancing_lightp.vs create mode 100644 binaries/data/mods/official/shaders/instancing_lightp.xml create mode 100644 binaries/data/mods/official/shaders/instancingp.vs create mode 100644 binaries/data/mods/official/shaders/instancingp.xml create mode 100644 binaries/data/mods/official/shaders/model_lightp.vs create mode 100644 binaries/data/mods/official/shaders/model_lightp.xml create mode 100644 binaries/data/mods/official/shaders/postouv1.vs 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.