From 95724d1ec226135780c9fcc56a28860f7bde676d Mon Sep 17 00:00:00 2001 From: Mark Yang Date: Sat, 7 Mar 2026 21:45:12 -0500 Subject: [PATCH] Fix vfs load for mesh gmeshs type --- src/user/user_flexcomp.cc | 14 ++++++------ src/user/user_flexcomp.h | 8 ++++--- src/xml/xml_native_reader.cc | 2 +- test/user/user_flex_test.cc | 43 ++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/user/user_flexcomp.cc b/src/user/user_flexcomp.cc index 7997c8de..b313a671 100644 --- a/src/user/user_flexcomp.cc +++ b/src/user/user_flexcomp.cc @@ -99,7 +99,7 @@ mjCFlexcomp::mjCFlexcomp(void) { // make flexcomp object -bool mjCFlexcomp::Make(mjsBody* body, char* error, int error_sz) { +bool mjCFlexcomp::Make(mjsBody* body, char* error, int error_sz, const mjVFS* vfs) { mjCModel* model = static_cast(body->element)->model; mjsCompiler* compiler = static_cast(body->element)->compiler; mjsFlex* dflex = def.spec.flex; @@ -170,11 +170,11 @@ bool mjCFlexcomp::Make(mjsBody* body, char* error, int error_sz) { break; case mjFCOMPTYPE_MESH: - res = MakeMesh(model, compiler, error, error_sz); + res = MakeMesh(model, compiler, error, error_sz, vfs); break; case mjFCOMPTYPE_GMSH: - res = MakeGMSH(model, compiler, error, error_sz); + res = MakeGMSH(model, compiler, error, error_sz, vfs); break; case mjFCOMPTYPE_DIRECT: @@ -1129,7 +1129,7 @@ template static T* VecToArray(std::vector& vector, bool clear = // make mesh -bool mjCFlexcomp::MakeMesh(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz) { +bool mjCFlexcomp::MakeMesh(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz, const mjVFS* vfs) { // strip path if (!file.empty() && model->spec.strippath) { file = mjuu_strippath(file); @@ -1156,7 +1156,7 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, mjsCompiler* compiler, char* error, try { resource = mjCBase::LoadResource(mjs_getString(model->spec.modelfiledir), - filename, 0); + filename, vfs); } catch (mjCError err) { return comperr(error, err.message, error_sz); } @@ -1248,7 +1248,7 @@ static int findstring(const char* buffer, int buffer_sz, const char* str) { // load points and elements from GMSH file -bool mjCFlexcomp::MakeGMSH(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz) { +bool mjCFlexcomp::MakeGMSH(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz, const mjVFS* vfs) { // strip path if (!file.empty() && model->spec.strippath) { file = mjuu_strippath(file); @@ -1264,7 +1264,7 @@ bool mjCFlexcomp::MakeGMSH(mjCModel* model, mjsCompiler* compiler, char* error, try { std::string filename = mjuu_combinePaths(mjs_getString(compiler->meshdir), file); resource = mjCBase::LoadResource(mjs_getString(model->spec.modelfiledir), - filename, 0); + filename, vfs); } catch (mjCError err) { return comperr(error, err.message, error_sz); } diff --git a/src/user/user_flexcomp.h b/src/user/user_flexcomp.h index dd3374c8..4b346cf4 100644 --- a/src/user/user_flexcomp.h +++ b/src/user/user_flexcomp.h @@ -53,13 +53,15 @@ typedef enum _mjtDof { class mjCFlexcomp { public: mjCFlexcomp(void); - bool Make(mjsBody* body, char* error, int error_sz); + bool Make(mjsBody* body, char* error, int error_sz, const mjVFS* vfs = nullptr); bool MakeGrid(char* error, int error_sz); bool MakeBox(char* error, int error_sz, int dim, bool open = true); bool MakeSquare(char* error, int error_sz); - bool MakeMesh(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz); - bool MakeGMSH(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz); + bool MakeMesh(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz, + const mjVFS* vfs = nullptr); + bool MakeGMSH(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz, + const mjVFS* vfs = nullptr); void LoadGMSH(mjCModel* model, mjResource* resource); void LoadGMSH41(char* buffer, int binary, int nodeend, int nodebegin, int elemend, int elembegin); diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 430d1d4a..ebbfb24f 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -2849,7 +2849,7 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjsBody* body, const mjVFS* vfs) { // make flexcomp char error[200]; - bool res = fcomp.Make(body, error, 200); + bool res = fcomp.Make(body, error, 200, vfs); // throw error if (!res) { diff --git a/test/user/user_flex_test.cc b/test/user/user_flex_test.cc index 841bcdac..c37ac7dc 100644 --- a/test/user/user_flex_test.cc +++ b/test/user/user_flex_test.cc @@ -15,6 +15,7 @@ // Tests for user/user_model.cc. #include +#include #include #include @@ -876,5 +877,47 @@ TEST_F(UserFlexTest, MeshNodePinning) { mj_deleteModel(m); } +TEST_F(UserFlexTest, FlexcompMeshLoadsFromVFS) { + // read cube.stl from testdata into a buffer + const std::string stl_path = + GetTestDataFilePath("user/testdata/cube.stl"); + FILE* f = fopen(stl_path.c_str(), "rb"); + ASSERT_THAT(f, NotNull()) << "Could not open " << stl_path; + fseek(f, 0, SEEK_END); + long stl_size = ftell(f); + fseek(f, 0, SEEK_SET); + std::string stl_data(stl_size, '\0'); + fread(stl_data.data(), 1, stl_size, f); + fclose(f); + + // add the STL data to a VFS + mjVFS vfs; + mj_defaultVFS(&vfs); + mj_addBufferVFS(&vfs, "cube.stl", stl_data.data(), stl_size); + + // XML that uses flexcomp type="mesh" referencing the VFS file + static constexpr char xml[] = R"( + + + + + + + + + + )"; + + // cleanup + std::array error; + mjModel* m = LoadModelFromString(xml, error.data(), error.size(), &vfs); + ASSERT_THAT(m, NotNull()) << error.data(); + mjData* d = mj_makeData(m); + mj_step(m, d); + mj_deleteData(d); + mj_deleteModel(m); + mj_deleteVFS(&vfs); +} + } // namespace } // namespace mujoco