#include "pch.h" #include "canvas_modes.h" #include "app.h" #include "canvas.h" #include "legacy_canvas_draw_merge_services.h" #include "legacy_ui_overlay_services.h" #include "node_tool_bucket.h" #include "texture.h" void CanvasModeFill::init() { m_shape.create(); } void CanvasModeFill::leave(kCanvasMode next) { if (m_points.size() > 2) { auto drawer = [this](const glm::mat4& camera, const glm::mat4& proj) { 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(); Canvas::I->m_smask_active = true; } else { Canvas::I->m_smask_active = false; } } void CanvasModeFill::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: { node->mouse_capture(); m_dragging = true; glm::vec3 ro, rd, hit_o, hit_d; glm::vec2 hit_fb; int plane_id; if (Canvas::I->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, 0)) { m_dirty_planes[plane_id]++; 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::I->m_smask.clear({0, 0, 0, 0}); break; } case kEventType::MouseUpL: pp::panopainter::release_legacy_mouse_capture(*node); 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::I->point_trace(loc, ro, rd, hit_o, fb_pos, hit_d, plane_id)) { 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; 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 CanvasModeFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) { if (!m_points.empty()) { pp::panopainter::setup_legacy_vr_color_shader({ .color = { 0, 0, 0, .25 }, .mvp = proj * camera, }); m_dragging ? m_shape.draw_fill() : m_shape.draw_stroke(); } } void CanvasModeFloodFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) { m_draw_tip = App::I->draws_canvas_tip_for_input(me->m_source, me->m_type); if (Canvas::I->m_touch_lock && me->m_source == kEventSource::Touch) return; struct ActionFloodFill : public Action { std::shared_ptr m_layer; std::shared_ptr m_snap; std::array m_dirty_face = SIXPLETTE(false); std::array m_dirty_box = SIXPLETTE(glm::vec4(0)); glm::ivec2 m_pos; glm::vec4 m_color; float m_threshold; int m_layer_index; int m_plane; virtual void run() override { } virtual size_t memory() override { return m_snap->memsize(); } virtual Action* get_redo() override { auto a = new ActionFloodFill; a->m_direction = reverse_direction(); a->m_layer = m_layer; a->m_snap = m_snap; a->m_pos = m_pos; a->m_color = m_color; a->m_layer_index = m_layer_index; a->m_threshold = m_threshold; a->m_plane = m_plane; a->m_dirty_box = m_dirty_box; a->m_dirty_face = m_dirty_face; return a; } virtual void undo() override { if (m_direction == Direction::Undo) { m_layer->restore(*m_snap); } else { Canvas::FloodData plane_data; std::unique_ptr color; Canvas::I->flood_fill(m_layer_index, m_plane, { m_pos }, plane_data, m_threshold, m_color, color); plane_data.apply(); } } }; switch (me->m_type) { case kEventType::MouseUpL: glm::vec3 ro, rd, hit, n; glm::vec2 pos; int plane; if (Canvas::I->point_trace(loc, ro, rd, hit, pos, n, plane)) { Canvas::FloodData plane_data; std::unique_ptr color; Canvas::I->flood_fill(Canvas::I->m_current_layer_idx, plane, { (glm::ivec2)pos }, plane_data, m_tool->get_threshold(), Canvas::I->m_current_brush->m_tip_color, color); auto a = new ActionFloodFill; a->m_direction = Action::Direction::Undo; a->m_layer = plane_data.layer; a->m_snap = std::make_shared(plane_data.layer->snapshot()); a->m_pos = (glm::ivec2)pos; a->m_color = Canvas::I->m_current_brush->m_tip_color; a->m_layer_index = Canvas::I->m_current_layer_idx; a->m_threshold = m_tool->get_threshold(); a->m_plane = plane; a->m_dirty_box = plane_data.layer->frame().m_dirty_box; a->m_dirty_face = plane_data.layer->frame().m_dirty_face; ActionManager::add(a); plane_data.apply(); } break; default: break; } } void CanvasModeFloodFill::init() { TextureManager::load(m_cursor_path.c_str()); } void CanvasModeFloodFill::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) { if (m_draw_tip) { pp::panopainter::setup_legacy_canvas_draw_merge_texture_shader({ .mvp = glm::scale(glm::vec3(1, -1, 1)) * ortho * glm::translate(glm::vec3(Canvas::I->m_cur_pos, 0.f)) * glm::scale(glm::vec3(32, 32, 1)) * glm::translate(glm::vec3(0.5f, -0.5f, 0)), .texture_slot = 0, }); auto& t = TextureManager::get(m_cursor_id); Canvas::I->m_sampler_linear.bind(0); t.bind(); Canvas::I->m_plane.draw_fill(); t.unbind(); } } void CanvasModeFloodFill::enter(kCanvasMode prev) { auto tools = App::I->layout[App::I->main_id]->find("tools-container"); m_tool = tools->add_child(); } void CanvasModeFloodFill::leave(kCanvasMode next) { pp::panopainter::destroy_legacy_node(*m_tool); m_tool = nullptr; }