#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 "util.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: if (App::I.keys[(int)kKey::KeyAlt]) break; 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 * 2.0f; 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(); } else { canvas->stroke_start(loc, me->m_pressure, canvas->m_current_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(); glm::vec4 pix = canvas->pick_get(loc); canvas->m_current_brush.m_tip_color = pix; App::I.color->set_color(pix); canvas->pick_end(); } m_dragging = false; m_picking = false; break; case kEventType::MouseDownR: if (App::I.keys[(int)kKey::KeyAlt]) { m_resizing = true; m_dragging = true; m_size_pos_start = m_cur_pos; m_size_value_start = canvas->m_current_brush.m_tip_size; node->mouse_capture(); } break; case kEventType::MouseUpR: if (m_dragging && m_resizing) { node->mouse_release(); m_dragging = false; m_resizing = false; } break; case kEventType::MouseMove: if (m_dragging && !m_picking && !m_resizing) canvas->stroke_update(loc, me->m_pressure); if (m_dragging && m_picking) { glm::vec4 pix = canvas->pick_get(loc); canvas->m_current_brush.m_tip_color = pix; App::I.color->set_color(pix); } if (m_dragging && m_resizing) { auto diff = m_cur_pos - m_size_pos_start; canvas->m_current_brush.m_tip_size = m_size_value_start + diff.x * 0.001f; } m_cur_pos = loc; break; case kEventType::MouseCancel: if (m_dragging) { canvas->stroke_cancel(); m_dragging = false; node->mouse_release(); } if (m_picking) m_picking = false; if (m_resizing) m_resizing = false; break; default: break; } } void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) { #ifndef __IOS__ if (1) { auto pos = m_resizing ? m_size_pos_start : m_cur_pos; if (App::I.keys[(int)kKey::KeyAlt]) pos.x = pos.x - canvas->m_current_brush.m_tip_size * 500; ui::ShaderManager::use(ui::kShader::StrokePreview); ui::ShaderManager::u_int(ui::kShaderUniform::Tex, 0); ui::ShaderManager::u_float(ui::kShaderUniform::Alpha, canvas->m_current_brush.m_tip_flow); auto tip_color = glm::vec4(glm::vec3(canvas->m_current_brush.m_tip_color), 1); ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, tip_color); //ui::ShaderManager::u_int(ui::kShaderUniform::Highlight, 0); float tip_scale = 1.f / glm::tan(glm::radians(ui::Canvas::I->m_cam_fov * 0.5f)); ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, glm::scale(glm::vec3(1, -1, 1)) * ortho * glm::translate(glm::vec3(pos, 0)) * glm::scale(glm::vec3(canvas->m_current_brush.m_tip_size * 800.f * tip_scale)) ); glEnable(GL_BLEND); glActiveTexture(GL_TEXTURE0); auto& tex = TextureManager::get(canvas->m_current_brush.m_tex_id); tex.bind(); canvas->m_sampler_brush.bind(0); canvas->m_plane.draw_fill(); tex.unbind(); } #endif } void CanvasModePen::leave() { m_brush = canvas->m_current_brush; } void CanvasModePen::enter() { m_cur_pos = ui::Canvas::I->m_cur_pos; if (m_valid_brush) { canvas->m_current_brush = m_brush; App::I.brush_update(); } else { m_brush = canvas->m_current_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, canvas->m_current_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, canvas->m_current_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 = xy(canvas->m_cam_pos); 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 = glm::vec3(m_pos_start + (me->m_pos - m_drag_start) * glm::vec2(1, -1) * 0.001f, canvas->m_cam_pos.z); 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 CanvasModeMaskFree::init() { m_shape.create(); } void CanvasModeMaskFree::leave() { // canvas->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(), std::placeholders::_1, std::placeholders::_2)); // m_points.clear(); } void CanvasModeMaskFree::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::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.emplace_back(std::make_shared(m_points2d[i].x, m_points2d[i].y)); auto v = canvas->triangulate(points); canvas->project2Dpoints(v); LOG("%d points", (int)v.size()); m_shape.update_vertices(v.data(), (int)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(); }; canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask); //m_points.clear(); // close the path m_points.push_back(m_points[m_points.size() - 2]); m_points.push_back(m_points.front()); canvas->project2Dpoints(m_points); // reset m_shape to contour rendering m_shape.update_vertices(m_points.data(), (int)m_points.size()); } } 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(), (int)m_points.size()); } } break; } case kEventType::MouseCancel: if (m_dragging) { m_points.pop_back(); m_shape.update_vertices(m_points.data(), (int)m_points.size()); } m_dragging = false; node->mouse_release(); if (m_points.size() < 4) { m_points.clear(); m_shape.update_vertices(m_points.data(), (int)m_points.size()); } break; default: break; } } void CanvasModeMaskFree::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) { if (m_points.size() > 3) { if (m_dragging) { 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, { 0, 0, 0, 1 }); //m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill(); m_shape.draw_stroke(); } else { ui::ShaderManager::use(ui::kShader::Color); ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera); ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 1 }); m_shape.draw_stroke(); } } } //////////////////////////////////////////////////////////////////// void CanvasModeMaskLine::init() { m_shape.create(); } void CanvasModeMaskLine::leave() { if (m_points2d.size() > 3) { std::vector> points; for (int i = 0; i < (int)m_points2d.size(); i++) points.emplace_back(std::make_shared(m_points2d[i].x, m_points2d[i].y)); auto v = canvas->triangulate(points); canvas->project2Dpoints(v); LOG("%d points", (int)v.size()); m_shape.update_vertices(v.data(), (int)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(); }; canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask); //m_points.clear(); // close the path m_points.push_back(m_points.back()); m_points.push_back(m_points.back()); m_points.push_back(m_points.front()); canvas->project2Dpoints(m_points); // reset m_shape to contour rendering m_shape.update_vertices(m_points.data(), (int)m_points.size()); } } else { canvas->m_smask_active = false; } m_active_tool = false; } void CanvasModeMaskLine::enter() { m_points2d.clear(); m_points.clear(); canvas->m_smask.clear({0, 0, 0, 0}); canvas->m_smask_active = true; m_active_tool = true; } void CanvasModeMaskLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc) { switch (me->m_type) { case kEventType::MouseDownL: { node->mouse_capture(); m_dragging = true; m_points2d.push_back(loc); ui::Shape::vertex_t vert; vert.pos = glm::vec4(loc, 0, 1); m_points.push_back(vert); m_shape.update_vertices(m_points.data(), (int)m_points.size()); break; } case kEventType::MouseUpL: node->mouse_release(); m_dragging = false; if (m_points.size() > 1) { m_points.push_back(m_points.back()); m_shape.update_vertices(m_points.data(), (int)m_points.size()); } break; case kEventType::MouseMove: { if (m_dragging) { m_points.back().pos = glm::vec4(loc, 0, 1); m_points2d.back() = loc; m_shape.update_vertices(m_points.data(), (int)m_points.size()); } break; } case kEventType::MouseCancel: if (m_dragging) { m_points.pop_back(); m_shape.update_vertices(m_points.data(), (int)m_points.size()); } m_dragging = false; node->mouse_release(); if (m_points.size() < 4) { m_points.clear(); m_shape.update_vertices(m_points.data(), (int)m_points.size()); } break; default: break; } } void CanvasModeMaskLine::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) { if (m_points.size() > 3) { if (m_active_tool) { 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, { 0, 0, 0, 1 }); //m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill(); m_shape.draw_stroke(); } else { ui::ShaderManager::use(ui::kShader::Color); ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, proj * camera); ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, 1 }); m_shape.draw_stroke(); } } } //////////////////////////////////////////////////////////////////// void CanvasModeFill::init() { m_shape.create(); } void CanvasModeFill::leave() { if (m_points.size() > 2) { 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, 1, 1, 1}); m_shape.draw_fill(); }; canvas->draw_objects(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), canvas->m_smask); m_points.clear(); canvas->m_smask_active = true; } else { canvas->m_smask_active = false; } } void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) { switch (me->m_type) { case kEventType::MouseDownL: { node->mouse_capture(); m_dragging = true; 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); } m_shape.update_vertices(m_points.data(), (int)m_points.size()); } canvas->m_smask.clear({0, 0, 0, 0}); break; } case kEventType::MouseUpL: node->mouse_release(); m_dragging = false; break; case kEventType::MouseMove: { glm::vec3 ro, rd, hit_o, hit_d; glm::vec2 fb_pos; int plane_id; if (m_dragging && canvas->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, plane_id)) { ui::Shape::vertex_t v; v.pos = glm::vec4(hit_o, 1); v.uvs = glm::vec2(0); m_points.back() = v; m_shape.update_vertices(m_points.data(), (int)m_points.size()); } break; } case kEventType::MouseCancel: if (m_dragging) { m_points.pop_back(); m_shape.update_vertices(m_points.data(), (int)m_points.size()); } m_dragging = false; node->mouse_release(); if (m_points.size() < 4) { m_points.clear(); m_shape.update_vertices(m_points.data(), (int)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, proj * camera); ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, { 0, 0, 0, .25 }); m_dragging ? m_shape.draw_fill() : m_shape.draw_stroke(); } }