#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 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 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 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 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 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(); } }