diff --git a/doc/APIreference/functions.rst b/doc/APIreference/functions.rst index a86386d5..49656292 100644 --- a/doc/APIreference/functions.rst +++ b/doc/APIreference/functions.rst @@ -1364,6 +1364,15 @@ If the model buffer is unallocated the initial configuration will not be set. Copy mjData. m is only required to contain the size fields from MJMODEL_INTS. +.. _mjv_copyData: + +`mjv_copyData <#mjv_copyData>`__ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. mujoco-include:: mjv_copyData + +Copy mjData, skip large arrays not required for visualization. + .. _mj_resetData: `mj_resetData <#mj_resetData>`__ diff --git a/doc/includes/references.h b/doc/includes/references.h index 59320911..f55992d0 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -3283,6 +3283,7 @@ void mj_deleteModel(mjModel* m); int mj_sizeModel(const mjModel* m); mjData* mj_makeData(const mjModel* m); mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src); +mjData* mjv_copyData(mjData* dest, const mjModel* m, const mjData* src); void mj_resetData(const mjModel* m, mjData* d); void mj_resetDataDebug(const mjModel* m, mjData* d, unsigned char debug_value); void mj_resetDataKeyframe(const mjModel* m, mjData* d, int key); diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index ecd40310..9ba47b19 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -268,7 +268,7 @@ X ( mjtNum, geom_friction, ngeom, 3 ) \ X ( mjtNum, geom_margin, ngeom, 1 ) \ X ( mjtNum, geom_gap, ngeom, 1 ) \ - X ( mjtNum, geom_fluid, ngeom, mjNFLUID ) \ + XNV ( mjtNum, geom_fluid, ngeom, mjNFLUID ) \ X ( mjtNum, geom_user, ngeom, MJ_M(nuser_geom) ) \ XMJV( float, geom_rgba, ngeom, 4 ) \ XMJV( int, site_type, nsite, 1 ) \ @@ -401,15 +401,15 @@ XNV ( int, mesh_facetexcoord, nmeshface, 3 ) \ XNV ( int, mesh_graph, nmeshgraph, 1 ) \ XMJV( int, mesh_pathadr, nmesh, 1 ) \ - X ( int, mesh_polynum, nmesh, 1 ) \ - X ( int, mesh_polyadr, nmesh, 1 ) \ - X ( mjtNum, mesh_polynormal, nmeshpoly, 3 ) \ - X ( int, mesh_polyvertadr, nmeshpoly, 1 ) \ - X ( int, mesh_polyvertnum, nmeshpoly, 1 ) \ - X ( int, mesh_polyvert, nmeshpolyvert, 1 ) \ - X ( int, mesh_polymapadr, nmeshvert, 1 ) \ - X ( int, mesh_polymapnum, nmeshvert, 1 ) \ - X ( int, mesh_polymap, nmeshpolymap, 1 ) \ + XNV ( int, mesh_polynum, nmesh, 1 ) \ + XNV ( int, mesh_polyadr, nmesh, 1 ) \ + XNV ( mjtNum, mesh_polynormal, nmeshpoly, 3 ) \ + XNV ( int, mesh_polyvertadr, nmeshpoly, 1 ) \ + XNV ( int, mesh_polyvertnum, nmeshpoly, 1 ) \ + XNV ( int, mesh_polyvert, nmeshpolyvert, 1 ) \ + XNV ( int, mesh_polymapadr, nmeshvert, 1 ) \ + XNV ( int, mesh_polymapnum, nmeshvert, 1 ) \ + XNV ( int, mesh_polymap, nmeshpolymap, 1 ) \ XMJV( int, skin_matid, nskin, 1 ) \ XMJV( int, skin_group, nskin, 1 ) \ XMJV( float, skin_rgba, nskin, 4 ) \ @@ -655,10 +655,10 @@ X ( int, moment_rowadr, nu, 1 ) \ X ( int, moment_colind, nJmom, 1 ) \ X ( mjtNum, actuator_moment, nJmom, 1 ) \ - X ( mjtNum, crb, nbody, 10 ) \ - X ( mjtNum, qM, nM, 1 ) \ - X ( mjtNum, M, nC, 1 ) \ - X ( mjtNum, qLD, nC, 1 ) \ + XNV ( mjtNum, crb, nbody, 10 ) \ + XNV ( mjtNum, qM, nM, 1 ) \ + XNV ( mjtNum, M, nC, 1 ) \ + XNV ( mjtNum, qLD, nC, 1 ) \ X ( mjtNum, qLDiagInv, nv, 1 ) \ XMJV( mjtNum, bvh_aabb_dyn, nbvhdynamic, 6 ) \ XMJV( mjtByte, bvh_active, nbvh, 1 ) \ @@ -675,23 +675,23 @@ X ( mjtNum, qfrc_passive, nv, 1 ) \ X ( mjtNum, subtree_linvel, nbody, 3 ) \ X ( mjtNum, subtree_angmom, nbody, 3 ) \ - X ( mjtNum, qH, nC, 1 ) \ + XNV ( mjtNum, qH, nC, 1 ) \ X ( mjtNum, qHDiagInv, nv, 1 ) \ - X ( int, B_rownnz, nbody, 1 ) \ - X ( int, B_rowadr, nbody, 1 ) \ - X ( int, B_colind, nB, 1 ) \ - X ( int, M_rownnz, nv, 1 ) \ - X ( int, M_rowadr, nv, 1 ) \ - X ( int, M_colind, nC, 1 ) \ - X ( int, mapM2M, nC, 1 ) \ - X ( int, D_rownnz, nv, 1 ) \ - X ( int, D_rowadr, nv, 1 ) \ - X ( int, D_diag, nv, 1 ) \ - X ( int, D_colind, nD, 1 ) \ - X ( int, mapM2D, nD, 1 ) \ - X ( int, mapD2M, nM, 1 ) \ - X ( mjtNum, qDeriv, nD, 1 ) \ - X ( mjtNum, qLU, nD, 1 ) \ + XNV ( int, B_rownnz, nbody, 1 ) \ + XNV ( int, B_rowadr, nbody, 1 ) \ + XNV ( int, B_colind, nB, 1 ) \ + XNV ( int, M_rownnz, nv, 1 ) \ + XNV ( int, M_rowadr, nv, 1 ) \ + XNV ( int, M_colind, nC, 1 ) \ + XNV ( int, mapM2M, nC, 1 ) \ + XNV ( int, D_rownnz, nv, 1 ) \ + XNV ( int, D_rowadr, nv, 1 ) \ + XNV ( int, D_diag, nv, 1 ) \ + XNV ( int, D_colind, nD, 1 ) \ + XNV ( int, mapM2D, nD, 1 ) \ + XNV ( int, mapD2M, nM, 1 ) \ + XNV ( mjtNum, qDeriv, nD, 1 ) \ + XNV ( mjtNum, qLU, nD, 1 ) \ X ( mjtNum, actuator_force, nu, 1 ) \ X ( mjtNum, qfrc_actuator, nv, 1 ) \ X ( mjtNum, qfrc_smooth, nv, 1 ) \ @@ -712,83 +712,83 @@ X( mjContact, contact, MJ_D(ncon), 1 ) // array fields of mjData that are used in the primal problem -#define MJDATA_ARENA_POINTERS_SOLVER \ - X( int, efc_type, MJ_D(nefc), 1 ) \ - X( int, efc_id, MJ_D(nefc), 1 ) \ - X( int, efc_J_rownnz, MJ_D(nefc), 1 ) \ - X( int, efc_J_rowadr, MJ_D(nefc), 1 ) \ - X( int, efc_J_rowsuper, MJ_D(nefc), 1 ) \ - X( int, efc_J_colind, MJ_D(nJ), 1 ) \ - X( int, efc_JT_rownnz, MJ_M(nv), 1 ) \ - X( int, efc_JT_rowadr, MJ_M(nv), 1 ) \ - X( int, efc_JT_rowsuper, MJ_M(nv), 1 ) \ - X( int, efc_JT_colind, MJ_D(nJ), 1 ) \ - X( mjtNum, efc_J, MJ_D(nJ), 1 ) \ - X( mjtNum, efc_JT, MJ_D(nJ), 1 ) \ - X( mjtNum, efc_pos, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_margin, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_frictionloss, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_diagApprox, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_KBIP, MJ_D(nefc), 4 ) \ - X( mjtNum, efc_D, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_R, MJ_D(nefc), 1 ) \ - X( int, tendon_efcadr, MJ_M(ntendon), 1 ) \ - X( mjtNum, efc_vel, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_aref, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_b, MJ_D(nefc), 1 ) \ - X( mjtNum, efc_force, MJ_D(nefc), 1 ) \ - X( int, efc_state, MJ_D(nefc), 1 ) +#define MJDATA_ARENA_POINTERS_SOLVER \ + X ( int, efc_type, MJ_D(nefc), 1 ) \ + X ( int, efc_id, MJ_D(nefc), 1 ) \ + XNV( int, efc_J_rownnz, MJ_D(nefc), 1 ) \ + XNV( int, efc_J_rowadr, MJ_D(nefc), 1 ) \ + XNV( int, efc_J_rowsuper, MJ_D(nefc), 1 ) \ + XNV( int, efc_J_colind, MJ_D(nJ), 1 ) \ + XNV( int, efc_JT_rownnz, MJ_M(nv), 1 ) \ + XNV( int, efc_JT_rowadr, MJ_M(nv), 1 ) \ + XNV( int, efc_JT_rowsuper, MJ_M(nv), 1 ) \ + XNV( int, efc_JT_colind, MJ_D(nJ), 1 ) \ + XNV( mjtNum, efc_J, MJ_D(nJ), 1 ) \ + XNV( mjtNum, efc_JT, MJ_D(nJ), 1 ) \ + X ( mjtNum, efc_pos, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_margin, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_frictionloss, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_diagApprox, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_KBIP, MJ_D(nefc), 4 ) \ + X ( mjtNum, efc_D, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_R, MJ_D(nefc), 1 ) \ + X ( int, tendon_efcadr, MJ_M(ntendon), 1 ) \ + X ( mjtNum, efc_vel, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_aref, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_b, MJ_D(nefc), 1 ) \ + X ( mjtNum, efc_force, MJ_D(nefc), 1 ) \ + X ( int, efc_state, MJ_D(nefc), 1 ) // array fields of mjData that are used in the dual problem -#define MJDATA_ARENA_POINTERS_DUAL \ - X( int, efc_AR_rownnz, MJ_D(nefc), 1 ) \ - X( int, efc_AR_rowadr, MJ_D(nefc), 1 ) \ - X( int, efc_AR_colind, MJ_D(nA), 1 ) \ - X( mjtNum, efc_AR, MJ_D(nA), 1 ) +#define MJDATA_ARENA_POINTERS_DUAL \ + XNV( int, efc_AR_rownnz, MJ_D(nefc), 1 ) \ + XNV( int, efc_AR_rowadr, MJ_D(nefc), 1 ) \ + XNV( int, efc_AR_colind, MJ_D(nA), 1 ) \ + XNV( mjtNum, efc_AR, MJ_D(nA), 1 ) // array fields of mjData that are used for constraint islands -#define MJDATA_ARENA_POINTERS_ISLAND \ - X( int, dof_island, MJ_M(nv), 1 ) \ - X( int, island_nv, MJ_D(nisland), 1 ) \ - X( int, island_idofadr, MJ_D(nisland), 1 ) \ - X( int, island_dofadr, MJ_D(nisland), 1 ) \ - X( int, map_dof2idof, MJ_M(nv), 1 ) \ - X( int, map_idof2dof, MJ_M(nv), 1 ) \ - X( mjtNum, ifrc_smooth, MJ_D(nidof), 1 ) \ - X( mjtNum, iacc_smooth, MJ_D(nidof), 1 ) \ - X( int, iM_rownnz, MJ_D(nidof), 1 ) \ - X( int, iM_rowadr, MJ_D(nidof), 1 ) \ - X( int, iM_colind, MJ_M(nC), 1 ) \ - X( mjtNum, iM, MJ_M(nC), 1 ) \ - X( mjtNum, iLD, MJ_M(nC), 1 ) \ - X( mjtNum, iLDiagInv, MJ_D(nidof), 1 ) \ - X( mjtNum, iacc, MJ_D(nidof), 1 ) \ - X( int, efc_island, MJ_D(nefc), 1 ) \ - X( int, island_ne, MJ_D(nisland), 1 ) \ - X( int, island_nf, MJ_D(nisland), 1 ) \ - X( int, island_nefc, MJ_D(nisland), 1 ) \ - X( int, island_iefcadr, MJ_D(nisland), 1 ) \ - X( int, map_efc2iefc, MJ_D(nefc), 1 ) \ - X( int, map_iefc2efc, MJ_D(nefc), 1 ) \ - X( int, iefc_type, MJ_D(nefc), 1 ) \ - X( int, iefc_id, MJ_D(nefc), 1 ) \ - X( int, iefc_J_rownnz, MJ_D(nefc), 1 ) \ - X( int, iefc_J_rowadr, MJ_D(nefc), 1 ) \ - X( int, iefc_J_rowsuper, MJ_D(nefc), 1 ) \ - X( int, iefc_J_colind, MJ_D(nJ), 1 ) \ - X( int, iefc_JT_rownnz, MJ_D(nidof), 1 ) \ - X( int, iefc_JT_rowadr, MJ_D(nidof), 1 ) \ - X( int, iefc_JT_rowsuper, MJ_D(nidof), 1 ) \ - X( int, iefc_JT_colind, MJ_D(nJ), 1 ) \ - X( mjtNum, iefc_J, MJ_D(nJ), 1 ) \ - X( mjtNum, iefc_JT, MJ_D(nJ), 1 ) \ - X( mjtNum, iefc_frictionloss, MJ_D(nefc), 1 ) \ - X( mjtNum, iefc_D, MJ_D(nefc), 1 ) \ - X( mjtNum, iefc_R, MJ_D(nefc), 1 ) \ - X( mjtNum, iefc_aref, MJ_D(nefc), 1 ) \ - X( int, iefc_state, MJ_D(nefc), 1 ) \ - X( mjtNum, iefc_force, MJ_D(nefc), 1 ) \ - X( mjtNum, ifrc_constraint, MJ_D(nidof), 1 ) +#define MJDATA_ARENA_POINTERS_ISLAND \ + X ( int, dof_island, MJ_M(nv), 1 ) \ + X ( int, island_nv, MJ_D(nisland), 1 ) \ + X ( int, island_idofadr, MJ_D(nisland), 1 ) \ + X ( int, island_dofadr, MJ_D(nisland), 1 ) \ + X ( int, map_dof2idof, MJ_M(nv), 1 ) \ + X ( int, map_idof2dof, MJ_M(nv), 1 ) \ + X ( mjtNum, ifrc_smooth, MJ_D(nidof), 1 ) \ + X ( mjtNum, iacc_smooth, MJ_D(nidof), 1 ) \ + XNV( int, iM_rownnz, MJ_D(nidof), 1 ) \ + XNV( int, iM_rowadr, MJ_D(nidof), 1 ) \ + XNV( int, iM_colind, MJ_M(nC), 1 ) \ + XNV( mjtNum, iM, MJ_M(nC), 1 ) \ + XNV( mjtNum, iLD, MJ_M(nC), 1 ) \ + X ( mjtNum, iLDiagInv, MJ_D(nidof), 1 ) \ + X ( mjtNum, iacc, MJ_D(nidof), 1 ) \ + X ( int, efc_island, MJ_D(nefc), 1 ) \ + X ( int, island_ne, MJ_D(nisland), 1 ) \ + X ( int, island_nf, MJ_D(nisland), 1 ) \ + X ( int, island_nefc, MJ_D(nisland), 1 ) \ + X ( int, island_iefcadr, MJ_D(nisland), 1 ) \ + X ( int, map_efc2iefc, MJ_D(nefc), 1 ) \ + X ( int, map_iefc2efc, MJ_D(nefc), 1 ) \ + X ( int, iefc_type, MJ_D(nefc), 1 ) \ + X ( int, iefc_id, MJ_D(nefc), 1 ) \ + XNV( int, iefc_J_rownnz, MJ_D(nefc), 1 ) \ + XNV( int, iefc_J_rowadr, MJ_D(nefc), 1 ) \ + XNV( int, iefc_J_rowsuper, MJ_D(nefc), 1 ) \ + XNV( int, iefc_J_colind, MJ_D(nJ), 1 ) \ + XNV( int, iefc_JT_rownnz, MJ_D(nidof), 1 ) \ + XNV( int, iefc_JT_rowadr, MJ_D(nidof), 1 ) \ + XNV( int, iefc_JT_rowsuper, MJ_D(nidof), 1 ) \ + XNV( int, iefc_JT_colind, MJ_D(nJ), 1 ) \ + XNV( mjtNum, iefc_J, MJ_D(nJ), 1 ) \ + XNV( mjtNum, iefc_JT, MJ_D(nJ), 1 ) \ + X ( mjtNum, iefc_frictionloss, MJ_D(nefc), 1 ) \ + X ( mjtNum, iefc_D, MJ_D(nefc), 1 ) \ + X ( mjtNum, iefc_R, MJ_D(nefc), 1 ) \ + X ( mjtNum, iefc_aref, MJ_D(nefc), 1 ) \ + X ( int, iefc_state, MJ_D(nefc), 1 ) \ + X ( mjtNum, iefc_force, MJ_D(nefc), 1 ) \ + X ( mjtNum, ifrc_constraint, MJ_D(nidof), 1 ) // array fields of mjData that live in d->arena #define MJDATA_ARENA_POINTERS \ diff --git a/include/mujoco/mujoco.h b/include/mujoco/mujoco.h index 784d1ab8..8d8cb8c2 100644 --- a/include/mujoco/mujoco.h +++ b/include/mujoco/mujoco.h @@ -187,6 +187,9 @@ MJAPI mjData* mj_makeData(const mjModel* m); // m is only required to contain the size fields from MJMODEL_INTS. MJAPI mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src); +// Copy mjData, skip large arrays not required for visualization. +MJAPI mjData* mjv_copyData(mjData* dest, const mjModel* m, const mjData* src); + // Reset data to defaults. MJAPI void mj_resetData(const mjModel* m, mjData* d); diff --git a/python/mujoco/introspect/functions.py b/python/mujoco/introspect/functions.py index ef8bcd58..1f495c03 100644 --- a/python/mujoco/introspect/functions.py +++ b/python/mujoco/introspect/functions.py @@ -745,6 +745,34 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([ ), doc='Copy mjData. m is only required to contain the size fields from MJMODEL_INTS.', # pylint: disable=line-too-long )), + ('mjv_copyData', + FunctionDecl( + name='mjv_copyData', + return_type=PointerType( + inner_type=ValueType(name='mjData'), + ), + parameters=( + FunctionParameterDecl( + name='dest', + type=PointerType( + inner_type=ValueType(name='mjData'), + ), + ), + FunctionParameterDecl( + name='m', + type=PointerType( + inner_type=ValueType(name='mjModel', is_const=True), + ), + ), + FunctionParameterDecl( + name='src', + type=PointerType( + inner_type=ValueType(name='mjData', is_const=True), + ), + ), + ), + doc='Copy mjData, skip large arrays not required for visualization.', + )), ('mj_resetData', FunctionDecl( name='mj_resetData', diff --git a/src/engine/engine_io.c b/src/engine/engine_io.c index d090f229..49325b30 100644 --- a/src/engine/engine_io.c +++ b/src/engine/engine_io.c @@ -1415,8 +1415,9 @@ mjData* mj_makeData(const mjModel* m) { -// copy mjData, if dest==NULL create new data -mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) { +// copy mjData, if dest==NULL create new data; +// flg_all 1: copy all fields, 0: skip fields not required for visualization +mjData* mj_copyDataVisual(mjData* dest, const mjModel* m, const mjData* src, int flg_all) { void* save_buffer; void* save_arena; @@ -1461,10 +1462,25 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) { // copy buffer { MJDATA_POINTERS_PREAMBLE(m) - #define X(type, name, nr, nc) \ - memcpy((char*)dest->name, (const char*)src->name, sizeof(type)*(m->nr)*nc); - MJDATA_POINTERS - #undef X + if (flg_all) { + #define X(type, name, nr, nc) \ + memcpy((char*)dest->name, (const char*)src->name, sizeof(type)*(m->nr)*nc); + MJDATA_POINTERS + #undef X + } else { + // redefine XNV to nothing + #undef XNV + #define XNV(type, name, nr, nc) + + #define X(type, name, nr, nc) \ + memcpy((char*)dest->name, (const char*)src->name, sizeof(type)*(m->nr)*nc); + MJDATA_POINTERS + #undef X + + // redefine XNV to be the same as X + #undef XNV + #define XNV X + } } @@ -1474,7 +1490,8 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) { #undef MJ_M #define MJ_M(n) (m->n) - #define X(type, name, nr, nc) \ + if (flg_all) { + #define X(type, name, nr, nc) \ if (src->name) { \ dest->name = (type*)((char*)dest->arena + PTRDIFF(src->name, src->arena)); \ ASAN_UNPOISON_MEMORY_REGION(dest->name, sizeof(type) * nr * nc); \ @@ -1482,8 +1499,28 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) { } else { \ dest->name = NULL; \ } - MJDATA_ARENA_POINTERS - #undef X + MJDATA_ARENA_POINTERS + #undef X + } else { + // redefine XNV to nothing + #undef XNV + #define XNV(type, name, nr, nc) + + #define X(type, name, nr, nc) \ + if (src->name) { \ + dest->name = (type*)((char*)dest->arena + PTRDIFF(src->name, src->arena)); \ + ASAN_UNPOISON_MEMORY_REGION(dest->name, sizeof(type) * nr * nc); \ + memcpy((char*)dest->name, (const char*)src->name, sizeof(type) * nr * nc); \ + } else { \ + dest->name = NULL; \ + } + MJDATA_ARENA_POINTERS + #undef X + + // redefine XNV to be the same as X + #undef XNV + #define XNV X + } #undef MJ_M #define MJ_M(n) n @@ -1515,6 +1552,14 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) { } +mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) { + return mj_copyDataVisual(dest, m, src, /*flg_all=*/1); +} + + +mjData* mjv_copyData(mjData* dest, const mjModel* m, const mjData* src) { + return mj_copyDataVisual(dest, m, src, /*flg_all=*/0); +} static void maybe_lock_alloc_mutex(mjData* d) { if (d->threadpool != 0) { diff --git a/src/engine/engine_io.h b/src/engine/engine_io.h index 809d9e83..bdf0e2ce 100644 --- a/src/engine/engine_io.h +++ b/src/engine/engine_io.h @@ -99,6 +99,9 @@ MJAPI void mj_makeRawData(mjData** dest, const mjModel* m); // m is only required to contain the size fields from MJMODEL_INTS. MJAPI mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src); +// copy mjData, skip large arrays not required for abstract visualization +MJAPI mjData* mjv_copyData(mjData* dest, const mjModel* m, const mjData* src); + // set data to defaults MJAPI void mj_resetData(const mjModel* m, mjData* d); diff --git a/test/engine/engine_io_test.cc b/test/engine/engine_io_test.cc index 470f6f02..72e942d1 100644 --- a/test/engine/engine_io_test.cc +++ b/test/engine/engine_io_test.cc @@ -226,11 +226,42 @@ TEST_F(EngineIoTest, MjvCopyModel) { EXPECT_FLOAT_EQ(model2->mesh_vert[0], 0.1); // unchanged EXPECT_FLOAT_EQ(model2->geom_rgba[0], 0.4); - // mj_deleteData(data); mj_deleteModel(model2); mj_deleteModel(model1); } +TEST_F(EngineIoTest, MjvCopyData) { + static constexpr char xml[] = R"( + + + + + + + + + + )"; + char error[1024]; + mjModel* model = LoadModelFromString(xml, error, sizeof(error)); + ASSERT_THAT(model, NotNull()) << error; + + mjData* data1 = mj_makeData(model); + mj_forward(model, data1); + EXPECT_THAT(data1->efc_J, NotNull()); + + mjData* data2 = mj_copyData(nullptr, model, data1); + EXPECT_THAT(data2->efc_J, NotNull()); + + mj_deleteData(data2); + data2 = mjv_copyData(nullptr, model, data1); + EXPECT_THAT(data2->efc_J, IsNull()); + + mj_deleteData(data2); + mj_deleteData(data1); + mj_deleteModel(model); +} + using ValidateReferencesTest = MujocoTest; TEST_F(ValidateReferencesTest, BodyReferences) { diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index d0dd61aa..cdeeca54 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -6622,6 +6622,9 @@ public static unsafe extern mjData_* mj_makeData(mjModel_* m); [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern mjData_* mj_copyData(mjData_* dest, mjModel_* m, mjData_* src); +[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] +public static unsafe extern mjData_* mjv_copyData(mjData_* dest, mjModel_* m, mjData_* src); + [DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)] public static unsafe extern void mj_resetData(mjModel_* m, mjData_* d);