Extract canvas mask modes, preview draw pass, and node style shell

This commit is contained in:
2026-06-16 21:50:12 +02:00
parent c25af6f493
commit a2a67960c8
12 changed files with 916 additions and 557 deletions

View File

@@ -2,26 +2,19 @@
#include <cstdint>
#include "log.h"
#include "canvas_modes.h"
#include "layout.h"
#include "canvas.h"
#include "shader.h"
#include "node_canvas.h"
#include "legacy_canvas_draw_merge_services.h"
#include "legacy_canvas_stroke_composite_services.h"
#include "legacy_canvas_mode_helpers.h"
#include "legacy_ui_overlay_services.h"
#include "legacy_ui_gl_dispatch.h"
#include "app.h"
#include "util.h"
#include "renderer_gl/opengl_capabilities.h"
NodeCanvas* CanvasMode::node;
using pp::legacy_canvas_mode::apply_canvas_mode_capability;
using pp::legacy_canvas_mode::apply_canvas_mode_viewport;
using pp::legacy_canvas_mode::query_canvas_mode_capability;
using pp::legacy_canvas_mode::query_canvas_mode_read_framebuffer;
////////////////////////////////////////////////////////////////////
@@ -199,332 +192,6 @@ void ActionModeGrid::undo()
////////////////////////////////////////////////////////////////////
void CanvasModeMaskFree::init()
{
m_shape.create();
}
void CanvasModeMaskFree::leave(kCanvasMode next)
{
// Canvas::I->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(1), std::placeholders::_1, std::placeholders::_2));
if (next != kCanvasMode::Draw && next != kCanvasMode::Erase && next != kCanvasMode::Line)
{
m_points.clear();
Canvas::I->m_smask_active = false;
}
}
void CanvasModeMaskFree::clear()
{
m_points.clear();
m_points2d.clear();
m_shape.clear();
}
void CanvasModeMaskFree::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
static glm::vec2 oldpos;
static glm::vec2 oldvec;
static float acc = 0.f;
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
m_dragging = true;
m_points2d.clear();
m_points.clear();
oldpos = loc;
oldvec = {1.f, 0.f};
acc = 0;
vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points2d.push_back(loc);
m_points2d.push_back(loc);
m_points.push_back(vert);
m_points.push_back(vert);
if (!(App::I->keys[(int)kKey::KeyShift] || App::I->keys[(int)kKey::KeyCtrl]))
Canvas::I->m_smask.clear({0, 0, 0, 0});
Canvas::I->m_smask_active = true;
Canvas::I->m_smask_mode = 1;
break;
}
case kEventType::MouseUpL:
pp::panopainter::release_legacy_mouse_capture(*node);
m_dragging = false;
if (m_points2d.size() > 3)
{
if (!m_points.empty())
{
m_selection_cam = Canvas::I->get_camera();
//m_points2d = poly_intersect(poly_remove_duplicate(m_points2d), Canvas::I->face_to_shape2D(0));
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
// blending state intentionally left unchanged here.
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
pp::panopainter::setup_legacy_vr_color_shader({
.color = App::I->keys[(int)kKey::KeyCtrl] ? glm::vec4(0, 0, 0, 1) : glm::vec4(1, 1, 1, 1),
.mvp = proj * camera,
});
m_shape.draw_fill();
};
// use m_shape to render the mask polygon
auto v = triangulate(poly_remove_duplicate(m_points2d));
Canvas::I->project2Dpoints(v);
m_shape.update_vertices(v.data(), (int)v.size());
Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0);
// close the path and reset m_shape to contour rendering
m_points.push_back(m_points.back());
m_points.push_back(m_points.front());
Canvas::I->project2Dpoints(m_points);
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
else
{
Canvas::I->m_smask_active = false;
}
break;
case kEventType::MouseMove:
{
if (m_dragging)
{
auto v = loc - oldpos;
float len = glm::length(v);
if (len > 5)
{
m_points.back().pos = glm::vec4(loc, 0, 1);
m_points2d.back() = loc;
v = glm::normalize(v);
float d = 1.f - glm::dot(v, oldvec);
acc += d;
oldpos = loc;
oldvec = v;
if (acc > 0.001) // angle change tolerance
{
//LOG("d=%f acc=%f", d, acc);
acc = 0;
m_points2d.push_back(loc);
vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points.push_back(vert);
m_points.push_back(vert);
}
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
pp::panopainter::release_legacy_mouse_capture(*node);
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeMaskFree::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
const bool depth = query_canvas_mode_capability(pp::renderer::gl::depth_test_state());
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
if (m_points.size() > 3)
{
if (m_dragging)
{
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 0, 0, 0, 1 },
.mvp = glm::scale(glm::vec3(1, -1, 1)) * ortho,
});
//m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
m_shape.draw_stroke();
}
//else
//{
// ShaderManager::use(kShader::Color);
// ShaderManager::u_mat4(kShaderUniform::MVP, proj * camera);
// ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
// m_shape.draw_stroke();
//}
}
if (depth) apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), true);
}
////////////////////////////////////////////////////////////////////
void CanvasModeMaskLine::init()
{
m_shape.create();
}
void CanvasModeMaskLine::leave(kCanvasMode next)
{
if (next != kCanvasMode::Draw && next != kCanvasMode::Erase && next != kCanvasMode::Line)
{
m_points.clear();
m_active_tool = false;
Canvas::I->m_smask_active = false;
}
if (!m_active_tool)
return;
if (m_points2d.size() > 3)
{
std::vector<vertex_t> points;
for (int i = 0; i < (int)m_points2d.size(); i++)
points.emplace_back(m_points2d[i]);
auto v = triangulate(poly_remove_duplicate(points));
Canvas::I->project2Dpoints(v);
LOG("%d points", (int)v.size());
m_shape.update_vertices(v.data(), (int)v.size());
if (!m_points.empty())
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
// blending state intentionally left unchanged here.
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 1, 1, 1, 1 },
.mvp = proj * camera,
});
m_shape.draw_fill();
};
Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0);
//m_points.clear();
// close the path
m_points.push_back(m_points.back());
m_points.push_back(m_points.back());
m_points.push_back(m_points.front());
Canvas::I->project2Dpoints(m_points);
// reset m_shape to contour rendering
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
else
{
Canvas::I->m_smask_active = false;
}
m_active_tool = false;
}
void CanvasModeMaskLine::enter(kCanvasMode prev)
{
//m_points2d.clear();
//m_points.clear();
//Canvas::I->m_smask.clear({0, 0, 0, 0});
//m_active_tool = true;
}
void CanvasModeMaskLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseDownL:
{
if (m_active_tool == false)
{
m_active_tool = true;
m_points2d.clear();
m_points.clear();
Canvas::I->m_smask.clear({ 0, 0, 0, 0 });
Canvas::I->m_smask_active = true;
Canvas::I->m_smask_mode = 2;
}
node->mouse_capture();
m_dragging = true;
m_points2d.push_back(loc);
vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points.push_back(vert);
m_shape.update_vertices(m_points.data(), (int)m_points.size());
break;
}
case kEventType::MouseUpL:
pp::panopainter::release_legacy_mouse_capture(*node);
m_dragging = false;
if (m_points.size() > 1)
{
m_selection_cam = Canvas::I->get_camera();
m_points.push_back(m_points.back());
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
case kEventType::MouseMove:
{
if (m_dragging)
{
if (glm::distance(m_points2d.front(), loc) < 10)
loc = m_points2d.front();
m_points.back().pos = glm::vec4(loc, 0, 1);
m_points2d.back() = loc;
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
pp::panopainter::release_legacy_mouse_capture(*node);
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeMaskLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_points.size() > 1)
{
if (m_active_tool)
{
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 0, 0, 0, 1 },
.mvp = glm::scale(glm::vec3(1, -1, 1)) * ortho,
});
//m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
m_shape.draw_stroke();
}
else
{
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 0, 0, 0, 1 },
.mvp = proj * camera,
});
m_shape.draw_stroke();
}
}
}
////////////////////////////////////////////////////////////////////
void CanvasModeFill::init()
{
m_shape.create();

View File

@@ -0,0 +1,327 @@
#include "pch.h"
#include "canvas_modes.h"
#include "app.h"
#include "canvas.h"
#include "legacy_canvas_mode_helpers.h"
#include "legacy_ui_overlay_services.h"
#include "log.h"
#include "renderer_gl/opengl_capabilities.h"
using pp::legacy_canvas_mode::apply_canvas_mode_capability;
using pp::legacy_canvas_mode::query_canvas_mode_capability;
void CanvasModeMaskFree::init()
{
m_shape.create();
}
void CanvasModeMaskFree::leave(kCanvasMode next)
{
// Canvas::I->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(1), std::placeholders::_1, std::placeholders::_2));
if (next != kCanvasMode::Draw && next != kCanvasMode::Erase && next != kCanvasMode::Line)
{
m_points.clear();
Canvas::I->m_smask_active = false;
}
}
void CanvasModeMaskFree::clear()
{
m_points.clear();
m_points2d.clear();
m_shape.clear();
}
void CanvasModeMaskFree::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
static glm::vec2 oldpos;
static glm::vec2 oldvec;
static float acc = 0.f;
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseDownL:
{
node->mouse_capture();
m_dragging = true;
m_points2d.clear();
m_points.clear();
oldpos = loc;
oldvec = {1.f, 0.f};
acc = 0;
vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points2d.push_back(loc);
m_points2d.push_back(loc);
m_points.push_back(vert);
m_points.push_back(vert);
if (!(App::I->keys[(int)kKey::KeyShift] || App::I->keys[(int)kKey::KeyCtrl]))
Canvas::I->m_smask.clear({0, 0, 0, 0});
Canvas::I->m_smask_active = true;
Canvas::I->m_smask_mode = 1;
break;
}
case kEventType::MouseUpL:
pp::panopainter::release_legacy_mouse_capture(*node);
m_dragging = false;
if (m_points2d.size() > 3)
{
if (!m_points.empty())
{
m_selection_cam = Canvas::I->get_camera();
//m_points2d = poly_intersect(poly_remove_duplicate(m_points2d), Canvas::I->face_to_shape2D(0));
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
// blending state intentionally left unchanged here.
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
pp::panopainter::setup_legacy_vr_color_shader({
.color = App::I->keys[(int)kKey::KeyCtrl] ? glm::vec4(0, 0, 0, 1) : glm::vec4(1, 1, 1, 1),
.mvp = proj * camera,
});
m_shape.draw_fill();
};
// use m_shape to render the mask polygon
auto v = triangulate(poly_remove_duplicate(m_points2d));
Canvas::I->project2Dpoints(v);
m_shape.update_vertices(v.data(), (int)v.size());
Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0);
// close the path and reset m_shape to contour rendering
m_points.push_back(m_points.back());
m_points.push_back(m_points.front());
Canvas::I->project2Dpoints(m_points);
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
else
{
Canvas::I->m_smask_active = false;
}
break;
case kEventType::MouseMove:
{
if (m_dragging)
{
auto v = loc - oldpos;
float len = glm::length(v);
if (len > 5)
{
m_points.back().pos = glm::vec4(loc, 0, 1);
m_points2d.back() = loc;
v = glm::normalize(v);
float d = 1.f - glm::dot(v, oldvec);
acc += d;
oldpos = loc;
oldvec = v;
if (acc > 0.001) // angle change tolerance
{
//LOG("d=%f acc=%f", d, acc);
acc = 0;
m_points2d.push_back(loc);
vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points.push_back(vert);
m_points.push_back(vert);
}
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
pp::panopainter::release_legacy_mouse_capture(*node);
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeMaskFree::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
const bool depth = query_canvas_mode_capability(pp::renderer::gl::depth_test_state());
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
if (m_points.size() > 3)
{
if (m_dragging)
{
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 0, 0, 0, 1 },
.mvp = glm::scale(glm::vec3(1, -1, 1)) * ortho,
});
//m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
m_shape.draw_stroke();
}
}
if (depth) apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), true);
}
void CanvasModeMaskLine::init()
{
m_shape.create();
}
void CanvasModeMaskLine::leave(kCanvasMode next)
{
if (next != kCanvasMode::Draw && next != kCanvasMode::Erase && next != kCanvasMode::Line)
{
m_points.clear();
m_active_tool = false;
Canvas::I->m_smask_active = false;
}
if (!m_active_tool)
return;
if (m_points2d.size() > 3)
{
std::vector<vertex_t> points;
for (int i = 0; i < (int)m_points2d.size(); i++)
points.emplace_back(m_points2d[i]);
auto v = triangulate(poly_remove_duplicate(points));
Canvas::I->project2Dpoints(v);
LOG("%d points", (int)v.size());
m_shape.update_vertices(v.data(), (int)v.size());
if (!m_points.empty())
{
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
// blending state intentionally left unchanged here.
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 1, 1, 1, 1 },
.mvp = proj * camera,
});
m_shape.draw_fill();
};
Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0);
//m_points.clear();
// close the path
m_points.push_back(m_points.back());
m_points.push_back(m_points.back());
m_points.push_back(m_points.front());
Canvas::I->project2Dpoints(m_points);
// reset m_shape to contour rendering
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
}
else
{
Canvas::I->m_smask_active = false;
}
m_active_tool = false;
}
void CanvasModeMaskLine::enter(kCanvasMode prev)
{
//m_points2d.clear();
//m_points.clear();
//Canvas::I->m_smask.clear({0, 0, 0, 0});
//m_active_tool = true;
}
void CanvasModeMaskLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
{
if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch)
return;
switch (me->m_type)
{
case kEventType::MouseDownL:
{
if (m_active_tool == false)
{
m_active_tool = true;
m_points2d.clear();
m_points.clear();
Canvas::I->m_smask.clear({ 0, 0, 0, 0 });
Canvas::I->m_smask_active = true;
Canvas::I->m_smask_mode = 2;
}
node->mouse_capture();
m_dragging = true;
m_points2d.push_back(loc);
vertex_t vert;
vert.pos = glm::vec4(loc, 0, 1);
m_points.push_back(vert);
m_shape.update_vertices(m_points.data(), (int)m_points.size());
break;
}
case kEventType::MouseUpL:
pp::panopainter::release_legacy_mouse_capture(*node);
m_dragging = false;
if (m_points.size() > 1)
{
m_selection_cam = Canvas::I->get_camera();
m_points.push_back(m_points.back());
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
case kEventType::MouseMove:
{
if (m_dragging)
{
if (glm::distance(m_points2d.front(), loc) < 10)
loc = m_points2d.front();
m_points.back().pos = glm::vec4(loc, 0, 1);
m_points2d.back() = loc;
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
}
case kEventType::MouseCancel:
if (m_dragging)
{
m_points.pop_back();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
m_dragging = false;
pp::panopainter::release_legacy_mouse_capture(*node);
if (m_points.size() < 4)
{
m_points.clear();
m_shape.update_vertices(m_points.data(), (int)m_points.size());
}
break;
default:
break;
}
}
void CanvasModeMaskLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{
if (m_points.size() > 1)
{
if (m_active_tool)
{
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 0, 0, 0, 1 },
.mvp = glm::scale(glm::vec3(1, -1, 1)) * ortho,
});
//m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
m_shape.draw_stroke();
}
else
{
pp::panopainter::setup_legacy_vr_color_shader({
.color = { 0, 0, 0, 1 },
.mvp = proj * camera,
});
m_shape.draw_stroke();
}
}
}

