Extract final canvas wrappers and preview mix pass

This commit is contained in:
2026-06-16 23:02:05 +02:00
parent 5f76716732
commit a8e4e02e94
14 changed files with 458 additions and 604 deletions

View File

@@ -1,256 +1,5 @@
#include "pch.h"
#include "log.h"
#include "canvas.h"
#include "legacy_canvas_render_shell_services.h"
#include "legacy_ui_gl_dispatch.h"
#include "legacy_canvas_stroke_erase_services.h"
#include "legacy_gl_renderbuffer_dispatch.h"
#include "legacy_canvas_stroke_commit_services.h"
#include "legacy_canvas_stroke_composite_services.h"
#include "legacy_canvas_stroke_edge_services.h"
#include "legacy_canvas_stroke_execution_services.h"
#include "legacy_canvas_stroke_runtime_services.h"
#include "legacy_canvas_stroke_shader_services.h"
#include "legacy_canvas_object_draw_services.h"
#include "legacy_canvas_projection_services.h"
#include "legacy_canvas_stroke_services.h"
#include "legacy_ui_overlay_services.h"
#include "app_core/document_canvas.h"
#include "texture.h"
#include "node_progress_bar.h"
#include "paint_renderer/compositor.h"
#include "renderer_gl/opengl_capabilities.h"
#include "util.h"
#include <array>
#include <condition_variable>
#include <deque>
#include <mutex>
#include <stop_token>
#include <thread>
#include <algorithm>
#include <cstdint>
#include <numeric>
#ifdef __APPLE__
#include <Foundation/Foundation.h>
#endif
namespace {
GLint current_canvas_stroke_internal_format()
{
const auto renderer_features = ShaderManager::render_device_features();
if (renderer_features.float32_linear_filtering)
return static_cast<GLint>(pp::renderer::gl::rgba32f_internal_format());
if (renderer_features.float16_render_targets)
return static_cast<GLint>(pp::renderer::gl::rgba16f_internal_format());
return static_cast<GLint>(pp::renderer::gl::rgba8_internal_format());
}
GLint rgba8_internal_format()
{
return static_cast<GLint>(pp::renderer::gl::rgba8_internal_format());
}
pp::renderer::RenderDeviceFeatures canvas_render_device_features() noexcept
{
return ShaderManager::render_device_features();
}
pp::paint_renderer::CanvasStrokeRasterizationPlan canvas_stroke_rasterization_plan(
int width,
int height) noexcept
{
return pp::panopainter::plan_legacy_canvas_stroke_rasterization(
canvas_render_device_features(),
width,
height);
}
pp::paint_renderer::CanvasStrokeFeedbackPlan canvas_destination_feedback_plan(
int width,
int height) noexcept
{
return canvas_stroke_rasterization_plan(width, height).feedback;
}
pp::paint_renderer::CanvasStrokeMaterialPlan canvas_stroke_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,
});
}
pp::renderer::Extent2D canvas_stroke_extent(int width, int height) noexcept
{
return pp::renderer::Extent2D {
.width = static_cast<std::uint32_t>(std::max(width, 0)),
.height = static_cast<std::uint32_t>(std::max(height, 0)),
};
}
pp::paint_renderer::CanvasBlendGatePlan draw_merge_blend_gate_plan(
int width,
int height,
const std::vector<std::shared_ptr<Layer>>& layers,
const Brush* brush) noexcept
{
std::vector<int> layer_blend_modes;
layer_blend_modes.reserve(layers.size());
for (const auto& layer : layers) {
if (!layer) {
continue;
}
layer_blend_modes.push_back(layer->m_blend_mode);
}
const auto plan = pp::paint_renderer::plan_canvas_blend_gate(
canvas_render_device_features(),
pp::paint_renderer::CanvasBlendGateRequest {
.extent = pp::renderer::Extent2D {
.width = static_cast<std::uint32_t>(std::max(width, 0)),
.height = static_cast<std::uint32_t>(std::max(height, 0)),
},
.layer_blend_modes = layer_blend_modes,
.has_stroke_blend_mode = brush != nullptr,
.stroke_blend_mode = brush ? brush->m_blend_mode : 0,
});
if (plan) {
return plan.value();
}
pp::paint_renderer::CanvasBlendGatePlan fallback;
fallback.shader_blend = true;
fallback.complex_blend = true;
fallback.compatibility_fallback = true;
return fallback;
}
GLenum depth_test_state()
{
return static_cast<GLenum>(pp::renderer::gl::depth_test_state());
}
GLenum scissor_test_state()
{
return static_cast<GLenum>(pp::renderer::gl::scissor_test_state());
}
GLenum blend_state()
{
return static_cast<GLenum>(pp::renderer::gl::blend_state());
}
GLint texture_filter_linear()
{
return static_cast<GLint>(pp::renderer::gl::linear_texture_filter());
}
GLint texture_filter_linear_mipmap_linear()
{
return static_cast<GLint>(pp::renderer::gl::linear_mipmap_linear_texture_filter());
}
GLint texture_filter_nearest()
{
return static_cast<GLint>(pp::renderer::gl::nearest_texture_filter());
}
GLint texture_wrap_repeat()
{
return static_cast<GLint>(pp::renderer::gl::repeat_texture_wrap());
}
GLint texture_wrap_clamp_to_border()
{
return static_cast<GLint>(pp::renderer::gl::clamp_to_border_texture_wrap());
}
pp::renderer::gl::OpenGlPixelFormat texture_format_for_image_channels(int channel_count)
{
return pp::renderer::gl::texture_format_for_channel_count(static_cast<std::uint32_t>(channel_count));
}
void set_active_texture_unit(std::uint32_t unit_index)
{
pp::legacy::ui_gl::activate_texture_unit(unit_index, "Canvas");
}
void unbind_texture_2d()
{
pp::legacy::ui_gl::unbind_texture_2d("Canvas");
}
void apply_canvas_viewport(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
{
pp::legacy::ui_gl::apply_viewport(x, y, width, height, "Canvas");
}
pp::renderer::gl::OpenGlViewportRect query_canvas_viewport()
{
return pp::legacy::ui_gl::query_viewport_rect("Canvas");
}
std::array<float, 4> query_canvas_clear_color()
{
return pp::legacy::ui_gl::query_clear_color("Canvas");
}
void apply_canvas_clear_color(std::array<float, 4> color)
{
pp::legacy::ui_gl::set_clear_color(color, "Canvas");
}
void apply_canvas_scissor(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height)
{
pp::legacy::ui_gl::apply_scissor_rect(x, y, width, height, "Canvas");
}
void apply_canvas_capability(std::uint32_t state, bool enabled)
{
pp::legacy::ui_gl::set_capability(state, enabled, "Canvas");
}
bool query_canvas_capability(std::uint32_t state)
{
return pp::legacy::ui_gl::query_capability(state, "Canvas");
}
GLuint allocate_canvas_depth_renderbuffer(int width, int height)
{
return static_cast<GLuint>(pp::legacy::gl_renderbuffer::allocate_depth_renderbuffer(
width,
height,
"OpenGL canvas depth renderbuffer allocation"));
}
void attach_canvas_depth_renderbuffer(GLuint renderbuffer)
{
pp::legacy::gl_renderbuffer::attach_depth_renderbuffer(
static_cast<std::uint32_t>(renderbuffer),
"OpenGL canvas depth renderbuffer attachment");
}
void delete_canvas_renderbuffer(GLuint renderbuffer)
{
pp::legacy::gl_renderbuffer::delete_renderbuffer(
static_cast<std::uint32_t>(renderbuffer),
"OpenGL canvas renderbuffer delete");
}
}
Canvas* Canvas::I;
std::vector<CanvasMode*> Canvas::modes[] = {
@@ -267,154 +16,3 @@ std::vector<CanvasMode*> Canvas::modes[] = {
{ new CanvasModeMaskLine, new CanvasModeBasicCamera }, // mask-poly
{ new CanvasModeFloodFill, new CanvasModeBasicCamera }, // flood-fill
};
void Canvas::stroke_end() { pp::panopainter::legacy_canvas_stroke_end(*this); }
void Canvas::stroke_cancel() { pp::panopainter::legacy_canvas_stroke_cancel(*this); }
void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
{
pp::panopainter::legacy_canvas_stroke_draw_mix(*this, bb_min, bb_sz);
}
std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vertex_t, 4>& B, bool project_3d /*= false*/, glm::mat4 mv /*= glm::mat4(1)*/) const
{
return pp::panopainter::legacy_canvas_stroke_draw_project(*this, B, project_3d, mv);
}
void Canvas::draw_merge_temporary_paint_branch(
int layer_index,
int plane_index,
std::shared_ptr<Layer> layer,
const Brush& brush,
const glm::mat4& ortho)
{
pp::panopainter::legacy_canvas_draw_merge_temporary_paint_branch(
*this,
layer_index,
plane_index,
std::move(layer),
brush,
ortho);
}
void Canvas::draw_merge_branch_orchestration(
int plane_index,
int layer_index,
const std::shared_ptr<Layer>& layer,
const Brush& brush,
const glm::mat4& ortho,
bool use_blend,
bool copy_blend_destination)
{
pp::panopainter::legacy_canvas_draw_merge_branch_orchestration(
*this,
plane_index,
layer_index,
layer,
brush,
ortho,
use_blend,
copy_blend_destination);
}
void Canvas::draw_merge_final_plane_composite(
const glm::mat4& ortho,
bool draw_checkerboard)
{
pp::panopainter::legacy_canvas_draw_merge_final_plane_composite(
*this,
ortho,
draw_checkerboard);
}
void Canvas::stroke_draw()
{
stroke_draw_live();
}
bool Canvas::point_trace(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec2& fb_pos, glm::vec3& hit_normal, int& out_plane_id)
{
return pp::panopainter::legacy_canvas_point_trace(*this, loc, ray_origin, ray_dir, hit_pos, fb_pos, hit_normal, out_plane_id);
}
/*
bool Canvas::point_trace_plane(glm::vec2 loc, glm::vec3& hit_pos, glm::vec2& hit_fb_pos, int plane_id)
{
auto ln = (loc / zw(m_box)) * 2.f - 1.f;
auto p = m_plane_unproject[plane_id] * glm::vec4(ln, 1, 1);
if (p.w <= 0)
{
return true;
}
return false;
}
*/
bool Canvas::point_trace_plane(glm::vec2 loc, glm::vec3& ray_origin, glm::vec3& ray_dir,
glm::vec3& hit_pos, glm::vec3& hit_normal, glm::vec2& hit_fb_pos, int plane_id)
{
return pp::panopainter::legacy_canvas_point_trace_plane(*this, loc, ray_origin, ray_dir, hit_pos, hit_normal, hit_fb_pos, plane_id);
}
void Canvas::point_unproject(glm::vec2 loc, glm::vec4 vp, glm::mat4 camera, glm::mat4 proj,
glm::vec3& out_origin, glm::vec3& out_dir)
{
pp::panopainter::legacy_canvas_point_unproject(loc, vp, camera, proj, out_origin, out_dir);
}
void Canvas::point_unproject(glm::vec2 loc, glm::vec3& out_origin, glm::vec3& out_dir)
{
pp::panopainter::legacy_canvas_point_unproject(*this, loc, out_origin, out_dir);
}
glm::vec3 Canvas::point_trace(glm::vec2 loc)
{
return pp::panopainter::legacy_canvas_point_trace(*this, loc);
}
void Canvas::stroke_commit_timelapse()
{
pp::panopainter::legacy_canvas_stroke_commit_timelapse(*this);
}
void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SIXPLETTE(true)*/)
{
pp::panopainter::legacy_canvas_draw_merge(*this, draw_checkerboard, faces);
}
void Canvas::stroke_update(glm::vec3 point, float pressure) { pp::panopainter::legacy_canvas_stroke_update(*this, point, pressure); }
void Canvas::stroke_start(glm::vec3 point, float pressure) { pp::panopainter::legacy_canvas_stroke_start(*this, point, pressure); }
void Canvas::destroy()
{
pp::panopainter::legacy_canvas_destroy(*this);
}
bool Canvas::create(int width, int height)
{
return pp::panopainter::legacy_canvas_create(*this, width, height);
}
void Canvas::clear_context()
{
pp::panopainter::legacy_canvas_clear_context(*this);
}
void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer, int frame)
{
pp::panopainter::legacy_canvas_draw_objects_direct(*this, std::move(observer), layer, frame);
}
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer, int frame, bool save_history)
{
pp::panopainter::legacy_canvas_draw_objects(*this, std::move(observer), layer, frame, save_history);
}
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, int frame, bool save_history)
{
draw_objects(observer, layer(), frame, save_history);
}
void Canvas::project2Dpoints(std::vector<vertex_t>& vertices)
{
pp::panopainter::legacy_canvas_project_2d_points(*this, vertices);
}
glm::vec3 Canvas::project2Dpoint(glm::vec2 pt)
{
return pp::panopainter::legacy_canvas_project_2d_point(*this, pt);
}

