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: