diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 3136e1c9..10725cfa 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -63,6 +63,100 @@ X( o_friction, 5 ) +//-------------------------------- mjStatistic ----------------------------------------------------- + +// fields of mjStatistic +#define MJSTATISTIC_FIELDS \ + X( mjtNum, meaninertia, 1 ) \ + X( mjtNum, meanmass, 1 ) \ + X( mjtNum, meansize, 1 ) \ + X( mjtNum, extent, 1 ) \ + X( mjtNum, center, 3 ) + + +//-------------------------------- mjVisual -------------------------------------------------------- + +// fields of mjVisual +#define MJVISUAL_FIELDS \ + X( global, int, cameraid, 1 ) \ + X( global, int, orthographic, 1 ) \ + X( global, float, fovy, 1 ) \ + X( global, float, ipd, 1 ) \ + X( global, float, azimuth, 1 ) \ + X( global, float, elevation, 1 ) \ + X( global, float, linewidth, 1 ) \ + X( global, float, glow, 1 ) \ + X( global, float, realtime, 1 ) \ + X( global, int, offwidth, 1 ) \ + X( global, int, offheight, 1 ) \ + X( global, int, ellipsoidinertia, 1 ) \ + X( global, int, bvactive, 1 ) \ + X( quality, int, shadowsize, 1 ) \ + X( quality, int, offsamples, 1 ) \ + X( quality, int, numslices, 1 ) \ + X( quality, int, numstacks, 1 ) \ + X( quality, int, numquads, 1 ) \ + X( headlight, float, ambient, 3 ) \ + X( headlight, float, diffuse, 3 ) \ + X( headlight, float, specular, 3 ) \ + X( headlight, int, active, 1 ) \ + X( map, float, stiffness, 1 ) \ + X( map, float, stiffnessrot, 1 ) \ + X( map, float, force, 1 ) \ + X( map, float, torque, 1 ) \ + X( map, float, alpha, 1 ) \ + X( map, float, fogstart, 1 ) \ + X( map, float, fogend, 1 ) \ + X( map, float, znear, 1 ) \ + X( map, float, zfar, 1 ) \ + X( map, float, haze, 1 ) \ + X( map, float, shadowclip, 1 ) \ + X( map, float, shadowscale, 1 ) \ + X( map, float, actuatortendon, 1 ) \ + X( scale, float, forcewidth, 1 ) \ + X( scale, float, contactwidth, 1 ) \ + X( scale, float, contactheight, 1 ) \ + X( scale, float, connect, 1 ) \ + X( scale, float, com, 1 ) \ + X( scale, float, camera, 1 ) \ + X( scale, float, light, 1 ) \ + X( scale, float, selectpoint, 1 ) \ + X( scale, float, jointlength, 1 ) \ + X( scale, float, jointwidth, 1 ) \ + X( scale, float, actuatorlength, 1 ) \ + X( scale, float, actuatorwidth, 1 ) \ + X( scale, float, framelength, 1 ) \ + X( scale, float, framewidth, 1 ) \ + X( scale, float, constraint, 1 ) \ + X( scale, float, slidercrank, 1 ) \ + X( scale, float, frustum, 1 ) \ + X( rgba, float, fog, 4 ) \ + X( rgba, float, haze, 4 ) \ + X( rgba, float, force, 4 ) \ + X( rgba, float, inertia, 4 ) \ + X( rgba, float, joint, 4 ) \ + X( rgba, float, actuator, 4 ) \ + X( rgba, float, actuatornegative, 4 ) \ + X( rgba, float, actuatorpositive, 4 ) \ + X( rgba, float, com, 4 ) \ + X( rgba, float, camera, 4 ) \ + X( rgba, float, light, 4 ) \ + X( rgba, float, selectpoint, 4 ) \ + X( rgba, float, connect, 4 ) \ + X( rgba, float, contactpoint, 4 ) \ + X( rgba, float, contactforce, 4 ) \ + X( rgba, float, contactfriction, 4 ) \ + X( rgba, float, contacttorque, 4 ) \ + X( rgba, float, contactgap, 4 ) \ + X( rgba, float, rangefinder, 4 ) \ + X( rgba, float, constraint, 4 ) \ + X( rgba, float, slidercrank, 4 ) \ + X( rgba, float, crankbroken, 4 ) \ + X( rgba, float, frustum, 4 ) \ + X( rgba, float, bv, 4 ) \ + X( rgba, float, bvactive, 4 ) + + //-------------------------------- mjModel --------------------------------------------------------- // size fields of mjModel diff --git a/test/header_test.cc b/test/header_test.cc index 48f6e74d..5ed22082 100644 --- a/test/header_test.cc +++ b/test/header_test.cc @@ -16,8 +16,10 @@ #include #include +#include #include #include + #include #include #include @@ -30,6 +32,17 @@ namespace mujoco { namespace { +template +struct ArrayOrScalar { + using type = T[N]; +}; +template +struct ArrayOrScalar { + using type = T; +}; +template +using ArrayOrScalarT = typename ArrayOrScalar::type; + // check that a vector of named pointers are ordered by address void CheckAddressOrdering( const std::vector>& pointers, @@ -121,6 +134,64 @@ TEST_F(HeaderTest, MjOptionVectorsOrdered) { CheckAddressOrdering(vectors, "MJOPTION_VECTORS"); } +TEST_F(HeaderTest, MjStatisticFields) { + mjStatistic s; + std::vector> fields; + + // check that all X macros have the correct type and dim +#define X(type, name, dim) \ + static_assert( \ + std::is_same_v>, \ + "incorrect type for mjStatistic::" #name); \ + MJSTATISTIC_FIELDS +#undef X + + // check that the ordering of X macros agrees with the struct fields +#define X(type, name, dim) \ + fields.push_back({static_cast(&s.name), #name}); + MJSTATISTIC_FIELDS +#undef X + + CheckAddressOrdering(fields, "MJSTATISTIC_FIELDS"); + + // check that MJSTATISTIC_FIELDS is a complete list of struct fields + struct ExpectedMjStatistic { +#define X(type, name, dim) type name[dim]; + MJSTATISTIC_FIELDS; +#undef X + }; + static_assert(sizeof(mjStatistic) == sizeof(ExpectedMjStatistic)); +} + +TEST_F(HeaderTest, MjVisualFields) { + mjVisual v; + std::vector> fields; + + // check that all X macros have the correct type and dim +#define X(substruct, type, name, dim) \ + static_assert( \ + std::is_same_v>, \ + "incorrect type for mjVisual::" #substruct "::" #name); \ + MJVISUAL_FIELDS +#undef X + + // check that the ordering of X macros agrees with the struct fields +#define X(substruct, type, name, dim) \ + fields.push_back({static_cast(&v.substruct.name), #name}); + MJVISUAL_FIELDS +#undef X + + CheckAddressOrdering(fields, "MJVISUAL_FIELDS"); + + // check that MJVISUAL_FIELDS is a complete list of fields + struct ExpectedMjVisual { +#define X(substruct, type, name, dim) type substruct##_##name[dim]; + MJVISUAL_FIELDS; +#undef X + }; + static_assert(sizeof(mjVisual) == sizeof(ExpectedMjVisual)); +} + TEST_F(HeaderTest, MjModelIntsOrdered) { mjModel m; std::vector> ints;