View File

@@ -118,6 +118,34 @@ void LegacyBrushPresetPanelUi::init(NodePanelBrushPreset& owner)
owner.m_notification->SetVisibility(owner.m_container->m_children.size() == 0);
}
kEventResult LegacyBrushPresetPanelUi::handle_event(NodePanelBrushPreset& owner, Event* event)
{
switch (event->m_type)
{
case kEventType::MouseLeave:
if (!owner.m_interacted)
break;
// else fall through
case kEventType::MouseUpL:
if (!owner.m_mouse_inside)
{
pp::panopainter::release_legacy_mouse_capture(owner);
if (owner.m_parent)
{
pp::panopainter::detach_legacy_node_from_parent(owner);
}
if (owner.on_popup_close)
{
owner.on_popup_close(&owner);
}
}
break;
default:
return kEventResult::Available;
}
return kEventResult::Consumed;
}
void LegacyBrushPresetPanelUi::handle_click(NodePanelBrushPreset& owner, Node* target)
{
const int idx = owner.m_container->get_child_index(target);

View File

@@ -7,6 +7,7 @@ namespace pp::panopainter {
class LegacyBrushPresetPanelUi final {
public:
static void init(NodePanelBrushPreset& owner);
static kEventResult handle_event(NodePanelBrushPreset& owner, Event* event);
static void handle_click(NodePanelBrushPreset& owner, Node* target);
static void add_brush(NodePanelBrushPreset& owner, std::shared_ptr<Brush> brush);
static void added(NodePanelBrushPreset& owner);

View File

@@ -219,3 +219,28 @@ void legacy_canvas_draw_objects(
}
} // namespace pp::panopainter
void Canvas::draw_objects_direct(
std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer,
Layer& layer,
int frame)
{
pp::panopainter::legacy_canvas_draw_objects_direct(*this, std::move(observer), layer, frame);
}
void Canvas::draw_objects(
std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer,
Layer& layer,
int frame,
bool save_history)
{
pp::panopainter::legacy_canvas_draw_objects(*this, std::move(observer), layer, frame, save_history);
}
void Canvas::draw_objects(
std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer,
int frame,
bool save_history)
{
draw_objects(std::move(observer), layer(), frame, save_history);
}

View File

@@ -177,3 +177,58 @@ void legacy_canvas_set_camera(Canvas& canvas, const CameraData& camera)
}
} // namespace pp::panopainter
bool Canvas::point_trace(
glm::vec2 loc,
glm::vec3& ray_origin,
glm::vec3& ray_dir,
glm::vec3& hit_pos,
glm::vec2& fb_pos,
glm::vec3& hit_normal,
int& out_plane_id)
{
return pp::panopainter::legacy_canvas_point_trace(*this, loc, ray_origin, ray_dir, hit_pos, fb_pos, hit_normal, out_plane_id);
}
bool Canvas::point_trace_plane(
glm::vec2 loc,
glm::vec3& ray_origin,
glm::vec3& ray_dir,
glm::vec3& hit_pos,
glm::vec3& hit_normal,
glm::vec2& hit_fb_pos,
int plane_id)
{
return pp::panopainter::legacy_canvas_point_trace_plane(*this, loc, ray_origin, ray_dir, hit_pos, hit_normal, hit_fb_pos, plane_id);
}
void Canvas::point_unproject(
glm::vec2 loc,
glm::vec4 vp,
glm::mat4 camera,
glm::mat4 proj,
glm::vec3& out_origin,
glm::vec3& out_dir)
{
pp::panopainter::legacy_canvas_point_unproject(loc, vp, camera, proj, out_origin, out_dir);
}
void Canvas::point_unproject(glm::vec2 loc, glm::vec3& out_origin, glm::vec3& out_dir)
{
pp::panopainter::legacy_canvas_point_unproject(*this, loc, out_origin, out_dir);
}
glm::vec3 Canvas::point_trace(glm::vec2 loc)
{
return pp::panopainter::legacy_canvas_point_trace(*this, loc);
}
void Canvas::project2Dpoints(std::vector<vertex_t>& vertices)
{
pp::panopainter::legacy_canvas_project_2d_points(*this, vertices);
}
glm::vec3 Canvas::project2Dpoint(glm::vec2 pt)
{
return pp::panopainter::legacy_canvas_project_2d_point(*this, pt);
}

