diff --git a/graphics/include/gz/common/MeshManager.hh b/graphics/include/gz/common/MeshManager.hh index da2194bc..aaa9912b 100644 --- a/graphics/include/gz/common/MeshManager.hh +++ b/graphics/include/gz/common/MeshManager.hh @@ -107,7 +107,11 @@ namespace gz /// This MeshManager takes ownership of the mesh and will destroy it. /// See ~MeshManager. /// \param[in] the mesh to add. - public: void AddMesh(Mesh *_mesh); + /// \deprecated This API requires the user to allocate a Mesh object on + /// the heap and "move" it into MeshManager. However, this is not safe to + /// do across shared library boundaries and may cause segfaults during + /// MeshManager destruction. Use \ref CreateMesh instead + public: void GZ_DEPRECATED(8) AddMesh(Mesh *_mesh); /// \brief Remove a mesh based on a name. /// \param[in] _name Name of the mesh to remove. @@ -128,6 +132,13 @@ namespace gz /// \param[in] _name the name of the mesh public: bool HasMesh(const std::string &_name) const; + /// \brief Create an empty mesh and register it by name. If the mesh + /// already exists, returns nullptr. + /// \param[in] _name the name of the new mesh + /// \return a mutable pointer pointing to the newly allocated mesh, or + /// nullptr if the mesh name is already claimed. + public: common::Mesh *CreateMesh(const std::string &_name); + /// \brief Create a sphere mesh. /// \param[in] _name the name of the mesh /// \param[in] _radius radius of the sphere in meter diff --git a/graphics/src/MeshManager.cc b/graphics/src/MeshManager.cc index 5ebdd78f..ef329b04 100644 --- a/graphics/src/MeshManager.cc +++ b/graphics/src/MeshManager.cc @@ -261,6 +261,27 @@ void MeshManager::AddMesh(Mesh *_mesh) this->dataPtr->meshes[_mesh->Name()] = _mesh; } +////////////////////////////////////////////////// +Mesh *MeshManager::CreateMesh(const std::string &_name) +{ + if (_name.empty()) + { + gzerr << "Valid mesh name required." << std::endl; + return nullptr; + } + + if (this->HasMesh(_name)) + { + gzerr << "Mesh [" << _name << "] already exists." << std::endl; + return nullptr; + } + + Mesh *newMesh = new Mesh(); + newMesh->SetName(_name); + this->dataPtr->meshes[_name] = newMesh; + return newMesh; +} + ////////////////////////////////////////////////// const Mesh *MeshManager::MeshByName(const std::string &_name) const { diff --git a/graphics/src/MeshManager_TEST.cc b/graphics/src/MeshManager_TEST.cc index 66eed64f..d68b75f6 100644 --- a/graphics/src/MeshManager_TEST.cc +++ b/graphics/src/MeshManager_TEST.cc @@ -425,4 +425,37 @@ TEST_F(MeshManager, MergeSubMeshes) EXPECT_EQ(math::Vector2d(0, 0.6), mergedSubmesh->TexCoordBySet(5u, 2u)); } +///////////////////////////////////////////////// +TEST_F(MeshManager, CreateMesh) +{ + auto *mgr = common::MeshManager::Instance(); + std::string meshName = "test_create_mesh"; + + // Pre-condition + EXPECT_FALSE(mgr->HasMesh(meshName)); + EXPECT_EQ(nullptr, mgr->MeshByName(meshName)); + + // Create the mesh + common::Mesh *mutableMesh = mgr->CreateMesh(meshName); + ASSERT_NE(nullptr, mutableMesh); + EXPECT_EQ(meshName, mutableMesh->Name()); + + // Fetch the newly created mesh + const common::Mesh *cachedMesh = mgr->MeshByName(meshName); + ASSERT_NE(nullptr, cachedMesh); + EXPECT_EQ(mutableMesh, cachedMesh); + EXPECT_TRUE(mgr->HasMesh(meshName)); + + // Attempt to create the same mesh again should return nullptr safely + common::Mesh *duplicateMesh = mgr->CreateMesh(meshName); + EXPECT_EQ(nullptr, duplicateMesh); + + // Verify original mesh is intact + const common::Mesh *verifyMesh = mgr->MeshByName(meshName); + EXPECT_NE(nullptr, verifyMesh); + EXPECT_EQ(meshName, verifyMesh->Name()); + + mgr->RemoveAll(); +} + #endif