No public description

PiperOrigin-RevId: 809083979
Change-Id: I5c6641b73c76153c15f5cdf858b788e1433acc81
This commit is contained in:
Google DeepMind
2025-09-19 10:09:54 -07:00
committed by Copybara-Service
parent 26ea20a21f
commit 0e1104768a
16 changed files with 98 additions and 79 deletions
+2 -2
View File
@@ -1845,6 +1845,8 @@ typedef struct mjsCompiler_ { // compiler options
mjtByte saveinertial; // save explicit inertial clause for all bodies to XML mjtByte saveinertial; // save explicit inertial clause for all bodies to XML
int alignfree; // align free joints with inertial frame int alignfree; // align free joints with inertial frame
mjLROpt LRopt; // options for lengthrange computation mjLROpt LRopt; // options for lengthrange computation
mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory
} mjsCompiler; } mjsCompiler;
typedef struct mjSpec_ { // model specification typedef struct mjSpec_ { // model specification
mjsElement* element; // element type mjsElement* element; // element type
@@ -1853,8 +1855,6 @@ typedef struct mjSpec_ { // model specification
// compiler data // compiler data
mjsCompiler compiler; // compiler options mjsCompiler compiler; // compiler options
mjtByte strippath; // automatically strip paths from mesh files mjtByte strippath; // automatically strip paths from mesh files
mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory
// engine data // engine data
mjOption option; // physics options mjOption option; // physics options
+2 -2
View File
@@ -151,6 +151,8 @@ typedef struct mjsCompiler_ { // compiler options
mjtByte saveinertial; // save explicit inertial clause for all bodies to XML mjtByte saveinertial; // save explicit inertial clause for all bodies to XML
int alignfree; // align free joints with inertial frame int alignfree; // align free joints with inertial frame
mjLROpt LRopt; // options for lengthrange computation mjLROpt LRopt; // options for lengthrange computation
mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory
} mjsCompiler; } mjsCompiler;
@@ -161,8 +163,6 @@ typedef struct mjSpec_ { // model specification
// compiler data // compiler data
mjsCompiler compiler; // compiler options mjsCompiler compiler; // compiler options
mjtByte strippath; // automatically strip paths from mesh files mjtByte strippath; // automatically strip paths from mesh files
mjString* meshdir; // mesh and hfield directory
mjString* texturedir; // texture directory
// engine data // engine data
mjOption option; // physics options mjOption option; // physics options
+14 -14
View File
@@ -7928,6 +7928,20 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='mjLROpt'), type=ValueType(name='mjLROpt'),
doc='options for lengthrange computation', doc='options for lengthrange computation',
), ),
StructFieldDecl(
name='meshdir',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='mesh and hfield directory',
),
StructFieldDecl(
name='texturedir',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='texture directory',
),
), ),
)), )),
('mjSpec', ('mjSpec',
@@ -7959,20 +7973,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='mjtByte'), type=ValueType(name='mjtByte'),
doc='automatically strip paths from mesh files', doc='automatically strip paths from mesh files',
), ),
StructFieldDecl(
name='meshdir',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='mesh and hfield directory',
),
StructFieldDecl(
name='texturedir',
type=PointerType(
inner_type=ValueType(name='mjString'),
),
doc='texture directory',
),
StructFieldDecl( StructFieldDecl(
name='option', name='option',
type=ValueType(name='mjOption'), type=ValueType(name='mjOption'),
+16
View File
@@ -593,6 +593,22 @@ PYBIND11_MODULE(_specs, m) {
}, },
py::arg("degree"), py::arg("sequence") = py::none(), py::arg("degree"), py::arg("sequence") = py::none(),
py::arg("orientation"), py::return_value_policy::copy); py::arg("orientation"), py::return_value_policy::copy);
mjSpec.def_property(
"meshdir",
[](MjSpec& self) -> std::string_view {
return *self.ptr->compiler.meshdir;
},
[](MjSpec& self, std::string_view meshdir) {
*(self.ptr->compiler.meshdir) = meshdir;
});
mjSpec.def_property(
"texturedir",
[](MjSpec& self) -> std::string_view {
return *self.ptr->compiler.texturedir;
},
[](MjSpec& self, std::string_view texturedir) {
*(self.ptr->compiler.texturedir) = texturedir;
});
// ============================= MJSBODY ===================================== // ============================= MJSBODY =====================================
mjsBody.def( mjsBody.def(
+1 -1
View File
@@ -297,7 +297,7 @@ int mjs_isWarning(mjSpec* s) {
void mj_deleteSpec(mjSpec* s) { void mj_deleteSpec(mjSpec* s) {
if (s) { if (s) {
mjCModel* model = static_cast<mjCModel*>(s->element); mjCModel* model = static_cast<mjCModel*>(s->element);
delete model; model->Release();
} }
} }
+6 -6
View File
@@ -170,11 +170,11 @@ bool mjCFlexcomp::Make(mjsBody* body, char* error, int error_sz) {
break; break;
case mjFCOMPTYPE_MESH: case mjFCOMPTYPE_MESH:
res = MakeMesh(model, error, error_sz); res = MakeMesh(model, compiler, error, error_sz);
break; break;
case mjFCOMPTYPE_GMSH: case mjFCOMPTYPE_GMSH:
res = MakeGMSH(model, error, error_sz); res = MakeGMSH(model, compiler, error, error_sz);
break; break;
case mjFCOMPTYPE_DIRECT: case mjFCOMPTYPE_DIRECT:
@@ -1075,7 +1075,7 @@ template <typename T> static T* VecToArray(std::vector<T>& vector, bool clear =
// make mesh // make mesh
bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) { bool mjCFlexcomp::MakeMesh(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz) {
// strip path // strip path
if (!file.empty() && model->spec.strippath) { if (!file.empty() && model->spec.strippath) {
file = mjuu_strippath(file); file = mjuu_strippath(file);
@@ -1092,7 +1092,7 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) {
} }
// load resource // load resource
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.meshdir), file); std::string filename = mjuu_combinePaths(mjs_getString(compiler->meshdir), file);
mjResource* resource = nullptr; mjResource* resource = nullptr;
@@ -1194,7 +1194,7 @@ static int findstring(const char* buffer, int buffer_sz, const char* str) {
// load points and elements from GMSH file // load points and elements from GMSH file
bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) { bool mjCFlexcomp::MakeGMSH(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz) {
// strip path // strip path
if (!file.empty() && model->spec.strippath) { if (!file.empty() && model->spec.strippath) {
file = mjuu_strippath(file); file = mjuu_strippath(file);
@@ -1208,7 +1208,7 @@ bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) {
// open resource // open resource
mjResource* resource = nullptr; mjResource* resource = nullptr;
try { try {
std::string filename = mjuu_combinePaths(mjs_getString(model->spec.meshdir), file); std::string filename = mjuu_combinePaths(mjs_getString(compiler->meshdir), file);
resource = mjCBase::LoadResource(mjs_getString(model->spec.modelfiledir), resource = mjCBase::LoadResource(mjs_getString(model->spec.modelfiledir),
filename, 0); filename, 0);
} catch (mjCError err) { } catch (mjCError err) {
+2 -2
View File
@@ -57,8 +57,8 @@ class mjCFlexcomp {
bool MakeGrid(char* error, int error_sz); bool MakeGrid(char* error, int error_sz);
bool MakeBox(char* error, int error_sz, int dim, bool open = true); bool MakeBox(char* error, int error_sz, int dim, bool open = true);
bool MakeSquare(char* error, int error_sz); bool MakeSquare(char* error, int error_sz);
bool MakeMesh(mjCModel* model, char* error, int error_sz); bool MakeMesh(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz);
bool MakeGMSH(mjCModel* model, char* error, int error_sz); bool MakeGMSH(mjCModel* model, mjsCompiler* compiler, char* error, int error_sz);
void LoadGMSH(mjCModel* model, mjResource* resource); void LoadGMSH(mjCModel* model, mjResource* resource);
void LoadGMSH41(char* buffer, int binary, int nodeend, int nodebegin, void LoadGMSH41(char* buffer, int binary, int nodeend, int nodebegin,
int elemend, int elembegin); int elemend, int elembegin);
+5 -12
View File
@@ -303,9 +303,6 @@ void mjCMesh::NameSpace(const mjCModel* m) {
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(m->spec_modelfiledir_); modelfiledir_ = FilePath(m->spec_modelfiledir_);
} }
if (meshdir_.empty()) {
meshdir_ = FilePath(m->spec_meshdir_);
}
if (!plugin_instance_name.empty()) { if (!plugin_instance_name.empty()) {
plugin_instance_name = m->prefix + plugin_instance_name + m->suffix; plugin_instance_name = m->prefix + plugin_instance_name + m->suffix;
} }
@@ -705,12 +702,12 @@ void mjCMesh::TryCompile(const mjVFS* vfs) {
} }
// copy paths from model if not already defined // copy paths from model if not already defined
mujoco::user::FilePath meshdir_;
meshdir_ = FilePath(mjs_getString(compiler->meshdir));
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(model->modelfiledir_); modelfiledir_ = FilePath(model->modelfiledir_);
} }
if (meshdir_.empty()) {
meshdir_ = FilePath(model->meshdir_);
}
// remove path from file if necessary // remove path from file if necessary
if (model->strippath) { if (model->strippath) {
@@ -3131,9 +3128,6 @@ void mjCSkin::NameSpace(const mjCModel* m) {
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(m->spec_modelfiledir_); modelfiledir_ = FilePath(m->spec_modelfiledir_);
} }
if (meshdir_.empty()) {
meshdir_ = FilePath(m->spec_meshdir_);
}
} }
@@ -3224,9 +3218,8 @@ void mjCSkin::Compile(const mjVFS* vfs) {
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(model->modelfiledir_); modelfiledir_ = FilePath(model->modelfiledir_);
} }
if (meshdir_.empty()) { mujoco::user::FilePath meshdir_;
meshdir_ = FilePath(model->meshdir_); meshdir_ = FilePath(mjs_getString(compiler->meshdir));
}
FilePath filename = meshdir_ + FilePath(file_); FilePath filename = meshdir_ + FilePath(file_);
mjResource* resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs); mjResource* resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs);
+8 -10
View File
@@ -140,8 +140,8 @@ mjCModel::mjCModel() {
elemtype = mjOBJ_MODEL; elemtype = mjOBJ_MODEL;
spec_comment_.clear(); spec_comment_.clear();
spec_modelfiledir_.clear(); spec_modelfiledir_.clear();
spec_meshdir_.clear(); meshdir_.clear();
spec_texturedir_.clear(); texturedir_.clear();
spec_modelname_ = "MuJoCo Model"; spec_modelname_ = "MuJoCo Model";
//------------------------ auto-computed statistics //------------------------ auto-computed statistics
@@ -201,10 +201,12 @@ mjCModel& mjCModel::operator=(const mjCModel& other) {
this->spec = other.spec; this->spec = other.spec;
*static_cast<mjCModel_*>(this) = static_cast<const mjCModel_&>(other); *static_cast<mjCModel_*>(this) = static_cast<const mjCModel_&>(other);
*static_cast<mjSpec*>(this) = static_cast<const mjSpec&>(other); *static_cast<mjSpec*>(this) = static_cast<const mjSpec&>(other);
PointToLocal();
// copy attached specs first so that we can resolve references to them // copy attached specs first so that we can resolve references to them
for (const auto* s : other.specs_) { for (auto* s : other.specs_) {
specs_.push_back(mj_copySpec(s)); specs_.push_back(s);
static_cast<mjCModel*>(s->element)->AddRef();
compiler2spec_[&s->compiler] = specs_.back(); compiler2spec_[&s->compiler] = specs_.back();
} }
@@ -869,13 +871,11 @@ void mjCModel::PointToLocal() {
spec.comment = &spec_comment_; spec.comment = &spec_comment_;
spec.modelfiledir = &spec_modelfiledir_; spec.modelfiledir = &spec_modelfiledir_;
spec.modelname = &spec_modelname_; spec.modelname = &spec_modelname_;
spec.meshdir = &spec_meshdir_; spec.compiler.meshdir = &meshdir_;
spec.texturedir = &spec_texturedir_; spec.compiler.texturedir = &texturedir_;
comment = nullptr; comment = nullptr;
modelfiledir = nullptr; modelfiledir = nullptr;
modelname = nullptr; modelname = nullptr;
meshdir = nullptr;
texturedir = nullptr;
} }
@@ -885,8 +885,6 @@ void mjCModel::CopyFromSpec() {
comment_ = spec_comment_; comment_ = spec_comment_;
modelfiledir_ = spec_modelfiledir_; modelfiledir_ = spec_modelfiledir_;
modelname_ = spec_modelname_; modelname_ = spec_modelname_;
meshdir_ = spec_meshdir_;
texturedir_ = spec_texturedir_;
} }
+11 -2
View File
@@ -148,8 +148,6 @@ class mjCModel_ : public mjsElement {
std::string spec_comment_; std::string spec_comment_;
std::string spec_modelfiledir_; std::string spec_modelfiledir_;
std::string spec_modelname_; std::string spec_modelname_;
std::string spec_meshdir_;
std::string spec_texturedir_;
}; };
// mjCModel contains everything needed to generate the low-level model. // mjCModel contains everything needed to generate the low-level model.
@@ -330,7 +328,18 @@ class mjCModel : public mjCModel_, private mjSpec {
// check for repeated names in list // check for repeated names in list
void CheckRepeat(mjtObj type); void CheckRepeat(mjtObj type);
// increment and decrement reference count
void AddRef() { ++refcount; }
int GetRef() const { return refcount; }
void Release() {
if (--refcount == 0) {
delete this;
}
}
private: private:
int refcount = 1;
// settings for each defaults class // settings for each defaults class
std::vector<mjCDef*> defaults_; std::vector<mjCDef*> defaults_;
+18 -16
View File
@@ -1210,6 +1210,13 @@ void mjCBase::NameSpace(const mjCModel* m) {
mjsCompiler* mjCBase::FindCompiler(const mjsCompiler* compiler) const {
mjSpec* origin = model->FindSpec(compiler);
return origin ? &origin->compiler : &model->spec.compiler;
}
// load resource if found (fallback to OS filesystem) // load resource if found (fallback to OS filesystem)
mjResource* mjCBase::LoadResource(const std::string& modelfiledir, mjResource* mjCBase::LoadResource(const std::string& modelfiledir,
const std::string& filename, const std::string& filename,
@@ -1313,8 +1320,7 @@ mjCBody::mjCBody(mjCModel* _model) {
mjCBody::mjCBody(const mjCBody& other, mjCModel* _model) { mjCBody::mjCBody(const mjCBody& other, mjCModel* _model) {
model = _model; model = _model;
mjSpec* origin = model->FindSpec(other.compiler); compiler = FindCompiler(other.compiler);
compiler = origin ? &origin->compiler : &model->spec.compiler;
*this = other; *this = other;
CopyPlugin(); CopyPlugin();
} }
@@ -1389,7 +1395,8 @@ mjCBody& mjCBody::operator+=(const mjCBody& other) {
mjCBody& mjCBody::operator+=(const mjCFrame& other) { mjCBody& mjCBody::operator+=(const mjCFrame& other) {
// append a copy of the attached spec // append a copy of the attached spec
if (other.model != model && !model->FindSpec(&other.model->spec.compiler)) { if (other.model != model && !model->FindSpec(&other.model->spec.compiler)) {
model->AppendSpec(mj_copySpec(&other.model->spec), &other.model->spec.compiler); model->AppendSpec(&other.model->spec, &other.model->spec.compiler);
static_cast<mjCModel*>(other.model->spec.element)->AddRef();
} }
// create a copy of the subtree that contains the frame // create a copy of the subtree that contains the frame
@@ -2644,7 +2651,8 @@ mjCFrame& mjCFrame::operator=(const mjCFrame& other) {
mjCFrame& mjCFrame::operator+=(const mjCBody& other) { mjCFrame& mjCFrame::operator+=(const mjCBody& other) {
// append a copy of the attached spec // append a copy of the attached spec
if (other.model != model && !model->FindSpec(&other.model->spec.compiler)) { if (other.model != model && !model->FindSpec(&other.model->spec.compiler)) {
model->AppendSpec(mj_copySpec(&other.model->spec), &other.model->spec.compiler); model->AppendSpec(&other.model->spec, &other.model->spec.compiler);
static_cast<mjCModel*>(other.model->spec.element)->AddRef();
} }
// apply namespace and store keyframes in the source model // apply namespace and store keyframes in the source model
@@ -4363,9 +4371,6 @@ void mjCHField::NameSpace(const mjCModel* m) {
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(m->spec_modelfiledir_); modelfiledir_ = FilePath(m->spec_modelfiledir_);
} }
if (meshdir_.empty()) {
meshdir_ = FilePath(m->spec_meshdir_);
}
} }
@@ -4489,9 +4494,8 @@ void mjCHField::Compile(const mjVFS* vfs) {
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(model->modelfiledir_); modelfiledir_ = FilePath(model->modelfiledir_);
} }
if (meshdir_.empty()) { mujoco::user::FilePath meshdir_;
meshdir_ = FilePath(model->meshdir_); meshdir_ = FilePath(mjs_getString(compiler->meshdir));
}
FilePath filename = meshdir_ + FilePath(file_); FilePath filename = meshdir_ + FilePath(file_);
mjResource* resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs); mjResource* resource = LoadResource(modelfiledir_.Str(), filename.Str(), vfs);
@@ -4626,9 +4630,6 @@ void mjCTexture::NameSpace(const mjCModel* m) {
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(m->spec_modelfiledir_); modelfiledir_ = FilePath(m->spec_modelfiledir_);
} }
if (texturedir_.empty()) {
texturedir_ = FilePath(m->spec_texturedir_);
}
} }
@@ -5218,6 +5219,8 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) {
} }
// make filename // make filename
mujoco::user::FilePath texturedir_;
texturedir_ = FilePath(mjs_getString(compiler->texturedir));
FilePath filename = texturedir_ + FilePath(cubefiles_[i]); FilePath filename = texturedir_ + FilePath(cubefiles_[i]);
// load PNG or custom // load PNG or custom
@@ -5296,9 +5299,8 @@ void mjCTexture::Compile(const mjVFS* vfs) {
if (modelfiledir_.empty()) { if (modelfiledir_.empty()) {
modelfiledir_ = FilePath(model->modelfiledir_); modelfiledir_ = FilePath(model->modelfiledir_);
} }
if (texturedir_.empty()) { mujoco::user::FilePath texturedir_;
texturedir_ = FilePath(model->texturedir_); texturedir_ = FilePath(mjs_getString(compiler->texturedir));
}
// buffer from user // buffer from user
if (!data_.empty()) { if (!data_.empty()) {
+3 -4
View File
@@ -361,6 +361,9 @@ class mjCBase : public mjCBase_ {
// Returns parent of this object // Returns parent of this object
virtual mjCBase* GetParent() const { return nullptr; } virtual mjCBase* GetParent() const { return nullptr; }
// Returns the model of this object
mjsCompiler* FindCompiler(const mjsCompiler* compiler) const;
// Copy assignment // Copy assignment
mjCBase& operator=(const mjCBase& other); mjCBase& operator=(const mjCBase& other);
@@ -1094,7 +1097,6 @@ class mjCMesh_ : public mjCBase {
// paths stored during model attachment // paths stored during model attachment
mujoco::user::FilePath modelfiledir_; mujoco::user::FilePath modelfiledir_;
mujoco::user::FilePath meshdir_;
}; };
class mjCMesh: public mjCMesh_, private mjsMesh { class mjCMesh: public mjCMesh_, private mjsMesh {
@@ -1310,7 +1312,6 @@ class mjCSkin_ : public mjCBase {
// paths stored during model attachment // paths stored during model attachment
mujoco::user::FilePath modelfiledir_; mujoco::user::FilePath modelfiledir_;
mujoco::user::FilePath meshdir_;
}; };
class mjCSkin: public mjCSkin_, private mjsSkin { class mjCSkin: public mjCSkin_, private mjsSkin {
@@ -1366,7 +1367,6 @@ class mjCHField_ : public mjCBase {
// paths stored during model attachment // paths stored during model attachment
mujoco::user::FilePath modelfiledir_; mujoco::user::FilePath modelfiledir_;
mujoco::user::FilePath meshdir_;
}; };
class mjCHField : public mjCHField_, private mjsHField { class mjCHField : public mjCHField_, private mjsHField {
@@ -1417,7 +1417,6 @@ class mjCTexture_ : public mjCBase {
// paths stored during model attachment // paths stored during model attachment
mujoco::user::FilePath modelfiledir_; mujoco::user::FilePath modelfiledir_;
mujoco::user::FilePath texturedir_;
}; };
class mjCTexture : public mjCTexture_, private mjsTexture { class mjCTexture : public mjCTexture_, private mjsTexture {
+4 -4
View File
@@ -1067,16 +1067,16 @@ void mjXReader::Compiler(XMLElement* section, mjSpec* s) {
memcpy(s->compiler.eulerseq, text.c_str(), 3); memcpy(s->compiler.eulerseq, text.c_str(), 3);
} }
if (ReadAttrTxt(section, "assetdir", text)) { if (ReadAttrTxt(section, "assetdir", text)) {
mjs_setString(s->meshdir, text.c_str()); mjs_setString(s->compiler.meshdir, text.c_str());
mjs_setString(s->texturedir, text.c_str()); mjs_setString(s->compiler.texturedir, text.c_str());
} }
// meshdir and texturedir take precedence over assetdir // meshdir and texturedir take precedence over assetdir
string meshdir, texturedir; string meshdir, texturedir;
if (ReadAttrTxt(section, "meshdir", meshdir)) { if (ReadAttrTxt(section, "meshdir", meshdir)) {
mjs_setString(s->meshdir, meshdir.c_str()); mjs_setString(s->compiler.meshdir, meshdir.c_str());
}; };
if (ReadAttrTxt(section, "texturedir", texturedir)) { if (ReadAttrTxt(section, "texturedir", texturedir)) {
mjs_setString(s->texturedir, texturedir.c_str()); mjs_setString(s->compiler.texturedir, texturedir.c_str());
} }
if (MapValue(section, "discardvisual", &n, bool_map, 2)) { if (MapValue(section, "discardvisual", &n, bool_map, 2)) {
s->compiler.discardvisual = (n == 1); s->compiler.discardvisual = (n == 1);
+2 -2
View File
@@ -2631,7 +2631,7 @@ TEST_F(MujocoTest, DifferentOptionsInAttachedFrame) {
mj_deleteModel(m_attached); mj_deleteModel(m_attached);
} }
TEST_F(MujocoTest, CopyAttachedSpec) { TEST_F(MujocoTest, NotCopyAttachedSpec) {
static constexpr char xml_parent[] = R"( static constexpr char xml_parent[] = R"(
<mujoco> <mujoco>
<asset> <asset>
@@ -2675,7 +2675,7 @@ TEST_F(MujocoTest, CopyAttachedSpec) {
mjSpec* child_copy = mjs_findSpec(copy, "child"); mjSpec* child_copy = mjs_findSpec(copy, "child");
EXPECT_THAT(child_copy, NotNull()); EXPECT_THAT(child_copy, NotNull());
EXPECT_NE(child_copy, child); EXPECT_EQ(child_copy, child);
mj_deleteSpec(spec); mj_deleteSpec(spec);
mj_deleteSpec(copy); mj_deleteSpec(copy);
+2 -2
View File
@@ -781,7 +781,7 @@ TEST_F(MujocoTest, Modeldir) {
mjsMesh* mesh = mjs_addMesh(child, 0); mjsMesh* mesh = mjs_addMesh(child, 0);
mjsFrame* frame = mjs_addFrame(mjs_findBody(child, "world"), 0); mjsFrame* frame = mjs_addFrame(mjs_findBody(child, "world"), 0);
mjsGeom* geom = mjs_addGeom(mjs_findBody(child, "world"), 0); mjsGeom* geom = mjs_addGeom(mjs_findBody(child, "world"), 0);
mjs_setString(child->meshdir, "meshdir"); mjs_setString(child->compiler.meshdir, "meshdir");
mjs_setString(mesh->file, "cube.obj"); mjs_setString(mesh->file, "cube.obj");
mjs_setName(mesh->element, "cube"); mjs_setName(mesh->element, "cube");
mjs_setString(geom->meshname, "cube"); mjs_setString(geom->meshname, "cube");
@@ -791,7 +791,7 @@ TEST_F(MujocoTest, Modeldir) {
// parent attaching the child // parent attaching the child
mjSpec* spec = mj_makeSpec(); mjSpec* spec = mj_makeSpec();
mjs_setDeepCopy(spec, true); mjs_setDeepCopy(spec, true);
mjs_setString(spec->meshdir, "asset"); mjs_setString(spec->compiler.meshdir, "asset");
mjs_attach(mjs_findBody(spec, "world")->element, frame->element, "_", ""); mjs_attach(mjs_findBody(spec, "world")->element, frame->element, "_", "");
mjModel* model = mj_compile(spec, vfs.get()); mjModel* model = mj_compile(spec, vfs.get());
EXPECT_THAT(model, NotNull()); EXPECT_THAT(model, NotNull());
+2
View File
@@ -5854,6 +5854,8 @@ public unsafe struct mjsCompiler_ {
public byte saveinertial; public byte saveinertial;
public int alignfree; public int alignfree;
public mjLROpt_ LRopt; public mjLROpt_ LRopt;
public void* meshdir;
public void* texturedir;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]