From 4e5b194e88bef7e0ab5bf3fd9cde2dda546c0d94 Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Mon, 12 Feb 2024 02:55:00 -0800 Subject: [PATCH] Add mjmMaterial and mjmFrame to C API. PiperOrigin-RevId: 606191307 Change-Id: Iaf43f81522029002b28bba14ea046b1c968ab2e7 --- src/user/user_api.cc | 29 +++++++++++---- src/user/user_api.h | 38 ++++++++++++++++++-- src/user/user_init.cc | 24 +++++++++++++ src/user/user_model.cc | 10 +++--- src/user/user_objects.cc | 69 +++++++++++++++++++++++++++++------- src/user/user_objects.h | 39 ++++++++++++-------- src/xml/xml_native_reader.cc | 31 ++++++++++------ src/xml/xml_native_reader.h | 4 +-- src/xml/xml_native_writer.cc | 2 +- 9 files changed, 192 insertions(+), 54 deletions(-) diff --git a/src/user/user_api.cc b/src/user/user_api.cc index 3c12ed5f..84c11eeb 100644 --- a/src/user/user_api.cc +++ b/src/user/user_api.cc @@ -115,10 +115,24 @@ mjmLight* mjm_addLight(mjmBody* bodyspec, void* defspec) { // add frame to body -void* mjm_addFrame(mjmBody* bodyspec, void* parentframe) { - mjCFrame* parentframeC = static_cast(parentframe); - mjCFrame* frameC = reinterpret_cast(bodyspec->element)->AddFrame(parentframeC); - return frameC; +mjmFrame* mjm_addFrame(mjmBody* bodyspec, mjmFrame* parentframe) { + mjCFrame* parentframeC = 0; + if (parentframe) { + parentframeC = reinterpret_cast(parentframe->element); + } + mjCBody* body = reinterpret_cast(bodyspec->element); + mjCFrame* frameC = body->AddFrame(parentframeC); + return &frameC->spec; +} + + + +// Add material to model. +mjmMaterial* mjm_addMaterial(void* model, void* defspec) { + mjCModel* modelC = static_cast(model); + mjCDef* def = static_cast(defspec); + mjCMaterial* material = modelC->AddMaterial(def); + return &material->spec; } @@ -246,8 +260,11 @@ mjmBody* mjm_findChild(mjmBody* bodyspec, const char* name) { // set frame -void mjm_setFrame(mjElement dest, void* frame) { - mjCFrame* frameC = static_cast(frame); +void mjm_setFrame(mjElement dest, mjmFrame* frame) { + if (!frame) { + return; + } + mjCFrame* frameC = reinterpret_cast(frame->element); mjCBase* baseC = reinterpret_cast(dest); baseC->SetFrame(frameC); } diff --git a/src/user/user_api.h b/src/user/user_api.h index c6c51cd3..21146739 100644 --- a/src/user/user_api.h +++ b/src/user/user_api.h @@ -87,6 +87,15 @@ typedef struct _mjmBody { // body specification } mjmBody; +typedef struct _mjmFrame { // frame specification + mjElement element; // internal, do not modify + double pos[3]; // position + double quat[4]; // orientation + mjmOrientation alt; // alternative orientation + mjString info; // message appended to compiler errors +} mjmFrame; + + typedef struct _mjmJoint { // joint specification mjElement element; // internal, do not modify mjString name; // name @@ -256,6 +265,22 @@ typedef struct _mjmLight { // light specification } mjmLight; +typedef struct _mjmMaterial { // material specification + mjElement element; // internal, do not modify + mjString name; // name + mjString classname; // class name + mjString texture; // name of texture (empty: none) + bool texuniform; // make texture cube uniform + float texrepeat[2]; // texture repetition for 2D mapping + float emission; // emission + float specular; // specular + float shininess; // shininess + float reflectance; // reflectance + float rgba[4]; // rgba + mjString info; // message appended to compiler errors +} mjmMaterial; + + typedef struct _mjmEquality { // equality specification mjElement element; // internal, do not modify mjString name; // name @@ -415,7 +440,10 @@ MJAPI mjmCamera* mjm_addCamera(mjmBody* body, void* defspec); MJAPI mjmLight* mjm_addLight(mjmBody* body, void* defspec); // Add frame to body. -MJAPI void* mjm_addFrame(mjmBody* body, void* parentframe); +MJAPI mjmFrame* mjm_addFrame(mjmBody* body, mjmFrame* parentframe); + +// Add material to model. +MJAPI mjmMaterial* mjm_addMaterial(void* model, void* defspec); // Add equality to model. MJAPI mjmEquality* mjm_addEquality(void* model, void* defspec); @@ -475,7 +503,7 @@ MJAPI const double* mjm_getDouble(mjDouble source, int* size); MJAPI void mjm_setDefault(mjElement element, void* defspec); // Set frame. -MJAPI void mjm_setFrame(mjElement dest, void* frame); +MJAPI void mjm_setFrame(mjElement dest, mjmFrame* frame); // Compute quat and inertia from body->fullinertia. MJAPI const char* mjm_setFullInertia(mjmBody* body, double quat[4], double inertia[3]); @@ -486,6 +514,9 @@ MJAPI const char* mjm_setFullInertia(mjmBody* body, double quat[4], double inert // Default body attributes. MJAPI void mjm_defaultBody(mjmBody& body); +// Default frame attributes. +MJAPI void mjm_defaultFrame(mjmFrame& frame); + // Default joint attributes. MJAPI void mjm_defaultJoint(mjmJoint& joint); @@ -501,6 +532,9 @@ MJAPI void mjm_defaultCamera(mjmCamera& camera); // Default light attributes. MJAPI void mjm_defaultLight(mjmLight& light); +// Default material attributes. +MJAPI void mjm_defaultMaterial(mjmMaterial& material); + // Default equality attributes. MJAPI void mjm_defaultEquality(mjmEquality& equality); diff --git a/src/user/user_init.cc b/src/user/user_init.cc index 5cb09af3..ed12d2f9 100644 --- a/src/user/user_init.cc +++ b/src/user/user_init.cc @@ -38,6 +38,16 @@ void mjm_defaultBody(mjmBody& body) { +// default frame attributes +void mjm_defaultFrame(mjmFrame& frame) { + memset(&frame, 0, sizeof(mjmFrame)); + mju_zero3(frame.pos); + mjuu_setvec(frame.quat, 1, 0, 0, 0); + frame.alt.axisangle[0] = frame.alt.xyaxes[0] = frame.alt.zaxis[0] = frame.alt.euler[0] = mjNAN; +} + + + // default joint attributes void mjm_defaultJoint(mjmJoint& joint) { memset(&joint, 0, sizeof(mjmJoint)); @@ -157,6 +167,20 @@ void mjm_defaultLight(mjmLight& light) { +// Default material attributes. +void mjm_defaultMaterial(mjmMaterial& material) { + memset(&material, 0, sizeof(mjmMaterial)); + material.texuniform = false; + material.texrepeat[0] = material.texrepeat[1] = 1; + material.emission = 0; + material.specular = 0.5; + material.shininess = 0.5; + material.reflectance = 0; + material.rgba[0] = material.rgba[1] = material.rgba[2] = material.rgba[3] = 1; +} + + + // default equality attributes void mjm_defaultEquality(mjmEquality& equality) { memset(&equality, 0, sizeof(mjmEquality)); diff --git a/src/user/user_model.cc b/src/user/user_model.cc index 7fab7efe..f85fc3b2 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -667,8 +667,8 @@ void mjCModel::DeleteMaterial(std::vector& list, std::string_view name) { template static void DeleteTexture(std::vector& list, std::string_view name = "") { for (T* plist : list) { - if (name.empty() || plist->texture == name) { - plist->texture.clear(); + if (name.empty() || plist->get_texture() == name) { + plist->del_texture(); } } } @@ -869,12 +869,12 @@ void mjCModel::IndexAssets(bool discard) { mjCMaterial* pmat = materials[i]; // find texture by name - if (!pmat->texture.empty()) { - mjCBase* m = FindObject(mjOBJ_TEXTURE, pmat->texture); + if (!pmat->texture_.empty()) { + mjCBase* m = FindObject(mjOBJ_TEXTURE, pmat->texture_); if (m) { pmat->texid = m->id; } else { - throw mjCError(pmat, "texture '%s' not found in material %d", pmat->texture.c_str(), i); + throw mjCError(pmat, "texture '%s' not found in material %d", pmat->texture_.c_str(), i); } } } diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index 2d7e2379..942e7699 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -1175,19 +1175,42 @@ void mjCBody::Compile(void) { // initialize frame mjCFrame::mjCFrame(mjCModel* _model, mjCFrame* _frame) { + mjm_defaultFrame(spec); compiled = false; model = _model; frame = _frame ? _frame : NULL; - mju_zero3(pos); - mjuu_setvec(quat, 1, 0, 0, 0); + PointToLocal(); + CopyFromSpec(); } + + +void mjCFrame::PointToLocal() { + spec.element = (mjElement)this; + spec.info = (mjString)&info; +} + + + +void mjCFrame::CopyFromSpec() { + *static_cast(this) = spec; + mju_copy3(pos, spec.pos); + mju_copy4(quat, spec.quat); + mju_copy4(alt_.axisangle, alt.axisangle); + mju_copy(alt_.xyaxes, alt.xyaxes, 6); + mju_copy3(alt_.zaxis, alt.zaxis); + mju_copy3(alt_.euler, alt.euler); +} + + + void mjCFrame::Compile() { if (compiled) { return; } - const char* err = alt.Set(quat, model->degree, model->euler); + CopyFromSpec(); + const char* err = alt_.Set(quat, model->degree, model->euler); if (err) { throw mjCError(this, "orientation specification error '%s' in site %d", err, id); } @@ -3264,32 +3287,52 @@ void mjCTexture::Compile(const mjVFS* vfs) { // initialize defaults mjCMaterial::mjCMaterial(mjCModel* _model, mjCDef* _def) { - // set defaults - texture.clear(); + mjm_defaultMaterial(spec); + + // clear internal + spec_texture_.clear(); texid = -1; - texuniform = false; - texrepeat[0] = texrepeat[1] = 1; - emission = 0; - specular = 0.5; - shininess = 0.5; - reflectance = 0; - rgba[0] = rgba[1] = rgba[2] = rgba[3] = 1; // reset to default if given if (_def) { + _def->material.CopyFromSpec(); *this = _def->material; } // set model, def model = _model; def = (_def ? _def : (_model ? _model->defaults[0] : 0)); + + // point to local (needs to be after defaults) + PointToLocal(); + + // in case this camera is not compiled + CopyFromSpec(); +} + + + +void mjCMaterial::PointToLocal() { + spec.element = (mjElement)this; + spec.name = (mjString)&name; + spec.classname = (mjString)&classname; + spec.texture = (mjString)&spec_texture_; + spec.info = (mjString)&info; +} + + + +void mjCMaterial::CopyFromSpec() { + *static_cast(this) = spec; + texture_ = spec_texture_; + texture = (mjString)&texture_; } // compiler void mjCMaterial::Compile(void) { - // nothing to do for now + CopyFromSpec(); } diff --git a/src/user/user_objects.h b/src/user/user_objects.h index fdae10b9..d6ca7b7a 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -305,18 +305,26 @@ class mjCBody : public mjCBase, private mjmBody { //------------------------- class mjCFrame --------------------------------------------------------- // Describes a coordinate transformation relative to its parent -class mjCFrame : public mjCBase { +class mjCFrame : public mjCBase, private mjmFrame { friend class mjCBase; friend class mjCBody; + friend class mjCGeom; + friend class mjCJoint; + friend class mjCSite; + friend class mjCCamera; + friend class mjCLight; friend class mjCModel; public: - double pos[3]; // frame position - double quat[4]; // frame orientation - mjCAlternative alt; // alternative orientation specification + mjmFrame spec; + using mjCBase::info; + + void CopyFromSpec(void); + void PointToLocal(void); private: bool compiled; // frame already compiled + mjCAlternative alt_; mjCFrame(mjCModel* = 0, mjCFrame* = 0); // constructor void Compile(void); // compiler @@ -931,27 +939,30 @@ class mjCTexture : public mjCBase { //------------------------- class mjCMaterial ------------------------------------------------------ // Describes a material for rendering -class mjCMaterial : public mjCBase { +class mjCMaterial : public mjCBase, private mjmMaterial { friend class mjCDef; friend class mjCModel; friend class mjXWriter; public: - // variables set by user - std::string texture; // name of texture (empty: none) - bool texuniform; // make texture cube uniform - float texrepeat[2]; // texture repetition for 2D mapping - float emission; // emission - float specular; // specular - float shininess; // shininess - float reflectance; // reflectance - float rgba[4]; // rgba + mjmMaterial spec; + using mjCBase::name; + using mjCBase::classname; + using mjCBase::info; + + void CopyFromSpec(); + void PointToLocal(); + + std::string get_texture() { return texture_; } + void del_texture() { texture_.clear(); } private: mjCMaterial(mjCModel* = 0, mjCDef* = 0); // constructor void Compile(void); // compiler int texid; // id of material + std::string texture_; + std::string spec_texture_; }; diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 3c81f253..11c396ff 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -1441,14 +1441,20 @@ void mjXReader::OneSkin(XMLElement* elem, mjCSkin* pskin) { // material element parser -void mjXReader::OneMaterial(XMLElement* elem, mjCMaterial* pmat) { - string text; +void mjXReader::OneMaterial(XMLElement* elem, mjmMaterial* pmat) { + string text, name, classname, texture; int n; // read attributes - ReadAttrTxt(elem, "name", pmat->name); - ReadAttrTxt(elem, "class", pmat->classname); - ReadAttrTxt(elem, "texture", pmat->texture); + if (ReadAttrTxt(elem, "name", name)) { + mjm_setString(pmat->name, name.c_str()); + } + if (ReadAttrTxt(elem, "class", classname)) { + mjm_setString(pmat->classname, classname.c_str()); + } + if (ReadAttrTxt(elem, "texture", texture)) { + mjm_setString(pmat->texture, texture.c_str()); + } if (MapValue(elem, "texuniform", &n, bool_map, 2)) { pmat->texuniform = (n==1); } @@ -1459,7 +1465,9 @@ void mjXReader::OneMaterial(XMLElement* elem, mjCMaterial* pmat) { ReadAttr(elem, "reflectance", 1, &pmat->reflectance, text); ReadAttr(elem, "rgba", 4, pmat->rgba, text); - GetXMLPos(elem, pmat); + // write error info + mjm_setString(pmat->info, + std::string("line = " + std::to_string(elem->GetLineNum()) + ", column = -1").c_str()); } @@ -2580,7 +2588,7 @@ void mjXReader::Default(XMLElement* section, int parentid) { if (name=="mesh") OneMesh(elem, &def->mesh); // read material - else if (name=="material") OneMaterial(elem, &def->material); + else if (name=="material") OneMaterial(elem, &def->material.spec); // read joint else if (name=="joint") OneJoint(elem, &def->joint.spec); @@ -2626,6 +2634,7 @@ void mjXReader::Default(XMLElement* section, int parentid) { mjm_finalize(def->camera.spec.element); mjm_finalize(def->light.spec.element); mjm_finalize(def->actuator.spec.element); + mjm_finalize(def->material.spec.element); mjm_finalize(def->equality.spec.element); mjm_finalize(def->tendon.spec.element); @@ -3019,7 +3028,7 @@ void mjXReader::Asset(XMLElement* section) { // material sub-element else if (name=="material") { // create material and parse - mjCMaterial* pmat = model->AddMaterial(def); + mjmMaterial* pmat = mjm_addMaterial(model, def); OneMaterial(elem, pmat); } @@ -3089,7 +3098,7 @@ void mjXReader::Asset(XMLElement* section) { // body/world section parser; recursive -void mjXReader::Body(XMLElement* section, mjmBody* pbody, mjCFrame* frame) { +void mjXReader::Body(XMLElement* section, mjmBody* pbody, mjmFrame* frame) { string text, name; XMLElement* elem; int n; @@ -3220,8 +3229,8 @@ void mjXReader::Body(XMLElement* section, mjmBody* pbody, mjCFrame* frame) { // frame sub-element else if (name=="frame") { - mjCFrame* pframe = (mjCFrame*)mjm_addFrame(pbody, frame); - GetXMLPos(elem, pframe); + mjmFrame* pframe = mjm_addFrame(pbody, frame); + mjm_setString(pframe->info, ("line = " + std::to_string(elem->GetLineNum())).c_str()); ReadAttr(elem, "pos", 3, pframe->pos, text); ReadQuat(elem, "quat", pframe->quat, text); diff --git a/src/xml/xml_native_reader.h b/src/xml/xml_native_reader.h index 5f4dc6c1..c20564e7 100644 --- a/src/xml/xml_native_reader.h +++ b/src/xml/xml_native_reader.h @@ -43,7 +43,7 @@ class mjXReader : public mjXBase { void Statistic(tinyxml2::XMLElement* section); // statistic section void Asset(tinyxml2::XMLElement* section); // asset section void Body(tinyxml2::XMLElement* section, mjmBody* pbody, - mjCFrame* pframe); // body/world section + mjmFrame* 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 @@ -56,7 +56,7 @@ class mjXReader : public mjXBase { void OneFlex(tinyxml2::XMLElement* elem, mjCFlex* pflex); void OneMesh(tinyxml2::XMLElement* elem, mjCMesh* pmesh); void OneSkin(tinyxml2::XMLElement* elem, mjCSkin* pskin); - void OneMaterial(tinyxml2::XMLElement* elem, mjCMaterial* pmaterial); + 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); diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index 63671cb9..e5b6099b 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -259,7 +259,7 @@ void mjXWriter::OneMaterial(XMLElement* elem, mjCMaterial* pmat, mjCDef* def) { // defaults and regular if (pmat->texture != def->material.texture) { - WriteAttrTxt(elem, "texture", pmat->texture); + WriteAttrTxt(elem, "texture", pmat->get_texture()); } WriteAttrKey(elem, "texuniform", bool_map, 2, pmat->texuniform, def->material.texuniform); WriteAttr(elem, "texrepeat", 2, pmat->texrepeat, def->material.texrepeat);