Extract canvas stroke runtime and preview draw shells
This commit is contained in:
286
src/canvas.cpp
286
src/canvas.cpp
@@ -9,6 +9,7 @@
|
||||
#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"
|
||||
@@ -252,12 +253,6 @@ void delete_canvas_renderbuffer(GLuint renderbuffer)
|
||||
|
||||
}
|
||||
|
||||
|
||||
pp::panopainter::LegacyCanvasStrokeMixPassShell make_canvas_stroke_mix_pass_shell(
|
||||
Canvas& canvas,
|
||||
const glm::vec2& bb_min,
|
||||
const glm::vec2& bb_sz);
|
||||
|
||||
Canvas* Canvas::I;
|
||||
std::vector<CanvasMode*> Canvas::modes[] = {
|
||||
{ new CanvasModePen, new CanvasModeBasicCamera }, // brush
|
||||
@@ -307,114 +302,16 @@ glm::mat4 Canvas::m_plane_transform[6] = {
|
||||
glm::lookAt(glm::vec3(), { 0,-1, 0}, {0, 0, 1}), // bottom
|
||||
};
|
||||
|
||||
void Canvas::stroke_end()
|
||||
{
|
||||
if (!m_current_stroke)
|
||||
return;
|
||||
if (m_current_stroke->has_sample())
|
||||
{
|
||||
m_commit_delayed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_show_tmp = false;
|
||||
stroke_commit();
|
||||
m_current_stroke = nullptr;
|
||||
}
|
||||
}
|
||||
void Canvas::stroke_cancel()
|
||||
{
|
||||
if (!m_current_stroke)
|
||||
return;
|
||||
m_current_stroke = nullptr;
|
||||
m_show_tmp = false;
|
||||
}
|
||||
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)
|
||||
{
|
||||
gl_state gl;
|
||||
gl.save();
|
||||
const auto mix_shell = make_canvas_stroke_mix_pass_shell(*this, bb_min, bb_sz);
|
||||
[[maybe_unused]] const auto mix_result = pp::panopainter::execute_legacy_canvas_stroke_mix_pass_shell(
|
||||
mix_shell.setup.begin,
|
||||
mix_shell.setup.end,
|
||||
mix_shell.request);
|
||||
|
||||
gl.restore();
|
||||
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
|
||||
{
|
||||
// intersect P with the current face to clip diverging points from the plane
|
||||
const auto unp_vp = zw(m_box);
|
||||
const auto unp_inv = glm::inverse(m_proj * m_mv);
|
||||
std::array<std::vector<vertex_t>, 6> ret;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
struct ray_t {
|
||||
glm::vec3 o;
|
||||
glm::vec3 d;
|
||||
vertex_t v;
|
||||
ray_t(glm::vec3 o, glm::vec3 d, vertex_t v) : o(o), d(d), v(v) { }
|
||||
};
|
||||
std::vector<ray_t> rays;
|
||||
if (project_3d)
|
||||
{
|
||||
rays.reserve(B.size());
|
||||
for (auto const& b : B)
|
||||
rays.emplace_back(glm::vec3(0), b.pos, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto P = poly_intersect(B.data(), B.data() + 4, m_plane_shape[i]);
|
||||
rays.reserve(P.size());
|
||||
for (auto const& p : P)
|
||||
{
|
||||
glm::vec3 ray_origin, ray_dir;
|
||||
auto clip_space = glm::vec2(p.pos.x, unp_vp.y - p.pos.y - 1.f) / unp_vp * 2.f - 1.f;
|
||||
auto wp0 = unp_inv * glm::vec4(clip_space, 0, 1);
|
||||
auto wp1 = unp_inv * glm::vec4(clip_space, .5, 1);
|
||||
ray_origin = xyz(wp0 / wp0.w);
|
||||
ray_dir = glm::normalize(xyz(wp1 / wp1.w) - ray_origin);
|
||||
rays.emplace_back(ray_origin, ray_dir, p);
|
||||
}
|
||||
}
|
||||
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
|
||||
std::vector<vertex_t> face_ret;
|
||||
face_ret.reserve(rays.size());
|
||||
for (auto const& r : rays)
|
||||
{
|
||||
glm::vec3 hit;
|
||||
float hit_t;
|
||||
if (ray_intersect(r.o, r.d, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit, hit_t))
|
||||
{
|
||||
glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1);
|
||||
|
||||
//P[j].uvs2 = xy(P[j].pos) / glm::vec2(App::I->width, App::I->height);
|
||||
vertex_t v;
|
||||
v.pos.x = -(plane_local.x * 0.5f - 0.5f) * m_width;
|
||||
v.pos.y = (plane_local.y * 0.5f + 0.5f) * m_height;
|
||||
|
||||
// Black magic - BEWARE!
|
||||
// interpolation perspective correction, use the current camera projection to correct the interpolation
|
||||
// because the new shape will have z fixed with an ortho projection when drawn to the face
|
||||
// we need to imitate the same perspective as the once in the camera
|
||||
// see: https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
|
||||
auto hit_cam = mv * glm::vec4(hit, 1);
|
||||
v.pos.z = 0;
|
||||
v.pos.w = hit_cam.z;
|
||||
v.uvs = r.v.uvs * hit_cam.z;
|
||||
v.uvs2 = r.v.uvs2 * hit_cam.z;
|
||||
face_ret.emplace_back(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (face_ret.size() >= 3)
|
||||
ret[i] = std::move(face_ret);
|
||||
}
|
||||
return ret;
|
||||
return pp::panopainter::legacy_canvas_stroke_draw_project(*this, B, project_3d, mv);
|
||||
}
|
||||
|
||||
static void execute_canvas_draw_merge_layer_composite(
|
||||
@@ -842,96 +739,6 @@ static void execute_canvas_draw_merge_plane_final_composite(
|
||||
}
|
||||
}
|
||||
|
||||
pp::panopainter::LegacyCanvasStrokeMixPassShell make_canvas_stroke_mix_pass_shell(
|
||||
Canvas& canvas,
|
||||
const glm::vec2& bb_min,
|
||||
const glm::vec2& bb_sz)
|
||||
{
|
||||
const auto layer_index = canvas.m_current_layer_idx;
|
||||
auto& current_layer = *canvas.m_layers[layer_index];
|
||||
std::array<glm::mat4, 6> plane_transform {};
|
||||
std::copy(std::begin(Canvas::m_plane_transform), std::end(Canvas::m_plane_transform), plane_transform.begin());
|
||||
const auto mix_planes = pp::panopainter::plan_legacy_canvas_stroke_mix_pass_planes(
|
||||
current_layer.m_visible,
|
||||
current_layer.m_opacity,
|
||||
glm::scale(glm::vec3(1, -1, 1)) * canvas.m_proj * canvas.m_mv,
|
||||
plane_transform,
|
||||
[&](int plane_index) {
|
||||
return current_layer.face(plane_index);
|
||||
});
|
||||
const auto& b = canvas.m_current_stroke->m_brush;
|
||||
return pp::panopainter::make_legacy_canvas_stroke_mix_pass_shell(
|
||||
[&] {
|
||||
canvas.m_mixer.bindFramebuffer();
|
||||
apply_canvas_viewport(0, 0, canvas.m_mixer.getWidth(), canvas.m_mixer.getHeight());
|
||||
apply_canvas_capability(depth_test_state(), false);
|
||||
apply_canvas_capability(scissor_test_state(), true);
|
||||
apply_canvas_capability(blend_state(), false);
|
||||
apply_canvas_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));
|
||||
},
|
||||
[&] {
|
||||
canvas.m_mixer.unbindFramebuffer();
|
||||
},
|
||||
"Canvas::stroke_draw_mix",
|
||||
canvas.m_size,
|
||||
mix_planes,
|
||||
[&] {
|
||||
canvas.m_sampler.bind(0);
|
||||
canvas.m_sampler.bind(1);
|
||||
canvas.m_sampler.bind(2);
|
||||
},
|
||||
[&] {
|
||||
canvas.m_sampler.unbind();
|
||||
},
|
||||
[&](int plane_index, const glm::mat4& plane_mvp_z) {
|
||||
(void)plane_index;
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = canvas.m_size,
|
||||
.mvp = plane_mvp_z,
|
||||
.pattern_texture_slot = 3,
|
||||
.layer_alpha = 1.0f,
|
||||
.alpha_lock = false,
|
||||
.mask_enabled = false,
|
||||
.use_fragcoord = false,
|
||||
.blend_mode = b->m_blend_mode,
|
||||
.use_dual = false,
|
||||
.use_pattern = false,
|
||||
});
|
||||
},
|
||||
[&](int plane_index) {
|
||||
set_active_texture_unit(0);
|
||||
current_layer.rtt(plane_index).bindTexture();
|
||||
},
|
||||
[&](int plane_index) {
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].bindTexture();
|
||||
},
|
||||
[&](int plane_index) {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).bindTexture();
|
||||
},
|
||||
[&] {
|
||||
canvas.m_node->m_face_plane.draw_fill();
|
||||
},
|
||||
[&](int plane_index) {
|
||||
set_active_texture_unit(2);
|
||||
canvas.m_smask.rtt(plane_index).unbindTexture();
|
||||
},
|
||||
[&](int plane_index) {
|
||||
set_active_texture_unit(1);
|
||||
canvas.m_tmp[plane_index].unbindTexture();
|
||||
},
|
||||
[&](int plane_index) {
|
||||
set_active_texture_unit(0);
|
||||
current_layer.rtt(plane_index).unbindTexture();
|
||||
});
|
||||
}
|
||||
|
||||
static pp::panopainter::LegacyCanvasDrawMergeTemporaryCompositeExecution
|
||||
make_canvas_draw_merge_temporary_paint_request(
|
||||
Canvas& canvas,
|
||||
@@ -1157,87 +964,8 @@ void Canvas::draw_merge(bool draw_checkerboard, std::array<bool, 6> faces /*= SI
|
||||
draw_checkerboard);
|
||||
}
|
||||
|
||||
void Canvas::stroke_update(glm::vec3 point, float pressure)
|
||||
{
|
||||
m_current_stroke->add_point(point, pressure);
|
||||
if (m_dual_stroke)
|
||||
m_dual_stroke->add_point(point, pressure);
|
||||
}
|
||||
void Canvas::stroke_start(glm::vec3 point, float pressure)
|
||||
{
|
||||
assert(App::I->is_render_thread());
|
||||
|
||||
// need to commit this now before starting a new stroke
|
||||
if (m_current_stroke && m_commit_delayed)
|
||||
{
|
||||
m_show_tmp = false;
|
||||
m_commit_delayed = false;
|
||||
stroke_commit();
|
||||
m_current_stroke = nullptr;
|
||||
m_dual_stroke = nullptr;
|
||||
}
|
||||
|
||||
m_pattern_offset = m_current_brush->m_pattern_rand_offset ?
|
||||
glm::vec2((rand()%1000)*0.001f, (rand()%1000)*0.001f) :
|
||||
glm::vec2(0);
|
||||
|
||||
m_current_stroke = std::make_unique<Stroke>();
|
||||
m_current_stroke->m_camera.rot = m_cam_rot;
|
||||
m_current_stroke->m_camera.fov = m_cam_fov;
|
||||
if (m_current_mode == kCanvasMode::Line)
|
||||
m_current_stroke->m_filter_points = false;
|
||||
m_current_stroke->randomize_prng();
|
||||
m_current_stroke->start(m_current_brush);
|
||||
m_current_stroke->add_point(point, pressure);
|
||||
|
||||
// Generate a brush for the dual-brush
|
||||
if (m_current_brush->m_dual_enabled)
|
||||
{
|
||||
auto dual_brush = std::make_shared<Brush>();
|
||||
dual_brush->m_tip_flow = m_current_brush->m_dual_flow;
|
||||
dual_brush->m_tip_opacity = m_current_brush->m_dual_opacity;
|
||||
dual_brush->m_tip_flipx = m_current_brush->m_dual_flipx;
|
||||
dual_brush->m_tip_flipy = m_current_brush->m_dual_flipy;
|
||||
dual_brush->m_tip_invert = m_current_brush->m_dual_invert;
|
||||
dual_brush->m_blend_mode = m_current_brush->m_dual_blend_mode;
|
||||
dual_brush->m_tip_randflipx = m_current_brush->m_dual_randflip;
|
||||
dual_brush->m_tip_randflipy = m_current_brush->m_dual_randflip;
|
||||
dual_brush->m_tip_size = m_current_brush->m_dual_size * m_current_brush->m_tip_size;
|
||||
dual_brush->m_tip_spacing = m_current_brush->m_dual_spacing;
|
||||
dual_brush->m_jitter_scatter = m_current_brush->m_dual_scatter;
|
||||
dual_brush->m_jitter_scatter_bothaxis = m_current_brush->m_dual_scatter_bothaxis;
|
||||
dual_brush->m_jitter_angle = m_current_brush->m_dual_rotate;
|
||||
dual_brush->m_tip_texture = m_current_brush->m_dual_texture;
|
||||
dual_brush->m_tip_aspect = m_current_brush->m_dual_aspect;
|
||||
m_dual_stroke = std::make_unique<Stroke>();
|
||||
m_dual_stroke->m_camera.rot = m_cam_rot;
|
||||
m_dual_stroke->m_camera.fov = m_cam_fov;
|
||||
m_dual_stroke->start(dual_brush);
|
||||
m_dual_stroke->add_point(point, pressure);
|
||||
}
|
||||
|
||||
auto const& l = m_layers[m_current_layer_idx];
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_dirty_box[i] = glm::vec4(m_width, m_height, 0, 0); // reset bounding box
|
||||
m_dirty_face[i] = false;
|
||||
|
||||
m_tmp[i].bindFramebuffer();
|
||||
m_tmp[i].clear({ 0, 0, 0, 0 });
|
||||
m_tmp[i].unbindFramebuffer();
|
||||
|
||||
if (m_current_brush->m_dual_enabled)
|
||||
{
|
||||
m_tmp_dual[i].bindFramebuffer();
|
||||
m_tmp_dual[i].clear({ 0, 0, 0, 0 });
|
||||
m_tmp_dual[i].unbindFramebuffer();
|
||||
}
|
||||
}
|
||||
m_mixer.bindFramebuffer();
|
||||
m_mixer.clear();
|
||||
m_mixer.unbindFramebuffer();
|
||||
m_show_tmp = true;
|
||||
}
|
||||
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()
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
|
||||
Reference in New Issue
Block a user