Index: ps/trunk/source/graphics/Model.h =================================================================== --- ps/trunk/source/graphics/Model.h +++ ps/trunk/source/graphics/Model.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -40,9 +40,8 @@ #define MODELFLAG_SILHOUETTE_OCCLUDER (1<<3) #define MODELFLAG_IGNORE_LOS (1<<4) #define MODELFLAG_FLOATONWATER (1<<5) -/////////////////////////////////////////////////////////////////////////////// -// CModel: basically, a mesh object - holds the texturing and skinning -// information for a model in game + +// Holds world information for a particular instance of a model in the game. class CModel : public CModelAbstract { NONCOPYABLE(CModel); @@ -75,34 +74,27 @@ }; public: - // constructor - CModel(CSimulation2& simulation); - // destructor + CModel(const CSimulation2& simulation, const CMaterial& material, const CModelDefPtr& modeldef); ~CModel(); - /// Dynamic cast virtual CModel* ToCModel() { 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 void UpdateTo(float time); // get the model's geometry data 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 void SetPlayerID(player_id_t id); // set the models mod color virtual void SetShadingColor(const CColor& color); // 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 bool SetAnimation(CSkeletonAnim* anim, bool once = false); @@ -118,6 +110,7 @@ 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); // remove shadow casting and receiving, recursively through props @@ -232,26 +225,23 @@ virtual void InvalidatePosition(); private: - // delete anything allocated by the model - void ReleaseData(); - // Needed for terrain aligned props - CSimulation2& m_Simulation; + const CSimulation2& m_Simulation; // object flags - int m_Flags; + int m_Flags{0}; // model's material CMaterial m_Material; // 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 // that can play on a model. Not always up-to-date - currently CalcBounds() // updates it when necessary. CBoundingBoxAligned m_ObjectBounds; // animation currently playing on this model, if any - CSkeletonAnim* m_Anim; + CSkeletonAnim* m_Anim = nullptr; // 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. @@ -261,19 +251,19 @@ * * @see SPropPoint */ - CMatrix3D* m_BoneMatrices; + CMatrix3D* m_BoneMatrices{nullptr}; // list of current props on model std::vector m_Props; /** * 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 */ - size_t m_AmmoLoadedProp; + size_t m_AmmoLoadedProp{0}; }; -#endif +#endif // INCLUDED_MODEL Index: ps/trunk/source/graphics/Model.cpp =================================================================== --- ps/trunk/source/graphics/Model.cpp +++ ps/trunk/source/graphics/Model.cpp @@ -37,62 +37,33 @@ #include "simulation2/Simulation2.h" -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Constructor -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) -{ -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 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) +CModel::CModel(const CSimulation2& simulation, const CMaterial& material, const CModelDefPtr& modeldef) + : m_Simulation{simulation}, m_Material{material}, m_pModelDef{modeldef} { - // clean up any existing data first - ReleaseData(); - - m_pModelDef = modeldef; - - size_t numBones = modeldef->GetNumBones(); - if (numBones != 0) + const size_t numberOfBones = modeldef->GetNumBones(); + if (numberOfBones != 0) { - size_t numBlends = modeldef->GetNumBlends(); + const size_t numberOfBlends = modeldef->GetNumBlends(); // allocate matrices for bone transformations // (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); - for (size_t i = 0; i < numBones + 1 + numBlends; ++i) + m_BoneMatrices = (CMatrix3D*)rtl_AllocateAligned(sizeof(CMatrix3D) * (numberOfBones + 1 + numberOfBlends), 16); + for (size_t i = 0; i < numberOfBones + 1 + numberOfBlends; ++i) { m_BoneMatrices[i].SetIdentity(); } } 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 @@ -497,10 +468,8 @@ // Clone: return a clone of this model 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->InitModel(m_pModelDef); - clone->SetMaterial(m_Material); clone->SetAnimation(m_Anim); clone->SetFlags(m_Flags); @@ -555,11 +524,6 @@ } } -void CModel::SetMaterial(const CMaterial &material) -{ - m_Material = material; -} - void CModel::SetPlayerID(player_id_t id) { CModelAbstract::SetPlayerID(id); Index: ps/trunk/source/graphics/ObjectEntry.h =================================================================== --- ps/trunk/source/graphics/ObjectEntry.h +++ ps/trunk/source/graphics/ObjectEntry.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,29 +18,28 @@ #ifndef INCLUDED_OBJECTENTRY #define INCLUDED_OBJECTENTRY -class CModelAbstract; -class CSkeletonAnim; -class CObjectBase; -class CObjectManager; -class CSimulation2; +#include "graphics/Color.h" +#include "graphics/ObjectBase.h" +#include "lib/file/vfs/vfs_path.h" +#include "ps/CStr.h" #include #include #include #include -#include "graphics/Color.h" -#include "lib/file/vfs/vfs_path.h" -#include "ps/CStr.h" - -#include "graphics/ObjectBase.h" +class CModelAbstract; +class CSkeletonAnim; +class CObjectBase; +class CObjectManager; +class CSimulation2; class CObjectEntry { NONCOPYABLE(CObjectEntry); public: - CObjectEntry(const std::shared_ptr& base, CSimulation2& simulation); + CObjectEntry(const std::shared_ptr& base, const CSimulation2& simulation); ~CObjectEntry(); // Construct this actor, using the specified variation selections @@ -78,16 +77,14 @@ std::vector GetAnimations(const CStr& animationName, const CStr& ID = "") const; // corresponding model - CModelAbstract* m_Model; + std::unique_ptr m_Model; private: - - CSimulation2& m_Simulation; + const CSimulation2& m_Simulation; using SkeletonAnimMap = std::multimap>; SkeletonAnimMap m_Animations; // TODO: something more memory-efficient than storing loads of similar strings for each unit? }; - -#endif +#endif // INCLUDED_OBJECTENTRY Index: ps/trunk/source/graphics/ObjectEntry.cpp =================================================================== --- ps/trunk/source/graphics/ObjectEntry.cpp +++ ps/trunk/source/graphics/ObjectEntry.cpp @@ -43,16 +43,12 @@ #include -CObjectEntry::CObjectEntry(const std::shared_ptr& base, CSimulation2& simulation) : - m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f), m_Model(NULL), m_Simulation(simulation) +CObjectEntry::CObjectEntry(const std::shared_ptr& base, const CSimulation2& simulation) : + m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f), m_Simulation(simulation) { } -CObjectEntry::~CObjectEntry() -{ - delete m_Model; -} - +CObjectEntry::~CObjectEntry() = default; bool CObjectEntry::BuildVariation(const std::vector*>& completeSelections, const std::vector& variationKey, @@ -101,20 +97,20 @@ 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(objectManager.GetTerrain(), decal); + m_Model = std::make_unique(objectManager.GetTerrain(), decal); return true; } if (!variation.particles.empty()) { - m_Model = new CModelParticleEmitter(g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles)); + m_Model = std::make_unique(g_Renderer.GetSceneRenderer().GetParticleManager().LoadEmitterType(variation.particles)); return true; } if (variation.model.empty()) { - m_Model = new CModelDummy(); + m_Model = std::make_unique(); return true; } @@ -134,12 +130,8 @@ } // delete old model, create new - CModel* model = new CModel(m_Simulation); - delete m_Model; - 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); + CMaterial material = g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(m_Base->m_Material); + material.AddStaticUniform("objectColor", CVector4D(m_Color.r, m_Color.g, m_Color.b, m_Color.a)); if (m_Samplers.empty()) LOGERROR("Actor '%s' has no textures.", m_Base->GetIdentifier()); @@ -153,9 +145,13 @@ // 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. texture->Prefetch(); - model->GetMaterial().AddSampler(CMaterial::TextureSampler(samp.m_SamplerName, texture)); + material.AddSampler(CMaterial::TextureSampler(samp.m_SamplerName, texture)); } + std::unique_ptr newModel = std::make_unique(m_Simulation, material, modeldef); + CModel* model = newModel.get(); + m_Model = std::move(newModel); + for (const CStrIntern& requSampName : model->GetMaterial().GetRequiredSampler()) { if (std::find_if(m_Samplers.begin(), m_Samplers.end(),