579 lines
18 KiB
C++
579 lines
18 KiB
C++
#include "pch.h"
|
|
#include "log.h"
|
|
#include "canvas_modes.h"
|
|
#include "layout.h"
|
|
#include "canvas.h"
|
|
#include "shader.h"
|
|
#include "node_canvas.h"
|
|
#include "app.h"
|
|
#include <poly2tri.h>
|
|
|
|
NodeCanvas* CanvasMode::node;
|
|
ui::Canvas* CanvasMode::canvas;
|
|
|
|
void CanvasModeBasicCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownL:
|
|
break;
|
|
case kEventType::MouseUpL:
|
|
break;
|
|
case kEventType::MouseDownR:
|
|
m_draggingR = true;
|
|
m_dragR_start = me->m_pos;
|
|
m_pan_start = canvas->m_pan;
|
|
node->mouse_capture();
|
|
break;
|
|
case kEventType::MouseUpR:
|
|
m_draggingR = false;
|
|
node->mouse_release();
|
|
break;
|
|
case kEventType::MouseMove:
|
|
if (m_draggingR)
|
|
canvas->m_pan = m_pan_start + (me->m_pos - m_dragR_start) * glm::vec2(-1, -1) * (canvas->m_cam_fov / 85.f);
|
|
canvas->m_cam_rot = canvas->m_pan * 0.003f;
|
|
break;
|
|
case kEventType::MouseScroll:
|
|
m_zoom_canvas += me->m_scroll_delta * 0.1f;
|
|
canvas->m_cam_fov -= me->m_scroll_delta * 20.1f;
|
|
App::I.brush_update();
|
|
break;
|
|
case kEventType::MouseCancel:
|
|
m_draggingR = false;
|
|
node->mouse_release();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CanvasModeBasicCamera::on_GestureEvent(GestureEvent* ge)
|
|
{
|
|
switch (ge->m_type)
|
|
{
|
|
case kEventType::GestureStart:
|
|
m_pan_start = canvas->m_pan;
|
|
m_zoom_start = m_zoom_canvas;
|
|
m_camera_fov = canvas->m_cam_fov;
|
|
break;
|
|
case kEventType::GestureMove:
|
|
canvas->m_pan = m_pan_start + ge->m_pos_delta * glm::vec2(-1, -1) * 0.3f * (canvas->m_cam_fov / 85.f);
|
|
canvas->m_cam_fov = m_camera_fov - ge->m_distance_delta * .05f;
|
|
canvas->m_cam_rot = canvas->m_pan * 0.003f;
|
|
App::I.brush_update();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownL:
|
|
if (App::I.keys[(int)kKey::KeyAlt] || m_picking)
|
|
{
|
|
m_picking = true;
|
|
canvas->pick_start();
|
|
//canvas->m_show_tmp = true;
|
|
}
|
|
else
|
|
{
|
|
canvas->stroke_start(loc, me->m_pressure, node->m_brush);
|
|
}
|
|
m_dragging = true;
|
|
node->mouse_capture();
|
|
break;
|
|
case kEventType::MouseUpL:
|
|
if (m_dragging && !m_picking)
|
|
{
|
|
node->mouse_release();
|
|
canvas->stroke_end();
|
|
}
|
|
if (m_dragging && m_picking)
|
|
{
|
|
node->mouse_release();
|
|
//canvas->m_show_tmp = false;
|
|
|
|
glm::vec4 pix = canvas->pick_get(loc);
|
|
auto hsv = convert_rgb2hsv(glm::vec3(pix[0], pix[1], pix[2]));
|
|
App::I.color->m_hue->set_value(hsv.x);
|
|
App::I.color->m_quad->set_value(1.f - hsv.y, 1.f - hsv.z);
|
|
}
|
|
m_dragging = false;
|
|
m_picking = false;
|
|
break;
|
|
case kEventType::MouseMove:
|
|
if (m_dragging && !m_picking)
|
|
canvas->stroke_update(loc, me->m_pressure);
|
|
if (m_dragging && m_picking)
|
|
{
|
|
glm::vec4 pix = canvas->pick_get(loc);
|
|
auto hsv = convert_rgb2hsv(glm::vec3(pix[0], pix[1], pix[2]));
|
|
App::I.color->m_hue->set_value(hsv.x);
|
|
App::I.color->m_quad->set_value(1.f - hsv.y, 1.f - hsv.z);
|
|
}
|
|
break;
|
|
case kEventType::MouseCancel:
|
|
if (m_dragging)
|
|
{
|
|
canvas->stroke_cancel();
|
|
m_dragging = false;
|
|
node->mouse_release();
|
|
}
|
|
if (m_picking)
|
|
{
|
|
m_picking = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CanvasModePen::leave()
|
|
{
|
|
m_brush = node->m_brush;
|
|
}
|
|
|
|
void CanvasModePen::enter()
|
|
{
|
|
if (m_valid_brush)
|
|
{
|
|
node->m_brush = m_brush;
|
|
App::I.brush_update();
|
|
}
|
|
else
|
|
{
|
|
m_brush = node->m_brush;
|
|
m_valid_brush = true;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModeLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownL:
|
|
node->mouse_capture();
|
|
m_dragging = true;
|
|
m_drag_start = loc;
|
|
m_drag_pos = loc;
|
|
break;
|
|
case kEventType::MouseUpL:
|
|
node->mouse_release();
|
|
if (m_dragging)
|
|
{
|
|
canvas->stroke_start(m_drag_start, 1.f, node->m_brush);
|
|
canvas->stroke_update(m_drag_pos, 1.f);
|
|
canvas->stroke_end();
|
|
}
|
|
m_dragging = false;
|
|
break;
|
|
case kEventType::MouseMove:
|
|
if (m_dragging)
|
|
m_drag_pos = loc;
|
|
break;
|
|
case kEventType::MouseCancel:
|
|
node->mouse_release();
|
|
m_dragging = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CanvasModeLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
|
{
|
|
if (m_dragging)
|
|
{
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, ortho);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, node->m_brush.m_tip_color);
|
|
static glm::vec4 AB[2];
|
|
AB[0] = { m_drag_start, 0, 1 };
|
|
AB[1] = { m_drag_pos, 0, 1 };
|
|
AB[0].y = canvas->m_box.w - AB[0].y - 1; // invert Y
|
|
AB[1].y = canvas->m_box.w - AB[1].y - 1; // invert Y
|
|
m_line.update_vertices(AB);
|
|
m_line.draw_stroke();
|
|
}
|
|
}
|
|
|
|
void CanvasModeLine::init()
|
|
{
|
|
m_line.create();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModeCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownR:
|
|
canvas->m_cam_pos = { 0, 0, 0 };
|
|
break;
|
|
case kEventType::MouseDownL:
|
|
m_dragging = true;
|
|
m_drag_start = me->m_pos;
|
|
m_pos_start = canvas->m_cam_pos.xy;
|
|
node->mouse_capture();
|
|
break;
|
|
case kEventType::MouseUpL:
|
|
m_dragging = false;
|
|
node->mouse_release();
|
|
canvas->m_cam_pos = { 0, 0, 0 };
|
|
break;
|
|
case kEventType::MouseMove:
|
|
if (m_dragging)
|
|
canvas->m_cam_pos.xy = m_pos_start + (me->m_pos - m_drag_start) * glm::vec2(1, -1) * 0.001f;
|
|
break;
|
|
case kEventType::MouseCancel:
|
|
m_dragging = false;
|
|
node->mouse_release();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModeGrid::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownL:
|
|
{
|
|
node->mouse_capture();
|
|
glm::vec3 ro, rd, hit_o, hit_d;
|
|
glm::vec2 fb_pos;
|
|
if (canvas->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, m_plane_id))
|
|
{
|
|
m_lines.push_back({ hit_o, hit_d });
|
|
origin = hit_o;
|
|
dir = hit_d;
|
|
m_dragging = true;
|
|
}
|
|
break;
|
|
}
|
|
case kEventType::MouseUpL:
|
|
node->mouse_release();
|
|
m_dragging = false;
|
|
//commit();
|
|
break;
|
|
case kEventType::MouseMove:
|
|
{
|
|
glm::vec3 ro, rd, hit_o, hit_d;
|
|
glm::vec2 hit_fb;
|
|
if (m_dragging && canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, m_plane_id))
|
|
{
|
|
m_lines.back() = { hit_o, hit_d };
|
|
origin = hit_o;
|
|
dir = hit_d;
|
|
m_dragging = true;
|
|
}
|
|
break;
|
|
}
|
|
case kEventType::MouseCancel:
|
|
if (m_dragging)
|
|
m_lines.pop_back();
|
|
m_dragging = false;
|
|
node->mouse_release();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CanvasModeGrid::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
|
{
|
|
//if (m_dragging)
|
|
for (auto l : m_lines)
|
|
{
|
|
auto origin = l.o;
|
|
auto dir = l.d;
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 0, 0, 1});
|
|
static glm::vec4 AB[2];
|
|
AB[0] = {origin - dir * 10.f, 1};
|
|
AB[1] = {origin + dir * 10.f, 1 };
|
|
m_line.update_vertices(AB);
|
|
m_line.draw_stroke();
|
|
}
|
|
}
|
|
|
|
void CanvasModeGrid::init()
|
|
{
|
|
m_line.create();
|
|
}
|
|
|
|
void CanvasModeGrid::commit()
|
|
{
|
|
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj){
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 0, 0, 1});
|
|
static glm::vec4 AB[2];
|
|
AB[0] = {origin - dir * 10.f, 1};
|
|
AB[1] = {origin + dir * 10.f, 1 };
|
|
m_line.update_vertices(AB);
|
|
m_line.draw_stroke();
|
|
};
|
|
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2));
|
|
}
|
|
|
|
void CanvasModeGrid::clear()
|
|
{
|
|
m_lines.clear();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
void CanvasModeFill::init()
|
|
{
|
|
m_shape.create();
|
|
}
|
|
|
|
void CanvasModeFill::leave()
|
|
{
|
|
// canvas->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(), std::placeholders::_1, std::placeholders::_2));
|
|
// m_points.clear();
|
|
}
|
|
|
|
// Returns 1 if the lines intersect, otherwise 0. In addition, if the lines
|
|
// intersect the intersection point may be stored in the floats i_x and i_y.
|
|
char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y,
|
|
float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
|
|
{
|
|
float s1_x, s1_y, s2_x, s2_y;
|
|
s1_x = p1_x - p0_x; s1_y = p1_y - p0_y;
|
|
s2_x = p3_x - p2_x; s2_y = p3_y - p2_y;
|
|
|
|
float s, t;
|
|
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
|
|
t = (s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
|
|
|
|
if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
|
|
{
|
|
// Collision detected
|
|
if (i_x != NULL)
|
|
*i_x = p0_x + (t * s1_x);
|
|
if (i_y != NULL)
|
|
*i_y = p0_y + (t * s1_y);
|
|
return 1;
|
|
}
|
|
|
|
return 0; // No collision
|
|
}
|
|
|
|
void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
|
|
{
|
|
static glm::vec2 oldpos;
|
|
static glm::vec2 oldvec;
|
|
static float acc = 0.f;
|
|
switch (me->m_type)
|
|
{
|
|
case kEventType::MouseDownR:
|
|
{
|
|
/*
|
|
if (!m_points.empty())
|
|
{
|
|
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { node->m_brush.m_tip_color.rgb(), node->m_brush.m_tip_opacity });
|
|
m_shape.draw_fill();
|
|
};
|
|
std::vector<int> planes;
|
|
for (auto p : m_dirty_planes)
|
|
{
|
|
planes.push_back(p.first);
|
|
canvas->m_dirty_face[p.first] = true;
|
|
canvas->m_dirty_box[p.first] = { 0, 0, canvas->m_width, canvas->m_height };
|
|
}
|
|
canvas->snap_history(planes);
|
|
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2));
|
|
m_points.clear();
|
|
m_dirty_planes.clear();
|
|
}
|
|
*/
|
|
break;
|
|
}
|
|
case kEventType::MouseDownL:
|
|
{
|
|
node->mouse_capture();
|
|
m_dragging = true;
|
|
m_points2d.clear();
|
|
m_points.clear();
|
|
oldpos = loc;
|
|
oldvec = {1.f, 0.f};
|
|
acc = 0;
|
|
ui::Shape::vertex_t vert;
|
|
vert.pos = glm::vec4(loc, 0, 1);
|
|
m_points2d.push_back(loc);
|
|
m_points2d.push_back(loc);
|
|
m_points.push_back(vert);
|
|
m_points.push_back(vert);
|
|
canvas->m_smask.clear({0, 0, 0, 0});
|
|
canvas->m_smask_active = true;
|
|
break;
|
|
}
|
|
case kEventType::MouseUpL:
|
|
node->mouse_release();
|
|
m_dragging = false;
|
|
if (m_points2d.size() > 3)
|
|
{
|
|
std::vector<p2t::Point*> points;
|
|
for (int i = 0; i < (int)m_points2d.size() - 1; i++)
|
|
points.push_back(new p2t::Point(m_points2d[i].x, m_points2d[i].y));
|
|
p2t::CDT cdt(points);
|
|
cdt.Triangulate();
|
|
auto triangles = cdt.GetTriangles();
|
|
std::vector<ui::Shape::vertex_t> v;
|
|
for (auto t : triangles)
|
|
{
|
|
ui::Shape::vertex_t vertex;
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
auto p = t->GetPoint(i);
|
|
|
|
glm::vec3 ro, rd, hit_o, hit_d;
|
|
glm::vec2 hit_fb;
|
|
int plane_id;
|
|
if (canvas->point_trace({p->x, p->y}, ro, rd, hit_o, hit_fb, hit_d, plane_id))
|
|
{
|
|
m_dirty_planes[plane_id]++;
|
|
vertex.pos = glm::vec4(hit_o, 1);
|
|
v.push_back(vertex);
|
|
}
|
|
}
|
|
}
|
|
m_shape.update_vertices(v.data(), v.size());
|
|
|
|
if (!m_points.empty())
|
|
{
|
|
auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) {
|
|
//glEnable(GL_BLEND);
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, {1, 1, 1, 1});
|
|
m_shape.draw_fill();
|
|
};
|
|
std::vector<int> planes;
|
|
for (auto p : m_dirty_planes)
|
|
{
|
|
planes.push_back(p.first);
|
|
canvas->m_dirty_face[p.first] = true;
|
|
canvas->m_dirty_box[p.first] = { 0, 0, canvas->m_width, canvas->m_height };
|
|
}
|
|
canvas->snap_history(planes);
|
|
canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask);
|
|
m_points.clear();
|
|
m_dirty_planes.clear();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
canvas->m_smask_active = false;
|
|
}
|
|
break;
|
|
case kEventType::MouseMove:
|
|
{
|
|
if (m_dragging)
|
|
{
|
|
auto v = loc-oldpos;
|
|
float len = glm::length(v);
|
|
if (len > 5)
|
|
{
|
|
m_points.back().pos = glm::vec4(loc, 0, 1);
|
|
m_points2d.back() = loc;
|
|
|
|
v = glm::normalize(v);
|
|
float d = 1-glm::dot(v, oldvec);
|
|
acc += d;
|
|
oldpos = loc;
|
|
oldvec = v;
|
|
if (acc > 0.001) // angle change tollerance
|
|
{
|
|
LOG("d=%f acc=%f", d, acc);
|
|
acc = 0;
|
|
|
|
m_points2d.push_back(loc);
|
|
ui::Shape::vertex_t vert;
|
|
vert.pos = glm::vec4(loc, 0, 1);
|
|
m_points.push_back(vert);
|
|
m_points.push_back(vert);
|
|
}
|
|
m_shape.update_vertices(m_points.data(), m_points.size());
|
|
}
|
|
}
|
|
break;
|
|
/*
|
|
glm::vec3 ro, rd, hit_o, hit_d;
|
|
glm::vec2 hit_fb;
|
|
int plane_id;
|
|
if (canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, 0))
|
|
{
|
|
m_dirty_planes[plane_id]++;
|
|
ui::Shape::vertex_t v;
|
|
v.pos = glm::vec4(hit_o, 1);
|
|
v.uvs = glm::vec2(0);
|
|
if (m_points.size() < 3)
|
|
{
|
|
m_points.push_back(v);
|
|
}
|
|
else
|
|
{
|
|
auto last = m_points.back();
|
|
m_points.push_back(m_points[0]);
|
|
m_points.push_back(last);
|
|
m_points.push_back(v);
|
|
float isx, isy;
|
|
if (get_line_intersection(m_points[0].pos.x, m_points[0].pos.y, v.pos.x, v.pos.y, 1, -1, 1, 1, &isx, &isy))
|
|
{
|
|
LOG("intersection in %f %f", isx, isy);
|
|
}
|
|
}
|
|
m_shape.update_vertices(m_points.data(), m_points.size());
|
|
}
|
|
*/
|
|
}
|
|
case kEventType::MouseCancel:
|
|
if (m_dragging)
|
|
{
|
|
m_points.pop_back();
|
|
m_shape.update_vertices(m_points.data(), m_points.size());
|
|
}
|
|
m_dragging = false;
|
|
node->mouse_release();
|
|
if (m_points.size() < 4)
|
|
{
|
|
m_points.clear();
|
|
m_shape.update_vertices(m_points.data(), m_points.size());
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CanvasModeFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
|
|
{
|
|
if (!m_points.empty())
|
|
{
|
|
ui::ShaderManager::use(ui::kShader::Color);
|
|
ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, glm::scale(glm::vec3(1,-1,1)) * ortho);
|
|
ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { node->m_brush.m_tip_color.rgb(), node->m_brush.m_tip_opacity });
|
|
m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill();
|
|
}
|
|
}
|