Track authored flags for global attributes
PiperOrigin-RevId: 931585539 Change-Id: Ifdc8c59de6c5a553daf6e0af09d8192aff6b0610
This commit is contained in:
committed by
Copybara-Service
parent
0ea9c7cb3a
commit
67a1ea6dca
@@ -1420,6 +1420,16 @@ Compiler options.
|
||||
.. mujoco-include:: mjsCompiler
|
||||
|
||||
|
||||
.. _mjsAuthored:
|
||||
|
||||
mjsAuthored
|
||||
~~~~~~~~~~~
|
||||
|
||||
Authored tracking bitmasks for ``mjModel`` structs.
|
||||
|
||||
.. mujoco-include:: mjsAuthored
|
||||
|
||||
|
||||
.. _mjsBody:
|
||||
|
||||
mjsBody
|
||||
|
||||
@@ -1588,7 +1588,20 @@ typedef struct mjsCompiler_ { // compiler options
|
||||
mjLROpt LRopt; // options for lengthrange computation
|
||||
mjString* meshdir; // mesh and hfield directory
|
||||
mjString* texturedir; // texture directory
|
||||
uint64_t authored; // bitmask of authored compiler fields
|
||||
} mjsCompiler;
|
||||
typedef struct mjsAuthored_ { // authored tracking bitmasks for mjModel structs
|
||||
uint64_t option; // authored mjOption fields
|
||||
int disableflags; // individual authored disable flags
|
||||
int enableflags; // individual authored enable flags
|
||||
int disableactuator; // individual authored actuator groups
|
||||
uint64_t visual_global; // authored visual.global fields
|
||||
uint64_t visual_quality; // authored visual.quality fields
|
||||
uint64_t visual_headlight; // authored visual.headlight fields
|
||||
uint64_t visual_map; // authored visual.map fields
|
||||
uint64_t visual_scale; // authored visual.scale fields
|
||||
uint64_t visual_rgba; // authored visual.rgba fields
|
||||
} mjsAuthored;
|
||||
typedef struct mjSpec_ { // model specification
|
||||
mjsElement* element; // element type
|
||||
mjString* modelname; // model name
|
||||
@@ -1625,6 +1638,9 @@ typedef struct mjSpec_ { // model specification
|
||||
|
||||
// other
|
||||
mjtByte hasImplicitPluginElem; // already encountered an implicit plugin sensor/actuator
|
||||
|
||||
// authored tracking bitmasks for mjModel structs
|
||||
mjsAuthored authored;
|
||||
} mjSpec;
|
||||
typedef struct mjsOrientation_ { // alternative orientation specifiers
|
||||
mjtOrientation type; // active orientation specifier
|
||||
|
||||
@@ -20,19 +20,24 @@
|
||||
#include <mujoco/mjplugin.h>
|
||||
#include <mujoco/mjrender.h>
|
||||
#include <mujoco/mjspec.h>
|
||||
#include <mujoco/mjspecmacro.h>
|
||||
#include <mujoco/mjtype.h>
|
||||
#include <mujoco/mjui.h>
|
||||
#include <mujoco/mjvisualize.h>
|
||||
#include <mujoco/mjxmacro.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#define MJ_ASSERT_SIZE(type, size) \
|
||||
static_assert(sizeof(type) == (size), #type " must be " #size " bytes for MuJoCo ABI stability")
|
||||
#define MJ_STATIC_ASSERT(expr) static_assert(expr)
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
#define MJ_ASSERT_SIZE(type, size) \
|
||||
_Static_assert(sizeof(type) == (size), #type " must be " #size " bytes for MuJoCo ABI stability")
|
||||
#define MJ_STATIC_ASSERT(expr) _Static_assert(expr, #expr)
|
||||
#else
|
||||
#define MJ_ASSERT_SIZE(type, size) \
|
||||
typedef char mj_assert_##type[sizeof(type) == (size) ? 1 : -1]
|
||||
#define MJ_STATIC_ASSERT(expr)
|
||||
#endif
|
||||
|
||||
// primitive types
|
||||
@@ -125,6 +130,27 @@ MJ_ASSERT_SIZE(mjtSection, 4);
|
||||
// mjplugin.h
|
||||
MJ_ASSERT_SIZE(mjtPluginCapabilityBit, 4);
|
||||
|
||||
// authored bitmask field count assertions
|
||||
// each authored bitmask is uint64_t, so each FIELDS macro must have <= 64 entries
|
||||
#define X(type, name, dim) +1
|
||||
#define XVEC(type, name, dim) +1
|
||||
|
||||
// mjsCompiler
|
||||
MJ_STATIC_ASSERT((0 MJSCOMPILER_FIELDS) <= 64);
|
||||
|
||||
// mjOption and mjVisual
|
||||
MJ_STATIC_ASSERT((0 MJOPTION_FIELDS) <= 64);
|
||||
MJ_STATIC_ASSERT((0 MJVISUAL_GLOBAL_FIELDS) <= 64);
|
||||
MJ_STATIC_ASSERT((0 MJVISUAL_QUALITY_FIELDS) <= 64);
|
||||
MJ_STATIC_ASSERT((0 MJVISUAL_HEADLIGHT_FIELDS) <= 64);
|
||||
MJ_STATIC_ASSERT((0 MJVISUAL_MAP_FIELDS) <= 64);
|
||||
MJ_STATIC_ASSERT((0 MJVISUAL_SCALE_FIELDS) <= 64);
|
||||
MJ_STATIC_ASSERT((0 MJVISUAL_RGBA_FIELDS) <= 64);
|
||||
|
||||
#undef X
|
||||
#undef XVEC
|
||||
|
||||
#undef MJ_ASSERT_SIZE
|
||||
#undef MJ_STATIC_ASSERT
|
||||
|
||||
#endif // MUJOCO_MJASSERT_H_
|
||||
|
||||
@@ -174,9 +174,24 @@ typedef struct mjsCompiler_ { // compiler options
|
||||
mjLROpt LRopt; // options for lengthrange computation
|
||||
mjString* meshdir; // mesh and hfield directory
|
||||
mjString* texturedir; // texture directory
|
||||
uint64_t authored; // bitmask of authored compiler fields
|
||||
} mjsCompiler;
|
||||
|
||||
|
||||
typedef struct mjsAuthored_ { // authored tracking bitmasks for mjModel structs
|
||||
uint64_t option; // authored mjOption fields
|
||||
int disableflags; // individual authored disable flags
|
||||
int enableflags; // individual authored enable flags
|
||||
int disableactuator; // individual authored actuator groups
|
||||
uint64_t visual_global; // authored visual.global fields
|
||||
uint64_t visual_quality; // authored visual.quality fields
|
||||
uint64_t visual_headlight; // authored visual.headlight fields
|
||||
uint64_t visual_map; // authored visual.map fields
|
||||
uint64_t visual_scale; // authored visual.scale fields
|
||||
uint64_t visual_rgba; // authored visual.rgba fields
|
||||
} mjsAuthored;
|
||||
|
||||
|
||||
typedef struct mjSpec_ { // model specification
|
||||
mjsElement* element; // element type
|
||||
mjString* modelname; // model name
|
||||
@@ -213,6 +228,9 @@ typedef struct mjSpec_ { // model specification
|
||||
|
||||
// other
|
||||
mjtByte hasImplicitPluginElem; // already encountered an implicit plugin sensor/actuator
|
||||
|
||||
// authored tracking bitmasks for mjModel structs
|
||||
mjsAuthored authored;
|
||||
} mjSpec;
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
X ( int, alignfree, 1 ) \
|
||||
X ( mjLROpt, LRopt, 1 ) \
|
||||
X ( mjString*, meshdir, 1 ) \
|
||||
X ( mjString*, texturedir, 1 )
|
||||
X ( mjString*, texturedir, 1 ) \
|
||||
X ( uint64_t, authored, 1 )
|
||||
|
||||
|
||||
//-------------------------------- mjSpec ----------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <mujoco/mjspecmacro.h>
|
||||
#include <mujoco/mjxmacro.h>
|
||||
#include "engine/engine_support.h"
|
||||
#include "engine/engine_util_errmem.h"
|
||||
#include "user/user_cache.h"
|
||||
@@ -2373,3 +2375,169 @@ mjCache* mj_getCache() {
|
||||
}();
|
||||
return &cache_cwrapper;
|
||||
}
|
||||
|
||||
|
||||
// return 1 if a field was authored, 0 otherwise
|
||||
int mjs_isAuthored(const void* elem_ptr, const void* field_ptr) {
|
||||
if (!elem_ptr || !field_ptr) return 0;
|
||||
const mjsElement* el = *reinterpret_cast<const mjsElement* const*>(elem_ptr);
|
||||
if (!el) return 0;
|
||||
|
||||
// model-level sub-structs (compiler, option, visual)
|
||||
if (el->elemtype == mjOBJ_MODEL) {
|
||||
const mjCModel* cel = static_cast<const mjCModel*>(el);
|
||||
int idx = 0;
|
||||
|
||||
#define CHECK_FIELD(FIELD_PATH, AUTHORED_MASK) \
|
||||
if (field_ptr == &FIELD_PATH) return (AUTHORED_MASK & (1ULL << idx)) != 0; \
|
||||
idx++;
|
||||
#define CHECK_FIELD_VEC(FIELD_PATH, AUTHORED_MASK) \
|
||||
if (field_ptr == FIELD_PATH || field_ptr == &FIELD_PATH) \
|
||||
return (AUTHORED_MASK & (1ULL << idx)) != 0; \
|
||||
idx++;
|
||||
|
||||
#define X(type, name, dim) CHECK_FIELD(cel->spec.compiler.name, cel->spec.compiler.authored)
|
||||
#define XVEC(type, name, dim) CHECK_FIELD_VEC(cel->spec.compiler.name, cel->spec.compiler.authored)
|
||||
idx = 0;
|
||||
MJSCOMPILER_FIELDS
|
||||
#undef X
|
||||
#undef XVEC
|
||||
|
||||
#define X(type, name, dim) CHECK_FIELD(cel->spec.option.name, cel->spec.authored.option)
|
||||
#define XVEC(type, name, dim) CHECK_FIELD_VEC(cel->spec.option.name, cel->spec.authored.option)
|
||||
idx = 0;
|
||||
MJOPTION_FIELDS
|
||||
#undef X
|
||||
#undef XVEC
|
||||
|
||||
#define X(type, name, dim) \
|
||||
CHECK_FIELD(cel->spec.visual.global.name, cel->spec.authored.visual_global)
|
||||
idx = 0;
|
||||
MJVISUAL_GLOBAL_FIELDS
|
||||
#undef X
|
||||
|
||||
#define X(type, name, dim) \
|
||||
CHECK_FIELD(cel->spec.visual.quality.name, cel->spec.authored.visual_quality)
|
||||
idx = 0;
|
||||
MJVISUAL_QUALITY_FIELDS
|
||||
#undef X
|
||||
|
||||
#define X(type, name, dim) \
|
||||
CHECK_FIELD(cel->spec.visual.headlight.name, cel->spec.authored.visual_headlight)
|
||||
#define XVEC(type, name, dim) \
|
||||
CHECK_FIELD_VEC(cel->spec.visual.headlight.name, cel->spec.authored.visual_headlight)
|
||||
idx = 0;
|
||||
MJVISUAL_HEADLIGHT_FIELDS
|
||||
#undef X
|
||||
#undef XVEC
|
||||
|
||||
#define X(type, name, dim) CHECK_FIELD(cel->spec.visual.map.name, cel->spec.authored.visual_map)
|
||||
idx = 0;
|
||||
MJVISUAL_MAP_FIELDS
|
||||
#undef X
|
||||
|
||||
#define X(type, name, dim) CHECK_FIELD(cel->spec.visual.scale.name, cel->spec.authored.visual_scale)
|
||||
idx = 0;
|
||||
MJVISUAL_SCALE_FIELDS
|
||||
#undef X
|
||||
|
||||
#define XVEC(type, name, dim) \
|
||||
CHECK_FIELD_VEC(cel->spec.visual.rgba.name, cel->spec.authored.visual_rgba)
|
||||
idx = 0;
|
||||
MJVISUAL_RGBA_FIELDS
|
||||
#undef XVEC
|
||||
|
||||
#undef CHECK_FIELD
|
||||
#undef CHECK_FIELD_VEC
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// record explicit authoring of an element's field
|
||||
void mjs_setAuthored(const void* elem_ptr, const void* field_ptr, int authored) {
|
||||
if (!elem_ptr || !field_ptr) return;
|
||||
mjsElement* el = const_cast<mjsElement*>(*reinterpret_cast<const mjsElement* const*>(elem_ptr));
|
||||
if (!el) return;
|
||||
|
||||
#define SET_FIELD(FIELD_PATH, AUTHORED_MASK) \
|
||||
if (field_ptr == &FIELD_PATH) { \
|
||||
if (authored) \
|
||||
AUTHORED_MASK |= (1ULL << idx); \
|
||||
else \
|
||||
AUTHORED_MASK &= ~(1ULL << idx); \
|
||||
return; \
|
||||
} \
|
||||
idx++;
|
||||
|
||||
#define SET_FIELD_VEC(FIELD_PATH, AUTHORED_MASK) \
|
||||
if (field_ptr == FIELD_PATH || field_ptr == &FIELD_PATH) { \
|
||||
if (authored) \
|
||||
AUTHORED_MASK |= (1ULL << idx); \
|
||||
else \
|
||||
AUTHORED_MASK &= ~(1ULL << idx); \
|
||||
return; \
|
||||
} \
|
||||
idx++;
|
||||
|
||||
// model-level sub-structs (compiler, option, visual)
|
||||
if (el->elemtype == mjOBJ_MODEL) {
|
||||
mjCModel* cel = static_cast<mjCModel*>(el);
|
||||
int idx = 0;
|
||||
|
||||
#define X(type, name, dim) SET_FIELD(cel->spec.compiler.name, cel->spec.compiler.authored)
|
||||
#define XVEC(type, name, dim) SET_FIELD_VEC(cel->spec.compiler.name, cel->spec.compiler.authored)
|
||||
idx = 0;
|
||||
MJSCOMPILER_FIELDS
|
||||
#undef X
|
||||
#undef XVEC
|
||||
|
||||
#define X(type, name, dim) SET_FIELD(cel->spec.option.name, cel->spec.authored.option)
|
||||
#define XVEC(type, name, dim) SET_FIELD_VEC(cel->spec.option.name, cel->spec.authored.option)
|
||||
idx = 0;
|
||||
MJOPTION_FIELDS
|
||||
#undef X
|
||||
#undef XVEC
|
||||
|
||||
#define X(type, name, dim) SET_FIELD(cel->spec.visual.global.name, cel->spec.authored.visual_global)
|
||||
idx = 0;
|
||||
MJVISUAL_GLOBAL_FIELDS
|
||||
#undef X
|
||||
|
||||
#define X(type, name, dim) \
|
||||
SET_FIELD(cel->spec.visual.quality.name, cel->spec.authored.visual_quality)
|
||||
idx = 0;
|
||||
MJVISUAL_QUALITY_FIELDS
|
||||
#undef X
|
||||
|
||||
#define X(type, name, dim) \
|
||||
SET_FIELD(cel->spec.visual.headlight.name, cel->spec.authored.visual_headlight)
|
||||
#define XVEC(type, name, dim) \
|
||||
SET_FIELD_VEC(cel->spec.visual.headlight.name, cel->spec.authored.visual_headlight)
|
||||
idx = 0;
|
||||
MJVISUAL_HEADLIGHT_FIELDS
|
||||
#undef X
|
||||
#undef XVEC
|
||||
|
||||
#define X(type, name, dim) SET_FIELD(cel->spec.visual.map.name, cel->spec.authored.visual_map)
|
||||
idx = 0;
|
||||
MJVISUAL_MAP_FIELDS
|
||||
#undef X
|
||||
|
||||
#define X(type, name, dim) SET_FIELD(cel->spec.visual.scale.name, cel->spec.authored.visual_scale)
|
||||
idx = 0;
|
||||
MJVISUAL_SCALE_FIELDS
|
||||
#undef X
|
||||
|
||||
#define XVEC(type, name, dim) \
|
||||
SET_FIELD_VEC(cel->spec.visual.rgba.name, cel->spec.authored.visual_rgba)
|
||||
idx = 0;
|
||||
MJVISUAL_RGBA_FIELDS
|
||||
#undef XVEC
|
||||
}
|
||||
|
||||
#undef SET_FIELD
|
||||
#undef SET_FIELD_VEC
|
||||
}
|
||||
|
||||
@@ -431,6 +431,12 @@ MJAPI const void* mjs_getPluginAttributes(const mjsPlugin* plugin);
|
||||
|
||||
//---------------------------------- Other utilities -----------------------------------------------
|
||||
|
||||
// Return 1 if a field was authored or mutated relative to its inherited default, 0 otherwise.
|
||||
MJAPI int mjs_isAuthored(const void* elem_ptr, const void* field_ptr);
|
||||
|
||||
// Record explicit authoring of an element's field.
|
||||
MJAPI void mjs_setAuthored(const void* elem_ptr, const void* field_ptr, int authored);
|
||||
|
||||
// Set element's default.
|
||||
MJAPI void mjs_setDefault(mjsElement* element, const mjsDefault* def);
|
||||
|
||||
|
||||
+232
-182
@@ -25,17 +25,14 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <mujoco/mujoco.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include <mujoco/mjplugin.h>
|
||||
#include <mujoco/mjtype.h>
|
||||
#include <mujoco/mjvisualize.h>
|
||||
#include "engine/engine_plugin.h"
|
||||
#include "engine/engine_support.h"
|
||||
#include "engine/engine_util_errmem.h"
|
||||
#include "engine/engine_util_misc.h"
|
||||
#include <mujoco/mjspec.h>
|
||||
#include "user/user_api.h"
|
||||
@@ -53,6 +50,81 @@ using std::vector;
|
||||
using mujoco::user::FilePath;
|
||||
using tinyxml2::XMLElement;
|
||||
|
||||
|
||||
|
||||
//---------------------------------- helper utilities ----------------------------------------------
|
||||
|
||||
// GetAttrPtr: overload for scalar and pointer fields
|
||||
template <typename T>
|
||||
inline auto GetAttrPtr(T& val) -> std::enable_if_t<!std::is_array_v<T>, decltype(&val)> {
|
||||
if constexpr (std::is_pointer_v<T>) {
|
||||
return val;
|
||||
} else {
|
||||
return &val;
|
||||
}
|
||||
}
|
||||
|
||||
// GetAttrPtr: overload for array fields
|
||||
template <typename T, size_t N>
|
||||
inline T* GetAttrPtr(T (&arr)[N]) { return arr; }
|
||||
|
||||
|
||||
// helper class for reading attributes while recording authored bits
|
||||
struct Reader {
|
||||
Reader(XMLElement* xml_node, const void* elem) : xml_node_(xml_node), elem_(elem) {}
|
||||
|
||||
template <typename T>
|
||||
int operator()(const char* attr, int len, T& data, bool required = false, bool exact = true) {
|
||||
int res = mjXReader::ReadAttr(xml_node_, attr, len, GetAttrPtr(data), text_, required, exact);
|
||||
if (res) mjs_setAuthored(elem_, &data, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator()(const char* attr, T& data, const mjMap* map, int mapsz, bool required = false) {
|
||||
int map_val_temp;
|
||||
bool res = mjXReader::MapValue(xml_node_, attr, &map_val_temp, map, mapsz, required);
|
||||
if (res) {
|
||||
data = static_cast<T>(map_val_temp);
|
||||
mjs_setAuthored(elem_, &data, 1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator()(const char* attr, int& data, bool required = false) {
|
||||
bool res = mjXUtil::ReadAttrInt(xml_node_, attr, &data, required);
|
||||
if (res) mjs_setAuthored(elem_, &data, 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator()(const char* attr, mjString* target) {
|
||||
std::string txt_temp;
|
||||
bool res = mjXUtil::ReadAttrTxt(xml_node_, attr, txt_temp);
|
||||
if (res) {
|
||||
mjs_setString(target, txt_temp.c_str());
|
||||
mjs_setAuthored(elem_, target, 1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool txt(const char* attr, T& target, void (&set_func)(T&, const char*)) {
|
||||
std::string txt_temp;
|
||||
bool res = mjXUtil::ReadAttrTxt(xml_node_, attr, txt_temp);
|
||||
if (res) {
|
||||
set_func(target, txt_temp.c_str());
|
||||
mjs_setAuthored(elem_, &target, 1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void set_node(XMLElement* node) { xml_node_ = node; }
|
||||
|
||||
XMLElement* xml_node_;
|
||||
const void* elem_;
|
||||
std::string text_;
|
||||
};
|
||||
|
||||
void ReadPluginConfigs(tinyxml2::XMLElement* elem, mjsPlugin* p) {
|
||||
std::map<string, string, std::less<> > config_attribs;
|
||||
XMLElement* child = FirstChildElement(elem);
|
||||
@@ -1023,7 +1095,7 @@ void mjXReader::Parse(XMLElement* root, const mjVFS* vfs) {
|
||||
|
||||
for (XMLElement* section = FirstChildElement(root, "option"); section;
|
||||
section = NextSiblingElement(section, "option")) {
|
||||
Option(section, &spec->option);
|
||||
Option(section, spec, &spec->option);
|
||||
}
|
||||
|
||||
for (XMLElement* section = FirstChildElement(root, "size"); section;
|
||||
@@ -1116,73 +1188,49 @@ void mjXReader::Parse(XMLElement* root, const mjVFS* vfs) {
|
||||
|
||||
// compiler section parser
|
||||
void mjXReader::Compiler(XMLElement* section, mjSpec* s) {
|
||||
string text;
|
||||
int n;
|
||||
Reader read(section, s);
|
||||
|
||||
// top-level attributes
|
||||
if (MapValue(section, "autolimits", &n, bool_map, 2)) {
|
||||
s->compiler.autolimits = (n == 1);
|
||||
}
|
||||
ReadAttr(section, "boundmass", 1, &s->compiler.boundmass, text);
|
||||
ReadAttr(section, "boundinertia", 1, &s->compiler.boundinertia, text);
|
||||
ReadAttr(section, "settotalmass", 1, &s->compiler.settotalmass, text);
|
||||
if (MapValue(section, "balanceinertia", &n, bool_map, 2)) {
|
||||
s->compiler.balanceinertia = (n == 1);
|
||||
}
|
||||
if (MapValue(section, "strippath", &n, bool_map, 2)) {
|
||||
s->strippath = (n == 1);
|
||||
}
|
||||
if (MapValue(section, "fitaabb", &n, bool_map, 2)) {
|
||||
s->compiler.fitaabb = (n == 1);
|
||||
}
|
||||
if (MapValue(section, "coordinate", &n, coordinate_map, 2)) {
|
||||
read("autolimits", s->compiler.autolimits, bool_map, 2);
|
||||
read("boundmass", 1, s->compiler.boundmass);
|
||||
read("boundinertia", 1, s->compiler.boundinertia);
|
||||
read("settotalmass", 1, s->compiler.settotalmass);
|
||||
read("balanceinertia", s->compiler.balanceinertia, bool_map, 2);
|
||||
read("strippath", s->strippath, bool_map, 2);
|
||||
read("fitaabb", s->compiler.fitaabb, bool_map, 2);
|
||||
if (int n = 0; MapValue(section, "coordinate", &n, coordinate_map, 2)) {
|
||||
if (n == 1) {
|
||||
throw mjXError(section, "global coordinates no longer supported. To convert existing models, "
|
||||
"load and save them in MuJoCo 2.3.3 or older");
|
||||
}
|
||||
}
|
||||
if (MapValue(section, "angle", &n, angle_map, 2)) {
|
||||
s->compiler.degree = (n == 1);
|
||||
}
|
||||
if (ReadAttrTxt(section, "eulerseq", text)) {
|
||||
if (text.size() != 3) {
|
||||
read("angle", s->compiler.degree, angle_map, 2);
|
||||
if (ReadAttrTxt(section, "eulerseq", read.text_)) {
|
||||
if (read.text_.size() != 3) {
|
||||
throw mjXError(section, "euler format must have length 3");
|
||||
}
|
||||
memcpy(s->compiler.eulerseq, text.c_str(), 3);
|
||||
memcpy(s->compiler.eulerseq, read.text_.c_str(), 3);
|
||||
mjs_setAuthored(s, &s->compiler.eulerseq, 1);
|
||||
}
|
||||
if (ReadAttrTxt(section, "assetdir", text)) {
|
||||
mjs_setString(s->compiler.meshdir, text.c_str());
|
||||
mjs_setString(s->compiler.texturedir, text.c_str());
|
||||
if (ReadAttrTxt(section, "assetdir", read.text_)) {
|
||||
mjs_setString(s->compiler.meshdir, read.text_.c_str());
|
||||
mjs_setString(s->compiler.texturedir, read.text_.c_str());
|
||||
}
|
||||
// meshdir and texturedir take precedence over assetdir
|
||||
string meshdir, texturedir;
|
||||
if (ReadAttrTxt(section, "meshdir", meshdir)) {
|
||||
mjs_setString(s->compiler.meshdir, meshdir.c_str());
|
||||
};
|
||||
if (ReadAttrTxt(section, "texturedir", texturedir)) {
|
||||
mjs_setString(s->compiler.texturedir, texturedir.c_str());
|
||||
}
|
||||
if (MapValue(section, "discardvisual", &n, bool_map, 2)) {
|
||||
s->compiler.discardvisual = (n == 1);
|
||||
}
|
||||
if (MapValue(section, "usethread", &n, bool_map, 2)) {
|
||||
s->compiler.usethread = (n == 1);
|
||||
}
|
||||
if (MapValue(section, "fusestatic", &n, bool_map, 2)) {
|
||||
s->compiler.fusestatic = (n == 1);
|
||||
}
|
||||
MapValue(section, "inertiafromgeom", &s->compiler.inertiafromgeom, TFAuto_map, 3);
|
||||
ReadAttr(section, "inertiagrouprange", 2, s->compiler.inertiagrouprange, text);
|
||||
if (MapValue(section, "alignfree", &n, bool_map, 2)) {
|
||||
s->compiler.alignfree = (n == 1);
|
||||
}
|
||||
if (MapValue(section, "saveinertial", &n, bool_map, 2)) {
|
||||
s->compiler.saveinertial = (n == 1);
|
||||
}
|
||||
read("meshdir", s->compiler.meshdir);
|
||||
read("texturedir", s->compiler.texturedir);
|
||||
read("discardvisual", s->compiler.discardvisual, bool_map, 2);
|
||||
read("usethread", s->compiler.usethread, bool_map, 2);
|
||||
read("fusestatic", s->compiler.fusestatic, bool_map, 2);
|
||||
read("inertiafromgeom", s->compiler.inertiafromgeom, TFAuto_map, 3);
|
||||
read("inertiagrouprange", 2, s->compiler.inertiagrouprange);
|
||||
read("alignfree", s->compiler.alignfree, bool_map, 2);
|
||||
read("saveinertial", s->compiler.saveinertial, bool_map, 2);
|
||||
|
||||
// lengthrange subelement
|
||||
XMLElement* elem = FindSubElem(section, "lengthrange");
|
||||
if (elem) {
|
||||
int n;
|
||||
mjLROpt* opt = &(s->compiler.LRopt);
|
||||
|
||||
// flags
|
||||
@@ -1195,6 +1243,7 @@ void mjXReader::Compiler(XMLElement* section, mjSpec* s) {
|
||||
}
|
||||
|
||||
// algorithm parameters
|
||||
string text;
|
||||
ReadAttr(elem, "accel", 1, &opt->accel, text);
|
||||
ReadAttr(elem, "maxforce", 1, &opt->maxforce, text);
|
||||
ReadAttr(elem, "timeconst", 1, &opt->timeconst, text);
|
||||
@@ -1208,45 +1257,44 @@ void mjXReader::Compiler(XMLElement* section, mjSpec* s) {
|
||||
|
||||
|
||||
// option section parser
|
||||
void mjXReader::Option(XMLElement* section, mjOption* opt) {
|
||||
string text;
|
||||
int n;
|
||||
void mjXReader::Option(XMLElement* section, mjSpec* s, mjOption* opt) {
|
||||
Reader read(section, s);
|
||||
|
||||
// read options
|
||||
ReadAttr(section, "timestep", 1, &opt->timestep, text);
|
||||
ReadAttr(section, "impratio", 1, &opt->impratio, text);
|
||||
ReadAttr(section, "tolerance", 1, &opt->tolerance, text);
|
||||
ReadAttr(section, "ls_tolerance", 1, &opt->ls_tolerance, text);
|
||||
ReadAttr(section, "noslip_tolerance", 1, &opt->noslip_tolerance, text);
|
||||
ReadAttr(section, "ccd_tolerance", 1, &opt->ccd_tolerance, text);
|
||||
ReadAttr(section, "sleep_tolerance", 1, &opt->sleep_tolerance, text);
|
||||
ReadAttr(section, "gravity", 3, opt->gravity, text);
|
||||
ReadAttr(section, "wind", 3, opt->wind, text);
|
||||
ReadAttr(section, "magnetic", 3, opt->magnetic, text);
|
||||
ReadAttr(section, "density", 1, &opt->density, text);
|
||||
ReadAttr(section, "viscosity", 1, &opt->viscosity, text);
|
||||
read("timestep", 1, opt->timestep);
|
||||
read("impratio", 1, opt->impratio);
|
||||
read("tolerance", 1, opt->tolerance);
|
||||
read("ls_tolerance", 1, opt->ls_tolerance);
|
||||
read("noslip_tolerance", 1, opt->noslip_tolerance);
|
||||
read("ccd_tolerance", 1, opt->ccd_tolerance);
|
||||
read("sleep_tolerance", 1, opt->sleep_tolerance);
|
||||
read("gravity", 3, opt->gravity);
|
||||
read("wind", 3, opt->wind);
|
||||
read("magnetic", 3, opt->magnetic);
|
||||
read("density", 1, opt->density);
|
||||
read("viscosity", 1, opt->viscosity);
|
||||
|
||||
ReadAttr(section, "o_margin", 1, &opt->o_margin, text);
|
||||
ReadAttr(section, "o_solref", mjNREF, opt->o_solref, text, false, false);
|
||||
ReadAttr(section, "o_solimp", mjNIMP, opt->o_solimp, text, false, false);
|
||||
ReadAttr(section, "o_friction", 5, opt->o_friction, text, false, false);
|
||||
read("o_margin", 1, opt->o_margin);
|
||||
read("o_solref", mjNREF, opt->o_solref, false, false);
|
||||
read("o_solimp", mjNIMP, opt->o_solimp, false, false);
|
||||
read("o_friction", 5, opt->o_friction, false, false);
|
||||
|
||||
MapValue(section, "integrator", &opt->integrator, integrator_map, integrator_sz);
|
||||
MapValue(section, "cone", &opt->cone, cone_map, cone_sz);
|
||||
MapValue(section, "jacobian", &opt->jacobian, jac_map, jac_sz);
|
||||
MapValue(section, "solver", &opt->solver, solver_map, solver_sz);
|
||||
ReadAttrInt(section, "iterations", &opt->iterations);
|
||||
ReadAttrInt(section, "ls_iterations", &opt->ls_iterations);
|
||||
ReadAttrInt(section, "noslip_iterations", &opt->noslip_iterations);
|
||||
ReadAttrInt(section, "ccd_iterations", &opt->ccd_iterations);
|
||||
ReadAttrInt(section, "sdf_iterations", &opt->sdf_iterations);
|
||||
ReadAttrInt(section, "sdf_initpoints", &opt->sdf_initpoints);
|
||||
read("integrator", opt->integrator, integrator_map, integrator_sz);
|
||||
read("cone", opt->cone, cone_map, cone_sz);
|
||||
read("jacobian", opt->jacobian, jac_map, jac_sz);
|
||||
read("solver", opt->solver, solver_map, solver_sz);
|
||||
read("iterations", opt->iterations);
|
||||
read("ls_iterations", opt->ls_iterations);
|
||||
read("noslip_iterations", opt->noslip_iterations);
|
||||
read("ccd_iterations", opt->ccd_iterations);
|
||||
read("sdf_iterations", opt->sdf_iterations);
|
||||
read("sdf_initpoints", opt->sdf_initpoints);
|
||||
|
||||
// actuatorgroupdisable
|
||||
constexpr int num_bitflags = 31;
|
||||
int disabled_act_groups[num_bitflags];
|
||||
int num_found = ReadAttr(section, "actuatorgroupdisable", num_bitflags, disabled_act_groups,
|
||||
text, false, false);
|
||||
int num_found = read("actuatorgroupdisable", num_bitflags,
|
||||
disabled_act_groups, false, false);
|
||||
for (int i=0; i < num_found; i++) {
|
||||
int group = disabled_act_groups[i];
|
||||
if (group < 0) {
|
||||
@@ -1256,15 +1304,19 @@ void mjXReader::Option(XMLElement* section, mjOption* opt) {
|
||||
throw mjXError(section, "disabled actuator group value cannot exceed 30");
|
||||
}
|
||||
opt->disableactuator |= (1 << group);
|
||||
s->authored.disableactuator |= (1 << group);
|
||||
}
|
||||
|
||||
// read disable sub-element
|
||||
XMLElement* elem = FindSubElem(section, "flag");
|
||||
if (elem) {
|
||||
#define READDSBL(NAME, MASK) \
|
||||
if (MapValue(elem, NAME, &n, enable_map, 2)) { \
|
||||
opt->disableflags ^= (opt->disableflags & MASK); \
|
||||
opt->disableflags |= (n ? 0 : MASK); }
|
||||
int n = 0;
|
||||
#define READDSBL(NAME, MASK) \
|
||||
if (MapValue(elem, NAME, &n, enable_map, 2)) { \
|
||||
opt->disableflags ^= (opt->disableflags & MASK); \
|
||||
opt->disableflags |= (n ? 0 : MASK); \
|
||||
s->authored.disableflags |= MASK; \
|
||||
}
|
||||
|
||||
READDSBL("constraint", mjDSBL_CONSTRAINT)
|
||||
READDSBL("equality", mjDSBL_EQUALITY)
|
||||
@@ -1288,10 +1340,12 @@ void mjXReader::Option(XMLElement* section, mjOption* opt) {
|
||||
READDSBL("multiccd", mjDSBL_MULTICCD)
|
||||
#undef READDSBL
|
||||
|
||||
#define READENBL(NAME, MASK) \
|
||||
if (MapValue(elem, NAME, &n, enable_map, 2)) { \
|
||||
opt->enableflags ^= (opt->enableflags & MASK); \
|
||||
opt->enableflags |= (n ? MASK : 0); }
|
||||
#define READENBL(NAME, MASK) \
|
||||
if (MapValue(elem, NAME, &n, enable_map, 2)) { \
|
||||
opt->enableflags ^= (opt->enableflags & MASK); \
|
||||
opt->enableflags |= (n ? MASK : 0); \
|
||||
s->authored.enableflags |= MASK; \
|
||||
}
|
||||
|
||||
READENBL("override", mjENBL_OVERRIDE)
|
||||
READENBL("energy", mjENBL_ENERGY)
|
||||
@@ -3247,129 +3301,125 @@ void mjXReader::Custom(XMLElement* section) {
|
||||
|
||||
// visual section parser
|
||||
void mjXReader::Visual(XMLElement* section) {
|
||||
string text, name;
|
||||
string name;
|
||||
XMLElement* elem;
|
||||
mjVisual* vis = &spec->visual;
|
||||
int n;
|
||||
Reader read(section, spec);
|
||||
|
||||
// iterate over child elements
|
||||
elem = FirstChildElement(section);
|
||||
while (elem) {
|
||||
// get sub-element name
|
||||
name = elem->Value();
|
||||
read.set_node(elem);
|
||||
|
||||
// global sub-element
|
||||
if (name == "global") {
|
||||
ReadAttrInt(elem, "cameraid", &vis->global.cameraid);
|
||||
if (MapValue(elem, "orthographic", &n, bool_map, 2)) {
|
||||
vis->global.orthographic = (n == 1);
|
||||
}
|
||||
ReadAttr(elem, "fovy", 1, &vis->global.fovy, text);
|
||||
ReadAttr(elem, "ipd", 1, &vis->global.ipd, text);
|
||||
ReadAttr(elem, "azimuth", 1, &vis->global.azimuth, text);
|
||||
ReadAttr(elem, "elevation", 1, &vis->global.elevation, text);
|
||||
ReadAttr(elem, "linewidth", 1, &vis->global.linewidth, text);
|
||||
ReadAttr(elem, "glow", 1, &vis->global.glow, text);
|
||||
ReadAttrInt(elem, "offwidth", &vis->global.offwidth);
|
||||
ReadAttrInt(elem, "offheight", &vis->global.offheight);
|
||||
if (ReadAttr(elem, "realtime", 1, &vis->global.realtime, text)) {
|
||||
read("cameraid", vis->global.cameraid);
|
||||
read("orthographic", vis->global.orthographic, bool_map, 2);
|
||||
read("fovy", 1, vis->global.fovy);
|
||||
read("ipd", 1, vis->global.ipd);
|
||||
read("azimuth", 1, vis->global.azimuth);
|
||||
read("elevation", 1, vis->global.elevation);
|
||||
read("linewidth", 1, vis->global.linewidth);
|
||||
read("glow", 1, vis->global.glow);
|
||||
read("offwidth", vis->global.offwidth);
|
||||
read("offheight", vis->global.offheight);
|
||||
if (read("realtime", 1, vis->global.realtime)) {
|
||||
if (vis->global.realtime <= 0) {
|
||||
throw mjXError(elem, "realtime must be greater than 0");
|
||||
}
|
||||
}
|
||||
if (MapValue(elem, "ellipsoidinertia", &n, bool_map, 2)) {
|
||||
vis->global.ellipsoidinertia = (n == 1);
|
||||
}
|
||||
if (MapValue(elem, "bvactive", &n, bool_map, 2)) {
|
||||
vis->global.bvactive = (n == 1);
|
||||
}
|
||||
read("ellipsoidinertia", vis->global.ellipsoidinertia, bool_map, 2);
|
||||
read("bvactive", vis->global.bvactive, bool_map, 2);
|
||||
}
|
||||
|
||||
// quality sub-element
|
||||
else if (name == "quality") {
|
||||
ReadAttrInt(elem, "shadowsize", &vis->quality.shadowsize);
|
||||
ReadAttrInt(elem, "offsamples", &vis->quality.offsamples);
|
||||
ReadAttrInt(elem, "numslices", &vis->quality.numslices);
|
||||
ReadAttrInt(elem, "numstacks", &vis->quality.numstacks);
|
||||
ReadAttrInt(elem, "numquads", &vis->quality.numquads);
|
||||
read("shadowsize", vis->quality.shadowsize);
|
||||
read("offsamples", vis->quality.offsamples);
|
||||
read("numslices", vis->quality.numslices);
|
||||
read("numstacks", vis->quality.numstacks);
|
||||
read("numquads", vis->quality.numquads);
|
||||
}
|
||||
|
||||
// headlight sub-element
|
||||
else if (name == "headlight") {
|
||||
ReadAttr(elem, "ambient", 3, vis->headlight.ambient, text);
|
||||
ReadAttr(elem, "diffuse", 3, vis->headlight.diffuse, text);
|
||||
ReadAttr(elem, "specular", 3, vis->headlight.specular, text);
|
||||
ReadAttrInt(elem, "active", &vis->headlight.active);
|
||||
read("ambient", 3, vis->headlight.ambient);
|
||||
read("diffuse", 3, vis->headlight.diffuse);
|
||||
read("specular", 3, vis->headlight.specular);
|
||||
read("active", vis->headlight.active);
|
||||
}
|
||||
|
||||
// map sub-element
|
||||
else if (name == "map") {
|
||||
ReadAttr(elem, "stiffness", 1, &vis->map.stiffness, text);
|
||||
ReadAttr(elem, "stiffnessrot", 1, &vis->map.stiffnessrot, text);
|
||||
ReadAttr(elem, "force", 1, &vis->map.force, text);
|
||||
ReadAttr(elem, "torque", 1, &vis->map.torque, text);
|
||||
ReadAttr(elem, "alpha", 1, &vis->map.alpha, text);
|
||||
ReadAttr(elem, "fogstart", 1, &vis->map.fogstart, text);
|
||||
ReadAttr(elem, "fogend", 1, &vis->map.fogend, text);
|
||||
ReadAttr(elem, "znear", 1, &vis->map.znear, text);
|
||||
if (vis->map.znear <= 0) {
|
||||
throw mjXError(elem, "znear must be strictly positive");
|
||||
read("stiffness", 1, vis->map.stiffness);
|
||||
read("stiffnessrot", 1, vis->map.stiffnessrot);
|
||||
read("force", 1, vis->map.force);
|
||||
read("torque", 1, vis->map.torque);
|
||||
read("alpha", 1, vis->map.alpha);
|
||||
read("fogstart", 1, vis->map.fogstart);
|
||||
read("fogend", 1, vis->map.fogend);
|
||||
if (read("znear", 1, vis->map.znear)) {
|
||||
if (vis->map.znear <= 0) {
|
||||
throw mjXError(elem, "znear must be strictly positive");
|
||||
}
|
||||
}
|
||||
ReadAttr(elem, "zfar", 1, &vis->map.zfar, text);
|
||||
ReadAttr(elem, "haze", 1, &vis->map.haze, text);
|
||||
ReadAttr(elem, "shadowclip", 1, &vis->map.shadowclip, text);
|
||||
ReadAttr(elem, "shadowscale", 1, &vis->map.shadowscale, text);
|
||||
ReadAttr(elem, "actuatortendon", 1, &vis->map.actuatortendon, text);
|
||||
read("zfar", 1, vis->map.zfar);
|
||||
read("haze", 1, vis->map.haze);
|
||||
read("shadowclip", 1, vis->map.shadowclip);
|
||||
read("shadowscale", 1, vis->map.shadowscale);
|
||||
read("actuatortendon", 1, vis->map.actuatortendon);
|
||||
}
|
||||
|
||||
// scale sub-element
|
||||
else if (name == "scale") {
|
||||
ReadAttr(elem, "forcewidth", 1, &vis->scale.forcewidth, text);
|
||||
ReadAttr(elem, "contactwidth", 1, &vis->scale.contactwidth, text);
|
||||
ReadAttr(elem, "contactheight", 1, &vis->scale.contactheight, text);
|
||||
ReadAttr(elem, "connect", 1, &vis->scale.connect, text);
|
||||
ReadAttr(elem, "com", 1, &vis->scale.com, text);
|
||||
ReadAttr(elem, "camera", 1, &vis->scale.camera, text);
|
||||
ReadAttr(elem, "light", 1, &vis->scale.light, text);
|
||||
ReadAttr(elem, "selectpoint", 1, &vis->scale.selectpoint, text);
|
||||
ReadAttr(elem, "jointlength", 1, &vis->scale.jointlength, text);
|
||||
ReadAttr(elem, "jointwidth", 1, &vis->scale.jointwidth, text);
|
||||
ReadAttr(elem, "actuatorlength", 1, &vis->scale.actuatorlength, text);
|
||||
ReadAttr(elem, "actuatorwidth", 1, &vis->scale.actuatorwidth, text);
|
||||
ReadAttr(elem, "framelength", 1, &vis->scale.framelength, text);
|
||||
ReadAttr(elem, "framewidth", 1, &vis->scale.framewidth, text);
|
||||
ReadAttr(elem, "constraint", 1, &vis->scale.constraint, text);
|
||||
ReadAttr(elem, "slidercrank", 1, &vis->scale.slidercrank, text);
|
||||
ReadAttr(elem, "frustum", 1, &vis->scale.frustum, text);
|
||||
read("forcewidth", 1, vis->scale.forcewidth);
|
||||
read("contactwidth", 1, vis->scale.contactwidth);
|
||||
read("contactheight", 1, vis->scale.contactheight);
|
||||
read("connect", 1, vis->scale.connect);
|
||||
read("com", 1, vis->scale.com);
|
||||
read("camera", 1, vis->scale.camera);
|
||||
read("light", 1, vis->scale.light);
|
||||
read("selectpoint", 1, vis->scale.selectpoint);
|
||||
read("jointlength", 1, vis->scale.jointlength);
|
||||
read("jointwidth", 1, vis->scale.jointwidth);
|
||||
read("actuatorlength", 1, vis->scale.actuatorlength);
|
||||
read("actuatorwidth", 1, vis->scale.actuatorwidth);
|
||||
read("framelength", 1, vis->scale.framelength);
|
||||
read("framewidth", 1, vis->scale.framewidth);
|
||||
read("constraint", 1, vis->scale.constraint);
|
||||
read("slidercrank", 1, vis->scale.slidercrank);
|
||||
read("frustum", 1, vis->scale.frustum);
|
||||
}
|
||||
|
||||
// rgba sub-element
|
||||
else if (name == "rgba") {
|
||||
ReadAttr(elem, "fog", 4, vis->rgba.fog, text);
|
||||
ReadAttr(elem, "haze", 4, vis->rgba.haze, text);
|
||||
ReadAttr(elem, "force", 4, vis->rgba.force, text);
|
||||
ReadAttr(elem, "inertia", 4, vis->rgba.inertia, text);
|
||||
ReadAttr(elem, "joint", 4, vis->rgba.joint, text);
|
||||
ReadAttr(elem, "actuator", 4, vis->rgba.actuator, text);
|
||||
ReadAttr(elem, "actuatornegative", 4, vis->rgba.actuatornegative, text);
|
||||
ReadAttr(elem, "actuatorpositive", 4, vis->rgba.actuatorpositive, text);
|
||||
ReadAttr(elem, "com", 4, vis->rgba.com, text);
|
||||
ReadAttr(elem, "camera", 4, vis->rgba.camera, text);
|
||||
ReadAttr(elem, "light", 4, vis->rgba.light, text);
|
||||
ReadAttr(elem, "selectpoint", 4, vis->rgba.selectpoint, text);
|
||||
ReadAttr(elem, "connect", 4, vis->rgba.connect, text);
|
||||
ReadAttr(elem, "contactpoint", 4, vis->rgba.contactpoint, text);
|
||||
ReadAttr(elem, "contactforce", 4, vis->rgba.contactforce, text);
|
||||
ReadAttr(elem, "contactfriction", 4, vis->rgba.contactfriction, text);
|
||||
ReadAttr(elem, "contacttorque", 4, vis->rgba.contacttorque, text);
|
||||
ReadAttr(elem, "contactgap", 4, vis->rgba.contactgap, text);
|
||||
ReadAttr(elem, "rangefinder", 4, vis->rgba.rangefinder, text);
|
||||
ReadAttr(elem, "constraint", 4, vis->rgba.constraint, text);
|
||||
ReadAttr(elem, "slidercrank", 4, vis->rgba.slidercrank, text);
|
||||
ReadAttr(elem, "crankbroken", 4, vis->rgba.crankbroken, text);
|
||||
ReadAttr(elem, "frustum", 4, vis->rgba.frustum, text);
|
||||
ReadAttr(elem, "bv", 4, vis->rgba.bv, text);
|
||||
ReadAttr(elem, "bvactive", 4, vis->rgba.bvactive, text);
|
||||
read("fog", 4, vis->rgba.fog);
|
||||
read("haze", 4, vis->rgba.haze);
|
||||
read("force", 4, vis->rgba.force);
|
||||
read("inertia", 4, vis->rgba.inertia);
|
||||
read("joint", 4, vis->rgba.joint);
|
||||
read("actuator", 4, vis->rgba.actuator);
|
||||
read("actuatornegative", 4, vis->rgba.actuatornegative);
|
||||
read("actuatorpositive", 4, vis->rgba.actuatorpositive);
|
||||
read("com", 4, vis->rgba.com);
|
||||
read("camera", 4, vis->rgba.camera);
|
||||
read("light", 4, vis->rgba.light);
|
||||
read("selectpoint", 4, vis->rgba.selectpoint);
|
||||
read("connect", 4, vis->rgba.connect);
|
||||
read("contactpoint", 4, vis->rgba.contactpoint);
|
||||
read("contactforce", 4, vis->rgba.contactforce);
|
||||
read("contactfriction", 4, vis->rgba.contactfriction);
|
||||
read("contacttorque", 4, vis->rgba.contacttorque);
|
||||
read("contactgap", 4, vis->rgba.contactgap);
|
||||
read("rangefinder", 4, vis->rgba.rangefinder);
|
||||
read("constraint", 4, vis->rgba.constraint);
|
||||
read("slidercrank", 4, vis->rgba.slidercrank);
|
||||
read("crankbroken", 4, vis->rgba.crankbroken);
|
||||
read("frustum", 4, vis->rgba.frustum);
|
||||
read("bv", 4, vis->rgba.bv);
|
||||
read("bvactive", 4, vis->rgba.bvactive);
|
||||
}
|
||||
|
||||
// advance to next element
|
||||
|
||||
@@ -44,7 +44,7 @@ class mjXReader : public mjXBase {
|
||||
|
||||
// XML sections embedded in all formats
|
||||
static void Compiler(tinyxml2::XMLElement* section, mjSpec* s); // compiler section
|
||||
static void Option(tinyxml2::XMLElement* section, mjOption* opt); // option section
|
||||
static void Option(tinyxml2::XMLElement* section, mjSpec* s, mjOption* opt); // option section
|
||||
static void Size(tinyxml2::XMLElement* section, mjSpec* s); // size section
|
||||
|
||||
private:
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ void mjXURDF::Parse(
|
||||
}
|
||||
|
||||
if ((section = FindSubElem(mjc, "option"))) {
|
||||
mjXReader::Option(section, &spec->option);
|
||||
mjXReader::Option(section, spec, &spec->option);
|
||||
}
|
||||
|
||||
if ((section = FindSubElem(mjc, "size"))) {
|
||||
|
||||
+3
-2
@@ -845,14 +845,15 @@ template int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, int len,
|
||||
// throw error if identically zero
|
||||
int mjXUtil::ReadQuat(XMLElement* elem, const char* attr, double* data, std::string& text,
|
||||
bool required) {
|
||||
ReadAttr(elem, attr, /*len=*/4, data, text, required, /*exact=*/true);
|
||||
int n = ReadAttr(elem, attr, /*len=*/4, data, text, required, /*exact=*/true);
|
||||
if (n == 0) return 0;
|
||||
|
||||
// check for 0 quaternion
|
||||
if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) {
|
||||
throw mjXError(elem, "zero quaternion is not allowed");
|
||||
}
|
||||
|
||||
return 4;
|
||||
return n;
|
||||
}
|
||||
|
||||
// read DOUBLE array into C++ vector, return number read
|
||||
|
||||
@@ -30,7 +30,10 @@ namespace expected {
|
||||
|
||||
struct mjsElement { MJSELEMENT_FIELDS };
|
||||
struct mjsCompiler { MJSCOMPILER_FIELDS };
|
||||
struct mjSpec { MJSPEC_FIELDS };
|
||||
struct mjSpec {
|
||||
MJSPEC_FIELDS
|
||||
mjsAuthored authored;
|
||||
};
|
||||
struct mjsOrientation { MJSORIENTATION_FIELDS };
|
||||
struct mjsPlugin { MJSPLUGIN_FIELDS };
|
||||
struct mjsBody { MJSBODY_FIELDS };
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "src/cc/array_safety.h"
|
||||
#include "src/engine/engine_util_errmem.h"
|
||||
#include "src/user/user_api.h"
|
||||
#include "src/xml/xml_api.h"
|
||||
#include "test/compare_model.h"
|
||||
#include "test/fixture.h"
|
||||
@@ -64,6 +65,73 @@ TEST_F(XMLReaderTest, UniqueElementTest) {
|
||||
EXPECT_THAT(error.data(), HasSubstr("unique element 'flag' found 2 times"));
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, AuthoredFromXml) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<compiler boundmass="1"/>
|
||||
<option timestep="0.01" gravity="0 0 -5">
|
||||
<flag constraint="disable"/>
|
||||
</option>
|
||||
<visual>
|
||||
<global fovy="60"/>
|
||||
<quality shadowsize="1024"/>
|
||||
</visual>
|
||||
<worldbody/>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjSpec* spec = mj_parseXMLString(xml, 0, error.data(), error.size());
|
||||
ASSERT_THAT(spec, NotNull()) << error.data();
|
||||
|
||||
// option: timestep authored, gravity authored, density not authored
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->option.timestep), 1);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, spec->option.gravity), 1);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->option.density), 0);
|
||||
|
||||
// compiler: boundmass authored, boundinertia not authored
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->compiler.boundmass), 1);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->compiler.boundinertia), 0);
|
||||
|
||||
// flags: constraint disable authored, contact not authored
|
||||
EXPECT_NE(spec->authored.disableflags & mjDSBL_CONSTRAINT, 0);
|
||||
EXPECT_EQ(spec->authored.disableflags & mjDSBL_CONTACT, 0);
|
||||
|
||||
// visual global: fovy authored, ipd not authored
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->visual.global.fovy), 1);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->visual.global.ipd), 0);
|
||||
|
||||
// visual quality: shadowsize authored, offsamples not authored
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->visual.quality.shadowsize), 1);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->visual.quality.offsamples), 0);
|
||||
|
||||
mj_deleteSpec(spec);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, AuthoredDefaultsZero) {
|
||||
static constexpr char xml[] = R"(
|
||||
<mujoco>
|
||||
<worldbody/>
|
||||
</mujoco>
|
||||
)";
|
||||
|
||||
std::array<char, 1024> error;
|
||||
mjSpec* spec = mj_parseXMLString(xml, 0, error.data(), error.size());
|
||||
ASSERT_THAT(spec, NotNull()) << error.data();
|
||||
|
||||
// nothing authored in an empty model
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->option.timestep), 0);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->option.gravity), 0);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->compiler.boundmass), 0);
|
||||
EXPECT_EQ(spec->authored.disableflags, 0);
|
||||
EXPECT_EQ(spec->authored.enableflags, 0);
|
||||
EXPECT_EQ(spec->authored.disableactuator, 0);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->visual.global.fovy), 0);
|
||||
EXPECT_EQ(mjs_isAuthored(spec, &spec->visual.map.znear), 0);
|
||||
|
||||
mj_deleteSpec(spec);
|
||||
}
|
||||
|
||||
TEST_F(XMLReaderTest, MemorySize) {
|
||||
std::array<char, 1024> error;
|
||||
{
|
||||
|
||||
@@ -5868,6 +5868,21 @@ public unsafe struct mjsCompiler_ {
|
||||
public mjLROpt_ LRopt;
|
||||
public void* meshdir;
|
||||
public void* texturedir;
|
||||
public UInt64 authored;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe struct mjsAuthored_ {
|
||||
public UInt64 option;
|
||||
public int disableflags;
|
||||
public int enableflags;
|
||||
public int disableactuator;
|
||||
public UInt64 visual_global;
|
||||
public UInt64 visual_quality;
|
||||
public UInt64 visual_headlight;
|
||||
public UInt64 visual_map;
|
||||
public UInt64 visual_scale;
|
||||
public UInt64 visual_rgba;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
||||
@@ -1503,6 +1503,75 @@ struct MjWarningStat {
|
||||
bool owned_ = false;
|
||||
};
|
||||
|
||||
struct MjsAuthored {
|
||||
explicit MjsAuthored(mjsAuthored *ptr);
|
||||
mjsAuthored* get() const;
|
||||
void set(mjsAuthored* ptr);
|
||||
uint64_t option() const {
|
||||
return ptr_->option;
|
||||
}
|
||||
void set_option(uint64_t value) {
|
||||
ptr_->option = value;
|
||||
}
|
||||
int disableflags() const {
|
||||
return ptr_->disableflags;
|
||||
}
|
||||
void set_disableflags(int value) {
|
||||
ptr_->disableflags = value;
|
||||
}
|
||||
int enableflags() const {
|
||||
return ptr_->enableflags;
|
||||
}
|
||||
void set_enableflags(int value) {
|
||||
ptr_->enableflags = value;
|
||||
}
|
||||
int disableactuator() const {
|
||||
return ptr_->disableactuator;
|
||||
}
|
||||
void set_disableactuator(int value) {
|
||||
ptr_->disableactuator = value;
|
||||
}
|
||||
uint64_t visual_global() const {
|
||||
return ptr_->visual_global;
|
||||
}
|
||||
void set_visual_global(uint64_t value) {
|
||||
ptr_->visual_global = value;
|
||||
}
|
||||
uint64_t visual_quality() const {
|
||||
return ptr_->visual_quality;
|
||||
}
|
||||
void set_visual_quality(uint64_t value) {
|
||||
ptr_->visual_quality = value;
|
||||
}
|
||||
uint64_t visual_headlight() const {
|
||||
return ptr_->visual_headlight;
|
||||
}
|
||||
void set_visual_headlight(uint64_t value) {
|
||||
ptr_->visual_headlight = value;
|
||||
}
|
||||
uint64_t visual_map() const {
|
||||
return ptr_->visual_map;
|
||||
}
|
||||
void set_visual_map(uint64_t value) {
|
||||
ptr_->visual_map = value;
|
||||
}
|
||||
uint64_t visual_scale() const {
|
||||
return ptr_->visual_scale;
|
||||
}
|
||||
void set_visual_scale(uint64_t value) {
|
||||
ptr_->visual_scale = value;
|
||||
}
|
||||
uint64_t visual_rgba() const {
|
||||
return ptr_->visual_rgba;
|
||||
}
|
||||
void set_visual_rgba(uint64_t value) {
|
||||
ptr_->visual_rgba = value;
|
||||
}
|
||||
|
||||
private:
|
||||
mjsAuthored* ptr_;
|
||||
};
|
||||
|
||||
struct MjsElement {
|
||||
explicit MjsElement(mjsElement *ptr);
|
||||
mjsElement* get() const;
|
||||
@@ -2273,6 +2342,12 @@ struct MjsCompiler {
|
||||
*(ptr_->texturedir) = value;
|
||||
}
|
||||
}
|
||||
uint64_t authored() const {
|
||||
return ptr_->authored;
|
||||
}
|
||||
void set_authored(uint64_t value) {
|
||||
ptr_->authored = value;
|
||||
}
|
||||
|
||||
private:
|
||||
mjsCompiler* ptr_;
|
||||
@@ -5866,6 +5941,7 @@ struct MjSpec {
|
||||
MjOption option;
|
||||
MjVisual visual;
|
||||
MjStatistic stat;
|
||||
MjsAuthored authored;
|
||||
};
|
||||
|
||||
struct MjsActuator {
|
||||
@@ -7672,6 +7748,14 @@ void MjWarningStat::set(mjWarningStat* ptr) {
|
||||
ptr_ = ptr;
|
||||
}
|
||||
|
||||
MjsAuthored::MjsAuthored(mjsAuthored *ptr) : ptr_(ptr) {}
|
||||
mjsAuthored* MjsAuthored::get() const {
|
||||
return ptr_;
|
||||
}
|
||||
void MjsAuthored::set(mjsAuthored* ptr) {
|
||||
ptr_ = ptr;
|
||||
}
|
||||
|
||||
MjsElement::MjsElement(mjsElement *ptr) : ptr_(ptr) {}
|
||||
mjsElement* MjsElement::get() const {
|
||||
return ptr_;
|
||||
@@ -8514,7 +8598,8 @@ MjSpec::MjSpec()
|
||||
compiler(&ptr_->compiler),
|
||||
option(&ptr_->option),
|
||||
visual(&ptr_->visual),
|
||||
stat(&ptr_->stat) {
|
||||
stat(&ptr_->stat),
|
||||
authored(&ptr_->authored) {
|
||||
owned_ = true;
|
||||
mjs_defaultSpec(ptr_);
|
||||
};
|
||||
@@ -8525,7 +8610,8 @@ MjSpec::MjSpec(mjSpec *ptr)
|
||||
compiler(&ptr_->compiler),
|
||||
option(&ptr_->option),
|
||||
visual(&ptr_->visual),
|
||||
stat(&ptr_->stat) {}
|
||||
stat(&ptr_->stat),
|
||||
authored(&ptr_->authored) {}
|
||||
|
||||
MjSpec::MjSpec(const MjSpec &other)
|
||||
: ptr_(mj_copySpec(other.get())),
|
||||
@@ -8533,7 +8619,8 @@ MjSpec::MjSpec(const MjSpec &other)
|
||||
compiler(&ptr_->compiler),
|
||||
option(&ptr_->option),
|
||||
visual(&ptr_->visual),
|
||||
stat(&ptr_->stat) {
|
||||
stat(&ptr_->stat),
|
||||
authored(&ptr_->authored) {
|
||||
owned_ = true;
|
||||
}
|
||||
|
||||
@@ -12630,6 +12717,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
||||
emscripten::class_<MjSpec>("MjSpec")
|
||||
.constructor<const MjSpec &>()
|
||||
.property("timer", &MjSpec::timer)
|
||||
.property("authored", &MjSpec::authored, reference())
|
||||
.property("comment", &MjSpec::comment, &MjSpec::set_comment, reference())
|
||||
.property("compiler", &MjSpec::compiler, reference())
|
||||
.property("element", &MjSpec::element, reference())
|
||||
@@ -12810,6 +12898,17 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
||||
.property("target", &MjsActuator::target, &MjsActuator::set_target, reference())
|
||||
.property("trntype", &MjsActuator::trntype, &MjsActuator::set_trntype, reference())
|
||||
.property("userdata", &MjsActuator::userdata, reference());
|
||||
emscripten::class_<MjsAuthored>("MjsAuthored")
|
||||
.property("disableactuator", &MjsAuthored::disableactuator, &MjsAuthored::set_disableactuator, reference())
|
||||
.property("disableflags", &MjsAuthored::disableflags, &MjsAuthored::set_disableflags, reference())
|
||||
.property("enableflags", &MjsAuthored::enableflags, &MjsAuthored::set_enableflags, reference())
|
||||
.property("option", &MjsAuthored::option, &MjsAuthored::set_option, reference())
|
||||
.property("visual_global", &MjsAuthored::visual_global, &MjsAuthored::set_visual_global, reference())
|
||||
.property("visual_headlight", &MjsAuthored::visual_headlight, &MjsAuthored::set_visual_headlight, reference())
|
||||
.property("visual_map", &MjsAuthored::visual_map, &MjsAuthored::set_visual_map, reference())
|
||||
.property("visual_quality", &MjsAuthored::visual_quality, &MjsAuthored::set_visual_quality, reference())
|
||||
.property("visual_rgba", &MjsAuthored::visual_rgba, &MjsAuthored::set_visual_rgba, reference())
|
||||
.property("visual_scale", &MjsAuthored::visual_scale, &MjsAuthored::set_visual_scale, reference());
|
||||
emscripten::class_<MjsBody>("MjsBody")
|
||||
.property("alt", &MjsBody::alt, reference())
|
||||
.property("childclass", &MjsBody::childclass, &MjsBody::set_childclass, reference())
|
||||
@@ -12852,6 +12951,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
||||
emscripten::class_<MjsCompiler>("MjsCompiler")
|
||||
.property("LRopt", &MjsCompiler::LRopt, reference())
|
||||
.property("alignfree", &MjsCompiler::alignfree, &MjsCompiler::set_alignfree, reference())
|
||||
.property("authored", &MjsCompiler::authored, &MjsCompiler::set_authored, reference())
|
||||
.property("autolimits", &MjsCompiler::autolimits, &MjsCompiler::set_autolimits, reference())
|
||||
.property("balanceinertia", &MjsCompiler::balanceinertia, &MjsCompiler::set_balanceinertia, reference())
|
||||
.property("boundinertia", &MjsCompiler::boundinertia, &MjsCompiler::set_boundinertia, reference())
|
||||
@@ -13390,6 +13490,7 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) {
|
||||
.property("translate", &MjvScene::translate);
|
||||
emscripten::register_optional<MjSpec>();
|
||||
emscripten::register_optional<MjsActuator>();
|
||||
emscripten::register_optional<MjsAuthored>();
|
||||
emscripten::register_optional<MjsBody>();
|
||||
emscripten::register_optional<MjsCamera>();
|
||||
emscripten::register_optional<MjsCompiler>();
|
||||
|
||||
@@ -666,7 +666,8 @@ MjSpec::MjSpec()
|
||||
compiler(&ptr_->compiler),
|
||||
option(&ptr_->option),
|
||||
visual(&ptr_->visual),
|
||||
stat(&ptr_->stat) {
|
||||
stat(&ptr_->stat),
|
||||
authored(&ptr_->authored) {
|
||||
owned_ = true;
|
||||
mjs_defaultSpec(ptr_);
|
||||
};
|
||||
@@ -677,7 +678,8 @@ MjSpec::MjSpec(mjSpec *ptr)
|
||||
compiler(&ptr_->compiler),
|
||||
option(&ptr_->option),
|
||||
visual(&ptr_->visual),
|
||||
stat(&ptr_->stat) {}
|
||||
stat(&ptr_->stat),
|
||||
authored(&ptr_->authored) {}
|
||||
|
||||
MjSpec::MjSpec(const MjSpec &other)
|
||||
: ptr_(mj_copySpec(other.get())),
|
||||
@@ -685,7 +687,8 @@ MjSpec::MjSpec(const MjSpec &other)
|
||||
compiler(&ptr_->compiler),
|
||||
option(&ptr_->option),
|
||||
visual(&ptr_->visual),
|
||||
stat(&ptr_->stat) {
|
||||
stat(&ptr_->stat),
|
||||
authored(&ptr_->authored) {
|
||||
owned_ = true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user