View File

@@ -0,0 +1,123 @@
#include "pch.h"
#include "legacy_node_stroke_preview_draw_services.h"
namespace pp::panopainter {
namespace {
bool has_valid_live_render_callbacks(const LegacyNodeStrokePreviewLiveRenderRequest& request)
{
return request.bind_dual_pass_textures &&
request.capture_background &&
request.compute_frames &&
request.draw_samples &&
request.draw_mix &&
request.unbind_mixer_texture &&
request.bind_pattern_texture &&
request.draw_composite;
}
} // namespace
bool execute_legacy_node_stroke_preview_live_render_passes(
const LegacyNodeStrokePreviewLiveRenderRequest& request)
{
if (!has_valid_live_render_callbacks(request)) {
return false;
}
return execute_legacy_node_stroke_preview_draw_immediate_shell<LegacyNodeStrokePreviewFrame>(
request.brush,
request.pass_orchestration,
request.stroke_texture,
request.mixer_rtt,
request.render_target,
request.background_texture,
request.dual_texture,
request.preview_texture,
request.linear_sampler,
request.repeat_sampler,
request.copy_stroke_destination,
request.size,
kLegacyNodeStrokePreviewStrokeTextureSlot,
[&] {
if (!request.pass_orchestration.material.dual_pass.enabled) {
return;
}
setup_legacy_stroke_dual_shader(request.pass_orchestration.material.dual_pass.uses_pattern);
request.bind_dual_pass_textures(*request.prepared_strokes.dual_brush);
execute_legacy_stroke_preview_live_pass(
[&] {
request.render_target.clear();
},
[&] {
return request.compute_frames(
const_cast<Stroke&>(request.prepared_strokes.dual_stroke),
request.zoom);
},
[](auto& frame) {
frame.col = { 0, 0, 0, 1 };
},
[&](auto& frame) {
use_legacy_stroke_shader();
apply_legacy_stroke_sample_uniforms(
LegacyStrokeSampleUniforms {
.color = frame.col,
.alpha = frame.flow,
.opacity = frame.opacity,
});
},
[&](auto& frame) {
request.draw_samples(frame.shapes, request.dual_texture, request.copy_stroke_destination);
},
[&] {
copy_legacy_node_stroke_preview_framebuffer_to_texture(
request.dual_texture,
request.size,
kLegacyNodeStrokePreviewStrokeTextureSlot);
});
},
[&] {
request.capture_background(request.pass_orchestration.background_colorize);
},
[&] {
return request.compute_frames(
const_cast<Stroke&>(request.prepared_strokes.stroke),
request.zoom);
},
[&](auto& frame) {
if (request.brush.m_tip_mix > 0.0f) {
request.draw_mix(xy(frame.mixer_rect), zw(frame.mixer_rect));
}
frame.col = request.brush.m_blend_mode != 0 || request.brush.m_tip_mix > 0.0f ?
glm::vec4 { .7f, .4f, .1f, 1.0f } :
glm::vec4 { 0.0f, 0.0f, 0.0f, 1.0f };
frame.flow = glm::max(frame.flow, request.min_flow);
},
[&](auto& frame) {
use_legacy_stroke_shader();
apply_legacy_stroke_sample_uniforms(
LegacyStrokeSampleUniforms {
.color = frame.col,
.alpha = frame.flow,
.opacity = frame.opacity,
});
},
[&](auto& frame) {
request.draw_samples(frame.shapes, request.stroke_texture, request.copy_stroke_destination);
},
[&] {
request.unbind_mixer_texture();
},
[&] {
request.bind_pattern_texture();
},
[&] {
request.draw_composite();
});
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,51 @@
#pragma once
#include "brush.h"
#include "legacy_node_stroke_preview_execution_services.h"
#include "rtt.h"
#include "texture.h"
#include <array>
#include <functional>
#include <vector>
namespace pp::panopainter {
struct LegacyNodeStrokePreviewFrame {
glm::vec4 col {};
float flow = 0.0f;
float opacity = 0.0f;
std::array<vertex_t, 4> shapes {};
glm::vec4 mixer_rect {};
};
struct LegacyNodeStrokePreviewLiveRenderRequest {
const Brush& brush;
const LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration;
const LegacyNodeStrokePreviewPreparedStrokes& prepared_strokes;
Texture2D& stroke_texture;
RTT& mixer_rtt;
RTT& render_target;
Texture2D& background_texture;
Texture2D& dual_texture;
Texture2D& preview_texture;
Sampler& linear_sampler;
Sampler& repeat_sampler;
float zoom = 1.0f;
float min_flow = 0.0f;
bool copy_stroke_destination = false;
glm::vec2 size {};
std::function<void(const Brush&)> bind_dual_pass_textures;
std::function<void(bool)> capture_background;
std::function<std::vector<LegacyNodeStrokePreviewFrame>(const Stroke&, float)> compute_frames;
std::function<glm::vec4(std::array<vertex_t, 4>&, Texture2D&, bool)> draw_samples;
std::function<void(const glm::vec2&, const glm::vec2&)> draw_mix;
std::function<void()> unbind_mixer_texture;
std::function<void()> bind_pattern_texture;
std::function<void()> draw_composite;
};
[[nodiscard]] bool execute_legacy_node_stroke_preview_live_render_passes(
const LegacyNodeStrokePreviewLiveRenderRequest& request);
} // namespace pp::panopainter

View File

@@ -0,0 +1,250 @@
#include "pch.h"
#include "legacy_ui_node_style.h"
#include "app.h"
#include "node.h"
namespace pp::panopainter {
void legacy_ui_node_set_width(Node& node, float value)
{
YGNodeStyleSetWidth(node.y_node, value);
node.m_size.x = value;
node.auto_width = value == YGUndefined;
node.app_redraw();
}
void legacy_ui_node_set_width_percent(Node& node, float value)
{
YGNodeStyleSetWidthPercent(node.y_node, value);
node.auto_width = value == YGUndefined;
node.app_redraw();
}
void legacy_ui_node_set_height(Node& node, float value)
{
YGNodeStyleSetHeight(node.y_node, value);
node.m_size.y = value;
node.auto_height = value == YGUndefined;
node.app_redraw();
}
void legacy_ui_node_set_height_percent(Node& node, float value)
{
YGNodeStyleSetHeightPercent(node.y_node, value);
node.auto_height = value == YGUndefined;
node.app_redraw();
}
void legacy_ui_node_set_max_width(Node& node, float value)
{
YGNodeStyleSetMaxWidth(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_max_width_percent(Node& node, float value)
{
YGNodeStyleSetMaxWidthPercent(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_max_height(Node& node, float value)
{
YGNodeStyleSetMaxHeight(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_max_height_percent(Node& node, float value)
{
YGNodeStyleSetMaxHeightPercent(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_min_width(Node& node, float value)
{
YGNodeStyleSetMinWidth(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_min_width_percent(Node& node, float value)
{
YGNodeStyleSetMinWidthPercent(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_min_height(Node& node, float value)
{
YGNodeStyleSetMinHeight(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_min_height_percent(Node& node, float value)
{
YGNodeStyleSetMinHeightPercent(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_padding(Node& node, float t, float r, float b, float l)
{
YGNodeStyleSetPadding(node.y_node, YGEdgeTop, t);
YGNodeStyleSetPadding(node.y_node, YGEdgeRight, r);
YGNodeStyleSetPadding(node.y_node, YGEdgeBottom, b);
YGNodeStyleSetPadding(node.y_node, YGEdgeLeft, l);
node.app_redraw();
}
glm::vec4 legacy_ui_node_get_padding(const Node& node)
{
float t = YGNodeLayoutGetPadding(node.y_node, YGEdgeTop);
float r = YGNodeLayoutGetPadding(node.y_node, YGEdgeRight);
float b = YGNodeLayoutGetPadding(node.y_node, YGEdgeBottom);
float l = YGNodeLayoutGetPadding(node.y_node, YGEdgeLeft);
return { t, r, b, l };
}
void legacy_ui_node_set_margin(Node& node, float t, float r, float b, float l)
{
YGNodeStyleSetMargin(node.y_node, YGEdgeTop, t);
YGNodeStyleSetMargin(node.y_node, YGEdgeRight, r);
YGNodeStyleSetMargin(node.y_node, YGEdgeBottom, b);
YGNodeStyleSetMargin(node.y_node, YGEdgeLeft, l);
node.app_redraw();
}
glm::vec4 legacy_ui_node_get_margin(const Node& node)
{
float t = YGNodeLayoutGetMargin(node.y_node, YGEdgeTop);
float r = YGNodeLayoutGetMargin(node.y_node, YGEdgeRight);
float b = YGNodeLayoutGetMargin(node.y_node, YGEdgeBottom);
float l = YGNodeLayoutGetMargin(node.y_node, YGEdgeLeft);
return { t, r, b, l };
}
void legacy_ui_node_set_position(Node& node, float l, float t)
{
YGNodeStyleSetPosition(node.y_node, YGEdgeTop, t);
YGNodeStyleSetPosition(node.y_node, YGEdgeLeft, l);
node.m_pos = { l, t };
node.app_redraw();
}
void legacy_ui_node_set_position(Node& node, float l, float t, float r, float b)
{
YGNodeStyleSetPosition(node.y_node, YGEdgeTop, t);
YGNodeStyleSetPosition(node.y_node, YGEdgeRight, r);
YGNodeStyleSetPosition(node.y_node, YGEdgeBottom, b);
YGNodeStyleSetPosition(node.y_node, YGEdgeLeft, l);
node.app_redraw();
}
void legacy_ui_node_set_flex_grow(Node& node, float value)
{
YGNodeStyleSetFlexGrow(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_flex_shrink(Node& node, float value)
{
YGNodeStyleSetFlexShrink(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_flex_dir(Node& node, YGFlexDirection value)
{
YGNodeStyleSetFlexDirection(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_flex_wrap(Node& node, YGWrap value)
{
YGNodeStyleSetFlexWrap(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_justify(Node& node, YGJustify value)
{
YGNodeStyleSetJustifyContent(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_align(Node& node, YGAlign value)
{
YGNodeStyleSetAlignItems(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_positioning(Node& node, YGPositionType value)
{
YGNodeStyleSetPositionType(node.y_node, value);
node.app_redraw();
}
void legacy_ui_node_set_aspect_ratio(Node& node, float ar)
{
YGNodeStyleSetAspectRatio(node.y_node, ar);
node.app_redraw();
}
void legacy_ui_node_set_rtl(Node& node, YGDirection dir)
{
YGNodeStyleSetDirection(node.y_node, dir);
node.app_redraw();
}
bool legacy_ui_node_get_visibility(const Node& node)
{
return node.m_display;
}
void legacy_ui_node_set_visibility(Node& node, bool visible)
{
App::I->ui_task([&node, visible]
{
if (node.m_display && !visible)
{
int idx = node.m_parent->get_child_index(&node);
YGNodeRemoveChild(node.m_parent->y_node, node.y_node);
node.y_placeholder = YGNodeNew();
YGNodeInsertChild(node.m_parent->y_node, node.y_placeholder, idx);
}
else if (!node.m_display && visible)
{
int count = YGNodeGetChildCount(node.m_parent->y_node);
for (int i = 0; i < count; i++)
{
if (YGNodeGetChild(node.m_parent->y_node, i) == node.y_placeholder)
{
YGNodeRemoveChild(node.m_parent->y_node, node.y_placeholder);
YGNodeInsertChild(node.m_parent->y_node, node.y_node, i);
YGNodeFree(node.y_placeholder);
node.y_placeholder = nullptr;
break;
}
}
}
});
node.m_display = visible;
node.app_redraw();
}
glm::vec2 legacy_ui_node_get_position(const Node& node)
{
return { YGNodeLayoutGetLeft(node.y_node), YGNodeLayoutGetTop(node.y_node) };
}
float legacy_ui_node_get_width(const Node& node)
{
return YGNodeLayoutGetWidth(node.y_node);
}
float legacy_ui_node_get_height(const Node& node)
{
return YGNodeLayoutGetHeight(node.y_node);
}
YGDirection legacy_ui_node_get_rtl(const Node& node)
{
return YGNodeStyleGetDirection(node.y_node);
}
} // namespace pp::panopainter

View File

@@ -0,0 +1,45 @@
#pragma once
#include <glm/vec2.hpp>
#include <glm/vec4.hpp>
#include <yoga/Yoga.h>
class Node;
namespace pp::panopainter {
void legacy_ui_node_set_width(Node& node, float value);
void legacy_ui_node_set_width_percent(Node& node, float value);
void legacy_ui_node_set_height(Node& node, float value);
void legacy_ui_node_set_height_percent(Node& node, float value);
void legacy_ui_node_set_max_width(Node& node, float value);
void legacy_ui_node_set_max_width_percent(Node& node, float value);
void legacy_ui_node_set_max_height(Node& node, float value);
void legacy_ui_node_set_max_height_percent(Node& node, float value);
void legacy_ui_node_set_min_width(Node& node, float value);
void legacy_ui_node_set_min_width_percent(Node& node, float value);
void legacy_ui_node_set_min_height(Node& node, float value);
void legacy_ui_node_set_min_height_percent(Node& node, float value);
void legacy_ui_node_set_padding(Node& node, float t, float r, float b, float l);
glm::vec4 legacy_ui_node_get_padding(const Node& node);
void legacy_ui_node_set_margin(Node& node, float t, float r, float b, float l);
glm::vec4 legacy_ui_node_get_margin(const Node& node);
void legacy_ui_node_set_position(Node& node, float l, float t);
void legacy_ui_node_set_position(Node& node, float l, float t, float r, float b);
void legacy_ui_node_set_flex_grow(Node& node, float value);
void legacy_ui_node_set_flex_shrink(Node& node, float value);
void legacy_ui_node_set_flex_dir(Node& node, YGFlexDirection value);
void legacy_ui_node_set_flex_wrap(Node& node, YGWrap value);
void legacy_ui_node_set_justify(Node& node, YGJustify value);
void legacy_ui_node_set_align(Node& node, YGAlign value);
void legacy_ui_node_set_positioning(Node& node, YGPositionType value);
void legacy_ui_node_set_aspect_ratio(Node& node, float ar);
void legacy_ui_node_set_rtl(Node& node, YGDirection dir);
bool legacy_ui_node_get_visibility(const Node& node);
void legacy_ui_node_set_visibility(Node& node, bool visible);
glm::vec2 legacy_ui_node_get_position(const Node& node);
float legacy_ui_node_get_width(const Node& node);
float legacy_ui_node_get_height(const Node& node);
YGDirection legacy_ui_node_get_rtl(const Node& node);
} // namespace pp::panopainter

View File

@@ -4,6 +4,7 @@
#include "legacy_ui_node_attributes.h"
#include "legacy_ui_node_event.h"
#include "legacy_ui_node_loader.h"
#include "legacy_ui_node_style.h"
#include "node.h"
#include "layout.h"
#include "util.h"
@@ -163,32 +164,22 @@ Node::~Node()
void Node::SetWidth(float value)
{
YGNodeStyleSetWidth(y_node, value);
m_size.x = value;
auto_width = value == YGUndefined;
app_redraw();
pp::panopainter::legacy_ui_node_set_width(*this, value);
}
void Node::SetWidthP(float value)
{
YGNodeStyleSetWidthPercent(y_node, value);
auto_width = value == YGUndefined;
app_redraw();
pp::panopainter::legacy_ui_node_set_width_percent(*this, value);
}
void Node::SetHeight(float value)
{
YGNodeStyleSetHeight(y_node, value);
m_size.y = value;
auto_height = value == YGUndefined;
app_redraw();
pp::panopainter::legacy_ui_node_set_height(*this, value);
}
void Node::SetHeightP(float value)
{
YGNodeStyleSetHeightPercent(y_node, value);
auto_height = value == YGUndefined;
app_redraw();
pp::panopainter::legacy_ui_node_set_height_percent(*this, value);
}
void Node::SetSize(float w, float h)
@@ -231,86 +222,62 @@ void Node::SetMaxSize(glm::vec2 value)
void Node::SetMaxWidth(float value)
{
YGNodeStyleSetMaxWidth(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_max_width(*this, value);
}
void Node::SetMaxWidthP(float value)
{
YGNodeStyleSetMaxWidthPercent(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_max_width_percent(*this, value);
}
void Node::SetMaxHeight(float value)
{
YGNodeStyleSetMaxHeight(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_max_height(*this, value);
}
void Node::SetMaxHeightP(float value)
{
YGNodeStyleSetMaxHeightPercent(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_max_height_percent(*this, value);
}
void Node::SetMinWidth(float value)
{
YGNodeStyleSetMinWidth(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_min_width(*this, value);
}
void Node::SetMinWidthP(float value)
{
YGNodeStyleSetMinWidthPercent(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_min_width_percent(*this, value);
}
void Node::SetMinHeight(float value)
{
YGNodeStyleSetMinHeight(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_min_height(*this, value);
}
void Node::SetMinHeightP(float value)
{
YGNodeStyleSetMinHeightPercent(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_min_height_percent(*this, value);
}
void Node::SetPadding(float t, float r, float b, float l)
{
YGNodeStyleSetPadding(y_node, YGEdgeTop, t);
YGNodeStyleSetPadding(y_node, YGEdgeRight, r);
YGNodeStyleSetPadding(y_node, YGEdgeBottom, b);
YGNodeStyleSetPadding(y_node, YGEdgeLeft, l);
app_redraw();
pp::panopainter::legacy_ui_node_set_padding(*this, t, r, b, l);
}
glm::vec4 Node::GetPadding() const
{
float t = YGNodeLayoutGetPadding(y_node, YGEdgeTop);
float r = YGNodeLayoutGetPadding(y_node, YGEdgeRight);
float b = YGNodeLayoutGetPadding(y_node, YGEdgeBottom);
float l = YGNodeLayoutGetPadding(y_node, YGEdgeLeft);
return{ t, r, b, l };
return pp::panopainter::legacy_ui_node_get_padding(*this);
}
void Node::SetMargin(float t, float r, float b, float l)
{
YGNodeStyleSetMargin(y_node, YGEdgeTop, t);
YGNodeStyleSetMargin(y_node, YGEdgeRight, r);
YGNodeStyleSetMargin(y_node, YGEdgeBottom, b);
YGNodeStyleSetMargin(y_node, YGEdgeLeft, l);
app_redraw();
pp::panopainter::legacy_ui_node_set_margin(*this, t, r, b, l);
}
glm::vec4 Node::GetMargin() const
{
float t = YGNodeLayoutGetMargin(y_node, YGEdgeTop);
float r = YGNodeLayoutGetMargin(y_node, YGEdgeRight);
float b = YGNodeLayoutGetMargin(y_node, YGEdgeBottom);
float l = YGNodeLayoutGetMargin(y_node, YGEdgeLeft);
return{ t, r, b, l };
return pp::panopainter::legacy_ui_node_get_margin(*this);
}
void Node::SetPosition(const glm::vec2 pos)
@@ -322,110 +289,67 @@ void Node::SetPosition(const glm::vec2 pos)
void Node::SetPosition(float l, float t)
{
YGNodeStyleSetPosition(y_node, YGEdgeTop, t);
YGNodeStyleSetPosition(y_node, YGEdgeLeft, l);
m_pos = {l, t};
app_redraw();
pp::panopainter::legacy_ui_node_set_position(*this, l, t);
}
void Node::SetPosition(float l, float t, float r, float b)
{
YGNodeStyleSetPosition(y_node, YGEdgeTop, t);
YGNodeStyleSetPosition(y_node, YGEdgeRight, r);
YGNodeStyleSetPosition(y_node, YGEdgeBottom, b);
YGNodeStyleSetPosition(y_node, YGEdgeLeft, l);
app_redraw();
pp::panopainter::legacy_ui_node_set_position(*this, l, t, r, b);
}
void Node::SetFlexGrow(float value)
{
YGNodeStyleSetFlexGrow(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_flex_grow(*this, value);
}
void Node::SetFlexShrink(float value)
{
YGNodeStyleSetFlexShrink(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_flex_shrink(*this, value);
}
void Node::SetFlexDir(YGFlexDirection value)
{
YGNodeStyleSetFlexDirection(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_flex_dir(*this, value);
}
void Node::SetFlexWrap(YGWrap value)
{
YGNodeStyleSetFlexWrap(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_flex_wrap(*this, value);
}
void Node::SetJustify(YGJustify value)
{
YGNodeStyleSetJustifyContent(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_justify(*this, value);
}
void Node::SetAlign(YGAlign value)
{
YGNodeStyleSetAlignItems(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_align(*this, value);
}
void Node::SetPositioning(YGPositionType value)
{
YGNodeStyleSetPositionType(y_node, value);
app_redraw();
pp::panopainter::legacy_ui_node_set_positioning(*this, value);
}
void Node::SetAspectRatio(float ar)
{
YGNodeStyleSetAspectRatio(y_node, ar);
app_redraw();
pp::panopainter::legacy_ui_node_set_aspect_ratio(*this, ar);
}
void Node::SetRTL(YGDirection dir)
{
YGNodeStyleSetDirection(y_node, dir);
app_redraw();
pp::panopainter::legacy_ui_node_set_rtl(*this, dir);
}
bool Node::GetVisibility()
{
return m_display;
return pp::panopainter::legacy_ui_node_get_visibility(*this);
}
void Node::SetVisibility(bool visible)
{
App::I->ui_task([&]
{
if (m_display && !visible)
{
// hide
int idx = m_parent->get_child_index(this);
YGNodeRemoveChild(m_parent->y_node, y_node);
y_placeholder = YGNodeNew();
YGNodeInsertChild(m_parent->y_node, y_placeholder, idx);
}
else if (!m_display && visible)
{
int count = YGNodeGetChildCount(m_parent->y_node);
for (int i = 0; i < count; i++)
{
if (YGNodeGetChild(m_parent->y_node, i) == y_placeholder)
{
YGNodeRemoveChild(m_parent->y_node, y_placeholder);
YGNodeInsertChild(m_parent->y_node, y_node, i);
YGNodeFree(y_placeholder);
y_placeholder = nullptr;
break;
}
}
}
});
m_display = visible;
app_redraw();
pp::panopainter::legacy_ui_node_set_visibility(*this, visible);
}
void Node::ToggleVisibility()
@@ -435,17 +359,17 @@ void Node::ToggleVisibility()
glm::vec2 Node::GetPosition()
{
return { YGNodeLayoutGetLeft(y_node), YGNodeLayoutGetTop(y_node) };
return pp::panopainter::legacy_ui_node_get_position(*this);
}
float Node::GetWidth()
{
return YGNodeLayoutGetWidth(y_node);
return pp::panopainter::legacy_ui_node_get_width(*this);
}
float Node::GetHeight()
{
return YGNodeLayoutGetHeight(y_node);
return pp::panopainter::legacy_ui_node_get_height(*this);
}
glm::vec2 Node::GetSize()
@@ -455,7 +379,7 @@ glm::vec2 Node::GetSize()
YGDirection Node::GetRTL()
{
return YGNodeStyleGetDirection(y_node);
return pp::panopainter::legacy_ui_node_get_rtl(*this);
}
void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)

View File

@@ -448,9 +448,9 @@ glm::vec4 NodeStrokePreview::stroke_draw_samples(
copy_stroke_destination);
}
std::vector<NodeStrokePreview::StrokeFrame> NodeStrokePreview::stroke_draw_compute(Stroke& stroke, float zoom) const
std::vector<NodeStrokePreview::StrokeFrame> NodeStrokePreview::stroke_draw_compute(const Stroke& stroke, float zoom) const
{
auto samples = stroke.compute_samples();
auto samples = const_cast<Stroke&>(stroke).compute_samples();
StrokeSample previous_sample = stroke.m_prev_sample;
previous_sample.size *= zoom;
for (auto& sample : samples) {
@@ -475,13 +475,13 @@ std::vector<NodeStrokePreview::StrokeFrame> NodeStrokePreview::stroke_draw_compu
glm::vec4 color,
float flow,
float opacity,
std::array<vertex_t, 4>&& shapes) {
std::array<vertex_t, 4>&& shapes) -> StrokeFrame {
return StrokeFrame {
.col = color,
.flow = flow,
.opacity = opacity,
.shapes = std::move(shapes),
.m_mixer_rect = mixer_rect,
.mixer_rect = mixer_rect,
};
});
}
@@ -548,102 +548,55 @@ void NodeStrokePreview::draw_stroke_immediate()
size,
*b,
ortho_proj));
const bool copy_stroke_destination = pass_orchestration.copy_stroke_destination;
pp::panopainter::setup_legacy_stroke_shader(pass_orchestration.stroke_shader);
const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_draw_immediate_shell<StrokeFrame>(
*b,
pass_orchestration,
m_tex,
m_rtt_mixer,
m_rtt,
m_tex_background,
m_tex_dual,
m_tex_preview,
m_sampler_linear,
m_sampler_linear_repeat,
copy_stroke_destination,
size,
pp::panopainter::kLegacyNodeStrokePreviewStrokeTextureSlot,
[&] {
if (!pass_orchestration.material.dual_pass.enabled) {
return;
}
pp::panopainter::setup_legacy_stroke_dual_shader(pass_orchestration.material.dual_pass.uses_pattern);
bind_stroke_preview_dual_pass_textures(*prepared_strokes.dual_brush);
pp::panopainter::execute_legacy_stroke_preview_live_pass(
[&] {
m_rtt.clear();
},
[&] {
return stroke_draw_compute(prepared_strokes.dual_stroke, zoom);
},
[](auto& frame) {
frame.col = { 0, 0, 0, 1 };
},
[&](auto& frame) {
pp::panopainter::use_legacy_stroke_shader();
pp::panopainter::apply_legacy_stroke_sample_uniforms(
pp::panopainter::LegacyStrokeSampleUniforms {
.color = frame.col,
.alpha = frame.flow,
.opacity = frame.opacity,
});
},
[&](auto& frame) {
/*auto rect =*/ stroke_draw_samples(frame.shapes, m_tex_dual, copy_stroke_destination);
},
[&] {
pp::panopainter::copy_legacy_node_stroke_preview_framebuffer_to_texture(
m_tex_dual,
size,
pp::panopainter::kLegacyNodeStrokePreviewStrokeTextureSlot);
});
},
[&] {
execute_stroke_preview_background_capture_pass(
size,
pass_orchestration.background_colorize,
m_tex_background,
[&] {
m_plane.draw_fill();
});
},
[&] {
return stroke_draw_compute(prepared_strokes.stroke, zoom);
},
[&](auto& frame) {
if (b->m_tip_mix > 0.f)
{
stroke_draw_mix(xy(frame.m_mixer_rect), zw(frame.m_mixer_rect));
}
frame.col = b->m_blend_mode != 0 || b->m_tip_mix > 0.f ?
glm::vec4 { .7, .4, .1, 1 } :
glm::vec4 { 0, 0, 0, 1 };
frame.flow = glm::max(frame.flow, m_min_flow);
},
[&](auto& frame) {
pp::panopainter::use_legacy_stroke_shader();
pp::panopainter::apply_legacy_stroke_sample_uniforms(
pp::panopainter::LegacyStrokeSampleUniforms {
.color = frame.col,
.alpha = frame.flow,
.opacity = frame.opacity,
});
},
[&](auto& frame) {
/*auto rect =*/ stroke_draw_samples(frame.shapes, m_tex, copy_stroke_destination);
},
[&] {
set_active_texture_unit(3U);
m_rtt_mixer.unbindTexture();
},
[&] {
b->m_pattern_texture ? b->m_pattern_texture->bind() : unbind_texture_2d();
},
[&] {
m_plane.draw_fill();
const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_live_render_passes(
pp::panopainter::LegacyNodeStrokePreviewLiveRenderRequest {
.brush = *b,
.pass_orchestration = pass_orchestration,
.prepared_strokes = prepared_strokes,
.stroke_texture = m_tex,
.mixer_rtt = m_rtt_mixer,
.render_target = m_rtt,
.background_texture = m_tex_background,
.dual_texture = m_tex_dual,
.preview_texture = m_tex_preview,
.linear_sampler = m_sampler_linear,
.repeat_sampler = m_sampler_linear_repeat,
.zoom = zoom,
.min_flow = m_min_flow,
.copy_stroke_destination = pass_orchestration.copy_stroke_destination,
.size = size,
.bind_dual_pass_textures = [](const Brush& dual_brush) {
bind_stroke_preview_dual_pass_textures(dual_brush);
},
.capture_background = [&](bool colorize) {
execute_stroke_preview_background_capture_pass(
size,
colorize,
m_tex_background,
[&] {
m_plane.draw_fill();
});
},
.compute_frames = [&](const Stroke& stroke, float frame_zoom) {
return stroke_draw_compute(stroke, frame_zoom);
},
.draw_samples = [&](std::array<vertex_t, 4>& shapes, Texture2D& texture, bool copy_stroke_destination) {
return stroke_draw_samples(shapes, texture, copy_stroke_destination);
},
.draw_mix = [&](const glm::vec2& bb_min, const glm::vec2& bb_sz) {
stroke_draw_mix(bb_min, bb_sz);
},
.unbind_mixer_texture = [&] {
set_active_texture_unit(3U);
m_rtt_mixer.unbindTexture();
},
.bind_pattern_texture = [&] {
b->m_pattern_texture ? b->m_pattern_texture->bind() : unbind_texture_2d();
},
.draw_composite = [&] {
m_plane.draw_fill();
},
});
assert(sequence_ok);

View File

@@ -5,20 +5,12 @@
#include "rtt.h"
#include "brush.h"
#include "texture.h"
#include "legacy_node_stroke_preview_draw_services.h"
#include "legacy_node_stroke_preview_execution_services.h"
class NodeStrokePreview : public NodeBorder
{
struct StrokeFrame
{
glm::vec4 col;
float flow;
float opacity;
std::array<vertex_t, 4> shapes;
glm::vec4 m_mixer_rect;
};
using StrokeMainLivePassRequest = pp::panopainter::LegacyNodeStrokePreviewMainLivePassRequestT<StrokeFrame>;
using StrokeFrame = pp::panopainter::LegacyNodeStrokePreviewFrame;
static RTT m_rtt;
static RTT m_rtt_mixer;
@@ -55,7 +47,7 @@ public:
void stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz);
// return rect {origin, size}
glm::vec4 stroke_draw_samples(std::array<vertex_t, 4>& P, Texture2D& blend_tex, bool copy_stroke_destination);
std::vector<StrokeFrame> stroke_draw_compute(Stroke& stroke, float zoom) const;
std::vector<StrokeFrame> stroke_draw_compute(const Stroke& stroke, float zoom) const;
void draw_stroke();
void draw_stroke_immediate();
Image render_to_image();