diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 3bff5c53..fbd34918 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -66,27 +66,27 @@ //-------------------------------- mjVisual -------------------------------------------------------- // fields of mjVisual -#define MJVISUAL_GLOBAL_FIELDS \ - X( int, cameraid ) \ - X( int, orthographic ) \ - X( float, fovy ) \ - X( float, ipd ) \ - X( float, azimuth ) \ - X( float, elevation ) \ - X( float, linewidth ) \ - X( float, glow ) \ - X( float, realtime ) \ - X( int, offwidth ) \ - X( int, offheight ) \ - X( int, ellipsoidinertia ) \ - X( int, bvactive ) +#define MJVISUAL_GLOBAL_FIELDS \ + X ( int, cameraid, 1 ) \ + X ( int, orthographic, 1 ) \ + X ( float, fovy, 1 ) \ + X ( float, ipd, 1 ) \ + X ( float, azimuth, 1 ) \ + X ( float, elevation, 1 ) \ + X ( float, linewidth, 1 ) \ + X ( float, glow, 1 ) \ + X ( float, realtime, 1 ) \ + X ( int, offwidth, 1 ) \ + X ( int, offheight, 1 ) \ + X ( int, ellipsoidinertia, 1 ) \ + X ( int, bvactive, 1 ) #define MJVISUAL_QUALITY_FIELDS \ - X( shadowsize ) \ - X( offsamples ) \ - X( numslices ) \ - X( numstacks ) \ - X( numquads ) + X ( int, shadowsize, 1 ) \ + X ( int, offsamples, 1 ) \ + X ( int, numslices, 1 ) \ + X ( int, numstacks, 1 ) \ + X ( int, numquads, 1 ) #define MJVISUAL_HEADLIGHT_FIELDS \ XVEC( float, ambient, 3 ) \ @@ -94,66 +94,66 @@ XVEC( float, specular, 3 ) \ X ( int, active, 1 ) -#define MJVISUAL_MAP_FIELDS \ - X( stiffness ) \ - X( stiffnessrot ) \ - X( force ) \ - X( torque ) \ - X( alpha ) \ - X( fogstart ) \ - X( fogend ) \ - X( znear ) \ - X( zfar ) \ - X( haze ) \ - X( shadowclip ) \ - X( shadowscale ) \ - X( actuatortendon ) +#define MJVISUAL_MAP_FIELDS \ + X ( float, stiffness, 1 ) \ + X ( float, stiffnessrot, 1 ) \ + X ( float, force, 1 ) \ + X ( float, torque, 1 ) \ + X ( float, alpha, 1 ) \ + X ( float, fogstart, 1 ) \ + X ( float, fogend, 1 ) \ + X ( float, znear, 1 ) \ + X ( float, zfar, 1 ) \ + X ( float, haze, 1 ) \ + X ( float, shadowclip, 1 ) \ + X ( float, shadowscale, 1 ) \ + X ( float, actuatortendon, 1 ) -#define MJVISUAL_SCALE_FIELDS \ - X( forcewidth ) \ - X( contactwidth ) \ - X( contactheight ) \ - X( connect ) \ - X( com ) \ - X( camera ) \ - X( light ) \ - X( selectpoint ) \ - X( jointlength ) \ - X( jointwidth ) \ - X( actuatorlength ) \ - X( actuatorwidth ) \ - X( framelength ) \ - X( framewidth ) \ - X( constraint ) \ - X( slidercrank ) \ - X( frustum ) +#define MJVISUAL_SCALE_FIELDS \ + X ( float, forcewidth, 1 ) \ + X ( float, contactwidth, 1 ) \ + X ( float, contactheight, 1 ) \ + X ( float, connect, 1 ) \ + X ( float, com, 1 ) \ + X ( float, camera, 1 ) \ + X ( float, light, 1 ) \ + X ( float, selectpoint, 1 ) \ + X ( float, jointlength, 1 ) \ + X ( float, jointwidth, 1 ) \ + X ( float, actuatorlength, 1 ) \ + X ( float, actuatorwidth, 1 ) \ + X ( float, framelength, 1 ) \ + X ( float, framewidth, 1 ) \ + X ( float, constraint, 1 ) \ + X ( float, slidercrank, 1 ) \ + X ( float, frustum, 1 ) -#define MJVISUAL_RGBA_FIELDS \ - X( fog ) \ - X( haze ) \ - X( force ) \ - X( inertia ) \ - X( joint ) \ - X( actuator ) \ - X( actuatornegative ) \ - X( actuatorpositive ) \ - X( com ) \ - X( camera ) \ - X( light ) \ - X( selectpoint ) \ - X( connect ) \ - X( contactpoint ) \ - X( contactforce ) \ - X( contactfriction ) \ - X( contacttorque ) \ - X( contactgap ) \ - X( rangefinder ) \ - X( constraint ) \ - X( slidercrank ) \ - X( crankbroken ) \ - X( frustum ) \ - X( bv ) \ - X( bvactive ) +#define MJVISUAL_RGBA_FIELDS \ + XVEC( float, fog, 4 ) \ + XVEC( float, haze, 4 ) \ + XVEC( float, force, 4 ) \ + XVEC( float, inertia, 4 ) \ + XVEC( float, joint, 4 ) \ + XVEC( float, actuator, 4 ) \ + XVEC( float, actuatornegative, 4 ) \ + XVEC( float, actuatorpositive, 4 ) \ + XVEC( float, com, 4 ) \ + XVEC( float, camera, 4 ) \ + XVEC( float, light, 4 ) \ + XVEC( float, selectpoint, 4 ) \ + XVEC( float, connect, 4 ) \ + XVEC( float, contactpoint, 4 ) \ + XVEC( float, contactforce, 4 ) \ + XVEC( float, contactfriction, 4 ) \ + XVEC( float, contacttorque, 4 ) \ + XVEC( float, contactgap, 4 ) \ + XVEC( float, rangefinder, 4 ) \ + XVEC( float, constraint, 4 ) \ + XVEC( float, slidercrank, 4 ) \ + XVEC( float, crankbroken, 4 ) \ + XVEC( float, frustum, 4 ) \ + XVEC( float, bv, 4 ) \ + XVEC( float, bvactive, 4 ) //-------------------------------- mjModel --------------------------------------------------------- diff --git a/python/mujoco/structs.cc b/python/mujoco/structs.cc index a07f89b1..729387e8 100644 --- a/python/mujoco/structs.cc +++ b/python/mujoco/structs.cc @@ -207,7 +207,7 @@ PYBIND11_MODULE(_structs, m) { return raw::MjVisualGlobal(other); }); DefineStructFunctions(mjVisualGlobal); -#define X(type, var) \ +#define X(type, var, dim) \ mjVisualGlobal.def_readwrite(#var, &raw::MjVisualGlobal::var); MJVISUAL_GLOBAL_FIELDS #undef X @@ -221,7 +221,8 @@ PYBIND11_MODULE(_structs, m) { return raw::MjVisualQuality(other); }); DefineStructFunctions(mjVisualQuality); -#define X(var) mjVisualQuality.def_readwrite(#var, &raw::MjVisualQuality::var); +#define X(type, var, dim) \ + mjVisualQuality.def_readwrite(#var, &raw::MjVisualQuality::var); MJVISUAL_QUALITY_FIELDS #undef X @@ -254,7 +255,8 @@ PYBIND11_MODULE(_structs, m) { return raw::MjVisualMap(other); }); DefineStructFunctions(mjVisualMap); -#define X(var) mjVisualMap.def_readwrite(#var, &raw::MjVisualMap::var); +#define X(type, var, dim) \ + mjVisualMap.def_readwrite(#var, &raw::MjVisualMap::var); MJVISUAL_MAP_FIELDS #undef X @@ -267,7 +269,8 @@ PYBIND11_MODULE(_structs, m) { return raw::MjVisualScale(other); }); DefineStructFunctions(mjVisualScale); -#define X(var) mjVisualScale.def_readwrite(#var, &raw::MjVisualScale::var); +#define X(type, var, dim) \ + mjVisualScale.def_readwrite(#var, &raw::MjVisualScale::var); MJVISUAL_SCALE_FIELDS #undef X @@ -280,9 +283,10 @@ PYBIND11_MODULE(_structs, m) { return MjVisualRgbaWrapper(other); }); DefineStructFunctions(mjVisualRgba); -#define X(var) DefinePyArray(mjVisualRgba, #var, &MjVisualRgbaWrapper::var); +#define XVEC(type, var, dim) \ + DefinePyArray(mjVisualRgba, #var, &MjVisualRgbaWrapper::var); MJVISUAL_RGBA_FIELDS -#undef X +#undef XVEC #define X(var) \ mjVisual.def_property_readonly( \ @@ -615,15 +619,16 @@ This is useful for example when the MJB is not available as a file on disk.)")); X(int, nupdate); #undef X - // ==================== MJPRECONTACT ========================================== + // ==================== MJPRECONTACT ========================================= py::class_ mjPreContact(m, "MjPreContact"); mjPreContact.def(py::init<>()); mjPreContact.def("__copy__", [](const MjPreContactWrapper& self) { return MjPreContactWrapper(self); }); - mjPreContact.def("__deepcopy__", [](const MjPreContactWrapper& self, py::dict) { - return MjPreContactWrapper(self); - }); + mjPreContact.def("__deepcopy__", + [](const MjPreContactWrapper& self, py::dict) { + return MjPreContactWrapper(self); + }); DefineStructFunctions(mjPreContact); #define X(var) \ diff --git a/python/mujoco/structs.h b/python/mujoco/structs.h index 60bcf558..4bf3dd98 100644 --- a/python/mujoco/structs.h +++ b/python/mujoco/structs.h @@ -270,12 +270,12 @@ class MjWrapper : public WrapperBase { MjWrapper(raw::MjVisualRgba* ptr, pybind11::handle owner); ~MjWrapper() = default; - #define X(var) \ - py_array_or_tuple_t< \ - std::remove_all_extents_t> \ - var; +#define XVEC(type, var, dim) \ + py_array_or_tuple_t< \ + std::remove_all_extents_t> \ + var; MJVISUAL_RGBA_FIELDS - #undef X +#undef XVEC }; using MjVisualRgbaWrapper = MjWrapper; diff --git a/src/engine/engine_print.c b/src/engine/engine_print.c index b5c92ffe..3e5e04ed 100644 --- a/src/engine/engine_print.c +++ b/src/engine/engine_print.c @@ -633,7 +633,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char* fprintf(fp, "VISUAL\n"); fprintf(fp, " GLOBAL\n"); -#define X(type, name) \ +#define X(type, name, sz) \ fprintf(fp, NAME_FORMAT, " " #name); \ { \ const char* format = \ @@ -646,7 +646,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char* #undef X fprintf(fp, " QUALITY\n"); -#define X(name) \ +#define X(type, name, sz) \ fprintf(fp, NAME_FORMAT, " " #name); \ fprintf(fp, INT_FORMAT, m->vis.quality.name); \ fprintf(fp, "\n"); @@ -680,7 +680,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char* #undef X fprintf(fp, " MAP\n"); -#define X(name) \ +#define X(type, name, sz) \ fprintf(fp, NAME_FORMAT, " " #name); \ fprintf(fp, float_format, m->vis.map.name); \ fprintf(fp, "\n"); @@ -689,7 +689,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char* #undef X fprintf(fp, " SCALE\n"); -#define X(name) \ +#define X(type, name, sz) \ fprintf(fp, NAME_FORMAT, " " #name); \ fprintf(fp, float_format, m->vis.scale.name); \ fprintf(fp, "\n"); @@ -698,17 +698,16 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char* #undef X fprintf(fp, " RGBA\n"); -#define X(name) \ +#define XVEC(type, name, sz) \ fprintf(fp, NAME_FORMAT, " " #name); \ { \ - for (int i = 0; i < 4; i++) { \ + for (int i = 0; i < sz; i++) { \ fprintf(fp, float_format, m->vis.rgba.name[i]); \ } \ } \ fprintf(fp, "\n"); - MJVISUAL_RGBA_FIELDS -#undef X +#undef XVEC fprintf(fp, "\n"); // total mass diff --git a/test/header_test.cc b/test/header_test.cc index 3de549d2..6156e98a 100644 --- a/test/header_test.cc +++ b/test/header_test.cc @@ -153,14 +153,8 @@ TEST_F(HeaderTest, MjVisualFields) { mjVisual v; std::vector> fields; - // All member fields in quality, map, scale, and rgba have the same type. - using QualityMemberType = int; - using MapMemberType = float; - using ScaleMemberType = float; - using RgbaMemberType = float[4]; - // check that all X macros have the correct type and dim -#define X(type, name) \ +#define X(type, name, dim) \ static_assert( \ std::is_same_v, \ "incorrect type for mjVisual::global::" #name); @@ -169,10 +163,9 @@ TEST_F(HeaderTest, MjVisualFields) { #undef X -#define X(name) \ - static_assert( \ - std::is_same_v, \ - "incorrect type for mjVisual::quality::" #name); +#define X(type, name, dim) \ + static_assert(std::is_same_v, \ + "incorrect type for mjVisual::quality::" #name); MJVISUAL_QUALITY_FIELDS @@ -185,8 +178,8 @@ TEST_F(HeaderTest, MjVisualFields) { #define X(type, name, dim) \ static_assert(dim == 1, "use XVEC for non-scalar fields"); \ XIMPL(type, name, dim) -#define XVEC(type, name, dim) \ - static_assert(dim > 1, "use X for scalar fields"); \ +#define XVEC(type, name, dim) \ + static_assert(dim > 1, "use X for scalar fields"); \ XIMPL(type, name, dim) MJVISUAL_HEADLIGHT_FIELDS @@ -194,39 +187,37 @@ TEST_F(HeaderTest, MjVisualFields) { #undef X #undef XVEC -#define X(name) \ - static_assert( \ - std::is_same_v, \ - "incorrect type for mjVisual::map::" #name); +#define X(type, name, dim) \ + static_assert(std::is_same_v, \ + "incorrect type for mjVisual::map::" #name); MJVISUAL_MAP_FIELDS #undef X -#define X(name) \ - static_assert( \ - std::is_same_v, \ - "incorrect type for mjVisual::scale::" #name); +#define X(type, name, dim) \ + static_assert(std::is_same_v, \ + "incorrect type for mjVisual::scale::" #name); MJVISUAL_SCALE_FIELDS #undef X -#define X(name) \ - static_assert( \ - std::is_same_v, \ +#define XVEC(type, name, dim) \ + static_assert( \ + std::is_same_v>, \ "incorrect type for mjVisual::rgba::" #name); MJVISUAL_RGBA_FIELDS -#undef X +#undef XVEC // check that the ordering of X macros agrees with the struct fields -#define X(type, name) \ +#define X(type, name, dim) \ fields.push_back({static_cast(&v.global.name), #name}); MJVISUAL_GLOBAL_FIELDS #undef X -#define X(name) \ +#define X(type, name, dim) \ fields.push_back({static_cast(&v.quality.name), #name}); MJVISUAL_QUALITY_FIELDS #undef X @@ -236,30 +227,30 @@ TEST_F(HeaderTest, MjVisualFields) { MJVISUAL_HEADLIGHT_FIELDS #undef XVEC #undef X -#define X(name) \ +#define X(type, name, dim) \ fields.push_back({static_cast(&v.map.name), #name}); MJVISUAL_MAP_FIELDS #undef X -#define X(name) \ +#define X(type, name, dim) \ fields.push_back({static_cast(&v.scale.name), #name}); MJVISUAL_SCALE_FIELDS #undef X -#define X(name) \ +#define XVEC(type, name, dim) \ fields.push_back({static_cast(&v.rgba.name), #name}); MJVISUAL_RGBA_FIELDS -#undef X +#undef XVEC CheckAddressOrdering(fields, "MJVISUAL_FIELDS"); // check that MJVISUAL_FIELDS is a complete list of fields struct ExpectedMjVisual { struct { -#define X(type, name) type name; +#define X(type, name, dim) type name; MJVISUAL_GLOBAL_FIELDS; #undef X } global; struct { -#define X(name) QualityMemberType name; +#define X(type, name, dim) type name; MJVISUAL_QUALITY_FIELDS; #undef X } quality; @@ -271,19 +262,19 @@ TEST_F(HeaderTest, MjVisualFields) { #undef X } headlight; struct { -#define X(name) MapMemberType name; +#define X(type, name, dim) type name; MJVISUAL_MAP_FIELDS; #undef X } map; struct { -#define X(name) ScaleMemberType name; +#define X(type, name, dim) type name; MJVISUAL_SCALE_FIELDS; #undef X } scale; struct { -#define X(name) RgbaMemberType name; +#define XVEC(type, name, dim) type name[dim]; MJVISUAL_RGBA_FIELDS; -#undef X +#undef XVEC } rgba; };