Skip to content

Destroy material when a mesh is deleted #324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 27, 2021
8 changes: 8 additions & 0 deletions ogre/include/ignition/rendering/ogre/OgreMeshFactory.hh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,15 @@ namespace ignition

protected: virtual bool Validate(const MeshDescriptor &_desc);

/// \brief Remove internal material cache for a specific material
/// \param[in] _name Name of the template material to remove.
public: void ClearMaterialsCache(const std::string &_name);

protected: OgreScenePtr scene;

/// \brief Vector with the template materials, we keep the pointer to be
/// able to remove it when nobody is using it.
protected: std::vector<MaterialPtr> materialCache;
};

class IGNITION_RENDERING_OGRE_VISIBLE OgreSubMeshStoreFactory
Expand Down
4 changes: 4 additions & 0 deletions ogre/include/ignition/rendering/ogre/OgreScene.hh
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ namespace ignition

protected: virtual MaterialMapPtr Materials() const override;

/// \brief Remove internal material cache for a specific material
/// \param[in] _name Name of the template material to remove.
public: void ClearMaterialsCache(const std::string &_name);

private: void CreateContext();

private: void CreateRootVisual();
Expand Down
35 changes: 34 additions & 1 deletion ogre/src/OgreMaterial.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,18 @@ void OgreMaterial::Destroy()
{
if (!this->Scene()->IsInitialized())
return;

std::string materialName;
Ogre::MaterialManager &matManager = Ogre::MaterialManager::getSingleton();
#if OGRE_VERSION_LT_1_10_1
if (!this->ogreMaterial.isNull())
{
materialName = this->ogreMaterial->getName();

this->ogreTexState->setBlank();
auto indexUnitStateToRemove =
this->ogrePass->getTextureUnitStateIndex(this->ogreTexState);
this->ogrePass->removeTextureUnitState(indexUnitStateToRemove);

matManager.remove(this->ogreMaterial->getName());
this->ogreMaterial.setNull();
}
Expand All @@ -59,6 +66,32 @@ void OgreMaterial::Destroy()
this->ogreMaterial.reset();
}
#endif
auto &textureManager = Ogre::TextureManager::getSingleton();
auto iend = textureManager.getResourceIterator().end();
for (auto i = textureManager.getResourceIterator().begin(); i != iend;)
{
// A use count of 4 means that only RGM, RM and MeshManager have
// references RGM has one (this one) and RM has 2 (by name and by handle)
// and MeshManager keep another one int the template
Ogre::Resource* res = i->second.get();
if (i->second.useCount() == 4)
{
if (this->textureName == res->getName() &&
res->getName().find(
scene->Name() + "::RenderTexture") == std::string::npos)
{
OgreScenePtr s = std::dynamic_pointer_cast<OgreScene>(this->Scene());
s->ClearMaterialsCache(this->textureName);
this->Scene()->UnregisterMaterial(materialName);
if (i->second.useCount() == 3)
{
textureManager.remove(res->getHandle());
}
break;
}
}
++i;
}
}

//////////////////////////////////////////////////
Expand Down
22 changes: 22 additions & 0 deletions ogre/src/OgreMesh.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,28 @@ void OgreMesh::Destroy()

auto ogreScene = std::dynamic_pointer_cast<OgreScene>(this->Scene());

std::string ogreMeshName = this->ogreEntity->getMesh()->getName();

ogreScene->OgreSceneManager()->destroyEntity(this->ogreEntity);
this->ogreEntity = nullptr;

auto &meshManager = Ogre::MeshManager::getSingleton();
auto iend = meshManager.getResourceIterator().end();
for (auto i = meshManager.getResourceIterator().begin(); i != iend;)
{
// A use count of 3 means that only RGM and RM have references
// RGM has one (this one) and RM has 2 (by name and by handle)
Ogre::Resource* res = i->second.get();
if (i->second.useCount() == 3)
{
if (res->getName() == ogreMeshName)
{
Ogre::MeshManager::getSingleton().remove(ogreMeshName);
break;
}
}
i++;
}
}

//////////////////////////////////////////////////
Expand Down Expand Up @@ -284,6 +304,8 @@ Ogre::SubEntity *OgreSubMesh::OgreSubEntity() const
//////////////////////////////////////////////////
void OgreSubMesh::Destroy()
{
Ogre::MaterialManager::getSingleton().remove(
this->ogreSubEntity->getMaterialName());
OgreRTShaderSystem::Instance()->DetachEntity(this);

BaseSubMesh::Destroy();
Expand Down
20 changes: 20 additions & 0 deletions ogre/src/OgreMeshFactory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,25 @@ bool OgreMeshFactory::IsLoaded(const MeshDescriptor &_desc)
return Ogre::MeshManager::getSingleton().resourceExists(name);
}

