Refactors models and materials, part 1, reduces amount of mutable properties.

Comments By: phosit
Differential Revision: https://code.wildfiregames.com/D5108
This was SVN commit r27841.
This commit is contained in:
Vladislav Belov 2023-09-14 08:37:06 +00:00
parent af13be489e
commit b8cd3a0268
4 changed files with 57 additions and 110 deletions

View File

@ -37,62 +37,33 @@
#include "simulation2/Simulation2.h" #include "simulation2/Simulation2.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////// CModel::CModel(const CSimulation2& simulation, const CMaterial& material, const CModelDefPtr& modeldef)
// Constructor : m_Simulation{simulation}, m_Material{material}, m_pModelDef{modeldef}
CModel::CModel(CSimulation2& simulation)
: m_Flags(0), m_Anim(NULL), m_AnimTime(0), m_Simulation(simulation),
m_BoneMatrices(NULL), m_AmmoPropPoint(NULL), m_AmmoLoadedProp(0)
{ {
} const size_t numberOfBones = modeldef->GetNumBones();
if (numberOfBones != 0)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Destructor
CModel::~CModel()
{
ReleaseData();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ReleaseData: delete anything allocated by the model
void CModel::ReleaseData()
{
rtl_FreeAligned(m_BoneMatrices);
for (size_t i = 0; i < m_Props.size(); ++i)
delete m_Props[i].m_Model;
m_Props.clear();
m_pModelDef = CModelDefPtr();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// InitModel: setup model from given geometry
bool CModel::InitModel(const CModelDefPtr& modeldef)
{
// clean up any existing data first
ReleaseData();
m_pModelDef = modeldef;
size_t numBones = modeldef->GetNumBones();
if (numBones != 0)
{ {
size_t numBlends = modeldef->GetNumBlends(); const size_t numberOfBlends = modeldef->GetNumBlends();
// allocate matrices for bone transformations // allocate matrices for bone transformations
// (one extra matrix is used for the special case of bind-shape relative weighting) // (one extra matrix is used for the special case of bind-shape relative weighting)
m_BoneMatrices = (CMatrix3D*)rtl_AllocateAligned(sizeof(CMatrix3D) * (numBones + 1 + numBlends), 16); m_BoneMatrices = (CMatrix3D*)rtl_AllocateAligned(sizeof(CMatrix3D) * (numberOfBones + 1 + numberOfBlends), 16);
for (size_t i = 0; i < numBones + 1 + numBlends; ++i) for (size_t i = 0; i < numberOfBones + 1 + numberOfBlends; ++i)
{ {
m_BoneMatrices[i].SetIdentity(); m_BoneMatrices[i].SetIdentity();
} }
} }
m_PositionValid = true; m_PositionValid = true;
return true;
} }
CModel::~CModel()
{
rtl_FreeAligned(m_BoneMatrices);
for (Prop& prop : m_Props)
delete prop.m_Model;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CalcBound: calculate the world space bounds of this model // CalcBound: calculate the world space bounds of this model
@ -497,10 +468,8 @@ CModelAbstract* CModel::FindFirstAmmoProp()
// Clone: return a clone of this model // Clone: return a clone of this model
CModelAbstract* CModel::Clone() const CModelAbstract* CModel::Clone() const
{ {
CModel* clone = new CModel(m_Simulation); CModel* clone = new CModel(m_Simulation, m_Material, m_pModelDef);
clone->m_ObjectBounds = m_ObjectBounds; clone->m_ObjectBounds = m_ObjectBounds;
clone->InitModel(m_pModelDef);
clone->SetMaterial(m_Material);
clone->SetAnimation(m_Anim); clone->SetAnimation(m_Anim);
clone->SetFlags(m_Flags); clone->SetFlags(m_Flags);
@ -555,11 +524,6 @@ void CModel::RemoveShadowsRec()
} }
} }
void CModel::SetMaterial(const CMaterial &material)
{
m_Material = material;
}
void CModel::SetPlayerID(player_id_t id) void CModel::SetPlayerID(player_id_t id)
{ {
CModelAbstract::SetPlayerID(id); CModelAbstract::SetPlayerID(id);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games. /* Copyright (C) 2023 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -40,9 +40,8 @@ class CSimulation2;
#define MODELFLAG_SILHOUETTE_OCCLUDER (1<<3) #define MODELFLAG_SILHOUETTE_OCCLUDER (1<<3)
#define MODELFLAG_IGNORE_LOS (1<<4) #define MODELFLAG_IGNORE_LOS (1<<4)
#define MODELFLAG_FLOATONWATER (1<<5) #define MODELFLAG_FLOATONWATER (1<<5)
///////////////////////////////////////////////////////////////////////////////
// CModel: basically, a mesh object - holds the texturing and skinning // Holds world information for a particular instance of a model in the game.
// information for a model in game
class CModel : public CModelAbstract class CModel : public CModelAbstract
{ {
NONCOPYABLE(CModel); NONCOPYABLE(CModel);
@ -75,34 +74,27 @@ public:
}; };
public: public:
// constructor CModel(const CSimulation2& simulation, const CMaterial& material, const CModelDefPtr& modeldef);
CModel(CSimulation2& simulation);
// destructor
~CModel(); ~CModel();
/// Dynamic cast /// Dynamic cast
virtual CModel* ToCModel() virtual CModel* ToCModel()
{ {
return this; return this;
} }
// setup model from given geometry
bool InitModel(const CModelDefPtr& modeldef);
// update this model's state; 'time' is the absolute time since the start of the animation, in MS // update this model's state; 'time' is the absolute time since the start of the animation, in MS
void UpdateTo(float time); void UpdateTo(float time);
// get the model's geometry data // get the model's geometry data
const CModelDefPtr& GetModelDef() { return m_pModelDef; } const CModelDefPtr& GetModelDef() { return m_pModelDef; }
// set the model's material
void SetMaterial(const CMaterial &material);
// set the model's player ID, recursively through props // set the model's player ID, recursively through props
void SetPlayerID(player_id_t id); void SetPlayerID(player_id_t id);
// set the models mod color // set the models mod color
virtual void SetShadingColor(const CColor& color); virtual void SetShadingColor(const CColor& color);
// get the model's material // get the model's material
CMaterial& GetMaterial() { return m_Material; } const CMaterial& GetMaterial() { return m_Material; }
// set the given animation as the current animation on this model // set the given animation as the current animation on this model
bool SetAnimation(CSkeletonAnim* anim, bool once = false); bool SetAnimation(CSkeletonAnim* anim, bool once = false);
@ -118,6 +110,7 @@ public:
void SetFlags(int flags) { m_Flags=flags; } void SetFlags(int flags) { m_Flags=flags; }
// get object flags // get object flags
int GetFlags() const { return m_Flags; } int GetFlags() const { return m_Flags; }
// add object flags, recursively through props // add object flags, recursively through props
void AddFlagsRec(int flags); void AddFlagsRec(int flags);
// remove shadow casting and receiving, recursively through props // remove shadow casting and receiving, recursively through props
@ -232,26 +225,23 @@ public:
virtual void InvalidatePosition(); virtual void InvalidatePosition();
private: private:
// delete anything allocated by the model
void ReleaseData();
// Needed for terrain aligned props // Needed for terrain aligned props
CSimulation2& m_Simulation; const CSimulation2& m_Simulation;
// object flags // object flags
int m_Flags; int m_Flags{0};
// model's material // model's material
CMaterial m_Material; CMaterial m_Material;
// pointer to the model's raw 3d data // pointer to the model's raw 3d data
CModelDefPtr m_pModelDef; const CModelDefPtr m_pModelDef;
// object space bounds of model - accounts for bounds of all possible animations // object space bounds of model - accounts for bounds of all possible animations
// that can play on a model. Not always up-to-date - currently CalcBounds() // that can play on a model. Not always up-to-date - currently CalcBounds()
// updates it when necessary. // updates it when necessary.
CBoundingBoxAligned m_ObjectBounds; CBoundingBoxAligned m_ObjectBounds;
// animation currently playing on this model, if any // animation currently playing on this model, if any
CSkeletonAnim* m_Anim; CSkeletonAnim* m_Anim = nullptr;
// time (in MS) into the current animation // time (in MS) into the current animation
float m_AnimTime; float m_AnimTime{0.0f};
/** /**
* Current state of all bones on this model; null if associated modeldef isn't skeletal. * Current state of all bones on this model; null if associated modeldef isn't skeletal.
@ -261,19 +251,19 @@ private:
* *
* @see SPropPoint * @see SPropPoint
*/ */
CMatrix3D* m_BoneMatrices; CMatrix3D* m_BoneMatrices{nullptr};
// list of current props on model // list of current props on model
std::vector<Prop> m_Props; std::vector<Prop> m_Props;
/** /**
* The prop point to which the ammo prop is attached, or NULL if none * The prop point to which the ammo prop is attached, or NULL if none
*/ */
const SPropPoint* m_AmmoPropPoint; const SPropPoint* m_AmmoPropPoint{nullptr};
/** /**
* If m_AmmoPropPoint is not NULL, then the index in m_Props of the ammo prop * If m_AmmoPropPoint is not NULL, then the index in m_Props of the ammo prop
*/ */
size_t m_AmmoLoadedProp; size_t m_AmmoLoadedProp{0};
}; };
#endif #endif // INCLUDED_MODEL

View File

@ -43,16 +43,12 @@
#include <sstream> #include <sstream>
CObjectEntry::CObjectEntry(const std::shared_ptr<CObjectBase>& base, CSimulation2& simulation) : CObjectEntry::CObjectEntry(const std::shared_ptr<CObjectBase>& base, const CSimulation2& simulation) :
m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f), m_Model(NULL), m_Simulation(simulation) m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f), m_Simulation(simulation)
{ {
} }
CObjectEntry::~CObjectEntry() CObjectEntry::~CObjectEntry() = default;
{
delete m_Model;
}
bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& completeSelections, bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& completeSelections,
const std::vector<u8>& variationKey, const std::vector<u8>& variationKey,
@ -101,20 +97,20 @@ bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& comp
variation.decal.m_SizeX, variation.decal.m_SizeZ, variation.decal.m_SizeX, variation.decal.m_SizeZ,
variation.decal.m_Angle, variation.decal.m_OffsetX, variation.decal.m_OffsetZ, variation.decal.m_Angle, variation.decal.m_OffsetX, variation.decal.m_OffsetZ,
m_Base->m_Properties.m_FloatOnWater); m_Base->m_Properties.m_FloatOnWater);
m_Model = new CModelDecal(objectManager.GetTerrain(), decal); m_Model = std::make_unique<CModelDecal>(objectManager.GetTerrain(), decal);
return true; return true;
} }
if (!variation.particles.empty()) if (!variation.particles.empty())
{ {
m_Model = new CModelParticleEmitter(g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles)); m_Model = std::make_unique<CModelParticleEmitter>(g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles));
return true; return true;
} }
if (variation.model.empty()) if (variation.model.empty())
{ {
m_Model = new CModelDummy(); m_Model = std::make_unique<CModelDummy>();
return true; return true;
} }
@ -134,12 +130,8 @@ bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& comp
} }
// delete old model, create new // delete old model, create new
CModel* model = new CModel(m_Simulation); CMaterial material = g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(m_Base->m_Material);
delete m_Model; material.AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a));
m_Model = model;
model->SetMaterial(g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(m_Base->m_Material));
model->GetMaterial().AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a));
model->InitModel(modeldef);
if (m_Samplers.empty()) if (m_Samplers.empty())
LOGERROR("Actor '%s' has no textures.", m_Base->GetIdentifier()); LOGERROR("Actor '%s' has no textures.", m_Base->GetIdentifier());
@ -153,9 +145,13 @@ bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& comp
// All textures are prefetched even in the fixed pipeline, including the normal maps etc. // All textures are prefetched even in the fixed pipeline, including the normal maps etc.
// TODO: Should check which renderpath is selected and only preload the necessary textures. // TODO: Should check which renderpath is selected and only preload the necessary textures.
texture->Prefetch(); texture->Prefetch();
model->GetMaterial().AddSampler(CMaterial::TextureSampler(samp.m_SamplerName, texture)); material.AddSampler(CMaterial::TextureSampler(samp.m_SamplerName, texture));
} }
std::unique_ptr<CModel> newModel = std::make_unique<CModel>(m_Simulation, material, modeldef);
CModel* model = newModel.get();
m_Model = std::move(newModel);
for (const CStrIntern& requSampName : model->GetMaterial().GetRequiredSampler()) for (const CStrIntern& requSampName : model->GetMaterial().GetRequiredSampler())
{ {
if (std::find_if(m_Samplers.begin(), m_Samplers.end(), if (std::find_if(m_Samplers.begin(), m_Samplers.end(),

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games. /* Copyright (C) 2023 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -18,29 +18,28 @@
#ifndef INCLUDED_OBJECTENTRY #ifndef INCLUDED_OBJECTENTRY
#define INCLUDED_OBJECTENTRY #define INCLUDED_OBJECTENTRY
class CModelAbstract; #include "graphics/Color.h"
class CSkeletonAnim; #include "graphics/ObjectBase.h"
class CObjectBase; #include "lib/file/vfs/vfs_path.h"
class CObjectManager; #include "ps/CStr.h"
class CSimulation2;
#include <map> #include <map>
#include <memory> #include <memory>
#include <set> #include <set>
#include <vector> #include <vector>
#include "graphics/Color.h" class CModelAbstract;
#include "lib/file/vfs/vfs_path.h" class CSkeletonAnim;
#include "ps/CStr.h" class CObjectBase;
class CObjectManager;
#include "graphics/ObjectBase.h" class CSimulation2;
class CObjectEntry class CObjectEntry
{ {
NONCOPYABLE(CObjectEntry); NONCOPYABLE(CObjectEntry);
public: public:
CObjectEntry(const std::shared_ptr<CObjectBase>& base, CSimulation2& simulation); CObjectEntry(const std::shared_ptr<CObjectBase>& base, const CSimulation2& simulation);
~CObjectEntry(); ~CObjectEntry();
// Construct this actor, using the specified variation selections // Construct this actor, using the specified variation selections
@ -78,16 +77,14 @@ public:
std::vector<CSkeletonAnim*> GetAnimations(const CStr& animationName, const CStr& ID = "") const; std::vector<CSkeletonAnim*> GetAnimations(const CStr& animationName, const CStr& ID = "") const;
// corresponding model // corresponding model
CModelAbstract* m_Model; std::unique_ptr<CModelAbstract> m_Model;
private: private:
const CSimulation2& m_Simulation;
CSimulation2& m_Simulation;
using SkeletonAnimMap = std::multimap<CStr, std::unique_ptr<CSkeletonAnim>>; using SkeletonAnimMap = std::multimap<CStr, std::unique_ptr<CSkeletonAnim>>;
SkeletonAnimMap m_Animations; SkeletonAnimMap m_Animations;
// TODO: something more memory-efficient than storing loads of similar strings for each unit? // TODO: something more memory-efficient than storing loads of similar strings for each unit?
}; };
#endif // INCLUDED_OBJECTENTRY
#endif