diff --git a/engine/app_events.cpp b/engine/app_events.cpp index e28ab92..3992360 100644 --- a/engine/app_events.cpp +++ b/engine/app_events.cpp @@ -140,7 +140,7 @@ bool App::key_down(kKey key) e.m_type = kEventType::KeyDown; e.m_key = key; auto ret = layout[main_id]->on_event(&e); - //layout[main_id]->update(); + layout[main_id]->update(); return ret == kEventResult::Consumed; } bool App::key_up(kKey key) diff --git a/engine/canvas_modes.cpp b/engine/canvas_modes.cpp index 79baeab..0bbdb8a 100644 --- a/engine/canvas_modes.cpp +++ b/engine/canvas_modes.cpp @@ -6,7 +6,6 @@ #include "shader.h" #include "node_canvas.h" #include "app.h" -#include NodeCanvas* CanvasMode::node; ui::Canvas* CanvasMode::canvas; @@ -375,6 +374,145 @@ char get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, return 0; // No collision } +int SegmentCount = 0; +std::vector CanvasModeFill::triangulate(const std::vector>& points) +{ + struct Segment + { + std::shared_ptr a = nullptr; + std::shared_ptr b = nullptr; + Segment* prev = nullptr; + std::shared_ptr next = nullptr; + bool end = false; + Segment() + { + SegmentCount++; + } + ~Segment() + { + SegmentCount--; + } + }; + + std::shared_ptr root = std::make_shared(); + std::shared_ptr node = root; + for (int i = 0; i < points.size(); i++) + { + node->a = points[i]; + if (i == points.size() - 1) + { + node->b = points[0]; + node->next = root; + node->end = true; + root->prev = node.get(); + } + else + { + node->b = points[i + 1]; + node->next = std::make_shared(); + node->next->prev = node.get(); + } + node = node->next; + } + + node = root; + std::stack> todo; + std::vector> polys; + todo.push(root); + while (!todo.empty()) + { + node = todo.top(); + todo.pop(); + polys.push_back(node); + while (node) + { + std::shared_ptr other = node->next; + while (other) + { + if (*node->a == *other->a || *node->a == *other->b || + *node->b == *other->a || *node->b == *other->b) + { + other = other->end ? nullptr : other->next; + continue; + } + glm::vec2 s0a(node->a->x, node->a->y); + glm::vec2 s0b(node->b->x, node->b->y); + glm::vec2 s1a(other->a->x, other->a->y); + glm::vec2 s1b(other->b->x, other->b->y); + glm::vec2 is; + if (segments_intersect(s0a, s0b, s1a, s1b, is)) + { + auto p = std::make_shared(is.x, is.y); + auto poly_root = std::make_shared(); + poly_root->a = p; + poly_root->b = node->b; + poly_root->next = node->next; + todo.push(poly_root); + other->a = p; + node->b = p; + auto poly_end = std::make_shared(); + poly_end->a = other->prev->b; + poly_end->b = p; + poly_end->end = true; + poly_end->prev = other->prev; + other->prev->next = poly_end; + other->prev = node.get(); + node->next = other; + break; + } + other = other->end ? nullptr : other->next; + } + node = node->end ? nullptr : node->next; + } + } + + std::vector vertices; + for (auto poly : polys) + { + std::vector outline; + node = poly; + while (node) + { + outline.push_back(new p2t::Point(*node->a)); + auto current = node; + node = node->end ? nullptr : node->next; + current->next = nullptr; + } + LOG("poly %ld", outline.size()); + + if (outline.size() > 2) + { + p2t::CDT* cdt = new p2t::CDT(outline); + cdt->Triangulate(); + auto tr = cdt->GetTriangles(); + for (auto t : tr) + { + 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); + vertices.push_back(vertex); + } + } + } + + delete cdt; + } + for (auto p : outline) + delete p; + } + + return vertices; +} + void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) { static glm::vec2 oldpos; @@ -432,32 +570,14 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) m_dragging = false; if (m_points2d.size() > 3) { - std::vector points; + 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()); + points.emplace_back(std::make_shared(m_points2d[i].x, m_points2d[i].y)); + auto v = triangulate(points); + LOG("leaked segments: %d", SegmentCount); + LOG("%d points", (int)v.size()); + + m_shape.update_vertices(v.data(), (int)v.size()); if (!m_points.empty()) { @@ -513,7 +633,7 @@ void CanvasModeFill::on_MouseEvent(MouseEvent* me, glm::vec2& loc) m_points.push_back(vert); m_points.push_back(vert); } - m_shape.update_vertices(m_points.data(), m_points.size()); + m_shape.update_vertices(m_points.data(), (int)m_points.size()); } } break; @@ -551,14 +671,14 @@ if (canvas->point_trace_plane(loc, ro, rd, hit_o, hit_d, hit_fb, 0)) if (m_dragging) { m_points.pop_back(); - m_shape.update_vertices(m_points.data(), m_points.size()); + 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(), m_points.size()); + m_shape.update_vertices(m_points.data(), (int)m_points.size()); } break; default: diff --git a/engine/canvas_modes.h b/engine/canvas_modes.h index 4f70430..baf792e 100644 --- a/engine/canvas_modes.h +++ b/engine/canvas_modes.h @@ -2,6 +2,7 @@ #include "event.h" #include "shape.h" #include "brush.h" +#include NS_START class Canvas; @@ -100,4 +101,5 @@ public: virtual void on_MouseEvent(MouseEvent* me, glm::vec2& loc) override; virtual void init() override; virtual void leave() override; + std::vector triangulate(const std::vector>& points); }; diff --git a/engine/node.cpp b/engine/node.cpp index e6a28e6..c8ea42d 100644 --- a/engine/node.cpp +++ b/engine/node.cpp @@ -50,36 +50,31 @@ kEventResult Node::on_event(Event* e) { kEventResult ret = kEventResult::Available; - if (e->m_cat == kEventCategory::MouseEvent) + if (current_mouse_capture) + return current_mouse_capture->on_event(e); + + bool skip_children = false; + skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) && + (m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children; + + if (!skip_children) { + for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - if (current_mouse_capture) - return current_mouse_capture->on_event(e); - - bool skip_children = false; - skip_children |= (e->m_cat == kEventCategory::MouseEvent || e->m_cat == kEventCategory::GestureEvent) && - (m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children; - - if (!skip_children) + if ((*it)->on_event(e) == kEventResult::Consumed) { - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) + if (m_flood_events) { - if ((*it)->on_event(e) == kEventResult::Consumed) - { - if (m_flood_events) - { - ret = kEventResult::Consumed; - } - else - { - return kEventResult::Consumed; - } - } + ret = kEventResult::Consumed; + } + else + { + return kEventResult::Consumed; } - if (ret == kEventResult::Consumed) - return ret; } } + if (ret == kEventResult::Consumed) + return ret; } switch (e->m_cat) diff --git a/engine/node_dialog_open.cpp b/engine/node_dialog_open.cpp index 1bdc0f7..110a257 100644 --- a/engine/node_dialog_open.cpp +++ b/engine/node_dialog_open.cpp @@ -190,6 +190,10 @@ void NodeDialogSave::init_controls() destroy(); }; input = find("txt-input"); + input->on_return = [&](NodeTextInput* target){ + if (btn_ok->on_click) + btn_ok->on_click(btn_ok); + }; } void NodeDialogSave::loaded() { @@ -223,6 +227,10 @@ void NodeDialogNewDoc::init_controls() destroy(); }; input = find("txt-input"); + input->on_return = [&](NodeTextInput* target){ + if (btn_ok->on_click) + btn_ok->on_click(btn_ok); + }; } void NodeDialogNewDoc::loaded() { diff --git a/engine/node_panel_brush.cpp b/engine/node_panel_brush.cpp index 9b581d7..3c7202b 100644 --- a/engine/node_panel_brush.cpp +++ b/engine/node_panel_brush.cpp @@ -167,7 +167,7 @@ void NodePanelBrushPreset::init() brush->m_brush.m_tip_flow = .2; brush->m_brush.m_tip_opacity = 1; brush->m_brush.m_tip_spacing = 0.03; - brush->m_brush.m_jitter_spread = (rand() % 1000) * 0.0001; + //brush->m_brush.m_jitter_spread = (rand() % 1000) * 0.0001; brush->m_preview->m_brush = brush->m_brush; brush->m_preview->draw_stroke(); brush->m_thumb->m_path = path; diff --git a/engine/node_text_input.cpp b/engine/node_text_input.cpp index f09bc9e..9b3e0c3 100644 --- a/engine/node_text_input.cpp +++ b/engine/node_text_input.cpp @@ -75,6 +75,11 @@ kEventResult NodeTextInput::handle_event(Event* e) m_text->set_text(m_string.c_str()); } } + else if (ke->m_char == '\n' || ke->m_char == '\r') // enter/return + { + if (on_return) + on_return(this); + } else if (ke->m_char >= 32 && ke->m_char < (32 + 96)) { m_string += (char)ke->m_char; diff --git a/engine/node_text_input.h b/engine/node_text_input.h index 15ed09b..a9135b2 100644 --- a/engine/node_text_input.h +++ b/engine/node_text_input.h @@ -7,6 +7,7 @@ class NodeTextInput : public NodeBorder public: NodeText* m_text; std::string m_string; + std::function on_return; virtual Node* clone_instantiate() const override; virtual void clone_finalize(Node* dest) const override; virtual void init() override;