Extract node events, transform mode, and preview pass shells
This commit is contained in:
@@ -43,6 +43,8 @@ set(PP_LEGACY_RENDERER_GL_SOURCES
|
||||
set(PP_LEGACY_UI_CORE_SOURCES
|
||||
src/legacy_ui_node_loader.cpp
|
||||
src/legacy_ui_node_loader.h
|
||||
src/legacy_ui_node_event.cpp
|
||||
src/legacy_ui_node_event.h
|
||||
src/legacy_ui_node_execution.cpp
|
||||
src/layout.cpp
|
||||
src/node.cpp
|
||||
@@ -70,6 +72,7 @@ set(PP_LEGACY_APP_SOURCES
|
||||
src/canvas_modes.cpp
|
||||
src/legacy_canvas_mode_helpers.cpp
|
||||
src/legacy_canvas_mode_helpers.h
|
||||
src/legacy_canvas_mode_transform.cpp
|
||||
src/legacy_app_shell_services.cpp
|
||||
src/legacy_app_shell_services.h
|
||||
src/legacy_canvas_tool_services.cpp
|
||||
|
||||
@@ -81,11 +81,11 @@ Current hotspot files:
|
||||
|
||||
- `src/canvas.cpp`: 2122 lines
|
||||
- `src/app_layout.cpp`: 125 lines
|
||||
- `src/canvas_modes.cpp`: 1626 lines
|
||||
- `src/node.cpp`: 1368 lines
|
||||
- `src/canvas_modes.cpp`: 1014 lines
|
||||
- `src/node.cpp`: 995 lines
|
||||
- `src/main.cpp`: 271 lines
|
||||
- `src/node_panel_brush.cpp`: 652 lines
|
||||
- `src/node_stroke_preview.cpp`: 910 lines
|
||||
- `src/node_stroke_preview.cpp`: 751 lines
|
||||
- `src/node_canvas.cpp`: 877 lines
|
||||
- `src/app.cpp`: 575 lines
|
||||
- `src/app_dialogs.cpp`: 168 lines
|
||||
@@ -240,6 +240,10 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
`src/node_stroke_preview.cpp`, while the immediate preview pass-sequencing
|
||||
family inside `draw_stroke_immediate()` now also routes through
|
||||
`NodeStrokePreview::execute_stroke_draw_immediate_pass_sequence(...)`, while
|
||||
the remaining immediate preview pass shell now also routes through
|
||||
`execute_legacy_node_stroke_preview_draw_immediate_shell(...)`, which
|
||||
materially reduces the live preview-pass body even though broader
|
||||
worker/readback flow still remains inline, while
|
||||
`NodeCanvas::draw()` unmerged-pass blend-gate, layer-orientation, and
|
||||
callback-assembly setup now also route through
|
||||
`execute_node_canvas_draw_unmerged_pass(...)`, which trims another coherent
|
||||
@@ -256,7 +260,11 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
larger stroke commit/sample execution family now also route through
|
||||
`src/legacy_canvas_stroke_commit_services.*` instead of staying inline in
|
||||
`src/canvas.cpp`, which trims another large retained stroke-render and
|
||||
viewport-state execution family from the live canvas shell,
|
||||
viewport-state execution family from the live canvas shell, while the
|
||||
`CanvasModeTransform` interaction family now also routes through
|
||||
`src/legacy_canvas_mode_transform.cpp` instead of staying inline in
|
||||
`src/canvas_modes.cpp`, which materially thins another retained canvas-view
|
||||
and transform-mode execution pocket,
|
||||
while `NodePanelBrush` save/restore/scan/reload/find/get-path ownership now
|
||||
routes through `src/legacy_brush_panel_services.*` instead of staying inline
|
||||
in `src/node_panel_brush.cpp`, which trims another retained brush-workflow
|
||||
@@ -274,7 +282,11 @@ Current architecture mismatches that must be treated as real blockers:
|
||||
`src/canvas_modes.cpp`, while
|
||||
preview stroke preparation, dual-brush setup, and live pass-orchestration
|
||||
request assembly now also route through retained preview execution helpers,
|
||||
while `Node` child attach/detach/reorder operations now route through named
|
||||
while `Node::on_event(...)` plus mouse/key capture and release ownership now
|
||||
also route through `src/legacy_ui_node_event.*` instead of staying inline in
|
||||
`src/node.cpp`, which materially thins the base scene-graph event shell
|
||||
without changing its public surface, while `Node` child attach/detach/reorder
|
||||
operations now route through named
|
||||
local helpers in `src/node.cpp`, and `Node::load_internal(...)` child XML
|
||||
loading now also routes through `src/legacy_ui_node_loader.*`, which makes
|
||||
the scene-graph mutation and child-instantiation paths easier to reason
|
||||
|
||||
@@ -91,7 +91,7 @@ Status: In Progress
|
||||
|
||||
Why now:
|
||||
`src/canvas.cpp` is still the biggest single architectural blocker at about
|
||||
2122 lines.
|
||||
2122 lines, with `src/canvas_modes.cpp` still large at about 1014 lines.
|
||||
|
||||
Current slice:
|
||||
- Canvas state-management helpers for picking, clear/clear-all, layer
|
||||
@@ -122,6 +122,10 @@ Current slice:
|
||||
`src/legacy_canvas_mode_helpers.*` instead of staying inline in
|
||||
`src/canvas_modes.cpp`, which trims another coherent retained canvas-view
|
||||
interaction pocket from the broader canvas/render hotspot family.
|
||||
- The `CanvasModeTransform` interaction family now also lives in
|
||||
`src/legacy_canvas_mode_transform.cpp` instead of staying inline in
|
||||
`src/canvas_modes.cpp`, which materially thins another retained
|
||||
transform-mode pocket from the broader canvas/render hotspot family.
|
||||
|
||||
Write scope:
|
||||
- `src/canvas.cpp`
|
||||
@@ -182,6 +186,11 @@ Current slice:
|
||||
which trims another coherent setup pocket from
|
||||
`src/node_stroke_preview.cpp` even though worker/readback ownership and
|
||||
broader preview flow still remain inline.
|
||||
- The remaining immediate preview pass shell in
|
||||
`NodeStrokePreview::draw_stroke_immediate()` now also routes through
|
||||
`execute_legacy_node_stroke_preview_draw_immediate_shell(...)`, which
|
||||
materially reduces the live preview-pass body even though worker/readback
|
||||
ownership still remains inline.
|
||||
- `NodeCanvas` merged-path per-plane merged-texture draw execution now also
|
||||
routes through `execute_legacy_canvas_draw_merge_layer_texture(...)`.
|
||||
- `NodeCanvas` merged-path and non-blend checkerboard background setup now also
|
||||
@@ -706,6 +715,10 @@ Current slice:
|
||||
now also lives in `src/legacy_ui_node_execution.cpp` instead of staying
|
||||
inline in `src/node.cpp`, which materially thins the base scene-graph file
|
||||
without changing its public surface.
|
||||
- `Node::on_event(...)` plus mouse/key capture and release now also live in
|
||||
`src/legacy_ui_node_event.*` instead of staying inline in `src/node.cpp`,
|
||||
which materially thins the base scene-graph event shell without changing its
|
||||
public surface.
|
||||
|
||||
Write scope:
|
||||
- `src/node.cpp`
|
||||
|
||||
@@ -947,557 +947,6 @@ void CanvasModeFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, cons
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CanvasModeTransform::init()
|
||||
{
|
||||
m_sphere.create(1.f, glm::radians(-10.f), glm::radians(10.f), glm::radians(-10.f), glm::radians(10.f), 1.f);
|
||||
m_circle.create<16>(1.f);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_shape[i].create();
|
||||
m_points_face[i].clear();
|
||||
}
|
||||
m_xform = glm::mat4(1);
|
||||
m_xform_local = glm::mat4(1);
|
||||
}
|
||||
|
||||
void CanvasModeTransform::enter(kCanvasMode prev)
|
||||
{
|
||||
m_commit_on_leave = false;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_shape[i].clear();
|
||||
m_points_face[i].clear();
|
||||
}
|
||||
|
||||
if (m_action == ActionType::Import)
|
||||
{
|
||||
float aspect = 1.f;
|
||||
if (m_source_image.data())
|
||||
{
|
||||
m_tex[0].create(m_source_image);
|
||||
aspect = (float)m_source_image.width / (float)m_source_image.height;
|
||||
}
|
||||
|
||||
auto center = zw(Canvas::I->m_box) * 0.5f;
|
||||
glm::vec2 bb_sz = glm::vec2(aspect, 1.f) * 100.f * App::I->zoom;
|
||||
glm::vec2 bb_min = center - bb_sz * 0.5f;
|
||||
glm::vec2 bb_max = center + bb_sz * 0.5f;
|
||||
glm::vec2 midpoint = (bb_min + bb_max) * 0.5f;
|
||||
|
||||
auto cam_up = glm::inverse(Canvas::I->m_mv) * glm::vec4(0, 1, 0, 1);
|
||||
auto center_mat = glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up));
|
||||
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up)));
|
||||
m_xform_local = glm::mat4(1);
|
||||
|
||||
corners.clear();
|
||||
corners.emplace_back(bb_min, 0); // A
|
||||
corners.emplace_back(bb_max, 0); // C
|
||||
corners.emplace_back(bb_max.x, bb_min.y, 0); // B
|
||||
corners.emplace_back(bb_min.x, bb_max.y, 0); // D
|
||||
corners.emplace_back(midpoint, 0);
|
||||
corners.emplace_back(midpoint + (bb_max - bb_min) * glm::vec2(0.75f, 0), 0);
|
||||
|
||||
for (auto& c : corners)
|
||||
c = center_mat * glm::vec4(Canvas::I->point_trace(c), 1);
|
||||
|
||||
m_points_face[0] = std::vector<vertex_t>({
|
||||
vertex_t(corners[0], { 0, 0 }),
|
||||
vertex_t(corners[2], { 1, 0 }),
|
||||
vertex_t(corners[1], { 1, 1 }),
|
||||
vertex_t(corners[3], { 0, 1 }),
|
||||
});
|
||||
auto shape3d = triangulate(m_points_face[0]);
|
||||
m_shape[0].update_vertices(shape3d.data(), (int)shape3d.size());
|
||||
|
||||
m_commit_on_leave = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid recursive loop, store the last different mode not using Transform
|
||||
static kCanvasMode last_prev = kCanvasMode::Draw;
|
||||
if (prev != kCanvasMode::Copy && prev != kCanvasMode::Cut && prev != kCanvasMode::Import)
|
||||
last_prev = prev;
|
||||
|
||||
if (prev != kCanvasMode::MaskFree && prev != kCanvasMode::MaskLine)
|
||||
{
|
||||
Canvas::set_mode(last_prev);
|
||||
return;
|
||||
}
|
||||
|
||||
auto m = static_cast<CanvasModeMaskBase*>(Canvas::I->modes[(int)prev][0]);
|
||||
|
||||
if (m->m_points2d.size() < 3)
|
||||
{
|
||||
Canvas::set_mode(last_prev);
|
||||
return;
|
||||
}
|
||||
|
||||
Canvas::I->m_smask_active = false;
|
||||
auto points = m->m_points2d;
|
||||
|
||||
Canvas::I->push_camera();
|
||||
Canvas::I->set_camera(m->m_selection_cam);
|
||||
|
||||
glm::vec2 bb_min(FLT_MAX);
|
||||
glm::vec2 bb_max(-FLT_MAX);
|
||||
for (auto p2d : points)
|
||||
{
|
||||
bb_min = glm::min(bb_min, p2d);
|
||||
bb_max = glm::max(bb_max, p2d);
|
||||
}
|
||||
glm::vec2 midpoint = (bb_min + bb_max) * 0.5f;
|
||||
auto cam_up = glm::inverse(Canvas::I->m_mv) * glm::vec4(0, 1, 0, 1);
|
||||
auto center_mat = glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up));
|
||||
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up)));
|
||||
m_xform_local = glm::mat4(1);
|
||||
corners.clear();
|
||||
corners.emplace_back(bb_min, 0);
|
||||
corners.emplace_back(bb_max, 0);
|
||||
corners.emplace_back(bb_max.x, bb_min.y, 0);
|
||||
corners.emplace_back(bb_min.x, bb_max.y, 0);
|
||||
corners.emplace_back(midpoint, 0);
|
||||
corners.emplace_back(midpoint + (bb_max-bb_min) * glm::vec2(0.75f, 0), 0);
|
||||
for (auto& c : corners)
|
||||
c = center_mat * glm::vec4(Canvas::I->point_trace(c), 1);
|
||||
|
||||
for (int plane = 0; plane < 6; plane++)
|
||||
{
|
||||
auto face = Canvas::I->face_to_shape2D(plane);
|
||||
auto shape2d = poly_intersect(points, face);
|
||||
if (shape2d.size() < 3 || face.empty())
|
||||
{
|
||||
m_shape[plane].clear();
|
||||
m_points_face[plane].clear();
|
||||
continue;
|
||||
}
|
||||
m_points_face[plane].reserve(shape2d.size());
|
||||
glm::vec2 bb_min(Canvas::I->m_size);
|
||||
glm::vec2 bb_max(0, 0);
|
||||
for (auto p2d : shape2d)
|
||||
{
|
||||
p2d.y = Canvas::I->m_box.w - p2d.y - 1;
|
||||
auto p2d_clip = ((p2d / zw(Canvas::I->m_box)) * 2.f - 1.f);
|
||||
auto p3d_plane = Canvas::I->m_plane_unproject[plane] * glm::vec4(p2d_clip, 0, 1);
|
||||
if (p3d_plane.w < 0)
|
||||
continue;
|
||||
auto p3d_norm = -p3d_plane / p3d_plane.z;
|
||||
auto p2d_plane = xy(p3d_norm);
|
||||
auto p2d_plane_raster = (p2d_plane * 0.5f + 0.5f) * Canvas::I->m_size;
|
||||
auto p3d_world = Canvas::I->m_plane_transform[plane] * glm::vec4(p2d_plane, -1, 1);
|
||||
bb_min = glm::min(bb_min, p2d_plane_raster);
|
||||
bb_max = glm::max(bb_max, p2d_plane_raster);
|
||||
|
||||
//glm::vec3 pt_o, pt_d;
|
||||
//Canvas::I->point_unproject(p2d, pt_o, pt_d);
|
||||
|
||||
vertex_t v;
|
||||
v.pos = glm::vec4(xyz(p3d_world), 1);
|
||||
v.uvs = p2d_plane_raster;
|
||||
m_points_face[plane].push_back(v);
|
||||
}
|
||||
|
||||
if (m_points_face[plane].size() < 3)
|
||||
{
|
||||
m_shape[plane].clear();
|
||||
m_points_face[plane].clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto bb_sz = bb_max - bb_min;
|
||||
for (auto& v : m_points_face[plane])
|
||||
{
|
||||
v.uvs2 = v.uvs / Canvas::I->m_size;
|
||||
v.uvs = (v.uvs - bb_min) / bb_sz;
|
||||
v.pos = center_mat * v.pos;
|
||||
}
|
||||
|
||||
auto shape3d = triangulate(m_points_face[plane]);
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
m_shape[plane].update_vertices(shape3d.data(), (int)shape3d.size());
|
||||
Canvas::I->m_layers[Canvas::I->m_current_layer_idx]->rtt(plane).bindFramebuffer();
|
||||
m_tex[plane].create(bb_sz.x, bb_sz.y);
|
||||
m_tex[plane].bind();
|
||||
copy_framebuffer_to_texture_2d(
|
||||
0,
|
||||
0,
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y));
|
||||
m_tex[plane].unbind();
|
||||
Canvas::I->m_layers[Canvas::I->m_current_layer_idx]->rtt(plane).unbindFramebuffer();
|
||||
});
|
||||
|
||||
m_commit_on_leave = true;
|
||||
}
|
||||
|
||||
if (m_action == ActionType::Cut)
|
||||
{
|
||||
auto& layer = Canvas::I->m_layers[Canvas::I->m_current_layer_idx];
|
||||
|
||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||
|
||||
auto action = new ActionStroke;
|
||||
action->was_saved = !Canvas::I->m_unsaved;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane_camera = glm::lookAt(glm::vec3(0), Canvas::I->m_plane_origin[i], Canvas::I->m_plane_tangent[i]);
|
||||
auto mvp = proj * plane_camera * m_xform * m_xform_local;
|
||||
|
||||
glm::vec2 bb_min(Canvas::I->m_size);
|
||||
glm::vec2 bb_max(0, 0);
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
for (auto p : m_points_face[j])
|
||||
{
|
||||
auto p_clip = mvp * p.pos;
|
||||
auto p_norm = p_clip / p_clip.w;
|
||||
if (p_clip.w < 0 || glm::any(glm::greaterThan(glm::abs(xy(p_norm)), { 1, 1 })))
|
||||
continue;
|
||||
auto p_raster = (xy(p_norm) * 0.5f + 0.5f) * Canvas::I->m_size;
|
||||
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p_raster));
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::max(bb_max, p_raster));
|
||||
}
|
||||
}
|
||||
glm::vec2 pad(2);
|
||||
bb_min = glm::max({ 0, 0 }, glm::floor(bb_min) - pad);
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::ceil(bb_max) + pad);
|
||||
auto bb_sz = bb_max - bb_min;
|
||||
|
||||
if (bb_sz.x <= 0.f || bb_sz.y <= 0.f)
|
||||
continue;
|
||||
|
||||
action->m_image[i] = std::make_unique<uint8_t[]>(bb_sz.x * bb_sz.y * 4);
|
||||
action->m_box[i] = { bb_min, bb_max };
|
||||
action->m_old_box[i] = layer->box(i);
|
||||
action->m_old_dirty[i] = layer->face(i);
|
||||
|
||||
layer->face(i) = true;
|
||||
layer->box(i) = {
|
||||
glm::min(xy(layer->box(i)), bb_min),
|
||||
glm::max(zw(layer->box(i)), bb_max),
|
||||
};
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
apply_canvas_mode_viewport(0, 0, layer->w, layer->h);
|
||||
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 0, 0, 0, 0 },
|
||||
.mvp = mvp,
|
||||
});
|
||||
layer->rtt(i).bindFramebuffer();
|
||||
// copy framebuffer to action data
|
||||
layer->rtt(i).readPixelsRgba8(
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y),
|
||||
action->m_image[i].get());
|
||||
for (int j = 0; j < 6; j++)
|
||||
m_shape[j].draw_fill();
|
||||
layer->rtt(i).unbindFramebuffer();
|
||||
});
|
||||
}
|
||||
|
||||
action->m_layer_idx = Canvas::I->m_current_layer_idx;
|
||||
action->m_frame_idx = Canvas::I->layer().m_frame_index;
|
||||
action->m_canvas = Canvas::I;
|
||||
//action->m_stroke = std::move(m_current_stroke);
|
||||
ActionManager::add(action);
|
||||
|
||||
m_source_image.destroy();
|
||||
}
|
||||
|
||||
Canvas::I->pop_camera();
|
||||
}
|
||||
|
||||
void CanvasModeTransform::leave(kCanvasMode next)
|
||||
{
|
||||
if (!m_commit_on_leave)
|
||||
return;
|
||||
|
||||
auto& layer = Canvas::I->m_layers[Canvas::I->m_current_layer_idx];
|
||||
|
||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||
|
||||
auto action = new ActionStroke;
|
||||
action->was_saved = !Canvas::I->m_unsaved;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane_camera = glm::lookAt(glm::vec3(0), Canvas::I->m_plane_origin[i], Canvas::I->m_plane_tangent[i]);
|
||||
auto mv = plane_camera * m_xform * m_xform_local;
|
||||
auto mvp = proj * mv;
|
||||
|
||||
|
||||
std::vector<glm::vec2> poly2d;
|
||||
static std::vector<glm::vec2> face_corners{ {1,1}, {-1,1}, {-1,-1}, {1,-1} };
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
std::vector<glm::vec3> poly_cam;
|
||||
poly_cam.reserve(m_points_face[j].size());
|
||||
for (auto p : m_points_face[j])
|
||||
poly_cam.push_back(mv * p.pos);
|
||||
|
||||
auto poly_clipped = poly_clip_near(poly_cam, 0.01f);
|
||||
|
||||
for (auto p : poly_clipped)
|
||||
{
|
||||
auto p_clip = proj * glm::vec4(p, 1);
|
||||
if (p_clip.w < 0)
|
||||
continue;
|
||||
auto p_norm = p_clip / p_clip.w;
|
||||
poly2d.push_back(p_norm);
|
||||
}
|
||||
}
|
||||
|
||||
auto clipped = poly_intersect(poly2d, face_corners);
|
||||
|
||||
glm::vec2 bb_min(Canvas::I->m_size);
|
||||
glm::vec2 bb_max(0, 0);
|
||||
for (auto p_norm : clipped)
|
||||
{
|
||||
auto p_raster = (p_norm * 0.5f + 0.5f) * Canvas::I->m_size;
|
||||
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p_raster));
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::max(bb_max, p_raster));
|
||||
}
|
||||
glm::vec2 pad(2);
|
||||
bb_min = glm::max({ 0, 0 }, glm::floor(bb_min) - pad);
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::ceil(bb_max) + pad);
|
||||
auto bb_sz = bb_max - bb_min;
|
||||
|
||||
if (clipped.empty() || bb_sz.x <= 0.f || bb_sz.y <= 0.f)
|
||||
continue;
|
||||
|
||||
action->m_image[i] = std::make_unique<uint8_t[]>(bb_sz.x * bb_sz.y * 4);
|
||||
action->m_box[i] = { bb_min, bb_max };
|
||||
action->m_old_box[i] = layer->box(i);
|
||||
action->m_old_dirty[i] = layer->face(i);
|
||||
|
||||
layer->face(i) = true;
|
||||
layer->box(i) = {
|
||||
glm::min(xy(layer->box(i)), bb_min),
|
||||
glm::max(zw(layer->box(i)), bb_max),
|
||||
};
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
layer->rtt(i).bindFramebuffer();
|
||||
|
||||
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
apply_canvas_mode_viewport(0, 0, layer->rtt(i).getWidth(), layer->rtt(i).getHeight());
|
||||
|
||||
// save fb content for history
|
||||
layer->rtt(i).readPixelsRgba8(
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y),
|
||||
action->m_image[i].get());
|
||||
// copy fb content to texture for blending
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
Canvas::I->m_tex2[i].bind();
|
||||
copy_framebuffer_to_texture_2d(
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y));
|
||||
// slot for m_tex
|
||||
set_canvas_mode_active_texture_unit(1);
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = Canvas::I->m_size,
|
||||
.mvp = mvp,
|
||||
.texture_slot = 0,
|
||||
.stroke_texture_slot = 1,
|
||||
.layer_alpha = 1.0f,
|
||||
.alpha_lock = false,
|
||||
.mask_enabled = false,
|
||||
.use_fragcoord = true,
|
||||
.blend_mode = 0,
|
||||
.use_dual = false,
|
||||
.use_pattern = false,
|
||||
});
|
||||
Canvas::I->m_sampler_linear.bind(1);
|
||||
Canvas::I->m_sampler_linear.bind(0);
|
||||
m_tex[j].bind();
|
||||
m_shape[j].draw_fill();
|
||||
m_tex[j].unbind();
|
||||
}
|
||||
layer->rtt(i).unbindFramebuffer();
|
||||
});
|
||||
}
|
||||
|
||||
action->m_layer_idx = Canvas::I->m_current_layer_idx;
|
||||
action->m_canvas = Canvas::I;
|
||||
action->m_frame_idx = Canvas::I->layer().m_frame_index;
|
||||
//action->m_stroke = std::move(m_current_stroke);
|
||||
ActionManager::add(action);
|
||||
layer->optimize();
|
||||
//auto m = static_cast<CanvasModeMaskFree*>(Canvas::I->modes[(int)kCanvasMode::MaskFree][0]);
|
||||
//m->clear();
|
||||
}
|
||||
|
||||
void CanvasModeTransform::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);
|
||||
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), true);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 0, 1, 1, .1 },
|
||||
.mvp = proj * camera * m_xform * m_xform_local,
|
||||
});
|
||||
m_shape[i].draw_fill();
|
||||
|
||||
pp::panopainter::setup_legacy_canvas_draw_merge_texture_shader({
|
||||
.mvp = proj * camera * m_xform * m_xform_local,
|
||||
.texture_slot = 0,
|
||||
});
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
m_tex[i].bind();
|
||||
Canvas::I->m_sampler_linear.bind(0);
|
||||
m_shape[i].draw_fill();
|
||||
m_tex[i].unbind();
|
||||
}
|
||||
|
||||
auto m2d = Canvas::I->m_proj * Canvas::I->m_mv * m_xform * m_xform_local;
|
||||
for (int i = 0; i < corners.size(); i++)
|
||||
{
|
||||
auto c = m2d * glm::vec4(corners[i], 1);
|
||||
if (c.w < 0)
|
||||
continue;
|
||||
auto c3d = c / c.w;
|
||||
auto c2d = (xy(c3d) * 0.5f + 0.5f) * zw(Canvas::I->m_box);
|
||||
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 1, 1, 1, i == corner_hl ? 1.f : .1f },
|
||||
.mvp = ortho * glm::translate(glm::vec3(c2d, 0)) * glm::scale(glm::vec3(20.f) * App::I->zoom),
|
||||
});
|
||||
m_circle.draw_fill();
|
||||
|
||||
// draw black border
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 0, 0, 0, 1 },
|
||||
.mvp = ortho * glm::translate(glm::vec3(c2d, 0)) * glm::scale(glm::vec3(20.f) * App::I->zoom),
|
||||
});
|
||||
m_circle.draw_stroke();
|
||||
}
|
||||
|
||||
if (depth) apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), true);
|
||||
}
|
||||
|
||||
void CanvasModeTransform::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
{
|
||||
auto m2d = glm::scale(glm::vec3(1, -1, 1)) * Canvas::I->m_proj *
|
||||
Canvas::I->m_mv * m_xform * m_xform_local;
|
||||
|
||||
switch (me->m_type)
|
||||
{
|
||||
case kEventType::MouseDownR:
|
||||
{
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseUpL:
|
||||
m_dragging = false;
|
||||
corner_hl = -1;
|
||||
break;
|
||||
case kEventType::MouseDownL:
|
||||
corner_hl = -1;
|
||||
corners2d.resize(corners.size());
|
||||
for (int i = 0; i < corners.size(); i++)
|
||||
{
|
||||
auto c = m2d * glm::vec4(corners[i], 1);
|
||||
corners2d[i] = ((xy(c) / c.z) * 0.5f + 0.5f) * zw(Canvas::I->m_box);
|
||||
float d = glm::distance(corners2d[i], loc);
|
||||
if (d < 20.f * App::I->zoom)
|
||||
corner_hl = i;
|
||||
}
|
||||
if (corner_hl != -1)
|
||||
{
|
||||
m_dragging = true;
|
||||
m_drag_start = loc;
|
||||
m_drag_xform = m_xform;
|
||||
m_drag_xform_local = m_xform_local;
|
||||
m_drag_corner = corner_hl;
|
||||
m_drag_corners2d = corners2d;
|
||||
if (m_drag_corner < 4)
|
||||
{
|
||||
m_drag_diag = glm::distance(corners2d[4], corners2d[m_drag_corner]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
{
|
||||
corner_hl = -1;
|
||||
corners2d.resize(corners.size());
|
||||
for (int i = 0; i < corners.size(); i++)
|
||||
{
|
||||
auto c = m2d * glm::vec4(corners[i], 1);
|
||||
corners2d[i] = ((xy(c) / c.z) * 0.5f + 0.5f) * zw(Canvas::I->m_box);
|
||||
float d = glm::distance(corners2d[i], loc);
|
||||
if (d < 20.f * App::I->zoom)
|
||||
corner_hl = i;
|
||||
}
|
||||
if (m_dragging)
|
||||
{
|
||||
auto cam_up = glm::inverse(Canvas::I->m_mv) * glm::vec4(0, 1, 0, 1);
|
||||
//auto diff = glm::radians(loc - m_drag_start) * 0.1f;
|
||||
//auto m = glm::eulerAngleXY(-diff.y, -diff.x);
|
||||
//m_xform = m * m_drag_xform;
|
||||
if (m_drag_corner > -1 && m_drag_corner < 4)
|
||||
{
|
||||
auto diag = glm::distance(corners2d[4], loc);
|
||||
auto scale = diag / m_drag_diag;
|
||||
m_xform_local = m_drag_xform_local * glm::scale(glm::vec3(scale, scale, 1));
|
||||
}
|
||||
if (m_drag_corner == 4)
|
||||
{
|
||||
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(loc), xyz(cam_up)));
|
||||
}
|
||||
if (m_drag_corner == 5)
|
||||
{
|
||||
auto a = glm::normalize(m_drag_corners2d[m_drag_corner] - m_drag_corners2d[4]);
|
||||
auto b = glm::normalize(loc - m_drag_corners2d[4]);
|
||||
auto angle = glm::orientedAngle(a, b);
|
||||
m_xform_local = m_drag_xform_local * glm::eulerAngleZ(-angle);
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
auto p2d = loc;
|
||||
//p2d.y = Canvas::I->m_box.w - p2d.y - 1;
|
||||
auto p2d_clip = ((p2d / zw(Canvas::I->m_box)) * 2.f - 1.f) * glm::vec2(1, -1);
|
||||
auto p3d_plane = Canvas::I->m_plane_unproject[0] * glm::vec4(p2d_clip, 0, 1);
|
||||
auto p2d_plane = -p3d_plane / p3d_plane.z;
|
||||
// auto p3d_world = Canvas::I->m_plane_transform[0] * glm::vec4(p2d_plane, -1, 1);
|
||||
int x = 0;
|
||||
LOG("pt %f %f %f %f", p2d_plane.x, p2d_plane.y, p2d_plane.z, p2d_plane.w);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
|
||||
567
src/legacy_canvas_mode_transform.cpp
Normal file
567
src/legacy_canvas_mode_transform.cpp
Normal file
@@ -0,0 +1,567 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "canvas_modes.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "canvas.h"
|
||||
#include "legacy_canvas_mode_helpers.h"
|
||||
#include "legacy_canvas_draw_merge_services.h"
|
||||
#include "legacy_canvas_stroke_composite_services.h"
|
||||
#include "legacy_ui_overlay_services.h"
|
||||
#include "renderer_gl/opengl_capabilities.h"
|
||||
|
||||
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::set_canvas_mode_active_texture_unit;
|
||||
|
||||
void CanvasModeTransform::init()
|
||||
{
|
||||
m_sphere.create(1.f, glm::radians(-10.f), glm::radians(10.f), glm::radians(-10.f), glm::radians(10.f), 1.f);
|
||||
m_circle.create<16>(1.f);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_shape[i].create();
|
||||
m_points_face[i].clear();
|
||||
}
|
||||
m_xform = glm::mat4(1);
|
||||
m_xform_local = glm::mat4(1);
|
||||
}
|
||||
|
||||
void CanvasModeTransform::enter(kCanvasMode prev)
|
||||
{
|
||||
m_commit_on_leave = false;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_shape[i].clear();
|
||||
m_points_face[i].clear();
|
||||
}
|
||||
|
||||
if (m_action == ActionType::Import)
|
||||
{
|
||||
float aspect = 1.f;
|
||||
if (m_source_image.data())
|
||||
{
|
||||
m_tex[0].create(m_source_image);
|
||||
aspect = (float)m_source_image.width / (float)m_source_image.height;
|
||||
}
|
||||
|
||||
auto center = zw(Canvas::I->m_box) * 0.5f;
|
||||
glm::vec2 bb_sz = glm::vec2(aspect, 1.f) * 100.f * App::I->zoom;
|
||||
glm::vec2 bb_min = center - bb_sz * 0.5f;
|
||||
glm::vec2 bb_max = center + bb_sz * 0.5f;
|
||||
glm::vec2 midpoint = (bb_min + bb_max) * 0.5f;
|
||||
|
||||
auto cam_up = glm::inverse(Canvas::I->m_mv) * glm::vec4(0, 1, 0, 1);
|
||||
auto center_mat = glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up));
|
||||
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up)));
|
||||
m_xform_local = glm::mat4(1);
|
||||
|
||||
corners.clear();
|
||||
corners.emplace_back(bb_min, 0); // A
|
||||
corners.emplace_back(bb_max, 0); // C
|
||||
corners.emplace_back(bb_max.x, bb_min.y, 0); // B
|
||||
corners.emplace_back(bb_min.x, bb_max.y, 0); // D
|
||||
corners.emplace_back(midpoint, 0);
|
||||
corners.emplace_back(midpoint + (bb_max - bb_min) * glm::vec2(0.75f, 0), 0);
|
||||
|
||||
for (auto& c : corners)
|
||||
c = center_mat * glm::vec4(Canvas::I->point_trace(c), 1);
|
||||
|
||||
m_points_face[0] = std::vector<vertex_t>({
|
||||
vertex_t(corners[0], { 0, 0 }),
|
||||
vertex_t(corners[2], { 1, 0 }),
|
||||
vertex_t(corners[1], { 1, 1 }),
|
||||
vertex_t(corners[3], { 0, 1 }),
|
||||
});
|
||||
auto shape3d = triangulate(m_points_face[0]);
|
||||
m_shape[0].update_vertices(shape3d.data(), (int)shape3d.size());
|
||||
|
||||
m_commit_on_leave = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// avoid recursive loop, store the last different mode not using Transform
|
||||
static kCanvasMode last_prev = kCanvasMode::Draw;
|
||||
if (prev != kCanvasMode::Copy && prev != kCanvasMode::Cut && prev != kCanvasMode::Import)
|
||||
last_prev = prev;
|
||||
|
||||
if (prev != kCanvasMode::MaskFree && prev != kCanvasMode::MaskLine)
|
||||
{
|
||||
Canvas::set_mode(last_prev);
|
||||
return;
|
||||
}
|
||||
|
||||
auto m = static_cast<CanvasModeMaskBase*>(Canvas::I->modes[(int)prev][0]);
|
||||
|
||||
if (m->m_points2d.size() < 3)
|
||||
{
|
||||
Canvas::set_mode(last_prev);
|
||||
return;
|
||||
}
|
||||
|
||||
Canvas::I->m_smask_active = false;
|
||||
auto points = m->m_points2d;
|
||||
|
||||
Canvas::I->push_camera();
|
||||
Canvas::I->set_camera(m->m_selection_cam);
|
||||
|
||||
glm::vec2 bb_min(FLT_MAX);
|
||||
glm::vec2 bb_max(-FLT_MAX);
|
||||
for (auto p2d : points)
|
||||
{
|
||||
bb_min = glm::min(bb_min, p2d);
|
||||
bb_max = glm::max(bb_max, p2d);
|
||||
}
|
||||
glm::vec2 midpoint = (bb_min + bb_max) * 0.5f;
|
||||
auto cam_up = glm::inverse(Canvas::I->m_mv) * glm::vec4(0, 1, 0, 1);
|
||||
auto center_mat = glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up));
|
||||
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(midpoint), xyz(cam_up)));
|
||||
m_xform_local = glm::mat4(1);
|
||||
corners.clear();
|
||||
corners.emplace_back(bb_min, 0);
|
||||
corners.emplace_back(bb_max, 0);
|
||||
corners.emplace_back(bb_max.x, bb_min.y, 0);
|
||||
corners.emplace_back(bb_min.x, bb_max.y, 0);
|
||||
corners.emplace_back(midpoint, 0);
|
||||
corners.emplace_back(midpoint + (bb_max-bb_min) * glm::vec2(0.75f, 0), 0);
|
||||
for (auto& c : corners)
|
||||
c = center_mat * glm::vec4(Canvas::I->point_trace(c), 1);
|
||||
|
||||
for (int plane = 0; plane < 6; plane++)
|
||||
{
|
||||
auto face = Canvas::I->face_to_shape2D(plane);
|
||||
auto shape2d = poly_intersect(points, face);
|
||||
if (shape2d.size() < 3 || face.empty())
|
||||
{
|
||||
m_shape[plane].clear();
|
||||
m_points_face[plane].clear();
|
||||
continue;
|
||||
}
|
||||
m_points_face[plane].reserve(shape2d.size());
|
||||
glm::vec2 bb_min(Canvas::I->m_size);
|
||||
glm::vec2 bb_max(0, 0);
|
||||
for (auto p2d : shape2d)
|
||||
{
|
||||
p2d.y = Canvas::I->m_box.w - p2d.y - 1;
|
||||
auto p2d_clip = ((p2d / zw(Canvas::I->m_box)) * 2.f - 1.f);
|
||||
auto p3d_plane = Canvas::I->m_plane_unproject[plane] * glm::vec4(p2d_clip, 0, 1);
|
||||
if (p3d_plane.w < 0)
|
||||
continue;
|
||||
auto p3d_norm = -p3d_plane / p3d_plane.z;
|
||||
auto p2d_plane = xy(p3d_norm);
|
||||
auto p2d_plane_raster = (p2d_plane * 0.5f + 0.5f) * Canvas::I->m_size;
|
||||
auto p3d_world = Canvas::I->m_plane_transform[plane] * glm::vec4(p2d_plane, -1, 1);
|
||||
bb_min = glm::min(bb_min, p2d_plane_raster);
|
||||
bb_max = glm::max(bb_max, p2d_plane_raster);
|
||||
|
||||
//glm::vec3 pt_o, pt_d;
|
||||
//Canvas::I->point_unproject(p2d, pt_o, pt_d);
|
||||
|
||||
vertex_t v;
|
||||
v.pos = glm::vec4(xyz(p3d_world), 1);
|
||||
v.uvs = p2d_plane_raster;
|
||||
m_points_face[plane].push_back(v);
|
||||
}
|
||||
|
||||
if (m_points_face[plane].size() < 3)
|
||||
{
|
||||
m_shape[plane].clear();
|
||||
m_points_face[plane].clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto bb_sz = bb_max - bb_min;
|
||||
for (auto& v : m_points_face[plane])
|
||||
{
|
||||
v.uvs2 = v.uvs / Canvas::I->m_size;
|
||||
v.uvs = (v.uvs - bb_min) / bb_sz;
|
||||
v.pos = center_mat * v.pos;
|
||||
}
|
||||
|
||||
auto shape3d = triangulate(m_points_face[plane]);
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
m_shape[plane].update_vertices(shape3d.data(), (int)shape3d.size());
|
||||
Canvas::I->m_layers[Canvas::I->m_current_layer_idx]->rtt(plane).bindFramebuffer();
|
||||
m_tex[plane].create(bb_sz.x, bb_sz.y);
|
||||
m_tex[plane].bind();
|
||||
copy_framebuffer_to_texture_2d(
|
||||
0,
|
||||
0,
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y));
|
||||
m_tex[plane].unbind();
|
||||
Canvas::I->m_layers[Canvas::I->m_current_layer_idx]->rtt(plane).unbindFramebuffer();
|
||||
});
|
||||
|
||||
m_commit_on_leave = true;
|
||||
}
|
||||
|
||||
if (m_action == ActionType::Cut)
|
||||
{
|
||||
auto& layer = Canvas::I->m_layers[Canvas::I->m_current_layer_idx];
|
||||
|
||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||
|
||||
auto action = new ActionStroke;
|
||||
action->was_saved = !Canvas::I->m_unsaved;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane_camera = glm::lookAt(glm::vec3(0), Canvas::I->m_plane_origin[i], Canvas::I->m_plane_tangent[i]);
|
||||
auto mvp = proj * plane_camera * m_xform * m_xform_local;
|
||||
|
||||
glm::vec2 bb_min(Canvas::I->m_size);
|
||||
glm::vec2 bb_max(0, 0);
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
for (auto p : m_points_face[j])
|
||||
{
|
||||
auto p_clip = mvp * p.pos;
|
||||
auto p_norm = p_clip / p_clip.w;
|
||||
if (p_clip.w < 0 || glm::any(glm::greaterThan(glm::abs(xy(p_norm)), { 1, 1 })))
|
||||
continue;
|
||||
auto p_raster = (xy(p_norm) * 0.5f + 0.5f) * Canvas::I->m_size;
|
||||
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p_raster));
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::max(bb_max, p_raster));
|
||||
}
|
||||
}
|
||||
glm::vec2 pad(2);
|
||||
bb_min = glm::max({ 0, 0 }, glm::floor(bb_min) - pad);
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::ceil(bb_max) + pad);
|
||||
auto bb_sz = bb_max - bb_min;
|
||||
|
||||
if (bb_sz.x <= 0.f || bb_sz.y <= 0.f)
|
||||
continue;
|
||||
|
||||
action->m_image[i] = std::make_unique<uint8_t[]>(bb_sz.x * bb_sz.y * 4);
|
||||
action->m_box[i] = { bb_min, bb_max };
|
||||
action->m_old_box[i] = layer->box(i);
|
||||
action->m_old_dirty[i] = layer->face(i);
|
||||
|
||||
layer->face(i) = true;
|
||||
layer->box(i) = {
|
||||
glm::min(xy(layer->box(i)), bb_min),
|
||||
glm::max(zw(layer->box(i)), bb_max),
|
||||
};
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
apply_canvas_mode_viewport(0, 0, layer->w, layer->h);
|
||||
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 0, 0, 0, 0 },
|
||||
.mvp = mvp,
|
||||
});
|
||||
layer->rtt(i).bindFramebuffer();
|
||||
// copy framebuffer to action data
|
||||
layer->rtt(i).readPixelsRgba8(
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y),
|
||||
action->m_image[i].get());
|
||||
for (int j = 0; j < 6; j++)
|
||||
m_shape[j].draw_fill();
|
||||
layer->rtt(i).unbindFramebuffer();
|
||||
});
|
||||
}
|
||||
|
||||
action->m_layer_idx = Canvas::I->m_current_layer_idx;
|
||||
action->m_frame_idx = Canvas::I->layer().m_frame_index;
|
||||
action->m_canvas = Canvas::I;
|
||||
//action->m_stroke = std::move(m_current_stroke);
|
||||
ActionManager::add(action);
|
||||
|
||||
m_source_image.destroy();
|
||||
}
|
||||
|
||||
Canvas::I->pop_camera();
|
||||
}
|
||||
|
||||
void CanvasModeTransform::leave(kCanvasMode next)
|
||||
{
|
||||
if (!m_commit_on_leave)
|
||||
return;
|
||||
|
||||
auto& layer = Canvas::I->m_layers[Canvas::I->m_current_layer_idx];
|
||||
|
||||
glm::mat4 proj = glm::perspective(glm::radians(90.f), 1.f, .01f, 1000.f);
|
||||
|
||||
auto action = new ActionStroke;
|
||||
action->was_saved = !Canvas::I->m_unsaved;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane_camera = glm::lookAt(glm::vec3(0), Canvas::I->m_plane_origin[i], Canvas::I->m_plane_tangent[i]);
|
||||
auto mv = plane_camera * m_xform * m_xform_local;
|
||||
auto mvp = proj * mv;
|
||||
|
||||
|
||||
std::vector<glm::vec2> poly2d;
|
||||
static std::vector<glm::vec2> face_corners{ {1,1}, {-1,1}, {-1,-1}, {1,-1} };
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
std::vector<glm::vec3> poly_cam;
|
||||
poly_cam.reserve(m_points_face[j].size());
|
||||
for (auto p : m_points_face[j])
|
||||
poly_cam.push_back(mv * p.pos);
|
||||
|
||||
auto poly_clipped = poly_clip_near(poly_cam, 0.01f);
|
||||
|
||||
for (auto p : poly_clipped)
|
||||
{
|
||||
auto p_clip = proj * glm::vec4(p, 1);
|
||||
if (p_clip.w < 0)
|
||||
continue;
|
||||
auto p_norm = p_clip / p_clip.w;
|
||||
poly2d.push_back(p_norm);
|
||||
}
|
||||
}
|
||||
|
||||
auto clipped = poly_intersect(poly2d, face_corners);
|
||||
|
||||
glm::vec2 bb_min(Canvas::I->m_size);
|
||||
glm::vec2 bb_max(0, 0);
|
||||
for (auto p_norm : clipped)
|
||||
{
|
||||
auto p_raster = (p_norm * 0.5f + 0.5f) * Canvas::I->m_size;
|
||||
bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p_raster));
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::max(bb_max, p_raster));
|
||||
}
|
||||
glm::vec2 pad(2);
|
||||
bb_min = glm::max({ 0, 0 }, glm::floor(bb_min) - pad);
|
||||
bb_max = glm::min(Canvas::I->m_size, glm::ceil(bb_max) + pad);
|
||||
auto bb_sz = bb_max - bb_min;
|
||||
|
||||
if (clipped.empty() || bb_sz.x <= 0.f || bb_sz.y <= 0.f)
|
||||
continue;
|
||||
|
||||
action->m_image[i] = std::make_unique<uint8_t[]>(bb_sz.x * bb_sz.y * 4);
|
||||
action->m_box[i] = { bb_min, bb_max };
|
||||
action->m_old_box[i] = layer->box(i);
|
||||
action->m_old_dirty[i] = layer->face(i);
|
||||
|
||||
layer->face(i) = true;
|
||||
layer->box(i) = {
|
||||
glm::min(xy(layer->box(i)), bb_min),
|
||||
glm::max(zw(layer->box(i)), bb_max),
|
||||
};
|
||||
|
||||
App::I->render_task([&]
|
||||
{
|
||||
layer->rtt(i).bindFramebuffer();
|
||||
|
||||
apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false);
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), false);
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
apply_canvas_mode_viewport(0, 0, layer->rtt(i).getWidth(), layer->rtt(i).getHeight());
|
||||
|
||||
// save fb content for history
|
||||
layer->rtt(i).readPixelsRgba8(
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y),
|
||||
action->m_image[i].get());
|
||||
// copy fb content to texture for blending
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
Canvas::I->m_tex2[i].bind();
|
||||
copy_framebuffer_to_texture_2d(
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_min.x),
|
||||
static_cast<int>(bb_min.y),
|
||||
static_cast<int>(bb_sz.x),
|
||||
static_cast<int>(bb_sz.y));
|
||||
// slot for m_tex
|
||||
set_canvas_mode_active_texture_unit(1);
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
pp::panopainter::setup_legacy_stroke_composite_shader(
|
||||
pp::panopainter::LegacyStrokeCompositeUniforms {
|
||||
.resolution = Canvas::I->m_size,
|
||||
.mvp = mvp,
|
||||
.texture_slot = 0,
|
||||
.stroke_texture_slot = 1,
|
||||
.layer_alpha = 1.0f,
|
||||
.alpha_lock = false,
|
||||
.mask_enabled = false,
|
||||
.use_fragcoord = true,
|
||||
.blend_mode = 0,
|
||||
.use_dual = false,
|
||||
.use_pattern = false,
|
||||
});
|
||||
Canvas::I->m_sampler_linear.bind(1);
|
||||
Canvas::I->m_sampler_linear.bind(0);
|
||||
m_tex[j].bind();
|
||||
m_shape[j].draw_fill();
|
||||
m_tex[j].unbind();
|
||||
}
|
||||
layer->rtt(i).unbindFramebuffer();
|
||||
});
|
||||
}
|
||||
|
||||
action->m_layer_idx = Canvas::I->m_current_layer_idx;
|
||||
action->m_canvas = Canvas::I;
|
||||
action->m_frame_idx = Canvas::I->layer().m_frame_index;
|
||||
//action->m_stroke = std::move(m_current_stroke);
|
||||
ActionManager::add(action);
|
||||
layer->optimize();
|
||||
//auto m = static_cast<CanvasModeMaskFree*>(Canvas::I->modes[(int)kCanvasMode::MaskFree][0]);
|
||||
//m->clear();
|
||||
}
|
||||
|
||||
void CanvasModeTransform::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);
|
||||
|
||||
apply_canvas_mode_capability(pp::renderer::gl::blend_state(), true);
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 0, 1, 1, .1 },
|
||||
.mvp = proj * camera * m_xform * m_xform_local,
|
||||
});
|
||||
m_shape[i].draw_fill();
|
||||
|
||||
pp::panopainter::setup_legacy_canvas_draw_merge_texture_shader({
|
||||
.mvp = proj * camera * m_xform * m_xform_local,
|
||||
.texture_slot = 0,
|
||||
});
|
||||
set_canvas_mode_active_texture_unit(0);
|
||||
m_tex[i].bind();
|
||||
Canvas::I->m_sampler_linear.bind(0);
|
||||
m_shape[i].draw_fill();
|
||||
m_tex[i].unbind();
|
||||
}
|
||||
|
||||
auto m2d = Canvas::I->m_proj * Canvas::I->m_mv * m_xform * m_xform_local;
|
||||
for (int i = 0; i < corners.size(); i++)
|
||||
{
|
||||
auto c = m2d * glm::vec4(corners[i], 1);
|
||||
if (c.w < 0)
|
||||
continue;
|
||||
auto c3d = c / c.w;
|
||||
auto c2d = (xy(c3d) * 0.5f + 0.5f) * zw(Canvas::I->m_box);
|
||||
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 1, 1, 1, i == corner_hl ? 1.f : .1f },
|
||||
.mvp = ortho * glm::translate(glm::vec3(c2d, 0)) * glm::scale(glm::vec3(20.f) * App::I->zoom),
|
||||
});
|
||||
m_circle.draw_fill();
|
||||
|
||||
// draw black border
|
||||
pp::panopainter::setup_legacy_vr_color_shader({
|
||||
.color = { 0, 0, 0, 1 },
|
||||
.mvp = ortho * glm::translate(glm::vec3(c2d, 0)) * glm::scale(glm::vec3(20.f) * App::I->zoom),
|
||||
});
|
||||
m_circle.draw_stroke();
|
||||
}
|
||||
|
||||
if (depth) apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), true);
|
||||
}
|
||||
|
||||
void CanvasModeTransform::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
||||
{
|
||||
auto m2d = glm::scale(glm::vec3(1, -1, 1)) * Canvas::I->m_proj *
|
||||
Canvas::I->m_mv * m_xform * m_xform_local;
|
||||
|
||||
switch (me->m_type)
|
||||
{
|
||||
case kEventType::MouseDownR:
|
||||
{
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseUpL:
|
||||
m_dragging = false;
|
||||
corner_hl = -1;
|
||||
break;
|
||||
case kEventType::MouseDownL:
|
||||
corner_hl = -1;
|
||||
corners2d.resize(corners.size());
|
||||
for (int i = 0; i < corners.size(); i++)
|
||||
{
|
||||
auto c = m2d * glm::vec4(corners[i], 1);
|
||||
corners2d[i] = ((xy(c) / c.z) * 0.5f + 0.5f) * zw(Canvas::I->m_box);
|
||||
float d = glm::distance(corners2d[i], loc);
|
||||
if (d < 20.f * App::I->zoom)
|
||||
corner_hl = i;
|
||||
}
|
||||
if (corner_hl != -1)
|
||||
{
|
||||
m_dragging = true;
|
||||
m_drag_start = loc;
|
||||
m_drag_xform = m_xform;
|
||||
m_drag_xform_local = m_xform_local;
|
||||
m_drag_corner = corner_hl;
|
||||
m_drag_corners2d = corners2d;
|
||||
if (m_drag_corner < 4)
|
||||
{
|
||||
m_drag_diag = glm::distance(corners2d[4], corners2d[m_drag_corner]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
{
|
||||
corner_hl = -1;
|
||||
corners2d.resize(corners.size());
|
||||
for (int i = 0; i < corners.size(); i++)
|
||||
{
|
||||
auto c = m2d * glm::vec4(corners[i], 1);
|
||||
corners2d[i] = ((xy(c) / c.z) * 0.5f + 0.5f) * zw(Canvas::I->m_box);
|
||||
float d = glm::distance(corners2d[i], loc);
|
||||
if (d < 20.f * App::I->zoom)
|
||||
corner_hl = i;
|
||||
}
|
||||
if (m_dragging)
|
||||
{
|
||||
auto cam_up = glm::inverse(Canvas::I->m_mv) * glm::vec4(0, 1, 0, 1);
|
||||
//auto diff = glm::radians(loc - m_drag_start) * 0.1f;
|
||||
//auto m = glm::eulerAngleXY(-diff.y, -diff.x);
|
||||
//m_xform = m * m_drag_xform;
|
||||
if (m_drag_corner > -1 && m_drag_corner < 4)
|
||||
{
|
||||
auto diag = glm::distance(corners2d[4], loc);
|
||||
auto scale = diag / m_drag_diag;
|
||||
m_xform_local = m_drag_xform_local * glm::scale(glm::vec3(scale, scale, 1));
|
||||
}
|
||||
if (m_drag_corner == 4)
|
||||
{
|
||||
m_xform = glm::inverse(glm::lookAt({ 0, 0, 0 }, Canvas::I->point_trace(loc), xyz(cam_up)));
|
||||
}
|
||||
if (m_drag_corner == 5)
|
||||
{
|
||||
auto a = glm::normalize(m_drag_corners2d[m_drag_corner] - m_drag_corners2d[4]);
|
||||
auto b = glm::normalize(loc - m_drag_corners2d[4]);
|
||||
auto angle = glm::orientedAngle(a, b);
|
||||
m_xform_local = m_drag_xform_local * glm::eulerAngleZ(-angle);
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
auto p2d = loc;
|
||||
//p2d.y = Canvas::I->m_box.w - p2d.y - 1;
|
||||
auto p2d_clip = ((p2d / zw(Canvas::I->m_box)) * 2.f - 1.f) * glm::vec2(1, -1);
|
||||
auto p3d_plane = Canvas::I->m_plane_unproject[0] * glm::vec4(p2d_clip, 0, 1);
|
||||
auto p2d_plane = -p3d_plane / p3d_plane.z;
|
||||
// auto p3d_world = Canvas::I->m_plane_transform[0] * glm::vec4(p2d_plane, -1, 1);
|
||||
int x = 0;
|
||||
LOG("pt %f %f %f %f", p2d_plane.x, p2d_plane.y, p2d_plane.z, p2d_plane.w);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -400,6 +400,94 @@ struct LegacyNodeStrokePreviewImmediatePassSequenceRequest {
|
||||
return request.execute_final_composite();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool execute_legacy_node_stroke_preview_final_composite(
|
||||
glm::vec2 size,
|
||||
glm::vec2 pattern_scale,
|
||||
const Brush& brush,
|
||||
const pp::paint_renderer::CanvasStrokeCompositePassPlan& composite_pass,
|
||||
Texture2D& background_texture,
|
||||
Texture2D& stroke_texture,
|
||||
Texture2D& dual_texture,
|
||||
Texture2D& preview_texture,
|
||||
Sampler& linear_sampler,
|
||||
Sampler& repeat_sampler,
|
||||
std::function<void()> bind_pattern_texture,
|
||||
std::function<void()> draw_composite);
|
||||
|
||||
template <
|
||||
typename Frame,
|
||||
typename ExecuteDualPass,
|
||||
typename CaptureBackground,
|
||||
typename ComputeFrames,
|
||||
typename BeforeFrame,
|
||||
typename SetupSampleShader,
|
||||
typename DrawSample,
|
||||
typename FinishMainPass,
|
||||
typename BindPatternTexture,
|
||||
typename DrawComposite>
|
||||
[[nodiscard]] inline bool execute_legacy_node_stroke_preview_draw_immediate_shell(
|
||||
const Brush& brush,
|
||||
const LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
|
||||
Texture2D& stroke_texture,
|
||||
RTT& mixer_rtt,
|
||||
RTT& render_target,
|
||||
Texture2D& background_texture,
|
||||
Texture2D& dual_texture,
|
||||
Texture2D& preview_texture,
|
||||
Sampler& linear_sampler,
|
||||
Sampler& repeat_sampler,
|
||||
bool copy_stroke_destination,
|
||||
glm::vec2 size,
|
||||
std::uint32_t stroke_texture_slot,
|
||||
ExecuteDualPass&& execute_dual_pass,
|
||||
CaptureBackground&& capture_background,
|
||||
ComputeFrames&& compute_frames,
|
||||
BeforeFrame&& before_frame,
|
||||
SetupSampleShader&& setup_sample_shader,
|
||||
DrawSample&& draw_sample,
|
||||
FinishMainPass&& finish_main_pass,
|
||||
BindPatternTexture&& bind_pattern_texture,
|
||||
DrawComposite&& draw_composite)
|
||||
{
|
||||
return execute_legacy_node_stroke_preview_immediate_pass_sequence(
|
||||
LegacyNodeStrokePreviewImmediatePassSequenceRequest {
|
||||
.execute_dual_pass = std::forward<ExecuteDualPass>(execute_dual_pass),
|
||||
.capture_background = std::forward<CaptureBackground>(capture_background),
|
||||
.execute_main_live_pass = [&]() -> bool {
|
||||
return execute_legacy_node_stroke_preview_main_live_pass(
|
||||
make_legacy_node_stroke_preview_main_live_pass_request<Frame>(
|
||||
brush,
|
||||
pass_orchestration,
|
||||
stroke_texture,
|
||||
mixer_rtt,
|
||||
render_target,
|
||||
copy_stroke_destination,
|
||||
size,
|
||||
stroke_texture_slot,
|
||||
std::forward<ComputeFrames>(compute_frames),
|
||||
std::forward<BeforeFrame>(before_frame),
|
||||
std::forward<SetupSampleShader>(setup_sample_shader),
|
||||
std::forward<DrawSample>(draw_sample),
|
||||
std::forward<FinishMainPass>(finish_main_pass)));
|
||||
},
|
||||
.execute_final_composite = [&]() -> bool {
|
||||
return execute_legacy_node_stroke_preview_final_composite(
|
||||
size,
|
||||
glm::vec2(brush.m_pattern_scale),
|
||||
brush,
|
||||
pass_orchestration.material.composite_pass,
|
||||
background_texture,
|
||||
stroke_texture,
|
||||
dual_texture,
|
||||
preview_texture,
|
||||
linear_sampler,
|
||||
repeat_sampler,
|
||||
std::forward<BindPatternTexture>(bind_pattern_texture),
|
||||
std::forward<DrawComposite>(draw_composite));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool execute_legacy_node_stroke_preview_final_composite(
|
||||
glm::vec2 size,
|
||||
glm::vec2 pattern_scale,
|
||||
|
||||
309
src/legacy_ui_node_event.cpp
Normal file
309
src/legacy_ui_node_event.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "pch.h"
|
||||
#include "legacy_ui_node_event.h"
|
||||
|
||||
#include "node.h"
|
||||
#include "layout.h"
|
||||
|
||||
namespace pp::panopainter {
|
||||
namespace {
|
||||
|
||||
void transfer_mouse_focus(Node& node, Event* e)
|
||||
{
|
||||
if (e->m_cat != kEventCategory::MouseEvent)
|
||||
return;
|
||||
|
||||
if (node.child_mouse_focus == node.current_mouse_capture)
|
||||
return;
|
||||
|
||||
if (!node.is_child(node.current_mouse_capture.get()))
|
||||
return;
|
||||
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
if (node.child_mouse_focus)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseUnfocus;
|
||||
node.child_mouse_focus->handle_event(&e2);
|
||||
node.child_mouse_focus->m_mouse_focus = false;
|
||||
}
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseFocus;
|
||||
node.current_mouse_capture->handle_event(&e2);
|
||||
node.child_mouse_focus = node.current_mouse_capture;
|
||||
node.child_mouse_focus->m_mouse_focus = true;
|
||||
}
|
||||
|
||||
bool should_skip_children(Node& node, Event* e)
|
||||
{
|
||||
bool skip_children = false;
|
||||
|
||||
if (e->m_cat == kEventCategory::MouseEvent)
|
||||
{
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
skip_children |= !node.m_mouse_inside && !point_in_rect(me->m_pos, node.m_clip);
|
||||
}
|
||||
|
||||
skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) &&
|
||||
(node.m_mouse_captured) && (node.root()->current_mouse_capture.get() == &node) && node.m_capture_children; // <-- THIS IS WRONG "!m_capture_children" is correct, but it breaks everything if changed
|
||||
|
||||
return skip_children;
|
||||
}
|
||||
|
||||
void handle_mouse_focus_transition(Node& node, Event* e, const std::shared_ptr<Node>& child)
|
||||
{
|
||||
if (e->m_cat != kEventCategory::MouseEvent || node.child_mouse_focus.get() == child.get())
|
||||
return;
|
||||
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
if (node.child_mouse_focus && !node.child_mouse_focus->m_destroyed)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseUnfocus;
|
||||
node.child_mouse_focus->handle_event(&e2);
|
||||
node.child_mouse_focus->m_mouse_focus = false;
|
||||
}
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseFocus;
|
||||
child->handle_event(&e2);
|
||||
if (!child->m_destroyed)
|
||||
{
|
||||
node.child_mouse_focus = child;
|
||||
node.child_mouse_focus->m_mouse_focus = true;
|
||||
}
|
||||
}
|
||||
|
||||
void update_mouse_inside(Node& node, MouseEvent* me)
|
||||
{
|
||||
bool old_inside = node.m_mouse_inside;
|
||||
node.m_mouse_inside = point_in_rect(me->m_pos, node.m_clip);
|
||||
if (old_inside == false && node.m_mouse_inside == true)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseEnter;
|
||||
node.handle_event(&e2);
|
||||
}
|
||||
if (old_inside == true && node.m_mouse_inside == false)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseLeave;
|
||||
node.handle_event(&e2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
kEventResult handle_legacy_ui_node_event(Node& node, Event* e)
|
||||
{
|
||||
kEventResult ret = kEventResult::Available;
|
||||
|
||||
if (e->m_cat == kEventCategory::KeyEvent && node.current_key_capture)
|
||||
return node.current_key_capture->on_event(e);
|
||||
|
||||
if (node.current_mouse_capture && node.current_mouse_capture.get() != &node)
|
||||
{
|
||||
transfer_mouse_focus(node, e);
|
||||
return node.current_mouse_capture->on_event(e);
|
||||
}
|
||||
|
||||
// skip mouse events if outside
|
||||
if (!node.m_display || glm::any(glm::lessThanEqual(zw(node.m_clip), { 0, 0 })))
|
||||
return kEventResult::Available;
|
||||
|
||||
if (!should_skip_children(node, e))
|
||||
{
|
||||
// make a copy because any handler can change the children vector
|
||||
auto children_copy = node.m_children;
|
||||
for (auto it = children_copy.rbegin(); it != children_copy.rend(); ++it)
|
||||
{
|
||||
if ((*it)->on_event(e) == kEventResult::Consumed)
|
||||
{
|
||||
if (node.m_flood_events)
|
||||
{
|
||||
ret = kEventResult::Consumed;
|
||||
}
|
||||
else
|
||||
{
|
||||
handle_mouse_focus_transition(node, e, *it);
|
||||
ret = kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == kEventResult::Consumed)
|
||||
{
|
||||
if (e->m_cat == kEventCategory::MouseEvent)
|
||||
update_mouse_inside(node, static_cast<MouseEvent*>(e));
|
||||
return kEventResult::Consumed;
|
||||
}
|
||||
}
|
||||
|
||||
switch (e->m_cat)
|
||||
{
|
||||
case kEventCategory::MouseEvent:
|
||||
{
|
||||
if (node.m_mouse_ignore)
|
||||
break;
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
bool inside = point_in_rect(me->m_pos, node.m_clip);
|
||||
bool inside_old = node.m_mouse_inside;
|
||||
node.m_mouse_inside = inside;
|
||||
switch (e->m_type)
|
||||
{
|
||||
case kEventType::MouseScroll:
|
||||
case kEventType::MouseDownL:
|
||||
case kEventType::MouseDownR:
|
||||
case kEventType::MouseUpL:
|
||||
case kEventType::MouseUpR:
|
||||
if ((inside || node.m_mouse_captured) && ((node.handle_event(e) == kEventResult::Consumed) || node.m_force_mouse_capture))
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (inside_old == false && inside == true)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseEnter;
|
||||
node.handle_event(&e2);
|
||||
}
|
||||
if (inside || node.m_mouse_captured)
|
||||
{
|
||||
ret = node.handle_event(e);
|
||||
if (node.m_force_mouse_capture)
|
||||
ret = kEventResult::Consumed;
|
||||
}
|
||||
if (inside_old == true && inside == false)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseLeave;
|
||||
node.handle_event(&e2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (node.handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kEventCategory::GestureEvent:
|
||||
{
|
||||
if (node.m_mouse_ignore)
|
||||
break;
|
||||
GestureEvent* ge = static_cast<GestureEvent*>(e);
|
||||
bool inside = point_in_rect(ge->m_pos, node.m_clip);
|
||||
node.m_mouse_inside = inside;
|
||||
if ((inside || node.m_mouse_captured) && node.handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (node.handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void legacy_ui_node_mouse_capture(Node& node)
|
||||
{
|
||||
if (!node.m_parent || !node.m_manager)
|
||||
return;
|
||||
|
||||
auto root = node.m_manager->get_ref("main");
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
auto& c = root->current_mouse_capture;
|
||||
auto& s = root->m_capture_stack;
|
||||
|
||||
// already owner of capture
|
||||
if (c.get() == &node || std::find_if(s.begin(), s.end(),
|
||||
[&node](const auto& a) { return a.get() == &node; }) != s.end())
|
||||
return;
|
||||
|
||||
if (c)
|
||||
{
|
||||
if (c->is_child_recursive(&node))
|
||||
{
|
||||
// save on stack
|
||||
s.push_back(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cancel previous owner
|
||||
MouseEvent e;
|
||||
e.m_type = kEventType::MouseCancel;
|
||||
c->handle_event(&e);
|
||||
|
||||
// TODO: only delete nodes on a different tree,
|
||||
// so preserve direct parents of this
|
||||
|
||||
// also clear the whole stack
|
||||
//s.clear();
|
||||
|
||||
s.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
// make current
|
||||
c = node.shared_from_this();
|
||||
node.m_mouse_captured = true;
|
||||
}
|
||||
|
||||
void legacy_ui_node_mouse_release(Node& node)
|
||||
{
|
||||
if (!node.m_parent || !node.m_manager)
|
||||
return;
|
||||
|
||||
auto root = node.m_manager->get_ref("main");
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
auto& c = root->current_mouse_capture;
|
||||
auto& s = root->m_capture_stack;
|
||||
|
||||
s.erase(std::remove_if(s.begin(), s.end(),
|
||||
[&node](const auto& a) { return a.get() == &node; }), s.end());
|
||||
if (c.get() == &node)
|
||||
{
|
||||
if (s.empty())
|
||||
{
|
||||
c = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = s.back();
|
||||
s.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
node.m_mouse_captured = false;
|
||||
}
|
||||
|
||||
void legacy_ui_node_key_capture(Node& node)
|
||||
{
|
||||
if (!node.m_parent || !node.m_manager)
|
||||
return;
|
||||
|
||||
auto root = node.m_manager->get_ref("main");
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
root->current_key_capture = node.shared_from_this();
|
||||
node.m_key_captured = true;
|
||||
}
|
||||
|
||||
void legacy_ui_node_key_release(Node& node)
|
||||
{
|
||||
if (!node.m_parent || !node.m_manager)
|
||||
return;
|
||||
|
||||
auto root = node.m_manager->get_ref("main");
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
if (root->current_key_capture.get() == &node)
|
||||
root->current_key_capture = nullptr;
|
||||
node.m_key_captured = false;
|
||||
}
|
||||
|
||||
} // namespace pp::panopainter
|
||||
15
src/legacy_ui_node_event.h
Normal file
15
src/legacy_ui_node_event.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "event.h"
|
||||
|
||||
class Node;
|
||||
|
||||
namespace pp::panopainter {
|
||||
|
||||
kEventResult handle_legacy_ui_node_event(Node& node, Event* e);
|
||||
void legacy_ui_node_mouse_capture(Node& node);
|
||||
void legacy_ui_node_mouse_release(Node& node);
|
||||
void legacy_ui_node_key_capture(Node& node);
|
||||
void legacy_ui_node_key_release(Node& node);
|
||||
|
||||
} // namespace pp::panopainter
|
||||
263
src/node.cpp
263
src/node.cpp
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "app.h"
|
||||
#include "log.h"
|
||||
#include "legacy_ui_node_event.h"
|
||||
#include "legacy_ui_node_loader.h"
|
||||
#include "node.h"
|
||||
#include "layout.h"
|
||||
@@ -154,180 +155,7 @@ bool Node::added_to_root()
|
||||
|
||||
kEventResult Node::on_event(Event* e)
|
||||
{
|
||||
kEventResult ret = kEventResult::Available;
|
||||
|
||||
if (e->m_cat == kEventCategory::KeyEvent && current_key_capture)
|
||||
return current_key_capture->on_event(e);
|
||||
|
||||
if (current_mouse_capture && current_mouse_capture.get() != this)
|
||||
{
|
||||
if (e->m_cat == kEventCategory::MouseEvent &&
|
||||
child_mouse_focus != current_mouse_capture &&
|
||||
is_child(current_mouse_capture.get()))
|
||||
{
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
if (child_mouse_focus)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseUnfocus;
|
||||
child_mouse_focus->handle_event(&e2);
|
||||
child_mouse_focus->m_mouse_focus = false;
|
||||
}
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseFocus;
|
||||
current_mouse_capture->handle_event(&e2);
|
||||
child_mouse_focus = current_mouse_capture;
|
||||
child_mouse_focus->m_mouse_focus = true;
|
||||
}
|
||||
return current_mouse_capture->on_event(e);
|
||||
}
|
||||
|
||||
bool skip_children = false;
|
||||
|
||||
// skip mouse events if outside
|
||||
if (e->m_cat == kEventCategory::MouseEvent)
|
||||
{
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
skip_children |= !m_mouse_inside && !point_in_rect(me->m_pos, m_clip);
|
||||
}
|
||||
|
||||
skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) &&
|
||||
(m_mouse_captured) && (root()->current_mouse_capture.get() == this) && m_capture_children; // <-- THIS IS WRONG "!m_capture_children" is correct, but it breaks everything if changed
|
||||
|
||||
if (!m_display || glm::any(glm::lessThanEqual(zw(m_clip), { 0, 0 })))
|
||||
return kEventResult::Available;
|
||||
|
||||
if (!skip_children)
|
||||
{
|
||||
// make a copy because any handler can change the children vector
|
||||
auto children_copy = m_children;
|
||||
for (auto it = children_copy.rbegin(); it != children_copy.rend(); ++it)
|
||||
{
|
||||
if ((*it)->on_event(e) == kEventResult::Consumed)
|
||||
{
|
||||
if (m_flood_events)
|
||||
{
|
||||
ret = kEventResult::Consumed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e->m_cat == kEventCategory::MouseEvent && child_mouse_focus.get() != it->get())
|
||||
{
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
if (child_mouse_focus && !child_mouse_focus->m_destroyed)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseUnfocus;
|
||||
child_mouse_focus->handle_event(&e2);
|
||||
child_mouse_focus->m_mouse_focus = false;
|
||||
}
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseFocus;
|
||||
(*it)->handle_event(&e2);
|
||||
if (!(*it)->m_destroyed)
|
||||
{
|
||||
child_mouse_focus = *it;
|
||||
child_mouse_focus->m_mouse_focus = true;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// child_mouse_focus = nullptr;
|
||||
//}
|
||||
}
|
||||
ret = kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret == kEventResult::Consumed)
|
||||
{
|
||||
if (e->m_cat == kEventCategory::MouseEvent)
|
||||
{
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
bool old_inside = m_mouse_inside;
|
||||
m_mouse_inside = point_in_rect(me->m_pos, m_clip);
|
||||
if (old_inside == false && m_mouse_inside == true)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseEnter;
|
||||
handle_event(&e2);
|
||||
}
|
||||
if (old_inside == true && m_mouse_inside == false)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseLeave;
|
||||
handle_event(&e2);
|
||||
}
|
||||
}
|
||||
return kEventResult::Consumed;
|
||||
}
|
||||
}
|
||||
|
||||
switch (e->m_cat)
|
||||
{
|
||||
case kEventCategory::MouseEvent:
|
||||
{
|
||||
if (m_mouse_ignore)
|
||||
break;
|
||||
MouseEvent* me = static_cast<MouseEvent*>(e);
|
||||
bool inside = point_in_rect(me->m_pos, m_clip);
|
||||
bool inside_old = m_mouse_inside;
|
||||
m_mouse_inside = inside;
|
||||
switch (e->m_type)
|
||||
{
|
||||
case kEventType::MouseScroll:
|
||||
case kEventType::MouseDownL:
|
||||
case kEventType::MouseDownR:
|
||||
case kEventType::MouseUpL:
|
||||
case kEventType::MouseUpR:
|
||||
if ((inside || m_mouse_captured) && ((handle_event(e) == kEventResult::Consumed) || m_force_mouse_capture))
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
case kEventType::MouseMove:
|
||||
if (inside_old == false && inside == true)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseEnter;
|
||||
handle_event(&e2);
|
||||
}
|
||||
if (inside || m_mouse_captured)
|
||||
{
|
||||
ret = handle_event(e);
|
||||
if (m_force_mouse_capture)
|
||||
ret = kEventResult::Consumed;
|
||||
}
|
||||
if (inside_old == true && inside == false)
|
||||
{
|
||||
MouseEvent e2 = *me;
|
||||
e2.m_type = kEventType::MouseLeave;
|
||||
handle_event(&e2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kEventCategory::GestureEvent:
|
||||
{
|
||||
if (m_mouse_ignore)
|
||||
break;
|
||||
GestureEvent* ge = static_cast<GestureEvent*>(e);
|
||||
bool inside = point_in_rect(ge->m_pos, m_clip);
|
||||
//bool inside_old = m_mouse_inside;
|
||||
m_mouse_inside = inside;
|
||||
if ((inside || m_mouse_captured) && handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (handle_event(e) == kEventResult::Consumed)
|
||||
return kEventResult::Consumed;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return pp::panopainter::handle_legacy_ui_node_event(*this, e);
|
||||
}
|
||||
|
||||
kEventResult Node::handle_event(Event* e)
|
||||
@@ -622,101 +450,22 @@ bool Node::is_child(Node* o) const
|
||||
|
||||
void Node::mouse_capture()
|
||||
{
|
||||
if (!m_parent || !m_manager)
|
||||
return;
|
||||
|
||||
auto root = m_manager->get_ref("main");
|
||||
if (!root) return;
|
||||
|
||||
auto& c = root->current_mouse_capture;
|
||||
auto& s = root->m_capture_stack;
|
||||
|
||||
// already owner of capture
|
||||
if (c.get() == this || std::find_if(s.begin(), s.end(),
|
||||
[this](const auto& a) { return a.get() == this; }) != s.end())
|
||||
return;
|
||||
|
||||
if (c)
|
||||
{
|
||||
if (c->is_child_recursive(this))
|
||||
{
|
||||
// save on stack
|
||||
s.push_back(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cancel previous owner
|
||||
MouseEvent e;
|
||||
e.m_type = kEventType::MouseCancel;
|
||||
c->handle_event(&e);
|
||||
|
||||
// TODO: only delete nodes on a different tree,
|
||||
// so preserve direct parents of this
|
||||
|
||||
// also clear the whole stack
|
||||
//s.clear();
|
||||
|
||||
s.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
// make current
|
||||
c = shared_from_this();
|
||||
m_mouse_captured = true;
|
||||
pp::panopainter::legacy_ui_node_mouse_capture(*this);
|
||||
}
|
||||
|
||||
void Node::mouse_release()
|
||||
{
|
||||
if (!m_parent || !m_manager)
|
||||
return;
|
||||
|
||||
auto root = m_manager->get_ref("main");
|
||||
if (!root) return;
|
||||
|
||||
auto& c = root->current_mouse_capture;
|
||||
auto& s = root->m_capture_stack;
|
||||
|
||||
s.erase(std::remove_if(s.begin(), s.end(),
|
||||
[this](const auto& a) { return a.get() == this; }), s.end());
|
||||
if (c.get() == this)
|
||||
{
|
||||
if (s.empty())
|
||||
{
|
||||
c = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = s.back();
|
||||
s.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
m_mouse_captured = false;
|
||||
pp::panopainter::legacy_ui_node_mouse_release(*this);
|
||||
}
|
||||
|
||||
void Node::key_capture()
|
||||
{
|
||||
if (!m_parent || !m_manager)
|
||||
return;
|
||||
|
||||
auto root = m_manager->get_ref("main");
|
||||
if (!root) return;
|
||||
|
||||
root->current_key_capture = shared_from_this();
|
||||
m_key_captured = true;
|
||||
pp::panopainter::legacy_ui_node_key_capture(*this);
|
||||
}
|
||||
|
||||
void Node::key_release()
|
||||
{
|
||||
if (!m_parent || !m_manager)
|
||||
return;
|
||||
|
||||
auto root = m_manager->get_ref("main");
|
||||
if (!root) return;
|
||||
|
||||
if (root->current_key_capture.get() == this)
|
||||
root->current_key_capture = nullptr;
|
||||
m_key_captured = false;
|
||||
pp::panopainter::legacy_ui_node_key_release(*this);
|
||||
}
|
||||
|
||||
Node&& Node::operator=(Node&& o)
|
||||
|
||||
@@ -599,88 +599,79 @@ void NodeStrokePreview::draw_stroke_immediate()
|
||||
ortho_proj));
|
||||
const bool copy_stroke_destination = pass_orchestration.copy_stroke_destination;
|
||||
pp::panopainter::setup_legacy_stroke_shader(pass_orchestration.stroke_shader);
|
||||
execute_stroke_draw_immediate_pass_sequence(
|
||||
prepared_strokes.stroke,
|
||||
prepared_strokes.dual_stroke,
|
||||
const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_draw_immediate_shell<StrokeFrame>(
|
||||
*b,
|
||||
std::move(prepared_strokes.dual_brush),
|
||||
pass_orchestration,
|
||||
copy_stroke_destination,
|
||||
zoom,
|
||||
size);
|
||||
|
||||
m_rtt.unbindFramebuffer();
|
||||
|
||||
apply_stroke_preview_viewport(vp.x, vp.y, vp.width, vp.height);
|
||||
apply_stroke_preview_clear_color(cc);
|
||||
}
|
||||
|
||||
NodeStrokePreview::StrokeMainLivePassRequest
|
||||
NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request(
|
||||
Stroke& stroke,
|
||||
const Brush& brush,
|
||||
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
|
||||
bool copy_stroke_destination,
|
||||
float zoom,
|
||||
const glm::vec2& size)
|
||||
{
|
||||
return pp::panopainter::make_legacy_node_stroke_preview_main_live_pass_request<StrokeFrame>(
|
||||
brush,
|
||||
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,
|
||||
[&] {
|
||||
return stroke_draw_compute(stroke, zoom);
|
||||
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 (brush.m_tip_mix > 0.f)
|
||||
if (b->m_tip_mix > 0.f)
|
||||
{
|
||||
stroke_draw_mix(xy(frame.m_mixer_rect), zw(frame.m_mixer_rect));
|
||||
}
|
||||
|
||||
frame.col = brush.m_blend_mode != 0 || brush.m_tip_mix > 0.f ?
|
||||
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) {
|
||||
execute_stroke_draw_immediate_main_live_sample_pass(
|
||||
brush,
|
||||
copy_stroke_destination,
|
||||
frame,
|
||||
size);
|
||||
},
|
||||
[&](auto& frame) {
|
||||
/*auto rect =*/ stroke_draw_samples(frame.shapes, m_tex, copy_stroke_destination);
|
||||
},
|
||||
[&] { set_active_texture_unit(stroke_preview_live_slots::kMixer); m_rtt_mixer.unbindTexture(); });
|
||||
}
|
||||
|
||||
void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass(
|
||||
Stroke& dual_stroke,
|
||||
const Brush& brush,
|
||||
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
|
||||
std::shared_ptr<Brush> dual_brush,
|
||||
bool copy_stroke_destination,
|
||||
float zoom,
|
||||
const glm::vec2& size)
|
||||
{
|
||||
(void)pass_orchestration;
|
||||
(void)dual_brush;
|
||||
pp::panopainter::execute_legacy_stroke_preview_live_pass(
|
||||
[&] {
|
||||
m_rtt.clear();
|
||||
},
|
||||
[&] {
|
||||
return stroke_draw_compute(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(
|
||||
@@ -691,104 +682,24 @@ void NodeStrokePreview::execute_stroke_draw_immediate_dual_pass(
|
||||
});
|
||||
},
|
||||
[&](auto& frame) {
|
||||
/*auto rect =*/ stroke_draw_samples(frame.shapes, m_tex_dual, copy_stroke_destination);
|
||||
/*auto rect =*/ stroke_draw_samples(frame.shapes, m_tex, copy_stroke_destination);
|
||||
},
|
||||
[&] {
|
||||
pp::panopainter::copy_legacy_node_stroke_preview_framebuffer_to_texture(
|
||||
m_tex_dual,
|
||||
size,
|
||||
stroke_preview_composite_slots::kStroke);
|
||||
});
|
||||
}
|
||||
|
||||
void NodeStrokePreview::execute_stroke_draw_immediate_pass_sequence(
|
||||
Stroke& stroke,
|
||||
Stroke& dual_stroke,
|
||||
const Brush& brush,
|
||||
std::shared_ptr<Brush> dual_brush,
|
||||
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
|
||||
bool copy_stroke_destination,
|
||||
float zoom,
|
||||
const glm::vec2& size)
|
||||
{
|
||||
const auto& material = pass_orchestration.material;
|
||||
const bool sequence_ok = pp::panopainter::execute_legacy_node_stroke_preview_immediate_pass_sequence(
|
||||
pp::panopainter::LegacyNodeStrokePreviewImmediatePassSequenceRequest {
|
||||
.execute_dual_pass = [&] {
|
||||
if (!material.dual_pass.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
pp::panopainter::setup_legacy_stroke_dual_shader(
|
||||
material.dual_pass.uses_pattern);
|
||||
bind_stroke_preview_dual_pass_textures(*dual_brush);
|
||||
execute_stroke_draw_immediate_dual_pass(
|
||||
dual_stroke,
|
||||
brush,
|
||||
pass_orchestration,
|
||||
std::move(dual_brush),
|
||||
copy_stroke_destination,
|
||||
zoom,
|
||||
size);
|
||||
},
|
||||
.capture_background = [&] {
|
||||
execute_stroke_preview_background_capture_pass(
|
||||
size,
|
||||
pass_orchestration.background_colorize,
|
||||
m_tex_background,
|
||||
[&] {
|
||||
m_plane.draw_fill();
|
||||
});
|
||||
},
|
||||
.execute_main_live_pass = [&]() -> bool {
|
||||
return pp::panopainter::execute_legacy_node_stroke_preview_main_live_pass(
|
||||
make_stroke_draw_immediate_main_live_pass_request(
|
||||
stroke,
|
||||
brush,
|
||||
pass_orchestration,
|
||||
copy_stroke_destination,
|
||||
zoom,
|
||||
size));
|
||||
},
|
||||
.execute_final_composite = [&]() -> bool {
|
||||
return pp::panopainter::execute_legacy_node_stroke_preview_final_composite(
|
||||
size,
|
||||
glm::vec2(brush.m_pattern_scale),
|
||||
brush,
|
||||
material.composite_pass,
|
||||
m_tex_background,
|
||||
m_tex,
|
||||
m_tex_dual,
|
||||
m_tex_preview,
|
||||
m_sampler_linear,
|
||||
m_sampler_linear_repeat,
|
||||
[&] {
|
||||
brush.m_pattern_texture ? brush.m_pattern_texture->bind() : unbind_texture_2d();
|
||||
},
|
||||
[&] {
|
||||
m_plane.draw_fill();
|
||||
});
|
||||
},
|
||||
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();
|
||||
});
|
||||
assert(sequence_ok);
|
||||
}
|
||||
|
||||
void NodeStrokePreview::execute_stroke_draw_immediate_main_live_sample_pass(
|
||||
const Brush& brush,
|
||||
bool copy_stroke_destination,
|
||||
const StrokeFrame& frame,
|
||||
const glm::vec2& size)
|
||||
{
|
||||
(void)brush;
|
||||
(void)copy_stroke_destination;
|
||||
(void)size;
|
||||
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,
|
||||
});
|
||||
m_rtt.unbindFramebuffer();
|
||||
|
||||
apply_stroke_preview_viewport(vp.x, vp.y, vp.width, vp.height);
|
||||
apply_stroke_preview_clear_color(cc);
|
||||
}
|
||||
|
||||
Image NodeStrokePreview::render_to_image()
|
||||
|
||||
@@ -30,15 +30,6 @@ class NodeStrokePreview : public NodeBorder
|
||||
static Sampler m_sampler_mipmap;
|
||||
static DynamicShape m_brush_shape;
|
||||
Texture2D m_tex_preview;
|
||||
void execute_stroke_draw_immediate_pass_sequence(
|
||||
Stroke& stroke,
|
||||
Stroke& dual_stroke,
|
||||
const Brush& brush,
|
||||
std::shared_ptr<Brush> dual_brush,
|
||||
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
|
||||
bool copy_stroke_destination,
|
||||
float zoom,
|
||||
const glm::vec2& size);
|
||||
public:
|
||||
using parent = NodeBorder;
|
||||
static std::atomic_int s_instances;
|
||||
@@ -65,26 +56,6 @@ public:
|
||||
// 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;
|
||||
StrokeMainLivePassRequest make_stroke_draw_immediate_main_live_pass_request(
|
||||
Stroke& stroke,
|
||||
const Brush& brush,
|
||||
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
|
||||
bool copy_stroke_destination,
|
||||
float zoom,
|
||||
const glm::vec2& size);
|
||||
void execute_stroke_draw_immediate_main_live_sample_pass(
|
||||
const Brush& brush,
|
||||
bool copy_stroke_destination,
|
||||
const StrokeFrame& frame,
|
||||
const glm::vec2& size);
|
||||
void execute_stroke_draw_immediate_dual_pass(
|
||||
Stroke& dual_stroke,
|
||||
const Brush& brush,
|
||||
const pp::panopainter::LegacyNodeStrokePreviewPassOrchestrationPlan& pass_orchestration,
|
||||
std::shared_ptr<Brush> dual_brush,
|
||||
bool copy_stroke_destination,
|
||||
float zoom,
|
||||
const glm::vec2& size);
|
||||
void draw_stroke();
|
||||
void draw_stroke_immediate();
|
||||
Image render_to_image();
|
||||
|
||||
Reference in New Issue
Block a user