diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index d4cd147e..5051109c 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -18,6 +18,12 @@ agent or engineer to remove them without reconstructing context from chat. ## Recent Reductions +- 2026-06-15: `DEBT-0036` was narrowed again. `NodeStrokePreview` now drops the + retained pass-sequence, mix-execution, final-composite-request, background + capture, and preview-copy wrapper structs/functions in favor of direct + retained helper dispatch plus renderer-facing preview copy helpers; the live + preview path still owns concrete framebuffer, texture-binding, and draw + execution around those helpers. - 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_commit()` now routes the retained pre-dispatch state capture through local commit helpers; the live path still owns concrete layer/action mutation until the retained diff --git a/src/canvas.cpp b/src/canvas.cpp index 480508c2..2f721824 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1741,18 +1741,79 @@ void Canvas::stroke_draw_dual_pass( } pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest Canvas::make_stroke_draw_main_pass_request( + const Brush& brush, std::function bind_samplers, - std::function bind_textures, std::function execute_frame_pass, - std::function unbind_textures, std::function unbind_samplers) { + constexpr std::array main_pass_texture_bindings { + pp::panopainter::LegacyCanvasStrokeTextureBinding { + .input = pp::panopainter::LegacyCanvasStrokeTextureInput::brush_tip, + .slot = 0, + }, + pp::panopainter::LegacyCanvasStrokeTextureBinding { + .input = pp::panopainter::LegacyCanvasStrokeTextureInput::stroke_destination, + .slot = 1, + }, + pp::panopainter::LegacyCanvasStrokeTextureBinding { + .input = pp::panopainter::LegacyCanvasStrokeTextureInput::pattern, + .slot = 2, + }, + pp::panopainter::LegacyCanvasStrokeTextureBinding { + .input = pp::panopainter::LegacyCanvasStrokeTextureInput::mixer, + .slot = 3, + }, + }; + constexpr std::array main_pass_texture_unbindings { + pp::panopainter::LegacyCanvasStrokeTextureBinding { + .input = pp::panopainter::LegacyCanvasStrokeTextureInput::mixer, + .slot = 3, + }, + pp::panopainter::LegacyCanvasStrokeTextureBinding { + .input = pp::panopainter::LegacyCanvasStrokeTextureInput::stroke_destination, + .slot = 1, + }, + pp::panopainter::LegacyCanvasStrokeTextureBinding { + .input = pp::panopainter::LegacyCanvasStrokeTextureInput::brush_tip, + .slot = 0, + }, + }; + const auto main_pass_texture_dispatch = pp::panopainter::make_legacy_canvas_stroke_main_pass_texture_dispatch( + [&](int texture_slot) { + set_active_texture_unit(texture_slot); + }, + [&] { + brush.m_tip_texture->bind(); + }, + [&] { + brush.m_tip_texture->unbind(); + }, + [&] { + brush.m_pattern_texture ? + brush.m_pattern_texture->bind() : + unbind_texture_2d(); + }, + [&] { + m_mixer.bindTexture(); + }, + [&] { + m_mixer.unbindTexture(); + }); + return pp::panopainter::make_legacy_canvas_stroke_main_pass_execution_request( "Canvas::stroke_draw", std::move(bind_samplers), - std::move(bind_textures), + [&] { + pp::panopainter::bind_legacy_canvas_stroke_texture_inputs( + main_pass_texture_bindings, + main_pass_texture_dispatch); + }, std::move(execute_frame_pass), - std::move(unbind_textures), + [&] { + pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( + main_pass_texture_unbindings, + main_pass_texture_dispatch); + }, std::move(unbind_samplers)); } @@ -1872,20 +1933,6 @@ void Canvas::stroke_draw() }); // DRAW MAIN BRUSH - constexpr std::array main_pass_texture_bindings { - pp::panopainter::LegacyCanvasStrokeTextureBinding { - .input = pp::panopainter::LegacyCanvasStrokeTextureInput::brush_tip, - .slot = 0, - }, - pp::panopainter::LegacyCanvasStrokeTextureBinding { - .input = pp::panopainter::LegacyCanvasStrokeTextureInput::pattern, - .slot = 2, - }, - pp::panopainter::LegacyCanvasStrokeTextureBinding { - .input = pp::panopainter::LegacyCanvasStrokeTextureInput::mixer, - .slot = 3, - }, - }; constexpr std::array live_pass_sampler_bindings { pp::panopainter::LegacyCanvasStrokeTextureBinding { .input = pp::panopainter::LegacyCanvasStrokeTextureInput::brush_tip, @@ -1904,16 +1951,6 @@ void Canvas::stroke_draw() .slot = 3, }, }; - constexpr std::array main_pass_texture_unbindings { - pp::panopainter::LegacyCanvasStrokeTextureBinding { - .input = pp::panopainter::LegacyCanvasStrokeTextureInput::mixer, - .slot = 3, - }, - pp::panopainter::LegacyCanvasStrokeTextureBinding { - .input = pp::panopainter::LegacyCanvasStrokeTextureInput::brush_tip, - .slot = 0, - }, - }; const pp::panopainter::LegacyCanvasStrokeSamplerDispatch live_pass_sampler_dispatch = pp::panopainter::make_legacy_canvas_stroke_live_pass_sampler_dispatch( [&](int slot) { @@ -1937,30 +1974,9 @@ void Canvas::stroke_draw() [&](int slot) { m_sampler.bind(slot); }, - [&] { - m_sampler.unbind(); - }); - const auto main_pass_texture_dispatch = pp::panopainter::make_legacy_canvas_stroke_main_pass_texture_dispatch( - [&](int texture_slot) { - set_active_texture_unit(texture_slot); - }, - [&] { - brush->m_tip_texture->bind(); - }, - [&] { - brush->m_tip_texture->unbind(); - }, - [&] { - brush->m_pattern_texture ? - brush->m_pattern_texture->bind() : - unbind_texture_2d(); - }, - [&] { - m_mixer.bindTexture(); - }, - [&] { - m_mixer.unbindTexture(); - }); + [&] { + m_sampler.unbind(); + }); auto frames = stroke_draw_compute(*m_current_stroke); std::array box_face = SIXPLETTE(glm::vec4(m_size, 0, 0)); @@ -1970,16 +1986,12 @@ void Canvas::stroke_draw() [[maybe_unused]] const auto main_pass_result = pp::panopainter::execute_legacy_canvas_stroke_main_pass( make_stroke_draw_main_pass_request( + *brush, [&] { pp::panopainter::bind_legacy_canvas_stroke_sampler_inputs( live_pass_sampler_bindings, live_pass_sampler_dispatch); }, - [&] { - pp::panopainter::bind_legacy_canvas_stroke_texture_inputs( - main_pass_texture_bindings, - main_pass_texture_dispatch); - }, [&] { pp::panopainter::execute_legacy_canvas_stroke_main_pass_frame_callbacks( frames, @@ -2010,11 +2022,6 @@ void Canvas::stroke_draw() }, m_tmp); }, - [&] { - pp::panopainter::unbind_legacy_canvas_stroke_texture_inputs( - main_pass_texture_unbindings, - main_pass_texture_dispatch); - }, [&] { pp::panopainter::unbind_legacy_canvas_stroke_sampler_inputs( live_pass_sampler_bindings, diff --git a/src/canvas.h b/src/canvas.h index f0953f63..c2fff1b9 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -295,10 +295,9 @@ private: bool uses_pattern, bool copy_stroke_destination); pp::panopainter::LegacyCanvasStrokeMainPassExecutionRequest make_stroke_draw_main_pass_request( + const Brush& brush, std::function bind_samplers, - std::function bind_textures, std::function execute_frame_pass, - std::function unbind_textures, std::function unbind_samplers); pp::panopainter::LegacyCanvasStrokeDualPassRequest make_stroke_draw_dual_pass_request( const std::vector& frames_dual, diff --git a/src/legacy_canvas_stroke_preview_services.h b/src/legacy_canvas_stroke_preview_services.h index d0762807..72fc0a08 100644 --- a/src/legacy_canvas_stroke_preview_services.h +++ b/src/legacy_canvas_stroke_preview_services.h @@ -5,11 +5,6 @@ namespace pp::panopainter { -struct LegacyStrokePreviewCopySize { - int width = 0; - int height = 0; -}; - struct LegacyVrColorUniforms { glm::vec4 color { 1.0f }; glm::mat4 mvp { 1.0f }; @@ -40,24 +35,6 @@ inline void setup_legacy_vr_stroke_preview_shader(const LegacyVrStrokePreviewUni ShaderManager::u_mat4(kShaderUniform::MVP, uniforms.mvp); } -template < - typename SetupCheckerboard, - typename DrawPlane, - typename BindBackgroundTexture, - typename CopyFramebufferToTexture> -void execute_legacy_stroke_preview_background_capture( - SetupCheckerboard&& setup_checkerboard, - DrawPlane&& draw_plane, - BindBackgroundTexture&& bind_background_texture, - CopyFramebufferToTexture&& copy_framebuffer_to_texture, - LegacyStrokePreviewCopySize copy_size) -{ - setup_checkerboard(); - draw_plane(); - bind_background_texture(); - copy_framebuffer_to_texture(0, 0, 0, 0, copy_size.width, copy_size.height); -} - template < typename SetupCompositeShader, typename BindCompositeSamplers, @@ -100,14 +77,4 @@ void execute_legacy_stroke_preview_live_pass( copy_preview_result(); } -template -void copy_legacy_stroke_preview_texture( - BindPreviewTexture&& bind_preview_texture, - CopyFramebufferToTexture&& copy_framebuffer_to_texture, - LegacyStrokePreviewCopySize copy_size) -{ - bind_preview_texture(); - copy_framebuffer_to_texture(0, 0, 0, 0, copy_size.width, copy_size.height); -} - } // namespace pp::panopainter diff --git a/src/legacy_node_stroke_preview_execution_services.h b/src/legacy_node_stroke_preview_execution_services.h index 8d3294b3..c22e378f 100644 --- a/src/legacy_node_stroke_preview_execution_services.h +++ b/src/legacy_node_stroke_preview_execution_services.h @@ -92,24 +92,6 @@ struct LegacyNodeStrokePreviewMixPassRequest { int blend_mode = 0; }; -struct LegacyNodeStrokePreviewMixExecutionRequest { - LegacyNodeStrokePreviewMixPassPlan::ShaderPlan shader {}; - int mixer_width = 0; - int mixer_height = 0; - int scissor_x = 0; - int scissor_y = 0; - int scissor_width = 0; - int scissor_height = 0; - std::function save_state; - std::function setup_mix_shader; - std::function bind_mixer_framebuffer; - std::function configure_mix_target_state; - std::function bind_mix_inputs; - std::function draw_mix; - std::function unbind_mixer_framebuffer; - std::function restore_state; -}; - [[nodiscard]] inline LegacyNodeStrokePreviewMixPassPlan plan_legacy_node_stroke_preview_mix_pass( const LegacyNodeStrokePreviewMixPassRequest& request) noexcept { @@ -153,80 +135,6 @@ struct LegacyNodeStrokePreviewMixExecutionRequest { return plan; } -[[nodiscard]] inline bool execute_legacy_node_stroke_preview_mix_pass( - const LegacyNodeStrokePreviewMixExecutionRequest& request) -{ - if (request.mixer_width <= 0 || - request.mixer_height <= 0 || - !request.save_state || - !request.setup_mix_shader || - !request.bind_mixer_framebuffer || - !request.configure_mix_target_state || - !request.bind_mix_inputs || - !request.draw_mix || - !request.unbind_mixer_framebuffer || - !request.restore_state) { - return false; - } - - request.save_state(); - request.setup_mix_shader(request.shader); - request.bind_mixer_framebuffer(); - request.configure_mix_target_state( - request.mixer_width, - request.mixer_height, - request.scissor_x, - request.scissor_y, - request.scissor_width, - request.scissor_height); - request.bind_mix_inputs(); - request.draw_mix(); - request.unbind_mixer_framebuffer(); - request.restore_state(); - return true; -} - -struct LegacyNodeStrokePreviewPassSequenceRequest { - bool dual_pass_enabled = false; - std::function prepare_dual_pass; - std::function execute_dual_pass; - std::function capture_background; - std::function prepare_main_pass; - std::function execute_main_pass; - std::function finish_main_pass; - std::function execute_final_composite; - std::function copy_preview_result; -}; - -[[nodiscard]] inline bool execute_legacy_node_stroke_preview_pass_sequence( - const LegacyNodeStrokePreviewPassSequenceRequest& request) -{ - if (!request.capture_background || - !request.prepare_main_pass || - !request.execute_main_pass || - !request.finish_main_pass || - !request.execute_final_composite || - !request.copy_preview_result) { - return false; - } - - if (request.dual_pass_enabled) { - if (!request.prepare_dual_pass || !request.execute_dual_pass) { - return false; - } - request.prepare_dual_pass(); - request.execute_dual_pass(); - } - - request.capture_background(); - request.prepare_main_pass(); - request.execute_main_pass(); - request.finish_main_pass(); - request.execute_final_composite(); - request.copy_preview_result(); - return true; -} - struct LegacyNodeStrokePreviewPassOrchestrationPlan { pp::paint_renderer::CanvasStrokeFeedbackPlan feedback {}; pp::paint_renderer::CanvasStrokeMaterialPlan material {}; @@ -244,69 +152,6 @@ struct LegacyNodeStrokePreviewMainPassTextureDispatch { std::function bind_mixer; }; -struct LegacyNodeStrokePreviewFinalCompositeRequest { - glm::vec2 resolution {}; - glm::vec2 pattern_scale {}; - const Brush* brush = nullptr; - const pp::paint_renderer::CanvasStrokeCompositePassPlan* composite_pass = nullptr; - std::function setup_composite_shader; - std::function bind_composite_samplers; - std::function bind_composite_inputs; - std::function draw_composite; -}; - -[[nodiscard]] inline bool execute_legacy_node_stroke_preview_final_composite( - const LegacyNodeStrokePreviewFinalCompositeRequest& request) -{ - if (!request.brush || - !request.composite_pass || - !request.setup_composite_shader || - !request.bind_composite_samplers || - !request.bind_composite_inputs || - !request.draw_composite) { - return false; - } - - pp::panopainter::execute_legacy_stroke_preview_final_composite( - [&] { - request.setup_composite_shader(); - }, - [&] { - request.bind_composite_samplers(); - }, - [&] { - request.bind_composite_inputs(); - }, - [&] { - request.draw_composite(); - }); - return true; -} - -struct LegacyNodeStrokePreviewCopyResultRequest { - Texture2D* preview_texture = nullptr; - glm::vec2 size {}; - std::function copy_framebuffer_to_texture; -}; - -[[nodiscard]] inline bool copy_legacy_node_stroke_preview_result( - const LegacyNodeStrokePreviewCopyResultRequest& request) -{ - if (!request.preview_texture || !request.copy_framebuffer_to_texture) { - return false; - } - pp::panopainter::copy_legacy_stroke_preview_texture( - [&] { - request.preview_texture->bind(); - }, - request.copy_framebuffer_to_texture, - pp::panopainter::LegacyStrokePreviewCopySize { - .width = static_cast(request.size.x), - .height = static_cast(request.size.y), - }); - return true; -} - [[nodiscard]] inline LegacyNodeStrokePreviewMainPassTextureDispatch make_legacy_node_stroke_preview_main_pass_texture_dispatch( std::function activate_texture_unit, std::function bind_brush_tip, diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index b09d0935..939780e1 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -173,7 +173,7 @@ pp::panopainter::LegacyStrokeCompositeUniforms make_stroke_preview_mix_composite }; } -pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest make_stroke_preview_mix_execution_request( +pp::panopainter::LegacyCanvasStrokeMixPassRequest make_stroke_preview_mix_pass_execution_request( const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader, RTT& mixer_rtt, const Brush& brush, @@ -181,39 +181,18 @@ pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest make_stroke_preview_ Texture2D& background_texture, Texture2D& stroke_texture, Texture2D& dual_texture, - gl_state& gl, - const glm::vec2& bb_min, - const glm::vec2& bb_sz, + std::span mix_planes, std::function draw_mix) { - return pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest { - .shader = shader, - .mixer_width = mixer_rtt.getWidth(), - .mixer_height = mixer_rtt.getHeight(), - .scissor_x = static_cast(bb_min.x), - .scissor_y = static_cast(bb_min.y), - .scissor_width = static_cast(bb_sz.x), - .scissor_height = static_cast(bb_sz.y), - .save_state = [&] { gl.save(); }, - .setup_mix_shader = [&](const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader_plan) { - pp::panopainter::setup_legacy_stroke_composite_shader( - make_stroke_preview_mix_composite_uniforms(shader_plan)); - }, - .bind_mixer_framebuffer = [&] { mixer_rtt.bindFramebuffer(); }, - .configure_mix_target_state = [&](int mixer_width, - int mixer_height, - int scissor_x, - int scissor_y, - int scissor_width, - int scissor_height) { - apply_stroke_preview_viewport(0, 0, mixer_width, mixer_height); - apply_stroke_preview_capability(pp::renderer::gl::depth_test_state(), false); - apply_stroke_preview_capability(pp::renderer::gl::scissor_test_state(), true); - apply_stroke_preview_capability(pp::renderer::gl::blend_state(), false); - apply_stroke_preview_scissor(scissor_x, scissor_y, scissor_width, scissor_height); - }, - .bind_mix_inputs = [&] { + return pp::panopainter::make_legacy_canvas_stroke_mix_pass_request( + "NodeStrokePreview::stroke_draw_mix", + glm::vec2(static_cast(mixer_rtt.getWidth()), static_cast(mixer_rtt.getHeight())), + mix_planes, + [&] { linear_sampler.bind(stroke_preview_composite_slots::kBackground); + linear_sampler.bind(stroke_preview_composite_slots::kStroke); + linear_sampler.bind(stroke_preview_composite_slots::kDual); + linear_sampler.bind(stroke_preview_composite_slots::kPattern); set_active_texture_unit(stroke_preview_composite_slots::kBackground); background_texture.bind(); set_active_texture_unit(stroke_preview_composite_slots::kStroke); @@ -223,21 +202,48 @@ pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest make_stroke_preview_ set_active_texture_unit(stroke_preview_composite_slots::kPattern); brush.m_pattern_texture ? brush.m_pattern_texture->bind() : unbind_texture_2d(); }, - .draw_mix = std::move(draw_mix), - .unbind_mixer_framebuffer = [&] { mixer_rtt.unbindFramebuffer(); }, - .restore_state = [&] { gl.restore(); }, - }; + [] {}, + [&](int, const glm::mat4& plane_mvp) { + auto uniforms = make_stroke_preview_mix_composite_uniforms(shader); + uniforms.mvp = plane_mvp; + pp::panopainter::setup_legacy_stroke_composite_shader(uniforms); + }, + [&](int) { + set_active_texture_unit(stroke_preview_composite_slots::kBackground); + background_texture.bind(); + }, + [&](int) { + set_active_texture_unit(stroke_preview_composite_slots::kStroke); + stroke_texture.bind(); + }, + [&](int) { + set_active_texture_unit(stroke_preview_composite_slots::kDual); + dual_texture.bind(); + }, + std::move(draw_mix), + [&](int) { + set_active_texture_unit(stroke_preview_composite_slots::kDual); + dual_texture.unbind(); + }, + [&](int) { + set_active_texture_unit(stroke_preview_composite_slots::kStroke); + stroke_texture.unbind(); + }, + [&](int) { + set_active_texture_unit(stroke_preview_composite_slots::kBackground); + background_texture.unbind(); + }); } -pp::panopainter::LegacyNodeStrokePreviewFinalCompositeRequest make_stroke_preview_final_composite_request( - const StrokePreviewCompositePassInputs& inputs) +void copy_stroke_preview_result_to_texture(Texture2D& texture, glm::vec2 size); + +void execute_stroke_preview_final_composite_and_copy( + const StrokePreviewCompositePassInputs& inputs, + Texture2D& preview_texture, + glm::vec2 size) { - return pp::panopainter::LegacyNodeStrokePreviewFinalCompositeRequest { - .resolution = inputs.resolution, - .pattern_scale = inputs.pattern_scale, - .brush = &inputs.brush, - .composite_pass = &inputs.composite_pass, - .setup_composite_shader = [&] { + pp::panopainter::execute_legacy_stroke_preview_final_composite( + [&] { pp::panopainter::setup_legacy_stroke_composite_shader( pp::panopainter::LegacyStrokeCompositeUniforms { .resolution = inputs.resolution, @@ -262,14 +268,14 @@ pp::panopainter::LegacyNodeStrokePreviewFinalCompositeRequest make_stroke_previe .use_pattern = inputs.composite_pass.use_pattern, }); }, - .bind_composite_samplers = [&] { + [&] { inputs.linear_sampler.bind(stroke_preview_composite_slots::kBackground); inputs.linear_sampler.bind(stroke_preview_composite_slots::kStroke); inputs.linear_sampler.bind(2U); inputs.linear_sampler.bind(stroke_preview_composite_slots::kDual); inputs.repeat_sampler.bind(stroke_preview_composite_slots::kPattern); }, - .bind_composite_inputs = [&] { + [&] { set_active_texture_unit(stroke_preview_composite_slots::kBackground); inputs.background_texture.bind(); set_active_texture_unit(stroke_preview_composite_slots::kStroke); @@ -281,28 +287,9 @@ pp::panopainter::LegacyNodeStrokePreviewFinalCompositeRequest make_stroke_previe inputs.brush.m_pattern_texture->bind() : unbind_texture_2d(); }, - .draw_composite = [&] { + [&] { inputs.draw_composite(); - }, - }; -} - -void execute_stroke_preview_final_composite_pass(const StrokePreviewCompositePassInputs& inputs) -{ - [[maybe_unused]] const bool composite_ok = - pp::panopainter::execute_legacy_node_stroke_preview_final_composite( - make_stroke_preview_final_composite_request(inputs)); - assert(composite_ok); -} - -void copy_stroke_preview_result_to_texture(Texture2D& texture, glm::vec2 size); - -void execute_stroke_preview_final_composite_and_copy( - const StrokePreviewCompositePassInputs& inputs, - Texture2D& preview_texture, - glm::vec2 size) -{ - execute_stroke_preview_final_composite_pass(inputs); + }); copy_stroke_preview_result_to_texture(preview_texture, size); } @@ -486,18 +473,14 @@ void execute_stroke_preview_background_capture_pass( Texture2D& background_texture, const std::function& draw_checkerboard) { - pp::panopainter::execute_legacy_stroke_preview_background_capture( - [&] { - const float aspect = size.x / size.y; - pp::panopainter::setup_legacy_canvas_draw_merge_checkerboard_shader( - pp::panopainter::LegacyCanvasDrawMergeCheckerboardUniforms { - .mvp = glm::ortho(-.5f, .5f, -.5f / aspect, .5f / aspect, -1.f, 1.f), - .colorize = colorize, - }); - }, - [&] { - draw_checkerboard(); - }, + const float aspect = size.x / size.y; + pp::panopainter::setup_legacy_canvas_draw_merge_checkerboard_shader( + pp::panopainter::LegacyCanvasDrawMergeCheckerboardUniforms { + .mvp = glm::ortho(-.5f, .5f, -.5f / aspect, .5f / aspect, -1.f, 1.f), + .colorize = colorize, + }); + draw_checkerboard(); + const auto copy_status = pp::paint_renderer::copy_stroke_preview_result_to_texture( [&] { background_texture.bind(); }, @@ -510,30 +493,27 @@ void execute_stroke_preview_background_capture_pass( int height) { copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height); }, - pp::panopainter::LegacyStrokePreviewCopySize { + pp::paint_renderer::StrokePreviewCopySize { .width = static_cast(size.x), .height = static_cast(size.y), }); + assert(copy_status.ok()); } void copy_stroke_preview_result_to_texture(Texture2D& preview_texture, glm::vec2 size) { - [[maybe_unused]] const bool copy_ok = - pp::panopainter::copy_legacy_node_stroke_preview_result( - pp::panopainter::LegacyNodeStrokePreviewCopyResultRequest { - .preview_texture = &preview_texture, - .size = size, - .copy_framebuffer_to_texture = []( - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height) { - copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height); - }, - }); - assert(copy_ok); + const auto result = pp::paint_renderer::copy_stroke_preview_result_to_texture( + [&] { + preview_texture.bind(); + }, + [](int src_x, int src_y, int dst_x, int dst_y, int width, int height) { + copy_framebuffer_to_texture_2d(src_x, src_y, dst_x, dst_y, width, height); + }, + pp::paint_renderer::StrokePreviewCopySize { + .width = static_cast(size.x), + .height = static_cast(size.y), + }); + assert(result.ok()); } } @@ -617,14 +597,47 @@ void NodeStrokePreview::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2 const auto& b = m_brush; const auto mix_pass = pp::panopainter::plan_legacy_node_stroke_preview_mix_pass( make_stroke_preview_mix_pass_request(*b, m_size)); + const auto mix_planes = std::array { + pp::panopainter::LegacyCanvasStrokeMixPassPlane { + .index = 0, + .visible = true, + .has_target = true, + .opacity = 1.0f, + .mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f), + }, + }; gl_state gl; - [[maybe_unused]] const bool mix_ok = pp::panopainter::execute_legacy_node_stroke_preview_mix_pass( - make_stroke_draw_mix_execution_request( - mix_pass, - gl, - bb_min, - bb_sz)); - assert(mix_ok); + const auto mix_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_with_setup( + [&] { + apply_stroke_preview_viewport(0, 0, m_rtt_mixer.getWidth(), m_rtt_mixer.getHeight()); + apply_stroke_preview_capability(pp::renderer::gl::depth_test_state(), false); + apply_stroke_preview_capability(pp::renderer::gl::scissor_test_state(), true); + apply_stroke_preview_capability(pp::renderer::gl::blend_state(), false); + apply_stroke_preview_scissor( + static_cast(bb_min.x), + static_cast(bb_min.y), + static_cast(bb_sz.x), + static_cast(bb_sz.y)); + gl.save(); + m_rtt_mixer.bindFramebuffer(); + }, + [&] { + m_rtt_mixer.unbindFramebuffer(); + gl.restore(); + }, + make_stroke_preview_mix_pass_execution_request( + mix_pass.shader, + m_rtt_mixer, + *m_brush, + m_sampler_linear, + m_tex_background, + m_tex, + m_tex_dual, + mix_planes, + [this] { + m_plane.draw_fill(); + })); + assert(mix_result.ok); } glm::vec4 NodeStrokePreview::stroke_draw_samples( @@ -792,16 +805,60 @@ void NodeStrokePreview::draw_stroke_immediate() const auto& material = pass_orchestration.material; pp::panopainter::setup_legacy_stroke_shader(pass_orchestration.stroke_shader); - const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_pass_sequence( - make_stroke_draw_immediate_pass_sequence_request( - m_stroke, - m_dual_stroke, - *b, - pass_orchestration, - dual_brush, - copy_stroke_destination, - zoom, - size)); + const bool sequence_ok = [&] { + if (pass_orchestration.material.dual_pass.enabled) { + pp::panopainter::setup_legacy_stroke_dual_shader( + pass_orchestration.material.dual_pass.uses_pattern); + bind_stroke_preview_dual_pass_textures(*dual_brush); + execute_stroke_draw_immediate_dual_pass( + m_dual_stroke, + *b, + pass_orchestration, + std::move(dual_brush), + copy_stroke_destination, + zoom, + size); + } + + execute_stroke_preview_background_capture_pass( + size, + pass_orchestration.background_colorize, + m_tex_background, + [&] { + m_plane.draw_fill(); + }); + + [[maybe_unused]] const bool main_live_ok = + pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass( + make_stroke_draw_immediate_main_live_pass_request( + m_stroke, + *b, + pass_orchestration, + copy_stroke_destination, + zoom, + size)); + if (!main_live_ok) { + return false; + } + + execute_stroke_preview_final_composite_and_copy( + StrokePreviewCompositePassInputs( + size, + glm::vec2(b->m_pattern_scale), + *b, + material.composite_pass, + m_tex_background, + m_tex, + m_tex_dual, + m_sampler_linear, + m_sampler_linear_repeat, + [&] { + m_plane.draw_fill(); + }), + m_tex_preview, + size); + return true; + }(); assert(sequence_ok); m_rtt.unbindFramebuffer(); @@ -913,79 +970,6 @@ void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass( }); } -pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest -NodeStrokePreview::make_stroke_draw_immediate_pass_sequence_request( - Stroke& stroke, - Stroke& dual_stroke, - const Brush& brush, - const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, - std::shared_ptr dual_brush, - bool copy_stroke_destination, - float zoom, - const glm::vec2& size) -{ - const auto& material = pass_orchestration.material; - return pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest { - .dual_pass_enabled = material.dual_pass.enabled, - .prepare_dual_pass = [&] { - pp::panopainter::setup_legacy_stroke_dual_shader(material.dual_pass.uses_pattern); - bind_stroke_preview_dual_pass_textures(*dual_brush); - }, - .execute_dual_pass = [&] { - execute_stroke_draw_immediate_dual_pass( - dual_stroke, - brush, - pass_orchestration, - dual_brush, - copy_stroke_destination, - zoom, - size); - }, - .capture_background = [&] { - execute_stroke_preview_background_capture_pass( - size, - pass_orchestration.background_colorize, - m_tex_background, - [&] { - m_plane.draw_fill(); - }); - }, - .prepare_main_pass = [&] {}, - .execute_main_pass = [&] { - [[maybe_unused]] const bool main_live_ok = - pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass( - make_stroke_draw_immediate_main_live_pass_request( - stroke, - brush, - pass_orchestration, - copy_stroke_destination, - zoom, - size)); - }, - .finish_main_pass = [&] {}, - .execute_final_composite = [&] { - std::function draw_composite = [&] { - m_plane.draw_fill(); - }; - execute_stroke_preview_final_composite_and_copy( - StrokePreviewCompositePassInputs( - size, - glm::vec2(brush.m_pattern_scale), - brush, - material.composite_pass, - m_tex_background, - m_tex, - m_tex_dual, - m_sampler_linear, - m_sampler_linear_repeat, - std::move(draw_composite)), - m_tex_preview, - size); - }, - .copy_preview_result = [&] {}, - }; -} - void NodeStrokePreview::execute_stroke_draw_immediate_main_live_sample_pass( const Brush& brush, bool copy_stroke_destination, @@ -1004,29 +988,6 @@ void NodeStrokePreview::execute_stroke_draw_immediate_main_live_sample_pass( }); } -pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest -NodeStrokePreview::make_stroke_draw_mix_execution_request( - const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan& mix_pass, - gl_state& gl, - const glm::vec2& bb_min, - const glm::vec2& bb_sz) -{ - return make_stroke_preview_mix_execution_request( - mix_pass.shader, - m_rtt_mixer, - *m_brush, - m_sampler_linear, - m_tex_background, - m_tex, - m_tex_dual, - gl, - bb_min, - bb_sz, - [this] { - m_plane.draw_fill(); - }); -} - Image NodeStrokePreview::render_to_image() { std::lock_guard _lock(s_render_mutex); diff --git a/src/node_stroke_preview.h b/src/node_stroke_preview.h index a809ecd1..163fe22b 100644 --- a/src/node_stroke_preview.h +++ b/src/node_stroke_preview.h @@ -74,20 +74,6 @@ public: bool copy_stroke_destination, float zoom, const glm::vec2& size); - pp::panopainter::LegacyNodeStrokePreviewPassSequenceRequest make_stroke_draw_immediate_pass_sequence_request( - Stroke& stroke, - Stroke& dual_stroke, - const Brush& brush, - const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration, - std::shared_ptr dual_brush, - bool copy_stroke_destination, - float zoom, - const glm::vec2& size); - pp::panopainter::LegacyNodeStrokePreviewMixExecutionRequest make_stroke_draw_mix_execution_request( - const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan& mix_pass, - gl_state& gl, - const glm::vec2& bb_min, - const glm::vec2& bb_sz); void draw_stroke(); void draw_stroke_immediate(); Image render_to_image();