rename mjspec api structs and functions mjm -> mjs

PiperOrigin-RevId: 618017976
Change-Id: I5f790167e5ca670f8d5f92e8e1c920db8d236144
This commit is contained in:
Yuval Tassa
2024-03-21 18:04:06 -07:00
committed by Copybara-Service
parent f0ad80f268
commit 4660a297d1
22 changed files with 960 additions and 959 deletions
+6 -6
View File
@@ -345,14 +345,14 @@ mjSpec* mjParseXML(const char* filename, const mjVFS* vfs,
}
// create model, set filedir
model = mjm_createSpec();
model = mjs_createSpec();
const char* dir;
int ndir = 0;
mju_getResourceDir(resource, &dir, &ndir);
if (dir != nullptr) {
mjm_setString(model->modelfiledir, std::string(dir, ndir).c_str());
mjs_setString(model->modelfiledir, std::string(dir, ndir).c_str());
} else {
mjm_setString(model->modelfiledir, "");
mjs_setString(model->modelfiledir, "");
}
// close resource
@@ -364,8 +364,8 @@ mjSpec* mjParseXML(const char* filename, const mjVFS* vfs,
// find include elements, replace them with subtree from xml file
std::unordered_set<std::string> included = {filename};
mjXReader parser;
parser.SetModelFileDir(mjm_getString(model->modelfiledir));
mjIncludeXML(parser, root, mjm_getString(model->modelfiledir), vfs, included);
parser.SetModelFileDir(mjs_getString(model->modelfiledir));
mjIncludeXML(parser, root, mjs_getString(model->modelfiledir), vfs, included);
// parse MuJoCo model
parser.SetModel(model);
@@ -394,7 +394,7 @@ mjSpec* mjParseXML(const char* filename, const mjVFS* vfs,
// catch known errors
catch (mjXError err) {
mjCopyError(error, err.message, error_sz);
mjm_deleteSpec(model);
mjs_deleteSpec(model);
return nullptr;
}
+7 -7
View File
@@ -56,7 +56,7 @@ std::optional<std::string> GlobalModel::ToXML(const mjModel* m, char* error,
mjCopyError(error, "No XML model loaded", error_sz);
return std::nullopt;
}
mjm_copyBack(model_, m);
mjs_copyBack(model_, m);
std::string result = mjWriteXML(model_, error, error_sz);
if (result.empty()) {
return std::nullopt;
@@ -67,7 +67,7 @@ std::optional<std::string> GlobalModel::ToXML(const mjModel* m, char* error,
void GlobalModel::Set(mjSpec* model) {
std::lock_guard<std::mutex> lock(*mutex_);
if (model_ != nullptr) {
mjm_deleteSpec(model_);
mjs_deleteSpec(model_);
}
model_ = model;
}
@@ -93,21 +93,21 @@ mjModel* mj_loadXML(const char* filename, const mjVFS* vfs,
// parse new model
std::unique_ptr<mjSpec, std::function<void(mjSpec*)>> model(
mjParseXML(filename, vfs, error, error_sz),
[](mjSpec* m) { mjm_deleteSpec(m); });
[](mjSpec* m) { mjs_deleteSpec(m); });
if (!model) {
return nullptr;
}
// compile new model
mjModel* m = mjm_compile(model.get(), vfs);
mjModel* m = mjs_compile(model.get(), vfs);
if (!m) {
mjCopyError(error, mjm_getError(model.get()), error_sz);
mjCopyError(error, mjs_getError(model.get()), error_sz);
return nullptr;
}
// handle compile warning
if (mjm_isWarning(model.get())) {
mjCopyError(error, mjm_getError(model.get()), error_sz);
if (mjs_isWarning(model.get())) {
mjCopyError(error, mjs_getError(model.get()), error_sz);
} else if (error) {
error[0] = '\0';
}
+2 -1
View File
@@ -24,6 +24,7 @@
#include "user/user_api.h"
#include "user/user_model.h"
#include "user/user_objects.h"
#include "xml/xml_util.h"
#include "tinyxml2.h"
namespace {
@@ -51,7 +52,7 @@ void mjXBase::SetModel(mjSpec* _model) {
// read alternative orientation specification
int mjXBase::ReadAlternative(XMLElement* elem, mjmOrientation& alt) {
int mjXBase::ReadAlternative(XMLElement* elem, mjsOrientation& alt) {
string text;
int read = (int)(elem->Attribute("quat") != 0) +
(ReadAttr(elem, "axisangle", 4, alt.axisangle, text) ? 1 : 0) +
+1 -1
View File
@@ -90,7 +90,7 @@ class mjXBase : public mjXUtil {
virtual void SetModel(mjSpec*);
// read alternative orientation specification
static int ReadAlternative(tinyxml2::XMLElement* elem, mjmOrientation& alt);
static int ReadAlternative(tinyxml2::XMLElement* elem, mjsOrientation& alt);
protected:
mjSpec* model; // internally-allocated model
File diff suppressed because it is too large Load Diff
+18 -18
View File
@@ -54,8 +54,8 @@ class mjXReader : public mjXBase {
void Visual(tinyxml2::XMLElement* section); // visual section
void Statistic(tinyxml2::XMLElement* section); // statistic section
void Asset(tinyxml2::XMLElement* section); // asset section
void Body(tinyxml2::XMLElement* section, mjmBody* pbody,
mjmFrame* pframe); // body/world section
void Body(tinyxml2::XMLElement* section, mjsBody* pbody,
mjsFrame* pframe); // body/world section
void Contact(tinyxml2::XMLElement* section); // contact section
void Deformable(tinyxml2::XMLElement* section); // deformable section
void Equality(tinyxml2::XMLElement* section); // equality section
@@ -65,22 +65,22 @@ class mjXReader : public mjXBase {
void Keyframe(tinyxml2::XMLElement* section); // keyframe section
// single element parsers, used in defaults and main body
void OneFlex(tinyxml2::XMLElement* elem, mjmFlex* pflex);
void OneMesh(tinyxml2::XMLElement* elem, mjmMesh* pmesh);
void OneSkin(tinyxml2::XMLElement* elem, mjmSkin* pskin);
void OneMaterial(tinyxml2::XMLElement* elem, mjmMaterial* pmaterial);
void OneJoint(tinyxml2::XMLElement* elem, mjmJoint* pjoint);
void OneGeom(tinyxml2::XMLElement* elem, mjmGeom* pgeom);
void OneSite(tinyxml2::XMLElement* elem, mjmSite* site);
void OneCamera(tinyxml2::XMLElement* elem, mjmCamera* pcamera);
void OneLight(tinyxml2::XMLElement* elem, mjmLight* plight);
void OnePair(tinyxml2::XMLElement* elem, mjmPair* ppair);
void OneEquality(tinyxml2::XMLElement* elem, mjmEquality* pequality);
void OneTendon(tinyxml2::XMLElement* elem, mjmTendon* ptendon);
void OneActuator(tinyxml2::XMLElement* elem, mjmActuator* pactuator);
void OneComposite(tinyxml2::XMLElement* elem, mjmBody* pbody, mjmDefault* def);
void OneFlexcomp(tinyxml2::XMLElement* elem, mjmBody* pbody);
void OnePlugin(tinyxml2::XMLElement* elem, mjmPlugin* plugin);
void OneFlex(tinyxml2::XMLElement* elem, mjsFlex* pflex);
void OneMesh(tinyxml2::XMLElement* elem, mjsMesh* pmesh);
void OneSkin(tinyxml2::XMLElement* elem, mjsSkin* pskin);
void OneMaterial(tinyxml2::XMLElement* elem, mjsMaterial* pmaterial);
void OneJoint(tinyxml2::XMLElement* elem, mjsJoint* pjoint);
void OneGeom(tinyxml2::XMLElement* elem, mjsGeom* pgeom);
void OneSite(tinyxml2::XMLElement* elem, mjsSite* site);
void OneCamera(tinyxml2::XMLElement* elem, mjsCamera* pcamera);
void OneLight(tinyxml2::XMLElement* elem, mjsLight* plight);
void OnePair(tinyxml2::XMLElement* elem, mjsPair* ppair);
void OneEquality(tinyxml2::XMLElement* elem, mjsEquality* pequality);
void OneTendon(tinyxml2::XMLElement* elem, mjsTendon* ptendon);
void OneActuator(tinyxml2::XMLElement* elem, mjsActuator* pactuator);
void OneComposite(tinyxml2::XMLElement* elem, mjsBody* pbody, mjmDefault* def);
void OneFlexcomp(tinyxml2::XMLElement* elem, mjsBody* pbody);
void OnePlugin(tinyxml2::XMLElement* elem, mjsPlugin* plugin);
mjXSchema schema; // schema used for validation
mjmDefault* GetClass(tinyxml2::XMLElement* section); // get default class name
+14 -14
View File
@@ -553,33 +553,33 @@ void mjXWriter::OneEquality(XMLElement* elem, mjCEquality* peq, mjCDef* def) {
switch (peq->type) {
case mjEQ_CONNECT:
WriteAttrTxt(elem, "body1", mjm_getString(peq->name1));
WriteAttrTxt(elem, "body2", mjm_getString(peq->name2));
WriteAttrTxt(elem, "body1", mjs_getString(peq->name1));
WriteAttrTxt(elem, "body2", mjs_getString(peq->name2));
WriteAttr(elem, "anchor", 3, peq->data);
break;
case mjEQ_WELD:
WriteAttrTxt(elem, "body1", mjm_getString(peq->name1));
WriteAttrTxt(elem, "body2", mjm_getString(peq->name2));
WriteAttrTxt(elem, "body1", mjs_getString(peq->name1));
WriteAttrTxt(elem, "body2", mjs_getString(peq->name2));
WriteAttr(elem, "anchor", 3, peq->data);
WriteAttr(elem, "torquescale", 1, peq->data+10);
WriteAttr(elem, "relpose", 7, peq->data+3);
break;
case mjEQ_JOINT:
WriteAttrTxt(elem, "joint1", mjm_getString(peq->name1));
WriteAttrTxt(elem, "joint2", mjm_getString(peq->name2));
WriteAttrTxt(elem, "joint1", mjs_getString(peq->name1));
WriteAttrTxt(elem, "joint2", mjs_getString(peq->name2));
WriteAttr(elem, "polycoef", 5, peq->data);
break;
case mjEQ_TENDON:
WriteAttrTxt(elem, "tendon1", mjm_getString(peq->name1));
WriteAttrTxt(elem, "tendon2", mjm_getString(peq->name2));
WriteAttrTxt(elem, "tendon1", mjs_getString(peq->name1));
WriteAttrTxt(elem, "tendon2", mjs_getString(peq->name2));
WriteAttr(elem, "polycoef", 5, peq->data);
break;
case mjEQ_FLEX:
WriteAttrTxt(elem, "flex", mjm_getString(peq->name1));
WriteAttrTxt(elem, "flex", mjs_getString(peq->name1));
break;
default:
@@ -731,9 +731,9 @@ void mjXWriter::OneActuator(XMLElement* elem, mjCActuator* pact, mjCDef* def) {
// write plugin
void mjXWriter::OnePlugin(XMLElement* elem, mjmPlugin* plugin) {
const std::string instance_name = std::string(mjm_getString(plugin->instance_name));
const std::string plugin_name = std::string(mjm_getString(plugin->name));
void mjXWriter::OnePlugin(XMLElement* elem, mjsPlugin* plugin) {
const std::string instance_name = std::string(mjs_getString(plugin->instance_name));
const std::string plugin_name = std::string(mjs_getString(plugin->name));
if (!instance_name.empty()) {
WriteAttrTxt(elem, "instance", instance_name);
} else {
@@ -783,13 +783,13 @@ string mjXWriter::Write(char *error, size_t error_sz) {
// create document and root
XMLDocument doc;
XMLElement* root = doc.NewElement("mujoco");
root->SetAttribute("model", mjm_getString(model->modelname));
root->SetAttribute("model", mjs_getString(model->modelname));
// insert root
doc.InsertFirstChild(root);
// write comment if present
string text = mjm_getString(model->comment);
string text = mjs_getString(model->comment);
if (!text.empty()) {
XMLComment* comment = doc.NewComment(text.c_str());
root->LinkEndChild(comment);
+1 -1
View File
@@ -72,7 +72,7 @@ class mjXWriter : public mjXBase {
void OneEquality(tinyxml2::XMLElement* elem, mjCEquality* pequality, mjCDef* def);
void OneTendon(tinyxml2::XMLElement* elem, mjCTendon* ptendon, mjCDef* def);
void OneActuator(tinyxml2::XMLElement* elem, mjCActuator* pactuator, mjCDef* def);
void OnePlugin(tinyxml2::XMLElement* elem, mjmPlugin* plugin);
void OnePlugin(tinyxml2::XMLElement* elem, mjsPlugin* plugin);
bool writingdefaults; // true during defaults write
};
+47 -47
View File
@@ -112,7 +112,7 @@ void mjXURDF::Parse(
// get model name
std::string modelname;
if (ReadAttrTxt(root, "name", modelname)) {
mjm_setString(model->modelname, modelname.c_str());
mjs_setString(model->modelname, modelname.c_str());
}
// find and register all materials
@@ -206,16 +206,16 @@ void mjXURDF::Parse(
// override the pose for the base link and add a free joint
for (int i = 0; i < (int)urName.size(); i++) {
if (urParent[i] < 0) {
mjmBody* world = mjm_findBody(model, "world");
mjmBody* pbody = mjm_findChild(world, urName[i].c_str());
mjsBody* world = mjs_findBody(model, "world");
mjsBody* pbody = mjs_findChild(world, urName[i].c_str());
mjuu_copyvec(pbody->pos, pos, 3);
mjuu_copyvec(pbody->quat, quat, 4);
// add a free joint to allow motion of the body
// if the mass is 0, assume the object is static
if (!static_body && pbody->mass > 0) {
mjmJoint* pjoint = mjm_addJoint(pbody, 0);
mjm_setString(pjoint->name, (urName[i] + "_free_joint").c_str());
mjsJoint* pjoint = mjs_addJoint(pbody, 0);
mjs_setString(pjoint->name, (urName[i] + "_free_joint").c_str());
pjoint->type = mjJNT_FREE;
}
}
@@ -226,14 +226,14 @@ void mjXURDF::Parse(
void mjXURDF::Body(XMLElement* body_elem) {
std::string name, text;
XMLElement *elem, *temp, *temp1;
mjmBody *pbody, *world;
mjmGeom* pgeom;
mjsBody *pbody, *world;
mjsGeom* pgeom;
// get body name and pointer to mjmBody
// get body name and pointer to mjsBody
ReadAttrTxt(body_elem, "name", name, true);
name = GetPrefixedName(name);
world = mjm_findBody(model, "world");
pbody = mjm_findChild(world, name.c_str());
world = mjs_findBody(model, "world");
pbody = mjs_findChild(world, name.c_str());
if (!pbody) {
throw mjXError(body_elem, "URDF body not found"); // SHOULD NOT OCCUR
}
@@ -272,7 +272,7 @@ void mjXURDF::Body(XMLElement* body_elem) {
// lquat = rotation from specified to default (joint/body) inertial frame
double lquat[4] = {1, 0, 0, 0};
double tmpquat[4] = {1, 0, 0, 0};
const char* altres = mjm_setFullInertia(pbody, lquat, pbody->inertia);
const char* altres = mjs_setFullInertia(pbody, lquat, pbody->inertia);
// inertia are sometimes 0 in URDF files: ignore error in altres, fix later
(void) altres;
@@ -326,7 +326,7 @@ void mjXURDF::Body(XMLElement* body_elem) {
mjXUtil::ReadAttrTxt(elem, "name", geom_name);
name = GetPrefixedName(name);
if (urGeomNames.find(geom_name) == urGeomNames.end()) {
mjm_setString(pgeom->name, geom_name.c_str());
mjs_setString(pgeom->name, geom_name.c_str());
urGeomNames.insert(geom_name);
} else {
std::cerr << "WARNING: Geom with duplicate name '" << geom_name
@@ -349,7 +349,7 @@ void mjXURDF::Body(XMLElement* body_elem) {
mjXUtil::ReadAttrTxt(elem, "name", geom_name);
geom_name = GetPrefixedName(geom_name);
if (urGeomNames.find(geom_name) == urGeomNames.end()) {
mjm_setString(pgeom->name, geom_name.c_str());
mjs_setString(pgeom->name, geom_name.c_str());
urGeomNames.insert(geom_name);
} else {
std::cerr << "WARNING: Geom with duplicate name '" << geom_name
@@ -374,8 +374,8 @@ void mjXURDF::Parse(XMLElement* root) {
void mjXURDF::Joint(XMLElement* joint_elem) {
std::string jntname, name, text;
XMLElement *elem;
mjmBody *pbody, *parent, *world;
mjmJoint *pjoint=0, *pjoint1=0, *pjoint2=0;
mjsBody *pbody, *parent, *world;
mjsJoint *pjoint=0, *pjoint1=0, *pjoint2=0;
int jointtype;
// get type and name
@@ -390,8 +390,8 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
elem = FindSubElem(joint_elem, "parent", true);
ReadAttrTxt(elem, "link", name, true);
name = GetPrefixedName(name);
world = mjm_findBody(model, "world");
parent = mjm_findChild(world, name.c_str());
world = mjs_findBody(model, "world");
parent = mjs_findChild(world, name.c_str());
if (!parent) { // SHOULD NOT OCCUR
throw mjXError(elem, "invalid parent name in URDF joint definition");
}
@@ -400,8 +400,8 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
elem = FindSubElem(joint_elem, "child", true);
ReadAttrTxt(elem, "link", name, true);
name = GetPrefixedName(name);
world = mjm_findBody(model, "world");
pbody = mjm_findChild(world, name.c_str());
world = mjs_findBody(model, "world");
pbody = mjs_findChild(world, name.c_str());
if (!pbody) { // SHOULD NOT OCCUR
throw mjXError(elem, "invalid child name in URDF joint definition");
}
@@ -418,16 +418,16 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
switch (jointtype) {
case 0: // revolute
case 1: // continuous
pjoint = mjm_addJoint(pbody, 0);
mjm_setString(pjoint->name, jntname.c_str());
pjoint = mjs_addJoint(pbody, 0);
mjs_setString(pjoint->name, jntname.c_str());
pjoint->type = mjJNT_HINGE;
mjuu_setvec(pjoint->pos, 0, 0, 0);
mjuu_copyvec(pjoint->axis, axis, 3);
break;
case 2: // prismatic
pjoint = mjm_addJoint(pbody, 0);
mjm_setString(pjoint->name, jntname.c_str());
pjoint = mjs_addJoint(pbody, 0);
mjs_setString(pjoint->name, jntname.c_str());
pjoint->type = mjJNT_SLIDE;
mjuu_setvec(pjoint->pos, 0, 0, 0);
mjuu_copyvec(pjoint->axis, axis, 3);
@@ -437,8 +437,8 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
return;
case 4: // floating
pjoint = mjm_addJoint(pbody, 0);
mjm_setString(pjoint->name, jntname.c_str());
pjoint = mjs_addJoint(pbody, 0);
mjs_setString(pjoint->name, jntname.c_str());
pjoint->type = mjJNT_FREE;
break;
@@ -448,8 +448,8 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
mjuu_quat2mat(mat, quat);
// construct slider along x
pjoint = mjm_addJoint(pbody, 0);
mjm_setString(pjoint->name, (jntname + "_TX").c_str());
pjoint = mjs_addJoint(pbody, 0);
mjs_setString(pjoint->name, (jntname + "_TX").c_str());
pjoint->type = mjJNT_SLIDE;
tmpaxis[0] = mat[0];
tmpaxis[1] = mat[3];
@@ -458,8 +458,8 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
mjuu_copyvec(pjoint->axis, tmpaxis, 3);
// construct slider along y
pjoint1 = mjm_addJoint(pbody, 0);
mjm_setString(pjoint1->name, (jntname + "_TY").c_str());
pjoint1 = mjs_addJoint(pbody, 0);
mjs_setString(pjoint1->name, (jntname + "_TY").c_str());
pjoint1->type = mjJNT_SLIDE;
tmpaxis[0] = mat[1];
tmpaxis[1] = mat[4];
@@ -468,8 +468,8 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
mjuu_copyvec(pjoint1->axis, tmpaxis, 3);
// construct hinge around z = locaxis
pjoint2 = mjm_addJoint(pbody, 0);
mjm_setString(pjoint2->name, (jntname + "_RZ").c_str());
pjoint2 = mjs_addJoint(pbody, 0);
mjs_setString(pjoint2->name, (jntname + "_RZ").c_str());
pjoint2->type = mjJNT_HINGE;
mjuu_setvec(pjoint2->pos, 0, 0, 0);
mjuu_copyvec(pjoint2->axis, axis, 3);
@@ -506,7 +506,7 @@ void mjXURDF::Joint(XMLElement* joint_elem) {
// parse origin and geometry elements of visual or collision
mjmGeom* mjXURDF::Geom(XMLElement* geom_elem, mjmBody* pbody, bool collision) {
mjsGeom* mjXURDF::Geom(XMLElement* geom_elem, mjsBody* pbody, bool collision) {
XMLElement *elem, *temp;
std::string text, meshfile;
@@ -514,8 +514,8 @@ mjmGeom* mjXURDF::Geom(XMLElement* geom_elem, mjmBody* pbody, bool collision) {
elem = FindSubElem(geom_elem, "geometry", true);
// add BOX geom, modify type later
mjmGeom* pgeom = mjm_addGeom(pbody, 0);
mjm_setString(pgeom->name, "");
mjsGeom* pgeom = mjs_addGeom(pbody, 0);
mjs_setString(pgeom->name, "");
pgeom->type = mjGEOM_BOX;
if (collision) {
pgeom->contype = 1;
@@ -576,19 +576,19 @@ mjmGeom* mjXURDF::Geom(XMLElement* geom_elem, mjmBody* pbody, bool collision) {
meshname = mjuu_stripext(meshname);
// look for existing mesh
mjmMesh* mesh = mjm_findMesh(model, meshname.c_str());
mjmMesh* pmesh = 0;
mjsMesh* mesh = mjs_findMesh(model, meshname.c_str());
mjsMesh* pmesh = 0;
// does not exist: create
if (!mesh) {
pmesh = mjm_addMesh(model, 0);
pmesh = mjs_addMesh(model, 0);
}
// exists with different scale: append name with '1', create
else if (mesh->scale[0]!=meshscale[0] ||
mesh->scale[1]!=meshscale[1] ||
mesh->scale[2]!=meshscale[2]) {
pmesh = mjm_addMesh(model, 0);
pmesh = mjs_addMesh(model, 0);
meshname = meshname + "1";
}
@@ -598,9 +598,9 @@ mjmGeom* mjXURDF::Geom(XMLElement* geom_elem, mjmBody* pbody, bool collision) {
}
// set fields
mjm_setString(pmesh->file, meshfile.c_str());
mjm_setString(pmesh->name, meshname.c_str());
mjm_setString(pgeom->meshname, meshname.c_str());
mjs_setString(pmesh->file, meshfile.c_str());
mjs_setString(pmesh->name, meshname.c_str());
mjs_setString(pgeom->meshname, meshname.c_str());
pmesh->scale[0] = meshscale[0];
pmesh->scale[1] = meshscale[1];
pmesh->scale[2] = meshscale[2];
@@ -683,22 +683,22 @@ void mjXURDF::AddBody(std::string name) {
// add body with given number to the mjCModel tree, process children
void mjXURDF::AddToTree(int n) {
// get pointer to parent in mjCModel tree
mjmBody *parent = 0, *child = 0, *world = 0;
mjsBody *parent = 0, *child = 0, *world = 0;
if (urParent[n]>=0) {
world = mjm_findBody(model, "world");
parent = mjm_findChild(world, urName[urParent[n]].c_str());
world = mjs_findBody(model, "world");
parent = mjs_findChild(world, urName[urParent[n]].c_str());
if (!parent)
throw mjXError(0, "URDF body parent should already be in tree: %s",
urName[urParent[n]].c_str()); // SHOULD NOT OCCUR
} else {
parent = mjm_findBody(model, "world");
parent = mjs_findBody(model, "world");
}
// add this body
if (urName[n] != "world") {
child = mjm_addBody(parent, 0);
mjm_setString(child->name, urName[n].c_str());
child = mjs_addBody(parent, 0);
mjs_setString(child->name, urName[n].c_str());
}
// add children recursively
+2 -2
View File
@@ -51,8 +51,8 @@ class mjXURDF : public mjXBase {
void AddToTree(int n); // add body to mjCModel tree
void Body(tinyxml2::XMLElement* body_elem); // parse body
void Joint(tinyxml2::XMLElement* joint_elem); // parse joint
mjmGeom* Geom(tinyxml2::XMLElement* geom_elem,
mjmBody* pbody, bool collision); // parse origin and geometry of geom
mjsGeom* Geom(tinyxml2::XMLElement* geom_elem,
mjsBody* pbody, bool collision); // parse origin and geometry of geom
void Origin(tinyxml2::XMLElement* origin_elem, double* pos, double* quat); // parse origin element
void MakeMaterials(tinyxml2::XMLElement* elem); // find all materials recursively