//////////////////////////////////////////////////
void OgreMeshFactory::ClearMaterialsCache(const std::string &_name)
{
auto it = this->materialCache.begin();
for (auto &mat : this->materialCache)
{
std::string matName = mat->Name();
std::string textureName = mat->Texture();
if (textureName == _name)
{
this->scene->UnregisterMaterial(matName);
break;
}
++it;
}
if (it != this->materialCache.end())
this->materialCache.erase(it);
}

//////////////////////////////////////////////////
bool OgreMeshFactory::LoadImpl(const MeshDescriptor &_desc)
{
Expand Down Expand Up @@ -396,6 +415,7 @@ bool OgreMeshFactory::LoadImpl(const MeshDescriptor &_desc)
if (material)
{
mat->CopyFrom(*material);
materialCache.push_back(mat);
}
else
{
Expand Down
6 changes: 6 additions & 0 deletions ogre/src/OgreScene.cc
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@ VisualStorePtr OgreScene::Visuals() const
return this->visuals;
}

//////////////////////////////////////////////////
void OgreScene::ClearMaterialsCache(const std::string &_name)
{
this->meshFactory->ClearMaterialsCache(_name);
}

//////////////////////////////////////////////////
MaterialMapPtr OgreScene::Materials() const
{
Expand Down
15 changes: 13 additions & 2 deletions ogre2/include/ignition/rendering/ogre2/Ogre2Mesh.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ namespace ignition
//
// forward declaration
class Ogre2MeshPrivate;
class Ogre2SubMeshPrivate;

/// \brief Ogre2.x implementation of the mesh class
class IGNITION_RENDERING_OGRE2_VISIBLE Ogre2Mesh :
Expand Down Expand Up @@ -118,15 +119,22 @@ namespace ignition
/// \brief Destructor
public: virtual ~Ogre2SubMesh();

// Documentation inherited
public: virtual void Destroy() override;

/// \brief Set the name of the mesh stored in Ogre2
/// \param[in] _name Name of the mesh
public: void SetMeshName(const std::string &_name);

/// \brief Get internal ogre subitem created from this submesh
public: virtual Ogre::SubItem *Ogre2SubItem() const;

/// \brief Helper function for setting the material to use
/// \param[in] _material Material to be assigned to the submesh
protected: virtual void SetMaterialImpl(MaterialPtr _material);
protected: virtual void SetMaterialImpl(MaterialPtr _material) override;

/// \brief Initialize the submesh
protected: virtual void Init();
protected: virtual void Init() override;

/// \brief Ogre subitem representing the submesh
protected: Ogre::SubItem *ogreSubItem = nullptr;
Expand All @@ -137,6 +145,9 @@ namespace ignition
/// \brief Make submesh factory our friend so it can create an
/// ogre2 submesh
private: friend class Ogre2SubMeshStoreFactory;

/// \brief Pointer to private data
private: std::unique_ptr<Ogre2SubMeshPrivate> dataPtr;
};
}
}
Expand Down
3 changes: 3 additions & 0 deletions ogre2/include/ignition/rendering/ogre2/Ogre2MeshFactory.hh
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ namespace ignition
/// \brief Pointer to the scene object
protected: Ogre2ScenePtr scene;

/// \brief Remove internal material cache for a specific material
public: void ClearMaterialsCache(const std::string &_name);

/// \brief Pointer to private data class
private: std::unique_ptr<Ogre2MeshFactoryPrivate> dataPtr;
};
Expand Down
4 changes: 4 additions & 0 deletions ogre2/include/ignition/rendering/ogre2/Ogre2Scene.hh
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,10 @@ namespace ignition
/// \brief Create the vaiours storage objects
private: void CreateStores();

/// \brief Remove internal material cache for a specific material
/// \param[in] _name Name of the template material to remove.
public: void ClearMaterialsCache(const std::string &_name);

/// \brief Create a shared pointer to self
private: Ogre2ScenePtr SharedThis();

Expand Down
38 changes: 38 additions & 0 deletions ogre2/src/Ogre2Material.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <Hlms/Unlit/OgreHlmsUnlitDatablock.h>
#include <OgreHlmsManager.h>
#include <OgreMaterialManager.h>
#include <OgreTextureManager.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
Expand All @@ -44,6 +45,9 @@
/// \brief Private data for the Ogre2Material class
class ignition::rendering::Ogre2MaterialPrivate
{
/// \brief Ogre stores the name using hashes. This variable will
/// store the material hash name
public: std::string hashName;
};

