From 98593259e7906de60a36ef932fc23a6b31c2ab63 Mon Sep 17 00:00:00 2001 From: Matija Kecman Date: Thu, 22 Jan 2026 06:19:39 -0800 Subject: [PATCH] Internal change PiperOrigin-RevId: 859578296 Change-Id: If4dd4ca68ab9750693e5f6ff20ea0c78d6b93464 --- src/experimental/studio/app.cc | 97 ++++++++++++++++++++++------------ src/experimental/studio/app.h | 1 + 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/experimental/studio/app.cc b/src/experimental/studio/app.cc index 5f0b9623..8644d940 100644 --- a/src/experimental/studio/app.cc +++ b/src/experimental/studio/app.cc @@ -156,6 +156,7 @@ void App::ClearModel() { void App::RequestModelLoad(std::string model_file) { pending_load_ = std::move(model_file); + model_kind_ = kModelFromFile; } void App::RequestModelReload() { @@ -222,7 +223,7 @@ void App::LoadModelFromBuffer(std::span buffer, return; } - InitModel(model, spec, &vfs, "", kModelFromBuffer); + InitModel(model, spec, &vfs, std::string(filename), kModelFromBuffer); mj_deleteVFS(&vfs); } @@ -303,37 +304,39 @@ void App::UpdatePhysics() { return; } - if (!step_control_.IsPaused()) { - mju_zero(data_->xfrc_applied, 6 * model_->nbody); - mjv_applyPerturbPose(model_, data_, &perturb_, 0); - mjv_applyPerturbForce(model_, data_, &perturb_); - } else { - mjv_applyPerturbPose(model_, data_, &perturb_, 1); - } - - if (data_) { - for (int i = 0; i < mjNTIMER; i++) { - data_->timer[i].duration = 0; - data_->timer[i].number = 0; - } - } bool stepped = false; + { + if (!step_control_.IsPaused()) { + mju_zero(data_->xfrc_applied, 6 * model_->nbody); + mjv_applyPerturbPose(model_, data_, &perturb_, 0); + mjv_applyPerturbForce(model_, data_, &perturb_); + } else { + mjv_applyPerturbPose(model_, data_, &perturb_, 1); + } - platform::StepControl::Status status = step_control_.Advance(model_, data_); - if (status == platform::StepControl::Status::kPaused) { - // do nothing - } else if (status == platform::StepControl::Status::kOk) { - stepped = true; - // If we are adding to the history we didn't have a divergence error - step_error_ = ""; - } else if (status == platform::StepControl::Status::kAutoReset) { - ResetPhysics(); - } else if (status == platform::StepControl::Status::kDiverged) { - stepped = true; - for (mjtWarning w : platform::StepControl::kDivergedWarnings) { - if (data_->warning[w].number > 0) { - step_error_ = mju_warningText(w, data_->warning[w].lastinfo); + if (data_) { + for (int i = 0; i < mjNTIMER; i++) { + data_->timer[i].duration = 0; + data_->timer[i].number = 0; + } + } + + platform::StepControl::Status status = step_control_.Advance(model_, data_); + if (status == platform::StepControl::Status::kPaused) { + // do nothing + } else if (status == platform::StepControl::Status::kOk) { + stepped = true; + // If we are adding to the history we didn't have a divergence error + step_error_ = ""; + } else if (status == platform::StepControl::Status::kAutoReset) { + ResetPhysics(); + } else if (status == platform::StepControl::Status::kDiverged) { + stepped = true; + for (mjtWarning w : platform::StepControl::kDivergedWarnings) { + if (data_->warning[w].number > 0) { + step_error_ = mju_warningText(w, data_->warning[w].lastinfo); + } } } } @@ -373,13 +376,19 @@ bool App::Update() { // Check to see if we need to load a new model. if (pending_load_.has_value()) { - std::string model_file = std::move(pending_load_.value()); + std::string load_data = std::move(pending_load_.value()); pending_load_.reset(); - - if (model_file.empty()) { - InitEmptyModel(); + if (model_kind_ == kModelFromBuffer) { + // TODO(matijak): need to pass the content type and not assume mjb. + LoadModelFromBuffer( + std::span( + reinterpret_cast(load_data.data()), + load_data.size()), + "application/mjb", model_name_); + } else if (model_kind_ == kModelFromFile) { + LoadModelFromFile(load_data); } else { - LoadModelFromFile(model_file); + InitEmptyModel(); } } @@ -733,6 +742,15 @@ void App::LoadSettings() { if (!settings.empty()) { ui_.FromDict(platform::ReadIniSection(settings, "[Studio][UX]")); ImGui::LoadIniSettingsFromMemory(settings.data(), settings.size()); + + platform::KeyValues plugin_names = + platform::ReadIniSection(settings, "[Studio][Plugins]"); + platform::ForEachGuiPlugin([&](platform::GuiPlugin* plugin) { + auto it = plugin_names.find(plugin->name); + if (it != plugin_names.end()) { + plugin->active = std::stoi(it->second) != 0; + } + }); } } } @@ -741,6 +759,13 @@ void App::SaveSettings() { if (!ini_path_.empty()) { std::string settings = ImGui::SaveIniSettingsToMemory(); platform::AppendIniSection(settings, "[Studio][UX]", ui_.ToDict()); + + platform::KeyValues plugin_names; + platform::ForEachGuiPlugin([&](platform::GuiPlugin* plugin) { + plugin_names[plugin->name] = std::to_string((int)plugin->active); + }); + platform::AppendIniSection(settings, "[Studio][Plugins]", plugin_names); + platform::SaveText(settings, ini_path_); } } @@ -1545,6 +1570,7 @@ void App::MainMenuGui() { #endif // !__EMSCRIPTEN__ ImGui::EndMenu(); } + if (ImGui::BeginMenu("Simulation")) { if (ImGui::MenuItem("Pause", "Space", step_control_.IsPaused())) { step_control_.TogglePause(); @@ -1572,9 +1598,9 @@ void App::MainMenuGui() { } ImGui::EndMenu(); } - ImGui::EndMenu(); } + if (ImGui::BeginMenu("View")) { if (ImGui::MenuItem("Save Config")) { SaveSettings(); @@ -1604,6 +1630,7 @@ void App::MainMenuGui() { } ImGui::EndMenu(); } + if (ImGui::BeginMenu("Charts")) { if (ImGui::MenuItem("Solver", "F9")) { tmp_.chart_solver = !tmp_.chart_solver; diff --git a/src/experimental/studio/app.h b/src/experimental/studio/app.h index 47da2715..0d548e48 100644 --- a/src/experimental/studio/app.h +++ b/src/experimental/studio/app.h @@ -188,6 +188,7 @@ class App { std::vector GetCameraNames(); std::string ini_path_; + std::string model_name_; // Used if model_kind_ is kModelFromBuffer. std::string model_path_; std::string load_error_; std::string step_error_;