View File

@@ -19,6 +19,7 @@
#include <array>
#include <chrono>
#include <cstdint>
#include <utility>
namespace {
@@ -725,3 +726,71 @@ void legacy_canvas_render_shell_set_camera(Canvas& canvas, const CameraData& cam
}
} // namespace pp::panopainter
void Canvas::draw_merge_temporary_paint_branch(
int layer_index,
int plane_index,
std::shared_ptr<Layer> layer,
const Brush& brush,
const glm::mat4& ortho)
{
pp::panopainter::legacy_canvas_draw_merge_temporary_paint_branch(
*this,
layer_index,
plane_index,
std::move(layer),
brush,
ortho);
}
void Canvas::draw_merge_branch_orchestration(
int plane_index,
int layer_index,
const std::shared_ptr<Layer>& layer,
const Brush& brush,
const glm::mat4& ortho,
bool use_blend,
bool copy_blend_destination)
{
pp::panopainter::legacy_canvas_draw_merge_branch_orchestration(
*this,
plane_index,
layer_index,
layer,
brush,
ortho,
use_blend,
copy_blend_destination);
}
void Canvas::draw_merge_final_plane_composite(
const glm::mat4& ortho,
bool draw_checkerboard)
{
pp::panopainter::legacy_canvas_draw_merge_final_plane_composite(*this, ortho, draw_checkerboard);
}
void Canvas::stroke_commit_timelapse()
{
pp::panopainter::legacy_canvas_stroke_commit_timelapse(*this);
}
void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SIXPLETTE(true)*/)
{
pp::panopainter::legacy_canvas_draw_merge(*this, draw_checkerboard, faces);
}
void Canvas::destroy()
{
pp::panopainter::legacy_canvas_destroy(*this);
}
bool Canvas::create(int width, int height)
{
return pp::panopainter::legacy_canvas_create(*this, width, height);
}
void Canvas::clear_context()
{
pp::panopainter::legacy_canvas_clear_context(*this);
}

