Files
panopainter/docs/modernization/roadmap.md

35 KiB

PanoPainter Modernization Roadmap

Status: live Last updated: 2026-06-02

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 Not 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:

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_*: 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. 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.

Implementation tasks:

  • Set C++23 through target features, not raw compiler flags.
  • Add warning profiles:
    • MSVC: /W4 /permissive- /Zc:__cplusplus /Zc:preprocessor.
    • Optional MSVC analysis preset: /analyze.
    • Clang/GCC: -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Wnull-dereference.
  • 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
    • 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.
  • No global blanket warning suppression for project code.

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 runs headlessly, and PowerShell/bash wrappers exist for configure/build/test/analyze/platform-build/package-smoke. pano_cli exists with JSON automation commands for 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.

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 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, 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 shader blend modes, and deterministic stroke spacing/interpolation 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, PPI image import, and layer/frame/undo-redo history invariant tests. 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. 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 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. pano_cli create-document can create simple animation documents with explicit frame count/duration, and 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 parse-layout exercises the XML layout path. Continue expanding document behavior toward legacy Canvas parity and then port OpenGL classes behind the renderer boundary.

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_*
    11. 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 texture descriptor, byte-size, viewport, mesh, readback bounds, command context, render device, shader program descriptor, mesh, render target, readback, trace interface 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. Texture2D 2D texture binding, upload, mipmap generation, framebuffer readback setup, and update component-type tokens now delegate to pp_renderer_gl. 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, byte-count math, and PBO pixel-buffer target/usage/access tokens used by RTT and PBO readbacks now live in pp_renderer_gl. The framebuffer blit color mask and linear/nearest filter tokens used by RTT::resize and RTT::copy, plus the default render-target texture parameters, texture/renderbuffer targets, depth format, framebuffer targets, binding queries, attachment points, and completion status used by RTT::create and framebuffer bind/restore paths, also live in pp_renderer_gl. RTT clear color/depth masks and color-write-mask query tokens also live in pp_renderer_gl. RTT no longer spells GL enum names directly. 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. 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. 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. 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, 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 and resize path consume 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; Font no longer spells GL enum names directly. Canvas undo/redo dirty-region texture updates and readbacks now also delegate their 2D texture target, RGBA pixel format, and unsigned-byte component type mapping to pp_renderer_gl. NodeViewport preview rendering now also delegates viewport query, clear-color query, color-buffer clear mask, and blend-state tokens to pp_renderer_gl. NodeImageTexture preview drawing now delegates its fallback 2D texture bind target and blend-state tokens to pp_renderer_gl. NodeImage drawing and remote-image texture creation now delegate mipmapped sampler filters, blend-state tokens, 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 tokens to pp_renderer_gl. Simple UI text, text-input, border, scroll, and animation timeline draw paths now also delegate blend-state tokens to pp_renderer_gl. Canvas layer cube/equirect generation, clear, restore, and snapshot paths now also delegate cube/2D texture targets, active texture units, blend/clear state, and RGBA8 read/write pixel mapping to pp_renderer_gl. 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. Legacy util.cpp OpenGL error naming and gl_state save/restore now delegate error codes, state queries, framebuffer targets, texture binding targets, and active texture units to pp_renderer_gl. NodeStrokePreview brush preview rendering now delegates depth/scissor/blend state, viewport/clear-color queries, active texture units, 2D texture targets, copy targets, and sampler filters/wraps to pp_renderer_gl. 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 and info-string tokens to pp_renderer_gl; WGL context/pixel-format constants remain in the platform shell for a later platform-boundary slice. 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 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.

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 Parser and serializer fuzzing Fuzzer-capable compiler
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:

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_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
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
cmake --fresh --preset windows-clangcl-asan

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, dirty-face PNG payload metadata validation, 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, 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_renderer_api_tests passed, including shader descriptor validation, PanoPainter shader catalog validation, and invalid catalog rejection.
  • pp_paint_renderer_compositor_tests passed.
  • 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_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_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_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.
  • 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. 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.
  • PowerShell analyze automation returns JSON summaries and includes the shader validation target.
  • 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.
  • PowerShell package-smoke wrapper validates the Windows CMake app executable and runtime data/ copy.
  • Android arm64 configured with NDK 29.0.14206865 through the platform-build wrapper and compiled headless foundation/tool/test targets.
  • Desktop VR drawing now routes generic OpenGL scissor/depth/blend state, depth clears, active texture units, and fallback 2D texture unbinds through the renderer GL backend mapping; platform VR SDK bridges remain isolated for later platform-shell extraction.
  • Canvas mode overlay, mask, and transform paths now route generic OpenGL blend/depth state, active texture units, 2D copy targets, and RGBA8 readback formats through the renderer GL backend mapping.
  • NodeCanvas panorama UI rendering now routes sampler defaults, saved viewport/clear/blend/depth/scissor state, color clears, active texture units, fallback 2D texture unbinds, copy targets, and RGBA8 render-target formats through the renderer GL backend mapping.
  • 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.
  • 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.
  • VR/platform variants: OpenVR desktop, 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.