diff --git a/src/user/user_api.cc b/src/user/user_api.cc index 171a300f..18055a80 100644 --- a/src/user/user_api.cc +++ b/src/user/user_api.cc @@ -510,6 +510,9 @@ void mjm_setDouble(mjDoubleVec dest, const double* array, int size) { // get string const char* mjm_getString(const mjString source) { std::string* str = reinterpret_cast(source); + if (!str) { + return nullptr; + } return str->c_str(); } diff --git a/src/user/user_api.h b/src/user/user_api.h index 971fb7a4..81484e91 100644 --- a/src/user/user_api.h +++ b/src/user/user_api.h @@ -125,6 +125,13 @@ typedef struct _mjmModel { // model specification // sizes int nkey; // number of keyframes + + // global data + mjString comment; // comment at top of XML + mjString modelfiledir; // path to model file + + // other + bool hasImplicitPluginElem; // already encountered an implicit plugin sensor/actuator } mjmModel; diff --git a/src/user/user_flexcomp.cc b/src/user/user_flexcomp.cc index 47f3e952..de8f7922 100644 --- a/src/user/user_flexcomp.cc +++ b/src/user/user_flexcomp.cc @@ -837,7 +837,8 @@ bool mjCFlexcomp::MakeMesh(mjCModel* model, char* error, int error_sz) { } // load resource - string filename = mjuu_makefullname(model->modelfiledir, mjm_getString(model->spec.meshdir), file); + string filename = mjuu_makefullname(mjm_getString(model->spec.modelfiledir), + mjm_getString(model->spec.meshdir), file); mjResource* resource = nullptr; try { @@ -943,7 +944,8 @@ bool mjCFlexcomp::MakeGMSH(mjCModel* model, char* error, int error_sz) { } // open resource - string filename = mjuu_makefullname(model->modelfiledir, mjm_getString(model->spec.meshdir), file); + string filename = mjuu_makefullname(mjm_getString(model->spec.modelfiledir), + mjm_getString(model->spec.meshdir), file); mjResource* resource = nullptr; try { diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index a2a1a5d2..8f1aedda 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -348,7 +348,7 @@ void mjCMesh::Compile(const mjVFS* vfs) { throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str()); } - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir_, file_); + string filename = mjuu_makefullname(model->modelfiledir_, model->meshdir_, file_); mjResource* resource = LoadResource(filename, vfs); try { @@ -1951,7 +1951,7 @@ void mjCSkin::Compile(const mjVFS* vfs) { throw mjCError(this, "Unknown skin file type: %s", file_.c_str()); } - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir_, file_); + string filename = mjuu_makefullname(model->modelfiledir_, model->meshdir_, file_); mjResource* resource = LoadResource(filename, vfs); try { diff --git a/src/user/user_model.cc b/src/user/user_model.cc index bfeed5e8..8b32bc37 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -84,8 +84,8 @@ static void copyvec(T1* dest, T2* src, int n) { // constructor mjCModel::mjCModel() { mjm_defaultModel(spec); - comment.clear(); - modelfiledir.clear(); + spec_comment_.clear(); + spec_modelfiledir_.clear(); spec_meshdir_.clear(); spec_texturedir_.clear(); spec_modelname_ = "MuJoCo Model"; @@ -177,6 +177,8 @@ mjCModel::mjCModel() { void mjCModel::PointToLocal() { spec.element = (mjElement)this; + spec.comment = (mjString)&spec_comment_; + spec.modelfiledir = (mjString)&spec_modelfiledir_; spec.modelname = (mjString)&spec_modelname_; spec.meshdir = (mjString)&spec_meshdir_; spec.texturedir = (mjString)&spec_texturedir_; @@ -186,9 +188,13 @@ void mjCModel::PointToLocal() { void mjCModel::CopyFromSpec() { *static_cast(this) = spec; + comment_ = spec_comment_; + modelfiledir_ = spec_modelfiledir_; modelname_ = spec_modelname_; meshdir_ = spec_meshdir_; texturedir_ = spec_texturedir_; + comment = (mjString)&comment_; + modelfiledir = (mjString)&modelfiledir_; modelname = (mjString)&modelname_; meshdir = (mjString)&meshdir_; texturedir = (mjString)&texturedir_; diff --git a/src/user/user_model.h b/src/user/user_model.h index d25af4b2..d6610a60 100644 --- a/src/user/user_model.h +++ b/src/user/user_model.h @@ -129,9 +129,8 @@ class mjCModel : private mjmModel { //------------------------ global data - std::string comment; // comment at top of XML - std::string modelfiledir; // path to model file std::vector defaults; // settings for each defaults class + std::vector> active_plugins; // list of active plugins private: void TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs); @@ -245,8 +244,6 @@ class mjCModel : private mjmModel { std::vector texts; // list of text fields std::vector tuples; // list of tuple fields std::vector keys; // list of keyframe fields - - std::vector> active_plugins; // list of active plugins std::vector plugins; // list of plugin instances // pointers to objects created inside kinematic tree @@ -272,16 +269,19 @@ class mjCModel : private mjmModel { // map from object names to ids mjListKeyMap ids; - bool hasImplicitPluginElem; // already encountered an implicit plugin sensor/actuator bool compiled; // already compiled flag (cannot be compiled again) mjCError errInfo; // last error info int fixCount; // how many bodies have been fixed std::vector qpos0; // save qpos0, to recognize changed key_qpos in write // variable-size attributes + std::string comment_; // comment at top of XML + std::string modelfiledir_; // path to model file std::string modelname_; std::string meshdir_; std::string texturedir_; + std::string spec_comment_; + std::string spec_modelfiledir_; std::string spec_modelname_; std::string spec_meshdir_; std::string spec_texturedir_; diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 71dbcbeb..fb4650a1 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -2654,7 +2654,7 @@ void mjCHField::Compile(const mjVFS* vfs) { throw mjCError(this, "unsupported content type: '%s'", asset_type.c_str()); } - string filename = mjuu_makefullname(model->modelfiledir, model->meshdir_, file_); + string filename = mjuu_makefullname(model->modelfiledir_, model->meshdir_, file_); mjResource* resource = LoadResource(filename, vfs); try { @@ -3273,7 +3273,7 @@ void mjCTexture::LoadCubeSeparate(const mjVFS* vfs) { } // make filename - string filename = mjuu_makefullname(model->modelfiledir, model->texturedir_, cubefiles_[i]); + string filename = mjuu_makefullname(model->modelfiledir_, model->texturedir_, cubefiles_[i]); // load PNG or custom unsigned int w, h; @@ -3373,7 +3373,7 @@ void mjCTexture::Compile(const mjVFS* vfs) { } // make filename - string filename = mjuu_makefullname(model->modelfiledir, model->texturedir_, file_); + string filename = mjuu_makefullname(model->modelfiledir_, model->texturedir_, file_); // dispatch if (type==mjTEXTURE_2D) { diff --git a/src/xml/xml.cc b/src/xml/xml.cc index 95e169ee..95b7f124 100644 --- a/src/xml/xml.cc +++ b/src/xml/xml.cc @@ -15,6 +15,7 @@ #include "xml/xml.h" #include +#include "user/user_api.h" #if defined(__APPLE__) || defined(__FreeBSD__) #include @@ -348,9 +349,9 @@ mjCModel* mjParseXML(const char* filename, const mjVFS* vfs, int ndir = 0; mju_getResourceDir(resource, &dir, &ndir); if (dir != nullptr) { - model->modelfiledir = std::string(dir, ndir); + mjm_setString(model->spec.modelfiledir, std::string(dir, ndir).c_str()); } else { - model->modelfiledir = ""; + mjm_setString(model->spec.modelfiledir, ""); } // close resource @@ -362,8 +363,8 @@ mjCModel* mjParseXML(const char* filename, const mjVFS* vfs, // find include elements, replace them with subtree from xml file std::unordered_set included = {filename}; mjXReader parser; - parser.SetModelFileDir(model->modelfiledir); - mjIncludeXML(parser, root, model->modelfiledir, vfs, included); + parser.SetModelFileDir(mjm_getString(model->spec.modelfiledir)); + mjIncludeXML(parser, root, mjm_getString(model->spec.modelfiledir), vfs, included); // parse MuJoCo model parser.SetModel(model); diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index b5ff9417..26e5c18f 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -811,9 +811,9 @@ void mjXReader::Parse(XMLElement* root) { // get comment if (root->FirstChild() && root->FirstChild()->ToComment()) { - model->comment = root->FirstChild()->Value(); + mjm_setString(model->spec.comment, root->FirstChild()->Value()); } else { - model->comment.clear(); + mjm_setString(model->spec.comment, ""); } //------------------- parse MuJoCo sections embedded in all XML formats diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index 7e6be6aa..8f9b7ff2 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -781,8 +781,9 @@ string mjXWriter::Write(char *error, size_t error_sz) { doc.InsertFirstChild(root); // write comment if present - if (!model->comment.empty()) { - XMLComment* comment = doc.NewComment(model->comment.c_str()); + string text = mjm_getString(model->comment); + if (!text.empty()) { + XMLComment* comment = doc.NewComment(text.c_str()); root->LinkEndChild(comment); }