diff --git a/ogre/include/ignition/rendering/ogre/OgreMeshFactory.hh b/ogre/include/ignition/rendering/ogre/OgreMeshFactory.hh index ceecd1916..6c28369ab 100644 --- a/ogre/include/ignition/rendering/ogre/OgreMeshFactory.hh +++ b/ogre/include/ignition/rendering/ogre/OgreMeshFactory.hh @@ -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 materialCache; }; class IGNITION_RENDERING_OGRE_VISIBLE OgreSubMeshStoreFactory diff --git a/ogre/include/ignition/rendering/ogre/OgreScene.hh b/ogre/include/ignition/rendering/ogre/OgreScene.hh index 11145b2ac..fca6a5c2d 100644 --- a/ogre/include/ignition/rendering/ogre/OgreScene.hh +++ b/ogre/include/ignition/rendering/ogre/OgreScene.hh @@ -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(); diff --git a/ogre/src/OgreMaterial.cc b/ogre/src/OgreMaterial.cc index 69406aed7..a558c6fd9 100644 --- a/ogre/src/OgreMaterial.cc +++ b/ogre/src/OgreMaterial.cc @@ -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_11_0 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(); } @@ -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(this->Scene()); + s->ClearMaterialsCache(this->textureName); + this->Scene()->UnregisterMaterial(materialName); + if (i->second.useCount() == 3) + { + textureManager.remove(res->getHandle()); + } + break; + } + } + ++i; + } } ////////////////////////////////////////////////// diff --git a/ogre/src/OgreMesh.cc b/ogre/src/OgreMesh.cc index 764262636..bf77874a7 100644 --- a/ogre/src/OgreMesh.cc +++ b/ogre/src/OgreMesh.cc @@ -58,8 +58,28 @@ void OgreMesh::Destroy() auto ogreScene = std::dynamic_pointer_cast(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++; + } } ////////////////////////////////////////////////// @@ -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(); diff --git a/ogre/src/OgreMeshFactory.cc b/ogre/src/OgreMeshFactory.cc index c1101e825..d30c55a79 100644 --- a/ogre/src/OgreMeshFactory.cc +++ b/ogre/src/OgreMeshFactory.cc @@ -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) { @@ -396,6 +415,7 @@ bool OgreMeshFactory::LoadImpl(const MeshDescriptor &_desc) if (material) { mat->CopyFrom(*material); + materialCache.push_back(mat); } else { diff --git a/ogre/src/OgreScene.cc b/ogre/src/OgreScene.cc index e30bff8a7..c9e0a97e7 100644 --- a/ogre/src/OgreScene.cc +++ b/ogre/src/OgreScene.cc @@ -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 { diff --git a/ogre2/include/ignition/rendering/ogre2/Ogre2Mesh.hh b/ogre2/include/ignition/rendering/ogre2/Ogre2Mesh.hh index 038c9c3b4..cbad21a14 100644 --- a/ogre2/include/ignition/rendering/ogre2/Ogre2Mesh.hh +++ b/ogre2/include/ignition/rendering/ogre2/Ogre2Mesh.hh @@ -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 : @@ -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; @@ -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 dataPtr; }; } } diff --git a/ogre2/include/ignition/rendering/ogre2/Ogre2MeshFactory.hh b/ogre2/include/ignition/rendering/ogre2/Ogre2MeshFactory.hh index e98a253b1..202607cea 100644 --- a/ogre2/include/ignition/rendering/ogre2/Ogre2MeshFactory.hh +++ b/ogre2/include/ignition/rendering/ogre2/Ogre2MeshFactory.hh @@ -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 dataPtr; }; diff --git a/ogre2/include/ignition/rendering/ogre2/Ogre2Scene.hh b/ogre2/include/ignition/rendering/ogre2/Ogre2Scene.hh index 7193708f4..e4d05a2f9 100644 --- a/ogre2/include/ignition/rendering/ogre2/Ogre2Scene.hh +++ b/ogre2/include/ignition/rendering/ogre2/Ogre2Scene.hh @@ -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(); diff --git a/ogre2/src/Ogre2Material.cc b/ogre2/src/Ogre2Material.cc index f72d2b9e0..024ac33ef 100644 --- a/ogre2/src/Ogre2Material.cc +++ b/ogre2/src/Ogre2Material.cc @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef _MSC_VER #pragma warning(pop) #endif @@ -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; @@ -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(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; + } } ////////////////////////////////////////////////// @@ -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; diff --git a/ogre2/src/Ogre2Mesh.cc b/ogre2/src/Ogre2Mesh.cc index f47ee04cb..cff027eb3 100644 --- a/ogre2/src/Ogre2Mesh.cc +++ b/ogre2/src/Ogre2Mesh.cc @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #ifdef _MSC_VER #pragma warning(pop) #endif @@ -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; @@ -271,6 +282,7 @@ SubMeshStorePtr Ogre2Mesh::SubMeshes() const ////////////////////////////////////////////////// Ogre2SubMesh::Ogre2SubMesh() + : dataPtr(new Ogre2SubMeshPrivate) { } @@ -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 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() == 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 { diff --git a/ogre2/src/Ogre2MeshFactory.cc b/ogre2/src/Ogre2MeshFactory.cc index 0d460c0bc..82d392abb 100644 --- a/ogre2/src/Ogre2MeshFactory.cc +++ b/ogre2/src/Ogre2MeshFactory.cc @@ -58,6 +58,9 @@ /// \brief Private data for the Ogre2MeshFactory class class ignition::rendering::Ogre2MeshFactoryPrivate { + /// \brief Vector with the template materials, we keep the pointer to be + /// able to remove it when nobody is using it. + public: std::vector materialCache; }; /// \brief Private data for the Ogre2SubMeshStoreFactory class @@ -88,6 +91,25 @@ void Ogre2MeshFactory::Clear() this->ogreMeshes.clear(); } +////////////////////////////////////////////////// +void Ogre2MeshFactory::ClearMaterialsCache(const std::string &_name) +{ + auto it = this->dataPtr->materialCache.begin(); + for (auto &mat : this->dataPtr->materialCache) + { + std::string matName = mat->Name(); + std::string textureName = mat->Texture(); + if (textureName == _name) + { + this->scene->UnregisterMaterial(matName); + break; + } + ++it; + } + if (it != this->dataPtr->materialCache.end()) + this->dataPtr->materialCache.erase(it); +} + ////////////////////////////////////////////////// Ogre2MeshPtr Ogre2MeshFactory::Create(const MeshDescriptor &_desc) { @@ -108,6 +130,12 @@ Ogre2MeshPtr Ogre2MeshFactory::Create(const MeshDescriptor &_desc) // create sub-mesh store Ogre2SubMeshStoreFactory subMeshFactory(this->scene, mesh->ogreItem); mesh->subMeshes = subMeshFactory.Create(); + for (unsigned int i = 0; i < mesh->subMeshes->Size(); i++) + { + Ogre2SubMeshPtr submesh = + std::dynamic_pointer_cast(mesh->subMeshes->GetById(i)); + submesh->SetMeshName(this->MeshName(_desc)); + } return mesh; } @@ -447,6 +475,7 @@ bool Ogre2MeshFactory::LoadImpl(const MeshDescriptor &_desc) if (material) { mat->CopyFrom(*material); + this->dataPtr->materialCache.push_back(mat); } else { diff --git a/ogre2/src/Ogre2Scene.cc b/ogre2/src/Ogre2Scene.cc index 580734ef5..59f53be0e 100644 --- a/ogre2/src/Ogre2Scene.cc +++ b/ogre2/src/Ogre2Scene.cc @@ -116,6 +116,12 @@ math::Color Ogre2Scene::AmbientLight() const return Ogre2Conversions::Convert(ogreColor); } +////////////////////////////////////////////////// +void Ogre2Scene::ClearMaterialsCache(const std::string &_name) +{ + this->meshFactory->ClearMaterialsCache(_name); +} + ////////////////////////////////////////////////// void Ogre2Scene::SetAmbientLight(const math::Color &_color) {