From 004095680177b2a07438075dd92c0c81865d45d5 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 3 Dec 2024 01:25:49 +0100 Subject: [PATCH] Rework to weak_ptr from lots of shared_ptr. --- src/app-manager.h | 40 +++++---- src/connectable.h | 40 ++------- src/connector.h | 13 ++- src/edge.h | 12 +-- src/graph-manager.h | 185 ++++++++++++++++++++------------------ src/interaction-manager.h | 4 +- src/node.h | 25 ++---- src/signal-manager.h | 22 ++--- src/signal.h | 17 +++- src/state-io.h | 4 +- 10 files changed, 171 insertions(+), 191 deletions(-) diff --git a/src/app-manager.h b/src/app-manager.h index da66d49..151ca85 100644 --- a/src/app-manager.h +++ b/src/app-manager.h @@ -16,7 +16,6 @@ #include "ui.h" #include -#include using json = nlohmann::json; @@ -91,8 +90,11 @@ namespace VISEQ::APP { int start_id = e.at("start").get(); int end_id = e.at("end").get(); - VEC_SPTR_Node start = gm.nodes | RANGE_FILTER([start_id](SPTR_Node n){return n->id == start_id;}) | std::ranges::to(); - VEC_SPTR_Node end = gm.nodes | RANGE_FILTER([end_id](SPTR_Node n){return n->id == end_id;}) | std::ranges::to(); + VEC_WPTR_Node start = gm.getNodesByID(start_id); + VEC_WPTR_Node end = gm.getNodesByID(end_id); + +// VEC_SPTR_Node start = gm.nodes | RANGE_FILTER([start_id](SPTR_Node n){return n->id == start_id;}) | std::ranges::to(); +// VEC_SPTR_Node end = gm.nodes | RANGE_FILTER([end_id](SPTR_Node n){return n->id == end_id;}) | std::ranges::to(); if(!start.empty() && !end.empty()) { std::cout << std::format("connection {} to {}", start_id, end_id) << std::endl; @@ -100,18 +102,17 @@ namespace VISEQ::APP { } } - - gm.edges.back()->newId(highest_id); // set static id counter in base class to highest value from json file + gm.lastEdge().lock()->newId(highest_id); for(auto s : graph.at("signalmanager").at("signals")){ int start_id = s.at("start").get(); int next_id = s.at("next").get(); int last_id = s.at("last").get(); std::shared_ptr ms = s; + VEC_WPTR_Node start = gm.getNodesByID(start_id); + VEC_WPTR_Node last = gm.getNodesByID(last_id); + VEC_WPTR_Node next = gm.getNodesByID(next_id); - VEC_SPTR_Node start = gm.nodes | RANGE_FILTER([start_id](SPTR_Node n){return n->id == start_id;}) | std::ranges::to(); - VEC_SPTR_Node last = gm.nodes | RANGE_FILTER([last_id](SPTR_Node n){return n->id == last_id;}) | std::ranges::to(); - VEC_SPTR_Node next = gm.nodes | RANGE_FILTER([next_id](SPTR_Node n){return n->id == next_id;}) | std::ranges::to(); ms->start = start.front(); ms->next = next.front(); ms->last = last.front(); @@ -129,16 +130,16 @@ namespace VISEQ::APP { } for(int i = 0; i < 8; ++i){ - gm.addConnection(gm.nodes[i], gm.nodes[(i+1) % 8]); + gm.addConnection(gm.getNode(i), gm.getNode((i+1) % 8)); } - sm.addSignalAtNode(gm.nodes.front()); + sm.addSignalAtNode(gm.getFirstNode()); } } void updateMidiPorts(){ - for(auto&n : gm.nodes | RANGE_FILTER([](VISEQ::GRAPH::NODES::SPTR_Node n){return n->getNodeType() == NodeType::MIDINODE;})){ - auto nc = std::dynamic_pointer_cast(n); + for(auto&n : gm.getMidiNodes()){ + auto nc = std::dynamic_pointer_cast(n.lock()); for(auto& mo : sm.midi.midi_out_ports){ if(!nc->midi_outs.contains(mo.number) && mo.enabled){ nc->midi_outs[mo.number] = {mo.number, mo.port.port_name, false}; @@ -186,13 +187,14 @@ namespace VISEQ::APP { ui.draw(SCREEN_MOUSE, canvas->camera); mutex.unlock(); } + + /*inline void to_json(json& j, const AppManager& A){*/ + /* j = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}};*/ + /*}*/ + /**/ + /*inline void from_json(const json& j, AppManager& A){*/ + /* j.at("graphmanager").get_to(A.gm); // = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}};*/ + /*}*/ }; - inline void to_json(json& j, const AppManager& A){ - j = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}}; - } - - inline void from_json(const json& j, AppManager& A){ - j.at("graphmanager").get_to(A.gm); // = json{{"graphmanager", A.gm}, {"signalmanager", A.sm}}; - } } diff --git a/src/connectable.h b/src/connectable.h index 2a75e68..a8471f0 100644 --- a/src/connectable.h +++ b/src/connectable.h @@ -3,35 +3,19 @@ #include "draggable.h" #include "vmath.h" #include -#include namespace VISEQ::BASE { - class Connectable : public Draggable, public std::enable_shared_from_this { + class Connectable : public Draggable { public: Connectable() {} Connectable(Vec2Df position) : Draggable(position) {} - virtual ~Connectable() {remove();} - - inline static std::vector> connectables; - - std::shared_ptr partner; + + std::weak_ptr partner; + bool new_partner = false; bool connecting = false; Vec2Df connecting_position; - - std::shared_ptr getPtr(){ - return shared_from_this(); - } - - virtual void init() { - VISEQ::BASE::Connectable::connectables.emplace_back(this); - } - - virtual void remove() { - std::cout << "delete Connectable: " << getPtr() << std::endl; - // std::erase(VISEQ::BASE::Connectable::connectables, getPtr()); - } - + virtual void drag(Vec2Df new_position) override { connecting = true; connecting_position = new_position; @@ -44,22 +28,8 @@ namespace VISEQ::BASE { virtual void connect() { if(picked_up){ - std::cout << getPtr() << std::endl; - std::cout << "connect use count: " << getPtr().use_count() << std::endl; - for(auto c : connectables){ - if(c != getPtr() && c->hovering()) { - partner = c; - c->partner = getPtr(); - new_partner = true; - partner->new_partner = true; - std::cout << "connect use count: " << getPtr().use_count() << std::endl; - std::cout << connectables.size() << std::endl; - break; - } - } connecting = false; } - } virtual void draw(){ diff --git a/src/connector.h b/src/connector.h index 94948b1..ea762f7 100644 --- a/src/connector.h +++ b/src/connector.h @@ -13,7 +13,6 @@ namespace VISEQ::GRAPH { class Connector : public BASE::Connectable, public GraphItem{ public: Connector() {} - //~Connector() {BASE::Connectable::remove();} Connector(std::shared_ptr parent, Vec2Df center_position, float orbit) : orbit(orbit) { setPosition(center_position); @@ -33,11 +32,11 @@ namespace VISEQ::GRAPH { } std::shared_ptr getPtr(){ - return std::static_pointer_cast(BASE::Connectable::shared_from_this()); + return std::static_pointer_cast(shared_from_this()); } virtual bool hovering() override { - return !partner && CheckCollisionPointCircle(SCREEN_MOUSE, position, radius); + return !partner.expired() && CheckCollisionPointCircle(SCREEN_MOUSE, position, radius); } void setParent(std::shared_ptr _parent){ @@ -54,8 +53,8 @@ namespace VISEQ::GRAPH { if(pickedUp()) state->pushEvent({getPtr(), APP::Interaction::DRAG}); if(picked_up && released()) state->pushEvent({getPtr(), APP::Interaction::PUTDOWN}); - if(!partner) position = center_position - ((center_position - SCREEN_MOUSE)).norm() * (radius + orbit); - if(partner) position = center_position - ((center_position - partner->position)).norm() * (radius + orbit); + if(partner.expired()) position = center_position - ((center_position - SCREEN_MOUSE)).norm() * (radius + orbit); + if(!partner.expired()) position = center_position - ((center_position - partner.lock()->position)).norm() * (radius + orbit); if(new_partner) { new_partner = false; state->pushEvent({getPtr(), APP::Interaction::CONNECT}); @@ -66,8 +65,8 @@ namespace VISEQ::GRAPH { BASE::Connectable::draw(); float opacity = 150.0f - Clamp(position.dist(SCREEN_MOUSE), 0.0f, 150.0f); - if(partner){ - DrawLineV(position, partner->position, VS_COLOR_RED); + if(!partner.expired()){ + DrawLineV(position, partner.lock()->position, VS_COLOR_RED); } if(hovering()){ diff --git a/src/edge.h b/src/edge.h index 9344ebd..4515109 100644 --- a/src/edge.h +++ b/src/edge.h @@ -12,10 +12,10 @@ namespace VISEQ::GRAPH::EDGES { public: Edge() {} - Edge(std::shared_ptr start, std::shared_ptr end) : start(start), end(end) {} + Edge(std::weak_ptr start, std::weak_ptr end) : start(start), end(end) {} - std::shared_ptr start; - std::shared_ptr end; + std::weak_ptr start; + std::weak_ptr end; std::weak_ptr start_conn; std::weak_ptr end_conn; @@ -39,13 +39,15 @@ namespace VISEQ::GRAPH::EDGES { virtual EdgeType getEdgeType() const {return edgeType;} - std::shared_ptr getNextNode(std::shared_ptr origin){ - return start == origin ? end : start; + std::weak_ptr getNextNode(std::weak_ptr origin){ + return start.lock() == origin.lock() ? end : start; } void draw(Vec2Df mouse_pos, Camera2D cam) {} }; typedef std::shared_ptr SPTR_Edge; + typedef std::weak_ptr WPTR_Edge; typedef std::vector VEC_SPTR_Edge; + typedef std::vector VEC_WPTR_Edge; } diff --git a/src/graph-manager.h b/src/graph-manager.h index 9cd3440..52c8a97 100644 --- a/src/graph-manager.h +++ b/src/graph-manager.h @@ -15,7 +15,6 @@ #include "node.h" #include -#include #include #include #include @@ -35,6 +34,20 @@ using namespace VISEQ::GRAPH::EDGES; namespace VISEQ::GRAPH { class GraphManager : public std::enable_shared_from_this{ + private: + NODES::VEC_SPTR_Node nodes; + EDGES::VEC_SPTR_Edge edges; + + std::map connections; + + EDGES::VEC_WPTR_Edge remove_edges; + EDGES::VEC_WPTR_Edge split_edges; + + VEC_WPTR_Node selected_nodes; + + std::map counter; + + std::shared_ptr state = APP::State::get(); public: @@ -43,39 +56,24 @@ namespace VISEQ::GRAPH { std::shared_ptr getPtr(){ return shared_from_this(); } - - NODES::VEC_SPTR_Node nodes; - EDGES::VEC_SPTR_Edge edges; - std::map connections; - - EDGES::VEC_SPTR_Edge remove_edges; - EDGES::VEC_SPTR_Edge split_edges; - - VEC_SPTR_Node selected_nodes; - - std::map counter; - - std::shared_ptr state = APP::State::get(); - SPTR_Node addMidiNode(Vec2Df position){ + void addMidiNode(Vec2Df position){ nodes.emplace_back(std::make_shared(position)); - return nodes.back(); } void addNode(SPTR_Node node){ nodes.insert(nodes.end(), node); - nodes.back()->init(); } - void addConnection(SPTR_Node from, SPTR_Node to){ - if(from != to) { + void addConnection(WPTR_Node from, WPTR_Node to){ + if(from.lock() != to.lock()) { edges.emplace_back(std::make_shared()); edges.back()->start = from; edges.back()->end = to; - edges.back()->start_conn = from->connectors.back(); - edges.back()->end_conn = to->connectors.back(); - from->connections.push_back(edges.back()); - to->connections.push_back(edges.back()); + edges.back()->start_conn = from.lock()->connectors.back(); + edges.back()->end_conn = to.lock()->connectors.back(); + from.lock()->connections.push_back(edges.back()); + to.lock()->connections.push_back(edges.back()); } } @@ -84,20 +82,19 @@ namespace VISEQ::GRAPH { auto temp_nodes = nodes | RANGE_FILTER([](SPTR_Node n){return n->select();}) | std::ranges::to(); if(!KEYS_DOWN.shift) selected_nodes.clear(); selected_nodes.insert(selected_nodes.end(), temp_nodes.begin(), temp_nodes.end()); - std::for_each(selected_nodes.begin(), selected_nodes.end(), [](SPTR_Node n){n->selected = true;}); + std::for_each(selected_nodes.begin(), selected_nodes.end(), [](WPTR_Node n){n.lock()->selected = true;}); } void deselect(){ std::cout << "deselect" << std::endl; for(auto s : selected_nodes){ - s->selected = false; + s.lock()->selected = false; } selected_nodes.clear(); } - VEC_SPTR_Node getSelection(){ + VEC_WPTR_Node getSelection(){ return selected_nodes; - //return nodes | RANGE_FILTER([](SPTR_Node n){return n->selected;}) | std::ranges::to(); } void copyNodes(VEC_SPTR_Node _nodes, Vec2Df position){ @@ -139,6 +136,17 @@ namespace VISEQ::GRAPH { void reset(){ counter.clear(); } + WPTR_Node getNode(int i){ + return nodes.at(i); + } + + WPTR_Node getFirstNode(){ + return nodes.front(); + } + + VEC_WPTR_Node getMidiNodes(){ + return nodes | RANGE_FILTER([](VISEQ::GRAPH::NODES::SPTR_Node n){return n->getNodeType() == NodeType::MIDINODE;}) | std::ranges::to(); + } NODES::SPTR_Node getRandomNode(){ VEC_SPTR_GraphItem o; @@ -157,27 +165,29 @@ namespace VISEQ::GRAPH { std::sort(neighbors.begin(), neighbors.end(), [position](SPTR_Node na, SPTR_Node nb){ return na->position.dist(position) < nb->position.dist(position);}); return neighbors.front(); } + VEC_WPTR_Node getNodesByID(int _id){ + return nodes | RANGE_FILTER([_id](SPTR_Node n){return n->id == _id;}) | std::ranges::to(); // TODO: Multiple nodes with the same ID? Why not return only one node? + } + + WPTR_Edge lastEdge(){ + return edges.back(); + } - /*SPTR_Node next_node(SPTR_Node current, SPTR_Node last){*/ - /* std::vector> active_connectors;*/ - /**/ - /*}*/ - - SPTR_Node next(SPTR_Node current, SPTR_Node last){ - VEC_SPTR_Edge possible_connections = current->connections | RANGE_FILTER([current](SPTR_Edge c){ - return (c->start == current && c->pass_forward) || (c->end == current && c->pass_backward); - }) | std::ranges::to(); + WPTR_Node next(WPTR_Node current, WPTR_Node last){ + VEC_WPTR_Edge possible_connections = current.lock()->connections | RANGE_FILTER([current](WPTR_Edge c){ + return (c.lock()->start.lock() == current.lock() && c.lock()->pass_forward) || (c.lock()->end.lock() == current.lock() && c.lock()->pass_backward); + }) | std::ranges::to(); if(possible_connections.empty()) return SPTR_Node(nullptr); int return_path = 0; float angle = -1; - if(current->distributionMode == Distribution::GEOMETRIC){ - Vec2Df coming_from = (current->position - last->position).norm(); + if(current.lock()->distributionMode == Distribution::GEOMETRIC){ + Vec2Df coming_from = (current.lock()->position - last.lock()->position).norm(); int i = 0; for(auto n : possible_connections){ - SPTR_Node next_node = n->getNextNode(current); - float angle_v1_v2 = coming_from.norm().dot((next_node->position - current->position).norm()); + WPTR_Node next_node = n.lock()->getNextNode(current); + float angle_v1_v2 = coming_from.norm().dot((next_node.lock()->position - current.lock()->position).norm()); if(angle_v1_v2 > angle) { return_path = i; angle = angle_v1_v2; @@ -186,7 +196,7 @@ namespace VISEQ::GRAPH { } } - if(current->distributionMode == Distribution::ROUNDROBIN){ + if(current.lock()->distributionMode == Distribution::ROUNDROBIN){ if(counter.find(current) == counter.end()) { counter[current] = 0; } else { @@ -195,12 +205,11 @@ namespace VISEQ::GRAPH { } } - if(current->distributionMode == Distribution::RANDOM){ + if(current.lock()->distributionMode == Distribution::RANDOM){ return_path = rand() % possible_connections.size(); } - //possible_connections.at(return_path)->active = true; - return possible_connections.at(return_path)->getNextNode(current); + return possible_connections.at(return_path).lock()->getNextNode(current); } void splitEdge(SPTR_Edge edge){ @@ -209,10 +218,10 @@ namespace VISEQ::GRAPH { void splitEdges(){ for(auto s : split_edges){ - Vec2Df center = s->end->position.center(s->start->position); - SPTR_Node cn = copyNode(std::dynamic_pointer_cast(s->start), center); - addConnection(s->start, cn); - addConnection(cn, s->end); + Vec2Df center = s.lock()->end.lock()->position.center(s.lock()->start.lock()->position); + SPTR_Node cn = copyNode(std::dynamic_pointer_cast(s.lock()->start.lock()), center); + addConnection(s.lock()->start.lock(), cn); + addConnection(cn, s.lock()->end.lock()); remove_edges.push_back(s); } split_edges.clear(); @@ -224,40 +233,40 @@ namespace VISEQ::GRAPH { void removeEdges(){ for(auto edge : remove_edges){ - // edge->start->removeConnector(edge->start_conn); - // edge->end->removeConnector(edge->end_conn); - std::erase(edge->start->connections, edge); - std::erase(edge->end->connections, edge); - std::erase(edges, edge); + edge.lock()->start.lock()->removeConnector(edge.lock()->start_conn); + edge.lock()->end.lock()->removeConnector(edge.lock()->end_conn); + std::erase(edge.lock()->start.lock()->connections, edge.lock()); + std::erase(edge.lock()->end.lock()->connections, edge.lock()); + std::erase(edges, edge.lock()); } remove_edges.clear(); } - VEC_SPTR_Node getAdjacentNodes(VEC_SPTR_Node selected_nodes){ + VEC_WPTR_Node getAdjacentNodes(VEC_SPTR_Node selected_nodes){ for(auto n : nodes){ n->highlighted = false; } - auto erase_connections = edges | RANGE_FILTER([selected_nodes](SPTR_Edge c){ return std::ranges::contains(selected_nodes, c->start) || std::ranges::contains(selected_nodes, c->end);}); + auto erase_connections = edges | RANGE_FILTER([selected_nodes](SPTR_Edge c){ return std::ranges::contains(selected_nodes, c->start.lock()) || std::ranges::contains(selected_nodes, c->end.lock());}); - VEC_SPTR_Node adjacent_nodes; + VEC_WPTR_Node adjacent_nodes; for(auto c : erase_connections){ - if(!c->start->selected) adjacent_nodes.push_back(c->start); - if(!c->end->selected) adjacent_nodes.push_back(c->end); + if(!c->start.lock()->selected) adjacent_nodes.push_back(c->start); + if(!c->end.lock()->selected) adjacent_nodes.push_back(c->end); } return adjacent_nodes; } void removeNodesAndEdges(VEC_SPTR_Node selected_nodes){ - VEC_SPTR_Node adjacent_nodes = getAdjacentNodes(selected_nodes); + VEC_WPTR_Node adjacent_nodes = getAdjacentNodes(selected_nodes); for(auto n : adjacent_nodes){ - std::erase_if(n->connections, [n, selected_nodes](VISEQ::GRAPH::EDGES::SPTR_Edge c){ return std::ranges::contains(selected_nodes, c->start) || std::ranges::contains(selected_nodes, c->end);}); + std::erase_if(n.lock()->connections, [n, selected_nodes](VISEQ::GRAPH::EDGES::WPTR_Edge c){ return std::ranges::contains(selected_nodes, c.lock()->start.lock()) || std::ranges::contains(selected_nodes, c.lock()->end.lock());}); } for(auto n : selected_nodes){ - std::erase_if(this->edges, [n](SPTR_Edge c){ return c->start == n || c->end == n;}); + std::erase_if(this->edges, [n](WPTR_Edge c){ return c.lock()->start.lock() == n || c.lock()->end.lock() == n;}); } std::erase_if(this->nodes, [selected_nodes](SPTR_Node n){ return std::ranges::contains(selected_nodes, n);}); @@ -267,7 +276,7 @@ namespace VISEQ::GRAPH { VEC_SPTR_Edge copy_connections; for(auto c : edges){ - if(std::ranges::contains(nodes, c->start) && std::ranges::contains(nodes, c->end)) { + if(std::ranges::contains(nodes, c->start.lock()) && std::ranges::contains(nodes, c->end.lock())) { copy_connections.push_back(std::make_shared(*c)); } } @@ -288,13 +297,13 @@ namespace VISEQ::GRAPH { //TODO copy connectors for(auto c : copy_connections){ - if(c->start == old_node) { + if(c->start.lock() == old_node) { c->start = new_node; - c->start->connections.push_back(c); + c->start.lock()->connections.push_back(c); } - if(c->end == old_node) { + if(c->end.lock() == old_node) { c->end = new_node; - c->end->connections.push_back(c); + c->end.lock()->connections.push_back(c); } } } @@ -308,29 +317,29 @@ namespace VISEQ::GRAPH { void drawEdges(Vec2Df mouse_pos, Camera2D cam){ for(auto c : edges){ - Vec2Df v1_position = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->connector_offset); - Vec2Df v2_position = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->connector_offset); + Vec2Df v1_position = c->start.lock()->position - ((c->start.lock()->position - c->end.lock()->position)).norm() * (c->start.lock()->radius + c->connector_offset); + Vec2Df v2_position = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position)).norm() * (c->end.lock()->radius + c->connector_offset); float v1_v2_distance = v1_position.dist(&v2_position); - float midi_gate_v1 = Clamp((4.f / 1000.f) * std::dynamic_pointer_cast(c->start)->GGate(), 1.f, 4.f); - float midi_gate_v2 = Clamp((4.f / 1000.f) * std::dynamic_pointer_cast(c->end)->GGate(), 1.f, 4.f); + float midi_gate_v1 = Clamp((4.f / 1000.f) * std::dynamic_pointer_cast(c->start.lock())->GGate(), 1.f, 4.f); + float midi_gate_v2 = Clamp((4.f / 1000.f) * std::dynamic_pointer_cast(c->end.lock())->GGate(), 1.f, 4.f); // Line with small connector circles Color col = {229, 181, 103, 255}; if(c->GActive()) col = {108, 153, 187, 255}; DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, col); { - float d = c->start->position.dist(c->end->position); + float d = c->start.lock()->position.dist(c->end.lock()->position); std::string frac = MIDI::Fractions.at(std::clamp(round(d/60) - 1, 0, 31)); Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",d).c_str(), 10.0f, 2.0f); Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f); - Vec2Df middle_handle = c->start->position + (c->end->position - c->start->position) * ((d - text_length.x)*0.5f)/d; - Vec2Df middle_handle_frac = c->start->position + (c->end->position - c->start->position) * ((d - text_length_frac.x)*0.5f)/d; - Vec2Df text_position = middle_handle + (c->start->position - c->end->position).norm().orth() * 12.0f; - Vec2Df text_position_frac = middle_handle_frac - (c->start->position - c->end->position).norm().orth() * 4.0f; + Vec2Df middle_handle = c->start.lock()->position + (c->end.lock()->position - c->start.lock()->position) * ((d - text_length.x)*0.5f)/d; + Vec2Df middle_handle_frac = c->start.lock()->position + (c->end.lock()->position - c->start.lock()->position) * ((d - text_length_frac.x)*0.5f)/d; + Vec2Df text_position = middle_handle + (c->start.lock()->position - c->end.lock()->position).norm().orth() * 12.0f; + Vec2Df text_position_frac = middle_handle_frac - (c->start.lock()->position - c->end.lock()->position).norm().orth() * 4.0f; - float rotation = Vector2Angle((Vector2){1,0}, (c->end->position - c->start->position)) * RAD2DEG; + float rotation = Vector2Angle((Vector2){1,0}, (c->end.lock()->position - c->start.lock()->position)) * RAD2DEG; DrawTextPro(GetFontDefault(), std::format("{:.1f}",d).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); if( (int)d % 60 == 0) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK); } @@ -342,10 +351,10 @@ namespace VISEQ::GRAPH { DrawCircle(v2_position.x, v2_position.y, midi_gate_v2, col); if(v1_v2_distance < 100) c->switches_offset = v1_v2_distance/2.3f; - Vec2Df from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->switches_offset); - Vec2Df to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->switches_offset); - Vec2Df middle_handle = c->end->position - ((c->end->position - c->start->position))*0.4f; - Vec2Df middle_handle_2 = c->end->position - ((c->end->position - c->start->position))*0.6f; + Vec2Df from_to_handle = c->start.lock()->position - ((c->start.lock()->position - c->end.lock()->position)).norm() * (c->start.lock()->radius + c->switches_offset); + Vec2Df to_from_handle = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position)).norm() * (c->end.lock()->radius + c->switches_offset); + Vec2Df middle_handle = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position))*0.4f; + Vec2Df middle_handle_2 = c->end.lock()->position - ((c->end.lock()->position - c->start.lock()->position))*0.6f; Vec2Df flip_handle = middle_handle + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*0.2, 0.f, 20.f) : 1.0f); Vec2Df flip_handle_2 = middle_handle_2 + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*-0.2, -20.f, 0.f) : 1.0f); @@ -354,7 +363,7 @@ namespace VISEQ::GRAPH { unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f); unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f); - if(!c->start->picked_up && !c->end->picked_up){ + if(!c->start.lock()->picked_up && !c->end.lock()->picked_up){ // On/Off switches on both sides if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->pass_forward ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->pass_forward = !c->pass_forward; if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c->pass_backward ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c->pass_backward = !c->pass_backward; @@ -422,13 +431,13 @@ namespace VISEQ::GRAPH { } } + inline void to_json(json& j, const GraphManager& G){ + j = json{{"nodes", G.nodes}, {"edges", G.edges}}; + } + + inline void from_json(const json& j, GraphManager& G){ + j.at("nodes").template get_to(G.nodes); + } }; - inline void to_json(json& j, const GraphManager& G){ - j = json{{"nodes", G.nodes}, {"edges", G.edges}}; - } - - inline void from_json(const json& j, GraphManager& G){ - j.at("nodes").template get_to(G.nodes); // = json{{"nodes", G.nodes}, {"edges", G.edges}}; - } } diff --git a/src/interaction-manager.h b/src/interaction-manager.h index 9f80061..d31db40 100644 --- a/src/interaction-manager.h +++ b/src/interaction-manager.h @@ -7,10 +7,12 @@ #include "graph-item.h" #include "graph-manager.h" #include "interaction-event.h" +#include "node.h" #include "raylib.h" #include "signal-manager.h" #include "state.h" #include "canvas.h" +#include #include namespace VISEQ::INTERACTION{ @@ -64,7 +66,7 @@ namespace VISEQ::INTERACTION{ void update(){ if(KEYS_DOWN.ctrl && IsKeyPressed(KEY_C)){ - VEC_SPTR_Node selected_nodes = gm->getSelection(); + VEC_WPTR_Node selected_nodes = gm->getSelection(); if(!selected_nodes.empty()) cb.pushNodes(selected_nodes); } diff --git a/src/node.h b/src/node.h index 015c134..063468b 100644 --- a/src/node.h +++ b/src/node.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -26,16 +27,6 @@ namespace VISEQ::GRAPH::NODES { Node(float x, float y) : Draggable(Vec2Df(x, y)) {} Node(Vec2Df p) : Draggable(p) {} - /*Node(const Node& n){*/ - /* distributionMode = n.distributionMode;*/ - /* radius = n.radius;*/ - /* config = n.config;*/ - /* position = n.position;*/ - /* for(auto c : n.connectors){*/ - /* connectors.emplace_back(std::make_shared(*c));*/ - /* }*/ - /*}*/ - NodeType nodeType; std::vector> neighbors; @@ -54,15 +45,10 @@ namespace VISEQ::GRAPH::NODES { void addConnector() { connectors.emplace_back(std::make_shared(GraphItem::getptr(), position, radius + 5.0f)); - connectors.back()->init(); } - void removeConnector(std::shared_ptr connector){ - std::erase(connectors, connector); - } - - void init() { - addConnector(); + void removeConnector(std::weak_ptr connector){ + std::erase(connectors, connector.lock()); } virtual NodeType getNodeType() const {return nodeType;} @@ -87,7 +73,7 @@ namespace VISEQ::GRAPH::NODES { int free_connectors = 0; for(auto c : connectors){ - if(!c->partner) free_connectors++; + if(c->partner.expired()) free_connectors++; c->setPosition(position); c->update(); } @@ -105,6 +91,7 @@ namespace VISEQ::GRAPH::NODES { }; typedef std::shared_ptr SPTR_Node; + typedef std::weak_ptr WPTR_Node; typedef std::vector VEC_SPTR_Node; - + typedef std::vector VEC_WPTR_Node; } diff --git a/src/signal-manager.h b/src/signal-manager.h index d92d134..733f582 100644 --- a/src/signal-manager.h +++ b/src/signal-manager.h @@ -55,7 +55,7 @@ namespace VISEQ::SIGNAL { void reset(){ for(auto &s : signals){ - s->position = s->start->position + Vec2Df{0.1, 0.1}; + s->position = s->start.lock()->position + Vec2Df{0.1, 0.1}; s->next = s->start; s->last = s->start; } @@ -71,16 +71,16 @@ namespace VISEQ::SIGNAL { loop = false; } - void addSignalAtNode(SPTR_Node node){ + void addSignalAtNode(WPTR_Node node){ Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200}; - signals.emplace_back(std::make_shared(node->position + Vec2Df{0.5f, 0.5f}, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea! + signals.emplace_back(std::make_shared(node.lock()->position + Vec2Df{0.5f, 0.5f}, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea! signals.back()->next = node; signals.back()->last = node; signals.back()->start = node; } void rerouteSignal(VEC_SPTR_Node nodes, VEC_SPTR_Node adjacent_nodes){ - auto reroute_signals = signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->next);}); + auto reroute_signals = signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->next.lock());}); for(auto s : reroute_signals){ float dist = 10000000; @@ -98,7 +98,7 @@ namespace VISEQ::SIGNAL { } void rebaseSignal(VEC_SPTR_Node nodes){ - auto rebase_signals = signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->start);}); + auto rebase_signals = signals | RANGE_FILTER([nodes](SIGNAL::SPTR_Signal s){return std::ranges::contains(nodes, s->start.lock());}); for(auto s : rebase_signals){ s->start = s->next; @@ -117,14 +117,14 @@ namespace VISEQ::SIGNAL { mutex->lock(); if(play){ for(auto& s : signals){ - s->direction = (s->next->position - s->position).norm(); + s->direction = (s->next.lock()->position - s->position).norm(); s->update(diff.count()); - if(s->position.dist(s->next->position) < 0.6f) { - SPTR_Node next_node = gm->next(s->next, s->last); - s->next->trigger(); + if(s->position.dist(s->next.lock()->position) < 0.6f) { + WPTR_Node next_node = gm->next(s->next, s->last); + s->next.lock()->trigger(); - if(next_node != s->next && next_node != SPTR_Node(nullptr) && s->next->getNodeType() == NodeType::MIDINODE) { - auto midinode = std::dynamic_pointer_cast(s->next); + if(next_node.lock() != s->next.lock() && !next_node.expired() && s->next.lock()->getNodeType() == NodeType::MIDINODE) { + auto midinode = std::dynamic_pointer_cast(s->next.lock()); for(auto &m : midinode->midi_outs){ if(m.second.enabled) { if(midinode->send_note) midi.note(m.second.i, midinode->midi_note_channel, (int)Clamp(midinode->midi_note + s->midi_note_offset, 0, 127), midinode->midi_velocity, midinode->midi_gate); diff --git a/src/signal.h b/src/signal.h index d23bcb7..5582a97 100644 --- a/src/signal.h +++ b/src/signal.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "moveable.h" #include "node.h" @@ -15,11 +16,11 @@ namespace VISEQ::SIGNAL { Signal() {} Signal(Vec2Df position, float r, float _speed, Color color) : Movable(position, Vec2Df(0,0), _speed), radius(r), color(color) {} - NODES::SPTR_Node next; - NODES::SPTR_Node last; - EDGES::SPTR_Edge edge; + NODES::WPTR_Node next; + NODES::WPTR_Node last; + EDGES::WPTR_Edge edge; - NODES::SPTR_Node start; + NODES::WPTR_Node start; bool at_target = false; bool run = true; @@ -34,6 +35,14 @@ namespace VISEQ::SIGNAL { int midi_note_offset = 0; int midi_cc_offset = 0; + + void reset(){ + toStart(); + } + + void toStart(){ + position = start.lock()->position; + } void update(double t_delta){ // 120px / 16th = 1920px / whole note diff --git a/src/state-io.h b/src/state-io.h index e009102..de93399 100644 --- a/src/state-io.h +++ b/src/state-io.h @@ -24,7 +24,7 @@ namespace VISEQ::GRAPH::EDGES { using namespace VISEQ::GRAPH::NODES; inline void to_json(json& j, const VISEQ::GRAPH::EDGES::Edge& E){ - j = json{{"id",E.id}, {"start", E.start->id}, {"end",E.end->id}, {"pass_forward",E.pass_forward}, {"pass_backward", E.pass_backward}}; + j = json{{"id",E.id}, {"start", E.start.lock()->id}, {"end",E.end.lock()->id}, {"pass_forward",E.pass_forward}, {"pass_backward", E.pass_backward}}; } inline void from_json(const json& j, Edge& E){ @@ -167,7 +167,7 @@ namespace VISEQ::BASE{ namespace VISEQ::SIGNAL{ inline void to_json(json& j, const Signal& G){ std::map fc = {{"r",G.color.r},{"g",G.color.g},{"b",G.color.b},{"a",G.color.a}}; - j = json{{"color",fc},{"position", G.position},{"radius",G.radius},{"start",G.start->id},{"next",G.next->id},{"last",G.last->id},{"speed",G.speed},{"midi_note_offset",G.midi_note_offset},{"midi_cc_offset",G.midi_cc_offset},{"multiplier",G.multiplier}}; + j = json{{"color",fc},{"position", G.position},{"radius",G.radius},{"start",G.start.lock()->id},{"next",G.next.lock()->id},{"last",G.last.lock()->id},{"speed",G.speed},{"midi_note_offset",G.midi_note_offset},{"midi_cc_offset",G.midi_cc_offset},{"multiplier",G.multiplier}}; } inline void from_json(const json& j, Signal& S){