diff --git a/doc/includes/references.h b/doc/includes/references.h index 9b169ab3..f4aedde9 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -1182,20 +1182,23 @@ struct mjModel_ { int* skin_bonebodyid; // body id of each bone (nskinbone x 1) int* skin_bonevertid; // mesh ids of vertices in each bone (nskinbonevert x 1) float* skin_bonevertweight; // weights of vertices in each bone (nskinbonevert x 1) + int* skin_pathadr; // address of asset path for skin; -1: none (nskin x 1) // height fields - mjtNum* hfield_size; // (x, y, z_top, z_bottom) (nhfield x 4) - int* hfield_nrow; // number of rows in grid (nhfield x 1) - int* hfield_ncol; // number of columns in grid (nhfield x 1) - int* hfield_adr; // address in hfield_data (nhfield x 1) - float* hfield_data; // elevation data (nhfielddata x 1) + mjtNum* hfield_size; // (x, y, z_top, z_bottom) (nhfield x 4) + int* hfield_nrow; // number of rows in grid (nhfield x 1) + int* hfield_ncol; // number of columns in grid (nhfield x 1) + int* hfield_adr; // address in hfield_data (nhfield x 1) + float* hfield_data; // elevation data (nhfielddata x 1) + int* hfield_pathadr; // address of asset path for hfield; -1: none (nhfield x 1) // textures - int* tex_type; // texture type (mjtTexture) (ntex x 1) - int* tex_height; // number of rows in texture image (ntex x 1) - int* tex_width; // number of columns in texture image (ntex x 1) - int* tex_adr; // address in rgb (ntex x 1) - mjtByte* tex_rgb; // rgb (alpha = 1) (ntexdata x 1) + int* tex_type; // texture type (mjtTexture) (ntex x 1) + int* tex_height; // number of rows in texture image (ntex x 1) + int* tex_width; // number of columns in texture image (ntex x 1) + int* tex_adr; // address in rgb (ntex x 1) + mjtByte* tex_rgb; // rgb (alpha = 1) (ntexdata x 1) + int* tex_pathadr; // address of asset path for texture; -1: none (ntex x 1) // materials int* mat_texid; // texture id; -1: none (nmat x 1) @@ -2248,6 +2251,8 @@ struct mjvSceneState_ { mjtNum* flex_radius; float* flex_rgba; + int* hfield_pathadr; + int* mesh_bvhadr; int* mesh_bvhnum; int* mesh_texcoordadr; @@ -2274,6 +2279,9 @@ struct mjvSceneState_ { int* skin_bonebodyid; int* skin_bonevertid; float* skin_bonevertweight; + int* skin_pathadr; + + int* tex_pathadr; int* mat_texid; mjtByte* mat_texuniform; diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index b9f7b8e9..663e191f 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -895,20 +895,23 @@ struct mjModel_ { int* skin_bonebodyid; // body id of each bone (nskinbone x 1) int* skin_bonevertid; // mesh ids of vertices in each bone (nskinbonevert x 1) float* skin_bonevertweight; // weights of vertices in each bone (nskinbonevert x 1) + int* skin_pathadr; // address of asset path for skin; -1: none (nskin x 1) // height fields - mjtNum* hfield_size; // (x, y, z_top, z_bottom) (nhfield x 4) - int* hfield_nrow; // number of rows in grid (nhfield x 1) - int* hfield_ncol; // number of columns in grid (nhfield x 1) - int* hfield_adr; // address in hfield_data (nhfield x 1) - float* hfield_data; // elevation data (nhfielddata x 1) + mjtNum* hfield_size; // (x, y, z_top, z_bottom) (nhfield x 4) + int* hfield_nrow; // number of rows in grid (nhfield x 1) + int* hfield_ncol; // number of columns in grid (nhfield x 1) + int* hfield_adr; // address in hfield_data (nhfield x 1) + float* hfield_data; // elevation data (nhfielddata x 1) + int* hfield_pathadr; // address of asset path for hfield; -1: none (nhfield x 1) // textures - int* tex_type; // texture type (mjtTexture) (ntex x 1) - int* tex_height; // number of rows in texture image (ntex x 1) - int* tex_width; // number of columns in texture image (ntex x 1) - int* tex_adr; // address in rgb (ntex x 1) - mjtByte* tex_rgb; // rgb (alpha = 1) (ntexdata x 1) + int* tex_type; // texture type (mjtTexture) (ntex x 1) + int* tex_height; // number of rows in texture image (ntex x 1) + int* tex_width; // number of columns in texture image (ntex x 1) + int* tex_adr; // address in rgb (ntex x 1) + mjtByte* tex_rgb; // rgb (alpha = 1) (ntexdata x 1) + int* tex_pathadr; // address of asset path for texture; -1: none (ntex x 1) // materials int* mat_texid; // texture id; -1: none (nmat x 1) diff --git a/include/mujoco/mjvisualize.h b/include/mujoco/mjvisualize.h index e4114af8..d693df9c 100644 --- a/include/mujoco/mjvisualize.h +++ b/include/mujoco/mjvisualize.h @@ -520,6 +520,8 @@ struct mjvSceneState_ { mjtNum* flex_radius; float* flex_rgba; + int* hfield_pathadr; + int* mesh_bvhadr; int* mesh_bvhnum; int* mesh_texcoordadr; @@ -546,6 +548,9 @@ struct mjvSceneState_ { int* skin_bonebodyid; int* skin_bonevertid; float* skin_bonevertweight; + int* skin_pathadr; + + int* tex_pathadr; int* mat_texid; mjtByte* mat_texuniform; diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index be5a2b53..f4088314 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -395,16 +395,19 @@ XMJV( int, skin_bonebodyid, nskinbone, 1 ) \ XMJV( int, skin_bonevertid, nskinbonevert, 1 ) \ XMJV( float, skin_bonevertweight, nskinbonevert, 1 ) \ + XMJV( int, skin_pathadr, nskin, 1 ) \ X ( mjtNum, hfield_size, nhfield, 4 ) \ X ( int, hfield_nrow, nhfield, 1 ) \ X ( int, hfield_ncol, nhfield, 1 ) \ X ( int, hfield_adr, nhfield, 1 ) \ X ( float, hfield_data, nhfielddata, 1 ) \ + XMJV( int, hfield_pathadr, nhfield, 1 ) \ X ( int, tex_type, ntex, 1 ) \ X ( int, tex_height, ntex, 1 ) \ X ( int, tex_width, ntex, 1 ) \ X ( int, tex_adr, ntex, 1 ) \ X ( mjtByte, tex_rgb, ntexdata, 1 ) \ + XMJV( int, tex_pathadr, ntex, 1 ) \ XMJV( int, mat_texid, nmat, 1 ) \ XMJV( mjtByte, mat_texuniform, nmat, 1 ) \ XMJV( float, mat_texrepeat, nmat, 2 ) \ diff --git a/introspect/structs.py b/introspect/structs.py index 088a9c2c..a1fa3159 100644 --- a/introspect/structs.py +++ b/introspect/structs.py @@ -2787,75 +2787,96 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='weights of vertices in each bone (nskinbonevert x 1)', # pylint: disable=line-too-long ), + StructFieldDecl( + name='skin_pathadr', + type=PointerType( + inner_type=ValueType(name='int'), + ), + doc='address of asset path for skin; -1: none (nskin x 1)', + ), StructFieldDecl( name='hfield_size', type=PointerType( inner_type=ValueType(name='mjtNum'), ), - doc='(x, y, z_top, z_bottom) (nhfield x 4)', + doc='(x, y, z_top, z_bottom) (nhfield x 4)', ), StructFieldDecl( name='hfield_nrow', type=PointerType( inner_type=ValueType(name='int'), ), - doc='number of rows in grid (nhfield x 1)', + doc='number of rows in grid (nhfield x 1)', ), StructFieldDecl( name='hfield_ncol', type=PointerType( inner_type=ValueType(name='int'), ), - doc='number of columns in grid (nhfield x 1)', + doc='number of columns in grid (nhfield x 1)', ), StructFieldDecl( name='hfield_adr', type=PointerType( inner_type=ValueType(name='int'), ), - doc='address in hfield_data (nhfield x 1)', + doc='address in hfield_data (nhfield x 1)', ), StructFieldDecl( name='hfield_data', type=PointerType( inner_type=ValueType(name='float'), ), - doc='elevation data (nhfielddata x 1)', # pylint: disable=line-too-long + doc='elevation data (nhfielddata x 1)', # pylint: disable=line-too-long + ), + StructFieldDecl( + name='hfield_pathadr', + type=PointerType( + inner_type=ValueType(name='int'), + ), + doc='address of asset path for hfield; -1: none (nhfield x 1)', ), StructFieldDecl( name='tex_type', type=PointerType( inner_type=ValueType(name='int'), ), - doc='texture type (mjtTexture) (ntex x 1)', + doc='texture type (mjtTexture) (ntex x 1)', ), StructFieldDecl( name='tex_height', type=PointerType( inner_type=ValueType(name='int'), ), - doc='number of rows in texture image (ntex x 1)', + doc='number of rows in texture image (ntex x 1)', ), StructFieldDecl( name='tex_width', type=PointerType( inner_type=ValueType(name='int'), ), - doc='number of columns in texture image (ntex x 1)', + doc='number of columns in texture image (ntex x 1)', ), StructFieldDecl( name='tex_adr', type=PointerType( inner_type=ValueType(name='int'), ), - doc='address in rgb (ntex x 1)', + doc='address in rgb (ntex x 1)', ), StructFieldDecl( name='tex_rgb', type=PointerType( inner_type=ValueType(name='mjtByte'), ), - doc='rgb (alpha = 1) (ntexdata x 1)', + doc='rgb (alpha = 1) (ntexdata x 1)', # pylint: disable=line-too-long + ), + StructFieldDecl( + name='tex_pathadr', + type=PointerType( + inner_type=ValueType(name='int'), + ), + doc='address of asset path for texture; -1: none (ntex x 1)', ), StructFieldDecl( name='mat_texid', @@ -6825,6 +6846,13 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='', ), + StructFieldDecl( + name='hfield_pathadr', + type=PointerType( + inner_type=ValueType(name='int'), + ), + doc='', + ), StructFieldDecl( name='mesh_bvhadr', type=PointerType( @@ -7000,6 +7028,20 @@ STRUCTS: Mapping[str, StructDecl] = dict([ ), doc='', ), + StructFieldDecl( + name='skin_pathadr', + type=PointerType( + inner_type=ValueType(name='int'), + ), + doc='', + ), + StructFieldDecl( + name='tex_pathadr', + type=PointerType( + inner_type=ValueType(name='int'), + ), + doc='', + ), StructFieldDecl( name='mat_texid', type=PointerType( diff --git a/src/engine/engine_io.c b/src/engine/engine_io.c index 4b1ae161..48a1bd8c 100644 --- a/src/engine/engine_io.c +++ b/src/engine/engine_io.c @@ -1957,7 +1957,10 @@ const char* mj_validateReferences(const mjModel* m) { X(name_textadr, ntext, nnames , 0 ) \ X(name_tupleadr, ntuple, nnames , 0 ) \ X(name_keyadr, nkey, nnames , 0 ) \ - X(mesh_pathadr, nmesh, npaths , 0 ) + X(hfield_pathadr, nhfield, npaths , 0 ) \ + X(mesh_pathadr, nmesh, npaths , 0 ) \ + X(skin_pathadr, nskin, npaths , 0 ) \ + X(tex_pathadr, ntex, npaths , 0 ) #define X(adrarray, nadrs, ntarget, numarray) { \ int *nums = (numarray); \ diff --git a/src/user/user_model.cc b/src/user/user_model.cc index b3215aaa..693287fa 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -906,6 +906,18 @@ void mjCModel::SetDefaultNames(void) { const int nPOS[4] = {7, 4, 1, 1}; const int nVEL[4] = {6, 3, 1, 1}; +template +static size_t getpathslength(std::vector list) { + size_t result = 0; + for (const auto& element : list) { + if (!element->get_file().empty()) { + result += element->get_file().length() + 1; + } + } + + return result; +} + // set array sizes void mjCModel::SetSizes(void) { // set from object list sizes @@ -1038,18 +1050,16 @@ void mjCModel::SetSizes(void) { // npaths npaths = 0; - for (int i=0; ifile().empty()) { - continue; - } - npaths += (int)meshes[i]->file().length() + 1; - } + npaths += getpathslength(hfields); + npaths += getpathslength(meshes); + npaths += getpathslength(skins); + npaths += getpathslength(textures); if (npaths == 0) { npaths = 1; } // nemax - for (int i=0; itype==mjEQ_CONNECT) { nemax += 3; } else if (equalities[i]->type==mjEQ_WELD) { @@ -1057,6 +1067,7 @@ void mjCModel::SetSizes(void) { } else { nemax += 1; } + } } @@ -1243,6 +1254,25 @@ void mjCModel::LengthRange(mjModel* m, mjData* data) { } +// Add items to a generic list. This enables the names and paths to be stored. +// input - string to add +// adr - current address in the list +// output_adr_field - the field where the address should be stored (name_meshadr) +// output_buffer - the field where the data should be stored (i.e. names or paths) +static int addtolist(const std::string& input, int adr, int* output_adr_field, char* output_buffer) { + *output_adr_field = adr; + + // copy input + memcpy(output_buffer+adr, input.c_str(), input.size()); + adr += (int)input.size(); + + // append 0 + output_buffer[adr] = 0; + adr++; + + return adr; +} + // process names from one list: concatenate, compute addresses template static int namelist(vector& list, int adr, int* name_adr, char* names, int* map) { @@ -1262,15 +1292,7 @@ static int namelist(vector& list, int adr, int* name_adr, char* names, int* } for (unsigned int i=0; iname.c_str(), list[i]->name.size()); - adr += (int)list[i]->name.size(); - - // append 0 - names[adr] = 0; - adr++; + adr = addtolist(list[i]->name, adr, &name_adr[i], names); } return adr; @@ -1360,28 +1382,28 @@ void mjCModel::CopyNames(mjModel* m) { } } - -void mjCModel::CopyPaths(mjModel* m) { - // start with 0 address. - size_t adr = 0; - m->paths[0] = 0; - - for (unsigned int i=0; ifile().empty()) { - m->mesh_pathadr[i] = -1; +// process paths from one list: concatenate, compute addresses +template +static int pathlist(vector& list, int adr, int* path_adr, char* paths) { + for (unsigned int i = 0; i < list.size(); ++i) { + path_adr[i] = -1; + if (!list[i] || list[i]->get_file().empty()) { continue; } - m->mesh_pathadr[i] = adr; - - // copy path - size_t path_size = meshes[i]->file().size(); - memcpy(m->paths+adr, meshes[i]->file().c_str(), path_size); - adr += path_size; - - // append 0 - m->paths[adr] = 0; - adr++; + adr = addtolist(list[i]->get_file(), adr, &path_adr[i], paths); } + + return adr; +} + +void mjCModel::CopyPaths(mjModel* m) { + // start with 0 address, unlike m->names m->paths might be empty + size_t adr = 0; + m->paths[0] = 0; + adr = pathlist(hfields, adr, m->hfield_pathadr, m->paths); + adr = pathlist(meshes, adr, m->mesh_pathadr, m->paths); + adr = pathlist(skins, adr, m->skin_pathadr, m->paths); + adr = pathlist(textures, adr, m->tex_pathadr, m->paths); } @@ -2891,7 +2913,6 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { // resolve asset references, compute sizes IndexAssets(); SetSizes(); - // fuse static if enabled if (fusestatic) { FuseStatic(); diff --git a/src/user/user_objects.h b/src/user/user_objects.h index ab9a1aa9..505e13f3 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -615,6 +615,7 @@ class mjCMesh: public mjCBase { // public getters const std::string& content_type() const { return content_type_; } const std::string& file() const { return file_; } + const std::string& get_file() const { return file_; } const double* refpos() const { return refpos_; } const double* refquat() const { return refquat_; } const double* scale() const { return scale_; } @@ -766,6 +767,8 @@ class mjCSkin: public mjCBase { friend class mjXWriter; public: + std::string get_file() const { return file; } + std::string file; // skin file std::string material; // name of material used for rendering float rgba[4]; // rgba when material is omitted @@ -804,6 +807,8 @@ class mjCHField : public mjCBase { friend class mjXWriter; public: + std::string get_file() const { return file; } + std::string content_type; // content type of file std::string file; // file: (nrow, ncol, [elevation data]) double size[4]; // hfield size (ignore referencing geom size) @@ -831,6 +836,8 @@ class mjCTexture : public mjCBase { friend class mjXWriter; public: + std::string get_file() const { return file; } + mjtTexture type; // texture type // method 1: builtin diff --git a/test/testdata/model.xml b/test/testdata/model.xml index 6d2dcf76..8f1f16fe 100644 --- a/test/testdata/model.xml +++ b/test/testdata/model.xml @@ -18,6 +18,7 @@ -1.618 0 1 -1.618 0 -1"/> + diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index 2b6d8090..a17a2694 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -5393,16 +5393,19 @@ public unsafe struct mjModel_ { public int* skin_bonebodyid; public int* skin_bonevertid; public float* skin_bonevertweight; + public int* skin_pathadr; public double* hfield_size; public int* hfield_nrow; public int* hfield_ncol; public int* hfield_adr; public float* hfield_data; + public int* hfield_pathadr; public int* tex_type; public int* tex_height; public int* tex_width; public int* tex_adr; public byte* tex_rgb; + public int* tex_pathadr; public int* mat_texid; public byte* mat_texuniform; public float* mat_texrepeat; @@ -6164,6 +6167,7 @@ public unsafe struct model { public int* flex_bvhnum; public double* flex_radius; public float* flex_rgba; + public int* hfield_pathadr; public int* mesh_bvhadr; public int* mesh_bvhnum; public int* mesh_texcoordadr; @@ -6189,6 +6193,8 @@ public unsafe struct model { public int* skin_bonebodyid; public int* skin_bonevertid; public float* skin_bonevertweight; + public int* skin_pathadr; + public int* tex_pathadr; public int* mat_texid; public byte* mat_texuniform; public float* mat_texrepeat;