diff --git a/binaries/data/mods/public/simulation/templates/gaia/special_settlement.xml b/binaries/data/mods/public/simulation/templates/gaia/special_settlement.xml index 807c2ff393..52437a1b5e 100644 --- a/binaries/data/mods/public/simulation/templates/gaia/special_settlement.xml +++ b/binaries/data/mods/public/simulation/templates/gaia/special_settlement.xml @@ -2,5 +2,7 @@ structures/wrld_settlement_1.xml + false + false diff --git a/binaries/data/mods/public/simulation/templates/template_gaia.xml b/binaries/data/mods/public/simulation/templates/template_gaia.xml index 327ece4741..1f1190db49 100644 --- a/binaries/data/mods/public/simulation/templates/template_gaia.xml +++ b/binaries/data/mods/public/simulation/templates/template_gaia.xml @@ -24,4 +24,8 @@ false false + + false + true + diff --git a/binaries/data/mods/public/simulation/templates/template_structure.xml b/binaries/data/mods/public/simulation/templates/template_structure.xml index 96dff7bc2f..5851a7d4c6 100644 --- a/binaries/data/mods/public/simulation/templates/template_structure.xml +++ b/binaries/data/mods/public/simulation/templates/template_structure.xml @@ -70,4 +70,8 @@ false false + + false + true + diff --git a/binaries/data/mods/public/simulation/templates/template_unit.xml b/binaries/data/mods/public/simulation/templates/template_unit.xml index 9eb3ff530d..7f406682dd 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit.xml @@ -92,4 +92,8 @@ false false + + true + false + diff --git a/binaries/data/mods/public/simulation/templates/template_unit_fauna.xml b/binaries/data/mods/public/simulation/templates/template_unit_fauna.xml index e13218ea0d..49710af485 100644 --- a/binaries/data/mods/public/simulation/templates/template_unit_fauna.xml +++ b/binaries/data/mods/public/simulation/templates/template_unit_fauna.xml @@ -33,4 +33,7 @@ 15000 60000 + + false + diff --git a/source/graphics/Material.cpp b/source/graphics/Material.cpp index 54128f8767..e30b3d55c2 100644 --- a/source/graphics/Material.cpp +++ b/source/graphics/Material.cpp @@ -24,7 +24,6 @@ #include "ps/Overlay.h" // for CColor CMaterial NullMaterial; -CMaterial IdentityMaterial; // Values as taken straight from the Blue Book (god bless the Blue Book) static SMaterialColor IdentityDiffuse(0.8f, 0.8f, 0.8f, 1.0f); @@ -41,26 +40,13 @@ CMaterial::CMaterial() m_Emissive(IdentityEmissive), m_SpecularPower(0.0f), m_Alpha(false), - m_PlayerID(PLAYER_ID_NONE), - m_TextureColor(BrokenColor) + m_PlayerID(INVALID_PLAYER), + m_TextureColor(BrokenColor), + m_UsePlayerColor(false), + m_UseTextureColor(false) { } -bool CMaterial::operator==(const CMaterial& material) -{ - return( - m_Texture == m_Texture && - m_Diffuse == material.m_Diffuse && - m_Ambient == material.m_Ambient && - m_Specular == material.m_Specular && - m_Emissive == material.m_Emissive && - m_SpecularPower == material.m_SpecularPower && - m_Alpha == material.m_Alpha && - m_PlayerID == material.m_PlayerID && - m_TextureColor == material.m_TextureColor - ); -} - void CMaterial::Bind() { glMaterialf(GL_FRONT, GL_SHININESS, m_SpecularPower); @@ -96,31 +82,42 @@ SMaterialColor CMaterial::GetEmissive() return m_Emissive; } -SMaterialColor CMaterial::GetPlayerColor() +SMaterialColor CMaterial::GetObjectColor() { - debug_assert(m_PlayerID != PLAYER_ID_NONE); - // because this should never be called unless IsPlayer returned true - - if (m_PlayerID == PLAYER_ID_OTHER /* TODO: or if player-colour is globally disabled */ ) + if (m_UseTextureColor) return m_TextureColor; - if (m_PlayerID <= PLAYER_ID_LAST_VALID) - { - CColor c(g_Game->GetPlayerColour(m_PlayerID)); - return SMaterialColor(c.r, c.g, c.b, c.a); - } + debug_assert(m_UsePlayerColor); + // this should never be called unless IsPlayer returned true - // Oops, something failed. - return BrokenColor; + return GetPlayerColor(); } -void CMaterial::SetPlayerColor(size_t id) +SMaterialColor CMaterial::GetPlayerColor() { - if (m_PlayerID == PLAYER_ID_COMING_SOON || m_PlayerID <= PLAYER_ID_LAST_VALID) - m_PlayerID = id; + if (m_PlayerID == -1) + return BrokenColor; + + CColor c(g_Game->GetPlayerColour(m_PlayerID)); + return SMaterialColor(c.r, c.g, c.b, c.a); } -void CMaterial::SetPlayerColor(const CColor& colour) +void CMaterial::SetPlayerID(player_id_t id) +{ + m_PlayerID = id; +} + +void CMaterial::SetUsePlayerColor(bool use) +{ + m_UsePlayerColor = use; +} + +void CMaterial::SetUseTextureColor(bool use) +{ + m_UseTextureColor = use; +} + +void CMaterial::SetTextureColor(const CColor& colour) { m_TextureColor = SMaterialColor(colour.r, colour.g, colour.b, colour.a); } diff --git a/source/graphics/Material.h b/source/graphics/Material.h index 679edaa44f..986debb0b0 100644 --- a/source/graphics/Material.h +++ b/source/graphics/Material.h @@ -19,6 +19,9 @@ #define INCLUDED_MATERIAL #include "ps/CStr.h" +#include "simulation2/helpers/Player.h" + +// FIXME: This material system is almost entirely unused and probably broken struct CColor; @@ -38,15 +41,6 @@ public: b = _b; a = _a; } - bool operator==(const SMaterialColor& color) - { - return ( - r == color.r && - g == color.g && - b == color.b && - a == color.a - ); - } }; class CMaterial @@ -69,16 +63,18 @@ public: bool UsesAlpha() { return m_Alpha; } // Determines whether or not the model goes into the PlayerRenderer - bool IsPlayer() { return (m_PlayerID != PLAYER_ID_NONE); } - // Get the player colour (in a non-zero amount of time, so don't call it - // an unreasonable number of times. But it's fairly close to zero, so - // don't worry too much about it.) + bool IsPlayer() { return (m_UseTextureColor || m_UsePlayerColor); } + + // Get the player colour or texture colour to be applied to this object + SMaterialColor GetObjectColor(); + // Get the player colour SMaterialColor GetPlayerColor(); - void SetPlayerColor_PerPlayer() { m_PlayerID = PLAYER_ID_COMING_SOON; } - void SetPlayerColor_PerObject() { m_PlayerID = PLAYER_ID_OTHER; } - void SetPlayerColor(size_t id); - void SetPlayerColor(const CColor &colour); + void SetPlayerID(player_id_t id); + void SetTextureColor(const CColor &colour); + + void SetUsePlayerColor(bool use); + void SetUseTextureColor(bool use); void SetTexture(const CStr& texture); void SetVertexProgram(const CStr& prog); @@ -90,8 +86,7 @@ public: void SetSpecularPower(float power); void SetUsesAlpha(bool flag); - bool operator==(const CMaterial& material); -protected: +private: // Various reflective color properties SMaterialColor m_Diffuse; SMaterialColor m_Ambient; @@ -109,25 +104,13 @@ protected: // Alpha required flag bool m_Alpha; - // Player-colour settings. - // If m_PlayerID <= PLAYER_ID_LAST_VALID, the colour is retrieved from - // g_Game whenever it's needed. - // (It's not cached, because the player might change colour.) - // If m_PlayerID == PLAYER_ID_OTHER, or if player-colouring has been globally - // disabled, m_TextureColor is used instead. This allows per-model colours to - // be specified, instead of only a single colour per player. - // If m_PlayerID == PLAYER_ID_NONE, there's no player colour at all. - // If m_PlayerID == PLAYER_ID_COMING_SOON, it's going to be linked to a player, - // but hasn't yet. - static const size_t PLAYER_ID_NONE = SIZE_MAX-1; - static const size_t PLAYER_ID_OTHER = SIZE_MAX-2; - static const size_t PLAYER_ID_COMING_SOON = SIZE_MAX-3; - static const size_t PLAYER_ID_LAST_VALID = SIZE_MAX-4; - size_t m_PlayerID; + player_id_t m_PlayerID; SMaterialColor m_TextureColor; // used as an alternative to the per-player colour + + bool m_UsePlayerColor; + bool m_UseTextureColor; }; extern CMaterial NullMaterial; -extern CMaterial IdentityMaterial; #endif diff --git a/source/graphics/MaterialManager.cpp b/source/graphics/MaterialManager.cpp index cdbebca1cf..6f2044ec02 100644 --- a/source/graphics/MaterialManager.cpp +++ b/source/graphics/MaterialManager.cpp @@ -271,9 +271,9 @@ CMaterial& CMaterialManager::LoadMaterial(const VfsPath& pathname) // Determine whether the alpha is used for basic transparency or player color if (temp == "playercolor") - material->SetPlayerColor_PerPlayer(); + material->SetUsePlayerColor(true); else if (temp == "objectcolor") - material->SetPlayerColor_PerObject(); + material->SetUseTextureColor(true); else material->SetUsesAlpha(ParseUsage(temp)); } diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index 423cc03dd9..09b5275e1a 100644 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -463,27 +463,30 @@ void CModel::SetTransform(const CMatrix3D& transform) ////////////////////////////////////////////////////////////////////////// +void CModel::AddFlagsRec(int flags) +{ + m_Flags |= flags; + for (size_t i = 0; i < m_Props.size(); ++i) + if (m_Props[i].m_Model->ToCModel()) + m_Props[i].m_Model->ToCModel()->AddFlagsRec(flags); +} + void CModel::SetMaterial(const CMaterial &material) { m_Material = material; } -void CModel::SetPlayerID(size_t id) +void CModel::SetPlayerID(player_id_t id) { CModelAbstract::SetPlayerID(id); - if (id != (size_t)-1) - m_Material.SetPlayerColor(id); + if (id != INVALID_PLAYER) + m_Material.SetPlayerID(id); for (std::vector::iterator it = m_Props.begin(); it != m_Props.end(); ++it) it->m_Model->SetPlayerID(id); } -void CModel::SetPlayerColor(const CColor& colour) -{ - m_Material.SetPlayerColor(colour); -} - void CModel::SetShadingColor(const CColor& colour) { CModelAbstract::SetShadingColor(colour); diff --git a/source/graphics/Model.h b/source/graphics/Model.h index a06a0eede0..b4c4b86714 100644 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -38,6 +38,9 @@ class CSkeletonAnimManager; #define MODELFLAG_CASTSHADOWS (1<<0) #define MODELFLAG_NOLOOPANIMATION (1<<1) +#define MODELFLAG_SILHOUETTE_DISPLAY (1<<2) +#define MODELFLAG_SILHOUETTE_OCCLUDER (1<<3) + /////////////////////////////////////////////////////////////////////////////// // CModel: basically, a mesh object - holds the texturing and skinning @@ -85,9 +88,7 @@ public: // set the model's material void SetMaterial(const CMaterial &material); // set the model's player ID, recursively through props - void SetPlayerID(size_t id); - // set the model's player colour - virtual void SetPlayerColor(const CColor& colour); + void SetPlayerID(player_id_t id); // set the models mod color virtual void SetShadingColor(const CColor& colour); // get the model's texture @@ -109,6 +110,8 @@ public: void SetFlags(int flags) { m_Flags=flags; } // get object flags int GetFlags() const { return m_Flags; } + // add object flags, recursively through props + void AddFlagsRec(int flags); // recurse down tree setting dirty bits virtual void SetDirtyRec(int dirtyflags) { diff --git a/source/graphics/ModelAbstract.h b/source/graphics/ModelAbstract.h index 9536f80273..63c7f62e7e 100644 --- a/source/graphics/ModelAbstract.h +++ b/source/graphics/ModelAbstract.h @@ -20,6 +20,7 @@ #include "graphics/RenderableObject.h" #include "ps/Overlay.h" +#include "simulation2/helpers/Player.h" class CModel; class CModelDecal; @@ -37,7 +38,7 @@ class CModelAbstract : public CRenderableObject public: CModelAbstract() : m_Parent(NULL), m_PositionValid(false), - m_ShadingColor(1, 1, 1, 1), m_PlayerID((size_t)-1) + m_ShadingColor(1, 1, 1, 1), m_PlayerID(INVALID_PLAYER) { } @@ -76,10 +77,10 @@ public: */ virtual void InvalidatePosition() = 0; - virtual void SetPlayerID(size_t id) { m_PlayerID = id; } + virtual void SetPlayerID(player_id_t id) { m_PlayerID = id; } - // get the model's player ID; initial default is (size_t)-1 - virtual size_t GetPlayerID() const { return m_PlayerID; } + // get the model's player ID; initial default is INVALID_PLAYER + virtual player_id_t GetPlayerID() const { return m_PlayerID; } virtual void SetShadingColor(const CColor& colour) { m_ShadingColor = colour; } virtual CColor GetShadingColor() const { return m_ShadingColor; } @@ -90,7 +91,7 @@ public: /// True if both transform and and bone matrices are valid. bool m_PositionValid; - size_t m_PlayerID; + player_id_t m_PlayerID; // modulating color CColor m_ShadingColor; diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index ea3b023a65..11b820f355 100644 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -112,8 +112,8 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections delete m_Model; m_Model = model; model->SetMaterial(g_MaterialManager.LoadMaterial(m_Base->m_Material)); + model->GetMaterial().SetTextureColor(m_Color); model->InitModel(modeldef); - model->SetPlayerColor(m_Color); CTextureProperties textureProps(m_TextureName); textureProps.SetWrap(GL_CLAMP_TO_EDGE); diff --git a/source/graphics/Unit.cpp b/source/graphics/Unit.cpp index 6ca874855a..a20d438506 100644 --- a/source/graphics/Unit.cpp +++ b/source/graphics/Unit.cpp @@ -109,8 +109,14 @@ void CUnit::ReloadObject() newModel->SetTransform(m_Model->GetTransform()); newModel->SetPlayerID(m_Model->GetPlayerID()); if (newModel->ToCModel() && m_Model->ToCModel()) + { newModel->ToCModel()->CopyAnimationFrom(m_Model->ToCModel()); + // Copy flags that belong to this model instance (not those defined by the actor XML) + int instanceFlags = (MODELFLAG_SILHOUETTE_DISPLAY|MODELFLAG_SILHOUETTE_OCCLUDER) & m_Model->ToCModel()->GetFlags(); + newModel->ToCModel()->AddFlagsRec(instanceFlags); + } + delete m_Model; m_Model = newModel; m_Object = newObject; diff --git a/source/ps/VideoMode.cpp b/source/ps/VideoMode.cpp index 6c5d8853b6..378710e8fb 100644 --- a/source/ps/VideoMode.cpp +++ b/source/ps/VideoMode.cpp @@ -154,6 +154,7 @@ bool CVideoMode::InitSDL() int bpp = GetBestBPP(); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, g_VSync ? 1 : 0); diff --git a/source/renderer/PlayerRenderer.cpp b/source/renderer/PlayerRenderer.cpp index bcb89ff9b8..1b3643bcbe 100644 --- a/source/renderer/PlayerRenderer.cpp +++ b/source/renderer/PlayerRenderer.cpp @@ -131,7 +131,7 @@ void FastPlayerColorRender::PrepareTexture(int UNUSED(pass), CTexturePtr& textur void FastPlayerColorRender::PrepareModel(int UNUSED(pass), CModel* model) { // Get the player color - SMaterialColor colour = model->GetMaterial().GetPlayerColor(); + SMaterialColor colour = model->GetMaterial().GetObjectColor(); float* color = &colour.r; // because it's stored RGBA // Set the texture environment color the player color @@ -245,7 +245,7 @@ void SlowPlayerColorRender::PrepareModel(int pass, CModel* model) if (pass == 1) { // Get the player color - SMaterialColor colour = model->GetMaterial().GetPlayerColor(); + SMaterialColor colour = model->GetMaterial().GetObjectColor(); float* color = &colour.r; // because it's stored RGBA // Set the texture environment color the player color @@ -402,9 +402,45 @@ void LitPlayerColorRender::PrepareModel(int pass, CModel* model) if (pass == 0) { // Get the player color - SMaterialColor colour = model->GetMaterial().GetPlayerColor(); + SMaterialColor colour = model->GetMaterial().GetObjectColor(); // Send the player color glColor3f(colour.r, colour.g, colour.b); } } + +/////////////////////////////////////////////////////////////////////////////////////////////// +// SolidPlayerColorRender + +SolidPlayerColorRender::SolidPlayerColorRender() +{ +} + +SolidPlayerColorRender::~SolidPlayerColorRender() +{ +} + +int SolidPlayerColorRender::BeginPass(int UNUSED(pass)) +{ + ogl_tex_bind(0, 0); + + return STREAM_POS; +} + +bool SolidPlayerColorRender::EndPass(int UNUSED(pass)) +{ + return true; +} + +void SolidPlayerColorRender::PrepareTexture(int UNUSED(pass), CTexturePtr& UNUSED(texture)) +{ +} + +void SolidPlayerColorRender::PrepareModel(int UNUSED(pass), CModel* model) +{ + // 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 60c98d35de..5b072dcf8d 100644 --- a/source/renderer/PlayerRenderer.h +++ b/source/renderer/PlayerRenderer.h @@ -100,4 +100,21 @@ public: }; +/** + * Render all models using their player color without lighting. + */ +class SolidPlayerColorRender : public RenderModifier +{ +public: + SolidPlayerColorRender(); + ~SolidPlayerColorRender(); + + // Implementation + int BeginPass(int pass); + bool EndPass(int pass); + void PrepareTexture(int pass, CTexturePtr& texture); + void PrepareModel(int pass, CModel* model); +}; + + #endif diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index 9847aaeaa4..7e921fd137 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -274,6 +274,7 @@ public: // generic RenderModifiers that are supposed to be used directly RenderModifierPtr ModWireframe; RenderModifierPtr ModSolidColor; + RenderModifierPtr ModSolidPlayerColor; RenderModifierPtr ModTransparentShadow; RenderModifierPtr ModTransparentDepthShadow; @@ -355,6 +356,20 @@ public: const SViewPort &vp = camera.GetViewPort(); glViewport((GLint)vp.m_X,(GLint)vp.m_Y,(GLsizei)vp.m_Width,(GLsizei)vp.m_Height); } + + /** + * Renders all non-transparent models with the given modifiers. + */ + void CallModelRenderers(const RenderModifierPtr& modNormal, const RenderModifierPtr& modPlayer, int flags) + { + Model.Normal->Render(modNormal, flags); + if (Model.Normal != Model.NormalInstancing) + Model.NormalInstancing->Render(modNormal, flags); + + Model.Player->Render(modPlayer, flags); + if (Model.Player != Model.PlayerInstancing) + Model.PlayerInstancing->Render(modPlayer, flags); + } }; /////////////////////////////////////////////////////////////////////////////////// @@ -550,6 +565,7 @@ bool CRenderer::Open(int width, int height) SetFastPlayerColor(true); m->Model.ModPlayerLit = LitRenderModifierPtr(new LitPlayerColorRender); m->Model.ModSolidColor = RenderModifierPtr(new SolidColorRenderModifier); + m->Model.ModSolidPlayerColor = RenderModifierPtr(new SolidPlayerColorRender); m->Model.ModTransparentUnlit = RenderModifierPtr(new TransparentRenderModifier); m->Model.ModTransparentLit = LitRenderModifierPtr(new LitTransparentRenderModifier); m->Model.ModTransparentShadow = RenderModifierPtr(new TransparentShadowRenderModifier); @@ -807,7 +823,6 @@ void CRenderer::BeginFrame() m->Model.Transp = m->Model.pal_TranspFF[vertexType]; } - ////////////////////////////////////////////////////////////////////////////////////////// // SetClearColor: set color used to clear screen in BeginFrame() void CRenderer::SetClearColor(SColor4ub color) @@ -850,12 +865,7 @@ void CRenderer::RenderShadowMap() { PROFILE("render models"); - 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->CallModelRenderers(m->Model.ModSolidColor, m->Model.ModSolidColor, MODELFLAG_CASTSHADOWS); } { @@ -928,23 +938,13 @@ void CRenderer::RenderModels() glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); } - 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); + m->CallModelRenderers(m->Model.ModNormal, 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->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); + m->CallModelRenderers(m->Model.ModWireframe, m->Model.ModWireframe, 0); } } @@ -1096,7 +1096,7 @@ void CRenderer::RenderReflections() // Make the depth buffer work backwards; there seems to be some oddness with // oblique frustum clipping and the "sign" parameter here glClearDepth(0); - glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDepthFunc(GL_GEQUAL); // Render sky, terrain and models @@ -1164,7 +1164,7 @@ void CRenderer::RenderRefractions() // oblique frustum clipping and the "sign" parameter here glClearDepth(0); glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // a neutral gray to blend in with shores - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDepthFunc(GL_GEQUAL); // Render terrain and models @@ -1192,6 +1192,86 @@ void CRenderer::RenderRefractions() } +void CRenderer::RenderSilhouettes() +{ + PROFILE("render silhouettes"); + + // Render silhouettes of units hidden behind terrain or occluders. + // To avoid breaking the standard rendering of alpha-blended objects, this + // has to be done in a separate pass. + // First we render all occluders into depth, then render all units with + // inverted depth test so any behind an occluder will get drawn in a constant + // colour. + + float silhouetteAlpha = 0.75f; + + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + glColorMask(0, 0, 0, 0); + + // Render occluders: + + { + PROFILE("render patches"); + m->terrainRenderer->RenderPatches(); + } + + { + PROFILE("render model occluders"); + m->CallModelRenderers(m->Model.ModSolidColor, m->Model.ModSolidColor, MODELFLAG_SILHOUETTE_OCCLUDER); + } + + { + PROFILE("render transparent occluders"); + // Reuse the depth shadow modifier to get alpha-tested rendering + m->Model.Transp->Render(m->Model.ModTransparentDepthShadow, MODELFLAG_SILHOUETTE_OCCLUDER); + } + + glDepthFunc(GL_GEQUAL); + glColorMask(1, 1, 1, 1); + + // Render more efficiently if alpha == 1 + if (silhouetteAlpha == 1.f) + { + // Ideally we'd render objects back-to-front so nearer silhouettes would + // appear on top, but sorting has non-zero cost. So we'll keep the depth + // write enabled, to do the opposite - far objects will consistently appear + // on top. + glDepthMask(0); + } + else + { + // Since we can't sort, we'll use the stencil buffer to ensure we only draw + // a pixel once (using the colour of whatever model happens to be drawn first). + glEnable(GL_BLEND); + glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); + glBlendColor(0, 0, 0, silhouetteAlpha); + + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_NOTEQUAL, 1, -1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + + // TODO: For performance, we probably ought to do a quick raycasting check + // to see which units are likely blocked by occluders and not bother + // rendering any of the others + + { + PROFILE("render models"); + m->CallModelRenderers(m->Model.ModSolidPlayerColor, m->Model.ModSolidPlayerColor, MODELFLAG_SILHOUETTE_DISPLAY); + // (This won't render transparent objects with SILHOUETTE_DISPLAY - will + // we have any units that need that?) + } + + // Restore state + glDepthFunc(GL_LEQUAL); + glDepthMask(1); + glDisable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendColor(0, 0, 0, 0); + glDisable(GL_STENCIL_TEST); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// // RenderSubmissions: force rendering of any batched objects void CRenderer::RenderSubmissions() @@ -1241,7 +1321,7 @@ void CRenderer::RenderSubmissions() RenderReflections(); RenderRefractions(); glClearColor(m_ClearColor[0],m_ClearColor[1],m_ClearColor[2],m_ClearColor[3]); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } // render submitted patches and models @@ -1290,6 +1370,8 @@ void CRenderer::RenderSubmissions() // on all the time, so it might not be worth worrying about. } + RenderSilhouettes(); + // Clean up texture blend mode so particles and other things render OK // (really this should be cleaned up by whoever set it) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h index e37123d869..847b0abfe4 100644 --- a/source/renderer/Renderer.h +++ b/source/renderer/Renderer.h @@ -347,6 +347,8 @@ protected: void RenderModels(); void RenderTransparentModels(); + void RenderSilhouettes(); + // shadow rendering stuff void RenderShadowMap(); diff --git a/source/simulation2/components/CCmpTemplateManager.cpp b/source/simulation2/components/CCmpTemplateManager.cpp index 77705f121f..0aa7e0627d 100644 --- a/source/simulation2/components/CCmpTemplateManager.cpp +++ b/source/simulation2/components/CCmpTemplateManager.cpp @@ -368,6 +368,8 @@ void CCmpTemplateManager::ConstructTemplateActor(const std::string& actorName, C "" "" "" + name + "" + "false" + "false" "" ""; @@ -479,6 +481,10 @@ void CCmpTemplateManager::CopyPreviewSubset(CParamNode& out, const CParamNode& i // Corpses should include decay components and un-inactivate them if (out.GetChild("Entity").GetChild("Decay").IsOk()) CParamNode::LoadXMLString(out, ""); + + // Corpses shouldn't display silhouettes (especially since they're often half underground) + if (out.GetChild("Entity").GetChild("VisualActor").IsOk()) + CParamNode::LoadXMLString(out, "false"); } } diff --git a/source/simulation2/components/CCmpVisualActor.cpp b/source/simulation2/components/CCmpVisualActor.cpp index a5a1dbc1bf..e238403b1b 100644 --- a/source/simulation2/components/CCmpVisualActor.cpp +++ b/source/simulation2/components/CCmpVisualActor.cpp @@ -92,7 +92,13 @@ public: "" "" "" - ""; + "" + "" + "" + "" + "" + "" + ""; } virtual void Init(const CParamNode& paramNode) @@ -119,6 +125,15 @@ public: return; } + u32 modelFlags = 0; + if (paramNode.GetChild("SilhouetteDisplay").ToBool()) + modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY; + if (paramNode.GetChild("SilhouetteOccluder").ToBool()) + modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER; + + if (m_Unit->GetModel().ToCModel()) + m_Unit->GetModel().ToCModel()->AddFlagsRec(modelFlags); + m_Unit->SetID(GetEntityId()); SelectAnimation("idle", false, 0.f, L""); @@ -349,6 +364,8 @@ public: m_Unit->GetModel().SetShadingColor(shading); m_Unit->GetModel().SetPlayerID(playerID); + + // TODO: should copy/reset silhouette flags } private: