Add mjv_copyModel to copy mjModel, skipping large arrays not required for abstract visualization.
This functionality is meant for fast copying of `mjModel` when synchronizing the visualization state, as in the Python passive viewer. PiperOrigin-RevId: 699199743 Change-Id: I13a5160063eb09139ec1aee9c4969bc1c6f547f1
This commit is contained in:
committed by
Copybara-Service
parent
74dcd51d83
commit
1d64362adc
@@ -2163,6 +2163,15 @@ Update entire scene given model state.
|
|||||||
|
|
||||||
Update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings.
|
Update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings.
|
||||||
|
|
||||||
|
.. _mjv_copyModel:
|
||||||
|
|
||||||
|
`mjv_copyModel <#mjv_copyModel>`__
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. mujoco-include:: mjv_copyModel
|
||||||
|
|
||||||
|
Copy mjModel, skip large arrays not required for abstract visualization.
|
||||||
|
|
||||||
.. _mjv_defaultSceneState:
|
.. _mjv_defaultSceneState:
|
||||||
|
|
||||||
`mjv_defaultSceneState <#mjv_defaultSceneState>`__
|
`mjv_defaultSceneState <#mjv_defaultSceneState>`__
|
||||||
|
|||||||
@@ -3347,6 +3347,7 @@ void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
|
|||||||
int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt,
|
int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt,
|
||||||
const mjvPerturb* pert, mjvCamera* cam, int catmask,
|
const mjvPerturb* pert, mjvCamera* cam, int catmask,
|
||||||
mjvScene* scn);
|
mjvScene* scn);
|
||||||
|
void mjv_copyModel(mjModel* dest, const mjModel* src);
|
||||||
void mjv_defaultSceneState(mjvSceneState* scnstate);
|
void mjv_defaultSceneState(mjvSceneState* scnstate);
|
||||||
void mjv_makeSceneState(const mjModel* m, const mjData* d,
|
void mjv_makeSceneState(const mjModel* m, const mjData* d,
|
||||||
mjvSceneState* scnstate, int maxgeom);
|
mjvSceneState* scnstate, int maxgeom);
|
||||||
|
|||||||
@@ -378,13 +378,13 @@
|
|||||||
X ( mjtNum, mesh_scale, nmesh, 3 ) \
|
X ( mjtNum, mesh_scale, nmesh, 3 ) \
|
||||||
X ( mjtNum, mesh_pos, nmesh, 3 ) \
|
X ( mjtNum, mesh_pos, nmesh, 3 ) \
|
||||||
X ( mjtNum, mesh_quat, nmesh, 4 ) \
|
X ( mjtNum, mesh_quat, nmesh, 4 ) \
|
||||||
X ( float, mesh_vert, nmeshvert, 3 ) \
|
XNV ( float, mesh_vert, nmeshvert, 3 ) \
|
||||||
X ( float, mesh_normal, nmeshnormal, 3 ) \
|
XNV ( float, mesh_normal, nmeshnormal, 3 ) \
|
||||||
X ( float, mesh_texcoord, nmeshtexcoord, 2 ) \
|
XNV ( float, mesh_texcoord, nmeshtexcoord, 2 ) \
|
||||||
X ( int, mesh_face, nmeshface, 3 ) \
|
XNV ( int, mesh_face, nmeshface, 3 ) \
|
||||||
X ( int, mesh_facenormal, nmeshface, 3 ) \
|
XNV ( int, mesh_facenormal, nmeshface, 3 ) \
|
||||||
X ( int, mesh_facetexcoord, nmeshface, 3 ) \
|
XNV ( int, mesh_facetexcoord, nmeshface, 3 ) \
|
||||||
X ( int, mesh_graph, nmeshgraph, 1 ) \
|
XNV ( int, mesh_graph, nmeshgraph, 1 ) \
|
||||||
XMJV( int, mesh_pathadr, nmesh, 1 ) \
|
XMJV( int, mesh_pathadr, nmesh, 1 ) \
|
||||||
XMJV( int, skin_matid, nskin, 1 ) \
|
XMJV( int, skin_matid, nskin, 1 ) \
|
||||||
XMJV( int, skin_group, nskin, 1 ) \
|
XMJV( int, skin_group, nskin, 1 ) \
|
||||||
@@ -412,14 +412,14 @@
|
|||||||
X ( int, hfield_nrow, nhfield, 1 ) \
|
X ( int, hfield_nrow, nhfield, 1 ) \
|
||||||
X ( int, hfield_ncol, nhfield, 1 ) \
|
X ( int, hfield_ncol, nhfield, 1 ) \
|
||||||
X ( int, hfield_adr, nhfield, 1 ) \
|
X ( int, hfield_adr, nhfield, 1 ) \
|
||||||
X ( float, hfield_data, nhfielddata, 1 ) \
|
XNV ( float, hfield_data, nhfielddata, 1 ) \
|
||||||
XMJV( int, hfield_pathadr, nhfield, 1 ) \
|
XMJV( int, hfield_pathadr, nhfield, 1 ) \
|
||||||
X ( int, tex_type, ntex, 1 ) \
|
X ( int, tex_type, ntex, 1 ) \
|
||||||
X ( int, tex_height, ntex, 1 ) \
|
X ( int, tex_height, ntex, 1 ) \
|
||||||
X ( int, tex_width, ntex, 1 ) \
|
X ( int, tex_width, ntex, 1 ) \
|
||||||
X ( int, tex_nchannel, ntex, 1 ) \
|
X ( int, tex_nchannel, ntex, 1 ) \
|
||||||
X ( int, tex_adr, ntex, 1 ) \
|
X ( int, tex_adr, ntex, 1 ) \
|
||||||
X ( mjtByte, tex_data, ntexdata, 1 ) \
|
XNV ( mjtByte, tex_data, ntexdata, 1 ) \
|
||||||
XMJV( int, tex_pathadr, ntex, 1 ) \
|
XMJV( int, tex_pathadr, ntex, 1 ) \
|
||||||
XMJV( int, mat_texid, nmat, mjNTEXROLE ) \
|
XMJV( int, mat_texid, nmat, mjNTEXROLE ) \
|
||||||
XMJV( mjtByte, mat_texuniform, nmat, 1 ) \
|
XMJV( mjtByte, mat_texuniform, nmat, 1 ) \
|
||||||
@@ -779,4 +779,9 @@
|
|||||||
// redefine X to expand to nothing, and XMJV to do what's required
|
// redefine X to expand to nothing, and XMJV to do what's required
|
||||||
#define XMJV X
|
#define XMJV X
|
||||||
|
|
||||||
|
// alias XNV to be the same as X
|
||||||
|
// to obtain only X macros for fields that are relevant for mjvScene creation,
|
||||||
|
// redefine XNV to expand to nothing
|
||||||
|
#define XNV X
|
||||||
|
|
||||||
#endif // MUJOCO_MJXMACRO_H_
|
#endif // MUJOCO_MJXMACRO_H_
|
||||||
|
|||||||
@@ -692,6 +692,9 @@ MJAPI int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOptio
|
|||||||
const mjvPerturb* pert, mjvCamera* cam, int catmask,
|
const mjvPerturb* pert, mjvCamera* cam, int catmask,
|
||||||
mjvScene* scn);
|
mjvScene* scn);
|
||||||
|
|
||||||
|
// Copy mjModel, skip large arrays not required for abstract visualization.
|
||||||
|
MJAPI void mjv_copyModel(mjModel* dest, const mjModel* src);
|
||||||
|
|
||||||
// Set default scene state.
|
// Set default scene state.
|
||||||
MJAPI void mjv_defaultSceneState(mjvSceneState* scnstate);
|
MJAPI void mjv_defaultSceneState(mjvSceneState* scnstate);
|
||||||
|
|
||||||
|
|||||||
@@ -4550,6 +4550,26 @@ FUNCTIONS: Mapping[str, FunctionDecl] = dict([
|
|||||||
),
|
),
|
||||||
doc='Update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings.', # pylint: disable=line-too-long
|
doc='Update entire scene from a scene state, return the number of new mjWARN_VGEOMFULL warnings.', # pylint: disable=line-too-long
|
||||||
)),
|
)),
|
||||||
|
('mjv_copyModel',
|
||||||
|
FunctionDecl(
|
||||||
|
name='mjv_copyModel',
|
||||||
|
return_type=ValueType(name='void'),
|
||||||
|
parameters=(
|
||||||
|
FunctionParameterDecl(
|
||||||
|
name='dest',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjModel'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FunctionParameterDecl(
|
||||||
|
name='src',
|
||||||
|
type=PointerType(
|
||||||
|
inner_type=ValueType(name='mjModel', is_const=True),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
doc='Copy mjModel, skip large arrays not required for abstract visualization.', # pylint: disable=line-too-long
|
||||||
|
)),
|
||||||
('mjv_defaultSceneState',
|
('mjv_defaultSceneState',
|
||||||
FunctionDecl(
|
FunctionDecl(
|
||||||
name='mjv_defaultSceneState',
|
name='mjv_defaultSceneState',
|
||||||
|
|||||||
+57
-23
@@ -625,10 +625,10 @@ void mj_makeModel(mjModel** dest,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// copy mjModel, if dest==NULL create new model
|
// copy mjModel, if dest==NULL create new model
|
||||||
mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
||||||
void* save_bufptr;
|
|
||||||
|
|
||||||
// allocate new model if needed
|
// allocate new model if needed
|
||||||
if (!dest) {
|
if (!dest) {
|
||||||
mj_makeModel(&dest,
|
mj_makeModel(&dest,
|
||||||
@@ -658,13 +658,13 @@ mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
|||||||
mjERROR("dest and src models have different buffer size");
|
mjERROR("dest and src models have different buffer size");
|
||||||
}
|
}
|
||||||
|
|
||||||
// save buffer ptr, copy everything, restore buffer and other pointers
|
// save buffer ptr, copy struct, restore buffer and other pointers
|
||||||
save_bufptr = dest->buffer;
|
void* save_bufptr = dest->buffer;
|
||||||
*dest = *src;
|
*dest = *src;
|
||||||
dest->buffer = save_bufptr;
|
dest->buffer = save_bufptr;
|
||||||
mj_setPtrModel(dest);
|
mj_setPtrModel(dest);
|
||||||
|
|
||||||
// copy buffer
|
// copy buffer contents
|
||||||
{
|
{
|
||||||
MJMODEL_POINTERS_PREAMBLE(src)
|
MJMODEL_POINTERS_PREAMBLE(src)
|
||||||
#define X(type, name, nr, nc) \
|
#define X(type, name, nr, nc) \
|
||||||
@@ -678,6 +678,38 @@ mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// copy mjModel, skip large arrays not required for abstract visualization
|
||||||
|
void mjv_copyModel(mjModel* dest, const mjModel* src) {
|
||||||
|
// check sizes
|
||||||
|
if (dest->nbuffer != src->nbuffer) {
|
||||||
|
mjERROR("dest and src models have different buffer size");
|
||||||
|
}
|
||||||
|
|
||||||
|
// save buffer ptr, copy struct, restore buffer and other pointers
|
||||||
|
void* save_bufptr = dest->buffer;
|
||||||
|
*dest = *src;
|
||||||
|
dest->buffer = save_bufptr;
|
||||||
|
mj_setPtrModel(dest);
|
||||||
|
|
||||||
|
// redefine XNV to do nothing
|
||||||
|
#undef XNV
|
||||||
|
#define XNV(type, name, nr, nc)
|
||||||
|
|
||||||
|
// copy buffer contents, skipping arrays marked XNV
|
||||||
|
{
|
||||||
|
MJMODEL_POINTERS_PREAMBLE(src)
|
||||||
|
#define X(type, name, nr, nc) \
|
||||||
|
memcpy((char*)dest->name, (const char*)src->name, sizeof(type)*(src->nr)*nc);
|
||||||
|
MJMODEL_POINTERS
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
// redefine XNV to be the same as X
|
||||||
|
#undef XNV
|
||||||
|
#define XNV X
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// save model to binary file, or memory buffer of szbuf>0
|
// save model to binary file, or memory buffer of szbuf>0
|
||||||
void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buffer_sz) {
|
void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buffer_sz) {
|
||||||
FILE* fp = 0;
|
FILE* fp = 0;
|
||||||
@@ -1401,26 +1433,28 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) {
|
|||||||
#undef X
|
#undef X
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy arena memory
|
|
||||||
#undef MJ_D
|
|
||||||
#define MJ_D(n) (src->n)
|
|
||||||
#undef MJ_M
|
|
||||||
#define MJ_M(n) (m->n)
|
|
||||||
#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; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// copy arena memory
|
||||||
|
#undef MJ_D
|
||||||
|
#define MJ_D(n) (src->n)
|
||||||
|
#undef MJ_M
|
||||||
|
#define MJ_M(n) (m->n)
|
||||||
|
|
||||||
|
#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
|
MJDATA_ARENA_POINTERS
|
||||||
#undef X
|
#undef X
|
||||||
#undef MJ_M
|
|
||||||
#define MJ_M(n) n
|
#undef MJ_M
|
||||||
#undef MJ_D
|
#define MJ_M(n) n
|
||||||
#define MJ_D(n) n
|
#undef MJ_D
|
||||||
|
#define MJ_D(n) n
|
||||||
|
|
||||||
// restore contact pointer
|
// restore contact pointer
|
||||||
dest->contact = dest->arena;
|
dest->contact = dest->arena;
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ void mj_makeModel(mjModel** dest,
|
|||||||
// copy mjModel; allocate new if dest is NULL
|
// copy mjModel; allocate new if dest is NULL
|
||||||
MJAPI mjModel* mj_copyModel(mjModel* dest, const mjModel* src);
|
MJAPI mjModel* mj_copyModel(mjModel* dest, const mjModel* src);
|
||||||
|
|
||||||
|
// copy mjModel, skip large arrays not required for abstract visualization
|
||||||
|
MJAPI void mjv_copyModel(mjModel* dest, const mjModel* src);
|
||||||
|
|
||||||
// save model to binary file
|
// save model to binary file
|
||||||
MJAPI void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buffer_sz);
|
MJAPI void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buffer_sz);
|
||||||
|
|
||||||
|
|||||||
@@ -193,6 +193,43 @@ TEST_F(EngineIoTest, MakeDataResetsAllArenaPointerSizes) {
|
|||||||
mj_deleteModel(model);
|
mj_deleteModel(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(EngineIoTest, MjvCopyModel) {
|
||||||
|
static constexpr char xml[] = R"(
|
||||||
|
<mujoco>
|
||||||
|
<asset>
|
||||||
|
<mesh name="tet" vertex="0 0 0 1 0 0 0 1 0 0 0 1"/>
|
||||||
|
</asset>
|
||||||
|
<worldbody>
|
||||||
|
<geom type="mesh" mesh="tet"/>
|
||||||
|
</worldbody>
|
||||||
|
</mujoco>
|
||||||
|
)";
|
||||||
|
char error[1024];
|
||||||
|
mjModel* model1 = LoadModelFromString(xml, error, sizeof(error));
|
||||||
|
ASSERT_THAT(model1, NotNull()) << error;
|
||||||
|
|
||||||
|
mjModel* model2 = mj_copyModel(nullptr, model1);
|
||||||
|
ASSERT_THAT(model2, NotNull()) << error;
|
||||||
|
|
||||||
|
model1->mesh_vert[0] = 0.1;
|
||||||
|
model1->geom_rgba[0] = 0.2;
|
||||||
|
mj_copyModel(model2, model1);
|
||||||
|
|
||||||
|
EXPECT_FLOAT_EQ(model2->mesh_vert[0], 0.1);
|
||||||
|
EXPECT_FLOAT_EQ(model2->geom_rgba[0], 0.2);
|
||||||
|
|
||||||
|
model1->mesh_vert[0] = 0.3;
|
||||||
|
model1->geom_rgba[0] = 0.4;
|
||||||
|
mjv_copyModel(model2, model1);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
using ValidateReferencesTest = MujocoTest;
|
using ValidateReferencesTest = MujocoTest;
|
||||||
|
|
||||||
TEST_F(ValidateReferencesTest, BodyReferences) {
|
TEST_F(ValidateReferencesTest, BodyReferences) {
|
||||||
|
|||||||
@@ -6940,6 +6940,9 @@ public static unsafe extern void mjv_updateScene(mjModel_* m, mjData_* d, mjvOpt
|
|||||||
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static unsafe extern int mjv_updateSceneFromState(mjvSceneState_* scnstate, mjvOption_* opt, mjvPerturb_* pert, mjvCamera_* cam, int catmask, mjvScene_* scn);
|
public static unsafe extern int mjv_updateSceneFromState(mjvSceneState_* scnstate, mjvOption_* opt, mjvPerturb_* pert, mjvCamera_* cam, int catmask, mjvScene_* scn);
|
||||||
|
|
||||||
|
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static unsafe extern void mjv_copyModel(mjModel_* dest, mjModel_* src);
|
||||||
|
|
||||||
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("mujoco", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static unsafe extern void mjv_defaultSceneState(mjvSceneState_* scnstate);
|
public static unsafe extern void mjv_defaultSceneState(mjvSceneState_* scnstate);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user