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.
|
||||
|
||||
.. _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>`__
|
||||
|
||||
@@ -3347,6 +3347,7 @@ void mjv_updateScene(const mjModel* m, mjData* d, const mjvOption* opt,
|
||||
int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOption* opt,
|
||||
const mjvPerturb* pert, mjvCamera* cam, int catmask,
|
||||
mjvScene* scn);
|
||||
void mjv_copyModel(mjModel* dest, const mjModel* src);
|
||||
void mjv_defaultSceneState(mjvSceneState* scnstate);
|
||||
void mjv_makeSceneState(const mjModel* m, const mjData* d,
|
||||
mjvSceneState* scnstate, int maxgeom);
|
||||
|
||||
@@ -378,13 +378,13 @@
|
||||
X ( mjtNum, mesh_scale, nmesh, 3 ) \
|
||||
X ( mjtNum, mesh_pos, nmesh, 3 ) \
|
||||
X ( mjtNum, mesh_quat, nmesh, 4 ) \
|
||||
X ( float, mesh_vert, nmeshvert, 3 ) \
|
||||
X ( float, mesh_normal, nmeshnormal, 3 ) \
|
||||
X ( float, mesh_texcoord, nmeshtexcoord, 2 ) \
|
||||
X ( int, mesh_face, nmeshface, 3 ) \
|
||||
X ( int, mesh_facenormal, nmeshface, 3 ) \
|
||||
X ( int, mesh_facetexcoord, nmeshface, 3 ) \
|
||||
X ( int, mesh_graph, nmeshgraph, 1 ) \
|
||||
XNV ( float, mesh_vert, nmeshvert, 3 ) \
|
||||
XNV ( float, mesh_normal, nmeshnormal, 3 ) \
|
||||
XNV ( float, mesh_texcoord, nmeshtexcoord, 2 ) \
|
||||
XNV ( int, mesh_face, nmeshface, 3 ) \
|
||||
XNV ( int, mesh_facenormal, nmeshface, 3 ) \
|
||||
XNV ( int, mesh_facetexcoord, nmeshface, 3 ) \
|
||||
XNV ( int, mesh_graph, nmeshgraph, 1 ) \
|
||||
XMJV( int, mesh_pathadr, nmesh, 1 ) \
|
||||
XMJV( int, skin_matid, nskin, 1 ) \
|
||||
XMJV( int, skin_group, nskin, 1 ) \
|
||||
@@ -412,14 +412,14 @@
|
||||
X ( int, hfield_nrow, nhfield, 1 ) \
|
||||
X ( int, hfield_ncol, 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 ) \
|
||||
X ( int, tex_type, ntex, 1 ) \
|
||||
X ( int, tex_height, ntex, 1 ) \
|
||||
X ( int, tex_width, ntex, 1 ) \
|
||||
X ( int, tex_nchannel, 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, mat_texid, nmat, mjNTEXROLE ) \
|
||||
XMJV( mjtByte, mat_texuniform, nmat, 1 ) \
|
||||
@@ -779,4 +779,9 @@
|
||||
// redefine X to expand to nothing, and XMJV to do what's required
|
||||
#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_
|
||||
|
||||
@@ -692,6 +692,9 @@ MJAPI int mjv_updateSceneFromState(const mjvSceneState* scnstate, const mjvOptio
|
||||
const mjvPerturb* pert, mjvCamera* cam, int catmask,
|
||||
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.
|
||||
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
|
||||
)),
|
||||
('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',
|
||||
FunctionDecl(
|
||||
name='mjv_defaultSceneState',
|
||||
|
||||
+57
-23
@@ -625,10 +625,10 @@ void mj_makeModel(mjModel** dest,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// copy mjModel, if dest==NULL create new model
|
||||
mjModel* mj_copyModel(mjModel* dest, const mjModel* src) {
|
||||
void* save_bufptr;
|
||||
|
||||
// allocate new model if needed
|
||||
if (!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");
|
||||
}
|
||||
|
||||
// save buffer ptr, copy everything, restore buffer and other pointers
|
||||
save_bufptr = dest->buffer;
|
||||
// save buffer ptr, copy struct, restore buffer and other pointers
|
||||
void* save_bufptr = dest->buffer;
|
||||
*dest = *src;
|
||||
dest->buffer = save_bufptr;
|
||||
mj_setPtrModel(dest);
|
||||
|
||||
// copy buffer
|
||||
// copy buffer contents
|
||||
{
|
||||
MJMODEL_POINTERS_PREAMBLE(src)
|
||||
#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
|
||||
void mj_saveModel(const mjModel* m, const char* filename, void* buffer, int buffer_sz) {
|
||||
FILE* fp = 0;
|
||||
@@ -1401,26 +1433,28 @@ mjData* mj_copyData(mjData* dest, const mjModel* m, const mjData* src) {
|
||||
#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
|
||||
#undef X
|
||||
#undef MJ_M
|
||||
#define MJ_M(n) n
|
||||
#undef MJ_D
|
||||
#define MJ_D(n) n
|
||||
#undef X
|
||||
|
||||
#undef MJ_M
|
||||
#define MJ_M(n) n
|
||||
#undef MJ_D
|
||||
#define MJ_D(n) n
|
||||
|
||||
// restore contact pointer
|
||||
dest->contact = dest->arena;
|
||||
|
||||
@@ -69,6 +69,9 @@ void mj_makeModel(mjModel** dest,
|
||||
// copy mjModel; allocate new if dest is NULL
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)]
|
||||
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)]
|
||||
public static unsafe extern void mjv_defaultSceneState(mjvSceneState_* scnstate);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user