2024-10-30 14:55:24 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
2024-11-01 14:08:27 +01:00
|
|
|
|
2024-10-30 14:55:24 +01:00
|
|
|
#include "datatypes.h"
|
2024-11-01 14:08:27 +01:00
|
|
|
#include "raylib.h"
|
|
|
|
|
#include "raymath.h"
|
|
|
|
|
|
2024-11-02 15:52:16 +01:00
|
|
|
#include "nlohmann/json.hpp"
|
|
|
|
|
|
2024-11-01 14:08:27 +01:00
|
|
|
#include "button.h"
|
2024-11-02 23:12:38 +01:00
|
|
|
#include "midi-node.h"
|
2024-10-31 01:43:00 +01:00
|
|
|
#include "edge.h"
|
2024-11-03 03:48:49 +01:00
|
|
|
#include "node.h"
|
2024-11-01 14:08:27 +01:00
|
|
|
|
2024-10-31 01:43:00 +01:00
|
|
|
#include <algorithm>
|
2024-11-01 14:08:27 +01:00
|
|
|
#include <cstdio>
|
2024-11-02 02:06:26 +01:00
|
|
|
#include <iostream>
|
2024-10-31 01:43:00 +01:00
|
|
|
#include <iterator>
|
2024-10-30 14:55:24 +01:00
|
|
|
#include <map>
|
2024-10-31 01:43:00 +01:00
|
|
|
#include <memory>
|
2024-10-30 14:55:24 +01:00
|
|
|
#include <random>
|
|
|
|
|
#include <ranges>
|
2024-10-31 01:43:00 +01:00
|
|
|
#include <vector>
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-02 23:12:38 +01:00
|
|
|
#include "state-io.h"
|
|
|
|
|
|
2024-11-02 15:52:16 +01:00
|
|
|
using json = nlohmann::json;
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
using namespace VISEQ::GRAPH::NODES;
|
|
|
|
|
using namespace VISEQ::GRAPH::EDGES;
|
2024-11-02 23:12:38 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
namespace VISEQ::GRAPH {
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
class GraphManager{
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
public:
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
GraphManager() {}
|
2024-11-01 14:08:27 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
NODES::VEC_SPTR_Node nodes;
|
|
|
|
|
EDGES::VEC_SPTR_Edge edges;
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
EDGES::VEC_SPTR_Edge remove_edges;
|
|
|
|
|
EDGES::VEC_SPTR_Edge split_edges;
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
std::map<NODES::SPTR_Node, int> counter;
|
2024-11-02 15:52:16 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
NODES::SPTR_Node getRandomNode(){
|
|
|
|
|
VEC_SPTR_GraphItem o;
|
|
|
|
|
std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
|
|
|
|
return std::dynamic_pointer_cast<VISEQ::GRAPH::NODES::Node>(o.front());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EDGES::SPTR_Edge getRandomEdge(){
|
|
|
|
|
VEC_SPTR_GraphItem o;
|
|
|
|
|
std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
|
|
|
|
return std::dynamic_pointer_cast<VISEQ::GRAPH::EDGES::Edge>(o.front());
|
|
|
|
|
}
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void copyNodes(VEC_SPTR_Node _nodes, Vec2Df position){
|
|
|
|
|
for(auto n: _nodes){
|
|
|
|
|
nodes.insert(nodes.end(), std::make_shared<Node>(*n));
|
|
|
|
|
nodes.back()->setPosition(position + nodes.back()->drag_offset);
|
|
|
|
|
nodes.back()->selected = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void copyNodes(std::vector<std::shared_ptr<MidiNode>> _nodes, Vec2Df position){
|
|
|
|
|
for(auto n: _nodes){
|
|
|
|
|
nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));
|
|
|
|
|
nodes.back()->setPosition(position + nodes.back()->drag_offset);
|
|
|
|
|
nodes.back()->selected = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SPTR_Node copyNode(SPTR_Node n, Vec2Df position){
|
|
|
|
|
std::cout << "copy basenode" << std::endl;
|
2024-11-02 02:06:26 +01:00
|
|
|
nodes.insert(nodes.end(), std::make_shared<Node>(*n));
|
2024-11-03 03:48:49 +01:00
|
|
|
nodes.back()->setPosition(position);
|
|
|
|
|
return nodes.back();
|
2024-10-30 14:55:24 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
SPTR_Node copyNode(std::shared_ptr<MidiNode> n, Vec2Df position){
|
|
|
|
|
std::cout << "copy midinode" << std::endl;
|
2024-11-02 02:06:26 +01:00
|
|
|
nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));
|
2024-11-03 03:48:49 +01:00
|
|
|
nodes.back()->setPosition(position);
|
|
|
|
|
return nodes.back();
|
2024-11-01 02:38:47 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
SPTR_Node addMidiNode(Vec2Df position){
|
|
|
|
|
nodes.emplace_back(std::make_shared<MidiNode>(position));
|
|
|
|
|
return nodes.back();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setNodeMode(int mode){
|
|
|
|
|
for(auto n: nodes){
|
|
|
|
|
n->SMode(mode);
|
|
|
|
|
}
|
2024-10-31 01:43:00 +01:00
|
|
|
}
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void reset(){
|
|
|
|
|
counter.clear();
|
|
|
|
|
}
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
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<VEC_SPTR_Edge>();
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
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();
|
|
|
|
|
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());
|
|
|
|
|
if(angle_v1_v2 > angle) {
|
|
|
|
|
return_path = i;
|
|
|
|
|
angle = angle_v1_v2;
|
|
|
|
|
}
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(current->distributionMode == Distribution::ROUNDROBIN){
|
|
|
|
|
if(counter.find(current) == counter.end()) {
|
|
|
|
|
counter[current] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
counter[current] = (counter[current] + 1) % possible_connections.size();
|
|
|
|
|
return_path = counter[current];
|
2024-10-30 14:55:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
if(current->distributionMode == Distribution::RANDOM){
|
|
|
|
|
return_path = rand() % possible_connections.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//possible_connections.at(return_path)->active = true;
|
|
|
|
|
return possible_connections.at(return_path)->getNextNode(current);
|
2024-10-30 14:55:24 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-04 09:53:08 +01:00
|
|
|
SPTR_Node getClosestNode(Vec2Df position){
|
2024-11-10 01:56:33 +01:00
|
|
|
auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->picked_up;}) | std::ranges::to<VEC_SPTR_Node>();
|
2024-11-04 09:53:08 +01:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void addConnection(SPTR_Node from, SPTR_Node to){
|
|
|
|
|
if(from != to) {
|
|
|
|
|
edges.emplace_back(std::make_shared<Edge>());
|
|
|
|
|
edges.back()->start = from;
|
|
|
|
|
edges.back()->end = to;
|
|
|
|
|
from->connections.push_back(edges.back());
|
|
|
|
|
to->connections.push_back(edges.back());
|
2024-10-30 14:55:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
void splitEdge(SPTR_Edge edge){
|
|
|
|
|
split_edges.push_back(edge);
|
2024-10-30 14:55:24 +01:00
|
|
|
}
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
void splitEdges(){
|
|
|
|
|
for(auto s : split_edges){
|
|
|
|
|
Vec2Df center = s->end->position.center(s->start->position);
|
2024-11-04 01:00:59 +01:00
|
|
|
SPTR_Node cn = copyNode(std::dynamic_pointer_cast<MidiNode>(s->start), center);
|
2024-11-03 03:48:49 +01:00
|
|
|
addConnection(s->start, cn);
|
|
|
|
|
addConnection(cn, s->end);
|
|
|
|
|
remove_edges.push_back(s);
|
|
|
|
|
}
|
|
|
|
|
split_edges.clear();
|
2024-11-02 02:06:26 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
void removeEdge(SPTR_Edge edge){
|
|
|
|
|
remove_edges.push_back(edge);
|
2024-11-02 02:06:26 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
void removeEdges(){
|
|
|
|
|
for(auto edge : remove_edges){
|
|
|
|
|
std::erase(edge->start->connections, edge);
|
|
|
|
|
std::erase(edge->end->connections, edge);
|
|
|
|
|
std::erase(edges, edge);
|
|
|
|
|
}
|
|
|
|
|
remove_edges.clear();
|
2024-11-01 14:08:27 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
void drawEdges(Vec2Df mouse_pos, Camera2D cam){
|
|
|
|
|
if(!remove_edges.empty()) removeEdges();
|
|
|
|
|
if(!split_edges.empty()) splitEdges();
|
|
|
|
|
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);
|
|
|
|
|
float v1_v2_distance = v1_position.dist(&v2_position);
|
|
|
|
|
|
|
|
|
|
float midi_gate_v1 = Clamp((4.f / 1000.f) * c->start->GGate(), 1.f, 4.f);
|
|
|
|
|
float midi_gate_v2 = Clamp((4.f / 1000.f) * c->end->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);
|
2024-11-06 15:35:25 +01:00
|
|
|
{
|
|
|
|
|
float d = c->start->position.dist(c->end->position);
|
|
|
|
|
std::string frac = MIDI::Fractions.at(std::clamp<int>(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;
|
|
|
|
|
|
|
|
|
|
float rotation = Vector2Angle((Vector2){1,0}, (c->end->position - c->start->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);
|
|
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
if(midi_gate_v1 == 4.0f) col = VS_COLOR_RED;
|
|
|
|
|
DrawCircle(v1_position.x, v1_position.y, midi_gate_v1, col);
|
|
|
|
|
|
|
|
|
|
col = {229, 181, 103, 255};
|
|
|
|
|
if(midi_gate_v2 == 4.0f) col = VS_COLOR_RED;
|
|
|
|
|
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 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);
|
2024-10-31 01:43:00 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
// Dynamic opacity by distance to mouse
|
|
|
|
|
unsigned char opacity = 150.0f - Clamp(middle_handle.dist(mouse_pos), 0.0f, 150.0f);
|
|
|
|
|
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);
|
2024-10-31 01:43:00 +01:00
|
|
|
|
2024-11-10 01:56:33 +01:00
|
|
|
if(!c->start->picked_up && !c->end->picked_up){
|
2024-11-03 03:48:49 +01:00
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
|
if(!c->pass_forward){
|
|
|
|
|
Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle;
|
|
|
|
|
Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle;
|
|
|
|
|
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!c->pass_backward){
|
|
|
|
|
Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle;
|
|
|
|
|
Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle;
|
|
|
|
|
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_to});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ViButton(mouse_pos, flip_handle.x, flip_handle.y, 8.0f, (Color){232, 50, 32, opacity} )) removeEdge(c);
|
|
|
|
|
if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 125, 62, opacity} )) splitEdge(c);
|
2024-11-01 14:08:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-10-30 14:55:24 +01:00
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
|
|
|
|
|
void drawNodes(Vec2Df mouse_pos, Camera2D camera){
|
|
|
|
|
float min_d = 480;
|
|
|
|
|
for(auto n : nodes){
|
2024-11-10 01:56:33 +01:00
|
|
|
n->update();
|
|
|
|
|
if(n->picked_up){
|
|
|
|
|
auto neighbors_local = nodes | RANGE_FILTER([mouse_pos](SPTR_Node n){ return !n->picked_up && !n->selected && n->position.dist(mouse_pos) < 960;}) | std::ranges::to<VEC_SPTR_Node>();
|
2024-11-06 02:28:37 +01:00
|
|
|
std::sort(neighbors_local.begin(), neighbors_local.end(), [n, mouse_pos](SPTR_Node na, SPTR_Node nb){ return na->position.dist(mouse_pos) < nb->position.dist(mouse_pos);});
|
|
|
|
|
if(!neighbors_local.empty()){
|
|
|
|
|
min_d = neighbors_local.front()->position.dist(mouse_pos);
|
|
|
|
|
DrawCircleLinesV(neighbors_local.front()->position, 22.0f, VS_COLOR_PINK);
|
|
|
|
|
n->neighbors = neighbors_local | std::ranges::views::filter([mouse_pos, min_d](SPTR_Node n){return abs(n->position.dist(mouse_pos) - min_d) < 5;}) | std::ranges::to<VEC_SPTR_Node>();
|
|
|
|
|
for(auto nb : n->neighbors){
|
|
|
|
|
DrawCircleLinesV(nb->position, 20.0f, VS_COLOR_RED);
|
2024-11-03 03:48:49 +01:00
|
|
|
float d = nb->position.dist(mouse_pos);
|
|
|
|
|
float dn = nb->position.dist(n->position);
|
|
|
|
|
if(d > 0 && d < min_d*1.5 && d < 960) {
|
2024-11-06 02:28:37 +01:00
|
|
|
std::string frac = MIDI::Fractions.at(std::clamp<int>(round(dn/60) - 1, 0, 31));
|
2024-11-03 03:48:49 +01:00
|
|
|
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",dn).c_str(), 10.0f, 2.0f);
|
|
|
|
|
Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f);
|
|
|
|
|
|
|
|
|
|
Vec2Df middle_handle = nb->position + (n->position - nb->position) * ((dn - text_length.x)*0.5f)/dn;
|
|
|
|
|
Vec2Df middle_handle_frac = nb->position + (n->position - nb->position) * ((dn - text_length_frac.x)*0.5f)/dn;
|
|
|
|
|
Vec2Df text_position = middle_handle + (nb->position - n->position).norm().orth() * 12.0f;
|
|
|
|
|
Vec2Df text_position_frac = middle_handle_frac - (nb->position - n->position).norm().orth() * 4.0f;
|
|
|
|
|
|
|
|
|
|
float rotation = Vector2Angle((Vector2){1,0}, (n->position - nb->position)) * RAD2DEG;
|
|
|
|
|
DrawTextPro(GetFontDefault(), std::format("{:.1f}",dn).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
|
2024-11-06 02:28:37 +01:00
|
|
|
if(IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
|
2024-11-03 03:48:49 +01:00
|
|
|
Vec2Df n_position = n->position - ((n->position - nb->position)).norm() * 20.0f;
|
|
|
|
|
Vec2Df nb_position = nb->position - ((nb->position - n->position)).norm() * 20.0f;
|
|
|
|
|
DrawLineV(n_position, nb_position, VS_COLOR_PINK);
|
|
|
|
|
}
|
2024-10-30 14:55:24 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-03 03:48:49 +01:00
|
|
|
n->draw(mouse_pos, camera);
|
2024-10-30 14:55:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
};
|
2024-10-30 14:55:24 +01:00
|
|
|
|
2024-11-03 03:48:49 +01:00
|
|
|
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){
|
2024-11-03 15:15:42 +01:00
|
|
|
j.at("nodes").template get_to<VEC_SPTR_Node>(G.nodes); // = json{{"nodes", G.nodes}, {"edges", G.edges}};
|
2024-11-03 03:48:49 +01:00
|
|
|
}
|
|
|
|
|
}
|