Move model_, data_, and spec_ into private accessors.

This is in preparation for an upcoming change.

PiperOrigin-RevId: 865332731
Change-Id: I74041b3caf5de841f583f76682e1ced049557202
This commit is contained in:
Haroon Qureshi
2026-02-04 04:02:22 -08:00
committed by Copybara-Service
parent 0add985a15
commit c2ede20d08
2 changed files with 90 additions and 81 deletions
+83 -81
View File
@@ -229,8 +229,7 @@ void App::LoadModelFromBuffer(std::span<const std::byte> 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<mjtNum> 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<std::byte> 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<const char*> 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");
}
+7
View File
@@ -207,6 +207,13 @@ class App {
float GetExpectedLabelWidth();
std::vector<const char*> 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_;