From 9373e07d3effe3490d85cf93fcbf9ba4eb7375f3 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Fri, 5 Jun 2026 01:46:41 +0200 Subject: [PATCH] Route canvas camera reset through app core --- CMakeLists.txt | 1 + docs/modernization/build-inventory.md | 4 +++- docs/modernization/debt.md | 8 ++++++- docs/modernization/roadmap.md | 4 ++++ src/app_core/canvas_view.h | 29 ++++++++++++++++++++++++ src/node_canvas.cpp | 21 ++++++++++++++---- tests/CMakeLists.txt | 22 ++++++++++++++++++ tests/app_core/canvas_view_tests.cpp | 32 +++++++++++++++++++++++++++ tools/pano_cli/main.cpp | 28 +++++++++++++++++++++++ 9 files changed, 143 insertions(+), 6 deletions(-) create mode 100644 src/app_core/canvas_view.h create mode 100644 tests/app_core/canvas_view_tests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c39fd5..257cdd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,6 +248,7 @@ add_library(pp_app_core STATIC src/app_core/brush_ui.h src/app_core/canvas_hotkey.h src/app_core/canvas_tool_ui.h + src/app_core/canvas_view.h src/app_core/document_animation.h src/app_core/document_canvas.h src/app_core/document_cloud.h diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index 80e59ad..272a498 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -226,7 +226,9 @@ Known local toolchain state: `pp_app_core` contracts while legacy dialogs, pickers, cloud/share/export, Tools, About, history, canvas-clear, settings, and platform SonarPen startup execution remain tracked by `DEBT-0029`, `DEBT-0030`, `DEBT-0031`, - `DEBT-0033`, `DEBT-0034`, and `DEBT-0035`. + `DEBT-0033`, `DEBT-0034`, and `DEBT-0035`. `NodeCanvas::reset_camera()` + now consumes the tested `pp_app_core` reset-camera state exposed through + `pano_cli plan-canvas-camera-reset` before retained canvas camera mutation. - `src/legacy_app_preference_services.*` is the current app-shell bridge for options-menu preference execution. It keeps UI scale, viewport scale, RTL, VR mode, VR-controller, auto-timelapse, and canvas cursor-mode callbacks on diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index ec0d981..cf4e11b 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -75,6 +75,12 @@ agent or engineer to remove them without reconstructing context from chat. small-brush, not-painting, modifier, and malformed-brush states for automation. Legacy `Canvas`/`CanvasModePen` state reads and app cursor execution remain open under DEBT-0027. +- 2026-06-05: DEBT-0033 was narrowed. Canvas reset-camera defaults now go + through tested `pp_app_core`, live `NodeCanvas::reset_camera()` consumes the + planner before retained canvas mutation, and `pano_cli plan-canvas-camera-reset` + exposes the exact identity rotation, zero position/pan, and 85-degree field + of view for automation. Legacy Tools/document/cloud callers still reach the + legacy `NodeCanvas` adapter until canvas view services exist. - 2026-06-04: DEBT-0036 was narrowed again. Canvas stroke commit, thumbnail, and object-draw history paths now query saved blend state through tested `pp_renderer_gl` capability-state dispatch; CanvasLayer equirect @@ -121,7 +127,7 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0030 | Open | Modernization | File export menu action planning and execution dispatch now consume pure `pp_app_core` through the File menu, `pano_cli plan-export-menu`, and the `DocumentExportMenuServices` boundary, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy export dialogs and then reaches legacy canvas/render/video export code | Preserve current export menu behavior while export command execution moves toward document/app/renderer/video services | `pp_app_core_document_export_tests`; `pano_cli plan-export-menu --kind png`; `pano_cli plan-export-menu --kind animation-mp4 --demo`; `pano_cli plan-export-menu --kind layers --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Export menu routing, license gating, target creation, image/layer/cube/depth/animation/timelapse execution, and error reporting are owned by injected document/app/renderer/video services with File-menu callbacks acting only as UI adapters and no legacy export adapter | | DEBT-0031 | Open | Modernization | Top-level File menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_file`, `pano_cli plan-file-menu`, and the `FileMenuServices` boundary, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still invokes legacy dialogs, platform pickers, cloud code, share code, and canvas import/export paths directly | Preserve File menu behavior while app workflows move toward app/document/platform command services | `pp_app_core_file_menu_tests`; `pano_cli plan-file-menu --command save-as`; `pano_cli plan-file-menu --command import`; `pano_cli plan-file-menu --command cloud-upload`; `ctest --preset desktop-fast --build-config Debug` | File menu routing, picker dispatch, save/share/cloud/resize/export execution, and image/project import execution are owned by injected app/document/platform services with `App::init_menu_file` acting only as a UI adapter and no legacy File menu adapter | | DEBT-0032 | Open | Modernization | Layer menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_layer`, `pano_cli plan-layer-menu`, and the `DocumentLayerMenuServices` boundary; Layer menu clear reuses the `DocumentCanvasClearServices` executor; and Layer menu rename/clear/merge now share `src/legacy_document_layer_services.*`, but the bridge still calls the legacy rename dialog path, `NodePanelLayer::merge`, and reads `Canvas::I` animation/layer state directly | Preserve existing Layer menu behavior while layer commands move toward document/app services | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-menu --command clear --current-index 1 --current-name Paint`; `pano_cli plan-layer-menu --command merge --current-index 2 --lower-name Paint`; `pano_cli plan-layer-merge --layer-count 3 --from-index 2 --to-index 1`; `pano_cli plan-layer-merge --layer-count 3 --from-index 2 --to-index 1 --animation-duration 3`; `pano_cli plan-layer-menu --command rename --no-current-layer`; `ctest --preset desktop-fast --build-config Debug` | Layer rename, merge-down execution, animation gating, and selected-layer state are owned by injected document/app services with Layer-menu callbacks acting only as UI adapters and no legacy Layer menu adapter | -| DEBT-0033 | Open | Modernization | Tools menu planning and direct command execution dispatch now consume pure `pp_app_core` through `App::init_menu_tools`, `pano_cli plan-tools-menu`, `pano_cli plan-tools-panel`, and the `ToolsMenuServices` boundary, and direct command execution is centralized in `src/legacy_app_shell_services.*`; SonarPen availability/startup now routes through `PlatformServices`, but live adapters still construct legacy `NodePanelFloating` panels, mutate legacy panel nodes, clear `CanvasModeGrid`, reset `NodeCanvas` camera state, open legacy shortcuts UI, and rely on the legacy platform adapter for the retained iOS SonarPen bridge | Preserve current Tools menu behavior while UI shell actions move toward app/UI/platform services | `pp_app_core_tools_menu_tests`; `pp_platform_api_tests`; `pano_cli plan-tools-menu --command shortcuts`; `pano_cli plan-tools-panel --panel layers`; `pano_cli plan-tools-panel --panel animation --already-visible`; `ctest --preset desktop-fast --build-config Debug` | Tools panel creation, submenu routing, grid clear, camera reset, shortcuts dialog, and SonarPen dispatch are owned by injected app/UI/platform services with `App::init_menu_tools` acting only as a UI adapter and no legacy Tools adapter | +| DEBT-0033 | Open | Modernization | Tools menu planning and direct command execution dispatch now consume pure `pp_app_core` through `App::init_menu_tools`, `pano_cli plan-tools-menu`, `pano_cli plan-tools-panel`, `pano_cli plan-canvas-camera-reset`, and the `ToolsMenuServices` boundary, direct command execution is centralized in `src/legacy_app_shell_services.*`, SonarPen availability/startup now routes through `PlatformServices`, and `NodeCanvas::reset_camera()` consumes tested app-core reset defaults before mutating legacy canvas camera state, but live adapters still construct legacy `NodePanelFloating` panels, mutate legacy panel nodes, clear `CanvasModeGrid`, open legacy shortcuts UI, and rely on the legacy platform adapter for the retained iOS SonarPen bridge | Preserve current Tools menu and reset-camera behavior while UI shell actions move toward app/UI/platform/canvas services | `pp_app_core_tools_menu_tests`; `pp_app_core_canvas_view_tests`; `pp_platform_api_tests`; `pano_cli plan-tools-menu --command shortcuts`; `pano_cli plan-tools-panel --panel layers`; `pano_cli plan-tools-panel --panel animation --already-visible`; `pano_cli plan-canvas-camera-reset`; `ctest --preset desktop-fast --build-config Debug` | Tools panel creation, submenu routing, grid clear, camera reset, shortcuts dialog, and SonarPen dispatch are owned by injected app/UI/platform/canvas services with `App::init_menu_tools` acting only as a UI adapter and no legacy Tools adapter | | DEBT-0034 | Open | Modernization | About menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_about`, `pano_cli plan-about-menu`, and the `AboutMenuServices` boundary, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy About/manual/what's-new dialogs, invokes the injected crash hook, and runs the legacy Canvas stroke performance test directly | Preserve About menu behavior while dialogs and diagnostics move toward app/UI/platform services | `pp_app_core_about_menu_tests`; `pano_cli plan-about-menu --command news --version-major 2 --version-minor 5 --version-fix 7`; `pano_cli plan-about-menu --command performance --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | About/manual/what's-new dialog dispatch, crash-test dispatch, and performance-test execution are owned by injected app/UI/platform services with `App::init_menu_about` acting only as a UI adapter and no legacy About adapter | | DEBT-0035 | Open | Modernization | Main toolbar/status command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `pano_cli plan-main-toolbar`, and the `MainToolbarServices` boundary, history/canvas commands now hand off through `HistoryUiServices` and `DocumentCanvasClearServices`, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy open/save/settings/message-box dialogs and delegates to legacy history/canvas adapters | Preserve reachable toolbar/status behavior while app shell commands move toward app/document/UI services | `pp_app_core_main_toolbar_tests`; `pano_cli plan-main-toolbar --command undo --undo-count 2`; `pano_cli plan-main-toolbar --command clear-canvas --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Open/save/settings/message-box routing, undo/redo/clear-history execution, and canvas-clear execution are owned by injected app/document/UI services with `App::init_toolbar_main` acting only as a UI adapter and no legacy toolbar adapter | | DEBT-0036 | Open | Modernization | `pp_renderer_api`, `pp_paint_renderer`, `pano_cli plan-paint-feedback`, and `pano_cli plan-stroke-composite` can choose backend-neutral complex paint feedback strategies for fixed-function blending, framebuffer-fetch-capable renderers, or ping-pong render targets. OpenGL extension detection now stores `pp::renderer::RenderDeviceFeatures` through `ShaderManager`, using `pp_renderer_gl::query_opengl_capability_detection`, `detect_opengl_feature_state`, and `render_device_features` as the backend conversion point; that feature snapshot now includes float32-linear filtering, so canvas stroke texture format selection, renderer diagnostics, grid lightmap render planning, and grid bake target selection no longer read `ShaderManager::ext_*` flags directly. `pp_paint_renderer::plan_canvas_blend_gate` owns the compatibility mapping from persisted layer/brush blend indices to the extracted stroke-composite planner, and live `Canvas::draw_merge` plus `NodeCanvas` panorama rendering both call it with the stored renderer-neutral feature set for their existing shader-blend gates and destination-copy versus framebuffer-fetch decisions. `pp_paint_renderer::plan_canvas_stroke_feedback` also owns the current destination-feedback decision, and live `Canvas::stroke_draw`, thumbnail layer blending, and `NodeStrokePreview` brush-preview rendering use it for framebuffer-fetch versus destination-copy decisions. The retained `copy_framebuffer_to_texture_2d` utility bridge now routes 2D framebuffer-to-texture copies through tested `pp_renderer_gl` dispatch, retained `RTT::create`/`RTT::destroy` render-target texture parameter setup, optional depth renderbuffer allocation, framebuffer allocation/attachment/status checks, binding restore, and resource deletion now route through tested `pp_renderer_gl` dispatch, retained RTT clear, masked clear with color-write-mask restore, texture bind/unbind, and RGBA8 dirty-region texture writes now route through tested `pp_renderer_gl` dispatch, retained Canvas, NodeCanvas, and NodeStrokePreview texture-unit switches now route through tested active-texture dispatch, retained Canvas, NodeCanvas, NodeStrokePreview, and desktop HMD viewport/scissor/capability execution now route through tested `pp_renderer_gl` dispatch adapters, retained NodeCanvas, CanvasMode, and NodePanelGrid capability-state snapshots now route through tested `pp_renderer_gl` query dispatch, CanvasLayer cube/equirect generation plus frame clears now route blend state, active texture units, viewport execution, color clears, and cube-face framebuffer-to-texture copies through tested `pp_renderer_gl` dispatch adapters, `NodePanelGrid` live heightmap draw and bake setup now route depth/blend state, depth clears, color-write-mask toggles, active texture selection, bake viewport execution, sun-overlay viewport query, and desktop texture-resize readback through tested `pp_renderer_gl` dispatch adapters, retained CanvasMode overlay/mask/transform paths now route active texture, depth/blend state, transform/cut viewport execution, paint-mode blend/depth state snapshots, and canvas-tip pick framebuffer readback through tested `pp_renderer_gl` dispatch adapters, retained simple UI draw paths now share `legacy_ui_gl_dispatch` for blend-state execution, fallback 2D texture unbinds, `NodeViewport` viewport query/restore, color-buffer clears, and clear-color restore, retained `NodeCanvas` plus `NodeStrokePreview` draw-state paths now route viewport query, clear-color query, color-buffer clear, and clear-color restore through tested `pp_renderer_gl` dispatch helpers, and retained `Canvas` plus `CanvasLayer` stroke/object/thumbnail/frame-clear draw-state paths now route saved viewport or clear-color query and restore through the same tested helpers, but actual live stroke rasterization, dual-brush compositing, pattern feedback math, thumbnail layer compositing, brush-preview compositing, and the retained `ShaderManager::ext_*` compatibility fields still use legacy OpenGL canvas/UI execution | Preserve current painting behavior while the renderer boundary matures for OpenGL parity and later Vulkan/Metal experiments | `pp_renderer_api_tests`; `pp_renderer_gl_capabilities_tests`; `pp_paint_renderer_compositor_tests`; `pano_cli plan-paint-feedback --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-paint-feedback --texture-copy`; `pano_cli plan-stroke-composite --stroke-blend 10 --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-stroke-composite --layer-blend 4 --dual-blend --texture-copy`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Live stroke/layer compositing chooses its feedback path through `pp_paint_renderer` and renderer services, with OpenGL golden parity and Vulkan/Metal lab tests covering framebuffer-fetch and ping-pong behavior | diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index dcab289..6d389c0 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -646,6 +646,10 @@ dispatch through `ToolsMenuServices` in the shared app-shell bridge before the legacy UI/panel/canvas/platform adapters continue execution. The live animation panel route now also checks animation panel visibility and applies animation panel layout state instead of using the grid panel by mistake. +`pano_cli plan-canvas-camera-reset` exposes the shared app-core reset-camera +state used by live `NodeCanvas::reset_camera()` before retained legacy canvas +camera mutation, keeping document-open/session/cloud/tools reset defaults under +the same tested policy. The live SonarPen menu action now asks the active `PlatformServices` instance for availability and startup, removing the local iOS branch from the Tools menu and shared Tools executor while preserving the retained iOS bridge in the diff --git a/src/app_core/canvas_view.h b/src/app_core/canvas_view.h new file mode 100644 index 0000000..47bbbcc --- /dev/null +++ b/src/app_core/canvas_view.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +namespace pp::app { + +struct CanvasCameraState { + std::array rotation {}; + std::array position {}; + float field_of_view_degrees = 85.0F; + std::array pan {}; +}; + +[[nodiscard]] constexpr CanvasCameraState plan_canvas_camera_reset() noexcept +{ + CanvasCameraState state; + state.rotation = { + 1.0F, 0.0F, 0.0F, 0.0F, + 0.0F, 1.0F, 0.0F, 0.0F, + 0.0F, 0.0F, 1.0F, 0.0F, + 0.0F, 0.0F, 0.0F, 1.0F, + }; + state.position = { 0.0F, 0.0F, 0.0F }; + state.field_of_view_degrees = 85.0F; + state.pan = { 0.0F, 0.0F }; + return state; +} + +} // namespace pp::app diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp index 7187cc7..ef87f64 100644 --- a/src/node_canvas.cpp +++ b/src/node_canvas.cpp @@ -8,6 +8,7 @@ #include "app_core/canvas_hotkey.h" #include "app_core/canvas_tool_ui.h" +#include "app_core/canvas_view.h" #include "app_core/document_animation.h" #include "app.h" #include "legacy_canvas_tool_services.h" @@ -978,10 +979,22 @@ kEventResult NodeCanvas::handle_event(Event* e) void NodeCanvas::reset_camera() { - m_canvas->m_cam_rot = glm::mat4(1); - m_canvas->m_cam_pos = {0, 0, 0}; - m_canvas->m_cam_fov = 85; - m_canvas->m_pan = {0, 0}; + const auto state = pp::app::plan_canvas_camera_reset(); + m_canvas->m_cam_rot = glm::mat4( + state.rotation[0], state.rotation[1], state.rotation[2], state.rotation[3], + state.rotation[4], state.rotation[5], state.rotation[6], state.rotation[7], + state.rotation[8], state.rotation[9], state.rotation[10], state.rotation[11], + state.rotation[12], state.rotation[13], state.rotation[14], state.rotation[15]); + m_canvas->m_cam_pos = { + state.position[0], + state.position[1], + state.position[2], + }; + m_canvas->m_cam_fov = state.field_of_view_degrees; + m_canvas->m_pan = { + state.pan[0], + state.pan[1], + }; } void NodeCanvas::create_buffers() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 096a022..b9d9be8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -355,6 +355,16 @@ add_test(NAME pp_app_core_canvas_hotkey_tests COMMAND pp_app_core_canvas_hotkey_ set_tests_properties(pp_app_core_canvas_hotkey_tests PROPERTIES LABELS "app;ui;document;paint;desktop-fast;fuzz") +add_executable(pp_app_core_canvas_view_tests + app_core/canvas_view_tests.cpp) +target_link_libraries(pp_app_core_canvas_view_tests PRIVATE + pp_app_core + pp_test_harness) + +add_test(NAME pp_app_core_canvas_view_tests COMMAND pp_app_core_canvas_view_tests) +set_tests_properties(pp_app_core_canvas_view_tests PROPERTIES + LABELS "app;ui;desktop-fast") + add_executable(pp_app_core_grid_ui_tests app_core/grid_ui_tests.cpp) target_link_libraries(pp_app_core_grid_ui_tests PRIVATE @@ -1628,6 +1638,18 @@ if(TARGET pano_cli) LABELS "app;ui;integration;desktop-fast;fuzz" WILL_FAIL TRUE) + add_test(NAME pano_cli_plan_canvas_camera_reset_smoke + COMMAND pano_cli plan-canvas-camera-reset) + set_tests_properties(pano_cli_plan_canvas_camera_reset_smoke PROPERTIES + LABELS "app;ui;integration;desktop-fast" + PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-camera-reset\".*\"rotation\":\\[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1\\].*\"position\":\\[0,0,0\\].*\"fieldOfViewDegrees\":85.*\"pan\":\\[0,0\\]") + + add_test(NAME pano_cli_plan_canvas_camera_reset_rejects_options + COMMAND pano_cli plan-canvas-camera-reset --unexpected) + set_tests_properties(pano_cli_plan_canvas_camera_reset_rejects_options PROPERTIES + LABELS "app;ui;integration;desktop-fast;fuzz" + WILL_FAIL TRUE) + add_test(NAME pano_cli_plan_canvas_cursor_small_brush_smoke COMMAND pano_cli plan-canvas-cursor --mode draw --visibility small-brush --brush-size 9.5) set_tests_properties(pano_cli_plan_canvas_cursor_small_brush_smoke PROPERTIES diff --git a/tests/app_core/canvas_view_tests.cpp b/tests/app_core/canvas_view_tests.cpp new file mode 100644 index 0000000..52c8935 --- /dev/null +++ b/tests/app_core/canvas_view_tests.cpp @@ -0,0 +1,32 @@ +#include "app_core/canvas_view.h" +#include "test_harness.h" + +#include + +namespace { + +void camera_reset_projects_legacy_defaults(pp::tests::Harness& harness) +{ + const auto state = pp::app::plan_canvas_camera_reset(); + + for (std::size_t index = 0; index < state.rotation.size(); ++index) { + const bool diagonal = index == 0 || index == 5 || index == 10 || index == 15; + PP_EXPECT(harness, state.rotation[index] == (diagonal ? 1.0F : 0.0F)); + } + + PP_EXPECT(harness, state.position[0] == 0.0F); + PP_EXPECT(harness, state.position[1] == 0.0F); + PP_EXPECT(harness, state.position[2] == 0.0F); + PP_EXPECT(harness, state.field_of_view_degrees == 85.0F); + PP_EXPECT(harness, state.pan[0] == 0.0F); + PP_EXPECT(harness, state.pan[1] == 0.0F); +} + +} // namespace + +int main() +{ + pp::tests::Harness harness; + harness.run("camera reset projects legacy defaults", camera_reset_projects_legacy_defaults); + return harness.finish(); +} diff --git a/tools/pano_cli/main.cpp b/tools/pano_cli/main.cpp index 77cce79..13a4890 100644 --- a/tools/pano_cli/main.cpp +++ b/tools/pano_cli/main.cpp @@ -7,6 +7,7 @@ #include "app_core/brush_ui.h" #include "app_core/canvas_hotkey.h" #include "app_core/canvas_tool_ui.h" +#include "app_core/canvas_view.h" #include "app_core/document_animation.h" #include "app_core/document_canvas.h" #include "app_core/document_export.h" @@ -2031,6 +2032,7 @@ void print_help() << " plan-canvas-hotkey --event key-down|key-up|touch-tap --key e|z|s|tab|alt|android-back|bracket-left|bracket-right [--ctrl] [--shift] [--mouse-focus] [--undo-count N] [--redo-count N] [--touch-fingers N]\n" << " plan-canvas-tool --kind draw|erase|line|camera|grid|copy|cut|fill|mask-free|mask-line|bucket|pick|touch-lock [--current-mode-draw]\n" << " plan-canvas-tool-state [--mode draw|erase|line|camera|grid|copy|cut|fill|mask-free|mask-line|bucket] [--picking] [--touch-lock]\n" + << " plan-canvas-camera-reset\n" << " plan-canvas-cursor [--mode draw|erase|line|camera|grid|copy|cut|fill|mask-free|mask-line|bucket] [--visibility never|small-brush|not-painting|always] [--brush-size N] [--no-brush] [--drawing] [--alt] [--resizing] [--picking] [--bad-size]\n" << " plan-grid-operation --kind pick|load|reload|clear|render|commit [--path FILE] [--no-heightmap] [--no-canvas] [--float32] [--float16] [--texture-resolution N] [--samples N]\n" << " plan-history-operation --kind undo|redo|clear [--undo-count N] [--redo-count N] [--memory-bytes N]\n" @@ -6746,6 +6748,28 @@ int plan_canvas_tool_state(int argc, char** argv) return 0; } +int plan_canvas_camera_reset(int argc, char** argv) +{ + if (argc > 2) { + print_error("plan-canvas-camera-reset", "unknown option"); + return 2; + } + + const auto state = pp::app::plan_canvas_camera_reset(); + std::cout << "{\"ok\":true,\"command\":\"plan-canvas-camera-reset\"" + << ",\"rotation\":["; + for (std::size_t index = 0; index < state.rotation.size(); ++index) { + if (index != 0U) { + std::cout << ","; + } + std::cout << state.rotation[index]; + } + std::cout << "],\"position\":[" << state.position[0] << "," << state.position[1] << "," << state.position[2] + << "],\"fieldOfViewDegrees\":" << state.field_of_view_degrees + << ",\"pan\":[" << state.pan[0] << "," << state.pan[1] << "]}\n"; + return 0; +} + pp::foundation::Status parse_plan_canvas_cursor_args( int argc, char** argv, @@ -9905,6 +9929,10 @@ int main(int argc, char** argv) return plan_canvas_tool_state(argc, argv); } + if (command == "plan-canvas-camera-reset") { + return plan_canvas_camera_reset(argc, argv); + } + if (command == "plan-canvas-cursor") { return plan_canvas_cursor(argc, argv); }