Extract canvas stroke commit and brush preset services
This commit is contained in:
555
src/legacy_canvas_stroke_commit_services.cpp
Normal file
555
src/legacy_canvas_stroke_commit_services.cpp
Normal file
@@ -0,0 +1,555 @@
|
||||
#include "pch.h"
|
||||
#include "canvas.h"
|
||||
#include "app.h"
|
||||
#include "legacy_canvas_stroke_commit_services.h"
|
||||
#include "legacy_canvas_stroke_composite_services.h"
|
||||
#include "legacy_canvas_stroke_execution_services.h"
|
||||
#include "legacy_canvas_stroke_erase_services.h"
|
||||
#include "legacy_canvas_stroke_edge_services.h"
|
||||
#include "legacy_canvas_stroke_shader_services.h"
|
||||
#include "legacy_ui_gl_dispatch.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
|
||||
GLenum blend_state()
|
||||
{
|
||||
return static_cast<GLenum>(pp::renderer::gl::blend_state());
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
bool query_canvas_capability(std::uint32_t state)
|
||||
{
|
||||
return pp::legacy::ui_gl::query_capability(state, "Canvas");
|
||||
}
|
||||
|
||||
void apply_canvas_clear_color(std::array<float, 4> color)
|
||||
{
|
||||
pp::legacy::ui_gl::set_clear_color(color, "Canvas");
|
||||
}
|
||||
|
||||
void apply_canvas_capability(std::uint32_t capability, bool enabled)
|
||||
{
|
||||
pp::legacy::ui_gl::set_capability(capability, enabled, "Canvas");
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
struct CanvasStrokeCommitPrelude {
|
||||
pp::renderer::gl::OpenGlViewportRect viewport;
|
||||
std::array<float, 4> clear_color;
|
||||
bool blend;
|
||||
ActionStroke* action;
|
||||
};
|
||||
|
||||
void stamp_canvas_stroke_commit_action(
|
||||
Canvas& canvas,
|
||||
ActionStroke* action);
|
||||
|
||||
void capture_canvas_stroke_commit_layer_state(
|
||||
Canvas& canvas,
|
||||
ActionStroke* action,
|
||||
int i);
|
||||
|
||||
void apply_canvas_stroke_commit_dirty_mutation(
|
||||
Canvas& canvas,
|
||||
int i);
|
||||
|
||||
void copy_canvas_stroke_commit_layer_image(
|
||||
Canvas& canvas,
|
||||
int i);
|
||||
|
||||
template <typename SetActiveTextureUnit>
|
||||
static auto make_canvas_stroke_commit_callbacks(
|
||||
Canvas& canvas,
|
||||
pp::renderer::gl::OpenGlViewportRect vp,
|
||||
std::array<float, 4> cc,
|
||||
bool blend,
|
||||
SetActiveTextureUnit&& set_active_texture_unit,
|
||||
ActionStroke* action,
|
||||
const Stroke* current_stroke,
|
||||
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
||||
const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material)
|
||||
{
|
||||
const auto& b = current_stroke->m_brush;
|
||||
auto bind_commit_inputs = [&](int i) {
|
||||
pp::panopainter::bind_legacy_canvas_stroke_commit_face_inputs(
|
||||
sequence,
|
||||
[&](int texture_slot) {
|
||||
set_active_texture_unit(texture_slot);
|
||||
},
|
||||
[&](pp::paint_renderer::CanvasStrokeCommitTextureRole role) {
|
||||
switch (role) {
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::layer_scratch:
|
||||
canvas.m_tex2[i].bind();
|
||||
break;
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::stroke:
|
||||
canvas.m_tmp[i].bindTexture();
|
||||
break;
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::selection_mask:
|
||||
canvas.m_smask.rtt(i).bindTexture();
|
||||
break;
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::dual_stroke:
|
||||
canvas.m_tmp_dual[i].bindTexture();
|
||||
break;
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::pattern:
|
||||
b->m_pattern_texture ? b->m_pattern_texture->bind() : unbind_texture_2d();
|
||||
break;
|
||||
}
|
||||
},
|
||||
[&](pp::paint_renderer::CanvasStrokeCommitTextureRole role, int texture_slot) {
|
||||
switch (role) {
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::layer_scratch:
|
||||
canvas.m_sampler.bind(texture_slot);
|
||||
break;
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::stroke:
|
||||
canvas.m_sampler_nearest.bind(texture_slot);
|
||||
break;
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::selection_mask:
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::dual_stroke:
|
||||
canvas.m_sampler.bind(texture_slot);
|
||||
break;
|
||||
case pp::paint_renderer::CanvasStrokeCommitTextureRole::pattern:
|
||||
canvas.m_sampler_stencil.bind(texture_slot);
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
return pp::panopainter::make_legacy_canvas_stroke_commit_callbacks(
|
||||
[&]() {
|
||||
canvas.m_dirty = false;
|
||||
canvas.m_dirty_stroke = true; // new stroke ready for timelapse capture
|
||||
App::I->redraw = true;
|
||||
canvas.m_unsaved = true;
|
||||
App::I->title_update();
|
||||
},
|
||||
[]() {},
|
||||
[&]() {
|
||||
apply_canvas_viewport(0, 0, canvas.m_width, canvas.m_height);
|
||||
apply_canvas_capability(blend_state(), false);
|
||||
},
|
||||
[&]() {
|
||||
blend ? apply_canvas_capability(blend_state(), true) : apply_canvas_capability(blend_state(), false);
|
||||
apply_canvas_viewport(vp.x, vp.y, vp.width, vp.height);
|
||||
apply_canvas_clear_color(cc);
|
||||
set_active_texture_unit(0);
|
||||
},
|
||||
[&]() { stamp_canvas_stroke_commit_action(canvas, action); },
|
||||
[&]() {
|
||||
canvas.stroke_commit_timelapse();
|
||||
},
|
||||
[](int) {},
|
||||
[&](int i) { capture_canvas_stroke_commit_layer_state(canvas, action, i); },
|
||||
[&](int i) { apply_canvas_stroke_commit_dirty_mutation(canvas, i); },
|
||||
[&](int i) { copy_canvas_stroke_commit_layer_image(canvas, i); },
|
||||
[&](int i) {
|
||||
bind_commit_inputs(i);
|
||||
},
|
||||
[&](int) {
|
||||
pp::panopainter::execute_legacy_canvas_stroke_commit_erase(
|
||||
[&]() {
|
||||
pp::panopainter::setup_legacy_stroke_erase_shader(
|
||||
pp::panopainter::LegacyStrokeEraseUniforms {
|
||||
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
|
||||
.texture_slot = 0,
|
||||
.stroke_texture_slot = 1,
|
||||
.mask_texture_slot = 2,
|
||||
.alpha = 1.0f,
|
||||
.mask_enabled = canvas.m_smask_active,
|
||||
});
|
||||
},
|
||||
[&]() {
|
||||
canvas.m_plane.draw_fill();
|
||||
});
|
||||
},
|
||||
[&](int) {
|
||||
glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale);
|
||||
if (b->m_pattern_flipx) patt_scale.x *= -1.f;
|
||||
if (b->m_pattern_flipy) patt_scale.y *= -1.f;
|
||||
|
||||
pp::panopainter::execute_legacy_canvas_stroke_commit_paint(
|
||||
[&]() {
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = canvas.m_size,
|
||||
.pattern = {
|
||||
.scale = patt_scale,
|
||||
.invert = static_cast<float>(b->m_pattern_invert),
|
||||
.brightness = b->m_pattern_brightness,
|
||||
.contrast = b->m_pattern_contrast,
|
||||
.depth = b->m_pattern_depth,
|
||||
.blend_mode = b->m_pattern_blend_mode,
|
||||
.offset = canvas.m_pattern_offset,
|
||||
},
|
||||
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
|
||||
.layer_alpha = 1.0f,
|
||||
.alpha_lock = canvas.m_layers[canvas.m_current_layer_idx]->m_alpha_locked,
|
||||
.mask_enabled = canvas.m_smask_active,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = b->m_blend_mode,
|
||||
.use_dual = stroke_material.composite_pass.use_dual,
|
||||
.dual_blend_mode = stroke_material.composite_pass.dual_blend_mode,
|
||||
.dual_alpha = stroke_material.composite_pass.dual_alpha,
|
||||
.use_pattern = stroke_material.composite_pass.use_pattern,
|
||||
});
|
||||
},
|
||||
[&]() {
|
||||
canvas.m_plane.draw_fill();
|
||||
});
|
||||
},
|
||||
[&](int i) {
|
||||
const pp::panopainter::LegacyStrokeDilateUniforms dilate_uniforms {
|
||||
.mvp = glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f),
|
||||
};
|
||||
const pp::panopainter::LegacyCanvasStrokeCommitCopyExtent copy_extent {
|
||||
.width = canvas.m_width,
|
||||
.height = canvas.m_height,
|
||||
};
|
||||
pp::panopainter::copy_legacy_canvas_stroke_commit_to_dilate_source(
|
||||
sequence,
|
||||
[&]() {
|
||||
pp::panopainter::setup_legacy_stroke_dilate_shader(dilate_uniforms);
|
||||
},
|
||||
[&](int texture_slot) {
|
||||
set_active_texture_unit(texture_slot);
|
||||
},
|
||||
[&]() {
|
||||
canvas.m_tex2[i].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);
|
||||
},
|
||||
copy_extent);
|
||||
},
|
||||
[&](int) {
|
||||
pp::panopainter::execute_legacy_canvas_stroke_commit_dilate([&]() {
|
||||
canvas.m_plane.draw_fill();
|
||||
});
|
||||
},
|
||||
[&](int i) {
|
||||
canvas.m_layers[canvas.m_current_layer_idx]->rtt(i).unbindFramebuffer();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename BuildRequest>
|
||||
static auto execute_canvas_stroke_commit_sequence(
|
||||
BuildRequest&& build_request)
|
||||
{
|
||||
return pp::panopainter::execute_legacy_canvas_stroke_commit_sequence(
|
||||
build_request());
|
||||
}
|
||||
|
||||
template <typename SetActiveTextureUnit>
|
||||
static auto make_canvas_stroke_commit_request(
|
||||
Canvas& canvas,
|
||||
pp::renderer::gl::OpenGlViewportRect vp,
|
||||
std::array<float, 4> cc,
|
||||
bool blend,
|
||||
SetActiveTextureUnit&& set_active_texture_unit,
|
||||
ActionStroke* action,
|
||||
const Stroke* current_stroke,
|
||||
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
||||
const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material)
|
||||
{
|
||||
const auto commit_callbacks = make_canvas_stroke_commit_callbacks(
|
||||
canvas,
|
||||
vp,
|
||||
cc,
|
||||
blend,
|
||||
std::forward<SetActiveTextureUnit>(set_active_texture_unit),
|
||||
action,
|
||||
current_stroke,
|
||||
sequence,
|
||||
stroke_material);
|
||||
|
||||
const std::array<pp::panopainter::LegacyCanvasStrokeCommitFace, 6> faces {
|
||||
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 0, .dirty = canvas.m_dirty_face[0] },
|
||||
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 1, .dirty = canvas.m_dirty_face[1] },
|
||||
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 2, .dirty = canvas.m_dirty_face[2] },
|
||||
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 3, .dirty = canvas.m_dirty_face[3] },
|
||||
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 4, .dirty = canvas.m_dirty_face[4] },
|
||||
pp::panopainter::LegacyCanvasStrokeCommitFace { .index = 5, .dirty = canvas.m_dirty_face[5] },
|
||||
};
|
||||
|
||||
return pp::panopainter::make_legacy_canvas_stroke_commit_request(faces, sequence, commit_callbacks);
|
||||
}
|
||||
|
||||
template <typename SetActiveTextureUnit>
|
||||
static auto execute_canvas_stroke_commit_request(
|
||||
Canvas& canvas,
|
||||
pp::renderer::gl::OpenGlViewportRect vp,
|
||||
std::array<float, 4> cc,
|
||||
bool blend,
|
||||
SetActiveTextureUnit&& set_active_texture_unit,
|
||||
ActionStroke* action,
|
||||
const Stroke* current_stroke,
|
||||
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
||||
const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material)
|
||||
{
|
||||
return execute_canvas_stroke_commit_sequence([&]() {
|
||||
return make_canvas_stroke_commit_request(
|
||||
canvas,
|
||||
vp,
|
||||
cc,
|
||||
blend,
|
||||
std::forward<SetActiveTextureUnit>(set_active_texture_unit),
|
||||
action,
|
||||
current_stroke,
|
||||
sequence,
|
||||
stroke_material);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename SetActiveTextureUnit>
|
||||
static auto execute_canvas_stroke_commit_dispatch(
|
||||
Canvas& canvas,
|
||||
pp::renderer::gl::OpenGlViewportRect vp,
|
||||
std::array<float, 4> cc,
|
||||
bool blend,
|
||||
SetActiveTextureUnit&& set_active_texture_unit,
|
||||
ActionStroke* action,
|
||||
const Stroke* current_stroke,
|
||||
const pp::paint_renderer::CanvasStrokeCommitSequencePlan& sequence,
|
||||
const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material)
|
||||
{
|
||||
return execute_canvas_stroke_commit_request(
|
||||
canvas,
|
||||
vp,
|
||||
cc,
|
||||
blend,
|
||||
std::forward<SetActiveTextureUnit>(set_active_texture_unit),
|
||||
action,
|
||||
current_stroke,
|
||||
sequence,
|
||||
stroke_material);
|
||||
}
|
||||
|
||||
CanvasStrokeCommitPrelude make_canvas_stroke_commit_prelude(Canvas& canvas)
|
||||
{
|
||||
CanvasStrokeCommitPrelude prelude {
|
||||
.viewport = query_canvas_viewport(),
|
||||
.clear_color = query_canvas_clear_color(),
|
||||
.blend = query_canvas_capability(blend_state()),
|
||||
.action = new ActionStroke,
|
||||
};
|
||||
prelude.action->was_saved = !canvas.m_unsaved;
|
||||
return prelude;
|
||||
}
|
||||
|
||||
pp::paint_renderer::CanvasStrokeCommitSequencePlan
|
||||
make_canvas_stroke_commit_sequence_plan(
|
||||
const Canvas& canvas,
|
||||
kCanvasMode current_mode,
|
||||
int current_layer_idx,
|
||||
bool smask_active,
|
||||
const pp::paint_renderer::CanvasStrokeMaterialPlan& stroke_material)
|
||||
{
|
||||
return pp::paint_renderer::plan_canvas_stroke_commit_sequence(
|
||||
pp::paint_renderer::CanvasStrokeCommitRequest {
|
||||
.erase_mode = current_mode == kCanvasMode::Erase,
|
||||
.alpha_locked = canvas.m_layers[current_layer_idx]->m_alpha_locked,
|
||||
.selection_mask_active = smask_active,
|
||||
.dual_stroke_enabled = stroke_material.composite_pass.use_dual,
|
||||
.pattern_enabled = stroke_material.composite_pass.use_pattern,
|
||||
});
|
||||
}
|
||||
|
||||
void stamp_canvas_stroke_commit_action(
|
||||
Canvas& canvas,
|
||||
ActionStroke* action)
|
||||
{
|
||||
action->m_layer_idx = canvas.m_current_layer_idx;
|
||||
action->m_frame_idx = canvas.layer().m_frame_index;
|
||||
action->m_canvas = &canvas;
|
||||
ActionManager::add(action);
|
||||
}
|
||||
|
||||
void capture_canvas_stroke_commit_layer_state(
|
||||
Canvas& canvas,
|
||||
ActionStroke* action,
|
||||
int i)
|
||||
{
|
||||
canvas.m_layers[canvas.m_current_layer_idx]->rtt(i).bindFramebuffer();
|
||||
|
||||
glm::vec2 box_sz = zw(canvas.m_dirty_box[i]) - xy(canvas.m_dirty_box[i]);
|
||||
action->m_image[i] = std::make_unique<uint8_t[]>(
|
||||
static_cast<std::size_t>(box_sz.x * box_sz.y * 4));
|
||||
canvas.m_layers[canvas.m_current_layer_idx]->rtt(i).readPixelsRgba8(
|
||||
static_cast<int>(canvas.m_dirty_box[i].x),
|
||||
static_cast<int>(canvas.m_dirty_box[i].y),
|
||||
static_cast<int>(box_sz.x),
|
||||
static_cast<int>(box_sz.y),
|
||||
action->m_image[i].get());
|
||||
|
||||
action->m_box[i] = canvas.m_dirty_box[i];
|
||||
action->m_old_box[i] = canvas.m_layers[canvas.m_current_layer_idx]->box(i);
|
||||
action->m_old_dirty[i] = canvas.m_layers[canvas.m_current_layer_idx]->face(i);
|
||||
}
|
||||
|
||||
void apply_canvas_stroke_commit_dirty_mutation(
|
||||
Canvas& canvas,
|
||||
int i)
|
||||
{
|
||||
if (!canvas.m_layers[canvas.m_current_layer_idx]->m_alpha_locked) {
|
||||
auto& lbox = canvas.m_layers[canvas.m_current_layer_idx]->box(i);
|
||||
lbox = glm::vec4(
|
||||
glm::min(xy(canvas.m_dirty_box[i]), xy(lbox)),
|
||||
glm::max(zw(canvas.m_dirty_box[i]), zw(lbox)));
|
||||
}
|
||||
canvas.m_layers[canvas.m_current_layer_idx]->face(i) = true;
|
||||
}
|
||||
|
||||
void copy_canvas_stroke_commit_layer_image(
|
||||
Canvas& canvas,
|
||||
int i)
|
||||
{
|
||||
set_active_texture_unit(0);
|
||||
canvas.m_tex2[i].bind();
|
||||
copy_framebuffer_to_texture_2d(0, 0, 0, 0, canvas.m_width, canvas.m_height);
|
||||
canvas.m_tex2[i].unbind();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
glm::vec4 Canvas::stroke_draw_samples(
|
||||
int i,
|
||||
std::vector<vertex_t>& P,
|
||||
bool copy_stroke_destination)
|
||||
{
|
||||
constexpr std::array destination_texture_binding {
|
||||
pp::panopainter::LegacyCanvasStrokeTextureBinding {
|
||||
.input = pp::panopainter::LegacyCanvasStrokeTextureInput::stroke_destination,
|
||||
.slot = 1,
|
||||
},
|
||||
};
|
||||
const auto result = pp::panopainter::execute_legacy_canvas_stroke_face_sample_polygon(
|
||||
make_stroke_draw_samples_request(
|
||||
i,
|
||||
P,
|
||||
copy_stroke_destination),
|
||||
destination_texture_binding,
|
||||
make_stroke_draw_samples_destination_texture_dispatch(i));
|
||||
|
||||
return result.dirty_bounds;
|
||||
}
|
||||
|
||||
pp::panopainter::LegacyCanvasStrokeTextureInputDispatch Canvas::make_stroke_draw_samples_destination_texture_dispatch(
|
||||
int face_index)
|
||||
{
|
||||
return pp::panopainter::make_legacy_canvas_stroke_destination_texture_dispatch(
|
||||
[&](int texture_slot) {
|
||||
set_active_texture_unit(texture_slot);
|
||||
},
|
||||
[&, face_index] {
|
||||
m_tex[face_index].bind(); // bg, copy of framebuffer (copied before drawing)
|
||||
},
|
||||
[&, face_index] {
|
||||
m_tex[face_index].unbind();
|
||||
});
|
||||
}
|
||||
|
||||
pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest Canvas::make_stroke_draw_samples_request(
|
||||
int face_index,
|
||||
std::vector<vertex_t>& polygon_vertices,
|
||||
bool copy_stroke_destination)
|
||||
{
|
||||
return pp::panopainter::LegacyStrokeFaceSamplePolygonExecutionRequest {
|
||||
.context = "Canvas::stroke_draw_samples",
|
||||
.target_size = { m_width, m_height },
|
||||
.polygon_vertices = polygon_vertices,
|
||||
.face_index = face_index,
|
||||
.copy_stroke_destination = copy_stroke_destination,
|
||||
.copy_framebuffer_to_destination_texture = [](
|
||||
int,
|
||||
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);
|
||||
},
|
||||
.upload_brush_vertices = [&](int, std::span<const vertex_t> vertices) {
|
||||
m_brush_shape.update_vertices(
|
||||
const_cast<vertex_t*>(vertices.data()),
|
||||
static_cast<int>(vertices.size()));
|
||||
},
|
||||
.draw_brush_shape = [&](int) {
|
||||
m_brush_shape.draw_fill();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
void Canvas::stroke_commit()
|
||||
{
|
||||
if (!m_dirty || m_layers.empty())
|
||||
return;
|
||||
const auto prelude = make_canvas_stroke_commit_prelude(*this);
|
||||
|
||||
const auto& b = m_current_stroke->m_brush;
|
||||
const auto stroke_material = canvas_stroke_material_plan(*b, false);
|
||||
const auto stroke_commit_sequence = make_canvas_stroke_commit_sequence_plan(
|
||||
*this,
|
||||
m_current_mode,
|
||||
m_current_layer_idx,
|
||||
m_smask_active,
|
||||
stroke_material);
|
||||
[[maybe_unused]] const auto commit_result = execute_canvas_stroke_commit_dispatch(
|
||||
*this,
|
||||
prelude.viewport,
|
||||
prelude.clear_color,
|
||||
prelude.blend,
|
||||
[&](int texture_slot) {
|
||||
set_active_texture_unit(texture_slot);
|
||||
},
|
||||
prelude.action,
|
||||
m_current_stroke.get(),
|
||||
stroke_commit_sequence,
|
||||
stroke_material);
|
||||
}
|
||||
Reference in New Issue
Block a user