View File

@@ -612,3 +612,8 @@ void Canvas::stroke_draw_live()
m_current_stroke = nullptr;
}
}
void Canvas::stroke_draw()
{
stroke_draw_live();
}

View File

@@ -334,3 +334,36 @@ void legacy_canvas_stroke_start(Canvas& canvas, glm::vec3 point, float pressure)
}
} // namespace pp::panopainter
void Canvas::stroke_end()
{
pp::panopainter::legacy_canvas_stroke_end(*this);
}
void Canvas::stroke_cancel()
{
pp::panopainter::legacy_canvas_stroke_cancel(*this);
}
void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
{
pp::panopainter::legacy_canvas_stroke_draw_mix(*this, bb_min, bb_sz);
}
std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(
std::array<vertex_t, 4>& B,
bool project_3d /*= false*/,
glm::mat4 mv /*= glm::mat4(1)*/) const
{
return pp::panopainter::legacy_canvas_stroke_draw_project(*this, B, project_3d, mv);
}
void Canvas::stroke_update(glm::vec3 point, float pressure)
{
pp::panopainter::legacy_canvas_stroke_update(*this, point, pressure);
}
void Canvas::stroke_start(glm::vec3 point, float pressure)
{
pp::panopainter::legacy_canvas_stroke_start(*this, point, pressure);
}

