#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" 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_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; 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 = m_camera_fov - ge->m_distance_delta * .05f; canvas->m_cam_rot = canvas->m_pan * 0.003f; 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, node->m_brush); m_dragging = true; } node->mouse_capture(); break; case kEventType::MouseUpL: if (m_dragging) { canvas->stroke_end(); m_dragging = false; node->mouse_release(); } if (m_picking) { m_picking = false; node->mouse_release(); 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); /* glm::vec3 ray_origin; glm::vec3 ray_dir; glm::vec3 hit_pos; glm::vec3 hit_normal; int plane_id; if (canvas->point_trace(loc, ray_origin, ray_dir, hit_pos, hit_normal, plane_id)) { canvas->m_layers[canvas->m_current_layer_idx].m_rtt[plane_id].bindFramebuffer(); glm::vec2 fbpos = (hit_pos.xy() * 0.5f + 0.5f) * glm::vec2(canvas->m_width, canvas->m_height); int x = fbpos.x; int y = fbpos.y; glm::u8vec4 sample; glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &sample); glm::vec3 pix = glm::vec3(sample) / 255.f; 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); canvas->m_layers[canvas->m_current_layer_idx].m_rtt[plane_id].unbindFramebuffer(); } */ /* glm::vec2 fbpos = me->m_pos * node->root()->m_zoom; int x = fbpos.x; int y = App::I.height - fbpos.y - 1; glm::i8vec4 sample; glBindFramebuffer(GL_FRAMEBUFFER, 0); glReadBuffer(GL_FRONT); glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &sample); glm::vec3 pix = glm::vec3(sample) / 255.f; 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::MouseMove: if (m_dragging) canvas->stroke_update(loc, me->m_pressure); if (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; node->mouse_release(); } break; default: break; } } //////////////////////////////////////////////////////////////////// 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; if (canvas->point_trace(loc, ro, rd, hit_o, 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) { 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; 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()); } break; } case kEventType::MouseUpL: node->mouse_release(); m_dragging = false; break; case kEventType::MouseMove: { glm::vec3 ro, rd, hit_o, hit_d; int plane_id; if (m_dragging && canvas->point_trace(loc, ro, rd, hit_o, 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(), m_points.size()); } break; } 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, 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(); } }