@@ -199,45 +199,53 @@ void App::ClearModel() {
199199 error_ = " " ;
200200}
201201
202- void App::LoadModel (std::string model_file) {
203- pending_load_ = std::move (model_file);
204- }
205-
206- void App::ProcessPendingLoad () {
207- if (!pending_load_.has_value ()) {
208- return ;
202+ void App::RequestModelLoad (std::string model_file) {
203+ if (model_file.starts_with (' [' ) || model_file.ends_with (' ]' )) {
204+ pending_load_ = " " ;
205+ } else {
206+ pending_load_ = std::move (model_file);
209207 }
208+ }
210209
211- // Note that a non-empty model_file_ implies that a model was successfully
212- // loaded.
213- model_file_ = std::move (pending_load_.value ());
214- pending_load_.reset ();
215-
210+ void App::LoadModel (std::string data, ContentType type) {
216211 // Delete the existing mjModel and mjData.
217212 ClearModel ();
218213
219- // Try to load the requested mjModel.
220214 char err[1000 ] = " " ;
221- if (model_file_.ends_with (" .mjb" )) {
222- model_ = mj_loadModel (model_file_.c_str (), 0 );
223- } else if (model_file_.ends_with (" .xml" )) {
224- spec_ = mj_parseXML (model_file_.c_str (), nullptr , err, sizeof (err));
215+ if (type == ContentType::kFilepath ) {
216+ // Store the file path as the model name. Note that we use this model name
217+ // to perform reload operations.
218+ model_name_ = std::move (data);
219+ if (model_name_.ends_with (" .mjb" )) {
220+ model_ = mj_loadModel (model_name_.c_str (), 0 );
221+ } else if (model_name_.ends_with (" .xml" )) {
222+ spec_ = mj_parseXML (model_name_.c_str (), nullptr , err, sizeof (err));
223+ if (spec_ && err[0 ] == 0 ) {
224+ model_ = mj_compile (spec_, nullptr );
225+ }
226+ } else {
227+ error_ = " Unknown model file type; expected .mjb or .xml." ;
228+ }
229+ } else if (type == ContentType::kModelXml ) {
230+ model_name_ = " [xml]" ;
231+ spec_ = mj_parseXMLString (data.c_str (), nullptr , err, sizeof (err));
225232 if (spec_ && err[0 ] == 0 ) {
226233 model_ = mj_compile (spec_, nullptr );
227234 }
228- } else {
229- error_ = " Unknown model file type; expected .mjb or .xml." ;
235+ } else if (type == ContentType::kModelMjb ) {
236+ model_name_ = " [mjb]" ;
237+ model_ = mj_loadModelBuffer (data.data (), data.size ());
230238 }
239+
231240 if (err[0 ]) {
232241 error_ = err;
233- fprintf (stderr, " Error loading model: %s\n " , error_.c_str ());
234242 }
235243
236244 // If no mjModel was loaded, load an empty mjModel.
237- if (model_file_ .empty () || model_ == nullptr ) {
245+ if (model_name_ .empty () || model_ == nullptr ) {
238246 spec_ = mj_makeSpec ();
239247 model_ = mj_compile (spec_, 0 );
240- model_file_ = " " ;
248+ model_name_ = " " ;
241249 }
242250 if (!model_) {
243251 mju_error (" Error loading model: %s" , error_.c_str ());
@@ -270,11 +278,11 @@ void App::ProcessPendingLoad() {
270278 // to the loaded model.
271279 std::string base_path = " /" ;
272280 std::string model_name = " model" ;
273- if (!model_file_ .empty () &&
274- (model_file_ .ends_with (" .xml" ) || model_file_ .ends_with (" .mjb" ))) {
275- window_->SetTitle (" MuJoCo Studio : " + model_file_ );
276- tmp_.last_load_file = std::string (model_file_ );
277- std::filesystem::path path (model_file_ );
281+ if (!model_name_ .empty () &&
282+ (model_name_ .ends_with (" .xml" ) || model_name_ .ends_with (" .mjb" ))) {
283+ window_->SetTitle (" MuJoCo Studio : " + model_name_ );
284+ tmp_.last_load_file = std::string (model_name_ );
285+ std::filesystem::path path (model_name_ );
278286 base_path = path.parent_path ().string () + " /" ;
279287 model_name = path.stem ().string ();
280288 } else {
@@ -289,7 +297,7 @@ void App::ProcessPendingLoad() {
289297 tmp_.last_save_screenshot_file = base_path + " screenshot.webp" ;
290298}
291299
292- bool App::IsModelLoaded () const { return !model_file_ .empty (); }
300+ bool App::IsModelLoaded () const { return !model_name_ .empty (); }
293301
294302void App::ResetPhysics () {
295303 mj_resetData (model_, data_);
@@ -298,7 +306,11 @@ void App::ResetPhysics() {
298306}
299307
300308void App::UpdatePhysics () {
301- ProcessPendingLoad ();
309+ if (pending_load_.has_value ()) {
310+ std::string model_file = std::move (pending_load_.value ());
311+ pending_load_.reset ();
312+ LoadModel (model_file, ContentType::kFilepath );
313+ }
302314 if (!IsModelLoaded ()) {
303315 return ;
304316 }
@@ -372,7 +384,7 @@ bool App::Update() {
372384 // Check to see if a model was dropped on the window.
373385 const std::string drop_file = window_->GetDropFile ();
374386 if (!drop_file.empty ()) {
375- LoadModel (drop_file);
387+ RequestModelLoad (drop_file);
376388 }
377389
378390 // Only update the simulation if a popup window is not open. Note that the
@@ -564,7 +576,7 @@ void App::HandleKeyboardEvents() {
564576 std::string keyframe = platform::KeyframeToString (model_, data_, false );
565577 platform::MaybeSaveToClipboard (keyframe);
566578 } else if (ImGui_IsChordJustPressed (ImGuiKey_L | ImGuiMod_Ctrl)) {
567- LoadModel (model_file_ );
579+ RequestModelLoad (model_name_ );
568580 } else if (ImGui_IsChordJustPressed (ImGuiKey_Q | ImGuiMod_Ctrl)) {
569581 tmp_.should_exit = true ;
570582 } else if (ImGui_IsChordJustPressed (ImGuiKey_A | ImGuiMod_Ctrl)) {
@@ -1208,14 +1220,14 @@ void App::ToolBarGui() {
12081220 // Reset/Reload/Unload.
12091221 style.Color (ImGuiCol_ButtonHovered, ImColor (220 , 40 , 40 , 255 ));
12101222 if (ImGui::Button (ICON_UNLOAD_MODEL, ImVec2 (48 , 32 ))) {
1211- LoadModel (" " );
1223+ RequestModelLoad (" " );
12121224 }
12131225 ImGui::SetItemTooltip (" %s" , " Unload" );
12141226 style.Reset ();
12151227
12161228 ImGui::SameLine ();
12171229 if (ImGui::Button (ICON_RELOAD_MODEL, ImVec2 (48 , 32 ))) {
1218- LoadModel (model_file_ );
1230+ RequestModelLoad (model_name_ );
12191231 }
12201232 ImGui::SetItemTooltip (" %s" , " Reload" );
12211233
@@ -1324,7 +1336,7 @@ void App::StatusBarGui() {
13241336
13251337 ImGui::TableNextColumn ();
13261338
1327- if (model_file_. empty ()) {
1339+ if (! IsModelLoaded ()) {
13281340 ImGui::Text (" Not loaded" );
13291341 } else if (model_ == nullptr ) {
13301342 ImGui::Text (" Not loaded" );
@@ -1416,7 +1428,7 @@ void App::MainMenuGui() {
14161428 }
14171429 ImGui::Separator ();
14181430 if (ImGui::MenuItem (" Unload" , " Ctrl+U" )) {
1419- LoadModel (" " );
1431+ RequestModelLoad (" " );
14201432 }
14211433 ImGui::Separator ();
14221434 if (ImGui::MenuItem (" Quit" , " Ctrl+Q" )) {
@@ -1432,7 +1444,7 @@ void App::MainMenuGui() {
14321444 ResetPhysics ();
14331445 }
14341446 if (ImGui::MenuItem (" Reload" , " Ctrl+L" )) {
1435- LoadModel (model_file_ );
1447+ RequestModelLoad (model_name_ );
14361448 }
14371449 ImGui::Separator ();
14381450 if (ImGui::BeginMenu (" Keyframes" )) {
@@ -1561,7 +1573,7 @@ void App::FileDialogGui() {
15611573 if (ImGui::BeginPopupModal (" LoadModel" , NULL ,
15621574 ImGuiWindowFlags_AlwaysAutoResize)) {
15631575 if (platform::ImGui_FileDialog (tmp_.filename , sizeof (tmp_.filename ))) {
1564- LoadModel (tmp_.filename );
1576+ RequestModelLoad (tmp_.filename );
15651577 tmp_.last_load_file = tmp_.filename ;
15661578 }
15671579 ImGui::EndPopup ();
0 commit comments