From 6f958bc4040854eaf9a2bb3bc7df8452a7f5e9f1 Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Thu, 15 Feb 2024 05:07:51 -0800 Subject: [PATCH] Add mjmSkin to C API. PiperOrigin-RevId: 607295996 Change-Id: I63bf7213d41acbfb98770c097979ce9b889f21ca --- src/user/user_api.cc | 37 ++- src/user/user_api.h | 60 ++++- src/user/user_composite.cc | 484 ++++++++++++++++++----------------- src/user/user_composite.h | 23 +- src/user/user_flexcomp.cc | 6 +- src/user/user_init.cc | 11 + src/user/user_mesh.cc | 229 ++++++++++------- src/user/user_model.cc | 44 ++-- src/user/user_objects.cc | 1 - src/user/user_objects.h | 60 +++-- src/xml/xml_native_reader.cc | 69 +++-- src/xml/xml_native_reader.h | 2 +- src/xml/xml_native_writer.cc | 24 +- 13 files changed, 630 insertions(+), 420 deletions(-) diff --git a/src/user/user_api.cc b/src/user/user_api.cc index 1b146cfa..74ec08f0 100644 --- a/src/user/user_api.cc +++ b/src/user/user_api.cc @@ -156,6 +156,15 @@ mjmHField* mjm_addHField(void* model) { +// add skin to model +mjmSkin* mjm_addSkin(void* model) { + mjCModel* modelC = static_cast(model); + mjCSkin* skin = modelC->AddSkin(); + return &skin->spec; +} + + + // add texture to model mjmTexture* mjm_addTexture(void* model) { mjCModel* modelC = static_cast(model); @@ -370,6 +379,7 @@ int mjm_getId(mjElement element) { } + // set default void mjm_setDefault(mjElement element, void* defspec) { mjCBase* baseC = reinterpret_cast(element); @@ -377,6 +387,7 @@ void mjm_setDefault(mjElement element, void* defspec) { } + // set string void mjm_setString(mjString dest, const char* text) { std::string* str = reinterpret_cast(dest); @@ -405,14 +416,15 @@ void mjm_setStringVec(mjStringVec dest, const char* text) { } + // add text entry to destination string vector -void mjm_addToStringVec(mjStringVec dest, const char* text) { +void mjm_appendString(mjStringVec dest, const char* text) { std::vector* v = reinterpret_cast*>(dest); v->push_back(std::string(text)); } -// set int array +// copy int array to vector void mjm_setInt(mjIntVec dest, const int* array, int size) { std::vector* v = reinterpret_cast*>(dest); v->assign(size, 0.0); @@ -423,7 +435,15 @@ void mjm_setInt(mjIntVec dest, const int* array, int size) { -// set float array +// append int array to vector of arrays +void mjm_appendIntVec(mjIntVecVec dest, const int* array, int size) { + std::vector>* v = reinterpret_cast>*>(dest); + v->push_back(std::vector(array, array + size)); +} + + + +// copy float array to vector void mjm_setFloat(mjFloatVec dest, const float* array, int size) { std::vector* v = reinterpret_cast*>(dest); v->assign(size, 0.0); @@ -434,7 +454,16 @@ void mjm_setFloat(mjFloatVec dest, const float* array, int size) { -// set double array + +// append float array to vector of arrays +void mjm_appendFloatVec(mjFloatVecVec dest, const float* array, int size) { + std::vector>* v = reinterpret_cast>*>(dest); + v->push_back(std::vector(array, array + size)); +} + + + +// copy double array to vector void mjm_setDouble(mjDoubleVec dest, const double* array, int size) { std::vector* v = reinterpret_cast*>(dest); v->assign(size, 0.0); diff --git a/src/user/user_api.h b/src/user/user_api.h index 5042a916..fb9be03f 100644 --- a/src/user/user_api.h +++ b/src/user/user_api.h @@ -32,8 +32,10 @@ typedef struct _mjElement* mjElement; typedef struct _mjString* mjString; typedef struct _mjStringVec* mjStringVec; typedef struct _mjIntVec* mjIntVec; -typedef struct _mjDoubleVec* mjDoubleVec; +typedef struct _mjIntVecVec* mjIntVecVec; typedef struct _mjFloatVec* mjFloatVec; +typedef struct _mjFloatVecVec* mjFloatVecVec; +typedef struct _mjDoubleVec* mjDoubleVec; //---------------------------------- enum types (mjt) ---------------------------------------------- @@ -366,6 +368,34 @@ typedef struct _mjmHField { // height field specification } mjmHField; + +typedef struct _mjmSkin { // skin specification + mjElement element; // internal, do not modify + mjString name; // name + mjString classname; // class name + mjString file; // skin file + mjString material; // name of material used for rendering + float rgba[4]; // rgba when material is omitted + float inflate; // inflate in normal direction + int group; // group for visualization + + // mesh + mjFloatVec vert; // vertex positions + mjFloatVec texcoord; // texture coordinates + mjIntVec face; // faces + + // skin + mjStringVec bodyname; // body names + mjFloatVec bindpos; // bind pos + mjFloatVec bindquat; // bind quat + mjIntVecVec vertid; // vertex ids + mjFloatVecVec vertweight; // vertex weights + + // other + mjString info; // message appended to compiler errors +} mjmSkin; + + typedef struct _mjmTexture { // texture specification mjElement element; // internal, do not modify mjString name; // name @@ -655,6 +685,9 @@ MJAPI mjmMesh* mjm_addMesh(void* model, void* defspec); // Add height field to model. MJAPI mjmHField* mjm_addHField(void* model); +// Add skin to model. +MJAPI mjmSkin* mjm_addSkin(void* model); + // Add texture to model. MJAPI mjmTexture* mjm_addTexture(void* model); @@ -721,25 +754,31 @@ MJAPI mjmBody* mjm_findChild(mjmBody* body, const char* name); // Get element id. MJAPI int mjm_getId(mjElement element); -// Copy text to destination string. +// Copy text to string. MJAPI void mjm_setString(mjString dest, const char* text); -// Split text to entries and copy to destination string vector. +// Split text to entries and copy to string vector. MJAPI void mjm_setStringVec(mjStringVec dest, const char* text); -// Set specific entry in destination string vector. +// Set entry in string vector. MJAPI mjtByte mjm_setInStringVec(mjStringVec dest, int i, const char* text); -// Add text entry to destination string vector. -MJAPI void mjm_addToStringVec(mjStringVec dest, const char* text); +// Append text entry to string vector. +MJAPI void mjm_appendString(mjStringVec dest, const char* text); -// Copy int array to destination vector. +// Copy int array to vector. MJAPI void mjm_setInt(mjIntVec dest, const int* array, int size); -// Copy float array to destination vector. +// Append int array to vector of arrays. +MJAPI void mjm_appendIntVec(mjIntVecVec dest, const int* array, int size); + +// Copy float array to vector. MJAPI void mjm_setFloat(mjFloatVec dest, const float* array, int size); -// Copy double array to destination vector. +// Append float array to vector of arrays. +MJAPI void mjm_appendFloatVec(mjFloatVecVec dest, const float* array, int size); + +// Copy double array to vector. MJAPI void mjm_setDouble(mjDoubleVec dest, const double* array, int size); // Get string contents. @@ -790,6 +829,9 @@ MJAPI void mjm_defaultMesh(mjmMesh& mesh); // Default height field attributes. MJAPI void mjm_defaultHField(mjmHField& hfield); +// Default skin attributes. +MJAPI void mjm_defaultSkin(mjmSkin& skin); + // Default texture attributes. MJAPI void mjm_defaultTexture(mjmTexture& texture); diff --git a/src/user/user_composite.cc b/src/user/user_composite.cc index ff2edb62..ddb7e88a 100644 --- a/src/user/user_composite.cc +++ b/src/user/user_composite.cc @@ -279,6 +279,15 @@ bool mjCComposite::Make(mjCModel* model, mjmBody* body, char* error, int error_s } } + // clear skin vectors + face.clear(); + vert.clear(); + bindpos.clear(); + bindquat.clear(); + texcoord.clear(); + vertid.clear(); + vertweight.clear(); + // require 3x3 for subgrid if (skin && skinsubgrid>0 && type!=mjCOMPTYPE_CABLE) { if (count[0]<3 || count[1]<3) { @@ -1238,57 +1247,80 @@ void mjCComposite::MakeShear(mjCModel* model) { +// copy local vectors to skin +void mjCComposite::CopyIntoSkin(mjmSkin* skin) { + mjm_setInt(skin->face, face.data(), face.size()); + mjm_setFloat(skin->vert, vert.data(), vert.size()); + mjm_setFloat(skin->bindpos, bindpos.data(), bindpos.size()); + mjm_setFloat(skin->bindquat, bindquat.data(), bindquat.size()); + mjm_setFloat(skin->texcoord, texcoord.data(), texcoord.size()); + + for (int i=0; ivertid, vertid[i].data(), vertid[i].size()); + } + for (int i=0; i< vertweight.size(); i++) { + mjm_appendFloatVec(skin->vertweight, vertweight[i].data(), vertweight[i].size()); + } + + face.clear(); + vert.clear(); + bindpos.clear(); + bindquat.clear(); + texcoord.clear(); + vertid.clear(); + vertweight.clear(); +} + + + // add skin to 2D void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) { char txt[100]; int N = count[0]*count[1]; // add skin, set name and material - mjCSkin* skin = model->AddSkin(); + mjmSkin* skin = mjm_addSkin(model); mju::sprintf_arr(txt, "%sSkin", prefix.c_str()); - skin->name = txt; - skin->set_material(skinmaterial); + mjm_setString(skin->name, txt); + mjm_setString(skin->material, skinmaterial.c_str()); mjuu_copyvec(skin->rgba, skinrgba, 4); skin->inflate = inflate; skin->group = skingroup; // copy skin from existing mesh if (type==mjCOMPTYPE_PARTICLE && username.empty()) { - std::vector face; - mjXUtil::String2Vector(userface, face); + std::vector skinface; + mjXUtil::String2Vector(userface, skinface); int nvert = uservert.size()/3; for (int j=0; j<2; j++) { for (int i=0; ivert.push_back(0); - skin->vert.push_back(0); - skin->vert.push_back(0); + vert.push_back(0); + vert.push_back(0); + vert.push_back(0); mju::sprintf_arr(txt, "%sB%d", prefix.c_str(), i); - skin->bodyname.push_back(txt); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindquat.push_back(1); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, txt); + bindpos.push_back(0); + bindpos.push_back(0); + bindpos.push_back(0); + bindquat.push_back(1); + bindquat.push_back(0); + bindquat.push_back(0); + bindquat.push_back(0); - vector vertid; - vector vertweight; - vertid.push_back(j*nvert+i); - vertweight.push_back(1); - skin->vertid.push_back(vertid); - skin->vertweight.push_back(vertweight); + vertid.push_back({j*nvert+i}); + vertweight.push_back({1}); } - for (int i=0; iface.push_back(j*nvert+face[3*i]); - skin->face.push_back(j*nvert+face[3*i+(j==0 ? 1 : 2)]); - skin->face.push_back(j*nvert+face[3*i+(j==0 ? 2 : 1)]); + for (int i=0; ivert.push_back(0); - skin->vert.push_back(0); - skin->vert.push_back(0); + vert.push_back(0); + vert.push_back(0); + vert.push_back(0); // texture coordinate if (skintexcoord) { - skin->texcoord.push_back(ix/(float)(count[0]-1)); - skin->texcoord.push_back(iy/(float)(count[1]-1)); + texcoord.push_back(ix/(float)(count[0]-1)); + texcoord.push_back(iy/(float)(count[1]-1)); } // face if (ixface.push_back(i*N + ix*count[1]+iy); - skin->face.push_back(i*N + (ix+1)*count[1]+iy+(i==1)); - skin->face.push_back(i*N + (ix+1)*count[1]+iy+(i==0)); + face.push_back(i*N + ix*count[1]+iy); + face.push_back(i*N + (ix+1)*count[1]+iy+(i==1)); + face.push_back(i*N + (ix+1)*count[1]+iy+(i==0)); - skin->face.push_back(i*N + ix*count[1]+iy); - skin->face.push_back(i*N + (ix+(i==0))*count[1]+iy+1); - skin->face.push_back(i*N + (ix+(i==1))*count[1]+iy+1); + face.push_back(i*N + ix*count[1]+iy); + face.push_back(i*N + (ix+(i==0))*count[1]+iy+1); + face.push_back(i*N + (ix+(i==1))*count[1]+iy+1); } } } @@ -1323,46 +1355,46 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) { // add thin triangles: X direction, iy = 0 for (int ix=0; ixface.push_back(ix*count[1]); - skin->face.push_back(N + (ix+1)*count[1]); - skin->face.push_back((ix+1)*count[1]); + face.push_back(ix*count[1]); + face.push_back(N + (ix+1)*count[1]); + face.push_back((ix+1)*count[1]); - skin->face.push_back(ix*count[1]); - skin->face.push_back(N + ix*count[1]); - skin->face.push_back(N + (ix+1)*count[1]); + face.push_back(ix*count[1]); + face.push_back(N + ix*count[1]); + face.push_back(N + (ix+1)*count[1]); } // add thin triangles: X direction, iy = count[1]-1 for (int ix=0; ixface.push_back(ix*count[1] + count[1]-1); - skin->face.push_back((ix+1)*count[1] + count[1]-1); - skin->face.push_back(N + (ix+1)*count[1] + count[1]-1); + face.push_back(ix*count[1] + count[1]-1); + face.push_back((ix+1)*count[1] + count[1]-1); + face.push_back(N + (ix+1)*count[1] + count[1]-1); - skin->face.push_back(ix*count[1] + count[1]-1); - skin->face.push_back(N + (ix+1)*count[1] + count[1]-1); - skin->face.push_back(N + ix*count[1] + count[1]-1); + face.push_back(ix*count[1] + count[1]-1); + face.push_back(N + (ix+1)*count[1] + count[1]-1); + face.push_back(N + ix*count[1] + count[1]-1); } // add thin triangles: Y direction, ix = 0 for (int iy=0; iyface.push_back(iy); - skin->face.push_back(iy+1); - skin->face.push_back(N + iy+1); + face.push_back(iy); + face.push_back(iy+1); + face.push_back(N + iy+1); - skin->face.push_back(iy); - skin->face.push_back(N + iy+1); - skin->face.push_back(N + iy); + face.push_back(iy); + face.push_back(N + iy+1); + face.push_back(N + iy); } // add thin triangles: Y direction, ix = count[0]-1 for (int iy=0; iyface.push_back(iy + (count[0]-1)*count[1]); - skin->face.push_back(N + iy+1 + (count[0]-1)*count[1]); - skin->face.push_back(iy+1 + (count[0]-1)*count[1]); + face.push_back(iy + (count[0]-1)*count[1]); + face.push_back(N + iy+1 + (count[0]-1)*count[1]); + face.push_back(iy+1 + (count[0]-1)*count[1]); - skin->face.push_back(iy + (count[0]-1)*count[1]); - skin->face.push_back(N + iy + (count[0]-1)*count[1]); - skin->face.push_back(N + iy+1 + (count[0]-1)*count[1]); + face.push_back(iy + (count[0]-1)*count[1]); + face.push_back(N + iy + (count[0]-1)*count[1]); + face.push_back(N + iy+1 + (count[0]-1)*count[1]); } // couple with bones @@ -1371,12 +1403,14 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) { } else if (type==mjCOMPTYPE_CABLE) { MakeCableBones(model, skin); } + + CopyIntoSkin(skin); } // add bones in 2D -void mjCComposite::MakeClothBones(mjCModel* model, mjCSkin* skin) { +void mjCComposite::MakeClothBones(mjCModel* model, mjmSkin* skin) { char txt[100]; int N = count[0]*count[1]; @@ -1391,31 +1425,25 @@ void mjCComposite::MakeClothBones(mjCModel* model, mjCSkin* skin) { } // bind pose - skin->bodyname.push_back(txt); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindquat.push_back(1); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, txt); + bindpos.push_back(0); + bindpos.push_back(0); + bindpos.push_back(0); + bindquat.push_back(1); + bindquat.push_back(0); + bindquat.push_back(0); + bindquat.push_back(0); // create vertid and vertweight - vector vertid; - vector vertweight; - vertid.push_back(ix*count[1]+iy); - vertid.push_back(N + ix*count[1]+iy); - vertweight.push_back(1); - vertweight.push_back(1); - skin->vertid.push_back(vertid); - skin->vertweight.push_back(vertweight); + vertid.push_back({ix*count[1]+iy, N + ix*count[1]+iy}); + vertweight.push_back({1, 1}); } } } -void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin) { +void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjmSkin* skin) { char txt[100]; // populate bones @@ -1429,20 +1457,18 @@ void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin) { } // bind pose - skin->bodyname.push_back(txt); - skin->bindpos.push_back(ix*spacing); - skin->bindpos.push_back(iy*spacing); - skin->bindpos.push_back(0); - skin->bindquat.push_back(1); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, txt); + bindpos.push_back(ix*spacing); + bindpos.push_back(iy*spacing); + bindpos.push_back(0); + bindquat.push_back(1); + bindquat.push_back(0); + bindquat.push_back(0); + bindquat.push_back(0); // empty vertid and vertweight - vector vertid; - vector vertweight; - skin->vertid.push_back(vertid); - skin->vertweight.push_back(vertweight); + vertid.push_back({}); + vertweight.push_back({}); } } } @@ -1450,7 +1476,7 @@ void mjCComposite::MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin) { // add bones to 1D -void mjCComposite::MakeCableBones(mjCModel* model, mjCSkin* skin) { +void mjCComposite::MakeCableBones(mjCModel* model, mjmSkin* skin) { char this_body[100]; int N = count[0]*count[1]; @@ -1468,31 +1494,31 @@ void mjCComposite::MakeCableBones(mjCModel* model, mjCSkin* skin) { // bind pose if (iy==0) { - skin->bodyname.push_back(this_body); - skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); - skin->bindpos.push_back(-def[0].geom.spec.size[1]); - skin->bindpos.push_back(0); - skin->bindquat.push_back(1); skin->bindquat.push_back(0); - skin->bindquat.push_back(0); skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, this_body); + bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); + bindpos.push_back(-def[0].geom.spec.size[1]); + bindpos.push_back(0); + bindquat.push_back(1); bindquat.push_back(0); + bindquat.push_back(0); bindquat.push_back(0); } else { - skin->bodyname.push_back(this_body); - skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); - skin->bindpos.push_back(def[0].geom.spec.size[1]); - skin->bindpos.push_back(0); - skin->bindquat.push_back(1); skin->bindquat.push_back(0); - skin->bindquat.push_back(0); skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, this_body); + bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); + bindpos.push_back(def[0].geom.spec.size[1]); + bindpos.push_back(0); + bindquat.push_back(1); bindquat.push_back(0); + bindquat.push_back(0); bindquat.push_back(0); } // create vertid and vertweight - skin->vertid.push_back({ix*count[1]+iy, N + ix*count[1]+iy}); - skin->vertweight.push_back({1, 1}); + vertid.push_back({ix*count[1]+iy, N + ix*count[1]+iy}); + vertweight.push_back({1, 1}); } } } -void mjCComposite::MakeCableBonesSubgrid(mjCModel* model, mjCSkin* skin) { +void mjCComposite::MakeCableBonesSubgrid(mjCModel* model, mjmSkin* skin) { // populate bones for (int ix=0; ixbindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); - skin->bindpos.push_back(-def[0].geom.spec.size[1]); - skin->bindpos.push_back(0); + bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); + bindpos.push_back(-def[0].geom.spec.size[1]); + bindpos.push_back(0); } else if (iy==2) { - skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); - skin->bindpos.push_back(def[0].geom.spec.size[1]); - skin->bindpos.push_back(0); + bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); + bindpos.push_back(def[0].geom.spec.size[1]); + bindpos.push_back(0); } else { - skin->bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); + bindpos.push_back((ix==count[0]-1) ? -2*def[0].geom.spec.size[0] : 0); + bindpos.push_back(0); + bindpos.push_back(0); } - skin->bodyname.push_back(txt); - skin->bindquat.push_back(1); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, txt); + bindquat.push_back(1); + bindquat.push_back(0); + bindquat.push_back(0); + bindquat.push_back(0); // empty vertid and vertweight - skin->vertid.push_back({}); - skin->vertweight.push_back({}); + vertid.push_back({}); + vertweight.push_back({}); } } } @@ -1846,10 +1872,10 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) { // add skin, set name and material char txt[100]; - mjCSkin* skin = model->AddSkin(); + mjmSkin* skin = mjm_addSkin(model); mju::sprintf_arr(txt, "%sSkin", prefix.c_str()); - skin->name = txt; - skin->set_material(skinmaterial); + mjm_setString(skin->name, txt); + mjm_setString(skin->material, skinmaterial.c_str()); mjuu_copyvec(skin->rgba, skinrgba, 4); skin->inflate = inflate; skin->group = skingroup; @@ -1863,25 +1889,25 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) { for (int ix=0; ixvert.push_back(ix*S); - skin->vert.push_back(iy*S); - skin->vert.push_back(0); + vert.push_back(ix*S); + vert.push_back(iy*S); + vert.push_back(0); // texture coordinate if (skintexcoord) { - skin->texcoord.push_back(ix/(float)(C0-1)); - skin->texcoord.push_back(iy/(float)(C1-1)); + texcoord.push_back(ix/(float)(C0-1)); + texcoord.push_back(iy/(float)(C1-1)); } // face if (ixface.push_back(i*NN + ix*C1+iy); - skin->face.push_back(i*NN + (ix+1)*C1+iy+(i==1)); - skin->face.push_back(i*NN + (ix+1)*C1+iy+(i==0)); + face.push_back(i*NN + ix*C1+iy); + face.push_back(i*NN + (ix+1)*C1+iy+(i==1)); + face.push_back(i*NN + (ix+1)*C1+iy+(i==0)); - skin->face.push_back(i*NN + ix*C1+iy); - skin->face.push_back(i*NN + (ix+(i==0))*C1+iy+1); - skin->face.push_back(i*NN + (ix+(i==1))*C1+iy+1); + face.push_back(i*NN + ix*C1+iy); + face.push_back(i*NN + (ix+(i==0))*C1+iy+1); + face.push_back(i*NN + (ix+(i==1))*C1+iy+1); } } } @@ -1889,46 +1915,46 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) { // add thin triangles: X direction, iy = 0 for (int ix=0; ixface.push_back(ix*C1); - skin->face.push_back(NN + (ix+1)*C1); - skin->face.push_back((ix+1)*C1); + face.push_back(ix*C1); + face.push_back(NN + (ix+1)*C1); + face.push_back((ix+1)*C1); - skin->face.push_back(ix*C1); - skin->face.push_back(NN + ix*C1); - skin->face.push_back(NN + (ix+1)*C1); + face.push_back(ix*C1); + face.push_back(NN + ix*C1); + face.push_back(NN + (ix+1)*C1); } // add thin triangles: X direction, iy = C1-1 for (int ix=0; ixface.push_back(ix*C1 + C1-1); - skin->face.push_back((ix+1)*C1 + C1-1); - skin->face.push_back(NN + (ix+1)*C1 + C1-1); + face.push_back(ix*C1 + C1-1); + face.push_back((ix+1)*C1 + C1-1); + face.push_back(NN + (ix+1)*C1 + C1-1); - skin->face.push_back(ix*C1 + C1-1); - skin->face.push_back(NN + (ix+1)*C1 + C1-1); - skin->face.push_back(NN + ix*C1 + C1-1); + face.push_back(ix*C1 + C1-1); + face.push_back(NN + (ix+1)*C1 + C1-1); + face.push_back(NN + ix*C1 + C1-1); } // add thin triangles: Y direction, ix = 0 for (int iy=0; iyface.push_back(iy); - skin->face.push_back(iy+1); - skin->face.push_back(NN + iy+1); + face.push_back(iy); + face.push_back(iy+1); + face.push_back(NN + iy+1); - skin->face.push_back(iy); - skin->face.push_back(NN + iy+1); - skin->face.push_back(NN + iy); + face.push_back(iy); + face.push_back(NN + iy+1); + face.push_back(NN + iy); } // add thin triangles: Y direction, ix = C0-1 for (int iy=0; iyface.push_back(iy + (C0-1)*C1); - skin->face.push_back(NN + iy+1 + (C0-1)*C1); - skin->face.push_back(iy+1 + (C0-1)*C1); + face.push_back(iy + (C0-1)*C1); + face.push_back(NN + iy+1 + (C0-1)*C1); + face.push_back(iy+1 + (C0-1)*C1); - skin->face.push_back(iy + (C0-1)*C1); - skin->face.push_back(NN + iy + (C0-1)*C1); - skin->face.push_back(NN + iy+1 + (C0-1)*C1); + face.push_back(iy + (C0-1)*C1); + face.push_back(NN + iy + (C0-1)*C1); + face.push_back(NN + iy+1 + (C0-1)*C1); } if (type==mjCOMPTYPE_PARTICLE || type==mjCOMPTYPE_GRID) { @@ -1966,10 +1992,10 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) { for (int bi=0; bi<16; bi++) { mjtNum w = Weight[d*N*16 + n*16 + bi]; if (w) { - skin->vertid[boneid[bi]].push_back(vid); - skin->vertid[boneid[bi]].push_back(vid+NN); - skin->vertweight[boneid[bi]].push_back((float)w); - skin->vertweight[boneid[bi]].push_back((float)w); + vertid[boneid[bi]].push_back(vid); + vertid[boneid[bi]].push_back(vid+NN); + vertweight[boneid[bi]].push_back((float)w); + vertweight[boneid[bi]].push_back((float)w); } } } @@ -1977,6 +2003,8 @@ void mjCComposite::MakeSkin2Subgrid(mjCModel* model, mjtNum inflate) { } } + CopyIntoSkin(skin); + // free allocations mju_free(XY); mju_free(XY_W); @@ -1999,10 +2027,10 @@ void mjCComposite::MakeSkin3(mjCModel* model) { mju::sprintf_arr(cnt2, "%d", count[2]-1); // add skin, set name and material - mjCSkin* skin = model->AddSkin(); + mjmSkin* skin = mjm_addSkin(model); mju::sprintf_arr(txt, "%sSkin", prefix.c_str()); - skin->name = txt; - skin->set_material(skinmaterial); + mjm_setString(skin->name, txt); + mjm_setString(skin->material, skinmaterial.c_str()); mjuu_copyvec(skin->rgba, skinrgba, 4); skin->inflate = skininflate; skin->group = skingroup; @@ -2038,9 +2066,9 @@ void mjCComposite::MakeSkin3(mjCModel* model) { mju::sprintf_arr(txt, "%sB%d_%d_%d", prefix.c_str(), ix, iy, iz); // add vertex - skin->vert.push_back(0); - skin->vert.push_back(0); - skin->vert.push_back(0); + vert.push_back(0); + vert.push_back(0); + vert.push_back(0); // texture coordinate if (skintexcoord) { @@ -2053,8 +2081,8 @@ void mjCComposite::MakeSkin3(mjCModel* model) { Y = iz/(float)(count[2]-1); } - skin->texcoord.push_back(X); - skin->texcoord.push_back(Y); + texcoord.push_back(X); + texcoord.push_back(Y); } // save vertex id in map @@ -2095,9 +2123,9 @@ void mjCComposite::MakeSkin3(mjCModel* model) { mju::sprintf_arr(txt, "%sB%d_%d_%d", prefix.c_str(), ix, iy, iz); // add vertex - skin->vert.push_back(0); - skin->vert.push_back(0); - skin->vert.push_back(0); + vert.push_back(0); + vert.push_back(0); + vert.push_back(0); // texture coordinate if (skintexcoord) { @@ -2113,8 +2141,8 @@ void mjCComposite::MakeSkin3(mjCModel* model) { Y = iy/(float)(count[1]-1); } - skin->texcoord.push_back(X); - skin->texcoord.push_back(Y); + texcoord.push_back(X); + texcoord.push_back(Y); } // save vertex id in map @@ -2140,12 +2168,14 @@ void mjCComposite::MakeSkin3(mjCModel* model) { fmt = "%sB" + string(cnt0) + "_%d_%d"; MakeSkin3Smooth(skin, count[1], count[2], 0, vmap, fmt.c_str()); } + + CopyIntoSkin(skin); } // make one face of 3D skin, box -void mjCComposite::MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side, +void mjCComposite::MakeSkin3Box(mjmSkin* skin, int c0, int c1, int side, int& vcnt, const char* format) { char txt[100]; @@ -2153,47 +2183,43 @@ void mjCComposite::MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side, for (int i0=0; i0vert.push_back(0); - skin->vert.push_back(0); - skin->vert.push_back(0); + vert.push_back(0); + vert.push_back(0); + vert.push_back(0); // texture coordinate if (skintexcoord) { - skin->texcoord.push_back(i0/(float)(c0-1)); - skin->texcoord.push_back(i1/(float)(c1-1)); + texcoord.push_back(i0/(float)(c0-1)); + texcoord.push_back(i1/(float)(c1-1)); } // face if (i0face.push_back(vcnt + i0*c1+i1); - skin->face.push_back(vcnt + (i0+1)*c1+i1+(side==1)); - skin->face.push_back(vcnt + (i0+1)*c1+i1+(side==0)); + face.push_back(vcnt + i0*c1+i1); + face.push_back(vcnt + (i0+1)*c1+i1+(side==1)); + face.push_back(vcnt + (i0+1)*c1+i1+(side==0)); - skin->face.push_back(vcnt + i0*c1+i1); - skin->face.push_back(vcnt + (i0+(side==0))*c1+i1+1); - skin->face.push_back(vcnt + (i0+(side==1))*c1+i1+1); + face.push_back(vcnt + i0*c1+i1); + face.push_back(vcnt + (i0+(side==0))*c1+i1+1); + face.push_back(vcnt + (i0+(side==1))*c1+i1+1); } // body name mju::sprintf_arr(txt, format, prefix.c_str(), i0, i1); // bind pose: origin - skin->bodyname.push_back(txt); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindquat.push_back(1); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, txt); + bindpos.push_back(0); + bindpos.push_back(0); + bindpos.push_back(0); + bindquat.push_back(1); + bindquat.push_back(0); + bindquat.push_back(0); + bindquat.push_back(0); // vertid and vertweight - vector vertid; - vector vertweight; - vertid.push_back(vcnt + i0*c1+i1); - vertweight.push_back(1); - skin->vertid.push_back(vertid); - skin->vertweight.push_back(vertweight); + vertid.push_back({vcnt + i0*c1+i1}); + vertweight.push_back({1}); } } @@ -2204,7 +2230,7 @@ void mjCComposite::MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side, // make one face of 3D skin, smooth -void mjCComposite::MakeSkin3Smooth(mjCSkin* skin, int c0, int c1, int side, +void mjCComposite::MakeSkin3Smooth(mjmSkin* skin, int c0, int c1, int side, const std::map& vmap, const char* format) { char txt00[100], txt01[100], txt10[100], txt11[100]; @@ -2220,41 +2246,37 @@ void mjCComposite::MakeSkin3Smooth(mjCSkin* skin, int c0, int c1, int side, // face if (i0face.push_back(vmap.find(txt00)->second); - skin->face.push_back(vmap.find(txt10)->second); - skin->face.push_back(vmap.find(txt11)->second); + face.push_back(vmap.find(txt00)->second); + face.push_back(vmap.find(txt10)->second); + face.push_back(vmap.find(txt11)->second); - skin->face.push_back(vmap.find(txt00)->second); - skin->face.push_back(vmap.find(txt11)->second); - skin->face.push_back(vmap.find(txt01)->second); + face.push_back(vmap.find(txt00)->second); + face.push_back(vmap.find(txt11)->second); + face.push_back(vmap.find(txt01)->second); } else { - skin->face.push_back(vmap.find(txt00)->second); - skin->face.push_back(vmap.find(txt01)->second); - skin->face.push_back(vmap.find(txt11)->second); + face.push_back(vmap.find(txt00)->second); + face.push_back(vmap.find(txt01)->second); + face.push_back(vmap.find(txt11)->second); - skin->face.push_back(vmap.find(txt00)->second); - skin->face.push_back(vmap.find(txt11)->second); - skin->face.push_back(vmap.find(txt10)->second); + face.push_back(vmap.find(txt00)->second); + face.push_back(vmap.find(txt11)->second); + face.push_back(vmap.find(txt10)->second); } } // bind pose: origin - skin->bodyname.push_back(txt00); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindpos.push_back(0); - skin->bindquat.push_back(1); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); - skin->bindquat.push_back(0); + mjm_appendString(skin->bodyname, txt00); + bindpos.push_back(0); + bindpos.push_back(0); + bindpos.push_back(0); + bindquat.push_back(1); + bindquat.push_back(0); + bindquat.push_back(0); + bindquat.push_back(0); // vertid and vertweight - vector vertid; - vector vertweight; - vertid.push_back(vmap.find(txt00)->second); - vertweight.push_back(1); - skin->vertid.push_back(vertid); - skin->vertweight.push_back(vertweight); + vertid.push_back({vmap.find(txt00)->second}); + vertweight.push_back({1}); } } } diff --git a/src/user/user_composite.h b/src/user/user_composite.h index d85e5891..161b24ee 100644 --- a/src/user/user_composite.h +++ b/src/user/user_composite.h @@ -20,6 +20,7 @@ #include #include +#include "user/user_api.h" #include "user/user_model.h" #include "user/user_objects.h" @@ -79,14 +80,14 @@ class mjCComposite { void MakeSkin2(mjCModel* model, mjtNum inflate); void MakeSkin2Subgrid(mjCModel* model, mjtNum inflate); - void MakeClothBones(mjCModel* model, mjCSkin* skin); - void MakeClothBonesSubgrid(mjCModel* model, mjCSkin* skin); - void MakeCableBones(mjCModel* model, mjCSkin* skin); - void MakeCableBonesSubgrid(mjCModel* model, mjCSkin* skin); + void MakeClothBones(mjCModel* model, mjmSkin* skin); + void MakeClothBonesSubgrid(mjCModel* model, mjmSkin* skin); + void MakeCableBones(mjCModel* model, mjmSkin* skin); + void MakeCableBonesSubgrid(mjCModel* model, mjmSkin* skin); void MakeSkin3(mjCModel* model); - void MakeSkin3Box(mjCSkin* skin, int c0, int c1, int side, int& vcnt, const char* format); - void MakeSkin3Smooth(mjCSkin* skin, int c0, int c1, int side, + void MakeSkin3Box(mjmSkin* skin, int c0, int c1, int side, int& vcnt, const char* format); + void MakeSkin3Smooth(mjmSkin* skin, int c0, int c1, int side, const std::map& vmap, const char* format); void BoxProject(double* pos); @@ -138,6 +139,16 @@ class mjCComposite { private: mjmBody* AddRopeBody(mjCModel* model, mjmBody* body, int ix, int ix1); mjmBody* AddCableBody(mjCModel* model, mjmBody* body, int ix, mjtNum normal[3], mjtNum prev_quat[4]); + + // temporary skin vectors + void CopyIntoSkin(mjmSkin* skin); + std::vector face; + std::vector vert; + std::vector bindpos; + std::vector bindquat; + std::vector texcoord; + std::vector> vertid; + std::vector> vertweight; }; #endif // MUJOCO_SRC_USER_USER_COMPOSITE_H_ diff --git a/src/user/user_flexcomp.cc b/src/user/user_flexcomp.cc index 1f585a88..06bda286 100644 --- a/src/user/user_flexcomp.cc +++ b/src/user/user_flexcomp.cc @@ -385,7 +385,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz // rigid: set parent name, nothing else to do if (rigid) { - mjm_addToStringVec(pf->vertbody, mjm_getString(body->name)); + mjm_appendString(pf->vertbody, mjm_getString(body->name)); return true; } @@ -402,7 +402,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz // pinned: parent body if (pinned[i]) { - mjm_addToStringVec(pf->vertbody, mjm_getString(body->name)); + mjm_appendString(pf->vertbody, mjm_getString(body->name)); // add plugin if (plugin_instance) { @@ -459,7 +459,7 @@ bool mjCFlexcomp::Make(mjCModel* model, mjmBody* body, char* error, int error_sz char txt[100]; mju::sprintf_arr(txt, "%s_%d", name.c_str(), i); mjm_setString(pb->name, txt); - mjm_addToStringVec(pf->vertbody, mjm_getString(pb->name)); + mjm_appendString(pf->vertbody, mjm_getString(pb->name)); // clear flex vertex coordinates if allocated if (!centered) { diff --git a/src/user/user_init.cc b/src/user/user_init.cc index ff284e3b..0b91bfac 100644 --- a/src/user/user_init.cc +++ b/src/user/user_init.cc @@ -210,6 +210,17 @@ void mjm_defaultHField(mjmHField& hfield) { +// default skin attributes +void mjm_defaultSkin(mjmSkin& skin) { + memset(&skin, 0, sizeof(mjmSkin)); + skin.rgba[0] = skin.rgba[1] = skin.rgba[2] = 0.5f; + skin.rgba[3] = 1.0f; + skin.inflate = 0; + skin.group = 0; +} + + + // default texture attributes void mjm_defaultTexture(mjmTexture& texture) { memset(&texture, 0, sizeof(mjmTexture)); diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index 0d7f6b93..7c7d9488 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -1829,45 +1829,92 @@ void mjCMesh::MakeCenter(void) { // constructor mjCSkin::mjCSkin(mjCModel* _model) { + mjm_defaultSkin(spec); + // set model pointer model = _model; // clear data - file.clear(); - material_.clear(); - rgba[0] = rgba[1] = rgba[2] = 0.5f; - rgba[3] = 1.0f; - inflate = 0; - group = 0; + spec_file_.clear(); + spec_material_.clear(); + spec_vert_.clear(); + spec_texcoord_.clear(); + spec_face_.clear(); + spec_bodyname_.clear(); + spec_bindpos_.clear(); + spec_bindquat_.clear(); + spec_vertid_.clear(); + spec_vertweight_.clear(); - vert.clear(); - texcoord.clear(); - face.clear(); - - bodyname.clear(); - bindpos.clear(); - bindquat.clear(); - vertid.clear(); - vertweight.clear(); bodyid.clear(); - matid = -1; + + // point to local (needs to be after defaults) + PointToLocal(); + + // in case this camera is not compiled + CopyFromSpec(); +} + + + +void mjCSkin::PointToLocal() { + spec.element = (mjElement)this; + spec.name = (mjString)&name; + spec.classname = (mjString)&classname; + spec.file = (mjString)&spec_file_; + spec.material = (mjString)&spec_material_; + spec.vert = (mjFloatVec)&spec_vert_; + spec.texcoord = (mjFloatVec)&spec_texcoord_; + spec.face = (mjIntVec)&spec_face_; + spec.bodyname = (mjStringVec)&spec_bodyname_; + spec.bindpos = (mjFloatVec)&spec_bindpos_; + spec.bindquat = (mjFloatVec)&spec_bindquat_; + spec.vertid = (mjIntVecVec)&spec_vertid_; + spec.vertweight = (mjFloatVecVec)&spec_vertweight_; + spec.info = (mjString)&info; +} + + + +void mjCSkin::CopyFromSpec() { + *static_cast(this) = spec; + file_ = spec_file_; + material_ = spec_material_; + vert_ = spec_vert_; + texcoord_ = spec_texcoord_; + face_ = spec_face_; + bodyname_ = spec_bodyname_; + bindpos_ = spec_bindpos_; + bindquat_ = spec_bindquat_; + vertid_ = spec_vertid_; + vertweight_ = spec_vertweight_; + file = (mjString)&spec_file_; + material = (mjString)&spec_material_; + vert = (mjFloatVec)&spec_vert_; + texcoord = (mjFloatVec)&spec_texcoord_; + face = (mjIntVec)&spec_face_; + bodyname = (mjStringVec)&spec_bodyname_; + bindpos = (mjFloatVec)&spec_bindpos_; + bindquat = (mjFloatVec)&spec_bindquat_; + vertid = (mjIntVecVec)&spec_vertid_; + vertweight = (mjFloatVecVec)&spec_vertweight_; } // destructor mjCSkin::~mjCSkin() { - file.clear(); - material_.clear(); - vert.clear(); - texcoord.clear(); - face.clear(); - bodyname.clear(); - bindpos.clear(); - bindquat.clear(); - vertid.clear(); - vertweight.clear(); + spec_file_.clear(); + spec_material_.clear(); + spec_vert_.clear(); + spec_texcoord_.clear(); + spec_face_.clear(); + spec_bodyname_.clear(); + spec_bindpos_.clear(); + spec_bindquat_.clear(); + spec_vertid_.clear(); + spec_vertweight_.clear(); bodyid.clear(); } @@ -1875,33 +1922,35 @@ mjCSkin::~mjCSkin() { // compiler void mjCSkin::Compile(const mjVFS* vfs) { + CopyFromSpec(); + // load file - if (!file.empty()) { + if (!file_.empty()) { // make sure data is not present - if (!vert.empty() || - !texcoord.empty() || - !face.empty() || - !bodyname.empty() || - !bindpos.empty() || - !bindquat.empty() || - !vertid.empty() || - !vertweight.empty() || + if (!vert_.empty() || + !texcoord_.empty() || + !face_.empty() || + !bodyname_.empty() || + !bindpos_.empty() || + !bindquat_.empty() || + !vertid_.empty() || + !vertweight_.empty() || !bodyid.empty()) { - throw mjCError(this, "Data already exists, trying to load from skin file: %s", file.c_str()); + throw mjCError(this, "Data already exists, trying to load from skin file: %s", file_.c_str()); } // remove path from file if necessary if (model->strippath) { - file = mjuu_strippath(file); + file_ = mjuu_strippath(file_); } // load SKN - string ext = mjuu_getext(file); + string ext = mjuu_getext(file_); if (strcasecmp(ext.c_str(), ".skn")) { - throw mjCError(this, "Unknown skin file type: %s", file.c_str()); + 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 { @@ -1914,48 +1963,48 @@ void mjCSkin::Compile(const mjVFS* vfs) { } // make sure all data is present - if (vert.empty() || - face.empty() || - bodyname.empty() || - bindpos.empty() || - bindquat.empty() || - vertid.empty() || - vertweight.empty()) { + if (vert_.empty() || + face_.empty() || + bodyname_.empty() || + bindpos_.empty() || + bindquat_.empty() || + vertid_.empty() || + vertweight_.empty()) { throw mjCError(this, "Missing data in skin"); } // check mesh sizes - if (vert.size()%3) { + if (vert_.size()%3) { throw mjCError(this, "Vertex data must be multiple of 3"); } - if (!texcoord.empty() && texcoord.size()!=2*vert.size()/3) { + if (!texcoord_.empty() && texcoord_.size()!=2*vert_.size()/3) { throw mjCError(this, "Vertex and texcoord data incompatible size"); } - if (face.size()%3) { + if (face_.size()%3) { throw mjCError(this, "Face data must be multiple of 3"); } // check bone sizes - size_t nbone = bodyname.size(); - if (bindpos.size()!=3*nbone) { + size_t nbone = bodyname_.size(); + if (bindpos_.size()!=3*nbone) { throw mjCError(this, "Unexpected bindpos size in skin"); } - if (bindquat.size()!=4*nbone) { + if (bindquat_.size()!=4*nbone) { throw mjCError(this, "Unexpected bindquat size in skin"); } - if (vertid.size()!=nbone) { + if (vertid_.size()!=nbone) { throw mjCError(this, "Unexpected vertid size in skin"); } - if (vertweight.size()!=nbone) { + if (vertweight_.size()!=nbone) { throw mjCError(this, "Unexpected vertweight size in skin"); } // resolve body names bodyid.resize(nbone); for (int i=0; iFindObject(mjOBJ_BODY, bodyname[i]); + mjCBase* pbody = model->FindObject(mjOBJ_BODY, bodyname_[i]); if (!pbody) { - throw mjCError(this, "unknown body '%s' in skin", bodyname[i].c_str()); + throw mjCError(this, "unknown body '%s' in skin", bodyname_[i].c_str()); } bodyid[i] = pbody->id; } @@ -1970,28 +2019,28 @@ void mjCSkin::Compile(const mjVFS* vfs) { // set total vertex weights to 0 vector vw; - size_t nvert = vert.size()/3; + size_t nvert = vert_.size()/3; vw.resize(nvert); fill(vw.begin(), vw.end(), 0.0f); // accumulate vertex weights from all bones for (int i=0; i=nvert) { throw mjCError(this, "vertid %d out of range in skin", NULL, jj); } // accumulate - vw[jj] += vertweight[i][j]; + vw[jj] += vertweight_[i][j]; } } @@ -2004,25 +2053,25 @@ void mjCSkin::Compile(const mjVFS* vfs) { // normalize vertex weights for (int i=0; ivert.size()/3; - nskintexvert += skins[i]->texcoord.size()/2; - nskinface += skins[i]->face.size()/3; + nskinvert += skins[i]->get_vert().size()/3; + nskintexvert += skins[i]->get_texcoord().size()/2; + nskinface += skins[i]->get_face().size()/3; nskinbone += skins[i]->bodyid.size(); for (int j=0; jbodyid.size(); j++) { - nskinbonevert += skins[i]->vertid[j].size(); + nskinbonevert += skins[i]->get_vertid()[j].size(); } } @@ -2094,25 +2094,25 @@ void mjCModel::CopyObjects(mjModel* m) { copyvec(m->skin_rgba+4*i, psk->rgba, 4); m->skin_inflate[i] = psk->inflate; m->skin_vertadr[i] = vert_adr; - m->skin_vertnum[i] = psk->vert.size()/3; - m->skin_texcoordadr[i] = (!psk->texcoord.empty() ? texcoord_adr : -1); + m->skin_vertnum[i] = psk->get_vert().size()/3; + m->skin_texcoordadr[i] = (!psk->get_texcoord().empty() ? texcoord_adr : -1); m->skin_faceadr[i] = face_adr; - m->skin_facenum[i] = psk->face.size()/3; + m->skin_facenum[i] = psk->get_face().size()/3; m->skin_boneadr[i] = bone_adr; m->skin_bonenum[i] = psk->bodyid.size(); // copy mesh data - memcpy(m->skin_vert + 3*vert_adr, psk->vert.data(), psk->vert.size()*sizeof(float)); - if (!psk->texcoord.empty()) - memcpy(m->skin_texcoord + 2*texcoord_adr, psk->texcoord.data(), - psk->texcoord.size()*sizeof(float)); - memcpy(m->skin_face + 3*face_adr, psk->face.data(), psk->face.size()*sizeof(int)); + memcpy(m->skin_vert + 3*vert_adr, psk->get_vert().data(), psk->get_vert().size()*sizeof(float)); + if (!psk->get_texcoord().empty()) + memcpy(m->skin_texcoord + 2*texcoord_adr, psk->get_texcoord().data(), + psk->get_texcoord().size()*sizeof(float)); + memcpy(m->skin_face + 3*face_adr, psk->get_face().data(), psk->get_face().size()*sizeof(int)); // copy bind poses and body ids - memcpy(m->skin_bonebindpos+3*bone_adr, psk->bindpos.data(), - psk->bindpos.size()*sizeof(float)); - memcpy(m->skin_bonebindquat+4*bone_adr, psk->bindquat.data(), - psk->bindquat.size()*sizeof(float)); + memcpy(m->skin_bonebindpos+3*bone_adr, psk->get_bindpos().data(), + psk->get_bindpos().size()*sizeof(float)); + memcpy(m->skin_bonebindquat+4*bone_adr, psk->get_bindquat().data(), + psk->get_bindquat().size()*sizeof(float)); memcpy(m->skin_bonebodyid+bone_adr, psk->bodyid.data(), psk->bodyid.size()*sizeof(int)); @@ -2120,13 +2120,13 @@ void mjCModel::CopyObjects(mjModel* m) { for (int j=0; jskin_bonenum[i]; j++) { // set fields m->skin_bonevertadr[bone_adr+j] = bonevert_adr; - m->skin_bonevertnum[bone_adr+j] = (int)psk->vertid[j].size(); + m->skin_bonevertnum[bone_adr+j] = (int)psk->get_vertid()[j].size(); // copy data - memcpy(m->skin_bonevertid+bonevert_adr, psk->vertid[j].data(), - psk->vertid[j].size()*sizeof(int)); - memcpy(m->skin_bonevertweight+bonevert_adr, psk->vertweight[j].data(), - psk->vertid[j].size()*sizeof(float)); + memcpy(m->skin_bonevertid+bonevert_adr, psk->get_vertid()[j].data(), + psk->get_vertid()[j].size()*sizeof(int)); + memcpy(m->skin_bonevertweight+bonevert_adr, psk->get_vertweight()[j].data(), + psk->get_vertid()[j].size()*sizeof(float)); // advance counter bonevert_adr += m->skin_bonevertnum[bone_adr+j]; @@ -2134,7 +2134,7 @@ void mjCModel::CopyObjects(mjModel* m) { // advance mesh and bone counters vert_adr += m->skin_vertnum[i]; - texcoord_adr += psk->texcoord.size()/2; + texcoord_adr += psk->get_texcoord().size()/2; face_adr += m->skin_facenum[i]; bone_adr += m->skin_bonenum[i]; } diff --git a/src/user/user_objects.cc b/src/user/user_objects.cc index e25b0abf..cf19599d 100644 --- a/src/user/user_objects.cc +++ b/src/user/user_objects.cc @@ -3677,7 +3677,6 @@ mjCEquality::mjCEquality(mjCModel* _model, mjCDef* _def) { model = _model; def = (_def ? _def : (_model ? _model->defaults[0] : 0)); - // point to local (needs to be after defaults) PointToLocal(); diff --git a/src/user/user_objects.h b/src/user/user_objects.h index 545d3218..feaec000 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -771,32 +771,30 @@ class mjCMesh: public mjCBase, private mjmMesh { //------------------------- class mjCSkin ---------------------------------------------------------- // Describes a skin -class mjCSkin: public mjCBase { +class mjCSkin: public mjCBase, private mjmSkin { friend class mjCModel; friend class mjXWriter; public: - std::string get_file() const { return file; } - void set_material(std::string _material) { material_ = _material; } + mjmSkin spec; + using mjCBase::name; + using mjCBase::classname; + using mjCBase::info; + + std::string get_file() const { return file_; } std::string& get_material() { return material_; } + std::vector& get_vert() { return vert_; } + std::vector& get_texcoord() { return texcoord_; } + std::vector& get_face() { return face_; } + std::vector& get_bodyname() { return bodyname_; } + std::vector& get_bindpos() { return bindpos_; } + std::vector& get_bindquat() { return bindquat_; } + std::vector>& get_vertid() { return vertid_; } + std::vector>& get_vertweight() { return vertweight_; } void del_material() { material_.clear(); } - std::string file; // skin file - float rgba[4]; // rgba when material is omitted - float inflate; // inflate in normal direction - int group; // group for visualization - - // mesh - std::vector vert; // vertex positions - std::vector texcoord; // texture coordinates - std::vector face; // faces - - // skin - std::vector bodyname; // body names - std::vector bindpos; // bind pos - std::vector bindquat; // bind quat - std::vector> vertid; // vertex ids - std::vector> vertweight; // vertex weights + void CopyFromSpec(); + void PointToLocal(); private: mjCSkin(mjCModel* = 0); // constructor @@ -804,7 +802,29 @@ class mjCSkin: public mjCBase { void Compile(const mjVFS* vfs); // compiler void LoadSKN(mjResource* resource); // load skin in SKN BIN format - std::string material_; // name of material used for rendering + // variable size attributes + std::string file_; + std::string material_; + std::vector vert_; + std::vector texcoord_; + std::vector face_; + std::vector bodyname_; + std::vector bindpos_; + std::vector bindquat_; + std::vector> vertid_; + std::vector> vertweight_; + + std::string spec_file_; + std::string spec_material_; + std::vector spec_vert_; + std::vector spec_texcoord_; + std::vector spec_face_; + std::vector spec_bodyname_; + std::vector spec_bindpos_; + std::vector spec_bindquat_; + std::vector> spec_vertid_; + std::vector> spec_vertweight_; + int matid; // material id std::vector bodyid; // body ids }; diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index 39acdb18..3557a295 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -1416,14 +1416,20 @@ void mjXReader::OneMesh(XMLElement* elem, mjmMesh* pmesh) { // skin element parser -void mjXReader::OneSkin(XMLElement* elem, mjCSkin* pskin) { - string text; +void mjXReader::OneSkin(XMLElement* elem, mjmSkin* pskin) { + string text, name, file, material; float data[4]; // read attributes - ReadAttrTxt(elem, "name", pskin->name); - ReadAttrTxt(elem, "file", pskin->file); - ReadAttrTxt(elem, "material", pskin->get_material()); + if (ReadAttrTxt(elem, "name", name)) { + mjm_setString(pskin->name, name.c_str()); + } + if (ReadAttrTxt(elem, "file", file)) { + mjm_setString(pskin->file, file.c_str()); + } + if (ReadAttrTxt(elem, "material", material)) { + mjm_setString(pskin->material, material.c_str()); + } ReadAttrInt(elem, "group", &pskin->group); if (pskin->group<0 || pskin->group>=mjNGROUP) { throw mjXError(elem, "skin group must be between 0 and 5"); @@ -1432,51 +1438,72 @@ void mjXReader::OneSkin(XMLElement* elem, mjCSkin* pskin) { ReadAttr(elem, "inflate", 1, &pskin->inflate, text); // read vertex data - if (ReadAttrTxt(elem, "vertex", text)) String2Vector(text, pskin->vert); + if (ReadAttrTxt(elem, "vertex", text)) { + std::vector vert; + String2Vector(text, vert); + mjm_setFloat(pskin->vert, vert.data(), vert.size()); + } // read texcoord data - if (ReadAttrTxt(elem, "texcoord", text)) String2Vector(text, pskin->texcoord); + if (ReadAttrTxt(elem, "texcoord", text)) { + std::vector texcoord; + String2Vector(text, texcoord); + mjm_setFloat(pskin->texcoord, texcoord.data(), texcoord.size()); + } // read user face data - if (ReadAttrTxt(elem, "face", text)) String2Vector(text, pskin->face); + if (ReadAttrTxt(elem, "face", text)) { + std::vector face; + String2Vector(text, face); + mjm_setInt(pskin->face, face.data(), face.size()); + } // read bones XMLElement* bone = FirstChildElement(elem, "bone"); + std::vector bindpos; + std::vector bindquat; + while (bone) { // read body ReadAttrTxt(bone, "body", text, true); - pskin->bodyname.push_back(text); + mjm_appendString(pskin->bodyname, text.c_str()); // read bindpos ReadAttr(bone, "bindpos", 3, data, text, true); - pskin->bindpos.push_back(data[0]); - pskin->bindpos.push_back(data[1]); - pskin->bindpos.push_back(data[2]); + bindpos.push_back(data[0]); + bindpos.push_back(data[1]); + bindpos.push_back(data[2]); // read bindquat ReadAttr(bone, "bindquat", 4, data, text, true); - pskin->bindquat.push_back(data[0]); - pskin->bindquat.push_back(data[1]); - pskin->bindquat.push_back(data[2]); - pskin->bindquat.push_back(data[3]); + bindquat.push_back(data[0]); + bindquat.push_back(data[1]); + bindquat.push_back(data[2]); + bindquat.push_back(data[3]); // read vertid vector tempid; ReadAttrTxt(bone, "vertid", text, true); String2Vector(text, tempid); - pskin->vertid.push_back(tempid); + mjm_appendIntVec(pskin->vertid, tempid.data(), tempid.size()); // read vertweight vector tempweight; ReadAttrTxt(bone, "vertweight", text, true); String2Vector(text, tempweight); - pskin->vertweight.push_back(tempweight); + mjm_appendFloatVec(pskin->vertweight, tempweight.data(), tempweight.size()); // advance to next bone bone = NextSiblingElement(bone, "bone"); } - GetXMLPos(elem, pskin); + // set bind vectors + mjm_setFloat(pskin->bindpos, bindpos.data(), bindpos.size()); + mjm_setFloat(pskin->bindquat, bindquat.data(), bindquat.size()); + + // write error info + mjm_setString(pskin->info, + std::string("line = " + std::to_string(elem->GetLineNum()) + ", column = -1").c_str()); } @@ -3129,7 +3156,7 @@ void mjXReader::Asset(XMLElement* section) { // skin sub-element... deprecate ??? else if (name=="skin") { // create skin and parse - mjCSkin* pskin = model->AddSkin(); + mjmSkin* pskin = mjm_addSkin(model); OneSkin(elem, pskin); } @@ -3498,7 +3525,7 @@ void mjXReader::Deformable(XMLElement* section) { // skin sub-element else if (name=="skin") { // create skin and parse - mjCSkin* pskin = model->AddSkin(); + mjmSkin* pskin = mjm_addSkin(model); OneSkin(elem, pskin); } diff --git a/src/xml/xml_native_reader.h b/src/xml/xml_native_reader.h index 69682a35..f9bf0fde 100644 --- a/src/xml/xml_native_reader.h +++ b/src/xml/xml_native_reader.h @@ -60,7 +60,7 @@ class mjXReader : public mjXBase { // 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, mjCSkin* pskin); + 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); diff --git a/src/xml/xml_native_writer.cc b/src/xml/xml_native_writer.cc index 16a0a59a..add60d87 100644 --- a/src/xml/xml_native_writer.cc +++ b/src/xml/xml_native_writer.cc @@ -205,44 +205,44 @@ void mjXWriter::OneSkin(XMLElement* elem, mjCSkin* pskin) { // write attributes WriteAttrTxt(elem, "name", pskin->name); - WriteAttrTxt(elem, "file", pskin->file); + WriteAttrTxt(elem, "file", pskin->get_file()); WriteAttrTxt(elem, "material", pskin->get_material()); WriteAttrInt(elem, "group", pskin->group, 0); WriteAttr(elem, "rgba", 4, pskin->rgba, mydef.geom.rgba); WriteAttr(elem, "inflate", 1, &pskin->inflate, &zero); // write data if no file - if (pskin->file.empty()) { + if (pskin->get_file().empty()) { // mesh vert - Vector2String(text, pskin->vert); + Vector2String(text, pskin->get_vert()); WriteAttrTxt(elem, "vertex", text); // mesh texcoord - if (!pskin->texcoord.empty()) { - Vector2String(text, pskin->texcoord); + if (!pskin->get_texcoord().empty()) { + Vector2String(text, pskin->get_texcoord()); WriteAttrTxt(elem, "texcoord", text); } // mesh face - Vector2String(text, pskin->face); + Vector2String(text, pskin->get_face()); WriteAttrTxt(elem, "face", text); // bones - for (size_t i=0; ibodyname.size(); i++) { + for (size_t i=0; iget_bodyname().size(); i++) { // make bone XMLElement* bone = InsertEnd(elem, "bone"); // write attributes - WriteAttrTxt(bone, "body", pskin->bodyname[i]); - WriteAttr(bone, "bindpos", 3, pskin->bindpos.data()+3*i); - WriteAttr(bone, "bindquat", 4, pskin->bindquat.data()+4*i); + WriteAttrTxt(bone, "body", pskin->get_bodyname()[i]); + WriteAttr(bone, "bindpos", 3, pskin->get_bindpos().data()+3*i); + WriteAttr(bone, "bindquat", 4, pskin->get_bindquat().data()+4*i); // write vertid - Vector2String(text, pskin->vertid[i]); + Vector2String(text, pskin->get_vertid()[i]); WriteAttrTxt(bone, "vertid", text); // write vertweight - Vector2String(text, pskin->vertweight[i]); + Vector2String(text, pskin->get_vertweight()[i]); WriteAttrTxt(bone, "vertweight", text); } }