From 5f76716732a31a6e4a4851dee7fc53c626f7f0b5 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 16 Jun 2026 22:40:17 +0200 Subject: [PATCH] Extract app runtime tail, canvas camera shell, and preview sample services --- cmake/PanoPainterSources.cmake | 3 + docs/modernization/roadmap.md | 22 +++- docs/modernization/tasks.md | 14 +++ src/app.cpp | 69 ---------- src/canvas.cpp | 35 ------ src/legacy_app_runtime_shell_services.cpp | 69 ++++++++++ src/legacy_canvas_camera_services.cpp | 40 ++++++ ...cy_node_stroke_preview_sample_services.cpp | 60 +++++++++ ...gacy_node_stroke_preview_sample_services.h | 28 +++++ src/node_stroke_preview.cpp | 118 +++++------------- 10 files changed, 259 insertions(+), 199 deletions(-) create mode 100644 src/legacy_canvas_camera_services.cpp create mode 100644 src/legacy_node_stroke_preview_sample_services.cpp create mode 100644 src/legacy_node_stroke_preview_sample_services.h diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index 61c8304e..0d33cab0 100644 --- a/cmake/PanoPainterSources.cmake +++ b/cmake/PanoPainterSources.cmake @@ -32,6 +32,7 @@ set(PP_LEGACY_PAINT_DOCUMENT_SOURCES src/legacy_canvas_document_io_services.cpp src/legacy_canvas_object_draw_services.cpp src/legacy_canvas_object_draw_services.h + src/legacy_canvas_camera_services.cpp src/legacy_canvas_projection_services.cpp src/legacy_canvas_projection_services.h src/legacy_canvas_plane_data.cpp @@ -212,6 +213,8 @@ set(PP_PANOPAINTER_UI_SOURCES src/legacy_node_stroke_preview_draw_services.h src/legacy_node_stroke_preview_runtime_services.cpp src/legacy_node_stroke_preview_runtime_services.h + src/legacy_node_stroke_preview_sample_services.cpp + src/legacy_node_stroke_preview_sample_services.h src/node_stroke_preview.cpp src/node_tool_bucket.cpp src/node_usermanual.cpp diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 9efcaa7a..0990675e 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -79,15 +79,15 @@ What is still carrying too much live ownership: Current hotspot files: -- `src/canvas.cpp`: 396 lines +- `src/canvas.cpp`: 368 lines - `src/app_layout.cpp`: 125 lines - `src/canvas_modes.cpp`: 402 lines - `src/node.cpp`: 260 lines - `src/main.cpp`: 130 lines - `src/node_panel_brush.cpp`: 255 lines -- `src/node_stroke_preview.cpp`: 545 lines +- `src/node_stroke_preview.cpp`: 490 lines - `src/node_canvas.cpp`: 219 lines -- `src/app.cpp`: 171 lines +- `src/app.cpp`: 113 lines - `src/app_dialogs.cpp`: 168 lines Current architecture mismatches that must be treated as real blockers: @@ -235,7 +235,11 @@ Current architecture mismatches that must be treated as real blockers: now live in `src/legacy_app_frame_services.cpp` instead of staying inline in `src/app.cpp`, while the larger document/export/save/open/thumbnail document-IO cluster now lives in `src/legacy_canvas_document_io_services.cpp` - and `src/app.cpp` is materially thinner, + and `src/app.cpp` is materially thinner, while `App::clear()`, + `App::check_license()`, `App::async_start()`, `App::async_redraw()`, + `App::async_end()`, and `App::async_swap()` now also live in + `src/legacy_app_runtime_shell_services.cpp` instead of staying inline in + `src/app.cpp`, while the canvas state-management cluster for picking, clear/clear-all, layer add/remove/order/lookups, animation frame control, resize, and snapshot save/restore now lives in `src/legacy_canvas_state_services.cpp` instead of @@ -291,7 +295,9 @@ Current architecture mismatches that must be treated as real blockers: `Canvas::stroke_update(...)`, and `Canvas::stroke_start(...)` now also route through `src/legacy_canvas_stroke_runtime_services.*` instead of staying inline in `src/canvas.cpp`, which trims another large retained stroke/runtime - pocket, while the + pocket, while the final camera/timelapse member definitions now also live in + `src/legacy_canvas_camera_services.cpp` instead of staying inline in + `src/canvas.cpp`, which trims another retained canvas shell pocket, while the `CanvasModeTransform` interaction family now also routes through `src/legacy_canvas_mode_transform.cpp` instead of staying inline in `src/canvas_modes.cpp`, which materially thins another retained canvas-view @@ -381,7 +387,11 @@ Current architecture mismatches that must be treated as real blockers: `src/node_stroke_preview.cpp`, and while the generic Yoga style/visibility pocket from `Node::SetWidth(...)` through `Node::GetRTL()` now also routes through `src/legacy_ui_node_style.*` instead of staying - inline in `src/node.cpp`. + inline in `src/node.cpp`, while the preview sample execution pocket for + sample-point conversion, brush vertex upload, request assembly, and the + `execute_legacy_canvas_stroke_sample(...)` call now also lives in + `src/legacy_node_stroke_preview_sample_services.*` instead of staying inline + in `src/node_stroke_preview.cpp`. - Modern C++23 usage exists in extracted components, especially `std::span`, explicit result/status objects, and a few concepts, but the live app still does not consistently express ownership, thread affinity, or renderer diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index e9a289d6..01c8e30e 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -152,6 +152,9 @@ Current slice: `src/legacy_canvas_plane_data.cpp` instead of staying inline in `src/canvas.cpp`, which trims another retained data-ownership pocket from the live canvas shell. +- The final camera/timelapse member definitions now also live in + `src/legacy_canvas_camera_services.cpp` instead of staying inline in + `src/canvas.cpp`, which trims another retained canvas shell pocket. - The `CanvasModePen` and `CanvasModeLine` interaction families now also live in `src/legacy_canvas_mode_pen_line.cpp` instead of staying inline in `src/canvas_modes.cpp`, which materially thins another retained pen/line @@ -346,6 +349,12 @@ Current slice: `src/legacy_node_stroke_preview_runtime_services.*` instead of staying inline in `src/node_stroke_preview.cpp`, which trims another coherent preview runtime pocket while preserving the current live draw path. +- The preview sample execution pocket for sample-point conversion, brush + vertex upload, request assembly, and the + `execute_legacy_canvas_stroke_sample(...)` call now also lives in + `src/legacy_node_stroke_preview_sample_services.*` instead of staying inline + in `src/node_stroke_preview.cpp`, which trims another coherent preview + execution pocket while preserving the live draw path. - `NodeCanvas::init()` plus the remaining `NodeCanvas::draw()` outer shell now also live in `src/legacy_node_canvas_draw_services.*` instead of staying inline in `src/node_canvas.cpp`, which materially reduces the live node to a @@ -569,6 +578,11 @@ Current slice: instead of staying inline in `src/app.cpp`, which reduces the remaining app file to a thinner retained composition surface around startup and runtime delegation. +- `App::clear()`, `App::check_license()`, `App::async_start()`, + `App::async_redraw()`, `App::async_end()`, and `App::async_swap()` now also + live in `src/legacy_app_runtime_shell_services.cpp` instead of staying + inline in `src/app.cpp`, which reduces the remaining app file to a thinner + retained shell around document routing and runtime thread entrypoints. Write scope: - `src/app.cpp` diff --git a/src/app.cpp b/src/app.cpp index a6dcaa42..e57b89df 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -63,17 +63,6 @@ bool App::request_close() return close_decision == pp::app::CloseRequestDecision::close_now; } -void App::clear() -{ - const auto status = pp::renderer::gl::clear_panopainter_default_target( - pp::renderer::gl::OpenGlClearDispatch { - .clear_color = pp::legacy::ui_gl::set_opengl_clear_color, - .clear = pp::legacy::ui_gl::clear_opengl_buffer, - }); - if (!status.ok()) - LOG("OpenGL clear failed: %s", status.message); -} - void App::initAssets() { pp::panopainter::execute_legacy_app_init_assets(*this); @@ -89,69 +78,11 @@ namespace pp::panopainter bool update_legacy_app_ui_observer(App& app, Node* n); } -bool App::check_license() -{ - return true; // TODO: for distribuiton only - -#if WITH_CURL - CURL *curl = curl_easy_init(); - if (curl) - { - std::string url = "https://panopainter.com/license/7565D057-ACBE-4721-9A4E-F342D3DDB7D8.php"; - //std::string url = "https://panopainter.com/license/E8EDC2FE-E1BD-4AB1-91BD-FCCD926739BD.php"; // wacom - //std::string url = "https://panopainter.com/license/A744FBA9-BC6C-43C8-BD24-0CCE24B3D985.php"; // others - - std::string ret; - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); - - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); - //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L); - if (disables_network_tls_verification()) - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); - - auto err = curl_easy_perform(curl); - curl_easy_cleanup(curl); - - LOG("License check: %s", ret.c_str()); - if (err == CURLcode::CURLE_OK && ret == "success") - return true; - } -#endif //CURL - return false; -} - void App::init() { pp::panopainter::execute_legacy_app_init(*this); } -void App::async_start() -{ - acquire_render_context(); -} - -void App::async_redraw() -{ - const auto plan = pp::app::plan_app_async_redraw(); - if (plan.set_redraw) - redraw = true; - if (plan.notify_ui) - runtime_.notify_ui_worker(); -} - -void App::async_end() -{ - release_render_context(); -} - -void App::async_swap() -{ - present_render_context(); -} - bool App::update_ui_observer(Node *n) { return pp::panopainter::update_legacy_app_ui_observer(*this, n); diff --git a/src/canvas.cpp b/src/canvas.cpp index 514184c1..41b76249 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -418,38 +418,3 @@ glm::vec3 Canvas::project2Dpoint(glm::vec2 pt) return pp::panopainter::legacy_canvas_project_2d_point(*this, pt); } - - -// return the 2d shape of the faces based on the current camera -// this can be used for screen space shapes clipping -std::vector Canvas::face_to_shape2D(int plane_index) -{ - return pp::panopainter::legacy_canvas_face_to_shape_2d(*this, plane_index); -} - -void Canvas::push_camera() -{ - pp::panopainter::legacy_canvas_push_camera(*this); -} - -void Canvas::pop_camera() -{ - pp::panopainter::legacy_canvas_pop_camera(*this); -} - -CameraData Canvas::get_camera() -{ - return pp::panopainter::legacy_canvas_render_shell_get_camera(*this); -} - -void Canvas::set_camera(const CameraData& c) -{ - pp::panopainter::legacy_canvas_render_shell_set_camera(*this, c); -} - -void Canvas::timelapse_reset_encoder() noexcept -{ - m_encoder = std::make_unique(); - int res = glm::min(m_width / 2, 1024); - m_encoder->init(res * 4, res * 2, 30, 2000 << 10); -} diff --git a/src/legacy_app_runtime_shell_services.cpp b/src/legacy_app_runtime_shell_services.cpp index 9644bf5d..e5b23618 100644 --- a/src/legacy_app_runtime_shell_services.cpp +++ b/src/legacy_app_runtime_shell_services.cpp @@ -108,6 +108,75 @@ void App::update(float dt) pp::panopainter::update_legacy_canvas_toolbar(*this); } +void App::clear() +{ + const auto status = pp::renderer::gl::clear_panopainter_default_target( + pp::renderer::gl::OpenGlClearDispatch { + .clear_color = pp::legacy::ui_gl::set_opengl_clear_color, + .clear = pp::legacy::ui_gl::clear_opengl_buffer, + }); + if (!status.ok()) + LOG("OpenGL clear failed: %s", status.message); +} + +bool App::check_license() +{ + return true; // TODO: for distribuiton only + +#if WITH_CURL + CURL* curl = curl_easy_init(); + if (curl) + { + std::string url = "https://panopainter.com/license/7565D057-ACBE-4721-9A4E-F342D3DDB7D8.php"; + //std::string url = "https://panopainter.com/license/E8EDC2FE-E1BD-4AB1-91BD-FCCD926739BD.php"; // wacom + //std::string url = "https://panopainter.com/license/A744FBA9-BC6C-43C8-BD24-0CCE24B3D985.php"; // others + + std::string ret; + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ret); + //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2L); + if (disables_network_tls_verification()) + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + + const auto err = curl_easy_perform(curl); + curl_easy_cleanup(curl); + + LOG("License check: %s", ret.c_str()); + if (err == CURLcode::CURLE_OK && ret == "success") + return true; + } +#endif //CURL + return false; +} + +void App::async_start() +{ + acquire_render_context(); +} + +void App::async_redraw() +{ + const auto plan = pp::app::plan_app_async_redraw(); + if (plan.set_redraw) + redraw = true; + if (plan.notify_ui) + runtime_.notify_ui_worker(); +} + +void App::async_end() +{ + release_render_context(); +} + +void App::async_swap() +{ + present_render_context(); +} + void App::terminate() { LOG("App::terminate"); diff --git a/src/legacy_canvas_camera_services.cpp b/src/legacy_canvas_camera_services.cpp new file mode 100644 index 00000000..303c0867 --- /dev/null +++ b/src/legacy_canvas_camera_services.cpp @@ -0,0 +1,40 @@ +#include "pch.h" + +#include "canvas.h" + +#include "legacy_canvas_projection_services.h" +#include "legacy_canvas_render_shell_services.h" + +// return the 2d shape of the faces based on the current camera +// this can be used for screen space shapes clipping +std::vector Canvas::face_to_shape2D(int plane_index) +{ + return pp::panopainter::legacy_canvas_face_to_shape_2d(*this, plane_index); +} + +void Canvas::push_camera() +{ + pp::panopainter::legacy_canvas_push_camera(*this); +} + +void Canvas::pop_camera() +{ + pp::panopainter::legacy_canvas_pop_camera(*this); +} + +CameraData Canvas::get_camera() +{ + return pp::panopainter::legacy_canvas_render_shell_get_camera(*this); +} + +void Canvas::set_camera(const CameraData& c) +{ + pp::panopainter::legacy_canvas_render_shell_set_camera(*this, c); +} + +void Canvas::timelapse_reset_encoder() noexcept +{ + m_encoder = std::make_unique(); + int res = glm::min(m_width / 2, 1024); + m_encoder->init(res * 4, res * 2, 30, 2000 << 10); +} diff --git a/src/legacy_node_stroke_preview_sample_services.cpp b/src/legacy_node_stroke_preview_sample_services.cpp new file mode 100644 index 00000000..b767ab79 --- /dev/null +++ b/src/legacy_node_stroke_preview_sample_services.cpp @@ -0,0 +1,60 @@ +#include "pch.h" + +#include "legacy_node_stroke_preview_sample_services.h" + +namespace pp::panopainter { + +namespace { + +std::array make_stroke_preview_sample_points( + const std::array& vertices) +{ + return { + pp::paint_renderer::CanvasStrokePoint { .x = vertices[0].pos.x, .y = vertices[0].pos.y }, + pp::paint_renderer::CanvasStrokePoint { .x = vertices[1].pos.x, .y = vertices[1].pos.y }, + pp::paint_renderer::CanvasStrokePoint { .x = vertices[2].pos.x, .y = vertices[2].pos.y }, + pp::paint_renderer::CanvasStrokePoint { .x = vertices[3].pos.x, .y = vertices[3].pos.y }, + }; +} + +void upload_stroke_preview_brush_vertices(DynamicShape& brush_shape, std::span vertices) +{ + brush_shape.update_vertices( + const_cast(vertices.data()), + static_cast(vertices.size())); +} + +LegacyStrokeSampleExecutionRequest make_stroke_preview_sample_request( + const LegacyNodeStrokePreviewSamplePassRequest& request, + const std::array& sample_points) +{ + return LegacyStrokeSampleExecutionRequest { + .context = "NodeStrokePreview::stroke_draw_samples", + .target_size = request.target_size, + .vertices = request.vertices, + .sample_points = sample_points, + .copy_stroke_destination = request.copy_stroke_destination, + .bind_destination_texture = request.bind_destination_texture, + .copy_framebuffer_to_destination_texture = request.copy_framebuffer_to_destination_texture, + .unbind_destination_texture = request.unbind_destination_texture, + .upload_brush_vertices = [&](std::span brush_vertices) { + upload_stroke_preview_brush_vertices(request.brush_shape, brush_vertices); + }, + .draw_brush_shape = [&] { + request.brush_shape.draw_fill(); + }, + }; +} + +} // namespace + +glm::vec4 execute_legacy_node_stroke_preview_sample_pass( + const LegacyNodeStrokePreviewSamplePassRequest& request) +{ + const auto sample_points = make_stroke_preview_sample_points(request.vertices); + const auto result = execute_legacy_canvas_stroke_sample( + make_stroke_preview_sample_request(request, sample_points)); + return result.dirty_bounds; +} + +} // namespace pp::panopainter diff --git a/src/legacy_node_stroke_preview_sample_services.h b/src/legacy_node_stroke_preview_sample_services.h new file mode 100644 index 00000000..d55c117b --- /dev/null +++ b/src/legacy_node_stroke_preview_sample_services.h @@ -0,0 +1,28 @@ +#pragma once + +#include "legacy_canvas_stroke_execution_services.h" +#include "paint_renderer/compositor.h" +#include "shape.h" +#include "texture.h" +#include "util.h" + +#include +#include +#include + +namespace pp::panopainter { + +struct LegacyNodeStrokePreviewSamplePassRequest { + glm::vec2 target_size {}; + std::array& vertices; + DynamicShape& brush_shape; + bool copy_stroke_destination = false; + std::function bind_destination_texture; + std::function copy_framebuffer_to_destination_texture; + std::function unbind_destination_texture; +}; + +[[nodiscard]] glm::vec4 execute_legacy_node_stroke_preview_sample_pass( + const LegacyNodeStrokePreviewSamplePassRequest& request); + +} // namespace pp::panopainter diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index c6ad8348..ae831d92 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -14,6 +14,7 @@ #include "legacy_canvas_stroke_services.h" #include "legacy_node_stroke_preview_execution_services.h" #include "legacy_node_stroke_preview_runtime_services.h" +#include "legacy_node_stroke_preview_sample_services.h" #include "legacy_ui_gl_dispatch.h" #include "paint_renderer/compositor.h" #include "renderer_gl/opengl_capabilities.h" @@ -242,89 +243,6 @@ void copy_stroke_preview_destination_texture_region( copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height); } -std::array make_stroke_preview_sample_points( - const std::array& vertices) -{ - return { - pp::paint_renderer::CanvasStrokePoint { .x = vertices[0].pos.x, .y = vertices[0].pos.y }, - pp::paint_renderer::CanvasStrokePoint { .x = vertices[1].pos.x, .y = vertices[1].pos.y }, - pp::paint_renderer::CanvasStrokePoint { .x = vertices[2].pos.x, .y = vertices[2].pos.y }, - pp::paint_renderer::CanvasStrokePoint { .x = vertices[3].pos.x, .y = vertices[3].pos.y }, - }; -} - -void upload_stroke_preview_brush_vertices(DynamicShape& brush_shape, std::span vertices); - -pp::panopainter::LegacyStrokeSampleExecutionRequest make_stroke_preview_sample_request( - std::array& vertices, - const std::array& sample_points, - glm::vec2 target_size, - Texture2D& blend_texture, - DynamicShape& brush_shape, - bool copy_stroke_destination) -{ - return pp::panopainter::LegacyStrokeSampleExecutionRequest { - .context = "NodeStrokePreview::stroke_draw_samples", - .target_size = target_size, - .vertices = vertices, - .sample_points = sample_points, - .copy_stroke_destination = copy_stroke_destination, - .bind_destination_texture = [&] { - bind_stroke_preview_destination_texture(blend_texture); - }, - .copy_framebuffer_to_destination_texture = []( - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height) { - copy_stroke_preview_destination_texture_region( - src_x, - src_y, - dst_x, - dst_y, - width, - height); - }, - .unbind_destination_texture = [&] { - unbind_stroke_preview_destination_texture(blend_texture); - }, - .upload_brush_vertices = [&](std::span brush_vertices) { - upload_stroke_preview_brush_vertices(brush_shape, brush_vertices); - }, - .draw_brush_shape = [&] { - brush_shape.draw_fill(); - }, - }; -} - -void upload_stroke_preview_brush_vertices(DynamicShape& brush_shape, std::span vertices) -{ - brush_shape.update_vertices( - const_cast(vertices.data()), - static_cast(vertices.size())); -} - -glm::vec4 execute_stroke_preview_sample_pass( - std::array& vertices, - glm::vec2 target_size, - Texture2D& blend_texture, - DynamicShape& brush_shape, - bool copy_stroke_destination) -{ - const auto sample_points = make_stroke_preview_sample_points(vertices); - const auto result = pp::panopainter::execute_legacy_canvas_stroke_sample( - make_stroke_preview_sample_request( - vertices, - sample_points, - target_size, - blend_texture, - brush_shape, - copy_stroke_destination)); - return result.dirty_bounds; -} - void execute_stroke_preview_background_capture_pass( glm::vec2 size, bool colorize, @@ -441,12 +359,34 @@ glm::vec4 NodeStrokePreview::stroke_draw_samples( bool copy_stroke_destination) { const glm::vec2 size = { m_rtt.getWidth(), m_rtt.getHeight() }; - return execute_stroke_preview_sample_pass( - P, - size, - blend_tex, - m_brush_shape, - copy_stroke_destination); + return pp::panopainter::execute_legacy_node_stroke_preview_sample_pass( + pp::panopainter::LegacyNodeStrokePreviewSamplePassRequest { + .target_size = size, + .vertices = P, + .brush_shape = m_brush_shape, + .copy_stroke_destination = copy_stroke_destination, + .bind_destination_texture = [&] { + bind_stroke_preview_destination_texture(blend_tex); + }, + .copy_framebuffer_to_destination_texture = []( + int src_x, + int src_y, + int dst_x, + int dst_y, + int width, + int height) { + copy_stroke_preview_destination_texture_region( + src_x, + src_y, + dst_x, + dst_y, + width, + height); + }, + .unbind_destination_texture = [&] { + unbind_stroke_preview_destination_texture(blend_tex); + }, + }); } std::vector NodeStrokePreview::stroke_draw_compute(const Stroke& stroke, float zoom) const