From d69869f720275a44dfb90dc53dfcdbe6d9e8aa2c Mon Sep 17 00:00:00 2001 From: omigamedev Date: Fri, 12 Jun 2026 22:19:27 +0200 Subject: [PATCH] Route stroke preview material decisions through planner --- docs/modernization/debt.md | 4 +++ docs/modernization/roadmap.md | 6 +++-- src/node_stroke_preview.cpp | 48 +++++++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index d54c778..f860998 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -18,6 +18,10 @@ agent or engineer to remove them without reconstructing context from chat. ## Recent Reductions +- 2026-06-12: DEBT-0036 was narrowed again. `NodeStrokePreview` now consumes + the same `CanvasStrokeMaterialPlan` boundary for preview dual-brush, + each-sample pattern, and composite material decisions. Preview GL draw calls, + texture binding details, and pattern scale/offset uniforms remain retained. - 2026-06-12: DEBT-0036 was narrowed again. Live `Canvas::stroke_draw`, stroke commit, and draw-merge paths now consume `CanvasStrokeMaterialPlan` through `plan_legacy_canvas_stroke_material` for destination feedback, diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 07d076c..0676383 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -1341,8 +1341,10 @@ destination feedback/copy decisions, and `pp_paint_renderer` owns pure stroke material/pass planning for pattern, mixer, dual-brush, and final composite texture/uniform intent. Live `Canvas::stroke_draw`, stroke commit, and draw-merge paths consume that material plan for destination feedback, -each-sample pattern, dual-brush, and final composite decisions. Actual retained -OpenGL draw execution and preview material wiring remain under `DEBT-0036`. +each-sample pattern, dual-brush, and final composite decisions, and +`NodeStrokePreview` now consumes the same plan for preview material decisions. +Actual retained OpenGL draw execution and preview texture-binding details remain +under `DEBT-0036`. It also owns renderer API texture-format to OpenGL internal/pixel/component token mapping, including depth-stencil formats, for future backend texture objects. `Texture2D` 2D texture binding, upload, diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index 2248740..2b990d0 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -6,6 +6,7 @@ #include "bezier.h" #include "canvas.h" #include "app.h" +#include "legacy_canvas_stroke_services.h" #include "legacy_ui_gl_dispatch.h" #include "paint_renderer/compositor.h" #include "renderer_gl/opengl_capabilities.h" @@ -42,6 +43,25 @@ pp::paint_renderer::CanvasStrokeFeedbackPlan stroke_preview_destination_feedback return fallback; } +pp::paint_renderer::CanvasStrokeMaterialPlan stroke_preview_material_plan( + const Brush& brush, + bool destination_feedback_needed) noexcept +{ + return pp::panopainter::plan_legacy_canvas_stroke_material( + pp::paint_renderer::CanvasStrokeMaterialRequest { + .destination_feedback_needed = destination_feedback_needed, + .pattern_enabled = brush.m_pattern_enabled, + .pattern_eachsample = brush.m_pattern_eachsample, + .wet_blend = brush.m_tip_wet > 0.F, + .mix_blend = brush.m_tip_mix > 0.F, + .noise_enabled = brush.m_tip_noise > 0.F, + .dual_brush_enabled = brush.m_dual_enabled, + .dual_blend_mode = brush.m_dual_blend_mode, + .pattern_blend_mode = brush.m_pattern_blend_mode, + .dual_alpha = brush.m_dual_opacity, + }); +} + void set_active_texture_unit(std::uint32_t unit_index) { pp::legacy::ui_gl::activate_texture_unit(unit_index, "NodeStrokePreview"); @@ -194,17 +214,18 @@ void NodeStrokePreview::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2 ShaderManager::u_int(kShaderUniform::UseFragcoord, false); ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - ShaderManager::u_int(kShaderUniform::UseDual, b->m_dual_enabled); - ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && !b->m_pattern_eachsample); - ShaderManager::u_int(kShaderUniform::DualBlendMode, b->m_dual_blend_mode); + const auto material = stroke_preview_material_plan(*b, false); + ShaderManager::u_int(kShaderUniform::UseDual, material.composite_pass.use_dual); + ShaderManager::u_int(kShaderUniform::UsePattern, material.composite_pass.use_pattern); + ShaderManager::u_int(kShaderUniform::DualBlendMode, material.composite_pass.dual_blend_mode); ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale); ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert); ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness); ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast); ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth); - ShaderManager::u_int(kShaderUniform::PatternBlendMode, b->m_pattern_blend_mode); + ShaderManager::u_int(kShaderUniform::PatternBlendMode, material.composite_pass.pattern_blend_mode); ShaderManager::u_vec2(kShaderUniform::PatternOffset, glm::vec2(b->m_pattern_rand_offset ? 0.5f : 0.0f)); - ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity); + ShaderManager::u_float(kShaderUniform::DualAlpha, material.composite_pass.dual_alpha); m_sampler_linear.bind(0); set_active_texture_unit(0U); @@ -431,6 +452,7 @@ void NodeStrokePreview::draw_stroke_immediate() ShaderManager::u_int(kShaderUniform::Tex, 0); // brush const auto stroke_feedback = stroke_preview_destination_feedback_plan(m_rtt.getWidth(), m_rtt.getHeight()); const bool copy_stroke_destination = !stroke_feedback.reads_destination_color; + const auto material = stroke_preview_material_plan(*b, copy_stroke_destination); if (copy_stroke_destination) ShaderManager::u_int(kShaderUniform::TexBG, 1); // bg ShaderManager::u_int(kShaderUniform::TexPattern, 2); // pattern @@ -448,11 +470,11 @@ void NodeStrokePreview::draw_stroke_immediate() // DRAW DUAL BRUSH - if (b->m_dual_enabled) + if (material.dual_pass.enabled) { m_rtt.clear(); ShaderManager::use(kShader::Stroke); - ShaderManager::u_int(kShaderUniform::UsePattern, false); + ShaderManager::u_int(kShaderUniform::UsePattern, material.dual_pass.uses_pattern); ShaderManager::u_float(kShaderUniform::MixAlpha, 0); ShaderManager::u_float(kShaderUniform::Wet, 0); ShaderManager::u_float(kShaderUniform::Noise, 0); @@ -502,7 +524,7 @@ void NodeStrokePreview::draw_stroke_immediate() // DRAW MAIN BRUSH ShaderManager::use(kShader::Stroke); - ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && b->m_pattern_eachsample); + ShaderManager::u_int(kShaderUniform::UsePattern, material.stroke_pass.uses_pattern); ShaderManager::u_float(kShaderUniform::MixAlpha, b->m_tip_mix); ShaderManager::u_float(kShaderUniform::Wet, b->m_tip_wet); ShaderManager::u_float(kShaderUniform::Noise, b->m_tip_noise); @@ -566,17 +588,17 @@ void NodeStrokePreview::draw_stroke_immediate() ShaderManager::u_int(kShaderUniform::Mask, false); ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode); ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f)); - ShaderManager::u_int(kShaderUniform::UseDual, b->m_dual_enabled); - ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && !b->m_pattern_eachsample); - ShaderManager::u_int(kShaderUniform::DualBlendMode, b->m_dual_blend_mode); + ShaderManager::u_int(kShaderUniform::UseDual, material.composite_pass.use_dual); + ShaderManager::u_int(kShaderUniform::UsePattern, material.composite_pass.use_pattern); + ShaderManager::u_int(kShaderUniform::DualBlendMode, material.composite_pass.dual_blend_mode); ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale); ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert); ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness); ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast); ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth); - ShaderManager::u_int(kShaderUniform::PatternBlendMode, b->m_pattern_blend_mode); + ShaderManager::u_int(kShaderUniform::PatternBlendMode, material.composite_pass.pattern_blend_mode); ShaderManager::u_vec2(kShaderUniform::PatternOffset, glm::vec2(b->m_pattern_rand_offset ? 0.5f : 0.0f)); - ShaderManager::u_float(kShaderUniform::DualAlpha, b->m_dual_opacity); + ShaderManager::u_float(kShaderUniform::DualAlpha, material.composite_pass.dual_alpha); m_sampler_linear.bind(0); m_sampler_linear.bind(1);