diff --git a/source/graphics/Decal.cpp b/source/graphics/Decal.cpp
new file mode 100644
index 0000000000..30e6fc5fb8
--- /dev/null
+++ b/source/graphics/Decal.cpp
@@ -0,0 +1,107 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "Decal.h"
+
+#include "graphics/Terrain.h"
+#include "maths/MathUtil.h"
+
+CModelAbstract* CModelDecal::Clone() const
+{
+ CModelDecal* clone = new CModelDecal(m_Terrain, m_Decal);
+ return clone;
+}
+
+void CModelDecal::CalcVertexExtents(ssize_t& i0, ssize_t& j0, ssize_t& i1, ssize_t& j1)
+{
+ CVector3D corner0(m_Decal.m_OffsetX + m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ + m_Decal.m_SizeZ/2);
+ CVector3D corner1(m_Decal.m_OffsetX + m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ - m_Decal.m_SizeZ/2);
+ CVector3D corner2(m_Decal.m_OffsetX - m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ - m_Decal.m_SizeZ/2);
+ CVector3D corner3(m_Decal.m_OffsetX - m_Decal.m_SizeX/2, 0, m_Decal.m_OffsetZ + m_Decal.m_SizeZ/2);
+
+ corner0 = GetTransform().Transform(corner0);
+ corner1 = GetTransform().Transform(corner1);
+ corner2 = GetTransform().Transform(corner2);
+ corner3 = GetTransform().Transform(corner3);
+
+ i0 = floor(std::min(std::min(corner0.X, corner1.X), std::min(corner2.X, corner3.X)) / CELL_SIZE);
+ j0 = floor(std::min(std::min(corner0.Z, corner1.Z), std::min(corner2.Z, corner3.Z)) / CELL_SIZE);
+ i1 = ceil(std::max(std::max(corner0.X, corner1.X), std::max(corner2.X, corner3.X)) / CELL_SIZE);
+ j1 = ceil(std::max(std::max(corner0.Z, corner1.Z), std::max(corner2.Z, corner3.Z)) / CELL_SIZE);
+
+ i0 = clamp(i0, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1);
+ j0 = clamp(j0, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1);
+ i1 = clamp(i1, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1);
+ j1 = clamp(j1, (ssize_t)0, m_Terrain->GetVerticesPerSide()-1);
+}
+
+void CModelDecal::CalcBounds()
+{
+ ssize_t i0, j0, i1, j1;
+ CalcVertexExtents(i0, j0, i1, j1);
+ m_Bounds = m_Terrain->GetVertexesBound(i0, j0, i1, j1);
+}
+
+void CModelDecal::SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1)
+{
+ // Check if there's no intersection between the dirty range and this decal
+ ssize_t bi0, bj0, bi1, bj1;
+ CalcVertexExtents(bi0, bj0, bi1, bj1);
+ if (bi1 < i0 || bi0 > i1 || bj1 < j0 || bj0 > j1)
+ return;
+
+ SetDirty(RENDERDATA_UPDATE_VERTICES);
+}
+
+void CModelDecal::InvalidatePosition()
+{
+ m_PositionValid = false;
+}
+
+void CModelDecal::ValidatePosition()
+{
+ if (m_PositionValid)
+ {
+ debug_assert(!m_Parent || m_Parent->m_PositionValid);
+ return;
+ }
+
+ if (m_Parent && !m_Parent->m_PositionValid)
+ {
+ // Make sure we don't base our calculations on
+ // a parent animation state that is out of date.
+ m_Parent->ValidatePosition();
+
+ // Parent will recursively call our validation.
+ debug_assert(m_PositionValid);
+ return;
+ }
+
+ m_PositionValid = true;
+}
+
+void CModelDecal::SetTransform(const CMatrix3D& transform)
+{
+ CMatrix3D newTransform = transform;
+ newTransform.SetYRotation(m_Decal.m_Angle);
+ newTransform.Concatenate(transform);
+
+ CRenderableObject::SetTransform(newTransform);
+ InvalidatePosition();
+}
diff --git a/source/graphics/Decal.h b/source/graphics/Decal.h
new file mode 100644
index 0000000000..311d098112
--- /dev/null
+++ b/source/graphics/Decal.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#ifndef INCLUDED_DECAL
+#define INCLUDED_DECAL
+
+#include "graphics/ModelAbstract.h"
+#include "graphics/Texture.h"
+
+class CTerrain;
+
+/**
+ * Terrain decal definition.
+ * Decals are rectangular textures that are projected vertically downwards
+ * onto the terrain.
+ */
+struct SDecal
+{
+ SDecal(const CTexturePtr& texture, float sizeX, float sizeZ, float angle,
+ float offsetX, float offsetZ, bool floating)
+ : m_Texture(texture), m_SizeX(sizeX), m_SizeZ(sizeZ), m_Angle(angle),
+ m_OffsetX(offsetX), m_OffsetZ(offsetZ), m_Floating(floating)
+ {
+ }
+
+ CTexturePtr m_Texture;
+ float m_SizeX;
+ float m_SizeZ;
+ float m_Angle;
+ float m_OffsetX;
+ float m_OffsetZ;
+ bool m_Floating;
+};
+
+class CModelDecal : public CModelAbstract
+{
+public:
+ CModelDecal(CTerrain* terrain, const SDecal& decal)
+ : m_Terrain(terrain), m_Decal(decal)
+ {
+ }
+
+ /// Dynamic cast
+ virtual CModelDecal* ToCModelDecal()
+ {
+ return this;
+ }
+
+ virtual CModelAbstract* Clone() const;
+
+ virtual void SetDirtyRec(int dirtyflags)
+ {
+ SetDirty(dirtyflags);
+ }
+
+ virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1);
+
+ virtual void CalcBounds();
+ virtual void ValidatePosition();
+ virtual void InvalidatePosition();
+ virtual void SetTransform(const CMatrix3D& transform);
+
+ /**
+ * Compute the terrain vertex indexes that bound the decal's
+ * projection onto the terrain.
+ * The returned indexes are clamped to the terrain size.
+ */
+ void CalcVertexExtents(ssize_t& i0, ssize_t& j0, ssize_t& i1, ssize_t& j1);
+
+ CTerrain* m_Terrain;
+ SDecal m_Decal;
+};
+
+#endif // INCLUDED_DECAL
diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp
index b54b645863..f1f2f6b596 100644
--- a/source/graphics/GameView.cpp
+++ b/source/graphics/GameView.cpp
@@ -543,17 +543,6 @@ void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
}
-static void MarkUpdateColorRecursive(CModel& model)
-{
- model.SetDirty(RENDERDATA_UPDATE_COLOR);
-
- const std::vector& props = model.GetProps();
- for(size_t i = 0; i < props.size(); ++i) {
- debug_assert(props[i].m_Model);
- MarkUpdateColorRecursive(*props[i].m_Model);
- }
-}
-
void CGameView::CheckLightEnv()
{
if (m->CachedLightEnv == g_LightEnv)
@@ -569,9 +558,8 @@ void CGameView::CheckLightEnv()
pTerrain->MakeDirty(RENDERDATA_UPDATE_COLOR);
const std::vector& units = m->Game->GetWorld()->GetUnitManager().GetUnits();
- for(size_t i = 0; i < units.size(); ++i) {
- MarkUpdateColorRecursive(units[i]->GetModel());
- }
+ for (size_t i = 0; i < units.size(); ++i)
+ units[i]->GetModel().SetDirtyRec(RENDERDATA_UPDATE_COLOR);
}
diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp
index 5192d2e073..423cc03dd9 100644
--- a/source/graphics/Model.cpp
+++ b/source/graphics/Model.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -39,10 +39,9 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constructor
CModel::CModel(CSkeletonAnimManager& skeletonAnimManager)
- : m_Parent(NULL), m_Flags(0), m_Anim(NULL), m_AnimTime(0),
+ : m_Flags(0), m_Anim(NULL), m_AnimTime(0),
m_BoneMatrices(NULL), m_InverseBindBoneMatrices(NULL),
m_AmmoPropPoint(NULL), m_AmmoLoadedProp(0),
- m_PositionValid(false), m_ShadingColor(1,1,1,1), m_PlayerID((size_t)-1),
m_SkeletonAnimManager(skeletonAnimManager)
{
}
@@ -51,23 +50,6 @@ CModel::CModel(CSkeletonAnimManager& skeletonAnimManager)
// Destructor
CModel::~CModel()
{
- // Detach us from our parent
- if (m_Parent)
- {
- for(std::vector::iterator iter = m_Parent->m_Props.begin();
- iter != m_Parent->m_Props.end();
- ++iter)
- {
- if (iter->m_Model == this)
- {
- m_Parent->m_Props.erase(iter);
- break;
- }
- }
-
- m_Parent = 0;
- }
-
ReleaseData();
}
@@ -77,12 +59,11 @@ void CModel::ReleaseData()
{
delete[] m_BoneMatrices;
delete[] m_InverseBindBoneMatrices;
+
for (size_t i = 0; i < m_Props.size(); ++i)
- {
- m_Props[i].m_Model->m_Parent = 0;
delete m_Props[i].m_Model;
- }
m_Props.clear();
+
m_pModelDef = CModelDefPtr();
m_Texture.reset();
@@ -177,7 +158,7 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
// at the origin. The box is later re-transformed onto the object, without
// having to recalculate the size of the box.
CMatrix3D transform, oldtransform = GetTransform();
- CModel* oldparent = m_Parent;
+ CModelAbstract* oldparent = m_Parent;
m_Parent = 0;
transform.SetIdentity();
@@ -384,7 +365,7 @@ void CModel::CopyAnimationFrom(CModel* source)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AddProp: add a prop to the model on the given point
-void CModel::AddProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry)
+void CModel::AddProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry)
{
// position model according to prop point position
model->SetTransform(point->m_Transform);
@@ -397,7 +378,7 @@ void CModel::AddProp(const SPropPoint* point, CModel* model, CObjectEntry* objec
m_Props.push_back(prop);
}
-void CModel::AddAmmoProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry)
+void CModel::AddAmmoProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry)
{
AddProp(point, model, objectentry);
m_AmmoPropPoint = point;
@@ -427,16 +408,20 @@ void CModel::HideAmmoProp()
m_Props[i].m_Hidden = (i == m_AmmoLoadedProp);
}
-CModel* CModel::FindFirstAmmoProp()
+CModelAbstract* CModel::FindFirstAmmoProp()
{
if (m_AmmoPropPoint)
return m_Props[m_AmmoLoadedProp].m_Model;
for (size_t i = 0; i < m_Props.size(); ++i)
{
- CModel* model = m_Props[i].m_Model->FindFirstAmmoProp();
- if (model)
- return model;
+ CModel* propModel = m_Props[i].m_Model->ToCModel();
+ if (propModel)
+ {
+ CModelAbstract* model = propModel->FindFirstAmmoProp();
+ if (model)
+ return model;
+ }
}
return NULL;
@@ -444,7 +429,7 @@ CModel* CModel::FindFirstAmmoProp()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Clone: return a clone of this model
-CModel* CModel::Clone() const
+CModelAbstract* CModel::Clone() const
{
CModel* clone = new CModel(m_SkeletonAnimManager);
clone->m_ObjectBounds = m_ObjectBounds;
@@ -473,7 +458,6 @@ void CModel::SetTransform(const CMatrix3D& transform)
{
// call base class to set transform on this object
CRenderableObject::SetTransform(transform);
- InvalidateBounds();
InvalidatePosition();
}
@@ -486,7 +470,7 @@ void CModel::SetMaterial(const CMaterial &material)
void CModel::SetPlayerID(size_t id)
{
- m_PlayerID = id;
+ CModelAbstract::SetPlayerID(id);
if (id != (size_t)-1)
m_Material.SetPlayerColor(id);
@@ -495,11 +479,6 @@ void CModel::SetPlayerID(size_t id)
it->m_Model->SetPlayerID(id);
}
-size_t CModel::GetPlayerID()
-{
- return m_PlayerID;
-}
-
void CModel::SetPlayerColor(const CColor& colour)
{
m_Material.SetPlayerColor(colour);
@@ -507,7 +486,8 @@ void CModel::SetPlayerColor(const CColor& colour)
void CModel::SetShadingColor(const CColor& colour)
{
- m_ShadingColor = colour;
+ CModelAbstract::SetShadingColor(colour);
+
for (std::vector::iterator it = m_Props.begin(); it != m_Props.end(); ++it)
it->m_Model->SetShadingColor(colour);
}
diff --git a/source/graphics/Model.h b/source/graphics/Model.h
index a69f1a4ea9..a06a0eede0 100644
--- a/source/graphics/Model.h
+++ b/source/graphics/Model.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -24,10 +24,10 @@
#include
-#include "Texture.h"
-#include "MeshManager.h"
-#include "RenderableObject.h"
-#include "Material.h"
+#include "graphics/Texture.h"
+#include "graphics/Material.h"
+#include "graphics/MeshManager.h"
+#include "graphics/ModelAbstract.h"
#include "ps/Overlay.h"
struct SPropPoint;
@@ -42,7 +42,7 @@ class CSkeletonAnimManager;
///////////////////////////////////////////////////////////////////////////////
// CModel: basically, a mesh object - holds the texturing and skinning
// information for a model in game
-class CModel : public CRenderableObject
+class CModel : public CModelAbstract
{
NONCOPYABLE(CModel);
@@ -52,7 +52,7 @@ public:
Prop() : m_Point(0), m_Model(0), m_ObjectEntry(0), m_Hidden(false) {}
const SPropPoint* m_Point;
- CModel* m_Model;
+ CModelAbstract* m_Model;
CObjectEntry* m_ObjectEntry;
bool m_Hidden; // temporarily removed from rendering
@@ -64,10 +64,16 @@ public:
// destructor
~CModel();
+ /// Dynamic cast
+ virtual CModel* ToCModel()
+ {
+ return this;
+ }
+
// setup model from given geometry
bool InitModel(const CModelDefPtr& modeldef);
// calculate the world space bounds of this model
- void CalcBounds();
+ virtual void CalcBounds();
// update this model's state; 'time' is the absolute time since the start of the animation, in MS
void UpdateTo(float time);
@@ -80,18 +86,14 @@ public:
void SetMaterial(const CMaterial &material);
// set the model's player ID, recursively through props
void SetPlayerID(size_t id);
- // get the model's player ID, recursively through props; initial default is (size_t)-1
- size_t GetPlayerID();
// set the model's player colour
- void SetPlayerColor(const CColor& colour);
+ virtual void SetPlayerColor(const CColor& colour);
// set the models mod color
- void SetShadingColor(const CColor& colour);
+ virtual void SetShadingColor(const CColor& colour);
// get the model's texture
CTexturePtr& GetTexture() { return m_Texture; }
// get the model's material
CMaterial& GetMaterial() { return m_Material; }
- // get the model's shading color
- CColor GetShadingColor() { return m_ShadingColor; }
// set the given animation as the current animation on this model
bool SetAnimation(CSkeletonAnim* anim, bool once = false);
@@ -109,13 +111,19 @@ public:
int GetFlags() const { return m_Flags; }
// recurse down tree setting dirty bits
- void SetDirtyRec(int dirtyflags) {
+ virtual void SetDirtyRec(int dirtyflags) {
SetDirty(dirtyflags);
for (size_t i=0;iSetDirtyRec(dirtyflags);
}
}
+ virtual void SetTerrainDirty(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1)
+ {
+ for (size_t i = 0; i < m_Props.size(); ++i)
+ m_Props[i].m_Model->SetTerrainDirty(i0, j0, i1, j1);
+ }
+
// calculate object space bounds of this model, based solely on vertex positions
void CalcObjectBounds();
// calculate bounds encompassing all vertex positions for given animation
@@ -123,12 +131,12 @@ public:
/**
* Set transform of this object.
- *
+ *
* @note In order to ensure that all child props are updated properly,
* you must call ValidatePosition().
*/
- void SetTransform(const CMatrix3D& transform);
-
+ virtual void SetTransform(const CMatrix3D& transform);
+
/**
* Return whether this is a skinned/skeletal model. If it is, Get*BoneMatrices()
* will return valid non-NULL arrays.
@@ -159,13 +167,13 @@ public:
/**
* Add a prop to the model on the given point.
*/
- void AddProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry);
+ void AddProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry);
/**
* Add a prop to the model on the given point, and treat it as the ammo prop.
* The prop will be hidden by default.
*/
- void AddAmmoProp(const SPropPoint* point, CModel* model, CObjectEntry* objectentry);
+ void AddAmmoProp(const SPropPoint* point, CModelAbstract* model, CObjectEntry* objectentry);
/**
* Show the ammo prop (if any), and hide any other props on that prop point.
@@ -180,36 +188,30 @@ public:
/**
* Find the first prop used for ammo, by this model or its own props.
*/
- CModel* FindFirstAmmoProp();
+ CModelAbstract* FindFirstAmmoProp();
// return prop list
std::vector& GetProps() { return m_Props; }
const std::vector& GetProps() const { return m_Props; }
// return a clone of this model
- CModel* Clone() const;
+ virtual CModelAbstract* Clone() const;
/**
* Ensure that both the transformation and the bone
* matrices are correct for this model and all its props.
*/
- void ValidatePosition();
-
-private:
- // delete anything allocated by the model
- void ReleaseData();
+ virtual void ValidatePosition();
/**
* Mark this model's position and bone matrices,
* and all props' positions as invalid.
*/
- void InvalidatePosition();
-
- /**
- * If non-null, m_Parent points to the model that we
- * are attached to.
- */
- CModel* m_Parent;
+ virtual void InvalidatePosition();
+
+private:
+ // delete anything allocated by the model
+ void ReleaseData();
// object flags
int m_Flags;
@@ -244,16 +246,6 @@ private:
*/
size_t m_AmmoLoadedProp;
- /**
- * true if both transform and and bone matrices are valid.
- */
- bool m_PositionValid;
-
- // modulating color
- CColor m_ShadingColor;
-
- size_t m_PlayerID;
-
// manager object which can load animations for us
CSkeletonAnimManager& m_SkeletonAnimManager;
};
diff --git a/source/graphics/ObjectBase.cpp b/source/graphics/ObjectBase.cpp
index e7862b330b..a6f158b388 100644
--- a/source/graphics/ObjectBase.cpp
+++ b/source/graphics/ObjectBase.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -61,6 +61,7 @@ bool CObjectBase::Load(const VfsPath& pathname)
EL(mesh);
EL(texture);
EL(colour);
+ EL(decal);
AT(file);
AT(name);
AT(speed);
@@ -69,6 +70,11 @@ bool CObjectBase::Load(const VfsPath& pathname)
AT(attachpoint);
AT(actor);
AT(frequency);
+ AT(width);
+ AT(depth);
+ AT(angle);
+ AT(offsetx);
+ AT(offsetz);
#undef AT
#undef EL
@@ -130,20 +136,33 @@ bool CObjectBase::Load(const VfsPath& pathname)
currentVariant->m_Frequency = attr.Value.ToInt();
}
-
XERO_ITER_EL(variant, option)
{
int option_name = option.GetNodeName();
if (option_name == el_mesh)
+ {
currentVariant->m_ModelFilename = VfsPath(L"art/meshes")/(std::wstring)option.GetText().FromUTF8();
-
+ }
else if (option_name == el_texture)
+ {
currentVariant->m_TextureFilename = VfsPath(L"art/textures/skins")/(std::wstring)option.GetText().FromUTF8();
-
+ }
+ else if (option_name == el_decal)
+ {
+ XMBAttributeList attrs = option.GetAttributes();
+ Decal decal;
+ decal.m_SizeX = attrs.GetNamedItem(at_width).ToFloat();
+ decal.m_SizeZ = attrs.GetNamedItem(at_depth).ToFloat();
+ decal.m_Angle = DEGTORAD(attrs.GetNamedItem(at_angle).ToFloat());
+ decal.m_OffsetX = attrs.GetNamedItem(at_offsetx).ToFloat();
+ decal.m_OffsetZ = attrs.GetNamedItem(at_offsetz).ToFloat();
+ currentVariant->m_Decal = decal;
+ }
else if (option_name == el_colour)
+ {
currentVariant->m_Color = option.GetText();
-
+ }
else if (option_name == el_animations)
{
XERO_ITER_EL(option, anim_element)
@@ -362,6 +381,9 @@ const CObjectBase::Variation CObjectBase::BuildVariation(const std::vector&
if (! var.m_ModelFilename.empty())
variation.model = var.m_ModelFilename;
+ if (var.m_Decal.m_SizeX && var.m_Decal.m_SizeZ)
+ variation.decal = var.m_Decal;
+
if (! var.m_Color.empty())
variation.color = var.m_Color;
diff --git a/source/graphics/ObjectBase.h b/source/graphics/ObjectBase.h
index 693446f325..143ed5f9c1 100644
--- a/source/graphics/ObjectBase.h
+++ b/source/graphics/ObjectBase.h
@@ -33,7 +33,8 @@ class CObjectBase
NONCOPYABLE(CObjectBase);
public:
- struct Anim {
+ struct Anim
+ {
// constructor
Anim() : m_Speed(1.f), m_ActionPos(-1.f), m_ActionPos2(-1.f) {}
@@ -49,20 +50,34 @@ public:
float m_ActionPos2;
};
- struct Prop {
+ struct Prop
+ {
// name of the prop point to attach to - "Prop01", "Prop02", "Head", "LeftHand", etc ..
CStr m_PropPointName;
// name of the model file - art/actors/props/sword.xml or whatever
VfsPath m_ModelName;
};
+ struct Decal
+ {
+ Decal() : m_SizeX(0.f), m_SizeZ(0.f), m_Angle(0.f), m_OffsetX(0.f), m_OffsetZ(0.f) {}
+
+ float m_SizeX;
+ float m_SizeZ;
+ float m_Angle;
+ float m_OffsetX;
+ float m_OffsetZ;
+ };
+
struct Variant
{
Variant() : m_Frequency(0) {}
+
CStr m_VariantName; // lowercase name
int m_Frequency;
VfsPath m_ModelFilename;
VfsPath m_TextureFilename;
+ Decal m_Decal;
CStr m_Color;
std::vector m_Anims;
@@ -73,6 +88,7 @@ public:
{
VfsPath texture;
VfsPath model;
+ Decal decal;
CStr color;
std::multimap props;
std::multimap anims;
diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp
index 3fdb7ae958..ea3b023a65 100644
--- a/source/graphics/ObjectEntry.cpp
+++ b/source/graphics/ObjectEntry.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -18,18 +18,21 @@
#include "precompiled.h"
#include "ObjectEntry.h"
-#include "ObjectManager.h"
-#include "ObjectBase.h"
-#include "Model.h"
-#include "ModelDef.h"
-#include "ps/CLogger.h"
-#include "MaterialManager.h"
-#include "MeshManager.h"
-#include "SkeletonAnim.h"
-#include "TextureManager.h"
-#include "renderer/Renderer.h"
+#include "graphics/Decal.h"
+#include "graphics/MaterialManager.h"
+#include "graphics/MeshManager.h"
+#include "graphics/Model.h"
+#include "graphics/ModelDef.h"
+#include "graphics/ObjectBase.h"
+#include "graphics/ObjectManager.h"
+#include "graphics/SkeletonAnim.h"
+#include "graphics/TextureManager.h"
#include "lib/rand.h"
+#include "ps/CLogger.h"
+#include "ps/Game.h"
+#include "ps/World.h"
+#include "renderer/Renderer.h"
#include
@@ -70,6 +73,25 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections
m_Color = CColor(r/255.0f, g/255.0f, b/255.0f, 1.0f);
}
+ if (variation.decal.m_SizeX && variation.decal.m_SizeZ)
+ {
+ CTextureProperties textureProps(m_TextureName);
+
+ // Decals should be transparent, so clamp to the border (default 0,0,0,0)
+ textureProps.SetWrap(GL_CLAMP_TO_BORDER);
+
+ CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
+ texture->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture
+
+ SDecal decal(texture,
+ variation.decal.m_SizeX, variation.decal.m_SizeZ,
+ variation.decal.m_Angle, variation.decal.m_OffsetX, variation.decal.m_OffsetZ,
+ m_Base->m_Properties.m_FloatOnWater);
+ m_Model = new CModelDecal(g_Game->GetWorld()->GetTerrain(), decal);
+
+ return true;
+ }
+
std::vector props;
for (std::multimap::iterator it = variation.props.begin(); it != variation.props.end(); ++it)
@@ -77,11 +99,6 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections
// Build the model:
-/*
- // remember the old model so we can replace any models using it later on
- CModelDefPtr oldmodeldef = m_Model ? m_Model->GetModelDef() : CModelDefPtr();
-*/
-
// try and create a model
CModelDefPtr modeldef (objectManager.GetMeshManager().GetMesh(m_ModelName));
if (!modeldef)
@@ -91,20 +108,21 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections
}
// delete old model, create new
+ CModel* model = new CModel(objectManager.GetSkeletonAnimManager());
delete m_Model;
- m_Model = new CModel(objectManager.GetSkeletonAnimManager());
- m_Model->SetMaterial(g_MaterialManager.LoadMaterial(m_Base->m_Material));
- m_Model->InitModel(modeldef);
- m_Model->SetPlayerColor(m_Color);
+ m_Model = model;
+ model->SetMaterial(g_MaterialManager.LoadMaterial(m_Base->m_Material));
+ model->InitModel(modeldef);
+ model->SetPlayerColor(m_Color);
CTextureProperties textureProps(m_TextureName);
textureProps.SetWrap(GL_CLAMP_TO_EDGE);
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
texture->Prefetch(); // if we've loaded this model we're probably going to render it soon, so prefetch its texture
- m_Model->SetTexture(texture);
+ model->SetTexture(texture);
// calculate initial object space bounds, based on vertex positions
- m_Model->CalcObjectBounds();
+ model->CalcObjectBounds();
// load the animations
for (std::multimap::iterator it = variation.anims.begin(); it != variation.anims.end(); ++it)
@@ -119,7 +137,7 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections
if (! it->second.m_FileName.empty())
{
- CSkeletonAnim* anim = m_Model->BuildAnimation(it->second.m_FileName, name, it->second.m_Speed, it->second.m_ActionPos, it->second.m_ActionPos2);
+ CSkeletonAnim* anim = model->BuildAnimation(it->second.m_FileName, name, it->second.m_Speed, it->second.m_ActionPos, it->second.m_ActionPos2);
if (anim)
m_Animations.insert(std::make_pair(name, anim));
}
@@ -137,12 +155,12 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections
m_Animations.insert(std::make_pair("idle", anim));
// Ignore errors, since they're probably saying this is a non-animated model
- m_Model->SetAnimation(anim);
+ model->SetAnimation(anim);
}
else
{
// start up idling
- if (!m_Model->SetAnimation(GetRandomAnimation("idle")))
+ if (!model->SetAnimation(GetRandomAnimation("idle")))
LOGERROR(L"Failed to set idle animation in model \"%ls\"", m_ModelName.string().c_str());
}
@@ -184,12 +202,13 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections
const SPropPoint* proppoint = modeldef->FindPropPoint(ppn.c_str());
if (proppoint)
{
- CModel* propmodel = oe->m_Model->Clone();
+ CModelAbstract* propmodel = oe->m_Model->Clone();
if (isAmmo)
- m_Model->AddAmmoProp(proppoint, propmodel, oe);
+ model->AddAmmoProp(proppoint, propmodel, oe);
else
- m_Model->AddProp(proppoint, propmodel, oe);
- propmodel->SetAnimation(oe->GetRandomAnimation("idle"));
+ model->AddProp(proppoint, propmodel, oe);
+ if (propmodel->ToCModel())
+ propmodel->ToCModel()->SetAnimation(oe->GetRandomAnimation("idle"));
}
else
LOGERROR(L"Failed to find matching prop point called \"%hs\" in model \"%ls\" for actor \"%ls\"", ppn.c_str(), m_ModelName.string().c_str(), m_Base->m_ShortName.c_str());
@@ -198,44 +217,9 @@ bool CObjectEntry::BuildVariation(const std::vector >& selections
// setup flags
if (m_Base->m_Properties.m_CastShadows)
{
- m_Model->SetFlags(m_Model->GetFlags()|MODELFLAG_CASTSHADOWS);
+ model->SetFlags(model->GetFlags()|MODELFLAG_CASTSHADOWS);
}
- // replace any units using old model to now use new model; also reprop models, if necessary
- // FIXME, RC - ugh, doesn't recurse correctly through props
-/*
- // (PT: Removed this, since I'm not entirely sure what it's useful for, and it
- // gets a bit confusing with randomised actors)
-
- const std::vector& units = g_UnitMan.GetUnits();
- for (size_t i = 0; i < units.size(); ++i)
- {
- CModel* unitmodel=units[i]->GetModel();
- if (unitmodel->GetModelDef() == oldmodeldef)
- {
- unitmodel->InitModel(m_Model->GetModelDef());
- unitmodel->SetFlags(m_Model->GetFlags());
-
- const std::vector& newprops = m_Model->GetProps();
- for (size_t j = 0; j < newprops.size(); j++)
- unitmodel->AddProp(newprops[j].m_Point, newprops[j].m_Model->Clone());
- }
-
- std::vector& mdlprops = unitmodel->GetProps();
- for (size_t j = 0; j < mdlprops.size(); j++)
- {
- CModel::Prop& prop = mdlprops[j];
- if (prop.m_Model)
- {
- if (prop.m_Model->GetModelDef() == oldmodeldef)
- {
- delete prop.m_Model;
- prop.m_Model = m_Model->Clone();
- }
- }
- }
- }
-*/
return true;
}
diff --git a/source/graphics/ObjectEntry.h b/source/graphics/ObjectEntry.h
index 1e721c7756..ca31abde78 100644
--- a/source/graphics/ObjectEntry.h
+++ b/source/graphics/ObjectEntry.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -18,7 +18,7 @@
#ifndef INCLUDED_OBJECTENTRY
#define INCLUDED_OBJECTENTRY
-class CModel;
+class CModelAbstract;
class CSkeletonAnim;
class CObjectBase;
class CObjectManager;
@@ -65,7 +65,7 @@ public:
std::vector GetAnimations(const CStr& animationName) const;
// corresponding model
- CModel* m_Model;
+ CModelAbstract* m_Model;
private:
typedef std::multimap SkeletonAnimMap;
diff --git a/source/graphics/RenderableObject.h b/source/graphics/RenderableObject.h
index 3d0a5240bc..1b642f8f18 100644
--- a/source/graphics/RenderableObject.h
+++ b/source/graphics/RenderableObject.h
@@ -53,6 +53,8 @@ public:
// some renderdata necessary for the renderer to actually render it
class CRenderableObject
{
+ NONCOPYABLE(CRenderableObject);
+
public:
// constructor
CRenderableObject() : m_RenderData(0), m_BoundsValid(false) {
@@ -63,6 +65,8 @@ public:
// set object transform
virtual void SetTransform(const CMatrix3D& transform) {
+ if (m_Transform == transform)
+ return;
// store transform, calculate inverse
m_Transform=transform;
m_Transform.GetInverse(m_InvTransform);
diff --git a/source/graphics/Terrain.cpp b/source/graphics/Terrain.cpp
index 2b7d828a95..3f05de6722 100644
--- a/source/graphics/Terrain.cpp
+++ b/source/graphics/Terrain.cpp
@@ -550,3 +550,32 @@ void CTerrain::MakeDirty(int dirtyFlags)
}
}
}
+
+CBound CTerrain::GetVertexesBound(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1)
+{
+ i0 = clamp(i0, (ssize_t)0, m_MapSize-1);
+ j0 = clamp(j0, (ssize_t)0, m_MapSize-1);
+ i1 = clamp(i1, (ssize_t)0, m_MapSize-1);
+ j1 = clamp(j1, (ssize_t)0, m_MapSize-1);
+
+ u16 minH = 65535;
+ u16 maxH = 0;
+
+ for (ssize_t j = j0; j <= j1; ++j)
+ {
+ for (ssize_t i = i0; i <= i1; ++i)
+ {
+ minH = std::min(minH, m_Heightmap[j*m_MapSize + i]);
+ maxH = std::max(maxH, m_Heightmap[j*m_MapSize + i]);
+ }
+ }
+
+ CBound bound;
+ bound[0].X = (float)(i0*CELL_SIZE);
+ bound[0].Y = (float)(minH*HEIGHT_SCALE);
+ bound[0].Z = (float)(j0*CELL_SIZE);
+ bound[1].X = (float)(i1*CELL_SIZE);
+ bound[1].Y = (float)(maxH*HEIGHT_SCALE);
+ bound[1].Z = (float)(j1*CELL_SIZE);
+ return bound;
+}
diff --git a/source/graphics/Terrain.h b/source/graphics/Terrain.h
index 1b1112ea75..98445fc72a 100644
--- a/source/graphics/Terrain.h
+++ b/source/graphics/Terrain.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -30,6 +30,7 @@ class CPatch;
class CMiniPatch;
class CFixedVector3D;
class CStr8;
+class CBound;
///////////////////////////////////////////////////////////////////////////////
// Terrain Constants:
@@ -134,6 +135,11 @@ public:
// mark the entire map as dirty
void MakeDirty(int dirtyFlags);
+ /**
+ * Returns a 3D bounding box encompassing the given vertex range (inclusive)
+ */
+ CBound GetVertexesBound(ssize_t i0, ssize_t j0, ssize_t i1, ssize_t j1);
+
// get the base colour for the terrain (typically pure white - other colours
// will interact badly with LOS - but used by the Actor Viewer tool)
SColor4ub GetBaseColour() const { return m_BaseColour; }
diff --git a/source/graphics/Unit.cpp b/source/graphics/Unit.cpp
index d6a395923c..6ca874855a 100644
--- a/source/graphics/Unit.cpp
+++ b/source/graphics/Unit.cpp
@@ -32,7 +32,10 @@ CUnit::CUnit(CObjectEntry* object, CObjectManager& objectManager,
m_ID(INVALID_ENTITY), m_ActorSelections(actorSelections),
m_ObjectManager(objectManager)
{
- m_Animation = new CUnitAnimation(*this);
+ if (m_Model->ToCModel())
+ m_Animation = new CUnitAnimation(m_ID, m_Model->ToCModel(), m_Object);
+ else
+ m_Animation = NULL;
}
CUnit::~CUnit()
@@ -63,7 +66,8 @@ CUnit* CUnit::Create(const CStrW& actorName, const std::set& selections, C
void CUnit::UpdateModel(float frameTime)
{
- m_Animation->Update(frameTime*1000.0f);
+ if (m_Animation)
+ m_Animation->Update(frameTime*1000.0f);
}
void CUnit::SetEntitySelection(const CStr& selection)
@@ -99,17 +103,28 @@ void CUnit::ReloadObject()
if (newObject && newObject != m_Object)
{
// Clone the new object's base (non-instance) model
- CModel* newModel = newObject->m_Model->Clone();
+ CModelAbstract* newModel = newObject->m_Model->Clone();
// Copy the old instance-specific settings from the old model to the new instance
newModel->SetTransform(m_Model->GetTransform());
newModel->SetPlayerID(m_Model->GetPlayerID());
- newModel->CopyAnimationFrom(m_Model);
+ if (newModel->ToCModel() && m_Model->ToCModel())
+ newModel->ToCModel()->CopyAnimationFrom(m_Model->ToCModel());
delete m_Model;
m_Model = newModel;
m_Object = newObject;
- m_Animation->ReloadUnit(); // TODO: maybe this should try to preserve animation state?
+ if (m_Model->ToCModel())
+ {
+ if (m_Animation)
+ m_Animation->ReloadUnit(m_Model->ToCModel(), m_Object); // TODO: maybe this should try to preserve animation state?
+ else
+ m_Animation = new CUnitAnimation(m_ID, m_Model->ToCModel(), m_Object);
+ }
+ else
+ {
+ SAFE_DELETE(m_Animation);
+ }
}
}
diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h
index 889c04b01c..ddec350470 100644
--- a/source/graphics/Unit.h
+++ b/source/graphics/Unit.h
@@ -23,7 +23,7 @@
#include "ps/CStr.h"
#include "simulation2/system/Entity.h" // entity_id_t
-class CModel;
+class CModelAbstract;
class CObjectEntry;
class CObjectManager;
class CSkeletonAnim;
@@ -52,9 +52,9 @@ public:
// get unit's template object
const CObjectEntry& GetObject() const { return *m_Object; }
// get unit's model data
- CModel& GetModel() const { return *m_Model; }
+ CModelAbstract& GetModel() const { return *m_Model; }
- CUnitAnimation& GetAnimation() { return *m_Animation; }
+ CUnitAnimation* GetAnimation() { return m_Animation; }
/**
* Update the model's animation.
@@ -80,7 +80,7 @@ private:
// object from which unit was created; never NULL
CObjectEntry* m_Object;
// object model representation; never NULL
- CModel* m_Model;
+ CModelAbstract* m_Model;
CUnitAnimation* m_Animation;
diff --git a/source/graphics/UnitAnimation.cpp b/source/graphics/UnitAnimation.cpp
index 9e38e87b66..7d7d000a8d 100644
--- a/source/graphics/UnitAnimation.cpp
+++ b/source/graphics/UnitAnimation.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -40,10 +40,11 @@ static float DesyncSpeed(float speed, float desync)
return speed * (1.f - desync + 2.f*desync*(rand(0, 256)/255.f));
}
-CUnitAnimation::CUnitAnimation(CUnit& unit)
-: m_Unit(unit), m_State("idle"), m_Looping(true), m_Speed(1.f), m_SyncRepeatTime(0.f), m_OriginalSpeed(1.f), m_Desync(0.f)
+CUnitAnimation::CUnitAnimation(entity_id_t ent, CModel* model, CObjectEntry* object)
+ : m_Entity(ent), m_State("idle"), m_Looping(true),
+ m_Speed(1.f), m_SyncRepeatTime(0.f), m_OriginalSpeed(1.f), m_Desync(0.f)
{
- ReloadUnit();
+ ReloadUnit(model, object);
}
void CUnitAnimation::AddModel(CModel* model, const CObjectEntry* object)
@@ -70,17 +71,22 @@ void CUnitAnimation::AddModel(CModel* model, const CObjectEntry* object)
const std::vector& props = model->GetProps();
for (std::vector::const_iterator it = props.begin(); it != props.end(); ++it)
{
- AddModel(it->m_Model, it->m_ObjectEntry);
+ CModel* propModel = it->m_Model->ToCModel();
+ if (propModel)
+ AddModel(propModel, it->m_ObjectEntry);
}
}
-void CUnitAnimation::ReloadUnit()
+void CUnitAnimation::ReloadUnit(CModel* model, const CObjectEntry* object)
{
+ m_Model = model;
+ m_Object = object;
+
m_AnimStates.clear();
- AddModel(&m_Unit.GetModel(), &m_Unit.GetObject());
+ AddModel(m_Model, m_Object);
}
-void CUnitAnimation::SetAnimationState(const CStr& name, bool once, float speed, float desync, bool keepSelection, const CStrW& actionSound)
+void CUnitAnimation::SetAnimationState(const CStr& name, bool once, float speed, float desync, const CStrW& actionSound)
{
m_Looping = !once;
m_OriginalSpeed = speed;
@@ -94,10 +100,7 @@ void CUnitAnimation::SetAnimationState(const CStr& name, bool once, float speed,
{
m_State = name;
- if (! keepSelection)
- m_Unit.SetEntitySelection(name);
-
- ReloadUnit();
+ ReloadUnit(m_Model, m_Object);
}
}
@@ -179,7 +182,7 @@ void CUnitAnimation::Update(float time)
{
CmpPtr cmpSoundManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (!cmpSoundManager.null())
- cmpSoundManager->PlaySoundGroup(m_ActionSound, m_Unit.GetID());
+ cmpSoundManager->PlaySoundGroup(m_ActionSound, m_Entity);
}
it->pastActionPos = true;
diff --git a/source/graphics/UnitAnimation.h b/source/graphics/UnitAnimation.h
index 1330b1d986..4190a969d9 100644
--- a/source/graphics/UnitAnimation.h
+++ b/source/graphics/UnitAnimation.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -20,6 +20,8 @@
#include "ps/CStr.h"
+#include "simulation2/system/Entity.h"
+
class CUnit;
class CModel;
class CSkeletonAnim;
@@ -37,7 +39,7 @@ public:
/**
* Construct for a given unit, defaulting to the "idle" animation.
*/
- CUnitAnimation(CUnit& unit);
+ CUnitAnimation(entity_id_t ent, CModel* model, CObjectEntry* object);
/**
* Start playing an animation.
@@ -52,10 +54,9 @@ public:
* @param once if true then the animation freezes on its last frame; otherwise it loops
* @param speed fraction of actor-defined speed to play back at (should typically be 1.0)
* @param desync maximum fraction of length/speed to randomly adjust timings (or 0.0 for no desyncing)
- * @param keepSelection if false then the random actor variation will have the selection @p name added
* @param actionSound sound group name to be played at the 'action' point in the animation, or empty string
*/
- void SetAnimationState(const CStr& name, bool once, float speed, float desync, bool keepSelection, const CStrW& actionSound);
+ void SetAnimationState(const CStr& name, bool once, float speed, float desync, const CStrW& actionSound);
/**
* Adjust the speed of the current animation, so that Update(repeatTime) will do a
@@ -82,7 +83,7 @@ public:
* Regenerate internal animation state from the models in the current unit.
* This should be called whenever the unit is changed externally, to keep this in sync.
*/
- void ReloadUnit();
+ void ReloadUnit(CModel* model, const CObjectEntry* object);
private:
struct SModelAnimState
@@ -99,7 +100,9 @@ private:
void AddModel(CModel* model, const CObjectEntry* object);
- CUnit& m_Unit;
+ entity_id_t m_Entity;
+ CModel* m_Model;
+ const CObjectEntry* m_Object;
CStr m_State;
bool m_Looping;
float m_OriginalSpeed;
diff --git a/source/maths/Bound.cpp b/source/maths/Bound.cpp
index 757962937f..2da01b5816 100644
--- a/source/maths/Bound.cpp
+++ b/source/maths/Bound.cpp
@@ -206,37 +206,37 @@ void CBound::IntersectFrustumConservative(const CFrustum& frustum)
///////////////////////////////////////////////////////////////////////////////
// Render the bounding box
-void CBound::Render()
+void CBound::Render() const
{
glBegin(GL_QUADS);
- glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
- glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
+ glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
+ glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
+ glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
+ glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
- glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
- glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
- glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
+ glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
+ glTexCoord2f(1, 0); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
+ glTexCoord2f(1, 1); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
+ glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
- glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
- glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
+ glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
+ glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
+ glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
+ glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
- glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
- glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
- glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
+ glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
+ glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
+ glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
+ glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[0].Y, m_Data[1].Z);
- glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
- glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
+ glTexCoord2f(0, 0); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[1].Z);
+ glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
+ glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
+ glTexCoord2f(0, 1); glVertex3f(m_Data[1].X, m_Data[0].Y, m_Data[0].Z);
- glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
- glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
- glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
+ glTexCoord2f(0, 0); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[0].Z);
+ glTexCoord2f(1, 0); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[0].Z);
+ glTexCoord2f(1, 1); glVertex3f(m_Data[1].X, m_Data[1].Y, m_Data[1].Z);
+ glTexCoord2f(0, 1); glVertex3f(m_Data[0].X, m_Data[1].Y, m_Data[1].Z);
glEnd();
}
diff --git a/source/maths/Bound.h b/source/maths/Bound.h
index 38b3642a79..7247acfafe 100644
--- a/source/maths/Bound.h
+++ b/source/maths/Bound.h
@@ -80,7 +80,7 @@ public:
/**
* Render: Render the surfaces of the bound object as polygons.
*/
- void Render();
+ void Render() const;
private:
CVector3D m_Data[2];
diff --git a/source/maths/Matrix3D.cpp b/source/maths/Matrix3D.cpp
index a60411c2f2..6dfac6aa8b 100644
--- a/source/maths/Matrix3D.cpp
+++ b/source/maths/Matrix3D.cpp
@@ -134,6 +134,14 @@ CMatrix3D& CMatrix3D::operator+=(const CMatrix3D& m)
return *this;
}
+bool CMatrix3D::operator==(const CMatrix3D &matrix) const
+{
+ for (int i = 0; i < 16; ++i)
+ if (matrix._data[i] != _data[i])
+ return false;
+ return true;
+}
+
//Sets the identity matrix
void CMatrix3D::SetIdentity ()
{
diff --git a/source/maths/Matrix3D.h b/source/maths/Matrix3D.h
index 2388b6a9fc..3d23262c7c 100644
--- a/source/maths/Matrix3D.h
+++ b/source/maths/Matrix3D.h
@@ -75,6 +75,9 @@ public:
// matrix addition/assignment
CMatrix3D& operator+=(const CMatrix3D &matrix);
+ // equality
+ bool operator==(const CMatrix3D &matrix) const;
+
// set this matrix to the identity matrix
void SetIdentity();
// set this matrix to the zero matrix
diff --git a/source/renderer/DecalRData.cpp b/source/renderer/DecalRData.cpp
new file mode 100644
index 0000000000..dde2d1066f
--- /dev/null
+++ b/source/renderer/DecalRData.cpp
@@ -0,0 +1,185 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "DecalRData.h"
+
+#include "graphics/Decal.h"
+#include "graphics/Model.h"
+#include "graphics/Terrain.h"
+#include "graphics/TextureManager.h"
+#include "ps/Game.h"
+#include "ps/Profile.h"
+#include "renderer/Renderer.h"
+#include "simulation2/Simulation2.h"
+#include "simulation2/components/ICmpWaterManager.h"
+
+// TODO: Currently each decal is a separate CDecalRData. We might want to use
+// lots of decals for special effects like shadows, footprints, etc, in which
+// case we should probably redesign this to batch them all together for more
+// efficient rendering.
+
+CDecalRData::CDecalRData(CModelDecal* decal)
+ : m_Decal(decal), m_IndexArray(GL_STATIC_DRAW), m_Array(GL_STATIC_DRAW)
+{
+ m_Position.type = GL_FLOAT;
+ m_Position.elems = 3;
+ m_Array.AddAttribute(&m_Position);
+
+ m_UV.type = GL_FLOAT;
+ m_UV.elems = 2;
+ m_Array.AddAttribute(&m_UV);
+
+ BuildArrays();
+}
+
+CDecalRData::~CDecalRData()
+{
+}
+
+void CDecalRData::Update()
+{
+ if (m_UpdateFlags != 0)
+ {
+ BuildArrays();
+ m_UpdateFlags = 0;
+ }
+}
+
+void CDecalRData::Render()
+{
+ m_Decal->m_Decal.m_Texture->Bind(0);
+
+ // TODO: Need to handle floating decals correctly. In particular, we need
+ // to render non-floating before water and floating after water (to get
+ // the blending right), and we also need to apply the correct lighting in
+ // each case, which doesn't really seem possible with the current
+ // TerrainRenderer.
+ // Also, need to mark the decals as dirty when water height changes.
+
+// glDisable(GL_TEXTURE_2D);
+// m_Decal->GetBounds().Render();
+// glEnable(GL_TEXTURE_2D);
+
+ u8* base = m_Array.Bind();
+ GLsizei stride = (GLsizei)m_Array.GetStride();
+
+ u8* indexBase = m_IndexArray.Bind();
+
+ glColor3fv(m_Decal->GetShadingColor().FloatArray());
+
+ glVertexPointer(3, GL_FLOAT, stride, base + m_Position.offset);
+ glTexCoordPointer(2, GL_FLOAT, stride, base + m_UV.offset);
+
+ if (!g_Renderer.m_SkipSubmit)
+ {
+ glDrawElements(GL_TRIANGLES, (GLsizei)m_IndexArray.GetNumVertices(), GL_UNSIGNED_SHORT, indexBase);
+ }
+
+ // bump stats
+ g_Renderer.m_Stats.m_DrawCalls++;
+ g_Renderer.m_Stats.m_TerrainTris += m_IndexArray.GetNumVertices() / 3;
+
+ CVertexBuffer::Unbind();
+}
+
+void CDecalRData::BuildArrays()
+{
+ PROFILE("decal build");
+
+ const SDecal& decal = m_Decal->m_Decal;
+
+ // TODO: Currently this constructs an axis-aligned bounding rectangle around
+ // the decal. It would be more efficient for rendering if we excluded tiles
+ // that are outside the (non-axis-aligned) decal rectangle.
+
+ ssize_t i0, j0, i1, j1;
+ m_Decal->CalcVertexExtents(i0, j0, i1, j1);
+
+ // Construct vertex data arrays
+
+ CmpPtr cmpWaterManager(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
+
+ m_Array.SetNumVertices((i1-i0+1)*(j1-j0+1));
+ m_Array.Layout();
+ VertexArrayIterator Position = m_Position.GetIterator();
+ VertexArrayIterator UV = m_UV.GetIterator();
+
+ for (ssize_t j = j0; j <= j1; ++j)
+ {
+ for (ssize_t i = i0; i <= i1; ++i)
+ {
+ CVector3D pos;
+ m_Decal->m_Terrain->CalcPosition(i, j, pos);
+
+ if (decal.m_Floating && !cmpWaterManager.null())
+ pos.Y = std::max(pos.Y, cmpWaterManager->GetExactWaterLevel(pos.X, pos.Z));
+
+ *Position = pos;
+ ++Position;
+
+ // Map from world space back into decal texture space
+ CVector3D inv = m_Decal->GetInvTransform().Transform(pos);
+ (*UV)[0] = 0.5f + (inv.X - decal.m_OffsetX) / decal.m_SizeX;
+ (*UV)[1] = 0.5f - (inv.Z - decal.m_OffsetZ) / decal.m_SizeZ; // flip V to match our texture convention
+ ++UV;
+ }
+ }
+
+ m_Array.Upload();
+ m_Array.FreeBackingStore();
+
+ // Construct index arrays for each terrain tile
+
+ m_IndexArray.SetNumVertices((i1-i0)*(j1-j0)*6);
+ m_IndexArray.Layout();
+ VertexArrayIterator Index = m_IndexArray.GetIterator();
+
+ u16 base = 0;
+ ssize_t w = i1-i0+1;
+ for (ssize_t dj = 0; dj < j1-j0; ++dj)
+ {
+ for (ssize_t di = 0; di < i1-i0; ++di)
+ {
+ bool dir = m_Decal->m_Terrain->GetTriangulationDir(i0+di, j0+dj);
+ if (dir)
+ {
+ *Index++ = u16(((dj+0)*w+(di+0))+base);
+ *Index++ = u16(((dj+0)*w+(di+1))+base);
+ *Index++ = u16(((dj+1)*w+(di+0))+base);
+
+ *Index++ = u16(((dj+0)*w+(di+1))+base);
+ *Index++ = u16(((dj+1)*w+(di+1))+base);
+ *Index++ = u16(((dj+1)*w+(di+0))+base);
+ }
+ else
+ {
+ *Index++ = u16(((dj+0)*w+(di+0))+base);
+ *Index++ = u16(((dj+0)*w+(di+1))+base);
+ *Index++ = u16(((dj+1)*w+(di+1))+base);
+
+ *Index++ = u16(((dj+1)*w+(di+1))+base);
+ *Index++ = u16(((dj+1)*w+(di+0))+base);
+ *Index++ = u16(((dj+0)*w+(di+0))+base);
+ }
+ }
+ }
+
+ m_IndexArray.Upload();
+ m_IndexArray.FreeBackingStore();
+}
diff --git a/source/renderer/DecalRData.h b/source/renderer/DecalRData.h
new file mode 100644
index 0000000000..e0dd13cb9f
--- /dev/null
+++ b/source/renderer/DecalRData.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 2011 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with 0 A.D. If not, see .
+ */
+
+#ifndef INCLUDED_DECALRDATA
+#define INCLUDED_DECALRDATA
+
+#include "graphics/RenderableObject.h"
+#include "renderer/VertexArray.h"
+
+class CModelDecal;
+
+class CDecalRData : public CRenderData
+{
+public:
+ CDecalRData(CModelDecal* decal);
+ ~CDecalRData();
+
+ void Update();
+
+ void Render();
+
+private:
+ void BuildArrays();
+
+ VertexIndexArray m_IndexArray;
+
+ VertexArray m_Array;
+ VertexArray::Attribute m_Position;
+ VertexArray::Attribute m_UV;
+
+ CModelDecal* m_Decal;
+};
+
+#endif // INCLUDED_DECALRDATA
diff --git a/source/renderer/PatchRData.h b/source/renderer/PatchRData.h
index 79bb697a39..da0eece5c1 100644
--- a/source/renderer/PatchRData.h
+++ b/source/renderer/PatchRData.h
@@ -45,6 +45,8 @@ public:
static void RenderBlends(const std::vector& patches);
static void RenderStreams(const std::vector& patches, int streamflags);
+ CPatch* GetPatch() { return m_Patch; }
+
private:
struct SSplat {
SSplat() : m_Texture(0), m_IndexCount(0) {}
diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp
index b16f94a96a..e86f95115d 100644
--- a/source/renderer/Renderer.cpp
+++ b/source/renderer/Renderer.cpp
@@ -1410,6 +1410,11 @@ void CRenderer::Submit(SOverlaySprite* overlay)
m->overlayRenderer.Submit(overlay);
}
+void CRenderer::Submit(CModelDecal* decal)
+{
+ m->terrainRenderer->Submit(decal);
+}
+
void CRenderer::SubmitNonRecursive(CModel* model)
{
if (model->GetFlags() & MODELFLAG_CASTSHADOWS) {
diff --git a/source/renderer/Renderer.h b/source/renderer/Renderer.h
index 9ad2861321..e37123d869 100644
--- a/source/renderer/Renderer.h
+++ b/source/renderer/Renderer.h
@@ -303,6 +303,7 @@ protected:
friend struct CRendererInternals;
friend class CVertexBuffer;
friend class CPatchRData;
+ friend class CDecalRData;
friend class FixedFunctionModelRenderer;
friend class ModelRenderer;
friend class PolygonSortModelRenderer;
@@ -332,6 +333,7 @@ protected:
void Submit(CPatch* patch);
void Submit(SOverlayLine* overlay);
void Submit(SOverlaySprite* overlay);
+ void Submit(CModelDecal* decal);
void SubmitNonRecursive(CModel* model);
//END: Implementation of SceneCollector
diff --git a/source/renderer/Scene.cpp b/source/renderer/Scene.cpp
index a1c88a238b..49245c176e 100644
--- a/source/renderer/Scene.cpp
+++ b/source/renderer/Scene.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -34,14 +34,23 @@
///////////////////////////////////////////////////////////
// Default implementation traverses the model recursively and uses
// SubmitNonRecursive for the actual work.
-void SceneCollector::SubmitRecursive(CModel* model)
+void SceneCollector::SubmitRecursive(CModelAbstract* model)
{
- SubmitNonRecursive(model);
-
- const std::vector& props = model->GetProps();
- for (size_t i = 0; i < props.size(); i++)
+ if (model->ToCModel())
{
- if (!props[i].m_Hidden)
- SubmitRecursive(props[i].m_Model);
+ SubmitNonRecursive(model->ToCModel());
+
+ const std::vector& props = model->ToCModel()->GetProps();
+ for (size_t i = 0; i < props.size(); i++)
+ {
+ if (!props[i].m_Hidden)
+ SubmitRecursive(props[i].m_Model);
+ }
}
+ else if (model->ToCModelDecal())
+ {
+ Submit(model->ToCModelDecal());
+ }
+ else
+ debug_warn(L"unknown model type");
}
diff --git a/source/renderer/Scene.h b/source/renderer/Scene.h
index 356a52b136..a51dd95b37 100644
--- a/source/renderer/Scene.h
+++ b/source/renderer/Scene.h
@@ -30,6 +30,8 @@
class CFrustum;
class CModel;
+class CModelAbstract;
+class CModelDecal;
class CPatch;
struct SOverlayLine;
struct SOverlaySprite;
@@ -82,6 +84,11 @@ public:
*/
virtual void Submit(SOverlaySprite* overlay) = 0;
+ /**
+ * Submit a terrain decal.
+ */
+ virtual void Submit(CModelDecal* decal) = 0;
+
/**
* Submit a model that is part of the scene,
* without submitting attached models.
@@ -95,7 +102,7 @@ public:
* @note This function is implemented using SubmitNonRecursive,
* so you shouldn't have to reimplement it.
*/
- virtual void SubmitRecursive(CModel* model);
+ virtual void SubmitRecursive(CModelAbstract* model);
};
diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp
index 9e7c9c4fa1..3816313806 100644
--- a/source/renderer/TerrainRenderer.cpp
+++ b/source/renderer/TerrainRenderer.cpp
@@ -23,11 +23,13 @@
#include "precompiled.h"
#include "graphics/Camera.h"
+#include "graphics/Decal.h"
#include "graphics/LightEnv.h"
#include "graphics/LOSTexture.h"
#include "graphics/Patch.h"
#include "graphics/Terrain.h"
#include "graphics/GameView.h"
+#include "graphics/Model.h"
#include "maths/MathUtil.h"
@@ -38,10 +40,12 @@
#include "ps/Profile.h"
#include "ps/World.h"
+#include "renderer/DecalRData.h"
#include "renderer/PatchRData.h"
#include "renderer/Renderer.h"
#include "renderer/ShadowMap.h"
#include "renderer/TerrainRenderer.h"
+#include "renderer/VertexArray.h"
#include "renderer/WaterManager.h"
#include "lib/res/graphics/ogl_shader.h"
@@ -69,12 +73,11 @@ struct TerrainRendererInternals
/// Which phase (submitting or rendering patches) are we in right now?
Phase phase;
- /**
- * VisiblePatches: Patches that were submitted for this frame
- *
- * @todo Merge this list with CPatchRData list
- */
- std::vector visiblePatches;
+ /// Patches that were submitted for this frame
+ std::vector visiblePatches;
+
+ /// Decals that were submitted for this frame
+ std::vector visibleDecals;
/// Fancy water shader
Handle fancyWaterShader;
@@ -107,7 +110,7 @@ void TerrainRenderer::Submit(CPatch* patch)
{
debug_assert(m->phase == Phase_Submit);
- CPatchRData* data=(CPatchRData*) patch->GetRenderData();
+ CPatchRData* data = (CPatchRData*)patch->GetRenderData();
if (data == 0)
{
// no renderdata for patch, create it now
@@ -116,9 +119,26 @@ void TerrainRenderer::Submit(CPatch* patch)
}
data->Update();
- m->visiblePatches.push_back(patch);
+ m->visiblePatches.push_back(data);
}
+///////////////////////////////////////////////////////////////////
+// Submit a decal for rendering
+void TerrainRenderer::Submit(CModelDecal* decal)
+{
+ debug_assert(m->phase == Phase_Submit);
+
+ CDecalRData* data = (CDecalRData*)decal->GetRenderData();
+ if (data == 0)
+ {
+ // no renderdata for decal, create it now
+ data = new CDecalRData(decal);
+ decal->SetRenderData(data);
+ }
+ data->Update();
+
+ m->visibleDecals.push_back(data);
+}
///////////////////////////////////////////////////////////////////
// Prepare for rendering
@@ -136,40 +156,25 @@ void TerrainRenderer::EndFrame()
debug_assert(m->phase == Phase_Render || m->phase == Phase_Submit);
m->visiblePatches.clear();
+ m->visibleDecals.clear();
m->phase = Phase_Submit;
}
-///////////////////////////////////////////////////////////////////
-// Query if patches have been submitted this frame
-bool TerrainRenderer::HaveSubmissions()
-{
- return !m->visiblePatches.empty();
-}
-
-
///////////////////////////////////////////////////////////////////
// Full-featured terrain rendering with blending and everything
void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
{
debug_assert(m->phase == Phase_Render);
- std::vector patchRDatas;
- patchRDatas.reserve(m->visiblePatches.size());
- for (size_t i = 0; i < m->visiblePatches.size(); ++i)
- patchRDatas.push_back(static_cast(m->visiblePatches[i]->GetRenderData()));
-
// render the solid black sides of the map first
g_Renderer.BindTexture(0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glColor3f(0, 0, 0);
PROFILE_START("render terrain sides");
for (size_t i = 0; i < m->visiblePatches.size(); ++i)
- {
- CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
- patchdata->RenderSides();
- }
+ m->visiblePatches[i]->RenderSides();
PROFILE_END("render terrain sides");
// switch on required client states
@@ -192,7 +197,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, one);
PROFILE_START("render terrain base");
- CPatchRData::RenderBases(patchRDatas);
+ CPatchRData::RenderBases(m->visiblePatches);
PROFILE_END("render terrain base");
// render blends
@@ -222,13 +227,35 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
// render blend passes for each patch
PROFILE_START("render terrain blends");
- CPatchRData::RenderBlends(patchRDatas);
+ CPatchRData::RenderBlends(m->visiblePatches);
PROFILE_END("render terrain blends");
// Disable second texcoord array
pglClientActiveTextureARB(GL_TEXTURE1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ // Render terrain decals
+
+ g_Renderer.BindTexture(1, 0);
+ pglActiveTextureARB(GL_TEXTURE0);
+ pglClientActiveTextureARB(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_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
+ 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_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ PROFILE_START("render terrain decals");
+ for (size_t i = 0; i < m->visibleDecals.size(); ++i)
+ m->visibleDecals[i]->Render();
+ PROFILE_END("render terrain decals");
+
+
// Now apply lighting
const CLightEnv& lightEnv = g_Renderer.GetLightEnv();
@@ -292,15 +319,16 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
}
else
{
- const CMatrix3D& texturematrix = shadow->GetTextureMatrix();
+ losTexture.BindTexture(1);
+ g_Renderer.BindTexture(0, shadow->GetTexture());
+
+ const CMatrix3D& texturematrix = shadow->GetTextureMatrix();
pglActiveTextureARB(GL_TEXTURE0);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(&texturematrix._11);
glMatrixMode(GL_MODELVIEW);
- glBindTexture(GL_TEXTURE_2D, shadow->GetTexture());
-
if (shadow->GetUseDepthTexture())
{
// (Ambient + ShTranslucency * Diffuse * (1 - Shadow) + Diffuse * Shadow) * LOS
@@ -416,7 +444,7 @@ void TerrainRenderer::RenderTerrain(ShadowMap* shadow)
pglClientActiveTextureARB(GL_TEXTURE0);
PROFILE_START("render terrain streams");
- CPatchRData::RenderStreams(patchRDatas, streamflags);
+ CPatchRData::RenderStreams(m->visiblePatches, streamflags);
PROFILE_END("render terrain streams");
glMatrixMode(GL_TEXTURE);
@@ -475,13 +503,8 @@ void TerrainRenderer::RenderPatches()
{
debug_assert(m->phase == Phase_Render);
- std::vector patchRDatas;
- patchRDatas.reserve(m->visiblePatches.size());
- for (size_t i = 0; i < m->visiblePatches.size(); ++i)
- patchRDatas.push_back(static_cast(m->visiblePatches[i]->GetRenderData()));
-
glEnableClientState(GL_VERTEX_ARRAY);
- CPatchRData::RenderStreams(patchRDatas, STREAM_POS);
+ CPatchRData::RenderStreams(m->visiblePatches, STREAM_POS);
glDisableClientState(GL_VERTEX_ARRAY);
}
@@ -493,11 +516,8 @@ void TerrainRenderer::RenderOutlines()
debug_assert(m->phase == Phase_Render);
glEnableClientState(GL_VERTEX_ARRAY);
- for(size_t i = 0; i < m->visiblePatches.size(); ++i)
- {
- CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
- patchdata->RenderOutline();
- }
+ for (size_t i = 0; i < m->visiblePatches.size(); ++i)
+ m->visiblePatches[i]->RenderOutline();
glDisableClientState(GL_VERTEX_ARRAY);
}
@@ -665,7 +685,7 @@ void TerrainRenderer::RenderWater()
for(size_t i=0; ivisiblePatches.size(); i++)
{
- CPatch* patch = m->visiblePatches[i];
+ CPatch* patch = m->visiblePatches[i]->GetPatch();
for(ssize_t dx=0; dxvisiblePatches.size(); ++i)
- {
- CPatchRData* patchdata = (CPatchRData*)m->visiblePatches[i]->GetRenderData();
- patchdata->RenderPriorities();
- }
+ m->visiblePatches[i]->RenderPriorities();
}
diff --git a/source/renderer/TerrainRenderer.h b/source/renderer/TerrainRenderer.h
index 1708c45c64..9db03087fe 100644
--- a/source/renderer/TerrainRenderer.h
+++ b/source/renderer/TerrainRenderer.h
@@ -51,6 +51,11 @@ public:
*/
void Submit(CPatch* patch);
+ /**
+ * Submit: Add a terrain decal for rendering in this frame.
+ */
+ void Submit(CModelDecal* decal);
+
/**
* PrepareForRendering: Prepare internal data structures like vertex
* buffers for rendering.
@@ -66,15 +71,6 @@ public:
*/
void EndFrame();
- /**
- * HaveSubmissions: Query whether any patches have been submitted
- * for this frame.
- *
- * @return @c true if a patch has been submitted for this frame,
- * @c false otherwise.
- */
- bool HaveSubmissions();
-
/**
* RenderTerrain: Render textured terrain (including blends between
* different terrain types).
diff --git a/source/simulation2/components/CCmpProjectileManager.cpp b/source/simulation2/components/CCmpProjectileManager.cpp
index e525537e3d..e640359a90 100644
--- a/source/simulation2/components/CCmpProjectileManager.cpp
+++ b/source/simulation2/components/CCmpProjectileManager.cpp
@@ -337,7 +337,7 @@ void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrust
if (!losRevealAll && !los.IsVisible(posi, posj))
continue;
- CModel& model = m_Projectiles[i].unit->GetModel();
+ CModelAbstract& model = m_Projectiles[i].unit->GetModel();
model.ValidatePosition();
diff --git a/source/simulation2/components/CCmpVisualActor.cpp b/source/simulation2/components/CCmpVisualActor.cpp
index 1fcdb33859..a5a1dbc1bf 100644
--- a/source/simulation2/components/CCmpVisualActor.cpp
+++ b/source/simulation2/components/CCmpVisualActor.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010 Wildfire Games.
+/* Copyright (C) 2011 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -47,6 +47,7 @@ public:
componentManager.SubscribeToMessageType(MT_Interpolate);
componentManager.SubscribeToMessageType(MT_RenderSubmit);
componentManager.SubscribeToMessageType(MT_OwnershipChanged);
+ componentManager.SubscribeGloballyToMessageType(MT_TerrainChanged);
}
DEFAULT_COMPONENT_ALLOCATOR(VisualActor)
@@ -196,6 +197,12 @@ public:
m_Unit->GetModel().SetPlayerID(msgData.to);
break;
}
+ case MT_TerrainChanged:
+ {
+ const CMessageTerrainChanged& msgData = static_cast (msg);
+ m_Unit->GetModel().SetTerrainDirty(msgData.i0, msgData.j0, msgData.i1, msgData.j1);
+ break;
+ }
}
}
@@ -232,13 +239,17 @@ public:
if (!m_Unit)
return CVector3D();
- // Ensure the prop transforms are correct
- m_Unit->GetModel().ValidatePosition();
+ if (m_Unit->GetModel().ToCModel())
+ {
+ // Ensure the prop transforms are correct
+ m_Unit->GetModel().ValidatePosition();
- CModel* ammo = m_Unit->GetModel().FindFirstAmmoProp();
- if (!ammo)
- return CVector3D();
- return ammo->GetTransform().GetTranslation();
+ CModelAbstract* ammo = m_Unit->GetModel().ToCModel()->FindFirstAmmoProp();
+ if (ammo)
+ return ammo->GetTransform().GetTranslation();
+ }
+
+ return CVector3D();
}
virtual void SelectAnimation(std::string name, bool once, float speed, std::wstring soundgroup)
@@ -257,7 +268,9 @@ public:
m_AnimDesync = 0.05f; // TODO: make this an argument
m_AnimSyncRepeatTime = 0.0f;
- m_Unit->GetAnimation().SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, false, m_SoundGroup.c_str());
+ m_Unit->SetEntitySelection(m_AnimName);
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, m_SoundGroup.c_str());
}
virtual void SelectMovementAnimation(float runThreshold)
@@ -267,7 +280,9 @@ public:
m_AnimRunThreshold = runThreshold;
- m_Unit->GetAnimation().SetAnimationState("walk", false, 1.f, 0.f, false, L"");
+ m_Unit->SetEntitySelection("walk");
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationState("walk", false, 1.f, 0.f, L"");
}
virtual void SetAnimationSyncRepeat(float repeattime)
@@ -277,7 +292,8 @@ public:
m_AnimSyncRepeatTime = repeattime;
- m_Unit->GetAnimation().SetAnimationSyncRepeat(m_AnimSyncRepeatTime);
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime);
}
virtual void SetAnimationSyncOffset(float actiontime)
@@ -285,7 +301,8 @@ public:
if (!m_Unit)
return;
- m_Unit->GetAnimation().SetAnimationSyncOffset(actiontime);
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationSyncOffset(actiontime);
}
virtual void SetShadingColour(fixed r, fixed g, fixed b, fixed a)
@@ -320,11 +337,14 @@ public:
m_Unit->SetID(GetEntityId());
- m_Unit->GetAnimation().SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, false, m_SoundGroup.c_str());
+ m_Unit->SetEntitySelection(m_AnimName);
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationState(m_AnimName, m_AnimOnce, m_AnimSpeed, m_AnimDesync, m_SoundGroup.c_str());
// We'll lose the exact synchronisation but we should at least make sure it's going at the correct rate
if (m_AnimSyncRepeatTime != 0.0f)
- m_Unit->GetAnimation().SetAnimationSyncRepeat(m_AnimSyncRepeatTime);
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationSyncRepeat(m_AnimSyncRepeatTime);
m_Unit->GetModel().SetShadingColor(shading);
@@ -354,11 +374,23 @@ void CCmpVisualActor::Update(fixed turnLength)
float speed = cmpPosition->GetDistanceTravelled().ToFloat() / turnLength.ToFloat();
if (speed == 0.0f)
- m_Unit->GetAnimation().SetAnimationState("idle", false, 1.f, 0.f, false, L"");
+ {
+ m_Unit->SetEntitySelection("idle");
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationState("idle", false, 1.f, 0.f, L"");
+ }
else if (speed < m_AnimRunThreshold)
- m_Unit->GetAnimation().SetAnimationState("walk", false, speed, 0.f, false, L"");
+ {
+ m_Unit->SetEntitySelection("walk");
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationState("walk", false, speed, 0.f, L"");
+ }
else
- m_Unit->GetAnimation().SetAnimationState("run", false, speed, 0.f, false, L"");
+ {
+ m_Unit->SetEntitySelection("run");
+ if (m_Unit->GetAnimation())
+ m_Unit->GetAnimation()->SetAnimationState("run", false, speed, 0.f, L"");
+ }
}
}
@@ -398,7 +430,7 @@ void CCmpVisualActor::Interpolate(float frameTime, float frameOffset)
CMatrix3D transform(cmpPosition->GetInterpolatedTransform(frameOffset, floating));
- CModel& model = m_Unit->GetModel();
+ CModelAbstract& model = m_Unit->GetModel();
model.SetTransform(transform);
m_Unit->UpdateModel(frameTime);
@@ -423,7 +455,7 @@ void CCmpVisualActor::RenderSubmit(SceneCollector& collector, const CFrustum& fr
if (m_Visibility == ICmpRangeManager::VIS_HIDDEN)
return;
- CModel& model = m_Unit->GetModel();
+ CModelAbstract& model = m_Unit->GetModel();
if (culling && !frustum.IsBoxVisible(CVector3D(0, 0, 0), model.GetBounds()))
return;