From c2ede20d08c5e6bf4ac0302902b05be81aa437cd Mon Sep 17 00:00:00 2001 From: Haroon Qureshi Date: Wed, 4 Feb 2026 04:02:22 -0800 Subject: [PATCH] Move model_, data_, and spec_ into private accessors. This is in preparation for an upcoming change. PiperOrigin-RevId: 865332731 Change-Id: I74041b3caf5de841f583f76682e1ced049557202 --- src/experimental/studio/app.cc | 164 +++++++++++++++++---------------- src/experimental/studio/app.h | 7 ++ 2 files changed, 90 insertions(+), 81 deletions(-) diff --git a/src/experimental/studio/app.cc b/src/experimental/studio/app.cc index 350f8595..1e7af6e8 100644 --- a/src/experimental/studio/app.cc +++ b/src/experimental/studio/app.cc @@ -229,8 +229,7 @@ void App::LoadModelFromBuffer(std::span buffer, resource.name = (char*)filename.data(); spec = mju_decodeResource(&resource, content_type.data(), &vfs); } else { - SetLoadError( - "Unknown content type; expected text/xml or application/mjb"); + SetLoadError("Unknown content type; expected text/xml or application/mjb"); return; } if (err[0]) { @@ -327,20 +326,20 @@ void App::SetLoadError(std::string error) { } void App::ResetPhysics() { - mj_resetData(model_, data_); - mj_forward(model_, data_); + mj_resetData(model(), data()); + mj_forward(model(), data()); step_error_ = ""; } void App::UpdatePhysics() { - if (model_ == nullptr) { + if (!has_model()) { return; } bool stepped = false; platform::ForEachModelPlugin([&](platform::ModelPlugin* plugin) { if (plugin->do_update) { - if (plugin->do_update(plugin, model_, data_)) { + if (plugin->do_update(plugin, model(), data())) { stepped = true; } } @@ -348,21 +347,22 @@ void App::UpdatePhysics() { if (!stepped) { if (!step_control_.IsPaused()) { - mju_zero(data_->xfrc_applied, 6 * model_->nbody); - mjv_applyPerturbPose(model_, data_, &perturb_, 0); - mjv_applyPerturbForce(model_, data_, &perturb_); + 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); + mjv_applyPerturbPose(model(), data(), &perturb_, 1); } - if (data_) { + if (has_data()) { for (int i = 0; i < mjNTIMER; i++) { - data_->timer[i].duration = 0; - data_->timer[i].number = 0; + data()->timer[i].duration = 0; + data()->timer[i].number = 0; } } - platform::StepControl::Status status = step_control_.Advance(model_, data_); + platform::StepControl::Status status = + step_control_.Advance(model(), data()); if (status == platform::StepControl::Status::kPaused) { // do nothing } else if (status == platform::StepControl::Status::kOk) { @@ -374,18 +374,18 @@ void App::UpdatePhysics() { } 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()->warning[w].number > 0) { + step_error_ = mju_warningText(w, data()->warning[w].lastinfo); } } } } if (stepped) { - profiler_.Update(model_, data_); + profiler_.Update(model(), data()); std::span state = history_.AddToHistory(); if (!state.empty()) { - mj_getState(model_, data_, state.data(), mjSTATE_INTEGRATION); + mj_getState(model(), data(), state.data(), mjSTATE_INTEGRATION); } } } @@ -397,8 +397,8 @@ void App::LoadHistory(int offset) { step_control_.Pause(); // Load the state into the data buffer. - mj_setState(model_, data_, state.data(), mjSTATE_INTEGRATION); - mj_forward(model_, data_); + mj_setState(model(), data(), state.data(), mjSTATE_INTEGRATION); + mj_forward(model(), data()); } } @@ -430,16 +430,16 @@ void App::Render() { } else { pixels_.clear(); } - renderer_->Render(model_, data_, &perturb_, &camera_, &vis_options_, + renderer_->Render(model(), data(), &perturb_, &camera_, &vis_options_, width * scale, height * scale, pixels_); window_->EndFrame(); window_->Present(pixels_); - if (data_) { + if (has_data()) { for (int i = 0; i < mjNTIMER; i++) { - data_->timer[i].duration = 0; - data_->timer[i].number = 0; + data()->timer[i].duration = 0; + data()->timer[i].number = 0; } } } @@ -487,7 +487,7 @@ void App::HandleMouseEvents() { return; } - if (!model_ || !data_) { + if (!has_model() || !has_data()) { return; } @@ -522,9 +522,9 @@ void App::HandleMouseEvents() { const mjtPertBit active = action == mjMOUSE_MOVE_V ? mjPERT_TRANSLATE : mjPERT_ROTATE; if (active != perturb_.active) { - platform::InitPerturb(model_, data_, &camera_, &perturb_, active); + platform::InitPerturb(model(), data(), &camera_, &perturb_, active); } - platform::MovePerturb(model_, data_, &camera_, &perturb_, action, + platform::MovePerturb(model(), data(), &camera_, &perturb_, action, mouse_dx, mouse_dy); } } @@ -559,7 +559,7 @@ void App::HandleMouseEvents() { // Left double click. if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { platform::PickResult picked = - platform::Pick(model_, data_, &camera_, mouse_x, mouse_y, + platform::Pick(model(), data(), &camera_, mouse_x, mouse_y, window_->GetAspectRatio(), &vis_options_); if (picked.body >= 0) { perturb_.select = picked.body; @@ -568,8 +568,8 @@ void App::HandleMouseEvents() { // Compute the local position of the selected object in the world. mjtNum tmp[3]; - mju_sub3(tmp, picked.point, data_->xpos + 3 * picked.body); - mju_mulMatTVec(perturb_.localpos, data_->xmat + 9 * picked.body, tmp, 3, + mju_sub3(tmp, picked.point, data()->xpos + 3 * picked.body); + mju_mulMatTVec(perturb_.localpos, data()->xmat + 9 * picked.body, tmp, 3, 3); } else { perturb_.select = 0; @@ -581,7 +581,7 @@ void App::HandleMouseEvents() { // Right double click. if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Right)) { platform::PickResult picked = - platform::Pick(model_, data_, &camera_, mouse_x, mouse_y, + platform::Pick(model(), data(), &camera_, mouse_x, mouse_y, window_->GetAspectRatio(), &vis_options_); mju_copy3(camera_.lookat, picked.point); if (picked.body > 0 && io.KeyCtrl) { @@ -618,14 +618,14 @@ void App::HandleKeyboardEvents() { } else if (ImGui_IsChordJustPressed(ImGuiKey_P | ImGuiMod_Ctrl)) { tmp_.file_dialog = UiTempState::FileDialog_SaveScreenshot; } else if (ImGui_IsChordJustPressed(ImGuiKey_C | ImGuiMod_Ctrl)) { - std::string keyframe = platform::KeyframeToString(model_, data_, false); + std::string keyframe = platform::KeyframeToString(model(), data(), false); platform::MaybeSaveToClipboard(keyframe); } else if (ImGui_IsChordJustPressed(ImGuiKey_L | ImGuiMod_Ctrl)) { RequestModelReload(); } else if (ImGui_IsChordJustPressed(ImGuiKey_Q | ImGuiMod_Ctrl)) { tmp_.should_exit = true; } else if (ImGui_IsChordJustPressed(ImGuiKey_A | ImGuiMod_Ctrl)) { - mjv_defaultFreeCamera(model_, &camera_); + mjv_defaultFreeCamera(model(), &camera_); } else if (ImGui_IsChordJustPressed(ImGuiKey_Tab | ImGuiMod_Shift)) { tmp_.inspector_panel = !tmp_.inspector_panel; } else if (ImGui_IsChordJustPressed(ImGuiKey_Tab)) { @@ -651,7 +651,7 @@ void App::HandleKeyboardEvents() { } else if (ImGui_IsChordJustPressed(ImGuiKey_Backspace)) { ResetPhysics(); } else if (ImGui_IsChordJustPressed(ImGuiKey_PageUp)) { - SelectParentPerturb(model_, perturb_); + SelectParentPerturb(model(), perturb_); } else if (ImGui_IsChordJustPressed(ImGuiKey_F1)) { ToggleWindow(tmp_.help); } else if (ImGui_IsChordJustPressed(ImGuiKey_F2)) { @@ -740,16 +740,16 @@ void App::HandleKeyboardEvents() { ToggleFlag(vis_options_.geomgroup[4]); } else if (ImGui_IsChordJustPressed(ImGuiKey_5)) { ToggleFlag(vis_options_.geomgroup[5]); - } else if (model_) { + } else if (has_model()) { if (ImGui_IsChordJustPressed(ImGuiKey_Escape)) { ui_.camera_idx = - platform::SetCamera(model_, &camera_, platform::kTumbleCameraIdx); + platform::SetCamera(model(), &camera_, platform::kTumbleCameraIdx); } else if (ImGui_IsChordJustPressed(ImGuiKey_LeftBracket)) { ui_.camera_idx = - platform::SetCamera(model_, &camera_, ui_.camera_idx - 1); + platform::SetCamera(model(), &camera_, ui_.camera_idx - 1); } else if (ImGui_IsChordJustPressed(ImGuiKey_RightBracket)) { ui_.camera_idx = - platform::SetCamera(model_, &camera_, ui_.camera_idx + 1); + platform::SetCamera(model(), &camera_, ui_.camera_idx + 1); } // WASD camera controls for free camera. @@ -843,7 +843,7 @@ void App::SetSpeedIndex(int idx) { void App::MoveCamera(platform::CameraMotion motion, mjtNum reldx, mjtNum reldy) { - platform::MoveCamera(model_, data_, &camera_, motion, reldx, reldy); + platform::MoveCamera(model(), data(), &camera_, motion, reldx, reldy); } void App::BuildGui() { @@ -919,15 +919,15 @@ void App::BuildGui() { ImGui::SetNextWindowPos(chart_pos, ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(chart_size, ImGuiCond_FirstUseEver); if (ImGui::Begin("Solver", &tmp_.chart_solver)) { - platform::CountsGui(model_, data_); - platform::ConvergenceGui(model_, data_); + platform::CountsGui(model(), data()); + platform::ConvergenceGui(model(), data()); } ImGui::End(); } if (tmp_.picture_in_picture) { if (ImGui::Begin("Picture-in-Picture", &tmp_.picture_in_picture)) { - PipGui(model_, data_, window_.get(), renderer_.get(), &tmp_.pips); + PipGui(model(), data(), window_.get(), renderer_.get(), &tmp_.pips); } ImGui::End(); } @@ -949,7 +949,7 @@ void App::BuildGui() { style.Var(ImGuiStyleVar_Alpha, 0.6f); if (ImGui::Begin("Stats", &tmp_.stats)) { const float fps = renderer_->GetFps(); - platform::StatsGui(model_, data_, step_control_.IsPaused(), fps); + platform::StatsGui(model(), data(), step_control_.IsPaused(), fps); } ImGui::End(); } @@ -1042,14 +1042,14 @@ void App::ModelOptionsGui() { ImGui::BeginChild("PhysicsGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Physics Settings", node_flags)) { - platform::PhysicsGui(model_, min_width); + platform::PhysicsGui(model(), min_width); ImGui::TreePop(); } ImGui::EndChild(); ImGui::BeginChild("RenderingGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Rendering Settings", node_flags)) { - platform::RenderingGui(model_, &vis_options_, renderer_->GetRenderFlags(), + platform::RenderingGui(model(), &vis_options_, renderer_->GetRenderFlags(), min_width); ImGui::TreePop(); } @@ -1057,21 +1057,21 @@ void App::ModelOptionsGui() { ImGui::BeginChild("GroupsGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Visibility Groups", node_flags)) { - platform::GroupsGui(model_, &vis_options_, min_width); + platform::GroupsGui(model(), &vis_options_, min_width); ImGui::TreePop(); } ImGui::EndChild(); ImGui::BeginChild("VisualizationGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Visualization", node_flags)) { - platform::VisualizationGui(model_, &vis_options_, &camera_, min_width); + platform::VisualizationGui(model(), &vis_options_, &camera_, min_width); ImGui::TreePop(); } ImGui::EndChild(); } void App::DataInspectorGui() { - if (data_ == nullptr) { + if (!has_data()) { ImGui::Text("No mjData loaded."); return; } @@ -1087,7 +1087,7 @@ void App::DataInspectorGui() { float noise_scale = 0; float noise_rate = 0; step_control_.GetNoiseParameters(noise_scale, noise_rate); - platform::NoiseGui(model_, data_, noise_scale, noise_rate); + platform::NoiseGui(model(), data(), noise_scale, noise_rate); step_control_.SetNoiseParameters(noise_scale, noise_rate); ImGui::TreePop(); } @@ -1095,36 +1095,36 @@ void App::DataInspectorGui() { ImGui::BeginChild("JointsGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Joints", node_flags)) { - platform::JointsGui(model_, data_, &vis_options_); + platform::JointsGui(model(), data(), &vis_options_); ImGui::TreePop(); } ImGui::EndChild(); ImGui::BeginChild("ControlsGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Controls", node_flags)) { - platform::ControlsGui(model_, data_, &vis_options_); + platform::ControlsGui(model(), data(), &vis_options_); ImGui::TreePop(); } ImGui::EndChild(); ImGui::BeginChild("SensorGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Sensor", node_flags)) { - platform::SensorGui(model_, data_); + platform::SensorGui(model(), data()); ImGui::TreePop(); } ImGui::EndChild(); ImGui::BeginChild("WatchGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("Watch", node_flags)) { - platform::WatchGui(model_, data_, ui_.watch_field, sizeof(ui_.watch_field), - ui_.watch_index); + platform::WatchGui(model(), data(), ui_.watch_field, + sizeof(ui_.watch_field), ui_.watch_index); ImGui::TreePop(); } ImGui::EndChild(); ImGui::BeginChild("StateGui", {0, 0}, child_flags); if (ImGui::TreeNodeEx("State", node_flags)) { - platform::StateGui(model_, data_, tmp_.state, tmp_.state_sig, min_width); + platform::StateGui(model(), data(), tmp_.state, tmp_.state_sig, min_width); ImGui::TreePop(); } ImGui::EndChild(); @@ -1140,7 +1140,7 @@ void DisplayElementTree(mjsElement* element) { } void App::SpecExplorerGui() { - if (spec_ == nullptr) { + if (!has_spec()) { ImGui::Text("No mjSpec loaded."); return; } @@ -1149,7 +1149,7 @@ void App::SpecExplorerGui() { ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Framed; auto display_group = [this](mjtObj type, const std::string& prefix) { - mjsElement* element = mjs_firstElement(spec_, type); + mjsElement* element = mjs_firstElement(spec(), type); while (element) { const int id = mjs_getId(element); @@ -1164,14 +1164,14 @@ void App::SpecExplorerGui() { tmp_.element_id = id; } - element = mjs_nextElement(spec_, element); + element = mjs_nextElement(spec(), element); } }; if (ImGui::TreeNodeEx("Bodies", flags)) { // We don't use `display_group` here because we do additional selection // logic tied to the `perturb_` field. - mjsElement* element = mjs_firstElement(spec_, mjOBJ_BODY); + mjsElement* element = mjs_firstElement(spec(), mjOBJ_BODY); while (element) { const int id = mjs_getId(element); @@ -1191,7 +1191,7 @@ void App::SpecExplorerGui() { perturb_.select = id; } - element = mjs_nextElement(spec_, element); + element = mjs_nextElement(spec(), element); } ImGui::TreePop(); } @@ -1217,18 +1217,20 @@ void App::PropertiesGui() { case mjOBJ_BODY: ImGui::Text("Body"); ImGui::Separator(); - platform::BodyPropertiesGui(model_, data_, tmp_.element, tmp_.element_id); + platform::BodyPropertiesGui(model(), data(), tmp_.element, + tmp_.element_id); break; case mjOBJ_JOINT: ImGui::Text("Joint"); ImGui::Separator(); - platform::JointPropertiesGui(model_, data_, tmp_.element, + platform::JointPropertiesGui(model(), data(), tmp_.element, tmp_.element_id); break; case mjOBJ_SITE: ImGui::Text("Site"); ImGui::Separator(); - platform::SitePropertiesGui(model_, data_, tmp_.element, tmp_.element_id); + platform::SitePropertiesGui(model(), data(), tmp_.element, + tmp_.element_id); break; default: // ignore other types @@ -1431,8 +1433,8 @@ void App::ToolBarGui() { if (ImGui::BeginCombo("##Camera", cameras[camera_idx], combo_flags)) { for (int n = 0; n < cameras.size(); n++) { if (ImGui::Selectable(cameras[n], (camera_idx == n))) { - ui_.camera_idx = platform::SetCamera( - model_, &camera_, n + platform::kTumbleCameraIdx); + ui_.camera_idx = platform::SetCamera(model(), &camera_, + n + platform::kTumbleCameraIdx); } } ImGui::EndCombo(); @@ -1440,7 +1442,7 @@ void App::ToolBarGui() { ImGui::SetItemTooltip("%s", "Camera"); ImGui::SameLine(); if (ImGui::Button(ICON_COPY_CAMERA)) { - std::string camera_string = platform::CameraToString(data_, &camera_); + std::string camera_string = platform::CameraToString(data(), &camera_); platform::MaybeSaveToClipboard(camera_string); } ImGui::SetItemTooltip("%s", "Copy Camera"); @@ -1524,7 +1526,7 @@ void App::StatusBarGui() { ImGui::TableNextColumn(); - if (model_ == nullptr) { + if (!has_model()) { ImGui::Text("No model loaded"); } else if (step_control_.IsPaused()) { ImGui::Text("Paused"); @@ -1645,16 +1647,16 @@ void App::MainMenuGui() { ImGui::Separator(); if (ImGui::BeginMenu("Keyframes")) { ImGui::SetNextItemWidth(200); - ImGui::SliderInt("##Key", &ui_.key_idx, 0, model_->nkey); + ImGui::SliderInt("##Key", &ui_.key_idx, 0, model()->nkey); if (ImGui::MenuItem("Load")) { - mj_resetDataKeyframe(model_, data_, ui_.key_idx); - mj_forward(model_, data_); + mj_resetDataKeyframe(model(), data(), ui_.key_idx); + mj_forward(model(), data()); } if (ImGui::MenuItem("Save")) { - mj_setKeyframe(model_, data_, ui_.key_idx); + mj_setKeyframe(model(), data(), ui_.key_idx); } if (ImGui::MenuItem("Copy")) { - std::string str = platform::KeyframeToString(model_, data_, false); + std::string str = platform::KeyframeToString(model(), data(), false); platform::MaybeSaveToClipboard(str); } ImGui::EndMenu(); @@ -1748,25 +1750,25 @@ void App::FileDialogGui() { RequestModelLoad(res.path); break; case UiTempState::FileDialog_SaveXml: - mj_saveLastXML(res.path.c_str(), model_, nullptr, 0); + mj_saveLastXML(res.path.c_str(), model(), nullptr, 0); break; case UiTempState::FileDialog_SaveMjb: - mj_saveModel(model_, res.path.c_str(), nullptr, 0); + mj_saveModel(model(), res.path.c_str(), nullptr, 0); break; case UiTempState::FileDialog_SaveScreenshot: { const int width = window_->GetWidth(); const int height = window_->GetHeight(); std::vector buffer(width * height * 3); - renderer_->RenderToTexture(model_, data_, &camera_, width, height, + renderer_->RenderToTexture(model(), data(), &camera_, width, height, buffer.data()); platform::SaveToWebp(width, height, buffer.data(), res.path); break; } case UiTempState::FileDialog_PrintModel: - mj_printModel(model_, res.path.c_str()); + mj_printModel(model(), res.path.c_str()); break; case UiTempState::FileDialog_PrintData: - mj_printData(model_, data_, res.path.c_str()); + mj_printData(model(), data(), res.path.c_str()); break; default: break; @@ -1818,14 +1820,14 @@ float App::GetExpectedLabelWidth() { std::vector App::GetCameraNames() { if (tmp_.camera_names.empty()) { - tmp_.camera_names.reserve(model_->ncam + 3); + tmp_.camera_names.reserve(model()->ncam + 3); tmp_.camera_names.push_back("Free: tumble"); tmp_.camera_names.push_back("Free: wasd"); tmp_.camera_names.push_back("Tracking (-1)"); - for (int i = 0; i < model_->ncam; i++) { - if (model_->names[model_->name_camadr[i]]) { - tmp_.camera_names.push_back(model_->names + model_->name_camadr[i]); + for (int i = 0; i < model()->ncam; i++) { + if (model()->names[model()->name_camadr[i]]) { + tmp_.camera_names.push_back(model()->names + model()->name_camadr[i]); } else { tmp_.camera_names.push_back("Unnamed"); } diff --git a/src/experimental/studio/app.h b/src/experimental/studio/app.h index 6cf8cd2e..a46dd03d 100644 --- a/src/experimental/studio/app.h +++ b/src/experimental/studio/app.h @@ -207,6 +207,13 @@ class App { float GetExpectedLabelWidth(); std::vector GetCameraNames(); + mjSpec* spec() { return spec_; } + mjModel* model() { return model_; } + mjData* data() { return data_; } + bool has_spec() const { return spec_ != nullptr; } + bool has_model() const { return model_ != nullptr; } + bool has_data() const { return data_ != nullptr; } + std::string ini_path_; std::string model_name_; // Used if model_kind_ is kModelFromBuffer. std::string model_path_;