15
15
#include < array>
16
16
#include < cstddef> // IWYU pragma: keep
17
17
#include < cstdint>
18
+ #include < cstring>
18
19
#include < memory>
19
20
#include < optional>
20
21
#include < string>
@@ -122,6 +123,41 @@ struct MjSpec {
122
123
~MjSpec () {
123
124
mj_deleteSpec (ptr);
124
125
}
126
+
127
+ raw::MjModel* Compile () {
128
+ if (assets.empty ()) {
129
+ auto m = mj_compile (ptr, 0 );
130
+ if (!m || mjs_isWarning (ptr)) {
131
+ throw py::value_error (mjs_getError (ptr));
132
+ }
133
+ return m;
134
+ }
135
+ mjVFS vfs;
136
+ mj_defaultVFS (&vfs);
137
+ for (const auto & asset : assets) {
138
+ std::string buffer_name =
139
+ _impl::StripPath (py::cast<std::string>(asset.first ).c_str ());
140
+ std::string buffer = py::cast<std::string>(asset.second );
141
+ const int vfs_error = InterceptMjErrors (mj_addBufferVFS)(
142
+ &vfs, buffer_name.c_str (), buffer.c_str (), buffer.size ());
143
+ if (vfs_error) {
144
+ mj_deleteVFS (&vfs);
145
+ if (vfs_error == 2 ) {
146
+ throw py::value_error (" Repeated file name in assets dict: " +
147
+ buffer_name);
148
+ } else {
149
+ throw py::value_error (" Asset failed to load: " + buffer_name);
150
+ }
151
+ }
152
+ }
153
+ auto m = mj_compile (ptr, &vfs);
154
+ if (!m || mjs_isWarning (ptr)) {
155
+ throw py::value_error (mjs_getError (ptr));
156
+ }
157
+ mj_deleteVFS (&vfs);
158
+ return m;
159
+ }
160
+
125
161
raw::MjSpec* ptr;
126
162
py::dict assets;
127
163
bool override_assets = true ;
@@ -245,8 +281,8 @@ void SetFrame(raw::MjsBody* body, mjtObj objtype, raw::MjsFrame* frame) {
245
281
246
282
PYBIND11_MODULE (_specs, m) {
247
283
auto structs_m = py::module::import (" mujoco._structs" );
248
- py::function mjmodel_from_spec_ptr =
249
- structs_m.attr (" MjModel" ).attr (" _from_spec_ptr " );
284
+ py::function mjmodel_from_raw_ptr =
285
+ structs_m.attr (" MjModel" ).attr (" _from_model_ptr " );
250
286
py::function mjmodel_mjdata_from_spec_ptr =
251
287
structs_m.attr (" _recompile_spec_addr" );
252
288
@@ -416,33 +452,8 @@ PYBIND11_MODULE(_specs, m) {
416
452
return mjs_findDefault (self.ptr , classname.c_str ());
417
453
},
418
454
py::return_value_policy::reference_internal);
419
- mjSpec.def (" compile" , [mjmodel_from_spec_ptr](MjSpec& self) -> py::object {
420
- if (self.assets .empty ()) {
421
- return mjmodel_from_spec_ptr (reinterpret_cast <uintptr_t >(self.ptr ));
422
- }
423
- mjVFS vfs;
424
- mj_defaultVFS (&vfs);
425
- for (const auto & asset : self.assets ) {
426
- std::string buffer_name =
427
- _impl::StripPath (py::cast<std::string>(asset.first ).c_str ());
428
- std::string buffer = py::cast<std::string>(asset.second );
429
- const int vfs_error = InterceptMjErrors (mj_addBufferVFS)(
430
- &vfs, buffer_name.c_str (), buffer.c_str (), buffer.size ());
431
- if (vfs_error) {
432
- mj_deleteVFS (&vfs);
433
- if (vfs_error == 2 ) {
434
- throw py::value_error (" Repeated file name in assets dict: " +
435
- buffer_name);
436
- } else {
437
- throw py::value_error (" Asset failed to load: " + buffer_name);
438
- }
439
- }
440
- }
441
- auto model =
442
- mjmodel_from_spec_ptr (reinterpret_cast <uintptr_t >(self.ptr ),
443
- reinterpret_cast <uintptr_t >(&vfs));
444
- mj_deleteVFS (&vfs);
445
- return model;
455
+ mjSpec.def (" compile" , [mjmodel_from_raw_ptr](MjSpec& self) -> py::object {
456
+ return mjmodel_from_raw_ptr (reinterpret_cast <uintptr_t >(self.Compile ()));
446
457
});
447
458
mjSpec.def_property (
448
459
" assets" ,
@@ -463,9 +474,10 @@ PYBIND11_MODULE(_specs, m) {
463
474
self.override_assets = override_assets;
464
475
});
465
476
mjSpec.def (" to_xml" , [](MjSpec& self) -> std::string {
477
+ mj_deleteModel (self.Compile ());
478
+ std::array<char , 1024 > err;
466
479
int size = mj_saveXMLString (self.ptr , nullptr , 0 , nullptr , 0 );
467
480
std::unique_ptr<char []> buf (new char [size + 1 ]);
468
- std::array<char , 1024 > err;
469
481
buf[0 ] = ' \0 ' ;
470
482
err[0 ] = ' \0 ' ;
471
483
mj_saveXMLString (self.ptr , buf.get (), size + 1 , err.data (), err.size ());
0 commit comments