2714 lines
161 KiB
Markdown
2714 lines
161 KiB
Markdown
# PanoPainter Modernization Roadmap
|
|
|
|
Status: live
|
|
Last updated: 2026-06-05
|
|
|
|
This is the living roadmap for modernizing PanoPainter into independently
|
|
testable C++23 components while retaining all existing functionality. Keep this
|
|
file current as phases are implemented. Do not let shortcuts, skipped platforms,
|
|
or temporary adapters live only in chat history.
|
|
|
|
## How To Keep This Roadmap Live
|
|
|
|
- Update the phase status before and after each implementation pass.
|
|
- When a shortcut is introduced, add it to the debt log section in this file
|
|
until `docs/modernization/debt.md` exists, then move debt entries there.
|
|
- When a major architectural decision is made, add an ADR under `docs/adr/`
|
|
once that directory exists.
|
|
- Every phase must preserve old behavior unless the roadmap explicitly says
|
|
otherwise.
|
|
- Each phase must leave the repo in a buildable and testable state.
|
|
- Do not add stubs without a debt entry, validation command, and removal
|
|
condition.
|
|
|
|
## Locked Decisions
|
|
|
|
- Graphics path: keep OpenGL working first; add Vulkan and Metal after the
|
|
renderer boundary exists.
|
|
- Required platforms at phase gates: Windows desktop/AppX, macOS, iOS,
|
|
Android standard, Quest, Focus/Wave, Linux, and WebGL.
|
|
- Dependency policy: use vcpkg where reliable; keep SDK, patched, or
|
|
vendor-only dependencies with documented reasons.
|
|
- Test stack: Catch2, golden/approval tests, and fuzz/property tests where
|
|
useful.
|
|
- Automation: local reproducible matrix first; hosted CI can be added later.
|
|
- Documentation: ADRs, debt log, and this living roadmap.
|
|
- "vkpkg" in older notes means `vcpkg`.
|
|
- Target C++ standard: C++23.
|
|
- Initial Windows CMake generator target: Visual Studio 2026 when available.
|
|
|
|
## Phase Status
|
|
|
|
| Phase | Name | Status | Gate |
|
|
| --- | --- | --- | --- |
|
|
| 0 | Inventory, Safety Rails, And Memory | Complete | No behavior changes; old builds still work |
|
|
| 1 | Unified CMake Skeleton | In progress | Root CMake builds the Windows app and owns the source list |
|
|
| 2 | Toolchain, Diagnostics, And Dependencies | In progress | Strict desktop library builds compile cleanly |
|
|
| 3 | Test Harness And Agent-Ready Automation | In progress | `ctest --preset desktop-fast` runs headlessly |
|
|
| 4 | Component Split Without Behavior Change | Started | Each extracted target builds and tests |
|
|
| 5 | Renderer Boundary And OpenGL Parity | Started | OpenGL output matches golden readbacks |
|
|
| 6 | Platform Alignment | Started | Every supported platform has named validation |
|
|
| 7 | Hardening, Coverage, And Breaking-Point Tests | Not started | Each component has edge/failure tests |
|
|
| 8 | Future Backend Readiness | Not started | Vulkan/Metal lab targets remain non-default |
|
|
|
|
## Target Component Architecture
|
|
|
|
The refactor should move toward one-way dependencies:
|
|
|
|
```text
|
|
pp_foundation
|
|
-> pp_assets
|
|
-> pp_paint
|
|
-> pp_document
|
|
-> pp_renderer_api
|
|
-> pp_renderer_gl
|
|
-> pp_paint_renderer
|
|
-> pp_ui_core
|
|
-> pp_panopainter_ui
|
|
-> pp_platform_*
|
|
-> panopainter_app
|
|
```
|
|
|
|
Intended responsibilities:
|
|
|
|
- `pp_foundation`: logging facade, math/util helpers, events, task queues,
|
|
binary streams.
|
|
- `pp_assets`: `Asset`, `Image`, `Settings`, serialization, ABR, PPBR, and PPI
|
|
helpers.
|
|
- `pp_paint`: pure `Brush`, `Stroke`, stroke sampling, and CPU reference blend
|
|
math.
|
|
- `pp_document`: canvas document model, layers, animation frames, and undo/redo
|
|
model.
|
|
- `pp_renderer_api`: renderer-neutral interfaces for textures, render targets,
|
|
shaders, meshes, readback, frame capture, and tracing.
|
|
- `pp_renderer_gl`: current OpenGL implementation behind renderer interfaces.
|
|
- `pp_paint_renderer`: stroke rasterization, layer compositing, cube/equirect
|
|
export using `pp_renderer_api`.
|
|
- `pp_ui_core`: `Node`, layout, generic controls, text/image primitives.
|
|
- `pp_panopainter_ui`: panels, dialogs, `NodeCanvas`, and app-specific
|
|
workflows.
|
|
- `pp_platform_api`: SDK-free service interfaces for clipboard, cursor,
|
|
virtual keyboard, file pickers, sharing, and future platform automation.
|
|
- `pp_platform_*`: Windows, macOS/iOS, Android, Linux, and WebGL shells.
|
|
- `panopainter_app`: composition root only.
|
|
|
|
Rules:
|
|
|
|
- Component headers must not include platform SDK or graphics API headers unless
|
|
the component name includes that backend or platform.
|
|
- Pure libraries must build and test without a window, GL context, network,
|
|
tablet, VR headset, or filesystem outside test temp directories.
|
|
- Public APIs should return explicit status/result objects. PanoPainter app
|
|
code keeps exceptions disabled unless isolated SDK wrappers require them.
|
|
- Singleton access should be replaced at component boundaries with context or
|
|
service objects. Temporary facade shims require debt entries.
|
|
|
|
## Phase 0: Inventory, Safety Rails, And Memory
|
|
|
|
Status: complete on 2026-05-31. Created this roadmap,
|
|
`docs/modernization/debt.md`, `docs/modernization/capability-map.md`,
|
|
`docs/modernization/build-inventory.md`, and ADR 0001.
|
|
|
|
Goal: create durable project memory and prevent silent shortcuts before large
|
|
refactors begin.
|
|
|
|
Implementation tasks:
|
|
|
|
- Add `docs/modernization/roadmap.md`, `docs/modernization/debt.md`, and
|
|
`docs/adr/`.
|
|
- Add a shortcut rule: every temporary adapter, fallback, skipped platform, or
|
|
retained vendored dependency must have owner, reason, validation command, and
|
|
removal condition.
|
|
- Generate a current capability map covering:
|
|
- project open/save and PPI compatibility
|
|
- image import/export and thumbnails
|
|
- brush presets, ABR import, PPBR export/import
|
|
- layers, blend modes, alpha lock, selection mask
|
|
- animation frames and MP4/timelapse recording
|
|
- VR, tablet, touch, mouse, keyboard, gestures
|
|
- cloud upload/download/browse
|
|
- UI dialogs, panels, layout XML, settings
|
|
- Windows/AppX, macOS, iOS, Android standard, Quest, Focus/Wave, Linux, WebGL
|
|
- Record current build commands and known platform prerequisites.
|
|
|
|
Gate:
|
|
|
|
- No behavior changes.
|
|
- Existing Visual Studio, platform CMake, Gradle, Apple, Linux, and WebGL paths
|
|
are not removed.
|
|
|
|
## Phase 1: Unified CMake Skeleton
|
|
|
|
Goal: make CMake the canonical source list without breaking existing projects.
|
|
|
|
Status: in progress. Root `CMakeLists.txt`, `CMakePresets.json`, and project
|
|
option targets exist. The Windows desktop app builds through CMake as
|
|
`PanoPainter`; the raw Visual Studio solution/project files were removed on
|
|
2026-05-31 by user decision. The root CMake Windows app graph now includes a
|
|
`panopainter_app` composition target and `pp_platform_windows` shell target so
|
|
`PanoPainter` is only the executable/resource wrapper; Windows and vendor link
|
|
dependencies now belong to the platform shell target, and Windows runtime
|
|
payload deployment lives behind `cmake/PanoPainterRuntime.cmake`.
|
|
`pp_legacy_vendor` now owns the retained third-party source bundle as an
|
|
interim containment boundary until vcpkg, SDK imports, or documented permanent
|
|
vendoring decisions replace each dependency. `pp_legacy_engine` now contains
|
|
the retained legacy tablet, video, and low-level runtime sources as an interim
|
|
containment boundary while pure replacement components take over.
|
|
`pp_legacy_assets_io` now owns retained ABR, asset/file, binary stream, image,
|
|
serializer, and settings implementations until `pp_assets` fully replaces those
|
|
paths in the app. `pp_legacy_paint_document` now owns retained action, bezier,
|
|
brush, canvas, canvas-layer, and event implementations until `pp_paint` and
|
|
`pp_document` fully replace those paths in the app.
|
|
`pp_legacy_renderer_gl` now owns the retained OpenGL runtime implementations
|
|
for `Font`, `RTT`, `Shader`, `Shape`, `Texture2D`, `TextureCube`, `Sampler`,
|
|
and `TextureManager` as an object-library boundary folded into the retained
|
|
engine until the renderer API inversion is complete. `pp_legacy_ui_core` now
|
|
owns retained base `Node`, layout, text, image, input, popup, slider, scroll,
|
|
and settings UI controls as an object-library boundary folded into the legacy
|
|
app adapter until those paths are replaced by `pp_ui_core` and app-specific UI
|
|
targets.
|
|
`pp_app_core` now owns tested app-level document-open routing for project
|
|
files, ABR imports, and PPBR imports without UI, filesystem, platform, or
|
|
renderer dependencies; `App::open_document` and `pano_cli classify-open`
|
|
consume this route contract. It also owns tested session decisions for
|
|
project-open, app-close, save, save-as, and save-version flows;
|
|
`App::open_document`, `App::request_close`, file-menu save actions,
|
|
`NodeCanvas` save hotkeys, and `pano_cli simulate-app-session` consume those
|
|
contracts while legacy canvas/project loading remains in place.
|
|
`pp_app_core` also owns tested app preference plans for UI scale/font scale,
|
|
scale option selection, viewport scale, RTL layout direction, timelapse
|
|
recording toggles, VR mode start/stop, VR controller enablement, and canvas cursor mode;
|
|
the live tools/options menu and `pano_cli plan-app-preferences` consume those
|
|
contracts. Options-menu preference execution now dispatches through
|
|
`AppPreferenceServices` and `src/legacy_app_preference_services.*` before
|
|
legacy widgets, settings persistence, recording toggles, and canvas cursor
|
|
updates continue.
|
|
It also owns tested startup plans for run-counter increments, preference-save
|
|
intent, auto-timelapse startup, stored VR-controller state, license-warning
|
|
visibility, and main startup resource sequencing for shader, asset, layout,
|
|
title, and UI render-target setup. `App::init` now plans those decisions before
|
|
heavy initialization, executes run-counter persistence through
|
|
`src/legacy_app_startup_services.*` before resource setup, dispatches the
|
|
resource sequence through the same bridge, and executes runtime startup side
|
|
effects after the UI layout and main render target exist.
|
|
It also owns tested app status/display plans for document title text,
|
|
resolution mapping/labels, DPI text, history-memory text, and recording-frame
|
|
status text, plus renderer diagnostic indicator labels for framebuffer fetch
|
|
and floating-point render targets; `App::title_update`,
|
|
`App::update_memory_usage`, `App::update_rec_frames`, resolution helpers,
|
|
`App::initLayout`, and `pano_cli plan-app-status` consume those contracts while
|
|
legacy UI nodes still render the strings and status lights.
|
|
App-level progress, message, and input dialog metadata now also lives in
|
|
`pp_app_core` through `plan_app_progress_dialog`,
|
|
`plan_app_message_dialog`, and `plan_app_input_dialog`; `App::show_progress`,
|
|
`App::message_box`, `App::input_box`, and `pano_cli plan-app-dialog` consume
|
|
those plans before `src/legacy_app_dialog_services.*` creates retained
|
|
`NodeProgressBar`, `NodeMessageBox`, and `NodeInputBox` instances. Legacy
|
|
dialog node lifetime/layout ownership remains tracked under `DEBT-0058`.
|
|
Frame-level app decisions for the initial surface size, redraw/animation update
|
|
gating, layout ticking, resize render-target recreation, canvas-stroke drawing,
|
|
VR UI drawing, main UI drawing, UI observer clipping/on-screen transition/scissor
|
|
projection, and redraw reset now live in `pp_app_core`;
|
|
`App::create`, `App::tick`, `App::resize`, `App::update`, `App::draw`, and
|
|
`pano_cli plan-app-frame` consume those plans while retained layout traversal,
|
|
render-target recreation, `Node` parent walking, on-screen callbacks, and
|
|
OpenGL/UI drawing stay in the legacy app.
|
|
App input dispatch decisions for pointer coordinate normalization, mouse
|
|
designer-first routing, gesture midpoint/delta math, touch/key main-layout
|
|
routing, VR spacebar camera-sync intent, UI visibility toggling, and stylus
|
|
touch-lock attachment now live in `pp_app_core`; `App::mouse_*`,
|
|
`App::gesture_*`, `App::touch_tap`, `App::key_*`, `App::toggle_ui`,
|
|
`App::set_stylus`, and `pano_cli plan-app-input` consume those plans while
|
|
retained event objects, child-node mutation, and legacy `Node` dispatch stay
|
|
in the app shell.
|
|
App thread orchestration decisions for render/UI task dispatch, unique queued
|
|
task replacement, queue draining, render-context wrapping, async redraw
|
|
notification, UI tick redraw scheduling, UI-loop timer/report/reload cadence,
|
|
and thread start/stop intents now live in `pp_app_core`; `App::render_task*`,
|
|
`App::ui_task*`, `App::async_redraw`, `App::render_thread_*`,
|
|
`App::ui_thread_*`, and `pano_cli plan-app-thread` consume those plans while
|
|
retained `std::thread`, condition-variable, OpenGL context, live reload, and
|
|
task execution remain in the app shell.
|
|
Shutdown lifecycle staging for UI-state save, stroke-preview renderer shutdown,
|
|
recording stop, texture/shader invalidation, layout unload, render-target
|
|
destruction, panel-node release, and quick-mode cleanup now lives in
|
|
`pp_app_core`; `App::terminate` and `pano_cli plan-app-shutdown` consume that
|
|
plan while retained cleanup execution stays in the legacy app.
|
|
Command-line panorama conversion planning for renderer-state setup, temporary
|
|
canvas allocation, project open, and equirectangular export now lives in
|
|
`pp_app_core`; `App::cmd_convert` and `pano_cli plan-command-convert` consume
|
|
that sequence while retained OpenGL state dispatch and legacy `Canvas`
|
|
open/export execution stay in the legacy app.
|
|
`panopainter_app` is now a real static target that owns app orchestration
|
|
sources, app version metadata, and version-header generation.
|
|
`pp_panopainter_ui` now owns app-specific modal, dialog, panel, canvas,
|
|
viewport, color-picker, stroke-preview, and tool UI workflow nodes outside
|
|
`pp_legacy_app`; base `Node` controls and layout plumbing remain in the legacy
|
|
target until the UI core/app UI boundary is tightened. Android arm64 now
|
|
configures and builds headless
|
|
foundation/tool targets through the root CMake/NDK path. Non-Windows platform
|
|
app/package files remain during Phase 6 alignment.
|
|
|
|
Implementation tasks:
|
|
|
|
- Add root `CMakeLists.txt` and shared CMake modules under `cmake/`.
|
|
- Add `CMakePresets.json` with at least:
|
|
- `windows-vs2026-x64`
|
|
- `windows-clangcl-asan`
|
|
- `linux-clang`
|
|
- `android-arm64`
|
|
- `android-x64`
|
|
- `emscripten`
|
|
- `macos`
|
|
- `ios-device`
|
|
- `ios-simulator`
|
|
- Keep Android CMake, Linux CMake, WebGL CMake, Apple project files, and AppX
|
|
packaging during the transition until each consumes shared component targets.
|
|
- Move version generation into a CMake custom command using
|
|
`scripts/pre-build.py`.
|
|
- Fix `scripts/pre-build.py` only if required to avoid unnecessary rewrites or
|
|
missing-tag failures.
|
|
- Add CMake options:
|
|
- `PP_BUILD_APP`
|
|
- `PP_BUILD_TESTS`
|
|
- `PP_BUILD_TOOLS`
|
|
- `PP_ENABLE_OPENGL`
|
|
- `PP_ENABLE_VULKAN_EXPERIMENTAL=OFF`
|
|
- `PP_ENABLE_VR`
|
|
- `PP_ENABLE_CLOUD`
|
|
- `PP_ENABLE_VIDEO`
|
|
- Define source-list helper targets so per-platform source duplication can be
|
|
reduced incrementally.
|
|
|
|
Gate:
|
|
|
|
- Windows desktop app builds through CMake.
|
|
- New CMake can configure on Windows.
|
|
- Source list differences are understood and documented.
|
|
- Non-Windows platform migration is debt-tracked until Phase 6.
|
|
|
|
## Phase 2: Toolchain, Diagnostics, And Dependencies
|
|
|
|
Goal: turn the build into an error-finding system before deep refactors.
|
|
|
|
Status: in progress. Initial warning/sanitizer option targets, `vcpkg.json`,
|
|
a validated Windows headless vcpkg preset, `pp_ui_core` support for vcpkg
|
|
tinyxml2 on that preset, and a headless `panopainter_validate_shaders` target
|
|
exist. `windows-clangcl-asan` now configures as a headless Ninja/clang-cl ASan
|
|
preset and uses the release MSVC runtime required by clang-cl ASan, but local
|
|
ASan builds are blocked by DEBT-0014 until Clang and the selected MSVC STL are
|
|
compatible. Dependency migration is not complete until remaining component
|
|
dependencies and mobile/Apple triplets are validated. Root CMake now also
|
|
exposes `panopainter_platform_build_vcpkg_ui_core`, a focused automation target
|
|
that resolves `VCPKG_ROOT` through the platform-build wrapper and validates the
|
|
vcpkg-backed `pp_ui_core`/tinyxml2 XML test boundary from the CMake target
|
|
graph.
|
|
|
|
Implementation tasks:
|
|
|
|
- Set C++23 through target features, not raw compiler flags.
|
|
- Add warning profiles:
|
|
- MSVC: `/W4 /permissive- /Zc:__cplusplus /Zc:preprocessor`, with
|
|
`C4100` muted temporarily under `DEBT-0019`.
|
|
- Optional MSVC analysis preset: `/analyze`.
|
|
- Clang/GCC: `-Wall -Wextra -Wpedantic -Wconversion -Wshadow
|
|
-Wnull-dereference`, with `-Wunused-parameter` muted temporarily under
|
|
`DEBT-0019`.
|
|
- Keep exceptions disabled for PanoPainter targets, except isolated SDK wrapper
|
|
targets when unavoidable.
|
|
- Add sanitizer presets:
|
|
- Clang/GCC ASan and UBSan for headless libraries.
|
|
- MSVC ASan where supported.
|
|
- TSan only for pure/headless targets.
|
|
- Add tooling hooks:
|
|
- `clang-tidy`
|
|
- `cppcheck`
|
|
- shader validation or compile checks
|
|
- CTest dashboard output
|
|
- Add `vcpkg.json`.
|
|
- Move reliable dependencies to vcpkg first:
|
|
- `fmt`
|
|
- `glm`
|
|
- `tinyxml2`
|
|
- `stb`
|
|
- `curl`
|
|
- `sqlite3`
|
|
- `glad`
|
|
- `Catch2`
|
|
- Keep vendored until proven:
|
|
- OpenVR only as the temporary desktop compatibility fallback while OpenXR is
|
|
introduced behind `pp_platform_vr`
|
|
- OVR/Wave SDKs
|
|
- Wacom WinTab
|
|
- AppCenter
|
|
- openh264
|
|
- mp4v2
|
|
- libyuv
|
|
- patched or SDK-specific libraries
|
|
|
|
Gate:
|
|
|
|
- Desktop library targets compile with strict diagnostics.
|
|
- New warnings caused by refactor are fixed or locally justified.
|
|
- Any global warning suppression must have an open debt entry, validation
|
|
command, and removal condition.
|
|
|
|
## Phase 3: Test Harness And Agent-Ready Automation
|
|
|
|
Goal: make each component reachable by automated tools and future agents.
|
|
|
|
Status: in progress. `tests/` exists, `desktop-fast`, `fuzz`, and `stress`
|
|
CTest presets run headlessly, and
|
|
PowerShell/bash wrappers exist for
|
|
configure/build/test/analyze/platform-build/package-smoke. `pano_cli` exists
|
|
with JSON automation commands for app document-open routing, app session
|
|
dirty-state and save decisions, creating a `pp_document` model, metadata-only
|
|
PPI project loading, and inspecting image signatures, PPI headers, and layout
|
|
XML; full document/app integration is debt-tracked as DEBT-0010 and full PPI
|
|
body parsing is debt-tracked as DEBT-0013. Agent code navigation now includes
|
|
`scripts/dev/clangd_nav.py` with symbol/detail/path regex filters and a
|
|
`panopainter_clangd_nav_regex_self_test` CTest so broad symbol-family searches
|
|
can be validated before they guide refactors. Agents must use the
|
|
`panopainter-code-navigation` skill before broad text search whenever C++
|
|
symbol identity, generated-style symbol families, declarations/definitions,
|
|
override groups, or platform/backend path slices are the real question.
|
|
|
|
Implementation tasks:
|
|
|
|
- Add `tests/` with one executable per component.
|
|
- Register CTest labels:
|
|
- `foundation`
|
|
- `assets`
|
|
- `paint`
|
|
- `document`
|
|
- `renderer`
|
|
- `ui`
|
|
- `platform`
|
|
- `integration`
|
|
- `fuzz`
|
|
- `slow`
|
|
- `gpu`
|
|
- Add `tools/pano_cli` for headless automation.
|
|
- `pano_cli` should support:
|
|
- create document
|
|
- load project
|
|
- save project
|
|
- apply scripted strokes
|
|
- import/export images
|
|
- inspect layers
|
|
- run layout parse
|
|
- emit JSON results
|
|
- Add local automation wrappers under `scripts/automation/`:
|
|
- configure
|
|
- build
|
|
- test
|
|
- analyze
|
|
- package smoke
|
|
- All wrappers must return machine-readable logs or summaries.
|
|
- Establish `tests/data/` fixtures:
|
|
- tiny PPI files
|
|
- corrupt/truncated PPI cases
|
|
- PNG/JPEG fixtures
|
|
- ABR/PPBR samples
|
|
- layout XML
|
|
- shader snippets
|
|
- brush stroke scripts
|
|
|
|
Gate:
|
|
|
|
- `ctest --preset desktop-fast --build-config Debug` runs without a GL
|
|
context.
|
|
- Non-render components can be tested on a headless machine.
|
|
|
|
## Phase 4: Component Split Without Behavior Change
|
|
|
|
Goal: split libraries while keeping current app behavior.
|
|
|
|
Status: started. `pp_foundation` exists with binary stream utilities and
|
|
boundary/overread/overlapping-write tests. It also owns strict decimal `uint32` parsing used by
|
|
`pano_cli`, with rejection tests for empty, signed, mixed, and overflowing
|
|
input. A synchronous event dispatcher, structured logging facade, bounded FIFO
|
|
task queue, and deterministic `TraceRecorder` now record
|
|
component/name/thread/frame/stroke metadata with filtering, capacity, and
|
|
invalid-end tests. `pp_assets` has started with PNG/JPEG signature detection,
|
|
PNG IHDR metadata parsing, PPI header/project byte-layout/body-summary
|
|
recognition, layer/frame indexing, dirty-face PNG payload metadata validation,
|
|
asset-level RGBA PNG payload decoding, and a pure typed settings document
|
|
model, with
|
|
corrupt/truncated/unsupported, non-finite opacity, unsupported blend-mode,
|
|
extreme-dimension, and key/value limit tests.
|
|
`pp_paint` has started with pure brush parameter validation/stamp evaluation,
|
|
CPU reference math for the five current final RGBA shader blend modes plus the
|
|
shader-style stroke-alpha blend modes used by pattern/dual-brush mixing, and deterministic
|
|
stroke spacing/interpolation plus duplicate-segment, non-finite, sample-limit,
|
|
and 1001-sample stress coverage, plus a pure text stroke-script parser.
|
|
`pp_document` has
|
|
started with a pure canvas/layer/frame model, alpha-lock metadata, snapshot
|
|
construction, per-layer frame metadata, layer metadata operations, frame
|
|
move/duration queries, renderer-free RGBA8 cube-face payload storage,
|
|
renderer-free alpha8 selection-mask storage, PPI image import/export, and
|
|
layer/frame/undo-redo history invariant tests. Snapshot construction validates
|
|
embedded face-pixel payload bounds, byte counts, duplicate face payloads, and
|
|
duplicate selection masks.
|
|
`pp_renderer_api` has started with renderer-neutral
|
|
texture/readback descriptors and validation tests. `pp_paint_renderer` has
|
|
started with deterministic CPU layer compositing over renderer extents using
|
|
the paint blend reference, and now exposes a pure `pp_document` face
|
|
compositor that expands per-layer dirty face payload rectangles into a full
|
|
renderer-sized RGBA buffer for a requested frame/face. `pp_ui_core` has started with XML-layout-facing
|
|
length parsing, color parsing, tinyxml-backed layout XML parsing, and invalid
|
|
input tests.
|
|
`pano_cli inspect-image` exposes PNG IHDR metadata as JSON,
|
|
`pano_cli import-image` accepts a PNG path and imports decoded RGBA8 pixels
|
|
into a new pure `pp_document` face payload,
|
|
with checked-in decodable PNG and truncated PNG automation coverage,
|
|
`pano_cli export-image` writes a deterministic RGBA8 PNG through `pp_assets`
|
|
and round-trips it back through file import automation,
|
|
`pano_cli inspect-project` reports validated PPI thumbnail/body byte layout,
|
|
body summary, layer/frame descriptors, dirty-face PNG payload metadata, and
|
|
asset-level decode coverage, and
|
|
`pano_cli load-project` creates a `pp_document` projection with per-layer frame
|
|
counts, durations, and decoded face-pixel payload attachment when PPI image
|
|
payloads are present.
|
|
`pp_assets` can write generated PPI projects with explicit per-layer names,
|
|
visibility, opacity, blend mode, alpha lock, per-layer frame durations, and
|
|
dirty-face payloads targeted to layer/frame/face slots. `pano_cli save-project`
|
|
exposes the generated writer for metadata-only and test dirty-face-payload
|
|
round-trips through `load-project` and rejects non-finite automation float
|
|
inputs before writing files.
|
|
`pp_document::export_ppi_project_document` converts pure documents into PPI
|
|
bytes using that writer, including PNG-encoded layer/frame face payloads.
|
|
`pano_cli simulate-document-export` exercises that pure document export path,
|
|
decodes the generated PPI bytes, reimports them, and emits JSON round-trip
|
|
metadata.
|
|
`pano_cli save-document-project` writes the same pure document export to a PPI
|
|
file for inspect/load round-trip automation.
|
|
`pano_cli create-document` can create simple animation documents with explicit
|
|
frame count/duration. `pano_cli simulate-document-edits` exercises pure
|
|
layer metadata, frame reordering, active-index preservation, tiny face-payload
|
|
attachment, and selection-mask attachment. `pano_cli simulate-document-history` exercises the
|
|
pure `pp_document::DocumentHistory` apply/undo/redo path and emits JSON state
|
|
summaries. `pano_cli simulate-image-import` decodes an embedded tiny PNG
|
|
through `pp_assets` and attaches the resulting RGBA8 payload to `pp_document`.
|
|
`pano_cli simulate-document-export` exercises pure document-to-PPI export,
|
|
asset-level PPI image decode, and document reimport in one automation command.
|
|
`pano_cli save-document-project` writes a deterministic pure document export
|
|
PPI and verifies it through inspect/load smoke coverage.
|
|
`pano_cli simulate-blend` exposes deterministic final RGBA and stroke-alpha
|
|
blend reference vectors through JSON automation.
|
|
`pano_cli simulate-stroke` exercises the pure stroke sampler for
|
|
scripted-stroke automation. `pano_cli simulate-stroke-script`
|
|
loads stroke script fixtures, parses them through `pp_paint`, and samples every
|
|
stroke. `pano_cli apply-stroke-script` maps sampled script points into a
|
|
bounded `pp_document` RGBA8 face payload, writes a PPI file, and verifies that
|
|
the applied stroke payload survives inspect/load round-trip automation, with a
|
|
rejection smoke test for unsafe tiny canvas dimensions.
|
|
`pano_cli classify-open` exposes the pure `pp_app_core` document-open route
|
|
contract for project files, ABR imports, PPBR imports, and malformed path
|
|
rejection. `pano_cli plan-open-route` exposes the pure `pp_app_core`
|
|
document-open action plan for clean project open, dirty project prompt, and
|
|
brush-import prompt flows. `pano_cli simulate-app-session` exposes the pure
|
|
`pp_app_core` session decisions used by project-open, app-close, save, save-as,
|
|
and save-version flows, plus the save-before-continue workflow gate used by
|
|
new-document/open/browse dialogs. `pano_cli plan-new-document` exposes the
|
|
same app-core new-document target, legacy resolution-index mapping, and
|
|
overwrite decision used by the live new-document dialog, including invalid
|
|
resolution rejection. `pano_cli plan-document-file` exposes the same app-core
|
|
document-name validation, legacy `.ppi` path construction, and overwrite
|
|
prompt decision used by save-as dialogs through one combined save-file plan.
|
|
`pano_cli plan-document-version` exposes the save-version suffix parsing,
|
|
candidate generation, collision skipping, and no-slot failure behavior used by
|
|
the live save-version dialog.
|
|
`pano_cli plan-export-target` exposes app-core export target planning for
|
|
equirectangular image files, layer/frame collection stems, picked-directory
|
|
stems, and MP4 suggested names used by the live export dialogs.
|
|
`pano_cli plan-export-start` exposes the app-core export availability decision
|
|
used by live image, layer, animation-frame, depth, and cube-face export dialogs
|
|
plus MP4 animation and timelapse export dialogs before they call legacy
|
|
canvas/recording export execution.
|
|
`pano_cli plan-export-message` exposes the app-core export completion dialog
|
|
metadata now consumed by the live legacy export bridge for equirectangular,
|
|
layer/frame, depth/cube, animation MP4, and timelapse success reporting,
|
|
including platform-style destinations and no-message/suppressed branches.
|
|
`pano_cli plan-export-report` exposes app-core failure and license-disabled
|
|
dialog metadata now consumed by live export dialogs before retained legacy
|
|
export execution/logging continues.
|
|
`pano_cli plan-recording-session` exposes the app-core recording start, stop,
|
|
clear, platform recorded-file cleanup, frame reset, export progress-total, and
|
|
export progress-dialog decisions used by the live recording controls. Recording
|
|
lifecycle and MP4 export execution now dispatch through `RecordingServices` in
|
|
`src/legacy_recording_services.*` before legacy recording threads, PBO readback,
|
|
and MP4 encoder execution continue. The retained MP4 export progress bar now
|
|
uses `src/legacy_app_dialog_services.*` for creation while progress lifetime
|
|
and MP4 writing remain legacy-owned.
|
|
`pano_cli plan-share-file` exposes the app-core saved-path decision used by the
|
|
live platform share command before iOS/macOS sharing bridges or retained no-op
|
|
platform branches execute.
|
|
`pano_cli plan-picked-path` exposes the app-core selected-path decision used by
|
|
live image, file, save-file, and directory picker branches before retained
|
|
platform callbacks or legacy picker bridges continue.
|
|
`pano_cli plan-display-file` exposes the app-core external file presentation
|
|
decision used by live display-file requests before retained platform open-file
|
|
bridges continue.
|
|
`pano_cli plan-keyboard-visibility` exposes the app-core virtual keyboard
|
|
visibility decision used by live show/hide keyboard requests before retained
|
|
mobile platform keyboard bridges continue.
|
|
`pano_cli plan-cursor-visibility` exposes the app-core cursor visibility
|
|
decision used by live canvas cursor requests before retained desktop platform
|
|
cursor bridges continue.
|
|
`pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write` expose the
|
|
app-core clipboard text decisions used by live clipboard get/set requests
|
|
before retained platform clipboard bridges continue.
|
|
`pano_cli plan-document-resize` exposes the app-core resize dialog state and
|
|
selected-resolution commit plan used by the live document resize dialog, and
|
|
resize execution now dispatches through `DocumentResizeServices` before the
|
|
shared app-shell document-canvas bridge runs the legacy `Canvas` resize adapter
|
|
and history clearing.
|
|
`pano_cli plan-layer-rename` exposes the app-core layer rename decision used by
|
|
the live layer rename dialog, and rename execution now dispatches through
|
|
`DocumentLayerRenameServices` in the shared app-shell layer bridge
|
|
`src/legacy_document_layer_services.*` before legacy `Canvas`, `NodeLayer`, and
|
|
`ActionManager` undo adapters continue.
|
|
`pano_cli plan-layer-operation` exposes app-core planning for layer add,
|
|
duplicate, select, reorder, remove, opacity, visibility, alpha-lock, blend-mode,
|
|
and highlight actions used by the live layer panel. Direct layer-panel
|
|
operations now dispatch through `DocumentLayerOperationServices` before the
|
|
shared app-shell layer bridge continues legacy `Canvas` and UI layer execution.
|
|
`pano_cli plan-layer-panel-view` exposes the app-core layer panel view model for
|
|
current opacity, alpha-lock, blend mode, and per-layer visibility state, and
|
|
live `NodePanelLayer::update_attributes()` now consumes that tested projection
|
|
before writing the retained legacy UI controls.
|
|
`pano_cli plan-layer-menu` exposes app-core planning for Layer menu clear,
|
|
rename, and merge-down labels/actions, and direct Layer menu commands now
|
|
dispatch through `DocumentLayerMenuServices` before the legacy canvas/layer UI
|
|
adapter in `src/legacy_document_layer_services.*` continues execution. Layer
|
|
menu clear now routes through the shared `DocumentCanvasClearServices` executor
|
|
from that bridge before the legacy canvas-clear adapter continues, and Layer
|
|
menu merge now validates and dispatches through `DocumentLayerMergeServices`
|
|
before the legacy layer-panel merge adapter continues.
|
|
`pano_cli plan-animation-operation` exposes app-core planning for animation
|
|
frame add, duplicate, remove, duration adjustment, timeline moves, timeline
|
|
goto/next/previous, onion-size updates, frame selection, no-reload playback
|
|
stepping, and play-mode toggles used by the live animation panel.
|
|
`pp_app_core` also owns onion-skin frame range and alpha falloff planning now
|
|
consumed by live `NodeCanvas` panorama drawing.
|
|
`pano_cli plan-animation-panel-action` exposes the higher-level animation panel
|
|
state/action planner for goto, next, previous, playback-step, and play-toggle
|
|
automation without requiring the legacy UI or canvas.
|
|
Panel-control, timeline, selected-frame click, playback tick, and play-button
|
|
toggle execution now dispatch through `DocumentAnimationServices` before the
|
|
shared `src/legacy_document_animation_services.*` bridge continues legacy
|
|
`Canvas`/`Layer`/canvas-mode and animation-panel state execution.
|
|
`pano_cli plan-brush-operation` exposes app-core planning for brush color
|
|
changes, tip/pattern/dual texture changes, preset brush replacement, and stroke
|
|
settings refreshes used by the live brush, quick, color, and floating panel
|
|
callbacks. Brush UI execution now dispatches through `BrushUiServices` before
|
|
the shared `src/legacy_brush_ui_services.*` bridge mutates legacy `Brush` and
|
|
panel state or loads brush resources.
|
|
`pano_cli plan-brush-texture-list` exposes app-core planning for brush/pattern
|
|
texture add, remove, and reorder actions, and `NodePanelBrush` now dispatches
|
|
those actions through `BrushTextureListServices` in the shared brush bridge
|
|
before the legacy image load/save and UI-list adapter continues.
|
|
`pano_cli plan-brush-stroke-control` exposes app-core planning for the live
|
|
stroke panel's slider, checkbox, blend-mode, tip-aspect reset, and default
|
|
brush reset commands. `NodePanelStroke` now dispatches those controls through
|
|
`BrushStrokeControlServices` in the shared brush bridge before the legacy
|
|
`Canvas::I`/`Brush`/stroke-panel adapter continues.
|
|
`pano_cli plan-brush-stroke-panel-view` exposes the app-core stroke-panel view
|
|
projection for brush float settings, toggles, blend modes, and thumbnail paths,
|
|
and live `NodePanelStroke::update_controls()` now consumes that tested
|
|
projection before applying retained slider-curve, preview, and thumbnail UI
|
|
updates.
|
|
`pano_cli plan-brush-refresh` exposes app-core planning for app-level brush
|
|
refresh fan-out, and live `App::brush_update()` now consumes that view before
|
|
applying retained stroke, quick, and floating color widget updates.
|
|
`pano_cli plan-canvas-tool` exposes app-core planning for draw/erase/line,
|
|
camera, grid, copy, cut, fill, mask, flood-fill, pick, and touch-lock toolbar
|
|
commands. Canvas tool execution now dispatches through `CanvasToolServices`
|
|
in `src/legacy_canvas_tool_services.*` before legacy toolbar selection, `Canvas`
|
|
mode, pen picking, touch-lock, and transform state adapters continue.
|
|
`pano_cli plan-canvas-tool-toolbar` now exposes the full draw-toolbar binding
|
|
set, including button ids, select/toggle actions, button-class expectation, and
|
|
the default draw-mode initialization. Live `App::init_toolbar_draw` consumes the
|
|
same app-core toolbar plan to install handlers and apply the initial draw tool
|
|
while retained `NodeButton`/`NodeButtonCustom` lookup and legacy canvas-tool
|
|
execution remain under `DEBT-0027`.
|
|
`pano_cli plan-canvas-tool-state` exposes the matching toolbar active-state
|
|
refresh used by `App::update` before legacy `Canvas` mode state remains the
|
|
source of truth. `NodeCanvas` stylus eraser mode switching consumes the same
|
|
shared bridge through its input-only path before legacy canvas mode execution
|
|
continues. Canvas mode pointer-tip visibility and Windows pressure remapping
|
|
now dispatch through `PlatformServices`, preserving iOS tip behavior and the
|
|
Windows pressure curve outside `canvas_modes.cpp`. `NodeCanvas` keyboard and
|
|
touch command handling now consumes
|
|
`pp_app_core` canvas-hotkey planning for E draw/erase, Ctrl+Z, Ctrl+Shift+Z,
|
|
Ctrl+S, Ctrl+Shift+S, Tab UI toggle, brush-size brackets, Android back, Alt
|
|
cursor reveal, and two-finger undo before the shared bridge delegates to legacy
|
|
UI/canvas/history adapters. `pano_cli plan-canvas-cursor` exposes the
|
|
canvas-specific cursor visibility policy for draw/erase versus non-paint
|
|
modes, small-brush thresholds, active-stroke hiding, and modifier/tool forced
|
|
visibility; live `NodeCanvas::update_cursor()` consumes that planner before
|
|
retained `App::show_cursor`/`App::hide_cursor` platform dispatch.
|
|
`pano_cli plan-canvas-clear` exposes app-core planning for the main toolbar
|
|
clear-current-layer command, including clear color validation, no-canvas
|
|
handling, undo recording intent, and dirty-state intent; live toolbar execution
|
|
and Layer menu clear now dispatch through the shared app-shell document-canvas
|
|
bridge before the legacy `Canvas::clear` adapter continues.
|
|
`pano_cli plan-image-import` exposes app-core planning for File > Import image
|
|
route decisions, including wide equirectangular images, legacy vertical cube
|
|
strips, regular transform-placement images, and invalid image dimensions; live
|
|
File > Import execution now dispatches through `DocumentImageImportServices`
|
|
before legacy image loading, `Canvas::import_equirectangular`, or import
|
|
transform-mode setup continues.
|
|
`pano_cli plan-file-menu` exposes app-core planning for the top-level File menu
|
|
commands, including new/open/import, save/save-as/save-version, share, resize,
|
|
cloud upload/browse, JPEG export, and export-submenu routing. Direct File menu
|
|
commands now dispatch through `FileMenuServices` in the shared app-shell bridge
|
|
`src/legacy_app_shell_services.*` before legacy dialogs, pickers, platform
|
|
services, cloud code, and canvas workflows continue.
|
|
`pano_cli plan-export-menu` exposes app-core planning for File menu export
|
|
choices, including image, layer, cube-face, depth, animation-frame, MP4, and
|
|
timelapse dialog routing plus license/canvas gating. Export menu commands now
|
|
dispatch through `DocumentExportMenuServices` in the shared app-shell bridge
|
|
before legacy export dialogs and renderer/video execution continue.
|
|
Export success-message metadata now also comes from `pp_app_core` through
|
|
`pano_cli plan-export-message` and the legacy document-export bridge, reducing
|
|
the bridge to export execution, platform handoff, and retained threading.
|
|
Export failure/license dialog metadata now comes from `pp_app_core` through
|
|
`pano_cli plan-export-report`, with legacy `App::dialog_export*` only showing
|
|
the planned dialog and dispatching retained export calls.
|
|
`pano_cli plan-grid-operation` exposes app-core planning for grid heightmap
|
|
pick/load/reload/clear, lightmap render capability/limit checks, and heightmap
|
|
commit used by the live grid panel. Grid execution now dispatches through
|
|
`GridUiServices` in `src/legacy_grid_ui_services.*` before legacy image loading,
|
|
OpenGL texture updates, nanort lightmap baking, and `Canvas::draw_objects`
|
|
execution continue.
|
|
The retained `NodePanelGrid` lightmap bake now uses the shared `parallel_for`
|
|
helper instead of platform-specific Win32 Concurrency Runtime and Apple
|
|
`dispatch_apply` branches, keeping the row-dispatch policy in common legacy
|
|
infrastructure while the bake itself remains debt-tracked.
|
|
`pano_cli plan-history-operation` exposes app-core planning for undo, redo, and
|
|
clear-history availability used by toolbar buttons and canvas shortcuts; live
|
|
toolbar and canvas-hotkey execution now dispatch through a shared app-shell
|
|
legacy history bridge before the legacy `ActionManager` stack adapter
|
|
continues. The bridge also centralizes saturated history metrics so app-core
|
|
plans never receive wrapped negative counts from oversized legacy stacks.
|
|
`pano_cli plan-main-toolbar` exposes app-core planning for the live main
|
|
toolbar/status-bar shell, including open/save dialogs, undo/redo availability,
|
|
clear-history availability, clear-canvas no-canvas blocking, message-box
|
|
creation, and settings dialog routing. The toolbar test-message dialog metadata
|
|
now lives in `pp_app_core` through `plan_main_toolbar_message_dialog`, and
|
|
`pano_cli plan-main-toolbar --command message-box` exposes it for automation.
|
|
`pp_app_core` now also owns a `MainToolbarServices` executor boundary, so
|
|
`App::init_toolbar_main` dispatches through `src/legacy_app_shell_services.*`
|
|
before legacy dialogs, history/canvas adapters, and settings UI execution
|
|
continue; retained toolbar message-box creation now uses
|
|
`src/legacy_app_dialog_services.*`.
|
|
`pano_cli plan-quick-operation` exposes app-core planning for quick brush/color
|
|
slot selection versus popup opening, plus quick mini-state restore/reset
|
|
validation used by the live quick panel. Quick-panel execution now dispatches
|
|
through `QuickUiServices` in `src/legacy_quick_ui_services.*` before the legacy
|
|
`Brush`, color picker, stroke preview, and preset popup adapter continues.
|
|
`pano_cli plan-quick-slider-preview` exposes app-core planning for quick
|
|
size/flow slider preview cursor placement, RTL offset handling, and pen/line
|
|
mode tip flags; live `NodePanelQuick` slider callbacks now consume that plan
|
|
before the retained `CanvasModePen`/`CanvasModeLine` and brush-preview updates.
|
|
`pano_cli plan-tools-menu` and `pano_cli plan-tools-panel` expose app-core
|
|
planning for top-level Tools commands and floating-panel requests, including
|
|
already-visible no-ops, panel chrome metadata, shortcuts, camera reset,
|
|
grid-clear, and platform-only SonarPen gating. Direct Tools commands now
|
|
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`, `pano_cli plan-canvas-view-density`, and
|
|
`pano_cli plan-canvas-view-cursor-mode` expose shared app-core canvas-view
|
|
state used by live reset-camera, viewport-density, and cursor-mode paths.
|
|
Tools reset-camera, document open/new-document reset, cloud download reset, and
|
|
options viewport/cursor callbacks now dispatch through
|
|
`src/legacy_canvas_view_services.*` before retained legacy canvas mutation and
|
|
settings writes.
|
|
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
|
|
legacy platform adapter.
|
|
Options-menu preference callbacks now dispatch UI scale, viewport scale, RTL,
|
|
VR mode, VR-controller, auto-timelapse, and cursor-mode side effects through
|
|
`AppPreferenceServices` in `src/legacy_app_preference_services.*` before
|
|
retained settings writes, recording lifecycle calls, and legacy canvas/UI
|
|
adapters continue.
|
|
VR mode start/stop now enters `App` platform wrappers that dispatch through
|
|
`PlatformServices`; the desktop runtime-selection policy in `pp_platform_api`
|
|
prefers OpenXR and marks OpenVR as a legacy fallback. Windows still reaches the
|
|
retained OpenVR bridge in `WindowsPlatformServices` until the OpenXR backend is
|
|
wired, while the legacy fallback reports unsupported VR startup on non-Windows
|
|
platforms until their shells own the service.
|
|
`pano_cli plan-about-menu` exposes app-core planning for About menu help,
|
|
about, what's-new, crash-test, and performance-test commands, including
|
|
versioned what's-new labels, diagnostic gating, and no-canvas performance-test
|
|
blocking. `pp_app_core` now also owns an `AboutMenuServices` executor boundary,
|
|
so `App::init_menu_about` dispatches through `src/legacy_app_shell_services.*`
|
|
before legacy dialogs, platform crash hooks, and Canvas performance strokes
|
|
continue.
|
|
`pp_platform_api` now owns a headless `PlatformServices` interface for
|
|
startup storage path preparation, clipboard text, cursor visibility,
|
|
virtual-keyboard visibility, UI-thread lifecycle hooks, render-context
|
|
acquire/release/present hooks, render-target binding hooks, render-capture
|
|
frame hooks, render platform hint hooks, render debug callback hooks, external
|
|
file display, file sharing, recording file cleanup, live asset/layout reload
|
|
policy, diagnostic stacktrace/crash hooks, SonarPen availability/startup,
|
|
VR mode start/stop,
|
|
image/file/save-file pickers, and directory pickers.
|
|
It also owns the SDK-free layout/asset file load policy helper used by
|
|
`LayoutManager`, so XML layout hot-reload timestamp checks no longer live in
|
|
the shared UI parser.
|
|
Windows installs an injected `WindowsPlatformServices` implementation from
|
|
`src/platform_windows/windows_platform_services.*` in `pp_platform_windows`;
|
|
other platforms still route through the debt-tracked legacy fallback adapter
|
|
now isolated in `src/platform_legacy/legacy_platform_services.*`, so behavior
|
|
is preserved while their platform shell implementations are extracted.
|
|
The central `App` header now forward-declares retained platform handles instead
|
|
of including Objective-C, Android, or GLFW SDK headers; the full platform
|
|
headers live in the legacy platform adapter until those handles move out of
|
|
`App` during Phase 6.
|
|
The retained `Asset` header is now Android-SDK-free, hides the Android asset
|
|
handles behind opaque pointers and `Asset::set_android_asset_manager`, and keeps
|
|
concrete Android asset-manager headers in `asset.cpp`/the Android entrypoint.
|
|
This reduces legacy asset I/O header coupling while the static manager bridge
|
|
and actual Android asset-reader implementation remain inside retained legacy
|
|
asset I/O.
|
|
Default canvas allocation size now dispatches through `PlatformServices`, so
|
|
`NodeCanvas` and command-line conversion creation paths preserve the desktop
|
|
1536 and WebGL 512 defaults without carrying the old `CANVAS_RES` platform
|
|
macro in `canvas.h`; DEBT-0057 tracks moving the retained WebGL policy branch
|
|
out of the legacy fallback when the Web shell owns injected services.
|
|
OpenGL runtime build-target classification now lives in `pp_renderer_gl`
|
|
through CMake-owned compile definitions and
|
|
`opengl_runtime_for_current_build()`, so `app_shaders.cpp` no longer decides
|
|
desktop GL/GLES/WebGL capability policy with local platform branches.
|
|
OpenGL extension enumeration now also lives in `pp_renderer_gl` through a
|
|
dispatch-tested `query_opengl_extensions` helper; shader startup still logs and
|
|
applies the resulting feature flags, but the GL extension query loop is no
|
|
longer app-owned.
|
|
OpenGL shader startup feature negotiation now also flows through
|
|
`pp_renderer_gl::query_opengl_capability_detection` and
|
|
`detect_opengl_feature_state`, so extension enumeration, desktop/GLES/WebGL
|
|
capability policy, and renderer-neutral feature conversion are tested together
|
|
behind the backend boundary. `App::initShaders` remains a legacy adapter that
|
|
copies the backend-owned feature snapshot into retained `ShaderManager` static
|
|
flags until `ShaderManager` itself becomes an OpenGL backend service.
|
|
Prepared-file save/download handoff is now also part of the service contract,
|
|
so iOS/Web export completion routes through `PlatformServices` after the app
|
|
writes the temporary/exported payload.
|
|
Prepared-file writable target selection now also dispatches through
|
|
`PlatformServices`, preserving the existing iOS temporary background-write path
|
|
and Web data-path synchronous write path while removing those platform branches
|
|
from `App::pick_file_save`.
|
|
PPBR and MP4 export dialogs now ask `PlatformServices` whether prepared-file
|
|
writes are used, so those dialog flows no longer spell local `__IOS__ ||
|
|
__WEB__` branches for mobile/Web export handoff.
|
|
Layer and animation-frame export dialogs now also ask `PlatformServices`
|
|
whether work-directory collection exports are used, then feed that into the
|
|
pure `pp_app_core` `plan_document_export_collection_target` policy. This
|
|
removes the local iOS branches from those dialogs while preserving iOS
|
|
`work_path/doc_layers` and `work_path/doc_frames` targets in the legacy
|
|
adapter until Apple platform services are injected.
|
|
App-owned curl helpers for download, upload, and license checks now ask
|
|
`PlatformServices` whether network TLS verification is disabled, removing the
|
|
local Android branches from those helpers while preserving Android's existing
|
|
TLS-verification bypass in the legacy adapter until a network/platform service
|
|
owns cloud transport.
|
|
The remaining legacy curl sites in `Asset::open_url`, `LogRemote::net_init`,
|
|
and `NodeDialogCloud::load_thumbs_thread` now consume the shared
|
|
`pp_platform_api` default TLS policy helper instead of spelling local Android
|
|
branches; this keeps the current Android behavior aligned with
|
|
`PlatformServices` while a dedicated network service is still pending.
|
|
The Tools menu SonarPen entry now asks `PlatformServices` whether SonarPen is
|
|
available and dispatches startup through the same service, preserving the
|
|
current iOS Objective-C bridge in the legacy adapter while removing iOS branches
|
|
from `App::init_menu_tools` and `LegacyToolsMenuServices`.
|
|
App VR lifecycle start/stop now asks `PlatformServices`, preserving the current
|
|
Windows OpenVR startup/shutdown bridge as the selected legacy fallback in
|
|
`WindowsPlatformServices` while non-Windows fallback adapters keep the existing
|
|
unsupported/no-op behavior.
|
|
Canvas image export publishing and explicit persistent-storage flushes now
|
|
dispatch through `PlatformServices` too, preserving iOS photo-library export
|
|
publication and WebGL filesystem sync behavior in the legacy adapter while
|
|
removing those direct platform calls from `Canvas` and brush preset storage.
|
|
Document-browser search root selection now dispatches through
|
|
`PlatformServices`, preserving the iOS `Inbox` root in the legacy adapter while
|
|
removing the iOS-specific branch from `App::dialog_browse`.
|
|
Save, New Document, and Browse dialog working-directory picker availability and
|
|
display-path formatting now also dispatch through `PlatformServices`, removing
|
|
desktop-only branches and Win32/macOS path formatting from those UI nodes while
|
|
preserving Windows and macOS picker behavior in platform adapters.
|
|
Native UI/window state saving now dispatches through `PlatformServices`,
|
|
preserving Windows window placement persistence in `WindowsPlatformServices`
|
|
and macOS UI state persistence in the legacy adapter while removing platform
|
|
guards from `App::ui_save`.
|
|
`App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, and
|
|
`App::hideKeyboard` now dispatch through the active service without local
|
|
platform guards; unsupported platforms rely on their service no-op behavior.
|
|
The unsaved-document close prompt now requests native app/window close through
|
|
`PlatformServices`, with Windows implemented by `WindowsPlatformServices` and
|
|
macOS/Linux still handled by the legacy adapter until those platform shells
|
|
are injected.
|
|
The UI loop's per-frame platform hooks now dispatch through
|
|
`PlatformServices`: Windows stylus timeout polling and FPS-title updates live
|
|
in `WindowsPlatformServices`, while Linux FPS-title updates remain in the
|
|
legacy adapter pending Phase 6 platform shell extraction.
|
|
Canvas input tip-visibility and pressure-remap policies now also dispatch
|
|
through `PlatformServices`, removing the local iOS and Windows branches from
|
|
pen, line, and flood-fill canvas modes.
|
|
The UI thread's platform attach/detach hooks now also dispatch through
|
|
`PlatformServices`, preserving Android JNI attach/detach behavior in the
|
|
legacy adapter while removing direct Android lifecycle calls from the main app
|
|
loop.
|
|
The app's render context acquire/release/present path now dispatches through
|
|
`PlatformServices` as well. Windows owns WGL acquisition, default framebuffer
|
|
rebinding, and swap in `WindowsPlatformServices`; Apple, Android, Linux, and
|
|
WebGL behavior is preserved behind the legacy adapter until their platform
|
|
shells are injected.
|
|
Render-task default-target binding and visible main-target binding now dispatch
|
|
through `PlatformServices`, preserving the existing iOS drawable bind in the
|
|
legacy adapter while removing the iOS drawable branch from `App::draw`.
|
|
Initial render platform hints now also dispatch through `PlatformServices`,
|
|
preserving the previous Windows/macOS program-point-size and line-smoothing
|
|
enablement while removing the Windows/macOS branch from `App::init`. The
|
|
Windows service now delegates the actual OpenGL program-point-size and
|
|
line-smooth enable sequence to a tested `pp_renderer_gl` dispatch helper, so
|
|
the platform shell no longer owns those backend state tokens. The legacy
|
|
non-Windows fallback now consumes the same helper for retained macOS render
|
|
platform hints, keeping the debt-tracked adapter as a thin GL call bridge
|
|
rather than a source of backend state policy.
|
|
Windows OpenGL debug callback setup now dispatches through `PlatformServices`,
|
|
moving Win32 console coloring and debug-break callback behavior into
|
|
`WindowsPlatformServices` while keeping other platform adapters as no-ops; the
|
|
debug-output/debug-output-synchronous state enable sequence is now a tested
|
|
`pp_renderer_gl` backend helper consumed by the Windows service.
|
|
Initial PanoPainter OpenGL depth/blend startup state is now represented and
|
|
applied by tested `pp_renderer_gl` startup-state contracts; `App::init`
|
|
delegates to the backend dispatch path instead of hard-coding the policy or
|
|
operation order, and its retained callback endpoints now reuse the shared UI
|
|
GL bridge instead of a local raw callback cluster.
|
|
OpenGL runtime version/vendor/renderer/GLSL string queries now also use a
|
|
tested `pp_renderer_gl` dispatch contract, leaving `App::init` to log the
|
|
result while the backend owns the query set and order. The Windows entrypoint
|
|
also uses that contract for early context logging and renderer-name window
|
|
title construction before replacing the temporary WGL context. Retained runtime
|
|
info and extension query callback endpoints now share
|
|
`legacy_gl_runtime_dispatch`.
|
|
The default app clear color and color-buffer clear operation now dispatch
|
|
through `pp_renderer_gl` as well, moving another direct OpenGL operation out
|
|
of `App::clear` while preserving the current gray clear behavior; the live
|
|
callback endpoints now share `legacy_ui_gl_dispatch`.
|
|
Main app UI viewport and scissor execution now dispatch through tested
|
|
`pp_renderer_gl` viewport/scissor contracts, leaving `App::draw` and UI node
|
|
clipping to provide rectangles while the backend owns scissor-state tokens and
|
|
the live OpenGL call sequence. The retained viewport/scissor callback endpoints
|
|
now share `legacy_ui_gl_dispatch`.
|
|
VR UI framebuffer viewport and scissor-test setup now also consumes those
|
|
`pp_renderer_gl` contracts, keeping desktop and VR UI rendering aligned while
|
|
the desktop XR path moves from the retained OpenVR app path toward OpenXR; its
|
|
retained callback endpoints now reuse the shared UI GL bridge.
|
|
VR draw blend/depth state snapshots, transitions, restore, and depth-buffer
|
|
clears, active texture unit switches, and fallback 2D texture unbinds now use
|
|
generic tested `pp_renderer_gl` capability query/apply, clear, active-texture,
|
|
and texture-bind dispatch contracts, reducing direct OpenGL execution in the
|
|
retained VR app path without changing state restore behavior. The remaining
|
|
retained VR draw adapter endpoints for these calls now share
|
|
`legacy_ui_gl_dispatch`.
|
|
The retained `gl_state` save/restore utility now snapshots and restores through
|
|
tested `pp_renderer_gl` saved-state dispatch contracts, covering capability
|
|
state, viewport, clear color, framebuffer/program bindings, active texture,
|
|
2D texture slots, samplers, and cube-map binding without changing the legacy
|
|
utility's public fields.
|
|
Legacy `Texture2D` allocation, binding, deletion, mipmap generation, region
|
|
update, and framebuffer readback now execute through tested `pp_renderer_gl`
|
|
texture dispatch contracts. This keeps the app API stable while moving another
|
|
resource lifecycle path behind the renderer backend boundary.
|
|
Legacy `RTT` resize/copy blits and byte/float framebuffer readbacks now execute
|
|
through tested `pp_renderer_gl` framebuffer dispatch contracts with draw/read
|
|
framebuffer binding restore handled by the backend helper.
|
|
Legacy `RTT::create`/`RTT::destroy` now route render-target texture allocation,
|
|
default texture parameter setup, optional depth renderbuffer allocation,
|
|
framebuffer color/depth attachment, framebuffer status checks, binding restore,
|
|
and resource deletion through tested `pp_renderer_gl` dispatch helpers.
|
|
Legacy `RTT` also exposes an RGBA8 region-readback helper that uses the same
|
|
backend framebuffer readback dispatch; canvas pick/history/snapshot and
|
|
transform history paths now call that helper instead of binding an RTT and
|
|
calling `glReadPixels` directly.
|
|
Legacy `RTT` now also exposes an RGBA8 region-update helper that routes dirty
|
|
rectangle texture writes through the tested `pp_renderer_gl` texture-update
|
|
dispatch; canvas undo, layer restore, and flood-fill apply paths now call it
|
|
instead of issuing direct `glTexSubImage2D` calls.
|
|
Retained `PBO` recording readbacks now route pixel-buffer allocation,
|
|
framebuffer readback, map, unmap, and deletion through tested
|
|
`pp_renderer_gl` dispatch helpers; recording thread ownership, progress UI, and
|
|
MP4 execution remain tracked by DEBT-0037.
|
|
Legacy `RTT::bindFramebuffer` and `RTT::unbindFramebuffer` now use tested
|
|
`pp_renderer_gl` draw/read framebuffer binding snapshot and restore contracts,
|
|
moving render-target pass entry/exit state management behind the backend.
|
|
Legacy `RTT::clear`, `RTT::clear_mask`, `RTT::bindTexture`, and
|
|
`RTT::unbindTexture` now dispatch through `pp_renderer_gl` clear,
|
|
color-write-mask restore, and texture-bind contracts, keeping render-target
|
|
utility operations behind the backend boundary. The retained RTT clear and
|
|
masked-clear callback endpoints now share `legacy_ui_gl_dispatch`.
|
|
Windows RenderDoc frame capture hooks now also dispatch through
|
|
`PlatformServices`, keeping capture integration in the platform service while
|
|
leaving non-Windows adapters as no-ops.
|
|
Startup data/work/recording/temp path preparation now dispatches through
|
|
`PlatformServices`, with Windows creating the Documents/PanoPainter folder
|
|
tree in `WindowsPlatformServices` and Apple/Linux/Web behavior preserved in the
|
|
legacy adapter until platform shells are injected.
|
|
Recording clear now asks `PlatformServices` whether the platform owns recorded
|
|
file deletion and dispatches the cleanup through the service, preserving the
|
|
current Apple recorded-frame cleanup while removing Apple-specific file cleanup
|
|
guards from `App::rec_clear`.
|
|
The UI loop now asks `PlatformServices` whether live shader/layout reloading
|
|
should run, preserving the previous Windows/macOS reload behavior while removing
|
|
the direct `(_WIN32 || __OSX__)` guard from `App::ui_thread_main`.
|
|
Layout XML reload read/skip decisions now go through `pp_platform_api` as well,
|
|
preserving desktop mtime-based reloads and non-desktop single-load behavior
|
|
while removing the direct Windows/macOS guard from `LayoutManager::load`.
|
|
`App::stacktrace` and `App::crash_test` now dispatch through `PlatformServices`,
|
|
with Windows retaining the debug-break crash hook and the legacy adapter
|
|
preserving Apple stacktrace/crash and Android crash-test behavior.
|
|
`pano_cli plan-cloud-upload` exposes the app-core cloud upload decision used by
|
|
the live cloud upload command for missing-canvas, new-document warning, publish
|
|
prompt, and dirty-document save-before-upload states before legacy UI, canvas,
|
|
and network execution continue.
|
|
`pano_cli plan-cloud-upload-all` exposes the app-core bulk upload file-count,
|
|
progress UI, and progress-total clamping decision used by the live upload-all
|
|
command before legacy asset listing, OpenGL context guard, progress UI, and
|
|
network upload execution continue.
|
|
`pano_cli plan-cloud-browse` exposes the app-core cloud browse and selected
|
|
download decisions used by the live cloud browse command before legacy dialog,
|
|
network download, canvas project-open, layer UI, and action-history execution
|
|
continue.
|
|
Cloud upload, bulk upload, and browse/download live execution now flows through
|
|
the `CloudServices` app-core boundary and `src/legacy_cloud_services.*`, keeping
|
|
`App::cloud_upload`, `App::cloud_upload_all`, and `App::cloud_browse` as thin
|
|
planning adapters while legacy save, progress UI, network, dialog, canvas-open,
|
|
layer-refresh, and action-history work remains tracked under `DEBT-0038`.
|
|
Cloud warning/publish/success prompts, bulk progress, and download-progress
|
|
prompt creation now route through `src/legacy_app_dialog_services.*`, while
|
|
cloud prompt/progress lifetime and network/document execution remain legacy.
|
|
The app-owned curl upload/download/license helpers now consume the platform TLS
|
|
verification policy through `PlatformServices`, and the retained Asset,
|
|
LogRemote, and cloud browse-dialog curl sites consume the same default platform
|
|
policy helper; retained cloud/network execution remains tracked under
|
|
`DEBT-0038`.
|
|
`pp_app_core` now also owns tested cloud transfer request and progress planning
|
|
through `plan_cloud_download_transfer`, `plan_cloud_upload_transfer`, and
|
|
`plan_cloud_transfer_progress`. Live `App::download` and `App::upload` consume
|
|
those plans before retained CURL setup, including missing endpoint rejection,
|
|
progress-callback enablement, TLS-verification policy, and zero/overrun progress
|
|
guards; `pano_cli plan-cloud-transfer` exposes the same path for automation.
|
|
Actual CURL ownership, upload form construction, response/error handling,
|
|
progress UI, and downloaded-project execution remain tracked under
|
|
`DEBT-0038`.
|
|
`pano_cli parse-layout` exercises the XML layout path. Continue expanding
|
|
document behavior toward legacy Canvas parity and then port OpenGL classes
|
|
behind the renderer boundary.
|
|
Brush preset-list add/select/move/remove/clear decisions now consume
|
|
`pp_app_core` through `NodePanelBrushPreset` and
|
|
`pano_cli plan-brush-preset-list`, so preset UI callbacks share tested
|
|
headless index/selection planning. Live preset-list execution now also
|
|
dispatches through `BrushPresetListServices` and the shared app-core executor
|
|
before the retained legacy bridge mutates child nodes. The remaining direct
|
|
`NodePanelBrushPreset` child-node execution, legacy `Brush` cloning, friend
|
|
adapter, and preset save/reload behavior stay tracked under `DEBT-0023`.
|
|
`App::open_document` now routes through the app-core document-open executor and
|
|
`src/legacy_document_open_services.*`, preserving ABR/PPBR import prompts,
|
|
unsaved-project discard prompts, project open, layer refresh, title updates,
|
|
and history clearing while those live effects remain tracked under
|
|
`DEBT-0039`. Accepted ABR/PPBR import prompts now delegate import execution to
|
|
the app-core brush package import executor and
|
|
`src/legacy_brush_package_import_services.*`, preserving detached legacy preset
|
|
panel import threads while retained brush asset execution remains tracked under
|
|
`DEBT-0048`.
|
|
`App::request_close`, `App::save_document`, and
|
|
`App::continue_document_workflow_after_optional_save` now route through
|
|
app-core document-session executors and `src/legacy_document_session_services.*`,
|
|
preserving close prompts, save dialogs, save-version routing, existing-project
|
|
save execution, and dirty-workflow save-before-continue prompts while retained
|
|
legacy UI/canvas behavior remains tracked under `DEBT-0040`.
|
|
The retained document-session prompt boxes now consume a pure prompt catalog for
|
|
close-unsaved, save-before-workflow, new-document overwrite, Save As overwrite,
|
|
and save-error metadata; `pano_cli plan-document-session-prompt` exposes the
|
|
same titles, messages, button captions, and cancel visibility for automation.
|
|
Close-unsaved, save-before-workflow, new-document overwrite, and Save As
|
|
overwrite prompt creation now also goes through
|
|
`src/legacy_app_dialog_services.*` before the document-session bridge attaches
|
|
its legacy callbacks.
|
|
`App::dialog_newdoc` now routes accepted new-document plans through the
|
|
app-core new-document executor and `src/legacy_document_session_services.*`,
|
|
preserving target overwrite prompts, legacy canvas resize/layer setup, history
|
|
clearing, title updates, dirty/new-document flag mutation, and keyboard/dialog
|
|
cleanup while retained execution remains tracked under `DEBT-0041`.
|
|
`App::dialog_save` and `App::dialog_save_ver` now route accepted Save As and
|
|
Save Version plans through app-core document file/version save executors and
|
|
`src/legacy_document_session_services.*`, preserving overwrite prompts,
|
|
legacy `Canvas::project_save`, app document field updates, title updates, and
|
|
keyboard/dialog cleanup while retained execution remains tracked under
|
|
`DEBT-0042`.
|
|
`App::dialog_export`, `App::dialog_export_layers`,
|
|
`App::dialog_export_anim_frames`, `App::dialog_export_depth`, and
|
|
`App::dialog_export_cube_faces` now route accepted file/stem/collection and
|
|
named export work through app-core document export executors and
|
|
`src/legacy_document_export_services.*`; layer/frame collection export target
|
|
destination is now planned in `pp_app_core` and selected by `PlatformServices`,
|
|
preserving existing platform messages, directory creation, picker-selected
|
|
stems, Web prepared-file handoff, and legacy `Canvas` export calls while
|
|
retained execution remains tracked under `DEBT-0043`.
|
|
`App::dialog_timelapse_export` and `App::dialog_export_mp4` now route
|
|
picker-selected MP4 export paths through the app-core document video export
|
|
executor and `src/legacy_document_export_services.*`, preserving mobile/Web
|
|
suggested-name save callbacks, desktop worker-thread timelapse export,
|
|
`App::rec_export`, animation `Canvas::export_anim_mp4` dispatch, and existing
|
|
success messages while retained execution remains tracked under `DEBT-0044`.
|
|
`App::dialog_ppbr_export` now routes picker-selected PPBR brush package exports
|
|
through the app-core brush package export executor and
|
|
`src/legacy_brush_package_export_services.*`, preserving dialog metadata
|
|
collection, legacy `Image` header ownership, desktop worker-thread export,
|
|
mobile/Web save completion, and `NodePanelBrushPreset::export_ppbr` while
|
|
export success-dialog metadata now comes from `pp_app_core` and is exposed by
|
|
`pano_cli plan-brush-package-export`. Retained execution remains tracked under
|
|
`DEBT-0047`.
|
|
PPBR package header validation and export target/data-directory planning now
|
|
live in `pp_assets::brush_package` and are exercised by
|
|
`pp_assets_brush_package_tests` plus `pano_cli plan-brush-package-export`.
|
|
The macOS-specific PPBR preview data-directory override now dispatches through
|
|
`PlatformServices`, so `NodePanelBrushPreset::export_ppbr` no longer spells a
|
|
local `__OSX__` branch while the actual PPBR serialization path remains
|
|
legacy-owned.
|
|
The live PPBR import/export path consumes those helpers, while legacy
|
|
Serializer/Image payload reading, stroke preview generation, preset storage,
|
|
and the historical permissive version check remain tracked under `DEBT-0047`
|
|
and `DEBT-0049`.
|
|
ABR and PPBR import image target planning for brush tips and patterns also now
|
|
uses `pp_assets::brush_package`, so the legacy preset panel no longer owns the
|
|
`data/brushes`, `data/brushes/thumbs`, `data/patterns`, and
|
|
`data/patterns/thumbs` path construction rules. Actual ABR/PPBR parsing,
|
|
duplicate policy, preset creation, save/reload, and progress/UI refresh remain
|
|
legacy-owned under `DEBT-0048`.
|
|
|
|
Implementation tasks:
|
|
|
|
- Extract components in this order:
|
|
1. `pp_foundation`
|
|
2. `pp_assets`
|
|
3. `pp_paint`
|
|
4. `pp_document`
|
|
5. `pp_renderer_api`
|
|
6. `pp_renderer_gl`
|
|
7. `pp_paint_renderer`
|
|
8. `pp_ui_core`
|
|
9. `pp_panopainter_ui`
|
|
10. `pp_platform_api`
|
|
11. `pp_platform_*`
|
|
12. `panopainter_app`
|
|
- Remove renderer/platform dependencies from pure headers first, especially:
|
|
- `Brush`
|
|
- document/layer model
|
|
- serializer
|
|
- UI core headers
|
|
- Keep facade shims where needed, but debt-track every shim.
|
|
- Avoid large behavioral rewrites during extraction.
|
|
- Each extracted component gets a focused test suite before moving to the next.
|
|
|
|
Gate:
|
|
|
|
- Old app still launches.
|
|
- Component tests pass after every extraction.
|
|
- No undocumented stubs or shortcuts.
|
|
|
|
## Phase 5: Renderer Boundary And OpenGL Parity
|
|
|
|
Goal: make OpenGL an implementation detail and establish parity tests before
|
|
adding new backends.
|
|
|
|
Status: started. `pp_renderer_api` exists as a headless renderer-neutral target
|
|
with renderer feature flags, explicit texture usage flags, texture descriptor, byte-size, viewport,
|
|
mesh, readback bounds, command context, render device, shader program
|
|
descriptor, mesh, render target, readback byte-size helpers,
|
|
texture mip-level validation, resource debug-label validation,
|
|
texture-upload/readback command validation,
|
|
mipmap-generation command validation, texture-state transition validation, frame-capture byte-size helpers,
|
|
readback/copy/frame-capture/blit descriptor validation, frame-capture command validation, render-target blit validation, texture-slot
|
|
binding validation, blend-state validation, scissor-state validation,
|
|
depth-state validation, trace marker/scope validation, sampler-state validation,
|
|
texture/mesh/shader resource-label validation,
|
|
recording-device reuse/reset validation, and the canonical PanoPainter shader
|
|
catalog now consumed by the legacy OpenGL app initialization path.
|
|
`pp_renderer_gl` now exists as the first OpenGL backend library and owns pure
|
|
OpenGL capability detection for framebuffer fetch, map-buffer alignment, and
|
|
float texture support. It also owns the OpenGL texture upload-type mapping used
|
|
by legacy `Texture2D` and `RTT` creation, RGBA pixel-format mapping used by
|
|
`RTT` texture allocation, plus image channel-count to texture
|
|
format mapping for `Texture2D` image uploads and framebuffer status naming for
|
|
`RTT` and `Texture2D` diagnostics. It also owns renderer API texture-format to
|
|
OpenGL internal/pixel/component token mapping, including depth-stencil formats,
|
|
for future backend texture objects. `Texture2D` 2D texture binding, upload,
|
|
mipmap generation, framebuffer readback setup, and update component-type tokens
|
|
now delegate to `pp_renderer_gl`; retained `Texture2D`, `TextureCube`, and
|
|
`RTT` texture allocation, bind, parameter, update, mipmap, and delete dispatch
|
|
now share the retained `legacy_gl_texture_dispatch` raw callback bridge.
|
|
`TextureCube` cube-map binding, allocation
|
|
face targets, RGBA allocation format, and unsigned-byte component type also
|
|
delegate to `pp_renderer_gl`. RGBA8/RGBA32F readback formats, checked byte-count math, PBO
|
|
pixel-buffer target/usage/access tokens, and PBO allocation/readback/map/unmap/delete
|
|
dispatch sequences used by retained recording readbacks now live in
|
|
`pp_renderer_gl`; retained `PBO` allocation, framebuffer readback, map, unmap,
|
|
and delete dispatch now share the retained `legacy_gl_pixel_buffer_dispatch`
|
|
raw callback bridge. Retained `Sampler` create, parameter, border-color, bind,
|
|
and unbind dispatch now share the retained `legacy_gl_sampler_dispatch` raw
|
|
callback bridge. The framebuffer blit color mask and linear/nearest
|
|
filter tokens used by `RTT::resize` and `RTT::copy`, renderer API blit-filter
|
|
to OpenGL token mapping, plus the default
|
|
render-target texture parameters and parameter dispatch, texture/renderbuffer
|
|
targets, depth format, framebuffer targets, binding queries, attachment points,
|
|
render-target framebuffer allocation/delete, binding restore, and completion
|
|
status used by `RTT::create`/`RTT::destroy` and framebuffer bind/restore paths,
|
|
also live in `pp_renderer_gl`; retained `Texture2D` readback and RTT
|
|
framebuffer allocation, deletion, bind/restore, blit, readback, and PBO
|
|
readback dispatch now share the retained `legacy_gl_framebuffer_dispatch` raw
|
|
callback bridge. Depth renderbuffer allocation/storage/delete and
|
|
framebuffer depth attach/detach sequences used by retained `RTT` and canvas
|
|
object-drawing helpers now execute through tested `pp_renderer_gl` dispatch
|
|
contracts and share the retained `legacy_gl_renderbuffer_dispatch` raw callback
|
|
bridge. 2D framebuffer-to-texture
|
|
copies used by canvas, transform, layer-conversion, panorama UI, brush preview,
|
|
and CanvasLayer cube-face generation paths now route through a tested
|
|
`pp_renderer_gl` copy dispatch via the retained target-aware framebuffer-copy
|
|
utility bridge. The copy bridge remains retained until renderer services own
|
|
cube and 2D framebuffer copy commands under `DEBT-0036`. RTT render-target clear, masked color clear
|
|
with color-write-mask restore, and texture bind/unbind dispatch now execute
|
|
through `pp_renderer_gl`; renderer API render-pass color/depth/stencil
|
|
clear-mask and clear-value mapping, and color-write-mask query tokens also live
|
|
there. `RTT` no longer spells GL enum names directly.
|
|
Renderer API primitive-topology to OpenGL draw-mode mapping, mesh index-type
|
|
and primitive-mode decisions used by legacy `Shape` drawing, plus Shape buffer
|
|
targets, static upload usage, and vertex attribute component/normalization
|
|
tokens, also live in `pp_renderer_gl`. Retained `Shape`, `TextMesh`, and
|
|
`NodeColorWheel` mesh buffer/VAO creation, dynamic vertex/index uploads,
|
|
fill/stroke/text draws, and buffer/VAO deletion now execute through tested
|
|
`pp_renderer_gl` dispatch contracts via the shared retained
|
|
`legacy_gl_mesh_dispatch` raw callback bridge. The
|
|
PanoPainter cube-face to
|
|
OpenGL texture-target mapping used by `TextureCube` also lives in
|
|
`pp_renderer_gl`. The legacy app delegates extension, upload-format,
|
|
framebuffer diagnostic, framebuffer blit, render-target setup, clear-state,
|
|
2D/cube texture setup, mesh draw-mode, and cube-face texture-target
|
|
interpretation to that backend library. Sampler wrap, min/mag filter, and
|
|
desktop border-color parameter mapping for legacy `Sampler` also lives in
|
|
`pp_renderer_gl`. Renderer API sampler filter/address-mode to OpenGL token
|
|
mapping, including mirrored-repeat, and aggregate renderer API sampler-state to
|
|
OpenGL min/mag/wrap mapping are also tested there. The PanoPainter shader attribute
|
|
binding catalog, shader stage tokens, compile/link status queries, active-uniform
|
|
count query, and matrix-uniform transpose token also live in `pp_renderer_gl`
|
|
and are consumed by legacy `Shader` creation; retained shader source
|
|
compilation/deletion, program attach/link/use/delete, attribute rebinding and
|
|
location lookup, active-uniform enumeration, uniform-location discovery, and
|
|
uniform writes now share the retained `legacy_gl_shader_dispatch` raw callback
|
|
bridge. Renderer API blend factor/op to
|
|
OpenGL token mapping also lives in `pp_renderer_gl`, with explicit support flags
|
|
so `GL_ZERO` remains distinguishable from unsupported enum values. Aggregate
|
|
renderer API blend-state to OpenGL enable/factor/equation/color-mask mapping,
|
|
depth compare-op to OpenGL depth-function mapping, and aggregate renderer API
|
|
depth-state to OpenGL enable/write/compare mapping also live in
|
|
`pp_renderer_gl`. Shader uniform hashing, catalog
|
|
validation, active-uniform mapping, and the legacy uniform uniqueness check now
|
|
delegate to `pp_renderer_gl` as well. `Shader` no longer spells GL enum names
|
|
directly. App OpenGL initialization debug severity, debug output, GL info
|
|
string, renderer API viewport/scissor rect conversion, default
|
|
depth/program-point/line-smooth state, blend factor/equation, and UI
|
|
render-target RGBA8 format tokens are now also cataloged and tested in
|
|
`pp_renderer_gl`; the legacy convert command now applies its depth,
|
|
program-point-size, source-alpha blend, and add-equation startup policy through
|
|
a tested backend dispatch contract, and the resize path consumes the same
|
|
backend-owned mapping. App clear color-buffer masks, default framebuffer
|
|
binding, scissor state, and sampler filter/wrap tokens now share that backend
|
|
mapping too. OpenGL extension enumeration query tokens used before runtime
|
|
capability detection also live in `pp_renderer_gl`. Legacy font atlas texture
|
|
formats, text mesh buffer targets, attribute component/normalization, draw
|
|
primitive/index type, upload usage, and active texture unit selection also
|
|
delegate to `pp_renderer_gl`; text mesh buffer/VAO creation, deferred index
|
|
and vertex uploads, indexed draw calls, and text draw texture-unit activation
|
|
now execute through the same tested dispatch contracts used by `Shape` through
|
|
`legacy_gl_mesh_dispatch`.
|
|
Canvas undo/redo dirty-region texture updates and readbacks now also execute
|
|
through retained `RTT` helpers backed by `pp_renderer_gl`, including 2D texture
|
|
target, dirty-region offsets, RGBA pixel format, and unsigned-byte component
|
|
type mapping. Canvas stroke commit, thumbnail generation, and object-draw
|
|
history paths now query saved blend state through the same tested capability
|
|
state dispatch before restoring it.
|
|
`NodeViewport` preview rendering now also delegates viewport query,
|
|
clear-color query, color-buffer clear mask, viewport execution, color clear,
|
|
clear-color restore, and blend-state execution through the shared
|
|
`legacy_ui_gl_dispatch` adapter and `pp_renderer_gl` mappings.
|
|
`NodeImageTexture` preview drawing now delegates its fallback 2D texture bind
|
|
and blend-state execution through the shared UI GL adapter.
|
|
`NodeImage` drawing and remote-image texture creation now delegate mipmapped
|
|
sampler filters, blend-state execution, and RGBA8/RGBA texture format mapping
|
|
to `pp_renderer_gl`.
|
|
`NodeColorWheel` triangle-buffer setup and draw-state handling now delegate
|
|
array-buffer, static-upload, vertex-attribute, primitive-mode, and blend-state
|
|
execution to `pp_renderer_gl`.
|
|
Simple UI text, text-input, border, scroll, and animation timeline draw paths
|
|
now also execute blend-state changes through the shared UI GL adapter.
|
|
Canvas layer cube/equirect generation, clear, restore, and snapshot paths now
|
|
also delegate cube/2D texture targets, active texture units, blend/clear state,
|
|
viewport execution, cube texture binding, color-buffer clears, clear-color
|
|
query/restore, and RGBA8 read/write pixel mapping to `pp_renderer_gl`. Its
|
|
active-texture, cube-texture binding, viewport, blend capability, clear-color,
|
|
and color-buffer clear adapter endpoints now share `legacy_ui_gl_dispatch`;
|
|
the cube-face framebuffer-to-texture copy now uses the shared retained
|
|
target-aware utility bridge and remains tracked under DEBT-0036 until a
|
|
renderer-owned cube copy command replaces it.
|
|
`NodePanelGrid` heightmap preview and lightmap baking now delegate texture
|
|
readback formats, sampler filters, depth/blend state, depth clears, viewport
|
|
queries, color-mask booleans, active texture units, and float render-target
|
|
formats to `pp_renderer_gl`, and its CPU lightmap row dispatch now uses the
|
|
shared legacy `parallel_for` helper rather than platform-specific worker APIs.
|
|
Its live heightmap draw and bake paths now execute depth/blend state changes,
|
|
depth clears, color-write-mask toggles, active texture selection, and bake
|
|
viewport changes through tested `pp_renderer_gl` dispatch adapters. Its desktop
|
|
texture-resize path now reuses `Texture2D::get_image()`, so grid texture
|
|
readback also goes through the tested framebuffer-backed texture readback
|
|
dispatch instead of direct `glGetTexImage`. Grid depth-state snapshots and sun
|
|
overlay viewport queries now also use tested backend query dispatch instead of
|
|
direct state reads.
|
|
Legacy `util.cpp` OpenGL error naming, framebuffer-to-texture copy helper, and
|
|
`gl_state` save/restore now delegate error codes, state queries, framebuffer
|
|
targets, texture binding targets, active texture units, shader program use, and
|
|
sampler binding to `pp_renderer_gl` through the shared retained bridge headers
|
|
instead of owning local raw OpenGL callbacks.
|
|
`NodeStrokePreview` brush preview rendering now delegates depth/scissor/blend
|
|
state, tested viewport/clear-color query dispatch, clear-color restore, active
|
|
texture unit execution, fallback 2D texture unbinds, 2D texture targets, copy
|
|
targets, sampler filters/wraps, and destination-feedback copy/fetch decisions
|
|
to `pp_renderer_gl` and `pp_paint_renderer`. Its live stroke-mixer and
|
|
brush-preview viewport, scissor, and depth/blend state changes now also
|
|
execute through tested `pp_renderer_gl` dispatch via the shared
|
|
`legacy_ui_gl_dispatch` bridge.
|
|
Retained `Canvas` stroke/thumbnail/object/export paths and `NodeCanvas`
|
|
panorama rendering use the same tested active-texture dispatch for their
|
|
texture-unit switches, and their live viewport, scissor, and generic
|
|
depth/blend/scissor capability changes and `NodeCanvas` capability-state
|
|
snapshots now route through the same backend dispatch contracts. Retained
|
|
`Canvas` stroke draw/commit, thumbnail
|
|
generation, object drawing, and `LayerFrame::clear` saved viewport/clear-color
|
|
query plus clear-color restore paths also use tested `pp_renderer_gl` dispatch
|
|
helpers. The retained `Canvas` active-texture, fallback texture unbind,
|
|
viewport/scissor execution, viewport and clear-color query, clear-color
|
|
restore, and capability query/apply adapter endpoints now share
|
|
`legacy_ui_gl_dispatch`; Canvas and RTT depth renderbuffer
|
|
allocation/attachment/delete now share `legacy_gl_renderbuffer_dispatch` while
|
|
resource lifetime ownership remains retained under DEBT-0036.
|
|
`NodeCanvas` saved viewport/clear-color query, density target color clear, and
|
|
clear-color restore paths use the same helpers. `NodeCanvas` and
|
|
`NodeStrokePreview` now share that retained UI GL dispatch bridge for
|
|
active-texture, fallback texture unbind, viewport/scissor, clear-color,
|
|
color-buffer clear, and capability query/apply adapter endpoints.
|
|
Retained `CanvasMode` overlay, mask, transform, and canvas-tip pick paths now
|
|
also use the same bridge for active-texture, capability query/apply, viewport,
|
|
read-framebuffer query, and RGBA8 pixel readback adapter endpoints while their
|
|
mode logic remains in the legacy UI implementation.
|
|
`NodePanelGrid` heightmap draw and bake setup now also share that bridge for
|
|
active-texture selection, depth/blend capability query/apply, viewport
|
|
query/execution, depth clears, and color-write-mask adapter endpoints.
|
|
Desktop HMD eye rendering now routes eye framebuffer viewport changes through
|
|
the tested `pp_renderer_gl` viewport dispatch while platform VR SDK bridges
|
|
remain isolated for later platform-shell extraction.
|
|
Legacy `Texture2D`, `TextureManager`, `Sampler`, and `RTT` public headers no
|
|
longer expose raw OpenGL enum defaults; default texture formats, sampler
|
|
filters/wraps, and render-target formats are resolved through backend-owned
|
|
overloads.
|
|
The Windows entrypoint now delegates generic OpenGL error-code/info-string
|
|
tokens, runtime string query ordering, and WGL core-context/pixel-format
|
|
attribute catalogs to `pp_renderer_gl`.
|
|
The headless OpenGL command planner now consumes `pp_renderer_api` recorded
|
|
commands and maps render-pass clear masks/values, viewport/scissor state,
|
|
blend/depth/sampler state, texture formats, primitive modes, draw counts, and
|
|
blit filters into GL-facing planned command data with explicit unsupported-token
|
|
rejection before a runtime GL context is needed. It also plans whole recorded
|
|
command streams, preserving per-command planned data while counting render
|
|
passes, draws, shader binds, shader uniforms, texture/sampler binds, texture
|
|
uploads, mipmap generation, texture transitions, texture copies, texture
|
|
readbacks, frame captures, passthrough commands, trace commands, unsupported
|
|
commands, and render-pass ordering errors such as state changes outside a pass,
|
|
nested passes, texture I/O or blits inside a pass, and unclosed passes. It
|
|
also validates executable command dependencies, including shader-before-uniform
|
|
and shader-plus-mesh before draw within each render pass, and rejects invalid
|
|
texture/sampler bind slots in malformed recorded streams.
|
|
The renderer-neutral API now also plans complex paint feedback strategies for
|
|
future stroke/layer compositing work: framebuffer-fetch-capable backends can
|
|
read destination color directly, while other backends must use ping-pong render
|
|
targets backed by texture copy or render-target blit support. This is exposed
|
|
through `pano_cli plan-paint-feedback` and tracked by DEBT-0036 until the live
|
|
paint renderer consumes the plan.
|
|
`pp_paint_renderer` now consumes that lower-level feedback planner through a
|
|
stroke composite plan that decides whether a stroke/layer blend can use
|
|
fixed-function blending or needs framebuffer-fetch/ping-pong destination
|
|
feedback. `pano_cli plan-stroke-composite` exposes the same decision for
|
|
automation, including layer blend, stroke blend, dual-brush, and pattern-blend
|
|
inputs. Live `Canvas::draw_merge` now uses this planner for its existing
|
|
shader-blend gate for layer and primary-brush blend modes while preserving the
|
|
legacy trigger policy; actual canvas stroke execution, dual-brush feedback, and
|
|
pattern feedback are still legacy OpenGL and remain tracked by DEBT-0036 until
|
|
the app calls through renderer services for the whole compositing path.
|
|
`pp_paint_renderer::plan_canvas_blend_gate` now also owns the compatibility
|
|
mapping from persisted layer and brush blend indices to that planner, including
|
|
fallback behavior for unknown nonzero indices. Both `Canvas::draw_merge` and
|
|
`NodeCanvas` panorama rendering consume that shared gate, so the live app no
|
|
longer has duplicate local blend-trigger logic or duplicate destination-copy
|
|
versus framebuffer-fetch decisions in those paths.
|
|
The OpenGL shader initialization path now stores a renderer-neutral
|
|
`RenderDeviceFeatures` snapshot converted by `pp_renderer_gl`, and those live
|
|
canvas gates consume that snapshot instead of rebuilding feature flags from
|
|
individual `ShaderManager` extension booleans.
|
|
`RenderDeviceFeatures` now carries the float32-linear-filtering bit as well,
|
|
so the canvas stroke texture format decision, renderer diagnostics, and grid
|
|
lightmap/bake target selection all consume the renderer-neutral feature
|
|
snapshot instead of reading `ShaderManager::ext_*` flags directly. The retained
|
|
extension booleans are now limited to the shader-manager compatibility adapter
|
|
and legacy logging.
|
|
`pp_paint_renderer::plan_canvas_stroke_feedback` now models the current stroke
|
|
shader's required destination feedback without changing the legacy shader math.
|
|
Live `Canvas::stroke_draw` consumes that plan for main-brush, dual-brush, and
|
|
stroke-pad destination-copy versus framebuffer-fetch decisions. Thumbnail layer
|
|
blending now consumes the same canvas destination-feedback decision for its
|
|
legacy `TextureBlend` path. `NodeStrokePreview` uses the same destination
|
|
feedback plan for its live brush-preview copy/fetch decision. The full
|
|
thumbnail and brush-preview compositing execution remains legacy OpenGL until a
|
|
fuller live paint-renderer boundary can take over.
|
|
The existing renderer classes are not yet fully
|
|
behind the renderer interfaces.
|
|
|
|
Implementation tasks:
|
|
|
|
- Introduce renderer interfaces:
|
|
- `IRenderDevice`
|
|
- `ITexture2D`
|
|
- `IRenderTarget`
|
|
- `IShaderProgram`
|
|
- `IMesh`
|
|
- `ICommandContext`
|
|
- `IReadbackBuffer`
|
|
- `IRenderTrace`
|
|
- Port current renderer classes behind OpenGL backend types:
|
|
- `RTT`
|
|
- `Texture2D`
|
|
- `Sampler`
|
|
- `ShaderManager`
|
|
- `Shape`
|
|
- Keep OpenGL runtime capability decisions in `pp_renderer_gl` with headless
|
|
tests before moving GL object lifetimes behind backend types.
|
|
- Preserve current shader behavior and asset paths.
|
|
- Add deterministic GPU tests:
|
|
- clear
|
|
- blit
|
|
- texture upload/download
|
|
- stroke composite
|
|
- erase
|
|
- layer blend
|
|
- equirect export
|
|
- readback bounds
|
|
- Add CPU reference tests for final RGBA and stroke-alpha blend modes.
|
|
- Compare GPU output to golden/reference data with explicit tolerances.
|
|
|
|
Gate:
|
|
|
|
- OpenGL readbacks match golden data on Windows and Linux.
|
|
- Mobile/WebGL compile gates remain green.
|
|
|
|
## Phase 6: Platform Alignment
|
|
|
|
Goal: every supported platform consumes the same component targets.
|
|
|
|
Status: started. Root CMake configure presets now have matching build presets
|
|
for Windows VS 2026/default, Windows clang-cl ASan, Linux clang, Android
|
|
standard x64/arm64, Android Quest arm64, Android Focus/Wave arm64,
|
|
Emscripten/WebGL, macOS, iOS device, and iOS simulator. `platform-build`
|
|
automation now builds the current headless component matrix, including
|
|
`pp_platform_api`, `pp_app_core`, platform API tests, brush-package tests, and
|
|
the current app-core startup/frame/shutdown/file/document/brush/canvas/history/grid/toolbar/
|
|
tools/about/preferences/status automation tests. The PowerShell wrapper also
|
|
normalizes comma-separated `-Presets` and `-Targets` values for reliable
|
|
machine-driven partial matrix checks. `panopainter_platform_build_target_matrix_self_test`
|
|
keeps the PowerShell and shell wrapper defaults aligned with every current
|
|
CMake test executable plus required component targets, and now verifies the
|
|
default Android preset set covers standard arm64/x64, Quest arm64, and
|
|
Focus/Wave arm64. The shell wrapper now mirrors the PowerShell wrapper's
|
|
multi-preset behavior and reports one structured result array. Root CMake now
|
|
also exposes non-default platform validation targets:
|
|
`panopainter_platform_build_headless`,
|
|
`panopainter_platform_build_android_assets`,
|
|
`panopainter_platform_build_vcpkg_ui_core`, and
|
|
`panopainter_platform_build_apple_remote`; the platform-build self-test guards
|
|
those target names and the wrapper matrix now includes
|
|
`pp_app_core_app_dialog_tests` with the rest of the CMake test executables.
|
|
`package-smoke` now emits a structured package readiness matrix for Windows
|
|
AppX, Android standard/Quest/Focus APKs, Apple bundles, Linux app output, and
|
|
WebGL output, with blocked prerequisites tied to DEBT-0011. It also has a
|
|
readiness-only mode for cheap package blocker inventory without building an app
|
|
artifact, and `panopainter_package_smoke_readiness_self_test` keeps the
|
|
PowerShell and shell readiness matrices aligned, including retained Linux/WebGL
|
|
CMake baseline metadata. The PowerShell wrapper can also run the retained
|
|
Android native package checks through `-AndroidNativeChecks`, reporting the
|
|
standard `native-lib` build plus Quest/Focus configure checks next to the APK
|
|
blocker matrix. Root CMake now exposes non-default package validation targets
|
|
for package readiness, Windows app artifact smoke, and retained Android native
|
|
checks: `panopainter_package_readiness`,
|
|
`panopainter_windows_app_package_smoke`,
|
|
`panopainter_android_standard_native_package`,
|
|
`panopainter_android_vr_native_package_configure`, and
|
|
`panopainter_android_native_package_smoke`, plus the retained Linux/WebGL
|
|
blocker target `panopainter_linux_webgl_package_readiness`. App/package
|
|
entrypoints still need to consume shared targets and remain covered by debt
|
|
until package validation is migrated from legacy package projects to root
|
|
CMake.
|
|
Retained Linux and WebGL app CMake entrypoints now match the interim platform
|
|
baseline used by Android package paths: CMake 3.10 plus target-level
|
|
`cxx_std_23`, with `panopainter_retained_platform_cmake_self_test` guarding
|
|
against regressions while those entrypoints wait behind root CMake package/app
|
|
target migration.
|
|
Apple compile validation now runs on the local Mac mini SSH host
|
|
`panopainter-mac` through `scripts/automation/apple-remote-build.ps1`. The host
|
|
uses Homebrew CMake/Ninja/Git plus full Xcode via `DEVELOPER_DIR`, pulls the
|
|
modernization branch from Gitea, initializes the source submodules needed by the
|
|
current headless matrix, and builds `macos`, `ios-simulator`, and `ios-device`.
|
|
The iOS device compile gate assigns generated bundle identifiers and disables
|
|
code signing for test/tool executables under DEBT-0059; signed Apple app bundle
|
|
and package-smoke migration remains open under DEBT-0011.
|
|
`pp_platform_api` now also owns a tested platform-family policy catalog used by
|
|
both `WindowsPlatformServices` and the retained non-Windows fallback for
|
|
exported-image publishing, persistent-storage flushing, document browse roots,
|
|
working-directory picker availability, prepared-file target planning,
|
|
work-directory collection export policy, PPBR data-directory override policy,
|
|
SonarPen availability, native UI/window state saving, live asset reload policy,
|
|
layout XML file mtime reload policy, recording cleanup policy, default canvas
|
|
resolution, and canvas tip visibility. Platform SDK calls and filesystem probes
|
|
remain in the platform shells or thin runtime wrappers while those decisions are
|
|
headless-testable.
|
|
The retained Android standard/Quest/Focus package CMake files now use CMake
|
|
3.10, request C++23 through target compile features, include the extracted
|
|
modern component/service source set that the legacy package still links
|
|
monolithically, and share a generated `nanort` compatibility overlay from
|
|
`android/cmake/PanoPainterAndroidLegacyCompat.cmake` instead of dirtying the
|
|
vendor submodule. The standard package `native-lib` arm64 target now compiles
|
|
and links with the current NDK; Quest and Focus configure with the aligned Yoga
|
|
source list and their SDK imported-library paths. Android automation now uses
|
|
`sdkmanager` to compare the newest available SDK-managed NDK and CMake packages,
|
|
installs newer or missing packages when needed, and selects those versions
|
|
before configuring Android presets or retained package paths; on the current
|
|
Windows host both NDK `30.0.14904198` and CMake `4.1.2` report
|
|
`already-latest-available`.
|
|
|
|
Implementation tasks:
|
|
|
|
- Convert these builds to shared component targets:
|
|
- Windows desktop
|
|
- Windows AppX
|
|
- macOS
|
|
- iOS
|
|
- Android standard
|
|
- Android Quest
|
|
- Android Focus/Wave
|
|
- Linux
|
|
- WebGL/Emscripten
|
|
- Keep platform entrypoints thin:
|
|
- window lifecycle
|
|
- input dispatch
|
|
- clipboard
|
|
- file picker/share
|
|
- GL context creation
|
|
- VR SDK bridge
|
|
- packaging only
|
|
- Add or refine CMake toolchain/preset support for:
|
|
- Android NDK ABIs
|
|
- iOS device
|
|
- iOS simulator
|
|
- macOS
|
|
- Emscripten
|
|
- Keep SDK-only imported libraries documented until vcpkg triplets are proven.
|
|
|
|
Gate:
|
|
|
|
- Every platform has a named configure/build command.
|
|
- Missing local prerequisites are documented.
|
|
- Each platform has at least compile or package validation.
|
|
|
|
## Phase 7: Hardening, Coverage, And Breaking-Point Tests
|
|
|
|
Goal: tests should try to break components, not only confirm current happy
|
|
paths.
|
|
|
|
Implementation tasks:
|
|
|
|
- Add property/fuzz tests for:
|
|
- binary streams
|
|
- serializers
|
|
- PPI parsing
|
|
- ABR parsing
|
|
- layout XML parsing
|
|
- image metadata parsing
|
|
- brush parameter extremes
|
|
- layer/frame operations
|
|
- undo/redo invariants
|
|
- Add stress tests for:
|
|
- thousands of stroke samples
|
|
- extreme resolutions guarded by memory limits
|
|
- rapid layer/frame edits
|
|
- corrupt assets
|
|
- cancellation during export
|
|
- concurrent render/UI task scheduling
|
|
- Add coverage for headless libraries on Clang/GCC.
|
|
- Require coverage reports for changed components first; do not set a global
|
|
threshold until the baseline is meaningful.
|
|
- Add tracing spans around:
|
|
- project load/save
|
|
- render passes
|
|
- stroke commit
|
|
- readback
|
|
- export
|
|
- UI layout
|
|
- platform I/O
|
|
- Logs must include component, thread, frame/stroke id, and timing.
|
|
|
|
Gate:
|
|
|
|
- No shortcut remains undocumented.
|
|
- Every component has unit tests and at least one failure or edge test.
|
|
|
|
## Phase 8: Future Backend Readiness
|
|
|
|
Goal: prepare Vulkan and Metal without destabilizing the OpenGL parity path.
|
|
|
|
Implementation tasks:
|
|
|
|
- Create non-default targets only after OpenGL backend parity:
|
|
- `pp_renderer_vulkan_lab`
|
|
- `pp_renderer_metal_lab`
|
|
- Use `D:\Dev\vkpaint` as reference material for Vulkan painting experiments,
|
|
not as direct production code.
|
|
- Before integration, prove:
|
|
- ping-pong compositing path
|
|
- input-attachment/subpass path where applicable
|
|
- feedback-loop or framebuffer-fetch-style path where supported
|
|
- synchronization and layout correctness under validation layers
|
|
- Keep WebGPU as an optional future portability backend, not the core renderer
|
|
contract.
|
|
|
|
Gate:
|
|
|
|
- Vulkan/Metal lab targets are opt-in.
|
|
- OpenGL production backend remains stable.
|
|
|
|
## Test Matrix
|
|
|
|
| Preset/Label | Purpose | Requires |
|
|
| --- | --- | --- |
|
|
| `desktop-fast` | Pure component unit tests | No GPU/window |
|
|
| `desktop-gpu` | OpenGL backend golden/readback tests | GPU/GL context |
|
|
| `fuzz` | Deterministic parser/serializer edge corpus; future libFuzzer entrypoint | No GPU/window today |
|
|
| `stress` | Large and adversarial scenarios | Longer runtime |
|
|
| `platform-build` | Configure/build each supported platform | Local toolchains |
|
|
| `package-smoke` | AppX/APK/Apple/WebGL package smoke | Platform SDKs |
|
|
|
|
Acceptance for each phase:
|
|
|
|
- Previous phase tests still pass.
|
|
- New component has its own tests.
|
|
- No undocumented stubs.
|
|
- No skipped platform without a debt entry.
|
|
- Automation command is recorded in this roadmap or linked docs.
|
|
|
|
## Verified Commands
|
|
|
|
Last verified on 2026-06-02:
|
|
|
|
```powershell
|
|
cmake --preset windows-msvc-default
|
|
cmake --build --preset windows-msvc-default --config Debug --target pp_foundation_binary_stream_tests pp_foundation_event_tests pp_foundation_log_tests pp_foundation_parse_tests pp_foundation_task_queue_tests pp_foundation_trace_tests pp_assets_image_format_tests pp_assets_image_metadata_tests pp_assets_image_pixels_tests pp_assets_ppi_header_tests pp_assets_settings_document_tests pp_paint_brush_tests pp_paint_blend_tests pp_paint_stroke_tests pp_document_tests pp_document_ppi_import_tests pp_document_ppi_export_tests pp_renderer_api_tests pp_paint_renderer_compositor_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pano_cli PanoPainter
|
|
ctest --preset desktop-fast --build-config Debug
|
|
ctest --preset fuzz --build-config Debug
|
|
ctest --preset stress --build-config Debug
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\test.ps1 -Preset desktop-fast -Configuration Debug
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\build.ps1 -Preset windows-msvc-default -Configuration Debug -Target pano_cli
|
|
cmake --build --preset windows-msvc-default --target panopainter_validate_shaders
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\analyze.ps1 -Preset windows-msvc-default -NoApp
|
|
set VCPKG_ROOT=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg
|
|
cmake --preset windows-msvc-vcpkg-headless
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets windows-msvc-vcpkg-headless
|
|
ctest --preset desktop-fast-vcpkg --build-config Debug
|
|
cmake --preset android-arm64
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly
|
|
cmake --fresh --preset windows-clangcl-asan
|
|
powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.ps1 -Presets macos,ios-simulator,ios-device
|
|
```
|
|
|
|
Results:
|
|
|
|
- `pp_foundation_binary_stream_tests` passed.
|
|
- `pp_foundation_event_tests` passed.
|
|
- `pp_foundation_log_tests` passed.
|
|
- `pp_foundation_parse_tests` passed.
|
|
- `pp_foundation_task_queue_tests` passed.
|
|
- `pp_foundation_trace_tests` passed.
|
|
- `pp_assets_image_format_tests` passed.
|
|
- `pp_assets_image_metadata_tests` passed.
|
|
- `pp_assets_image_pixels_tests` passed, including RGBA8 PNG decode and corrupt
|
|
payload rejection.
|
|
- `pp_assets_ppi_header_tests` passed, including PPI thumbnail/body layout,
|
|
body summary validation, layer/frame indexing, explicit per-layer metadata
|
|
and per-layer frame duration writing, dirty-face PNG payload metadata
|
|
validation, targeted layer/frame dirty-face writing, and decoded dirty-face
|
|
payload coverage.
|
|
- `pp_assets_settings_document_tests` passed.
|
|
- `pp_paint_brush_tests` passed.
|
|
- `pp_paint_blend_tests` passed.
|
|
- `pp_paint_stroke_tests` passed.
|
|
- `pp_paint_stroke_script_tests` passed.
|
|
- `pp_document_tests` passed, including snapshot construction, alpha-lock
|
|
metadata, per-layer frame metadata, frame move, duration, face-pixel payload
|
|
storage/replacement/rejection, snapshot-embedded face-payload rejection, and
|
|
history invariants.
|
|
- `pp_document_ppi_import_tests` passed, including decoded PPI dirty-face
|
|
payload attachment to `pp_document` layer/frame storage and out-of-range
|
|
payload rejection.
|
|
- `pp_document_ppi_export_tests` passed, including pure document metadata,
|
|
per-layer frame duration, and PNG-encoded face-payload export to PPI bytes,
|
|
plus malformed payload rejection at the export boundary.
|
|
- `pp_renderer_api_tests` passed, including shader descriptor validation,
|
|
PanoPainter shader catalog validation, explicit texture usage validation,
|
|
texture mip-level validation, resource debug-label validation, readback
|
|
byte-size and command-order validation, texture-upload byte-count validation,
|
|
mipmap-generation command validation, trace marker/scope validation,
|
|
frame-capture byte-size and command-order validation,
|
|
render-target blit validation, texture-slot binding validation, blend-state
|
|
validation, scissor-state validation, render-pass color/depth/stencil clear
|
|
validation, shader-uniform write validation, draw descriptor/range
|
|
validation, backend-neutral resource factory validation, texture-copy
|
|
validation, recording
|
|
render-pass clear/scissor/depth/blend/shader-uniform/texture/sampler-bind/
|
|
upload/texture-copy/readback/frame-capture/blit command capture, draw
|
|
mesh-input capture, explicit draw-range capture, and invalid catalog
|
|
rejection. The same suite now covers complex paint feedback planning for
|
|
framebuffer-fetch backends, ping-pong texture-copy/blit fallbacks, simple
|
|
no-feedback blends, invalid render-target usage, unsupported backends, and
|
|
depth-target rejection.
|
|
- `pp_paint_renderer_compositor_tests` passed, including pure
|
|
`pp_document` frame/face compositing over per-layer dirty face payloads.
|
|
The suite now covers fixed-function stroke composite planning,
|
|
framebuffer-fetch planning, ping-pong texture-copy/blit fallback planning,
|
|
dual/pattern blend feedback detection, invalid blend mode rejection,
|
|
unsupported backend rejection, and invalid render-target rejection.
|
|
- `pp_ui_core_color_tests` passed.
|
|
- `pp_ui_core_layout_value_tests` passed.
|
|
- `pp_ui_core_layout_xml_tests` passed.
|
|
- `pano_cli_create_document_smoke` passed.
|
|
- `pano_cli_create_animation_document_smoke` passed and reports animation
|
|
duration JSON.
|
|
- `pano_cli_simulate_document_edits_smoke` passed and reports pure
|
|
`pp_document` layer metadata, frame order, active indices, and face-payload
|
|
state as JSON.
|
|
- `pano_cli_simulate_document_history_smoke` passed and reports real
|
|
`pp_document::DocumentHistory` apply/undo/redo state as JSON.
|
|
- `pano_cli_simulate_document_export_smoke` passed and reports pure
|
|
`pp_document` export to PPI bytes, asset-level decode, and document reimport
|
|
round-trip state as JSON.
|
|
- `pano_cli_simulate_image_import_smoke` passed and reports embedded PNG decode
|
|
plus `pp_document` face-payload attachment state as JSON.
|
|
- `pano_cli_inspect_image_rejects_unsupported` passed as an expected failure
|
|
test.
|
|
- `pano_cli_inspect_png_metadata_smoke` passed and reports PNG metadata JSON
|
|
for the tiny IHDR fixture.
|
|
- `pano_cli_import_image_rejects_truncated_png` passed as an expected failure
|
|
test, proving the file-driven image import command rejects a metadata-valid
|
|
but undecodable PNG payload.
|
|
- `pano_cli_inspect_project_layout_smoke` passed and reports PPI
|
|
thumbnail/body byte layout, body summary, layer/frame descriptors, and
|
|
dirty-face PNG payload metadata JSON.
|
|
- `pano_cli_load_project_metadata_smoke` passed and reports a `pp_document`
|
|
projection with per-layer frame counts, durations, and zero loaded face
|
|
payloads for the minimal PPI fixture.
|
|
- `pano_cli_save_project_roundtrip_smoke` passed and proves the metadata-only
|
|
`pp_assets` PPI writer can save a generated multi-frame PPI and reload it
|
|
through `pano_cli load-project`.
|
|
- `pano_cli_save_project_payload_roundtrip_smoke` passed and proves the
|
|
`pp_assets` PPI writer can save a compressed RGBA PNG dirty-face payload to
|
|
an explicit layer/frame slot, inspect the serialized descriptor, and reload
|
|
it as decoded `pp_document` face-pixel data.
|
|
- `pano_cli_save_document_project_roundtrip_smoke` passed and proves a pure
|
|
`pp_document` export can be written to a PPI file, inspected for layer/frame
|
|
dirty-face descriptors, and loaded back through the PPI import path.
|
|
- `pano_cli_apply_stroke_script_roundtrip_smoke` passed and proves a checked-in
|
|
stroke script can be parsed, sampled, applied to a pure `pp_document` face
|
|
payload, written to PPI, inspected for the expected dirty-face box, and loaded
|
|
back as decoded document pixel data.
|
|
- `pano_cli_apply_stroke_script_rejects_tiny_canvas` passed as an expected
|
|
failure test, proving the stroke-script document command rejects dimensions
|
|
outside its bounded automation range before payload allocation.
|
|
- `pano_cli_parse_layout_smoke` passed.
|
|
- `pano_cli_simulate_stroke_smoke` passed and reports deterministic stroke
|
|
sample counts/distances.
|
|
- `pano_cli_simulate_stroke_script_smoke` passed and reports deterministic
|
|
aggregate stroke-script counts/distances.
|
|
- `pp_app_core_document_cloud_tests` passed, covering cloud upload no-canvas,
|
|
new-document warning, clean publish prompt, and dirty save-before-upload
|
|
decisions, plus cloud browse no-canvas/show-browser and selected-download
|
|
decisions, plus bulk upload progress visibility, zero-file, and clamped
|
|
progress-total decisions.
|
|
- `pano_cli_plan_cloud_upload_clean_smoke`,
|
|
`pano_cli_plan_cloud_upload_unsaved_smoke`,
|
|
`pano_cli_plan_cloud_upload_new_document_smoke`, and
|
|
`pano_cli_plan_cloud_upload_no_canvas_smoke` passed and expose those app-core
|
|
cloud upload decisions as JSON.
|
|
- `pano_cli_plan_cloud_upload_all_progress_smoke` and
|
|
`pano_cli_plan_cloud_upload_all_headless_smoke` passed and expose app-core
|
|
bulk upload progress decisions as JSON.
|
|
- `pano_cli_plan_cloud_browse_waiting_smoke`,
|
|
`pano_cli_plan_cloud_browse_selected_smoke`, and
|
|
`pano_cli_plan_cloud_browse_no_canvas_smoke` passed and expose app-core cloud
|
|
browse/download-selection decisions as JSON.
|
|
- `pp_app_core_document_cloud_tests` now also covers cloud transfer request
|
|
validation, progress-callback enablement, TLS-verification policy, and
|
|
zero/negative/overrun transfer-progress guards.
|
|
- `pano_cli_plan_cloud_transfer_download_smoke`,
|
|
`pano_cli_plan_cloud_transfer_upload_smoke`,
|
|
`pano_cli_plan_cloud_transfer_rejects_missing_destination`, and
|
|
`pano_cli_plan_cloud_transfer_zero_total_smoke` passed and expose the
|
|
app-core cloud transfer path as JSON.
|
|
- `PanoPainter`, `pp_app_core_document_cloud_tests`, and `pano_cli` built after
|
|
live `App::download` and `App::upload` started consuming the transfer plans
|
|
before retained CURL setup.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`, and
|
|
`pp_app_core_document_cloud_tests` built after the cloud transfer slice.
|
|
- `PanoPainter`, `pp_app_core_document_cloud_tests`, and `pano_cli` built after
|
|
cloud upload warning/publish/success prompts, bulk upload progress dialogs,
|
|
and download-progress messages moved to tested `pp_app_core` metadata plans.
|
|
- Focused cloud metadata CTest coverage passed for
|
|
`pp_app_core_document_cloud_tests` and representative
|
|
`pano_cli_plan_cloud_*` smoke tests, including prompt titles/captions,
|
|
progress-dialog titles, and formatted download progress messages.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`, and
|
|
`pp_app_core_document_cloud_tests` built after the cloud metadata slice.
|
|
- `PanoPainter`, `pp_app_core_document_cloud_tests`, and `pano_cli` built after
|
|
live cloud upload, bulk upload, and browse/download execution moved behind
|
|
the `CloudServices` boundary and `src/legacy_cloud_services.*`.
|
|
- Focused cloud CTest coverage passed for `pp_app_core_document_cloud_tests`
|
|
and all `pano_cli_plan_cloud_*` smoke tests after the live bridge split.
|
|
- `ctest --preset desktop-fast --build-config Debug` passed with 243 tests
|
|
after the cloud bridge split.
|
|
- `scripts/automation/package-smoke.ps1 -Preset windows-msvc-default
|
|
-Configuration Debug` passed executable/data checks after the cloud bridge
|
|
split; package target migration blockers remain under `DEBT-0011`.
|
|
- `PanoPainter`, `pp_app_core_document_cloud_tests`,
|
|
`pp_app_core_app_dialog_tests`, and `pano_cli` built after cloud
|
|
download-progress prompt creation moved onto
|
|
`src/legacy_app_dialog_services.*`.
|
|
- Focused cloud/app-dialog CTest coverage passed for
|
|
`pp_app_core_document_cloud_tests`, `pp_app_core_app_dialog_tests`, all
|
|
`pano_cli_plan_cloud_*` smoke tests, and `pano_cli_plan_app_dialog_*` after
|
|
the cloud prompt bridge split.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`,
|
|
`pp_app_core_document_cloud_tests`, and `pp_app_core_app_dialog_tests` built
|
|
after the cloud prompt bridge split.
|
|
- `PanoPainter`, `pp_app_core_document_session_tests`, and `pano_cli` built
|
|
after `App::open_document` moved live execution behind the document-open
|
|
services bridge. A clean rebuild was required once because MSVC reported the
|
|
known Debug PDB `LNK1103` corruption, after which the build passed.
|
|
- Focused document-open CTest coverage passed for
|
|
`pp_app_core_document_route_tests`, `pp_app_core_document_session_tests`, and
|
|
the `pano_cli_plan_open_route_*` smoke tests after the live bridge split.
|
|
- `PanoPainter`, `pp_app_core_document_session_tests`, and `pano_cli` built
|
|
after close request, document save, and dirty-workflow continuation execution
|
|
moved behind document-session services. A clean rebuild was required once
|
|
because MSVC reported the known Debug PDB `LNK1103` corruption, after which
|
|
the build passed.
|
|
- Focused document-session CTest coverage passed for
|
|
`pp_app_core_document_session_tests`, `pano_cli_simulate_app_session_*`, and
|
|
`pano_cli_plan_document_file/version_*` smoke tests after the live bridge
|
|
split.
|
|
- `PanoPainter`, `pp_app_core_document_session_tests`, and `pano_cli` built
|
|
after accepted new-document execution moved behind the new-document services
|
|
bridge. A clean rebuild was required once because MSVC reported the known
|
|
Debug PDB `LNK1103` corruption, after which the build passed.
|
|
- Focused new-document/session CTest coverage passed for
|
|
`pp_app_core_document_session_tests`, `pano_cli_plan_new_document_*`, and
|
|
`pano_cli_simulate_app_session_*` smoke tests after the live bridge split.
|
|
- `PanoPainter`, `pp_app_core_document_session_tests`, and `pano_cli` built
|
|
after accepted Save As and Save Version execution moved behind document
|
|
file/version save services. A clean rebuild was required once because MSVC
|
|
reported the known Debug PDB `LNK1103` corruption, after which the build
|
|
passed.
|
|
- Focused Save As/Version/session CTest coverage passed for
|
|
`pp_app_core_document_session_tests`, `pano_cli_plan_document_file_*`,
|
|
`pano_cli_plan_document_version_*`, and `pano_cli_simulate_app_session_*`
|
|
smoke tests after the live bridge split.
|
|
- `PanoPainter`, `pano_cli`, `pp_app_core_app_dialog_tests`, and
|
|
`pp_app_core_document_session_tests` built after close/save/workflow,
|
|
new-document overwrite, Save As overwrite, and save-error prompt metadata
|
|
moved into the pure document-session prompt catalog. A clean rebuild was
|
|
required once because MSVC reported the known Debug PDB `LNK1103`
|
|
corruption, after which the build passed.
|
|
- Focused document-session prompt CTest coverage passed for
|
|
`pp_app_core_app_dialog_tests`, `pp_app_core_document_session_tests`,
|
|
`pano_cli_plan_document_session_prompt_*`,
|
|
`pano_cli_plan_document_file_*`, `pano_cli_plan_new_document_*`, and
|
|
representative `pano_cli_simulate_app_session_*` smoke tests.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`,
|
|
`pp_app_core_app_dialog_tests`, and `pp_app_core_document_session_tests`
|
|
built after the same prompt-catalog change.
|
|
- `PanoPainter`, `pp_app_core_document_export_tests`, and `pano_cli` built
|
|
after equirectangular, layers, animation-frame, depth, and cube-face export
|
|
execution moved behind document export services. A clean rebuild was required
|
|
once because MSVC reported the known Debug PDB `LNK1103` corruption, after
|
|
which the build passed.
|
|
- Focused export CTest coverage passed for `pp_app_core_document_export_tests`,
|
|
`pano_cli_plan_export_start/menu/target_*`, and
|
|
`pano_cli_simulate_document_export_smoke` after the live bridge split.
|
|
- `PanoPainter`, `pp_app_core_document_export_tests`, and `pano_cli` built
|
|
after timelapse and animation MP4 export execution moved behind document
|
|
video export services. A clean rebuild was required once because MSVC
|
|
reported the known Debug PDB `LNK1103` corruption, after which the app,
|
|
export tests, and `pano_cli` targets built cleanly.
|
|
- Focused video export CTest coverage passed for
|
|
`pp_app_core_document_export_tests`, `pano_cli_plan_export_menu_*`,
|
|
`pano_cli_plan_export_target_name_smoke`, and
|
|
`pano_cli_simulate_document_export_smoke`.
|
|
- `PanoPainter`, `pp_app_core_app_preferences_tests`, and `pano_cli` built
|
|
after options-menu preference execution moved behind app preference services.
|
|
- Focused preference CTest coverage passed for
|
|
`pp_app_core_app_preferences_tests` and the app-preferences CLI smoke tests
|
|
after the live bridge split, including VR mode failed-start status coverage.
|
|
- `PanoPainter`, `pp_app_core_app_dialog_tests`, and `pano_cli` built after
|
|
progress/message/input dialog metadata moved into `pp_app_core` while live
|
|
`App` factories kept retained `Node*` creation.
|
|
- Focused app-dialog CTest coverage passed for
|
|
`pp_app_core_app_dialog_tests` and the `pano_cli_plan_app_dialog_*` smoke
|
|
tests, including negative progress-total clamping and rejected empty
|
|
input-dialog OK captions.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`, and
|
|
`pp_app_core_app_dialog_tests` built after the app-dialog planning slice.
|
|
- `PanoPainter`, `pp_app_core_app_dialog_tests`, and `pano_cli` built after
|
|
retained progress/message/input `Node*` creation moved into
|
|
`src/legacy_app_dialog_services.*`.
|
|
- Focused app-dialog CTest coverage passed again for
|
|
`pp_app_core_app_dialog_tests` and the `pano_cli_plan_app_dialog_*` smoke
|
|
tests after the legacy bridge split.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`, and
|
|
`pp_app_core_app_dialog_tests` built after the app-dialog bridge split.
|
|
- `PanoPainter`, `pp_app_core_document_session_tests`,
|
|
`pp_app_core_app_dialog_tests`, and `pano_cli` built after document-session
|
|
prompts moved onto `src/legacy_app_dialog_services.*`.
|
|
- Focused document-session/app-dialog CTest coverage passed for
|
|
`pp_app_core_document_session_tests`, `pp_app_core_app_dialog_tests`,
|
|
`pano_cli_plan_document_session_prompt_*`, `pano_cli_plan_app_dialog_*`, and
|
|
`pano_cli_simulate_app_session_*` after the document-session prompt bridge
|
|
split.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`,
|
|
`pp_app_core_document_session_tests`, and `pp_app_core_app_dialog_tests`
|
|
built after the document-session prompt bridge split.
|
|
- `PanoPainter`, `pp_app_core_app_startup_tests`, and `pano_cli` built after
|
|
startup preference/runtime execution and startup resource sequencing moved
|
|
behind app startup services.
|
|
- Focused startup CTest coverage passed for `pp_app_core_app_startup_tests`,
|
|
`pano_cli_plan_app_startup_smoke`, and
|
|
`pano_cli_plan_app_startup_rejects_negative_counter`, with startup resource
|
|
sequencing also covered by `pano_cli_plan_app_startup_resources_smoke` and
|
|
`pano_cli_plan_app_startup_resources_rejects_bad_size`.
|
|
- `PanoPainter`, `pp_app_core_app_frame_tests`, and `pano_cli` built after
|
|
app frame surface/update/tick/resize/draw-pass decisions moved into
|
|
`pp_app_core`.
|
|
- Focused frame CTest coverage passed for `pp_app_core_app_frame_tests`,
|
|
`pano_cli_plan_app_frame_vr_smoke`, and
|
|
`pano_cli_plan_app_frame_idle_missing_canvas_smoke`, with resize automation
|
|
covered by `pano_cli_plan_app_frame_resize_smoke` and
|
|
`pano_cli_plan_app_frame_rejects_bad_resize`. On 2026-06-05, UI observer
|
|
clipping/on-screen/scissor projection coverage was added through
|
|
`pp_app_core_app_frame_tests`, `pano_cli_plan_app_frame_observer_smoke`,
|
|
`pano_cli_plan_app_frame_observer_clipped_smoke`, and
|
|
`pano_cli_plan_app_frame_rejects_bad_observer`.
|
|
- `PanoPainter`, `pp_app_core_app_input_tests`, and `pano_cli` built after
|
|
app input routing and normalization moved into `pp_app_core`.
|
|
- Focused app-input CTest coverage passed for `pp_app_core_app_input_tests`,
|
|
`pano_cli_plan_app_input_pointer_smoke`,
|
|
`pano_cli_plan_app_input_gesture_smoke`,
|
|
`pano_cli_plan_app_input_key_vr_smoke`,
|
|
`pano_cli_plan_app_input_ui_toggle_smoke`,
|
|
`pano_cli_plan_app_input_stylus_smoke`,
|
|
`pano_cli_plan_app_input_rejects_bad_float`, and
|
|
`pano_cli_plan_app_input_rejects_missing_ui_panel`.
|
|
- `PanoPainter`, `pp_app_core_app_thread_tests`, and `pano_cli` built after
|
|
render/UI task dispatch, queue draining, UI-loop timer cadence, async redraw,
|
|
and start/stop decisions moved into `pp_app_core`.
|
|
- Focused app-thread CTest coverage passed for `pp_app_core_app_thread_tests`,
|
|
`pano_cli_plan_app_thread_dispatch_smoke`,
|
|
`pano_cli_plan_app_thread_ui_loop_smoke`,
|
|
`pano_cli_plan_app_thread_stop_smoke`, and
|
|
`pano_cli_plan_app_thread_rejects_bad_timer`.
|
|
- `PanoPainter`, `pp_app_core_app_shutdown_tests`, and `pano_cli` built after
|
|
shutdown cleanup staging moved into `pp_app_core`.
|
|
- Focused shutdown CTest coverage passed for `pp_app_core_app_shutdown_tests`,
|
|
`pano_cli_plan_app_shutdown_smoke`, and
|
|
`pano_cli_plan_app_shutdown_rejects_unknown_option`.
|
|
- `PanoPainter`, `pp_app_core_command_convert_tests`, and `pano_cli` built
|
|
after command-line panorama conversion planning moved into `pp_app_core`.
|
|
- Focused command-convert CTest coverage passed for
|
|
`pp_app_core_command_convert_tests`,
|
|
`pano_cli_plan_command_convert_smoke`,
|
|
`pano_cli_plan_command_convert_rejects_empty_project`, and
|
|
`pano_cli_plan_command_convert_rejects_bad_resolution`.
|
|
- `PanoPainter`, `pp_app_core_brush_package_export_tests`, and `pano_cli` built
|
|
after PPBR brush package export request validation and dispatch moved behind
|
|
app-core brush package services.
|
|
- Focused PPBR export CTest coverage passed for
|
|
`pp_app_core_brush_package_export_tests`,
|
|
`pano_cli_plan_brush_package_export_smoke`,
|
|
`pano_cli_plan_brush_package_export_rejects_empty_path`, and
|
|
`pano_cli_plan_brush_package_export_dest_without_data_smoke`.
|
|
- `PanoPainter`, `pp_app_core_brush_package_import_tests`, and `pano_cli` built
|
|
after ABR/PPBR brush package import execution moved behind app-core brush
|
|
import services.
|
|
- Focused brush import CTest coverage passed for
|
|
`pp_app_core_brush_package_import_tests`,
|
|
`pano_cli_plan_brush_package_import_ppbr_smoke`,
|
|
`pano_cli_plan_brush_package_import_abr_smoke`,
|
|
`pano_cli_plan_brush_package_import_rejects_empty_path`, and
|
|
`pano_cli_plan_brush_package_import_rejects_unknown_kind`.
|
|
- `PanoPainter`, `pp_assets_brush_package_tests`,
|
|
`pp_app_core_brush_package_export_tests`, and `pano_cli` built after PPBR
|
|
header validation and export path/data-directory planning moved into
|
|
`pp_assets`.
|
|
- Focused PPBR asset CTest coverage passed for `pp_assets_brush_package_tests`
|
|
and the brush package export CLI tests, including path-without-directory
|
|
rejection and legacy no-export-data data-directory planning.
|
|
- `PanoPainter`, `pp_assets_brush_package_tests`,
|
|
`pp_app_core_brush_package_import_tests`, and `pano_cli` built after ABR and
|
|
PPBR imported brush tip/pattern target paths moved into `pp_assets`.
|
|
- Focused brush import storage CTest coverage passed for
|
|
`pp_assets_brush_package_tests` and the brush package import/export CLI
|
|
smoke/failure tests.
|
|
- `PanoPainter`, `pp_app_core_brush_ui_tests`, and `pano_cli` built after brush
|
|
preset-list add/select/move/remove/clear planning moved into `pp_app_core`.
|
|
- Focused brush preset-list CTest coverage passed for
|
|
`pp_app_core_brush_ui_tests` and `pano_cli_plan_brush_preset_list_*` smoke
|
|
tests.
|
|
- `pp_app_core_document_recording_tests` passed, covering recording start/stop,
|
|
clear, platform recorded-file cleanup, frame-count reset, export progress
|
|
totals, oversized progress-total clamping, and recording-worker encode-wake
|
|
eligibility.
|
|
- `pano_cli_plan_recording_session_stopped_smoke`,
|
|
`pano_cli_plan_recording_session_running_smoke`, and
|
|
`pano_cli_plan_recording_session_platform_cleanup_smoke` passed and expose
|
|
app-core recording lifecycle/export decisions as JSON. On 2026-06-05,
|
|
`pano_cli_plan_recording_session_missing_encoder_smoke` was added for the
|
|
worker no-encode path.
|
|
- `PanoPainter`, `pp_app_core_document_recording_tests`,
|
|
`pp_app_core_app_dialog_tests`, and `pano_cli` built after MP4 recording
|
|
export progress-dialog metadata moved into `pp_app_core` and retained
|
|
progress bar creation routed through `src/legacy_app_dialog_services.*`.
|
|
- Focused recording/app-dialog CTest coverage passed for
|
|
`pp_app_core_document_recording_tests`, `pp_app_core_app_dialog_tests`,
|
|
`pano_cli_plan_recording_session_*`, and `pano_cli_plan_app_dialog_*`,
|
|
including the MP4 export progress-dialog metadata smoke.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`,
|
|
`pp_app_core_document_recording_tests`, and `pp_app_core_app_dialog_tests`
|
|
built after the recording progress bridge split.
|
|
- `pp_app_core_document_resize_tests` passed, covering resize dialog state,
|
|
unknown current-resolution labeling, selected-resolution mapping, square
|
|
canvas sizing, history-clearing intent, invalid selection rejection, service
|
|
dispatch order, optional history clearing, and invalid-dimension rejection.
|
|
- `pano_cli_plan_document_resize_smoke` and
|
|
`pano_cli_plan_document_resize_rejects_invalid_selection` passed and expose
|
|
live document-resize planning as JSON automation.
|
|
- `pp_app_core_document_layer_tests` passed, covering changed layer rename,
|
|
unchanged no-op rename, empty-name rejection, overlong-name rejection, rename
|
|
executor dispatch, no-op rename dialog finish, malformed rename-plan
|
|
rejection, layer add/duplicate/select/reorder/remove planning, metadata
|
|
planning, bad-index rejection, bad-opacity rejection, bad-blend-mode
|
|
rejection, transient highlight behavior, layer operation executor dispatch,
|
|
layer operation side-effect dispatch, no-op operation preservation,
|
|
malformed operation rejection, Layer menu labels/actions, merge-down routing,
|
|
animated merge blocking, missing selection handling, bad Layer menu state
|
|
rejection, Layer menu executor dispatch, no-op menu execution preservation,
|
|
merge-plan validation, unsupported animated merge rejection, merge executor
|
|
dispatch, and malformed merge-plan rejection.
|
|
- `pano_cli_plan_layer_rename_smoke`,
|
|
`pano_cli_plan_layer_rename_no_op_smoke`, and
|
|
`pano_cli_plan_layer_rename_rejects_empty_name` passed and expose live
|
|
layer-rename planning as JSON automation.
|
|
- `pano_cli_plan_layer_menu_merge_smoke`,
|
|
`pano_cli_plan_layer_menu_clear_smoke`,
|
|
`pano_cli_plan_layer_menu_merge_animated_blocked_smoke`,
|
|
`pano_cli_plan_layer_menu_missing_selection_smoke`, and
|
|
`pano_cli_plan_layer_menu_rejects_bad_state` passed and expose live Layer
|
|
menu planning as JSON automation.
|
|
- `pano_cli_plan_layer_merge_smoke` and
|
|
`pano_cli_plan_layer_merge_animated_rejected` passed and expose live
|
|
merge execution planning as JSON automation.
|
|
- `pano_cli_plan_layer_operation_add_smoke`,
|
|
`pano_cli_plan_layer_operation_reorder_no_op_smoke`,
|
|
`pano_cli_plan_layer_operation_highlight_smoke`, and
|
|
`pano_cli_plan_layer_operation_rejects_bad_opacity` passed and expose live
|
|
layer-panel operation planning as JSON automation.
|
|
- `pp_app_core_document_animation_tests` passed, covering animation frame
|
|
add/duplicate/remove planning, selected-frame rejection, last-frame remove
|
|
rejection, duration floor/overflow handling, timeline move edge behavior,
|
|
goto/next/previous wrapping, onion-size rejection, service dispatch ordering,
|
|
frame-click selection planning, no-reload playback step planning,
|
|
playback toggle start/stop planning, animation panel action planning,
|
|
invalid panel timeline state rejection, non-mutating duration no-ops, tested
|
|
onion-skin frame range/alpha falloff planning consumed by live `NodeCanvas`
|
|
panorama drawing, tested timeline mouse-scrub cursor-to-frame planning
|
|
consumed by live `NodeAnimationTimeline`, tested animation panel layer/frame
|
|
view-model projection consumed by live `NodePanelAnimation`, stale selected
|
|
frame preservation, and malformed execution payload rejection.
|
|
- `pano_cli_plan_animation_operation_add_smoke`,
|
|
`pano_cli_plan_animation_operation_duration_floor_smoke`,
|
|
`pano_cli_plan_animation_operation_next_wrap_smoke`,
|
|
`pano_cli_plan_animation_operation_select_smoke`,
|
|
`pano_cli_plan_animation_operation_playback_smoke`,
|
|
`pano_cli_plan_animation_operation_toggle_playback_start_smoke`,
|
|
`pano_cli_plan_animation_operation_toggle_playback_stop_smoke`,
|
|
`pano_cli_plan_animation_panel_action_next_smoke`,
|
|
`pano_cli_plan_animation_panel_action_toggle_stop_smoke`,
|
|
`pano_cli_plan_animation_panel_action_rejects_bad_timeline`,
|
|
`pano_cli_plan_animation_panel_view_smoke`,
|
|
`pano_cli_plan_animation_panel_view_allows_stale_selection`,
|
|
`pano_cli_plan_animation_panel_view_rejects_empty_frames`,
|
|
`pano_cli_plan_animation_timeline_scrub_smoke`,
|
|
`pano_cli_plan_animation_timeline_scrub_clamps_left`,
|
|
`pano_cli_plan_animation_timeline_scrub_rejects_bad_duration`,
|
|
`pano_cli_plan_animation_operation_rejects_remove_last_frame`, and
|
|
`pano_cli_plan_animation_operation_rejects_bad_selection` passed and expose
|
|
live animation-panel planning as JSON automation.
|
|
- `pp_app_core_brush_ui_tests` passed, covering brush color channel validation,
|
|
invalid color rejection, texture-path validation, preset-brush availability,
|
|
preserve-current-color intent, stroke-settings refresh intent, texture-list
|
|
add target path planning, user-texture removal intent, clamped reorder intent,
|
|
stroke-control slider/toggle/blend/reset planning, service dispatch ordering,
|
|
texture/preset/list/stroke-control execution payloads, execution failure
|
|
preservation, and invalid execution payload rejection.
|
|
- `pano_cli_plan_brush_operation_color_smoke`,
|
|
`pano_cli_plan_brush_operation_texture_smoke`,
|
|
`pano_cli_plan_brush_operation_preset_smoke`,
|
|
`pano_cli_plan_brush_operation_rejects_bad_color`, and
|
|
`pano_cli_plan_brush_operation_rejects_empty_texture` passed and expose live
|
|
brush/color/preset UI planning as JSON automation.
|
|
- `pano_cli_plan_brush_texture_list_add_smoke`,
|
|
`pano_cli_plan_brush_texture_list_remove_user_smoke`,
|
|
`pano_cli_plan_brush_texture_list_move_edge_smoke`, and
|
|
`pano_cli_plan_brush_texture_list_rejects_bad_source` passed and expose live
|
|
brush/pattern texture-list planning as JSON automation.
|
|
- `pano_cli_plan_brush_stroke_control_float_smoke`,
|
|
`pano_cli_plan_brush_stroke_control_toggle_smoke`,
|
|
`pano_cli_plan_brush_stroke_control_blend_smoke`,
|
|
`pano_cli_plan_brush_stroke_control_reset_smoke`,
|
|
`pano_cli_plan_brush_stroke_control_rejects_bad_setting`, and
|
|
`pano_cli_plan_brush_stroke_control_rejects_bad_blend` passed and expose live
|
|
stroke-panel slider/toggle/blend/reset planning as JSON automation.
|
|
- `pano_cli_plan_brush_stroke_panel_view_smoke`,
|
|
`pano_cli_plan_brush_stroke_panel_view_rejects_bad_float`, and
|
|
`pano_cli_plan_brush_stroke_panel_view_rejects_bad_blend` passed and expose
|
|
live stroke-panel state projection as JSON automation.
|
|
- `pp_app_core_grid_ui_tests` passed, covering heightmap pick/load/reload/clear
|
|
planning, lightmap capability and limit checks, missing-heightmap no-op
|
|
behavior, and commit canvas gating.
|
|
- `pano_cli_plan_grid_operation_pick_smoke`,
|
|
`pano_cli_plan_grid_operation_load_smoke`,
|
|
`pano_cli_plan_grid_operation_render_supported_smoke`,
|
|
`pano_cli_plan_grid_operation_render_unsupported_smoke`,
|
|
`pano_cli_plan_grid_operation_rejects_empty_reload`, and
|
|
`pano_cli_plan_grid_operation_rejects_bad_samples` passed and expose live
|
|
grid/heightmap/lightmap planning as JSON automation.
|
|
- `pp_app_core_canvas_tool_ui_tests` passed, covering toolbar mode selection,
|
|
copy/cut transform action planning, pick no-op outside draw mode, and
|
|
touch-lock toggling, full draw-toolbar binding projection, binding-to-action
|
|
conversion, plus toolbar active-state derivation for draw, copy, and bucket
|
|
modes, service dispatch ordering, pick no-op execution, and malformed
|
|
execution payload rejection.
|
|
- `pp_app_core_canvas_hotkey_tests` passed, covering E draw/erase toggles,
|
|
Ctrl+Z/Ctrl+Shift+Z history planning, Ctrl+S/Ctrl+Shift+S document save
|
|
intents, Tab UI toggles, brush-size brackets, Android back and two-finger
|
|
undo, no-op Ctrl-less Z, bad-count rejection, executor dispatch, and
|
|
malformed brush-size execution rejection.
|
|
- `pano_cli_plan_canvas_hotkey_ctrl_z_smoke`,
|
|
`pano_cli_plan_canvas_hotkey_save_dirty_version_smoke`,
|
|
`pano_cli_plan_canvas_hotkey_erase_smoke`,
|
|
`pano_cli_plan_canvas_hotkey_two_finger_undo_smoke`, and
|
|
`pano_cli_plan_canvas_hotkey_rejects_bad_count` passed and expose live
|
|
canvas keyboard/touch command planning as JSON automation.
|
|
- `pano_cli_plan_canvas_tool_draw_smoke`,
|
|
`pano_cli_plan_canvas_tool_copy_smoke`,
|
|
`pano_cli_plan_canvas_tool_pick_noop_smoke`,
|
|
`pano_cli_plan_canvas_tool_touch_lock_smoke`, and
|
|
`pano_cli_plan_canvas_tool_rejects_unknown` passed and expose live draw
|
|
toolbar planning as JSON automation.
|
|
- `pano_cli_plan_canvas_tool_toolbar_smoke` and
|
|
`pano_cli_plan_canvas_tool_toolbar_rejects_unknown` passed and expose the
|
|
full live draw-toolbar binding set as JSON automation.
|
|
- `pano_cli_plan_canvas_tool_state_draw_smoke`,
|
|
`pano_cli_plan_canvas_tool_state_copy_smoke`, and
|
|
`pano_cli_plan_canvas_tool_state_rejects_unknown` passed and expose draw
|
|
toolbar active-state refresh as JSON automation.
|
|
- `PanoPainter`, `pano_cli`, and `pp_app_core_canvas_tool_ui_tests` built on
|
|
Windows after `App::init_toolbar_draw()` moved to the app-core toolbar
|
|
binding plan; the build required the documented clean after a stale
|
|
debug-info `LNK1103`.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`, and
|
|
`pp_app_core_canvas_tool_ui_tests` built after the same toolbar binding
|
|
planner change.
|
|
- `pp_app_core_document_canvas_tests` passed, covering clear-current-layer
|
|
undo/dirty intent, no-canvas no-op behavior, and invalid clear color
|
|
rejection, service dispatch color forwarding, no-op execution preservation,
|
|
and invalid execution color rejection.
|
|
- `pano_cli_plan_canvas_clear_smoke`,
|
|
`pano_cli_plan_canvas_clear_no_canvas_smoke`, and
|
|
`pano_cli_plan_canvas_clear_rejects_bad_color` passed and expose toolbar
|
|
canvas clear planning as JSON automation.
|
|
- `pp_app_core_document_import_tests` passed, covering wide equirectangular,
|
|
legacy vertical cube strip, regular transform-placement, and invalid-dimension
|
|
import route decisions, equirectangular service dispatch, transform import
|
|
dispatch, empty-path rejection, and invalid execution dimension rejection.
|
|
- `pano_cli_plan_image_import_wide_equirect_smoke`,
|
|
`pano_cli_plan_image_import_transform_smoke`, and
|
|
`pano_cli_plan_image_import_rejects_invalid_dimensions` passed and expose File
|
|
> Import route planning as JSON automation.
|
|
- `pp_app_core_file_menu_tests` passed, covering top-level File menu routing for
|
|
creation/open/import, save intents, export/submenu/cloud actions, and unknown
|
|
command rejection, plus executor dispatch for dialog, picker, save, export,
|
|
share, resize, and cloud actions.
|
|
- `pano_cli_plan_file_menu_import_smoke`,
|
|
`pano_cli_plan_file_menu_save_as_smoke`,
|
|
`pano_cli_plan_file_menu_export_smoke`,
|
|
`pano_cli_plan_file_menu_cloud_upload_smoke`, and
|
|
`pano_cli_plan_file_menu_rejects_unknown` passed and expose top-level File
|
|
menu routing as JSON automation.
|
|
- `pp_app_core_document_export_tests` passed, now also covering export menu
|
|
dialog routing, demo-mode MP4/timelapse license gating, and missing-canvas
|
|
handling, plus export menu executor dispatch for all dialog, blocked, and
|
|
unavailable actions before legacy export dialogs continue.
|
|
- `pano_cli_plan_export_menu_png_smoke`,
|
|
`pano_cli_plan_export_menu_mp4_demo_blocked_smoke`,
|
|
`pano_cli_plan_export_menu_no_canvas_smoke`, and
|
|
`pano_cli_plan_export_menu_rejects_unknown` passed and expose File menu export
|
|
routing as JSON automation.
|
|
- `pp_app_core_history_ui_tests` passed, covering undo/redo availability,
|
|
no-op history commands, clear-history stack/memory state, memory-only clear,
|
|
negative metric rejection, service dispatch order, empty-history no-op
|
|
execution, and invalid execution metric rejection.
|
|
- `pano_cli_plan_history_operation_undo_smoke`,
|
|
`pano_cli_plan_history_operation_redo_empty_smoke`,
|
|
`pano_cli_plan_history_operation_clear_smoke`, and
|
|
`pano_cli_plan_history_operation_rejects_negative_count` passed and expose
|
|
toolbar/canvas history planning as JSON automation.
|
|
- `pp_app_core_quick_ui_tests` passed, covering quick brush/color slot
|
|
selection, active-slot popup decisions, invalid slot rejection, restore-state
|
|
validation, reset-state validation, service dispatch order, explicit
|
|
brush/color restore indices, and malformed execution payload rejection.
|
|
- `pano_cli_plan_quick_operation_select_brush_smoke`,
|
|
`pano_cli_plan_quick_operation_open_color_smoke`,
|
|
`pano_cli_plan_quick_operation_restore_smoke`,
|
|
`pano_cli_plan_quick_operation_reset_smoke`,
|
|
`pano_cli_plan_quick_operation_rejects_bad_slot`, and
|
|
`pano_cli_plan_quick_operation_rejects_bad_restore` passed and expose live
|
|
quick-panel planning as JSON automation.
|
|
- `pp_app_core_tools_menu_tests` passed, covering Tools submenu routing,
|
|
root-closing commands, platform-only SonarPen gating, executor dispatch,
|
|
unavailable no-op actions, floating panel chrome metadata, already-visible
|
|
panel no-ops, and animation panel non-droppable state.
|
|
- `pano_cli_plan_tools_menu_shortcuts_smoke`,
|
|
`pano_cli_plan_tools_menu_sonarpen_unavailable_smoke`,
|
|
`pano_cli_plan_tools_panel_layers_smoke`,
|
|
`pano_cli_plan_tools_panel_visible_noop_smoke`, and
|
|
`pano_cli_plan_tools_panel_rejects_unknown` passed and expose live Tools
|
|
menu/panel planning as JSON automation.
|
|
- `pp_app_core_about_menu_tests` passed, covering About/help/what's-new dialog
|
|
routing, versioned what's-new labels, crash diagnostic gating, performance
|
|
workload metadata, no-canvas performance-test blocking, dispatch through the
|
|
`AboutMenuServices` executor boundary, and no-op unavailable actions.
|
|
- `pano_cli_plan_about_menu_news_smoke`,
|
|
`pano_cli_plan_about_menu_performance_no_canvas_smoke`,
|
|
`pano_cli_plan_about_menu_crash_disabled_smoke`, and
|
|
`pano_cli_plan_about_menu_rejects_unknown` passed and expose live About menu
|
|
planning as JSON automation.
|
|
- `pp_app_core_main_toolbar_tests` passed, covering live toolbar/status direct
|
|
dialog routing, undo/redo availability, clear-history availability, no-canvas
|
|
clear blocking, negative history metric rejection, and dispatch through the
|
|
`MainToolbarServices` executor boundary without invoking no-op actions.
|
|
- `pano_cli_plan_main_toolbar_undo_smoke`,
|
|
`pano_cli_plan_main_toolbar_redo_empty_smoke`,
|
|
`pano_cli_plan_main_toolbar_clear_canvas_no_canvas_smoke`, and
|
|
`pano_cli_plan_main_toolbar_rejects_negative_count` passed and expose live
|
|
toolbar/status planning as JSON automation.
|
|
- `PanoPainter`, `pp_app_core_main_toolbar_tests`,
|
|
`pp_app_core_app_dialog_tests`, and `pano_cli` built after toolbar
|
|
test-message dialog metadata moved into `pp_app_core` and live message-box
|
|
creation routed through `src/legacy_app_dialog_services.*`.
|
|
- Focused main-toolbar/app-dialog CTest coverage passed for
|
|
`pp_app_core_main_toolbar_tests`, `pp_app_core_app_dialog_tests`,
|
|
`pano_cli_plan_main_toolbar_*`, and `pano_cli_plan_app_dialog_*`, including
|
|
the toolbar message-box dialog metadata smoke.
|
|
- Android arm64 headless `pp_app_core`, `pano_cli`,
|
|
`pp_app_core_main_toolbar_tests`, and `pp_app_core_app_dialog_tests` built
|
|
after the toolbar message-box bridge split.
|
|
- `pp_app_core_document_sharing_tests` passed, covering saved-path gating before
|
|
platform share execution.
|
|
- `pano_cli_plan_share_file_unsaved_smoke` and
|
|
`pano_cli_plan_share_file_saved_smoke` passed and expose app-core share
|
|
decisions as JSON.
|
|
- `pp_app_core_document_platform_io_tests` passed, covering empty selected-path
|
|
filtering and non-empty picked-path callback planning before platform picker
|
|
callbacks, plus empty/non-empty display-file planning before platform
|
|
display callbacks, plus virtual keyboard show/hide planning before platform
|
|
keyboard callbacks, plus cursor visibility planning before platform cursor
|
|
callbacks, plus clipboard read/write planning before platform clipboard
|
|
callbacks.
|
|
- `pano_cli_plan_picked_path_empty_smoke` and
|
|
`pano_cli_plan_picked_path_selected_smoke` passed and expose app-core picker
|
|
selected-path decisions as JSON.
|
|
- `pano_cli_plan_display_file_empty_smoke` and
|
|
`pano_cli_plan_display_file_selected_smoke` passed and expose app-core
|
|
display-file decisions as JSON.
|
|
- `pano_cli_plan_keyboard_visibility_hidden_smoke` and
|
|
`pano_cli_plan_keyboard_visibility_visible_smoke` passed and expose app-core
|
|
virtual keyboard decisions as JSON.
|
|
- `pano_cli_plan_cursor_visibility_hidden_smoke` and
|
|
`pano_cli_plan_cursor_visibility_visible_smoke` passed and expose app-core
|
|
cursor visibility decisions as JSON.
|
|
- `pano_cli_plan_clipboard_read_smoke`,
|
|
`pano_cli_plan_clipboard_write_smoke`, and
|
|
`pano_cli_plan_clipboard_write_empty_smoke` passed and expose app-core
|
|
clipboard decisions as JSON, including empty write text.
|
|
- `pp_platform_api_tests` passed, covering the SDK-free `PlatformServices`
|
|
interface for startup storage path preparation, clipboard read/write, empty
|
|
clipboard writes, cursor visibility dispatch, virtual-keyboard visibility
|
|
dispatch, external file display dispatch, file sharing dispatch, native
|
|
app/window close dispatch, UI-thread lifecycle dispatch, render-context
|
|
lifecycle dispatch, render-target binding dispatch, render platform hint
|
|
dispatch, render debug callback dispatch, render-capture frame hook dispatch,
|
|
recording cleanup dispatch, exported-image publish dispatch, persistent
|
|
storage flush dispatch, document browse-root dispatch,
|
|
working-directory picker policy and display-path formatting dispatch,
|
|
canvas input tip visibility and pressure remap dispatch,
|
|
native UI/window state save dispatch, prepared-file writable target dispatch,
|
|
prepared-file export-dialog policy dispatch, work-directory document export
|
|
collection policy dispatch, network TLS verification policy dispatch,
|
|
default network TLS policy coverage, PPBR export data-directory policy
|
|
dispatch, SonarPen availability/startup dispatch, VR lifecycle dispatch,
|
|
layout/asset file load policy coverage,
|
|
live asset/layout reload policy dispatch,
|
|
diagnostic hook dispatch, per-frame platform hook dispatch, picker callback
|
|
dispatch, and prepared-file save/download callback dispatch. The live Windows
|
|
app now
|
|
consumes this interface through an injected
|
|
`WindowsPlatformServices` instance isolated in
|
|
`src/platform_windows/windows_platform_services.*`; other platforms still
|
|
use the legacy fallback adapter, now isolated in
|
|
`src/platform_legacy/legacy_platform_services.*` instead of being owned by
|
|
`app_events.cpp`.
|
|
- `panopainter_validate_shaders` passed, validating 25 shader programs and 7
|
|
shader includes for stage markers and include graph integrity.
|
|
- `pp_renderer_gl_capabilities_tests` passed on default MSVC, vcpkg-headless,
|
|
and Android arm64 configure/build, covering framebuffer fetch, map-buffer
|
|
alignment, desktop GL core float support, GLES float/half-float extensions,
|
|
WebGL exclusion behavior, upload types for RGBA8/RGBA16F/RGBA32F internal
|
|
formats, image channel-count format mapping including invalid counts, and
|
|
RGBA8/RGBA32F readback format and byte-count mapping, PBO pixel-buffer
|
|
target/usage/access mapping, framebuffer status names, framebuffer blit color
|
|
mask and linear/nearest filters, plus Shape index-type and fill/stroke primitive mode mapping,
|
|
PanoPainter cube-face texture-target order, and the linear clamp-to-edge
|
|
render-target texture parameter set used by `RTT::create`.
|
|
Sampler parameter validation covers wrap S/T/R plus min/mag filter ordering
|
|
used by legacy `Sampler::set` and `Sampler::set_filter`, plus the desktop
|
|
border-color parameter name used by `Sampler::set_border`.
|
|
Legacy `TextureCube` allocation/bind/delete and `Sampler`
|
|
create/configure/border/bind/unbind paths now execute through tested
|
|
`pp_renderer_gl` dispatch contracts, keeping cube-map and sampler resource
|
|
lifecycle reachable without a live GL context.
|
|
Shader attribute binding catalog validation covers the current `pos`, `uvs`,
|
|
`uvs2`, `col`, and `nor` bindings and rejects empty, unnamed, null-name, and
|
|
duplicate-name catalogs while preserving legacy shared locations. Shader
|
|
uniform catalog validation covers the 43 legacy uniform
|
|
names used by `Shader`, preserves the legacy hash ids, and rejects empty,
|
|
unnamed, null-name, mismatched-hash, and duplicate-name catalogs.
|
|
Legacy `Shader` program use/delete, uniform writes, attribute-location
|
|
lookups, shader source compilation, shader deletion, program attach/link,
|
|
attribute rebinding, active-uniform count/enumeration, and uniform-location
|
|
discovery now execute through tested `pp_renderer_gl` dispatch contracts via
|
|
`legacy_gl_shader_dispatch`.
|
|
Retained `Shape`, `TextMesh`, and `NodeColorWheel` mesh buffer/VAO creation,
|
|
zero-byte dynamic-buffer creation, dynamic buffer uploads, indexed and
|
|
non-indexed draws, and resource deletion now execute through tested
|
|
`pp_renderer_gl` dispatch contracts via `legacy_gl_mesh_dispatch`.
|
|
- `pp_renderer_gl_command_plan_tests` covers the headless OpenGL command
|
|
planner for recorded render-pass clear masks/values, viewport/scissor state,
|
|
blend/depth/sampler state, texture format mapping, mesh/draw primitive modes,
|
|
draw counts, shader bind/uniform names and byte counts, texture
|
|
upload/mipmap/transition/copy/readback/capture metadata, blit filters and
|
|
byte totals, planned command names, unsupported enum/state rejection, whole
|
|
recorded stream planning, valid trace/render/shader/draw/blit ordering, typed
|
|
texture-command counts, broken render-pass order detection, and executable
|
|
draw/uniform dependency failures.
|
|
- PowerShell analyze automation returns JSON summaries and includes the shader
|
|
validation target and renderer-boundary guard.
|
|
- `windows-msvc-vcpkg-headless` configured through the Visual Studio bundled
|
|
vcpkg root, installed the manifest dependencies, built the headless component
|
|
matrix, and passed `desktop-fast-vcpkg`.
|
|
- `pp_ui_core` built and tested against vcpkg tinyxml2 on
|
|
`windows-msvc-vcpkg-headless` and against the vendored fallback on
|
|
`windows-msvc-default` and `android-arm64`.
|
|
- `windows-clangcl-asan` configures headlessly with clang-cl 18.1.8 and
|
|
release MSVC runtime selection; build remains blocked and debt-tracked in
|
|
DEBT-0014 because the selected VS 2026-preview STL requires Clang 20 or
|
|
newer.
|
|
- `PanoPainter.exe` built through CMake at
|
|
`out/build/windows-msvc-default/Debug/PanoPainter.exe`.
|
|
- PowerShell build/test automation wrappers return JSON summaries and passed
|
|
local smoke checks.
|
|
- Renderer-boundary automation fails if active non-backend source code
|
|
reintroduces raw `GL_*`/`WGL_*` constants outside the allowed legacy OpenGL
|
|
implementation files.
|
|
- `pp_renderer_api` now includes a headless `RecordingRenderDevice` with strict
|
|
renderer feature flags, renderer-owned resource factory and
|
|
command-order/render-pass-clear/scissor-state/depth-state/blend-state/
|
|
texture-usage/texture-bind/sampler-bind/shader-uniform/texture-upload/
|
|
mipmap-generation/texture-transition/readback/frame-capture/blit validation plus explicit draw
|
|
descriptor and texture-copy validation; it creates validated textures,
|
|
render targets, shaders, meshes, and readback buffers with validated debug
|
|
labels, then records commands, trace markers/scopes, render-pass
|
|
color/depth/stencil clear intent, scissor state, depth state, blend state,
|
|
shader uniform writes, texture/sampler binds, draw mesh inputs, explicit draw
|
|
ranges, texture uploads/mipmap generations/state transitions/copies/readbacks, frame captures,
|
|
and render-target blits, giving automation a backend-neutral render path that
|
|
does not require a window or GL context. Clearing the recording device now
|
|
resets active render-pass and trace-scope state so interrupted automation can
|
|
reuse a recorder without carrying stale frame state forward.
|
|
- `pano_cli record-render` exercises that headless recording renderer and emits
|
|
JSON command counts, backend feature flags, resource creation counts, target dimensions, backend
|
|
name, trace marker/scope and draw summary, labeled descriptor counts,
|
|
render-pass/depth-clear counts, and draw
|
|
descriptor vertex/index totals, scissor/depth/blend-state plus
|
|
shader-uniform/texture/sampler-bind/upload/mipmap-generation/texture-transition/texture-copy/readback/
|
|
frame-capture/blit command/byte totals for agent automation. When
|
|
`pp_renderer_gl` is available, it also emits an `openGlPlan` JSON object with
|
|
planned command count, support status, render-pass/draw/shader-bind/uniform/
|
|
texture-upload/mipmap/transition/copy/readback/capture/passthrough/trace
|
|
counts, unsupported command count, render-pass order error count, dependency
|
|
error count, and unclosed-pass state. The
|
|
`--exercise-clear` mode deliberately clears an interrupted trace/render pass,
|
|
verifies stale trace-scope state is rejected, verifies the render context can
|
|
be reused, and then emits that reset status in JSON. It also has an
|
|
expected-failure smoke for oversized render/readback targets.
|
|
- `pano_cli simulate-document-history` exercises pure document history
|
|
apply/undo/redo behavior and emits JSON layer/frame/history state for agent
|
|
automation.
|
|
- `pano_cli simulate-document-edits` exercises pure document layer/frame edit
|
|
operations and emits JSON metadata, frame order, face-payload state, and
|
|
selection-mask state for agent automation.
|
|
- `pano_cli simulate-image-import` exercises embedded PNG decode through
|
|
`pp_assets` and `pp_document` face-payload attachment through JSON
|
|
automation.
|
|
- `pano_cli import-image` accepts a PNG file path, decodes RGBA8 pixels through
|
|
`pp_assets`, attaches them to a pure `pp_document` face payload, and has
|
|
checked-in decodable-PNG plus truncated-PNG rejection smoke tests.
|
|
- `pano_cli export-image` writes deterministic RGBA8 PNGs through `pp_assets`
|
|
and has a save/import round-trip smoke test. Full legacy canvas export
|
|
remains a future `pano_cli` task.
|
|
- `pano_cli save-project` exposes generated multi-layer, multi-frame PPI
|
|
writing with layer metadata and targeted dirty-face layer/frame payloads
|
|
through JSON automation and is covered by metadata-only and
|
|
dirty-face-payload save/load round-trip smoke tests. Full legacy canvas save
|
|
parity remains tracked by DEBT-0013.
|
|
- `pp_assets::create_ppi_project` exposes the underlying generated PPI writer
|
|
for non-uniform layer metadata and frame-duration extraction work.
|
|
- `pp_document::export_ppi_project_document` exposes pure document-to-PPI byte
|
|
export through CTest coverage; legacy Canvas save integration remains tracked
|
|
by DEBT-0010/DEBT-0013.
|
|
- `pano_cli simulate-document-export` exposes the same export path through JSON
|
|
automation for agents.
|
|
- `pano_cli save-document-project` exposes file-writing document export
|
|
automation for inspect/load round trips.
|
|
- `pano_cli apply-stroke-script` exposes file-driven stroke-script application
|
|
to a pure document face payload and writes a PPI artifact for inspect/load
|
|
round-trip automation.
|
|
- Snapshot creation now rejects invalid embedded RGBA8 face payloads before
|
|
document export or history can persist malformed state.
|
|
- Package-smoke wrappers validate the Windows CMake app executable/runtime
|
|
`data/` copy and report structured package readiness for AppX, Android
|
|
standard/Quest/Focus APKs, Apple bundles, Linux app output, and WebGL
|
|
outputs. Actual package building remains blocked by DEBT-0011 until those
|
|
targets are migrated to root CMake. Readiness-only mode now reports the same
|
|
matrix without building the app first, and the package readiness self-test
|
|
keeps wrapper package kinds, retained Linux/WebGL CMake metadata, and blocker
|
|
metadata aligned. Root CMake target
|
|
`panopainter_linux_webgl_package_readiness` now exposes the filtered retained
|
|
Linux/WebGL readiness matrix from the CMake target graph.
|
|
- Android standard arm64/x64, Quest arm64, and Focus/Wave arm64 configure
|
|
through the platform-build wrapper by default. Focused validation compiled
|
|
representative headless component/tool targets across all four presets, and
|
|
the full refreshed component/test matrix remains the default gate for local
|
|
platform sweeps. The retained Android standard package CMake path also now
|
|
configures/builds `native-lib` directly for arm64 using C++23 and the shared
|
|
modern component source set, while Quest and Focus package CMake paths
|
|
configure with the same compatibility helper and current Yoga source list.
|
|
The Android platform-build wrapper and retained package helper now query
|
|
`sdkmanager`, install newer/missing SDK Manager NDK/CMake packages when
|
|
needed, select that pair automatically, and report the selected versions plus
|
|
update decisions in their structured output. `package-smoke.ps1
|
|
-ReadinessOnly -AndroidNativeChecks -PackageKinds
|
|
android-standard-apk,android-quest-apk,android-focus-apk` now runs those
|
|
retained native checks from the package-smoke surface while keeping APK
|
|
readiness blocked on root CMake package-target migration. Root CMake now has
|
|
named package validation targets for that same retained Android native gate;
|
|
`cmake --build --preset windows-msvc-default --config Debug --target
|
|
panopainter_android_native_package_smoke` validates the latest SDK-managed
|
|
NDK/CMake pair and reports the still-blocked APK package state.
|
|
- The Windows app artifact package smoke is also reachable from root CMake via
|
|
`cmake --build --preset windows-msvc-default --config Debug --target
|
|
panopainter_windows_app_package_smoke`, which builds the CMake `PanoPainter`
|
|
app target, validates the executable/runtime `data/` copy, and reports the
|
|
still-blocked Windows AppX package state.
|
|
- Retained Linux and WebGL app CMake files now use CMake 3.10 and target-level
|
|
C++23 instead of global C++14 flags; `python
|
|
scripts/dev/check_retained_platform_cmake.py` and CTest
|
|
`panopainter_retained_platform_cmake_self_test` guard those baselines while
|
|
the actual Linux/WebGL app/package targets remain outside root CMake.
|
|
- Root CMake now exposes platform validation targets for the default headless
|
|
platform-build sweep, the Android standard/Quest/Focus root CMake asset
|
|
component sweep, the vcpkg-backed UI core dependency boundary, and the
|
|
remote Apple compile gate. `cmake --build --preset windows-msvc-default
|
|
--config Debug --target panopainter_platform_build_android_assets` validated
|
|
`pp_assets` across Android arm64, Android x64, Quest arm64, and Focus/Wave
|
|
arm64 with the latest SDK-managed NDK/CMake pair; `cmake --build --preset
|
|
windows-msvc-default --config Debug --target
|
|
panopainter_platform_build_vcpkg_ui_core` validated `pp_ui_core` and
|
|
`pp_ui_core_layout_xml_tests` through the vcpkg tinyxml2 preset.
|
|
- Desktop VR drawing now routes generic OpenGL scissor/depth/blend state,
|
|
blend/depth state snapshots and restores, depth clears, active texture units,
|
|
and fallback 2D texture unbinds through tested renderer GL backend dispatch;
|
|
platform VR SDK bridges remain isolated for later platform-shell extraction.
|
|
Eye framebuffer viewport execution in the retained HMD path also routes
|
|
through tested `pp_renderer_gl` viewport dispatch.
|
|
- Canvas mode overlay, mask, and transform paths now route generic OpenGL
|
|
blend/depth state execution, active texture unit switches, transform/cut
|
|
viewport execution, 2D framebuffer-to-texture copy dispatch, RGBA8 readback
|
|
formats, and RTT-backed transform history region readbacks through the
|
|
renderer GL backend mapping. Canvas-tip pick readback now routes through the
|
|
tested framebuffer readback dispatch using the active read framebuffer, with
|
|
only local OpenGL adapter endpoints retained in `src/canvas_modes.cpp`.
|
|
Paint-mode blend/depth state snapshots also use tested capability-state query
|
|
dispatch.
|
|
- `NodeCanvas` panorama UI rendering now routes sampler defaults, saved
|
|
viewport/clear/blend/depth/scissor state, tested viewport and clear-color
|
|
query dispatch, color clears, clear-color restore, active texture units,
|
|
fallback 2D texture unbinds, 2D framebuffer-to-texture copy dispatch, and
|
|
RGBA8 render-target formats through the renderer GL backend mapping.
|
|
Its live viewport, generic blend/depth/scissor capability changes, and
|
|
density/offscreen color-buffer clears now execute through tested
|
|
`pp_renderer_gl` dispatch adapters, and its saved blend/depth/scissor state
|
|
queries now use tested capability-state query dispatch.
|
|
- Canvas resource setup now routes stroke-buffer RGBA8/RGBA16F/RGBA32F
|
|
formats, flood-fill texture upload format/type, brush/stencil/mix sampler
|
|
filters and wraps, and cube-strip import channel formats through the renderer
|
|
GL backend mapping. The clamp-to-border sampler wrap is now cataloged and
|
|
tested in `pp_renderer_gl`.
|
|
- Early canvas draw helpers now route pick readbacks, stroke mixer depth/scissor
|
|
and blend state, saved viewport/clear-state queries, active texture units,
|
|
fallback 2D texture unbinds, and stroke background copy targets through the
|
|
renderer GL backend mapping. Stroke mixer viewport/scissor execution also
|
|
routes through the tested backend dispatch contract.
|
|
- Canvas stroke commit now routes saved viewport/clear/blend state, history
|
|
readbacks, active texture units, fallback 2D texture unbinds, and layer
|
|
compositing copy targets through the renderer GL backend mapping; the
|
|
RTT-backed dirty-region readbacks now execute through the retained `RTT`
|
|
region-readback helper rather than direct `glReadPixels`, and 2D framebuffer
|
|
copies now execute through the retained utility bridge instead of direct
|
|
`glCopyTexSubImage2D`.
|
|
- Canvas layer merge rendering and explicit layer-merge compositing now route
|
|
depth/blend state, active texture units, fallback 2D texture unbinds, and
|
|
merge framebuffer copy targets through the renderer GL backend mapping.
|
|
- Canvas layer cube/equirect generation and frame clears now share
|
|
`legacy_ui_gl_dispatch` for active-texture selection, cube texture binding,
|
|
viewport execution, blend capability execution, clear-color query/restore,
|
|
and color-buffer clear adapter endpoints backed by tested renderer GL
|
|
backend dispatch contracts. The cube-face framebuffer-to-texture copy now
|
|
uses the shared retained target-aware utility bridge and remains tracked by
|
|
DEBT-0036 until renderer services own copy execution.
|
|
- `NodePanelGrid` live heightmap drawing and bake setup now route depth/blend
|
|
state, depth clears, color-write-mask toggles, active texture selection, and
|
|
bake viewport execution through tested renderer GL backend dispatch
|
|
contracts. Its desktop texture-resize readback now uses the retained
|
|
`Texture2D::get_image()` helper, so it consumes the same tested
|
|
framebuffer-backed texture readback dispatch instead of `glGetTexImage`.
|
|
Grid depth-state and viewport snapshots now also use tested backend query
|
|
dispatch.
|
|
- 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 clear, and clear-color restore. This covers
|
|
`NodeBorder`, `NodeImage`, `NodeImageTexture`, `NodeColorWheel`,
|
|
`NodeAnimationTimeline`, `NodeScroll`, `NodeText`, `NodeTextInput`, and
|
|
`NodeViewport` without changing their legacy draw ordering.
|
|
- Retained paint UI surface paths now use tested `pp_renderer_gl` viewport
|
|
query, clear-color query, clear-color restore, and color-buffer clear helpers
|
|
in `NodeCanvas` and `NodeStrokePreview`, removing direct query/clear calls
|
|
from those draw bodies while keeping their legacy compositing order. Their
|
|
active-texture, fallback texture unbind, viewport/scissor, clear-color,
|
|
color-buffer clear, and capability query/apply adapter endpoints are now
|
|
centralized in `legacy_ui_gl_dispatch` instead of being duplicated in each
|
|
node implementation.
|
|
- Retained Canvas stroke draw/commit, thumbnail, object-render, and
|
|
`LayerFrame::clear` paths now use the same tested backend viewport query,
|
|
clear-color query, and clear-color restore helpers, removing direct
|
|
viewport/clear-state queries from `src/canvas.cpp` and the frame clear path.
|
|
Their active-texture selection, fallback 2D texture unbind, viewport/scissor
|
|
execution, clear-color restore, and capability query/apply adapter endpoints
|
|
now share `legacy_ui_gl_dispatch`.
|
|
- Retained Canvas and RTT depth renderbuffer allocation, framebuffer depth
|
|
attachment, and renderbuffer deletion now share
|
|
`legacy_gl_renderbuffer_dispatch`, removing duplicated raw renderbuffer
|
|
callbacks from `src/canvas.cpp` and `src/rtt.cpp` while resource lifetime
|
|
ownership remains open under DEBT-0036.
|
|
- Retained `Texture2D`, `TextureCube`, and RTT texture allocation, deletion,
|
|
binding, parameter setup, 2D update, and mipmap dispatch now share
|
|
`legacy_gl_texture_dispatch`, removing duplicated raw texture callbacks from
|
|
`src/texture.cpp` and `src/rtt.cpp` while texture resource ownership remains
|
|
retained under DEBT-0036.
|
|
- Retained `Texture2D` readback plus RTT framebuffer allocation, deletion,
|
|
bind/restore, blit, readback, and PBO readback dispatch now share
|
|
`legacy_gl_framebuffer_dispatch`, removing duplicated raw framebuffer and
|
|
readback callbacks from `src/texture.cpp` and `src/rtt.cpp` while
|
|
framebuffer/readback ownership remains retained under DEBT-0036.
|
|
- Retained `Sampler` create, parameter, border-color, bind, and unbind dispatch
|
|
now share `legacy_gl_sampler_dispatch`, and retained `PBO` allocation,
|
|
framebuffer readback, map, unmap, and delete dispatch now share
|
|
`legacy_gl_pixel_buffer_dispatch`; this removes another pair of raw resource
|
|
callback clusters from `src/texture.cpp` and `src/rtt.cpp` while sampler and
|
|
pixel-buffer ownership remain retained under DEBT-0036.
|
|
- Retained `Shape`, `TextMesh`, and `NodeColorWheel` mesh buffer/VAO creation,
|
|
dynamic vertex/index uploads, fill/stroke/text draws, and buffer/VAO deletion
|
|
now share `legacy_gl_mesh_dispatch`, removing duplicated raw mesh callback
|
|
clusters from `src/shape.cpp`, `src/font.cpp`, and `src/node_colorwheel.cpp`
|
|
while mesh resource ownership remains retained under DEBT-0036.
|
|
- Retained shader source compilation/deletion, program attach/link/use/delete,
|
|
attribute rebinding and location lookup, active-uniform enumeration,
|
|
uniform-location discovery, and vec/mat/scalar uniform writes now share
|
|
`legacy_gl_shader_dispatch`, removing duplicated raw shader/program/uniform
|
|
callback ownership from `src/shader.cpp` while shader-program ownership
|
|
remains retained under DEBT-0036.
|
|
- Retained `gl_state` save/restore and `copy_framebuffer_to_texture_target`
|
|
now reuse `legacy_ui_gl_dispatch`, `legacy_gl_framebuffer_dispatch`,
|
|
`legacy_gl_shader_dispatch`, and `legacy_gl_sampler_dispatch`, removing the
|
|
local raw state/copy callback cluster from `src/util.cpp` while renderer
|
|
state and framebuffer-copy execution remain retained under DEBT-0036.
|
|
- Retained app startup, app clear, app UI viewport/scissor, command-convert
|
|
renderer state, and desktop VR draw-state endpoints now share
|
|
`legacy_ui_gl_dispatch` for capability, blend equation, clear, viewport,
|
|
scissor, active-texture, and 2D texture-unbind callbacks, removing duplicated
|
|
local raw callback clusters from `src/app.cpp`, `src/app_commands.cpp`, and
|
|
`src/app_vr.cpp` while app/VR renderer execution remains retained under
|
|
DEBT-0036.
|
|
- Retained RTT clear and masked-clear endpoints now share
|
|
`legacy_ui_gl_dispatch` for boolean color-mask query, color-mask apply,
|
|
clear-color, and buffer-clear callbacks, removing the local raw clear
|
|
callback cluster from `src/rtt.cpp` while RTT render-target execution remains
|
|
retained under DEBT-0036.
|
|
- Retained app startup logging, Windows early context logging/window-title
|
|
detection, and shader capability detection now share
|
|
`legacy_gl_runtime_dispatch` for runtime string and extension enumeration
|
|
callbacks, removing duplicated raw runtime-query clusters from `src/app.cpp`,
|
|
`src/main.cpp`, and `src/app_shaders.cpp` while runtime/capability probing
|
|
remains retained under DEBT-0036.
|
|
- Canvas draw-merge shader-blend selection now consumes the extracted
|
|
`pp_paint_renderer` stroke composite planner for current layer and primary
|
|
brush blend modes, while preserving legacy OpenGL compositing execution under
|
|
DEBT-0036.
|
|
- `NodeCanvas` panorama rendering now consumes the same tested
|
|
`pp_paint_renderer` canvas blend-gate planner as `Canvas::draw_merge`, so
|
|
layer and primary-brush blend-trigger compatibility is centralized.
|
|
- Shader initialization now publishes the OpenGL backend's renderer-neutral
|
|
feature snapshot through the legacy shader manager, and live canvas blend
|
|
gates consume that `RenderDeviceFeatures` value instead of hand-built
|
|
framebuffer-fetch/texture-copy flags.
|
|
- Canvas draw-merge and `NodeCanvas` panorama shader-blend paths now use the
|
|
shared canvas blend-gate plan to decide whether they can read destination
|
|
color through framebuffer fetch or must copy the destination texture before
|
|
the legacy OpenGL blend draw.
|
|
- Canvas main-brush, dual-brush, and stroke-pad draw paths now use the tested
|
|
`pp_paint_renderer` stroke-feedback plan to decide whether framebuffer fetch
|
|
supplies destination color or the legacy OpenGL path must copy the target
|
|
texture before drawing.
|
|
- Canvas thumbnail layer blending now uses the same canvas destination-feedback
|
|
plan for framebuffer-fetch versus texture-copy decisions; the thumbnail draw
|
|
itself still executes through retained OpenGL canvas code under DEBT-0036.
|
|
- Canvas equirectangular import drawing and depth export rendering now route
|
|
depth/blend state and active texture units through the renderer GL backend
|
|
mapping.
|
|
- Canvas thumbnail generation and object-drawing helpers now route saved
|
|
viewport/clear/blend state, active texture units, readback format/type,
|
|
framebuffer copy targets, and depth renderbuffer allocation plus framebuffer
|
|
depth attach/detach through tested renderer GL backend dispatch contracts;
|
|
`src/canvas.cpp` no longer owns raw renderbuffer callbacks.
|
|
- Retained Canvas, NodeCanvas, NodeStrokePreview, and HMD viewport/scissor/
|
|
capability execution now compiles through the renderer GL backend dispatch
|
|
adapters with `pp_legacy_paint_document`, `pp_panopainter_ui`, and
|
|
`panopainter_app`. CanvasMode overlay, mask, transform, and canvas-tip pick
|
|
paths now also consume the shared retained UI GL dispatch for active-texture,
|
|
capability query/apply, viewport, read-framebuffer query, and RGBA8 pixel
|
|
readback adapter endpoints, removing another local raw-GL adapter cluster
|
|
from `src/canvas_modes.cpp`. `NodePanelGrid` heightmap draw and bake setup
|
|
now uses the same bridge for active-texture, depth/blend capability
|
|
query/apply, viewport query/execution, depth clears, and color-write-mask
|
|
adapter endpoints instead of owning another local dispatch cluster.
|
|
- Windows desktop OpenGL context creation now consumes a tested
|
|
`windows_wgl_core_context_3_3_config()` catalog from `pp_renderer_gl`, moving
|
|
the active WGL context/pixel-format attribute literals out of the platform
|
|
entrypoint.
|
|
- Known remaining warnings: legacy project/vendor diagnostics, Visual Studio
|
|
vcpkg-manifest warning, `LNK4099` missing libyuv PDBs, and `LNK4098` runtime
|
|
library conflict from retained vendor binaries.
|
|
|
|
## Current Debt Log
|
|
|
|
The canonical debt log is now `docs/modernization/debt.md`. Keep this section
|
|
as a reminder only; do not add new debt entries here.
|
|
|
|
| ID | Status | Owner | Item | Reason | Validation | Removal Condition |
|
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
| DEBT-0001 | Open | TBD | Existing platform build files remain alongside new CMake | Required for incremental migration | Existing platform builds plus new CMake configure | Remove after all platform builds consume shared CMake targets |
|
|
| DEBT-0002 | Open | TBD | Vendored SDK and patched libraries retained initially | Some dependencies are SDK-only or have platform-specific binaries | Dependency inventory and platform build smoke tests | Replace or document permanent vendored status after vcpkg triplet evaluation |
|
|
| DEBT-0003 | Open | TBD | Existing singletons remain during initial split | Avoid behavior changes while introducing boundaries | App launch and component tests | Replace singleton reaches with context/service injection at component boundaries |
|
|
|
|
## Current Capability Map Seed
|
|
|
|
Use this as the starting checklist for Phase 0 inventory.
|
|
|
|
- Project I/O: PPI open/save, thumbnails, version metadata, autosave/save-as
|
|
flows.
|
|
- Image I/O: JPEG/PNG import/export, cube faces, equirectangular export,
|
|
depth export.
|
|
- Brush system: ABR import, PPBR import/export, presets, tip/pattern/dual brush,
|
|
pressure, jitter, blend modes.
|
|
- Painting: six cube faces, temporary stroke buffers, erase, flood fill, masks,
|
|
alpha lock, layer compositing.
|
|
- Layers and animation: layer add/remove/move/merge, blend/opacity/visibility,
|
|
frame add/remove/duplicate/duration, MP4/timelapse export.
|
|
- UI: XML layout, Yoga layout, panels, dialogs, color tools, brush tools,
|
|
layers, animation timeline, settings, shortcuts, manual/changelog/about.
|
|
- Input: mouse, keyboard, touch, gestures, Wacom tablet, stylus pressure,
|
|
VR controllers.
|
|
- Platform services: clipboard, file picker, save picker, directory picker,
|
|
share/display file, keyboard show/hide, cursor visibility.
|
|
- VR/platform variants: OpenXR desktop target with retained OpenVR fallback,
|
|
Quest, Focus/Wave, Android standard,
|
|
iOS/macOS, Linux, WebGL.
|
|
- Cloud/network: upload, download, browse, license/check flows.
|
|
- Recording/export: PBO readbacks, MP4 encoder, timelapse frames.
|