568 lines
20 KiB
C++
568 lines
20 KiB
C++
#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;
|
|
}
|
|
}
|