#include "pch.h" #include "canvas_modes.h" #include "app.h" #include "canvas.h" #include "legacy_canvas_mode_helpers.h" #include "legacy_ui_overlay_services.h" #include "log.h" #include "renderer_gl/opengl_capabilities.h" using pp::legacy_canvas_mode::apply_canvas_mode_capability; using pp::legacy_canvas_mode::query_canvas_mode_capability; void CanvasModeMaskFree::init() { m_shape.create(); } void CanvasModeMaskFree::leave(kCanvasMode next) { // Canvas::I->draw_objects(std::bind(&CanvasModeFill::on_Draw, this, glm::mat4(1), std::placeholders::_1, std::placeholders::_2)); if (next != kCanvasMode::Draw && next != kCanvasMode::Erase && next != kCanvasMode::Line) { m_points.clear(); Canvas::I->m_smask_active = false; } } void CanvasModeMaskFree::clear() { m_points.clear(); m_points2d.clear(); m_shape.clear(); } void CanvasModeMaskFree::on_MouseEvent(MouseEvent* me, glm::vec2& loc) { static glm::vec2 oldpos; static glm::vec2 oldvec; static float acc = 0.f; if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch) return; 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; 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); if (!(App::I->keys[(int)kKey::KeyShift] || App::I->keys[(int)kKey::KeyCtrl])) Canvas::I->m_smask.clear({0, 0, 0, 0}); Canvas::I->m_smask_active = true; Canvas::I->m_smask_mode = 1; break; } case kEventType::MouseUpL: pp::panopainter::release_legacy_mouse_capture(*node); m_dragging = false; if (m_points2d.size() > 3) { if (!m_points.empty()) { m_selection_cam = Canvas::I->get_camera(); //m_points2d = poly_intersect(poly_remove_duplicate(m_points2d), Canvas::I->face_to_shape2D(0)); auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) { // blending state intentionally left unchanged here. apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false); pp::panopainter::setup_legacy_vr_color_shader({ .color = App::I->keys[(int)kKey::KeyCtrl] ? glm::vec4(0, 0, 0, 1) : glm::vec4(1, 1, 1, 1), .mvp = proj * camera, }); m_shape.draw_fill(); }; // use m_shape to render the mask polygon auto v = triangulate(poly_remove_duplicate(m_points2d)); Canvas::I->project2Dpoints(v); m_shape.update_vertices(v.data(), (int)v.size()); Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0); // close the path and reset m_shape to contour rendering m_points.push_back(m_points.back()); m_points.push_back(m_points.front()); Canvas::I->project2Dpoints(m_points); m_shape.update_vertices(m_points.data(), (int)m_points.size()); } } else { Canvas::I->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.f - glm::dot(v, oldvec); acc += d; oldpos = loc; oldvec = v; if (acc > 0.001) // angle change tolerance { //LOG("d=%f acc=%f", d, acc); acc = 0; m_points2d.push_back(loc); 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; pp::panopainter::release_legacy_mouse_capture(*node); 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) { const bool depth = query_canvas_mode_capability(pp::renderer::gl::depth_test_state()); apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), false); if (m_points.size() > 3) { if (m_dragging) { pp::panopainter::setup_legacy_vr_color_shader({ .color = { 0, 0, 0, 1 }, .mvp = glm::scale(glm::vec3(1, -1, 1)) * ortho, }); //m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill(); m_shape.draw_stroke(); } } if (depth) apply_canvas_mode_capability(pp::renderer::gl::depth_test_state(), true); } void CanvasModeMaskLine::init() { m_shape.create(); } void CanvasModeMaskLine::leave(kCanvasMode next) { if (next != kCanvasMode::Draw && next != kCanvasMode::Erase && next != kCanvasMode::Line) { m_points.clear(); m_active_tool = false; Canvas::I->m_smask_active = false; } if (!m_active_tool) return; if (m_points2d.size() > 3) { std::vector points; for (int i = 0; i < (int)m_points2d.size(); i++) points.emplace_back(m_points2d[i]); auto v = triangulate(poly_remove_duplicate(points)); Canvas::I->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) { // blending state intentionally left unchanged here. pp::panopainter::setup_legacy_vr_color_shader({ .color = { 1, 1, 1, 1 }, .mvp = proj * camera, }); m_shape.draw_fill(); }; Canvas::I->draw_objects_direct(std::bind(drawer, std::placeholders::_1, std::placeholders::_2), Canvas::I->m_smask, 0); //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::I->project2Dpoints(m_points); // reset m_shape to contour rendering m_shape.update_vertices(m_points.data(), (int)m_points.size()); } } else { Canvas::I->m_smask_active = false; } m_active_tool = false; } void CanvasModeMaskLine::enter(kCanvasMode prev) { //m_points2d.clear(); //m_points.clear(); //Canvas::I->m_smask.clear({0, 0, 0, 0}); //m_active_tool = true; } void CanvasModeMaskLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc) { if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch) return; switch (me->m_type) { case kEventType::MouseDownL: { if (m_active_tool == false) { m_active_tool = true; m_points2d.clear(); m_points.clear(); Canvas::I->m_smask.clear({ 0, 0, 0, 0 }); Canvas::I->m_smask_active = true; Canvas::I->m_smask_mode = 2; } node->mouse_capture(); m_dragging = true; m_points2d.push_back(loc); 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: pp::panopainter::release_legacy_mouse_capture(*node); m_dragging = false; if (m_points.size() > 1) { m_selection_cam = Canvas::I->get_camera(); 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) { if (glm::distance(m_points2d.front(), loc) < 10) loc = m_points2d.front(); 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; pp::panopainter::release_legacy_mouse_capture(*node); 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() > 1) { if (m_active_tool) { pp::panopainter::setup_legacy_vr_color_shader({ .color = { 0, 0, 0, 1 }, .mvp = glm::scale(glm::vec3(1, -1, 1)) * ortho, }); //m_dragging ? m_shape.draw_stroke() : m_shape.draw_fill(); m_shape.draw_stroke(); } else { pp::panopainter::setup_legacy_vr_color_shader({ .color = { 0, 0, 0, 1 }, .mvp = proj * camera, }); m_shape.draw_stroke(); } } }