Track authored flags for global attributes

PiperOrigin-RevId: 931585539
Change-Id: Ifdc8c59de6c5a553daf6e0af09d8192aff6b0610
This commit is contained in:
Yuval Tassa
2026-06-13 02:57:52 -07:00
committed by Copybara-Service
parent 0ea9c7cb3a
commit 67a1ea6dca
21 changed files with 823 additions and 195 deletions
@@ -82,8 +82,10 @@ def _value_binding_code(
field.name == 'mjsPlugin'
or field.name == 'mjsOrientation'
or field.name == 'mjsCompiler'
or field.name == 'mjsAuthored'
):
fulltype = fulltype + '&' # plugin, orientation, compiler aren't pointers
# plugin, orientation, compiler, authored aren't pointers
fulltype = fulltype + '&'
else:
fulltype = fulltype + '*'
# non-mjs structs
+67
View File
@@ -6996,6 +6996,68 @@ STRUCTS: Mapping[str, StructDecl] = dict([
),
doc='texture directory',
),
StructFieldDecl(
name='authored',
type=ValueType(name='uint64_t'),
doc='bitmask of authored compiler fields',
),
),
)),
('mjsAuthored',
StructDecl(
name='mjsAuthored',
declname='struct mjsAuthored_',
fields=(
StructFieldDecl(
name='option',
type=ValueType(name='uint64_t'),
doc='authored mjOption fields',
),
StructFieldDecl(
name='disableflags',
type=ValueType(name='int'),
doc='individual authored disable flags',
),
StructFieldDecl(
name='enableflags',
type=ValueType(name='int'),
doc='individual authored enable flags',
),
StructFieldDecl(
name='disableactuator',
type=ValueType(name='int'),
doc='individual authored actuator groups',
),
StructFieldDecl(
name='visual_global',
type=ValueType(name='uint64_t'),
doc='authored visual.global fields',
),
StructFieldDecl(
name='visual_quality',
type=ValueType(name='uint64_t'),
doc='authored visual.quality fields',
),
StructFieldDecl(
name='visual_headlight',
type=ValueType(name='uint64_t'),
doc='authored visual.headlight fields',
),
StructFieldDecl(
name='visual_map',
type=ValueType(name='uint64_t'),
doc='authored visual.map fields',
),
StructFieldDecl(
name='visual_scale',
type=ValueType(name='uint64_t'),
doc='authored visual.scale fields',
),
StructFieldDecl(
name='visual_rgba',
type=ValueType(name='uint64_t'),
doc='authored visual.rgba fields',
),
),
)),
('mjSpec',
@@ -7136,6 +7198,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
type=ValueType(name='mjtByte'),
doc='already encountered an implicit plugin sensor/actuator',
),
StructFieldDecl(
name='authored',
type=ValueType(name='mjsAuthored'),
doc='authored tracking bitmasks for mjModel structs',
),
),
)),
('mjsOrientation',
+1
View File
@@ -61,6 +61,7 @@ using MjsTuple = ::mjsTuple;
using MjsKey = ::mjsKey;
using MjsDefault = ::mjsDefault;
using MjsCompiler = ::mjsCompiler;
using MjsAuthored = ::mjsAuthored;
using MjOption = ::mjOption;
using MjSolverStat = ::mjSolverStat;
using MjStatistic = ::mjStatistic;
+1
View File
@@ -267,6 +267,7 @@ PYBIND11_MODULE(_specs, m) {
py::class_<raw::MjVisualHeadlight> mjVisualHeadlight(m, "MjVisualHeadlight");
py::class_<raw::MjVisualRgba> mjVisualRgba(m, "MjVisualRgba");
py::class_<raw::MjsCompiler> mjsCompiler(m, "MjsCompiler");
py::class_<raw::MjsAuthored> mjsAuthored(m, "MjsAuthored");
DefineArray<char>(m, "MjCharVec");
DefineArray<std::string>(m, "MjStringVec");
DefineArray<std::byte>(m, "MjByteVec");
+71
View File
@@ -2102,5 +2102,76 @@ class SpecsTest(absltest.TestCase):
model = spec.compile()
self.assertIsNotNone(model)
def test_authored_struct(self):
spec = mujoco.MjSpec()
# authored struct should be accessible with correct fields
self.assertEqual(spec.authored.option, 0)
self.assertEqual(spec.authored.disableflags, 0)
self.assertEqual(spec.authored.enableflags, 0)
self.assertEqual(spec.authored.disableactuator, 0)
self.assertEqual(spec.authored.visual_global, 0)
self.assertEqual(spec.authored.visual_quality, 0)
self.assertEqual(spec.authored.visual_headlight, 0)
self.assertEqual(spec.authored.visual_map, 0)
self.assertEqual(spec.authored.visual_scale, 0)
self.assertEqual(spec.authored.visual_rgba, 0)
# compiler authored should be zero
self.assertEqual(spec.compiler.authored, 0)
def test_authored_flags_from_xml(self):
spec = mujoco.MjSpec.from_string("""
<mujoco>
<option timestep="0.01">
<flag constraint="disable" energy="enable"/>
</option>
<compiler boundmass="1"/>
<visual>
<global fovy="60"/>
<quality shadowsize="1024"/>
</visual>
<worldbody/>
</mujoco>
""")
# disable/enable flags should be tracked
self.assertNotEqual(
spec.authored.disableflags & mujoco.mjtDisableBit.mjDSBL_CONSTRAINT, 0)
self.assertEqual(
spec.authored.disableflags & mujoco.mjtDisableBit.mjDSBL_CONTACT, 0)
self.assertNotEqual(
spec.authored.enableflags & mujoco.mjtEnableBit.mjENBL_ENERGY, 0)
self.assertEqual(
spec.authored.enableflags & mujoco.mjtEnableBit.mjENBL_OVERRIDE, 0)
# option authored bitmask should be nonzero (timestep was authored)
self.assertNotEqual(spec.authored.option, 0)
# compiler authored bitmask should be nonzero (boundmass was authored)
self.assertNotEqual(spec.compiler.authored, 0)
# visual authored bitmask should be nonzero (fovy, shadowsize were authored)
self.assertNotEqual(spec.authored.visual_global, 0)
self.assertNotEqual(spec.authored.visual_quality, 0)
# visual sections that were not authored should be zero
self.assertEqual(spec.authored.visual_headlight, 0)
self.assertEqual(spec.authored.visual_map, 0)
self.assertEqual(spec.authored.visual_scale, 0)
self.assertEqual(spec.authored.visual_rgba, 0)
def test_authored_defaults_zero(self):
spec = mujoco.MjSpec.from_string("""
<mujoco>
<worldbody/>
</mujoco>
""")
# nothing authored in an empty model
self.assertEqual(spec.authored.option, 0)
self.assertEqual(spec.authored.disableflags, 0)
self.assertEqual(spec.authored.enableflags, 0)
self.assertEqual(spec.compiler.authored, 0)
self.assertEqual(spec.authored.visual_global, 0)
self.assertEqual(spec.authored.visual_quality, 0)
self.assertEqual(spec.authored.visual_map, 0)
if __name__ == '__main__':
absltest.main()