From 6bb1268edb6b3b367e3d716ee42a7e2206a623cc Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 13 Jun 2026 17:42:40 +0200 Subject: [PATCH] Extract stroke destination dispatch helper --- docs/modernization/tasks.md | 3 +++ src/canvas.cpp | 22 ++++++++-------- src/legacy_canvas_stroke_execution_services.h | 12 +++++++++ .../paint_renderer/stroke_execution_tests.cpp | 25 +++++++++++++++++++ 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/docs/modernization/tasks.md b/docs/modernization/tasks.md index 00a444b..bb927a0 100644 --- a/docs/modernization/tasks.md +++ b/docs/modernization/tasks.md @@ -515,6 +515,9 @@ Progress Notes: closeout. - 2026-06-13: `STR-004` closed the last inline stroke dispatch glue. `LATER-003` remains at the binding-only tail. +- 2026-06-13: `Canvas::stroke_draw_samples()` now reuses a retained destination + texture dispatch helper for the live sample path; `Canvas` still owns the + concrete face textures and callback execution. - 2026-06-13: `pp_paint_renderer_stroke_execution_tests` now also covers the new retained main-pass texture dispatch helper builder and its pattern/mixer wiring. Next slice should target another narrow `stroke_draw()` seam or stop diff --git a/src/canvas.cpp b/src/canvas.cpp index a258a65..ddaf313 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -564,17 +564,17 @@ glm::vec4 Canvas::stroke_draw_samples( .slot = 1, }, }; - const pp::panopainter::LegacyCanvasStrokeTextureInputDispatch destination_texture_dispatch { - .activate_texture_unit = [&](int texture_slot) { - set_active_texture_unit(texture_slot); - }, - .bind_stroke_destination = [&] { - m_tex[i].bind(); // bg, copy of framebuffer (copied before drawing) - }, - .unbind_stroke_destination = [&] { - m_tex[i].unbind(); - }, - }; + const auto destination_texture_dispatch = + pp::panopainter::make_legacy_canvas_stroke_destination_texture_dispatch( + [&](int texture_slot) { + set_active_texture_unit(texture_slot); + }, + [&] { + m_tex[i].bind(); // bg, copy of framebuffer (copied before drawing) + }, + [&] { + m_tex[i].unbind(); + }); const auto result = pp::panopainter::execute_legacy_canvas_stroke_face_sample_polygon( pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest { .context = "Canvas::stroke_draw_samples", diff --git a/src/legacy_canvas_stroke_execution_services.h b/src/legacy_canvas_stroke_execution_services.h index 6b897ea..773160c 100644 --- a/src/legacy_canvas_stroke_execution_services.h +++ b/src/legacy_canvas_stroke_execution_services.h @@ -116,6 +116,18 @@ struct LegacyCanvasStrokeTextureInputDispatch { }; } +[[nodiscard]] inline LegacyCanvasStrokeTextureInputDispatch make_legacy_canvas_stroke_destination_texture_dispatch( + std::function activate_texture_unit, + std::function bind_stroke_destination, + std::function unbind_stroke_destination) +{ + return LegacyCanvasStrokeTextureInputDispatch { + .activate_texture_unit = std::move(activate_texture_unit), + .bind_stroke_destination = std::move(bind_stroke_destination), + .unbind_stroke_destination = std::move(unbind_stroke_destination), + }; +} + [[nodiscard]] inline LegacyCanvasStrokeTextureInputDispatch make_legacy_canvas_stroke_pad_destination_texture_dispatch( std::function activate_texture_unit, std::function bind_stroke_destination, diff --git a/tests/paint_renderer/stroke_execution_tests.cpp b/tests/paint_renderer/stroke_execution_tests.cpp index 6d168d1..96c1f51 100644 --- a/tests/paint_renderer/stroke_execution_tests.cpp +++ b/tests/paint_renderer/stroke_execution_tests.cpp @@ -361,6 +361,28 @@ void retained_stroke_pad_destination_texture_dispatch_helper_builds_expected_cal PP_EXPECT(h, events == expected_events); } +void retained_stroke_destination_texture_dispatch_helper_builds_expected_callback_wiring(pp::tests::Harness& h) +{ + std::vector events; + const auto dispatch = pp::panopainter::make_legacy_canvas_stroke_destination_texture_dispatch( + [&](int slot) { events.emplace_back("activate:" + std::to_string(slot)); }, + [&] { events.emplace_back("bind:destination"); }, + [&] { events.emplace_back("unbind:destination"); }); + + pp::panopainter::bind_legacy_canvas_stroke_texture_input( + LegacyCanvasStrokeTextureInput::stroke_destination, + dispatch); + pp::panopainter::unbind_legacy_canvas_stroke_texture_input( + LegacyCanvasStrokeTextureInput::stroke_destination, + dispatch); + + const std::vector expected_events { + "bind:destination", + "unbind:destination", + }; + PP_EXPECT(h, events == expected_events); +} + void retained_stroke_sample_executor_copies_destination_and_expands_quads(pp::tests::Harness& h) { const auto vertices = make_quad_vertices(); @@ -1450,6 +1472,9 @@ int main() harness.run( "retained_stroke_brush_tip_texture_dispatch_helper_builds_expected_callback_wiring", retained_stroke_brush_tip_texture_dispatch_helper_builds_expected_callback_wiring); + harness.run( + "retained_stroke_destination_texture_dispatch_helper_builds_expected_callback_wiring", + retained_stroke_destination_texture_dispatch_helper_builds_expected_callback_wiring); harness.run( "retained_stroke_live_pass_sampler_dispatch_helper_builds_expected_callback_wiring", retained_stroke_live_pass_sampler_dispatch_helper_builds_expected_callback_wiring);