using namespace ignition;
Expand Down Expand Up @@ -87,6 +91,39 @@ void Ogre2Material::Destroy()
matManager.remove(this->ogreMaterial);
this->ogreMaterial.reset();
}

auto &textureManager = Ogre::TextureManager::getSingleton();
auto iend = textureManager.getResourceIterator().end();
for (auto i = textureManager.getResourceIterator().begin(); i != iend;)
{
// A use count of 4 means that only RGM, RM and MeshManager have references
// RGM has one (this one) and RM has 2 (by name and by handle)
// and MeshManager keep another one int the template
Ogre::Resource* res = i->second.get();
if (i->second.useCount() == 5)
{
if (this->dataPtr->hashName == res->getName() &&
res->getName().find(
scene->Name() + "::RenderTexture") == std::string::npos)
{
Ogre2ScenePtr s = std::dynamic_pointer_cast<Ogre2Scene>(this->Scene());
s->ClearMaterialsCache(this->textureName);
this->Scene()->UnregisterMaterial(this->name);
if (i->second.useCount() == 4)
{
textureManager.remove(res->getHandle());
if (!this->textureName.empty())
{
Ogre::HlmsTextureManager *hlmsTextureManager =
this->ogreHlmsPbs->getHlmsManager()->getTextureManager();
hlmsTextureManager->destroyTexture(this->textureName);
}
}
break;
}
}
++i;
}
}

//////////////////////////////////////////////////
Expand Down Expand Up @@ -538,6 +575,7 @@ void Ogre2Material::SetTextureMapImpl(const std::string &_texture,
Ogre::HlmsTextureManager::TextureLocation texLocation =
hlmsTextureManager->createOrRetrieveTexture(baseName,
this->ogreDatablock->suggestMapTypeBasedOnTextureType(_type));
this->dataPtr->hashName = texLocation.texture->getName();

Ogre::HlmsSamplerblock samplerBlockRef;
samplerBlockRef.mU = Ogre::TAM_WRAP;
Expand Down
46 changes: 46 additions & 0 deletions ogre2/src/Ogre2Mesh.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#include <Hlms/Pbs/OgreHlmsPbsDatablock.h>
#include <OgreItem.h>
#include <OgreSceneManager.h>
#include <OgreMeshManager.h>
#include <OgreMeshManager2.h>
#include <OgreMaterialManager.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
Expand All @@ -40,6 +43,14 @@ class ignition::rendering::Ogre2MeshPrivate
{
};

/// brief Private implementation of the Ogre2SubMesh class
class ignition::rendering::Ogre2SubMeshPrivate
{
/// \brief name of the mesh inside the mesh manager to be able to
/// remove it
public: std::string subMeshName;
};

using namespace ignition;
using namespace rendering;

Expand Down Expand Up @@ -271,6 +282,7 @@ SubMeshStorePtr Ogre2Mesh::SubMeshes() const

//////////////////////////////////////////////////
Ogre2SubMesh::Ogre2SubMesh()
: dataPtr(new Ogre2SubMeshPrivate)
{
}

Expand All @@ -280,6 +292,40 @@ Ogre2SubMesh::~Ogre2SubMesh()
this->Destroy();
}

//////////////////////////////////////////////////
void Ogre2SubMesh::SetMeshName(const std::string &_name)
{
this->dataPtr->subMeshName = _name;
}

//////////////////////////////////////////////////
void Ogre2SubMesh::Destroy()
{
auto meshManager = Ogre::MeshManager::getSingletonPtr();
if (meshManager)
{
auto iend = meshManager->getResourceIterator().end();
for (auto i = meshManager->getResourceIterator().begin(); i != iend;)
{
// A use count of 43 means that only RGM and RM have
// references RGM has one (this one) and RM has 2 (by name and by handle)
Ogre::Resource* res = i->second.get();
if (i->second.useCount() == 3)
{
if (res->getName() == this->dataPtr->subMeshName)
{
Ogre::v1::MeshManager::getSingleton().remove(
this->dataPtr->subMeshName);
Ogre::MeshManager::getSingleton().remove(this->dataPtr->subMeshName);
break;
}
}
++i;
}
}
BaseSubMesh::Destroy();
}

//////////////////////////////////////////////////
Ogre::SubItem *Ogre2SubMesh::Ogre2SubItem() const
{
Expand Down
Loading