View File

@@ -1,11 +1,192 @@
#include "pch.h"
#include "legacy_node_stroke_preview_draw_services.h"
#include "legacy_canvas_stroke_composite_services.h"
#include "legacy_canvas_stroke_execution_services.h"
#include "legacy_ui_gl_dispatch.h"
#include "renderer_gl/opengl_capabilities.h"
#include "util.h"
#include <array>
namespace pp::panopainter {
namespace {
namespace stroke_preview_composite_slots {
constexpr std::uint32_t kBackground = 0U;
constexpr std::uint32_t kStroke = 1U;
constexpr std::uint32_t kDual = 3U;
constexpr std::uint32_t kPattern = 4U;
}
pp::panopainter::LegacyStrokeCompositeUniforms make_stroke_preview_mix_composite_uniforms(
const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader_plan) noexcept
{
return {
.resolution = shader_plan.resolution,
.pattern = {
.scale = shader_plan.pattern_scale,
.invert = shader_plan.pattern_invert,
.brightness = shader_plan.pattern_brightness,
.contrast = shader_plan.pattern_contrast,
.depth = shader_plan.pattern_depth,
.blend_mode = shader_plan.pattern_blend_mode,
.offset = shader_plan.pattern_offset,
},
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
.layer_alpha = 1.0f,
.alpha_lock = false,
.mask_enabled = false,
.use_fragcoord = false,
.blend_mode = shader_plan.blend_mode,
.use_dual = shader_plan.use_dual,
.dual_blend_mode = shader_plan.dual_blend_mode,
.dual_alpha = shader_plan.dual_alpha,
.use_pattern = shader_plan.use_pattern,
};
}
pp::panopainter::LegacyCanvasStrokeMixPassRequest make_stroke_preview_mix_pass_execution_request(
const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader,
RTT& mixer_rtt,
const Brush& brush,
Sampler& linear_sampler,
Texture2D& background_texture,
Texture2D& stroke_texture,
Texture2D& dual_texture,
std::span<const pp::panopainter::LegacyCanvasStrokeMixPassPlane> mix_planes,
std::function<void()> draw_mix)
{
return pp::panopainter::make_legacy_canvas_stroke_mix_pass_request(
"NodeStrokePreview::stroke_draw_mix",
glm::vec2(static_cast<float>(mixer_rtt.getWidth()), static_cast<float>(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);
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kBackground, "NodeStrokePreview");
background_texture.bind();
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kStroke, "NodeStrokePreview");
stroke_texture.bind();
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kDual, "NodeStrokePreview");
dual_texture.bind();
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kPattern, "NodeStrokePreview");
brush.m_pattern_texture ? brush.m_pattern_texture->bind() : pp::legacy::ui_gl::unbind_texture_2d("NodeStrokePreview");
},
[] {},
[&](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) {
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kBackground, "NodeStrokePreview");
background_texture.bind();
},
[&](int) {
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kStroke, "NodeStrokePreview");
stroke_texture.bind();
},
[&](int) {
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kDual, "NodeStrokePreview");
dual_texture.bind();
},
std::move(draw_mix),
[&](int) {
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kDual, "NodeStrokePreview");
dual_texture.unbind();
},
[&](int) {
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kStroke, "NodeStrokePreview");
stroke_texture.unbind();
},
[&](int) {
pp::legacy::ui_gl::activate_texture_unit(stroke_preview_composite_slots::kBackground, "NodeStrokePreview");
background_texture.unbind();
});
}
} // namespace
bool execute_legacy_node_stroke_preview_mix_pass(
const LegacyNodeStrokePreviewMixPassExecutionRequest& request)
{
if (!request.draw_mix) {
return false;
}
const auto mix_pass = pp::panopainter::plan_legacy_node_stroke_preview_mix_pass(
pp::panopainter::LegacyNodeStrokePreviewMixPassRequest {
.resolution = request.preview_size,
.pattern_scale = request.brush.m_pattern_scale,
.pattern_flipx = request.brush.m_pattern_flipx,
.pattern_flipy = request.brush.m_pattern_flipy,
.pattern_invert = request.brush.m_pattern_invert,
.pattern_brightness = request.brush.m_pattern_brightness,
.pattern_contrast = request.brush.m_pattern_contrast,
.pattern_depth = request.brush.m_pattern_depth,
.pattern_rand_offset = request.brush.m_pattern_rand_offset,
.pattern_enabled = request.brush.m_pattern_enabled,
.pattern_eachsample = request.brush.m_pattern_eachsample,
.tip_wet = request.brush.m_tip_wet,
.tip_mix = request.brush.m_tip_mix,
.tip_noise = request.brush.m_tip_noise,
.dual_enabled = request.brush.m_dual_enabled,
.dual_blend_mode = request.brush.m_dual_blend_mode,
.pattern_blend_mode = request.brush.m_pattern_blend_mode,
.dual_opacity = request.brush.m_dual_opacity,
.blend_mode = request.brush.m_blend_mode,
});
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;
const auto mix_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_with_setup(
[&] {
pp::legacy::ui_gl::apply_viewport(
0,
0,
request.mixer_rtt.getWidth(),
request.mixer_rtt.getHeight(),
"NodeStrokePreview");
pp::legacy::ui_gl::set_capability(pp::renderer::gl::depth_test_state(), false, "NodeStrokePreview");
pp::legacy::ui_gl::set_capability(pp::renderer::gl::scissor_test_state(), true, "NodeStrokePreview");
pp::legacy::ui_gl::set_capability(pp::renderer::gl::blend_state(), false, "NodeStrokePreview");
pp::legacy::ui_gl::apply_scissor_rect(
static_cast<std::int32_t>(request.bb_min.x),
static_cast<std::int32_t>(request.bb_min.y),
static_cast<std::int32_t>(request.bb_sz.x),
static_cast<std::int32_t>(request.bb_sz.y),
"NodeStrokePreview");
gl.save();
request.mixer_rtt.bindFramebuffer();
},
[&] {
request.mixer_rtt.unbindFramebuffer();
gl.restore();
},
make_stroke_preview_mix_pass_execution_request(
mix_pass.shader,
request.mixer_rtt,
request.brush,
request.linear_sampler,
request.background_texture,
request.stroke_texture,
request.dual_texture,
mix_planes,
request.draw_mix));
return mix_result.ok;
}
bool has_valid_live_render_callbacks(const LegacyNodeStrokePreviewLiveRenderRequest& request)
{
return request.bind_dual_pass_textures &&
@@ -18,8 +199,6 @@ bool has_valid_live_render_callbacks(const LegacyNodeStrokePreviewLiveRenderRequ
request.draw_composite;
}
} // namespace
bool execute_legacy_node_stroke_preview_live_render_passes(
const LegacyNodeStrokePreviewLiveRenderRequest& request)
{

View File

@@ -45,6 +45,22 @@ struct LegacyNodeStrokePreviewLiveRenderRequest {
std::function<void()> draw_composite;
};
struct LegacyNodeStrokePreviewMixPassExecutionRequest {
const Brush& brush;
glm::vec2 preview_size {};
RTT& mixer_rtt;
glm::vec2 bb_min {};
glm::vec2 bb_sz {};
Sampler& linear_sampler;
Texture2D& background_texture;
Texture2D& stroke_texture;
Texture2D& dual_texture;
std::function<void()> draw_mix;
};
[[nodiscard]] bool execute_legacy_node_stroke_preview_mix_pass(
const LegacyNodeStrokePreviewMixPassExecutionRequest& request);
[[nodiscard]] bool execute_legacy_node_stroke_preview_live_render_passes(
const LegacyNodeStrokePreviewLiveRenderRequest& request);

View File

@@ -213,31 +213,7 @@ void NodePanelBrushPreset::init()
kEventResult NodePanelBrushPreset::handle_event(Event* e)
{
switch (e->m_type)
{
case kEventType::MouseLeave:
if (!m_interacted)
break;
// else fall through
case kEventType::MouseUpL:
if (!m_mouse_inside)
{
pp::panopainter::release_legacy_mouse_capture(*this);
if (m_parent)
{
pp::panopainter::detach_legacy_node_from_parent(*this);
}
if (on_popup_close)
{
on_popup_close(this);
}
}
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
return pp::panopainter::LegacyBrushPresetPanelUi::handle_event(*this, e);
}
void NodePanelBrushPreset::handle_click(Node* target)

View File

@@ -7,7 +7,6 @@
#include "canvas.h"
#include "app.h"
#include "legacy_canvas_draw_merge_services.h"
#include "legacy_canvas_stroke_composite_services.h"
#include "legacy_canvas_stroke_execution_services.h"
#include "legacy_canvas_stroke_preview_services.h"
#include "legacy_canvas_stroke_shader_services.h"
@@ -69,13 +68,6 @@ void apply_stroke_preview_capability(std::uint32_t state, bool enabled)
pp::legacy::ui_gl::set_capability(state, enabled, "NodeStrokePreview");
}
namespace stroke_preview_composite_slots {
constexpr std::uint32_t kBackground = 0U;
constexpr std::uint32_t kStroke = 1U;
constexpr std::uint32_t kDual = 3U;
constexpr std::uint32_t kPattern = 4U;
}
namespace stroke_preview_live_slots {
constexpr std::uint32_t kTip = 0U;
constexpr std::uint32_t kDestination = 1U;
@@ -84,122 +76,6 @@ constexpr std::uint32_t kMixer = 3U;
constexpr std::uint32_t kReservedLinear = 4U;
}
pp::panopainter::LegacyNodeStrokePreviewMixPassRequest make_stroke_preview_mix_pass_request(
const Brush& brush,
glm::vec2 resolution) noexcept
{
return {
.resolution = resolution,
.pattern_scale = brush.m_pattern_scale,
.pattern_flipx = brush.m_pattern_flipx,
.pattern_flipy = brush.m_pattern_flipy,
.pattern_invert = brush.m_pattern_invert,
.pattern_brightness = brush.m_pattern_brightness,
.pattern_contrast = brush.m_pattern_contrast,
.pattern_depth = brush.m_pattern_depth,
.pattern_rand_offset = brush.m_pattern_rand_offset,
.pattern_enabled = brush.m_pattern_enabled,
.pattern_eachsample = brush.m_pattern_eachsample,
.tip_wet = brush.m_tip_wet,
.tip_mix = brush.m_tip_mix,
.tip_noise = brush.m_tip_noise,
.dual_enabled = brush.m_dual_enabled,
.dual_blend_mode = brush.m_dual_blend_mode,
.pattern_blend_mode = brush.m_pattern_blend_mode,
.dual_opacity = brush.m_dual_opacity,
.blend_mode = brush.m_blend_mode,
};
}
pp::panopainter::LegacyStrokeCompositeUniforms make_stroke_preview_mix_composite_uniforms(
const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader_plan) noexcept
{
return {
.resolution = shader_plan.resolution,
.pattern = {
.scale = shader_plan.pattern_scale,
.invert = shader_plan.pattern_invert,
.brightness = shader_plan.pattern_brightness,
.contrast = shader_plan.pattern_contrast,
.depth = shader_plan.pattern_depth,
.blend_mode = shader_plan.pattern_blend_mode,
.offset = shader_plan.pattern_offset,
},
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
.layer_alpha = 1.0f,
.alpha_lock = false,
.mask_enabled = false,
.use_fragcoord = false,
.blend_mode = shader_plan.blend_mode,
.use_dual = shader_plan.use_dual,
.dual_blend_mode = shader_plan.dual_blend_mode,
.dual_alpha = shader_plan.dual_alpha,
.use_pattern = shader_plan.use_pattern,
};
}
pp::panopainter::LegacyCanvasStrokeMixPassRequest make_stroke_preview_mix_pass_execution_request(
const pp::panopainter::LegacyNodeStrokePreviewMixPassPlan::ShaderPlan& shader,
RTT& mixer_rtt,
const Brush& brush,
Sampler& linear_sampler,
Texture2D& background_texture,
Texture2D& stroke_texture,
Texture2D& dual_texture,
std::span<const pp::panopainter::LegacyCanvasStrokeMixPassPlane> mix_planes,
std::function<void()> draw_mix)
{
return pp::panopainter::make_legacy_canvas_stroke_mix_pass_request(
"NodeStrokePreview::stroke_draw_mix",
glm::vec2(static_cast<float>(mixer_rtt.getWidth()), static_cast<float>(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);
stroke_texture.bind();
set_active_texture_unit(stroke_preview_composite_slots::kDual);
dual_texture.bind();
set_active_texture_unit(stroke_preview_composite_slots::kPattern);
brush.m_pattern_texture ? brush.m_pattern_texture->bind() : unbind_texture_2d();
},
[] {},
[&](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();
});
}
void bind_stroke_preview_live_samplers(
Sampler& mipmap_sampler,
Sampler& linear_sampler,
@@ -308,49 +184,22 @@ void NodeStrokePreview::init_controls()
void NodeStrokePreview::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
{
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;
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<std::int32_t>(bb_min.x),
static_cast<std::int32_t>(bb_min.y),
static_cast<std::int32_t>(bb_sz.x),
static_cast<std::int32_t>(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] {
const bool mix_ok = pp::panopainter::execute_legacy_node_stroke_preview_mix_pass(
pp::panopainter::LegacyNodeStrokePreviewMixPassExecutionRequest {
.brush = *b,
.preview_size = m_size,
.mixer_rtt = m_rtt_mixer,
.bb_min = bb_min,
.bb_sz = bb_sz,
.linear_sampler = m_sampler_linear,
.background_texture = m_tex_background,
.stroke_texture = m_tex,
.dual_texture = m_tex_dual,
.draw_mix = [this] {
m_plane.draw_fill();
}));
assert(mix_result.ok);
},
});
assert(mix_ok);
}
glm::vec4 NodeStrokePreview::stroke_draw_samples(