diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index 94000819..34e29119 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -220,6 +220,10 @@ void mjCMesh::PointToLocal() { void mjCMesh::NameSpace(const mjCModel* m) { + if (name.empty()) { + std::string stripped = mjuu_strippath(spec_file_); + name = mjuu_stripext(stripped); + } mjCBase::NameSpace(m); if (modelfiledir_.empty()) { modelfiledir_ = FilePath(m->spec_modelfiledir_); @@ -252,6 +256,12 @@ void mjCMesh::CopyFromSpec() { szgraph_ = 0; center_ = NULL; graph_ = NULL; + + // use filename if name is missing + if (name.empty()) { + std::string stripped = mjuu_strippath(file_); + name = mjuu_stripext(stripped); + } } @@ -2034,6 +2044,11 @@ void mjCSkin::PointToLocal() { void mjCSkin::NameSpace(const mjCModel* m) { + // use filename if name is missing + if (name.empty()) { + std::string stripped = mjuu_strippath(spec_file_); + name = mjuu_stripext(stripped); + } for (auto& name : spec_bodyname_) { name = m->prefix + name + m->suffix; } @@ -2059,6 +2074,12 @@ void mjCSkin::CopyFromSpec() { bindquat_ = spec_bindquat_; vertid_ = spec_vertid_; vertweight_ = spec_vertweight_; + + // use filename if name is missing + if (name.empty()) { + std::string stripped = mjuu_strippath(file_); + name = mjuu_stripext(stripped); + } } diff --git a/src/user/user_model.cc b/src/user/user_model.cc index c5e650b2..13679ef9 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -1428,23 +1428,6 @@ void mjCModel::IndexAssets(bool discard) { -// if asset name is missing, set to filename -template -void mjCModel::SetDefaultNames(std::vector& assets) { - string stripped; - - // use filename if name is missing - for (int i=0; iCopyFromSpec(); - if (assets[i]->name.empty()) { - stripped = mjuu_strippath(assets[i]->File()); - assets[i]->name = mjuu_stripext(stripped); - } - } -} - - - // throw error if a name is missing void mjCModel::CheckEmptyNames(void) { // meshes @@ -3772,10 +3755,10 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { MakeLists(bodies_[0]); // fill missing names and check that they are all filled - SetDefaultNames(meshes_); - SetDefaultNames(skins_); - SetDefaultNames(hfields_); - SetDefaultNames(textures_); + for (const auto& asset : meshes_) asset->CopyFromSpec(); + for (const auto& asset : skins_) asset->CopyFromSpec(); + for (const auto& asset : hfields_) asset->CopyFromSpec(); + for (const auto& asset : textures_) asset->CopyFromSpec(); CheckEmptyNames(); // create pending keyframes diff --git a/src/user/user_model.h b/src/user/user_model.h index f3607c7f..88bcd9ee 100644 --- a/src/user/user_model.h +++ b/src/user/user_model.h @@ -279,9 +279,6 @@ class mjCModel : public mjCModel_, private mjSpec { // multi-threaded mesh compilation void CompileMeshes(const mjVFS* vfs); - // if asset name is missing, set to filename - template void SetDefaultNames(std::vector& assets); - // delete material from object template void DeleteMaterial(std::vector& list, std::string_view name = ""); diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 441e0c12..aa37a895 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -3399,11 +3399,22 @@ void mjCHField::CopyFromSpec() { nrow = 0; ncol = 0; } + + // use filename if name is missing + if (name.empty()) { + std::string stripped = mjuu_strippath(file_); + name = mjuu_stripext(stripped); + } } void mjCHField::NameSpace(const mjCModel* m) { + // use filename if name is missing + if (name.empty()) { + std::string stripped = mjuu_strippath(spec_file_); + name = mjuu_stripext(stripped); + } mjCBase::NameSpace(m); if (modelfiledir_.empty()) { modelfiledir_ = FilePath(m->spec_modelfiledir_); @@ -3648,11 +3659,22 @@ void mjCTexture::CopyFromSpec() { // clear precompiled asset. TODO: use asset cache data_.clear(); } + + // use filename if name is missing + if (name.empty()) { + std::string stripped = mjuu_strippath(file_); + name = mjuu_stripext(stripped); + } } void mjCTexture::NameSpace(const mjCModel* m) { + // use filename if name is missing + if (name.empty()) { + std::string stripped = mjuu_strippath(spec_file_); + name = mjuu_stripext(stripped); + } mjCBase::NameSpace(m); if (modelfiledir_.empty()) { modelfiledir_ = FilePath(m->spec_modelfiledir_); diff --git a/test/user/user_api_test.cc b/test/user/user_api_test.cc index bb084d6c..cdad61b3 100644 --- a/test/user/user_api_test.cc +++ b/test/user/user_api_test.cc @@ -1156,5 +1156,43 @@ TEST_F(MujocoTest, AttachMocap) { mj_deleteModel(m_expected); } +TEST_F(MujocoTest, AttachUnnamedAssets) { + static constexpr char cube[] = R"( + v -1 -1 1 + v 1 -1 1 + v -1 1 1 + v 1 1 1 + v -1 1 -1 + v 1 1 -1 + v -1 -1 -1 + v 1 -1 -1)"; + + auto vfs = std::make_unique(); + mj_defaultVFS(vfs.get()); + mj_addBufferVFS(vfs.get(), "cube.obj", cube, sizeof(cube)); + + mjSpec* child = mj_makeSpec(); + mjsMesh* mesh = mjs_addMesh(child, 0); + mjsFrame* frame = mjs_addFrame(mjs_findBody(child, "world"), 0); + mjsGeom* geom = mjs_addGeom(mjs_findBody(child, "world"), 0); + mjs_setFrame(geom->element, frame); + mjs_setString(mesh->file, "cube.obj"); + mjs_setString(geom->meshname, "cube"); + geom->type = mjGEOM_MESH; + + mjSpec* spec = mj_makeSpec(); + mjs_attachFrame(mjs_findBody(spec, "world"), frame, "_", ""); + + mjModel* model = mj_compile(spec, vfs.get()); + EXPECT_THAT(model, NotNull()); + EXPECT_THAT(model->nmesh, 1); + EXPECT_STREQ(mj_id2name(model, mjOBJ_MESH, 0), "_cube"); + + mj_deleteVFS(vfs.get()); + mj_deleteSpec(child); + mj_deleteSpec(spec); + mj_deleteModel(model); +} + } // namespace } // namespace mujoco