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 --------------------------------------------------------
// 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 ---------------------------------------------------------
+15 -10
View File
@@ -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_<MjPreContactWrapper> 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) \
+5 -5
View File
@@ -270,12 +270,12 @@ class MjWrapper<raw::MjVisualRgba> : public WrapperBase<raw::MjVisualRgba> {
MjWrapper(raw::MjVisualRgba* ptr, pybind11::handle owner);
~MjWrapper() = default;
#define X(var) \
py_array_or_tuple_t< \
std::remove_all_extents_t<decltype(raw::MjVisualRgba::var)>> \
var;
#define XVEC(type, var, dim) \
py_array_or_tuple_t< \
std::remove_all_extents_t<decltype(raw::MjVisualRgba::var)>> \
var;
MJVISUAL_RGBA_FIELDS
#undef X
#undef XVEC
};
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, " 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
+28 -37
View File
@@ -153,14 +153,8 @@ TEST_F(HeaderTest, MjVisualFields) {
mjVisual v;
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
#define X(type, name) \
#define X(type, name, dim) \
static_assert( \
std::is_same_v<decltype(v.global.name), type>, \
"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<decltype(v.quality.name), QualityMemberType>, \
"incorrect type for mjVisual::quality::" #name);
#define X(type, name, dim) \
static_assert(std::is_same_v<decltype(v.quality.name), type>, \
"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<decltype(v.map.name), MapMemberType>, \
"incorrect type for mjVisual::map::" #name);
#define X(type, name, dim) \
static_assert(std::is_same_v<decltype(v.map.name), type>, \
"incorrect type for mjVisual::map::" #name);
MJVISUAL_MAP_FIELDS
#undef X
#define X(name) \
static_assert( \
std::is_same_v<decltype(v.scale.name), ScaleMemberType>, \
"incorrect type for mjVisual::scale::" #name);
#define X(type, name, dim) \
static_assert(std::is_same_v<decltype(v.scale.name), type>, \
"incorrect type for mjVisual::scale::" #name);
MJVISUAL_SCALE_FIELDS
#undef X
#define X(name) \
static_assert( \
std::is_same_v<decltype(v.rgba.name), RgbaMemberType>, \
#define XVEC(type, name, dim) \
static_assert( \
std::is_same_v<decltype(v.rgba.name), ArrayOrScalarT<type, dim>>, \
"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<const void*>(&v.global.name), #name});
MJVISUAL_GLOBAL_FIELDS
#undef X
#define X(name) \
#define X(type, name, dim) \
fields.push_back({static_cast<const void*>(&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<const void*>(&v.map.name), #name});
MJVISUAL_MAP_FIELDS
#undef X
#define X(name) \
#define X(type, name, dim) \
fields.push_back({static_cast<const void*>(&v.scale.name), #name});
MJVISUAL_SCALE_FIELDS
#undef X
#define X(name) \
#define XVEC(type, name, dim) \
fields.push_back({static_cast<const void*>(&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;
};