Canonicalize mjVisual macros to include type and dimension.

PiperOrigin-RevId: 928506110
Change-Id: If5d031f9d87892f13486ae9ccde23c16131212de
This commit is contained in:
Yuval Tassa
2026-06-08 05:30:15 -07:00
committed by Copybara-Service
parent da5500c202
commit 6c33e16bf1
5 changed files with 132 additions and 137 deletions
+77 -77
View File
@@ -66,27 +66,27 @@
//-------------------------------- mjVisual -------------------------------------------------------- //-------------------------------- mjVisual --------------------------------------------------------
// fields of mjVisual // fields of mjVisual
#define MJVISUAL_GLOBAL_FIELDS \ #define MJVISUAL_GLOBAL_FIELDS \
X( int, cameraid ) \ X ( int, cameraid, 1 ) \
X( int, orthographic ) \ X ( int, orthographic, 1 ) \
X( float, fovy ) \ X ( float, fovy, 1 ) \
X( float, ipd ) \ X ( float, ipd, 1 ) \
X( float, azimuth ) \ X ( float, azimuth, 1 ) \
X( float, elevation ) \ X ( float, elevation, 1 ) \
X( float, linewidth ) \ X ( float, linewidth, 1 ) \
X( float, glow ) \ X ( float, glow, 1 ) \
X( float, realtime ) \ X ( float, realtime, 1 ) \
X( int, offwidth ) \ X ( int, offwidth, 1 ) \
X( int, offheight ) \ X ( int, offheight, 1 ) \
X( int, ellipsoidinertia ) \ X ( int, ellipsoidinertia, 1 ) \
X( int, bvactive ) X ( int, bvactive, 1 )
#define MJVISUAL_QUALITY_FIELDS \ #define MJVISUAL_QUALITY_FIELDS \
X( shadowsize ) \ X ( int, shadowsize, 1 ) \
X( offsamples ) \ X ( int, offsamples, 1 ) \
X( numslices ) \ X ( int, numslices, 1 ) \
X( numstacks ) \ X ( int, numstacks, 1 ) \
X( numquads ) X ( int, numquads, 1 )
#define MJVISUAL_HEADLIGHT_FIELDS \ #define MJVISUAL_HEADLIGHT_FIELDS \
XVEC( float, ambient, 3 ) \ XVEC( float, ambient, 3 ) \
@@ -94,66 +94,66 @@
XVEC( float, specular, 3 ) \ XVEC( float, specular, 3 ) \
X ( int, active, 1 ) X ( int, active, 1 )
#define MJVISUAL_MAP_FIELDS \ #define MJVISUAL_MAP_FIELDS \
X( stiffness ) \ X ( float, stiffness, 1 ) \
X( stiffnessrot ) \ X ( float, stiffnessrot, 1 ) \
X( force ) \ X ( float, force, 1 ) \
X( torque ) \ X ( float, torque, 1 ) \
X( alpha ) \ X ( float, alpha, 1 ) \
X( fogstart ) \ X ( float, fogstart, 1 ) \
X( fogend ) \ X ( float, fogend, 1 ) \
X( znear ) \ X ( float, znear, 1 ) \
X( zfar ) \ X ( float, zfar, 1 ) \
X( haze ) \ X ( float, haze, 1 ) \
X( shadowclip ) \ X ( float, shadowclip, 1 ) \
X( shadowscale ) \ X ( float, shadowscale, 1 ) \
X( actuatortendon ) X ( float, actuatortendon, 1 )
#define MJVISUAL_SCALE_FIELDS \ #define MJVISUAL_SCALE_FIELDS \
X( forcewidth ) \ X ( float, forcewidth, 1 ) \
X( contactwidth ) \ X ( float, contactwidth, 1 ) \
X( contactheight ) \ X ( float, contactheight, 1 ) \
X( connect ) \ X ( float, connect, 1 ) \
X( com ) \ X ( float, com, 1 ) \
X( camera ) \ X ( float, camera, 1 ) \
X( light ) \ X ( float, light, 1 ) \
X( selectpoint ) \ X ( float, selectpoint, 1 ) \
X( jointlength ) \ X ( float, jointlength, 1 ) \
X( jointwidth ) \ X ( float, jointwidth, 1 ) \
X( actuatorlength ) \ X ( float, actuatorlength, 1 ) \
X( actuatorwidth ) \ X ( float, actuatorwidth, 1 ) \
X( framelength ) \ X ( float, framelength, 1 ) \
X( framewidth ) \ X ( float, framewidth, 1 ) \
X( constraint ) \ X ( float, constraint, 1 ) \
X( slidercrank ) \ X ( float, slidercrank, 1 ) \
X( frustum ) X ( float, frustum, 1 )
#define MJVISUAL_RGBA_FIELDS \ #define MJVISUAL_RGBA_FIELDS \
X( fog ) \ XVEC( float, fog, 4 ) \
X( haze ) \ XVEC( float, haze, 4 ) \
X( force ) \ XVEC( float, force, 4 ) \
X( inertia ) \ XVEC( float, inertia, 4 ) \
X( joint ) \ XVEC( float, joint, 4 ) \
X( actuator ) \ XVEC( float, actuator, 4 ) \
X( actuatornegative ) \ XVEC( float, actuatornegative, 4 ) \
X( actuatorpositive ) \ XVEC( float, actuatorpositive, 4 ) \
X( com ) \ XVEC( float, com, 4 ) \
X( camera ) \ XVEC( float, camera, 4 ) \
X( light ) \ XVEC( float, light, 4 ) \
X( selectpoint ) \ XVEC( float, selectpoint, 4 ) \
X( connect ) \ XVEC( float, connect, 4 ) \
X( contactpoint ) \ XVEC( float, contactpoint, 4 ) \
X( contactforce ) \ XVEC( float, contactforce, 4 ) \
X( contactfriction ) \ XVEC( float, contactfriction, 4 ) \
X( contacttorque ) \ XVEC( float, contacttorque, 4 ) \
X( contactgap ) \ XVEC( float, contactgap, 4 ) \
X( rangefinder ) \ XVEC( float, rangefinder, 4 ) \
X( constraint ) \ XVEC( float, constraint, 4 ) \
X( slidercrank ) \ XVEC( float, slidercrank, 4 ) \
X( crankbroken ) \ XVEC( float, crankbroken, 4 ) \
X( frustum ) \ XVEC( float, frustum, 4 ) \
X( bv ) \ XVEC( float, bv, 4 ) \
X( bvactive ) XVEC( float, bvactive, 4 )
//-------------------------------- mjModel --------------------------------------------------------- //-------------------------------- mjModel ---------------------------------------------------------
+15 -10
View File
@@ -207,7 +207,7 @@ PYBIND11_MODULE(_structs, m) {
return raw::MjVisualGlobal(other); return raw::MjVisualGlobal(other);
}); });
DefineStructFunctions(mjVisualGlobal); DefineStructFunctions(mjVisualGlobal);
#define X(type, var) \ #define X(type, var, dim) \
mjVisualGlobal.def_readwrite(#var, &raw::MjVisualGlobal::var); mjVisualGlobal.def_readwrite(#var, &raw::MjVisualGlobal::var);
MJVISUAL_GLOBAL_FIELDS MJVISUAL_GLOBAL_FIELDS
#undef X #undef X
@@ -221,7 +221,8 @@ PYBIND11_MODULE(_structs, m) {
return raw::MjVisualQuality(other); return raw::MjVisualQuality(other);
}); });
DefineStructFunctions(mjVisualQuality); 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 MJVISUAL_QUALITY_FIELDS
#undef X #undef X
@@ -254,7 +255,8 @@ PYBIND11_MODULE(_structs, m) {
return raw::MjVisualMap(other); return raw::MjVisualMap(other);
}); });
DefineStructFunctions(mjVisualMap); 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 MJVISUAL_MAP_FIELDS
#undef X #undef X
@@ -267,7 +269,8 @@ PYBIND11_MODULE(_structs, m) {
return raw::MjVisualScale(other); return raw::MjVisualScale(other);
}); });
DefineStructFunctions(mjVisualScale); 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 MJVISUAL_SCALE_FIELDS
#undef X #undef X
@@ -280,9 +283,10 @@ PYBIND11_MODULE(_structs, m) {
return MjVisualRgbaWrapper(other); return MjVisualRgbaWrapper(other);
}); });
DefineStructFunctions(mjVisualRgba); DefineStructFunctions(mjVisualRgba);
#define X(var) DefinePyArray(mjVisualRgba, #var, &MjVisualRgbaWrapper::var); #define XVEC(type, var, dim) \
DefinePyArray(mjVisualRgba, #var, &MjVisualRgbaWrapper::var);
MJVISUAL_RGBA_FIELDS MJVISUAL_RGBA_FIELDS
#undef X #undef XVEC
#define X(var) \ #define X(var) \
mjVisual.def_property_readonly( \ 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); X(int, nupdate);
#undef X #undef X
// ==================== MJPRECONTACT ========================================== // ==================== MJPRECONTACT =========================================
py::class_<MjPreContactWrapper> mjPreContact(m, "MjPreContact"); py::class_<MjPreContactWrapper> mjPreContact(m, "MjPreContact");
mjPreContact.def(py::init<>()); mjPreContact.def(py::init<>());
mjPreContact.def("__copy__", [](const MjPreContactWrapper& self) { mjPreContact.def("__copy__", [](const MjPreContactWrapper& self) {
return MjPreContactWrapper(self); return MjPreContactWrapper(self);
}); });
mjPreContact.def("__deepcopy__", [](const MjPreContactWrapper& self, py::dict) { mjPreContact.def("__deepcopy__",
return MjPreContactWrapper(self); [](const MjPreContactWrapper& self, py::dict) {
}); return MjPreContactWrapper(self);
});
DefineStructFunctions(mjPreContact); DefineStructFunctions(mjPreContact);
#define X(var) \ #define X(var) \
+5 -5
View File
@@ -270,12 +270,12 @@ class MjWrapper<raw::MjVisualRgba> : public WrapperBase<raw::MjVisualRgba> {
MjWrapper(raw::MjVisualRgba* ptr, pybind11::handle owner); MjWrapper(raw::MjVisualRgba* ptr, pybind11::handle owner);
~MjWrapper() = default; ~MjWrapper() = default;
#define X(var) \ #define XVEC(type, var, dim) \
py_array_or_tuple_t< \ py_array_or_tuple_t< \
std::remove_all_extents_t<decltype(raw::MjVisualRgba::var)>> \ std::remove_all_extents_t<decltype(raw::MjVisualRgba::var)>> \
var; var;
MJVISUAL_RGBA_FIELDS MJVISUAL_RGBA_FIELDS
#undef X #undef XVEC
}; };
using MjVisualRgbaWrapper = MjWrapper<raw::MjVisualRgba>; using MjVisualRgbaWrapper = MjWrapper<raw::MjVisualRgba>;
+7 -8
View File
@@ -633,7 +633,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char*
fprintf(fp, "VISUAL\n"); fprintf(fp, "VISUAL\n");
fprintf(fp, " GLOBAL\n"); fprintf(fp, " GLOBAL\n");
#define X(type, name) \ #define X(type, name, sz) \
fprintf(fp, NAME_FORMAT, " " #name); \ fprintf(fp, NAME_FORMAT, " " #name); \
{ \ { \
const char* format = \ const char* format = \
@@ -646,7 +646,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char*
#undef X #undef X
fprintf(fp, " QUALITY\n"); fprintf(fp, " QUALITY\n");
#define X(name) \ #define X(type, name, sz) \
fprintf(fp, NAME_FORMAT, " " #name); \ fprintf(fp, NAME_FORMAT, " " #name); \
fprintf(fp, INT_FORMAT, m->vis.quality.name); \ fprintf(fp, INT_FORMAT, m->vis.quality.name); \
fprintf(fp, "\n"); fprintf(fp, "\n");
@@ -680,7 +680,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char*
#undef X #undef X
fprintf(fp, " MAP\n"); fprintf(fp, " MAP\n");
#define X(name) \ #define X(type, name, sz) \
fprintf(fp, NAME_FORMAT, " " #name); \ fprintf(fp, NAME_FORMAT, " " #name); \
fprintf(fp, float_format, m->vis.map.name); \ fprintf(fp, float_format, m->vis.map.name); \
fprintf(fp, "\n"); fprintf(fp, "\n");
@@ -689,7 +689,7 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char*
#undef X #undef X
fprintf(fp, " SCALE\n"); fprintf(fp, " SCALE\n");
#define X(name) \ #define X(type, name, sz) \
fprintf(fp, NAME_FORMAT, " " #name); \ fprintf(fp, NAME_FORMAT, " " #name); \
fprintf(fp, float_format, m->vis.scale.name); \ fprintf(fp, float_format, m->vis.scale.name); \
fprintf(fp, "\n"); fprintf(fp, "\n");
@@ -698,17 +698,16 @@ void mj_printFormattedModel(const mjModel* m, const char* filename, const char*
#undef X #undef X
fprintf(fp, " RGBA\n"); fprintf(fp, " RGBA\n");
#define X(name) \ #define XVEC(type, name, sz) \
fprintf(fp, NAME_FORMAT, " " #name); \ 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, float_format, m->vis.rgba.name[i]); \
} \ } \
} \ } \
fprintf(fp, "\n"); fprintf(fp, "\n");
MJVISUAL_RGBA_FIELDS MJVISUAL_RGBA_FIELDS
#undef X #undef XVEC
fprintf(fp, "\n"); fprintf(fp, "\n");
// total mass // total mass
+28 -37
View File
@@ -153,14 +153,8 @@ TEST_F(HeaderTest, MjVisualFields) {
mjVisual v; mjVisual v;
std::vector<std::pair<const void*, const char*>> fields; std::vector<std::pair<const void*, const char*>> 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 // check that all X macros have the correct type and dim
#define X(type, name) \ #define X(type, name, dim) \
static_assert( \ static_assert( \
std::is_same_v<decltype(v.global.name), type>, \ std::is_same_v<decltype(v.global.name), type>, \
"incorrect type for mjVisual::global::" #name); "incorrect type for mjVisual::global::" #name);
@@ -169,10 +163,9 @@ TEST_F(HeaderTest, MjVisualFields) {
#undef X #undef X
#define X(name) \ #define X(type, name, dim) \
static_assert( \ static_assert(std::is_same_v<decltype(v.quality.name), type>, \
std::is_same_v<decltype(v.quality.name), QualityMemberType>, \ "incorrect type for mjVisual::quality::" #name);
"incorrect type for mjVisual::quality::" #name);
MJVISUAL_QUALITY_FIELDS MJVISUAL_QUALITY_FIELDS
@@ -185,8 +178,8 @@ TEST_F(HeaderTest, MjVisualFields) {
#define X(type, name, dim) \ #define X(type, name, dim) \
static_assert(dim == 1, "use XVEC for non-scalar fields"); \ static_assert(dim == 1, "use XVEC for non-scalar fields"); \
XIMPL(type, name, dim) XIMPL(type, name, dim)
#define XVEC(type, name, dim) \ #define XVEC(type, name, dim) \
static_assert(dim > 1, "use X for scalar fields"); \ static_assert(dim > 1, "use X for scalar fields"); \
XIMPL(type, name, dim) XIMPL(type, name, dim)
MJVISUAL_HEADLIGHT_FIELDS MJVISUAL_HEADLIGHT_FIELDS
@@ -194,39 +187,37 @@ TEST_F(HeaderTest, MjVisualFields) {
#undef X #undef X
#undef XVEC #undef XVEC
#define X(name) \ #define X(type, name, dim) \
static_assert( \ static_assert(std::is_same_v<decltype(v.map.name), type>, \
std::is_same_v<decltype(v.map.name), MapMemberType>, \ "incorrect type for mjVisual::map::" #name);
"incorrect type for mjVisual::map::" #name);
MJVISUAL_MAP_FIELDS MJVISUAL_MAP_FIELDS
#undef X #undef X
#define X(name) \ #define X(type, name, dim) \
static_assert( \ static_assert(std::is_same_v<decltype(v.scale.name), type>, \
std::is_same_v<decltype(v.scale.name), ScaleMemberType>, \ "incorrect type for mjVisual::scale::" #name);
"incorrect type for mjVisual::scale::" #name);
MJVISUAL_SCALE_FIELDS MJVISUAL_SCALE_FIELDS
#undef X #undef X
#define X(name) \ #define XVEC(type, name, dim) \
static_assert( \ static_assert( \
std::is_same_v<decltype(v.rgba.name), RgbaMemberType>, \ std::is_same_v<decltype(v.rgba.name), ArrayOrScalarT<type, dim>>, \
"incorrect type for mjVisual::rgba::" #name); "incorrect type for mjVisual::rgba::" #name);
MJVISUAL_RGBA_FIELDS MJVISUAL_RGBA_FIELDS
#undef X #undef XVEC
// check that the ordering of X macros agrees with the struct fields // 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<const void*>(&v.global.name), #name}); fields.push_back({static_cast<const void*>(&v.global.name), #name});
MJVISUAL_GLOBAL_FIELDS MJVISUAL_GLOBAL_FIELDS
#undef X #undef X
#define X(name) \ #define X(type, name, dim) \
fields.push_back({static_cast<const void*>(&v.quality.name), #name}); fields.push_back({static_cast<const void*>(&v.quality.name), #name});
MJVISUAL_QUALITY_FIELDS MJVISUAL_QUALITY_FIELDS
#undef X #undef X
@@ -236,30 +227,30 @@ TEST_F(HeaderTest, MjVisualFields) {
MJVISUAL_HEADLIGHT_FIELDS MJVISUAL_HEADLIGHT_FIELDS
#undef XVEC #undef XVEC
#undef X #undef X
#define X(name) \ #define X(type, name, dim) \
fields.push_back({static_cast<const void*>(&v.map.name), #name}); fields.push_back({static_cast<const void*>(&v.map.name), #name});
MJVISUAL_MAP_FIELDS MJVISUAL_MAP_FIELDS
#undef X #undef X
#define X(name) \ #define X(type, name, dim) \
fields.push_back({static_cast<const void*>(&v.scale.name), #name}); fields.push_back({static_cast<const void*>(&v.scale.name), #name});
MJVISUAL_SCALE_FIELDS MJVISUAL_SCALE_FIELDS
#undef X #undef X
#define X(name) \ #define XVEC(type, name, dim) \
fields.push_back({static_cast<const void*>(&v.rgba.name), #name}); fields.push_back({static_cast<const void*>(&v.rgba.name), #name});
MJVISUAL_RGBA_FIELDS MJVISUAL_RGBA_FIELDS
#undef X #undef XVEC
CheckAddressOrdering(fields, "MJVISUAL_FIELDS"); CheckAddressOrdering(fields, "MJVISUAL_FIELDS");
// check that MJVISUAL_FIELDS is a complete list of fields // check that MJVISUAL_FIELDS is a complete list of fields
struct ExpectedMjVisual { struct ExpectedMjVisual {
struct { struct {
#define X(type, name) type name; #define X(type, name, dim) type name;
MJVISUAL_GLOBAL_FIELDS; MJVISUAL_GLOBAL_FIELDS;
#undef X #undef X
} global; } global;
struct { struct {
#define X(name) QualityMemberType name; #define X(type, name, dim) type name;
MJVISUAL_QUALITY_FIELDS; MJVISUAL_QUALITY_FIELDS;
#undef X #undef X
} quality; } quality;
@@ -271,19 +262,19 @@ TEST_F(HeaderTest, MjVisualFields) {
#undef X #undef X
} headlight; } headlight;
struct { struct {
#define X(name) MapMemberType name; #define X(type, name, dim) type name;
MJVISUAL_MAP_FIELDS; MJVISUAL_MAP_FIELDS;
#undef X #undef X
} map; } map;
struct { struct {
#define X(name) ScaleMemberType name; #define X(type, name, dim) type name;
MJVISUAL_SCALE_FIELDS; MJVISUAL_SCALE_FIELDS;
#undef X #undef X
} scale; } scale;
struct { struct {
#define X(name) RgbaMemberType name; #define XVEC(type, name, dim) type name[dim];
MJVISUAL_RGBA_FIELDS; MJVISUAL_RGBA_FIELDS;
#undef X #undef XVEC
} rgba; } rgba;
}; };