node deletion with connection deletion and signal redistribution implemented
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
CXX = g++
|
CXX = g++
|
||||||
CXXFLAGS = -std=c++20 -Wall -g -fno-omit-frame-pointer -gdwarf-4 -Og -Wnarrowing -DLIBREMIDI_ALSA=1
|
CXXFLAGS = -std=c++23 -Wall -g -fno-omit-frame-pointer -gdwarf-4 -Og -Wnarrowing -DLIBREMIDI_ALSA=1
|
||||||
CXXINC = -Iinclude
|
CXXINC = -Iinclude
|
||||||
|
|
||||||
LDLIBS = -lraylib -lasound -pthread
|
LDLIBS = -lraylib -lasound -pthread
|
||||||
|
|||||||
+14
-11
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
|
#include "node-manager.h"
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -9,40 +10,42 @@ class ConnectionManager{
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ConnectionManager() {}
|
ConnectionManager(NodeManager *nm) : nm(nm) {}
|
||||||
|
|
||||||
|
NodeManager *nm;
|
||||||
|
|
||||||
std::vector<Connection> connections;
|
std::vector<Connection> connections;
|
||||||
|
|
||||||
std::map<Node*, int> counter;
|
std::map<int, int> counter;
|
||||||
|
|
||||||
void reset(){
|
void reset(){
|
||||||
counter.clear();
|
counter.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* next(Node* current, Node* last){
|
int next(int current, int last){
|
||||||
std::vector<Connection*> paths;
|
std::vector<Connection*> paths;
|
||||||
std::vector<Node*> nodes;
|
std::vector<int> node_ids;
|
||||||
|
|
||||||
for(auto& p : connections){
|
for(auto& p : connections){
|
||||||
if((p.v1 == current && p.v1_v2) || (p.v2 == current && p.v2_v1)) {
|
if((p.v1 == current && p.v1_v2) || (p.v2 == current && p.v2_v1)) {
|
||||||
p.active = false;
|
p.active = false;
|
||||||
paths.push_back(&p);
|
paths.push_back(&p);
|
||||||
nodes.push_back( p.v1 == current ? p.v2 : p.v1 );
|
node_ids.push_back( p.v1 == current ? p.v2 : p.v1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(paths.size() == 2) {
|
if(paths.size() == 2) {
|
||||||
Node* next = nodes[0] == last ? nodes[1] : nodes[0];
|
int next = node_ids[0] == last ? node_ids[1] : node_ids[0];
|
||||||
if(paths[0]->v1 == next || paths[0]->v2 == next) paths[0]->active = true;
|
if(paths[0]->v1 == next || paths[0]->v2 == next) paths[0]->active = true;
|
||||||
if(paths[1]->v1 == next || paths[1]->v2 == next) paths[1]->active = true;
|
if(paths[1]->v1 == next || paths[1]->v2 == next) paths[1]->active = true;
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(paths.empty()) return nullptr;
|
if(paths.empty()) return -1;
|
||||||
|
|
||||||
int return_path = 0;
|
int return_path = 0;
|
||||||
|
|
||||||
if(current->mode == Distribution::ROUNDROBIN){
|
if(nm->nodes.at(current).mode == Distribution::ROUNDROBIN){
|
||||||
if(counter.find(current) == counter.end()) {
|
if(counter.find(current) == counter.end()) {
|
||||||
counter[current] = 0;
|
counter[current] = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -50,15 +53,15 @@ class ConnectionManager{
|
|||||||
return_path = counter[current];
|
return_path = counter[current];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(current->mode == Distribution::RANDOM){
|
if(nm->nodes.at(current).mode == Distribution::RANDOM){
|
||||||
return_path = rand() % paths.size();
|
return_path = rand() % paths.size();
|
||||||
}
|
}
|
||||||
paths.at(return_path)->active = true;
|
paths.at(return_path)->active = true;
|
||||||
return paths.at(return_path)->v1 == current ? paths.at(return_path)->v2 : paths.at(return_path)->v1;
|
return paths.at(return_path)->v1 == current ? paths.at(return_path)->v2 : paths.at(return_path)->v1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConnection(Node *from, Node *to){
|
void addConnection(int from, int to){
|
||||||
connections.emplace_back(from, to);
|
connections.emplace_back(&nm->nodes, from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
||||||
|
|||||||
+12
-11
@@ -7,11 +7,12 @@
|
|||||||
class Connection{
|
class Connection{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Connection() {}
|
Connection(std::map<int, Node> *nodes, int v1, int v2) : v1(v1), v2(v2), nodes(nodes) {}
|
||||||
Connection(Node* v1, Node* v2) : v1(v1), v2(v2) {}
|
|
||||||
|
|
||||||
Node* v1;
|
int v1;
|
||||||
Node* v2;
|
int v2;
|
||||||
|
|
||||||
|
std::map<int, Node> *nodes;
|
||||||
|
|
||||||
bool v1_v2 = true;
|
bool v1_v2 = true;
|
||||||
bool v2_v1 = true;
|
bool v2_v1 = true;
|
||||||
@@ -23,14 +24,14 @@ class Connection{
|
|||||||
float switches_offset = 25.0f;
|
float switches_offset = 25.0f;
|
||||||
|
|
||||||
void flip(){
|
void flip(){
|
||||||
Node* vt = v1;
|
int vt = v1;
|
||||||
v1 = v2;
|
v1 = v2;
|
||||||
v2 = vt;
|
v2 = vt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Vec2D<float> *mouse_pos, Camera2D *cam){
|
void draw(Vec2D<float> *mouse_pos, Camera2D *cam){
|
||||||
Vec2D<float> v1_position = v1->position - ((v1->position - v2->position)).norm() * (v1->radius + connector_offset);
|
Vec2D<float> v1_position = nodes->at(v1).position - ((nodes->at(v1).position - nodes->at(v2).position)).norm() * (nodes->at(v1).radius + connector_offset);
|
||||||
Vec2D<float> v2_position = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + connector_offset);
|
Vec2D<float> v2_position = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position)).norm() * (nodes->at(v2).radius + connector_offset);
|
||||||
float v1_v2_distance = v1_position.dist(&v2_position);
|
float v1_v2_distance = v1_position.dist(&v2_position);
|
||||||
|
|
||||||
// Line with small connector circles
|
// Line with small connector circles
|
||||||
@@ -41,10 +42,10 @@ class Connection{
|
|||||||
DrawCircle(v2_position.x, v2_position.y, 2.0f, c);
|
DrawCircle(v2_position.x, v2_position.y, 2.0f, c);
|
||||||
|
|
||||||
if(v1_v2_distance < 100) switches_offset = v1_v2_distance/2.3f;
|
if(v1_v2_distance < 100) switches_offset = v1_v2_distance/2.3f;
|
||||||
Vec2D<float> from_to_handle = v1->position - ((v1->position - v2->position)).norm() * (v1->radius + switches_offset);
|
Vec2D<float> from_to_handle = nodes->at(v1).position - ((nodes->at(v1).position - nodes->at(v2).position)).norm() * (nodes->at(v1).radius + switches_offset);
|
||||||
Vec2D<float> to_from_handle = v2->position - ((v2->position - v1->position)).norm() * (v2->radius + switches_offset);
|
Vec2D<float> to_from_handle = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position)).norm() * (nodes->at(v2).radius + switches_offset);
|
||||||
Vec2D<float> middle_handle = v2->position - ((v2->position - v1->position))*0.5f;
|
Vec2D<float> middle_handle = nodes->at(v2).position - ((nodes->at(v2).position - nodes->at(v1).position))*0.5f;
|
||||||
// Vec2D<float> config_handle = v2->position - ((v2->position - v1->position))*0.66f;
|
// Vec2D<float> config_handle = nodes.at(v2)->position - ((nodes.at(v2)->position - nodes.at(v1)->position))*0.66f;
|
||||||
Vec2D<float> 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);
|
Vec2D<float> 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);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+18
-18
@@ -50,7 +50,7 @@ int main(){
|
|||||||
|
|
||||||
app.ui.init();
|
app.ui.init();
|
||||||
|
|
||||||
int monitor = 0; //GetCurrentMonitor();
|
int monitor = 1; //GetCurrentMonitor();
|
||||||
|
|
||||||
SetWindowMonitor(monitor);
|
SetWindowMonitor(monitor);
|
||||||
|
|
||||||
@@ -83,10 +83,10 @@ int main(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 8; ++i){
|
for(int i = 0; i < 8; ++i){
|
||||||
app.cm.addConnection(&app.nm.nodes[i], &app.nm.nodes[(i+1) % 8]);
|
app.cm.addConnection(app.nm.nodes[i].id, app.nm.nodes[(i+1) % 8].id);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.sm.addSignalAtNode(&app.nm.nodes.front());
|
app.sm.addSignalAtNode((app.nm.nodes | std::views::values).front().id);
|
||||||
|
|
||||||
app.sm.startSignalThread();
|
app.sm.startSignalThread();
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ int main(){
|
|||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground((Color){46,46,46});
|
ClearBackground((Color){46,46,46});
|
||||||
BeginMode2D(camera);
|
BeginMode2D(camera);
|
||||||
//app.settings.mutex.lock();
|
|
||||||
app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f);
|
app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f);
|
||||||
|
|
||||||
Vector2 mp = GetScreenToWorld2D(GetMousePosition(), camera);
|
Vector2 mp = GetScreenToWorld2D(GetMousePosition(), camera);
|
||||||
@@ -128,11 +128,11 @@ int main(){
|
|||||||
Vec2D<float> mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
|
Vec2D<float> mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
|
||||||
Vec2D<float> delta = mouse_delta * (-1.0f/camera.zoom);
|
Vec2D<float> delta = mouse_delta * (-1.0f/camera.zoom);
|
||||||
|
|
||||||
auto dragging_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.dragging;});
|
auto dragging_nodes = app.nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n) { return n.dragging;});
|
||||||
auto connecting_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.connecting;});
|
auto connecting_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.connecting;});
|
||||||
auto selected_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;});
|
auto selected_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;});
|
||||||
auto hovering_nodes = app.nm.nodes | std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, n.position, n.radius);});
|
auto hovering_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, n.position, n.radius);});
|
||||||
auto hovering_connectors = app.nm.nodes | std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, (n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f)), 8.0f);});
|
auto hovering_connectors = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, (n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f)), 8.0f);});
|
||||||
|
|
||||||
if(!mouse_down && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::HOVER_CANVAS;
|
if(!mouse_down && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::HOVER_CANVAS;
|
||||||
if((mouse_clicked || mouse_down || mouse_released) && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::DRAW_SELECTION;
|
if((mouse_clicked || mouse_down || mouse_released) && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::DRAW_SELECTION;
|
||||||
@@ -163,7 +163,7 @@ int main(){
|
|||||||
DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});
|
DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});
|
||||||
selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};
|
selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};
|
||||||
|
|
||||||
for(auto& n : app.nm.nodes){
|
for(auto& n : app.nm.nodes | std::views::values){
|
||||||
if(CheckCollisionPointRec(n.position, selection)) {
|
if(CheckCollisionPointRec(n.position, selection)) {
|
||||||
n.in_rect = true;
|
n.in_rect = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -173,7 +173,7 @@ int main(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(mouse_released){
|
if(mouse_released){
|
||||||
for(auto& n : app.nm.nodes){
|
for(auto& n : app.nm.nodes | std::views::values){
|
||||||
if(CheckCollisionPointRec(n.position, selection)) {
|
if(CheckCollisionPointRec(n.position, selection)) {
|
||||||
n.selected = true;
|
n.selected = true;
|
||||||
n.in_rect = false;
|
n.in_rect = false;
|
||||||
@@ -236,24 +236,25 @@ int main(){
|
|||||||
if(mouse_released) {
|
if(mouse_released) {
|
||||||
if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){
|
if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){
|
||||||
if(!hovering_nodes.empty()){
|
if(!hovering_nodes.empty()){
|
||||||
app.cm.addConnection(&connecting_nodes.front(), &hovering_nodes.front());
|
app.cm.addConnection(connecting_nodes.front().id, hovering_nodes.front().id);
|
||||||
} else if(!hovering_connectors.empty()){
|
} else if(!hovering_connectors.empty()){
|
||||||
app.cm.addConnection(&connecting_nodes.front(), &hovering_connectors.front());
|
app.cm.addConnection(connecting_nodes.front().id, hovering_connectors.front().id);
|
||||||
} else {
|
} else {
|
||||||
app.nm.addNode(mouse_pos.x, mouse_pos.y);
|
int id = app.nm.addNode(mouse_pos.x, mouse_pos.y);
|
||||||
app.cm.addConnection(&connecting_nodes.front(), &app.nm.nodes.back());
|
app.cm.addConnection(connecting_nodes.front().id, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
connecting_nodes.front().connecting = false;
|
connecting_nodes.front().connecting = false;
|
||||||
|
istate = InteractionState::HOVER_CANVAS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InteractionState::DELETE_SELECTED_NODES:
|
case InteractionState::DELETE_SELECTED_NODES:
|
||||||
{
|
{
|
||||||
for(auto &n : app.nm.nodes){
|
for(auto &n : selected_nodes){
|
||||||
n.erase = true;
|
n.erase = true;
|
||||||
}
|
}
|
||||||
app.nm.removeNodes();
|
app.removeNodes();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -280,7 +281,6 @@ int main(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
app.draw(&mouse_pos, &camera);
|
app.draw(&mouse_pos, &camera);
|
||||||
|
|
||||||
EndMode2D();
|
EndMode2D();
|
||||||
|
|||||||
+21
-13
@@ -1,31 +1,39 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include <iterator>
|
||||||
|
#include <random>
|
||||||
|
#include <ranges>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class NodeManager{
|
class NodeManager{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NodeManager() {
|
NodeManager() {}
|
||||||
nodes.reserve(1000);
|
|
||||||
|
std::map<int, Node> nodes;
|
||||||
|
std::vector<int> keys;
|
||||||
|
int iterator = 0;
|
||||||
|
|
||||||
|
int getRandomNode(){
|
||||||
|
std::vector<int> o;
|
||||||
|
std::ranges::sample(keys, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
||||||
|
return o.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Node> nodes;
|
int addNode(float x, float y){
|
||||||
|
return addNode(Vec2D<float>(x,y));
|
||||||
void addNode(float x, float y){
|
|
||||||
addNode(Vec2D<float>(x,y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addNode(Vec2D<float> position){
|
int addNode(Vec2D<float> position){
|
||||||
nodes.emplace_back(position, 15.0f);
|
nodes.emplace(std::make_pair(iterator, Node(iterator, position, 15.0f)));
|
||||||
}
|
keys.push_back(iterator);
|
||||||
|
iterator++;
|
||||||
void removeNodes(){
|
return iterator - 1;
|
||||||
std::erase_if(nodes, [](Node n){ return n.erase;});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawNodes(Vec2D<float> *mouse_pos, Camera2D *camera){
|
void drawNodes(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||||
for(auto& n : nodes){
|
for(auto& n : nodes | std::ranges::views::values ){
|
||||||
n.draw(mouse_pos, camera);
|
n.draw(mouse_pos, camera);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -19,11 +19,13 @@ class Node : public Movable{
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Node() {}
|
Node() {}
|
||||||
Node(float x, float y, float r) : Movable(Vec2D<float>(x, y), 0.0f), radius(r) {}
|
Node(int id, float x, float y, float r) : Movable(Vec2D<float>(x, y), 0.0f), radius(r), id(id) {}
|
||||||
Node(Vec2D<float> p, float r) : Movable(p, 0.0f), radius(r) {}
|
Node(int id, Vec2D<float> p, float r) : Movable(p, 0.0f), radius(r), id(id) {}
|
||||||
|
|
||||||
float radius;
|
float radius;
|
||||||
|
|
||||||
|
int id;
|
||||||
|
|
||||||
bool picked_up = false;
|
bool picked_up = false;
|
||||||
bool dragging = false;
|
bool dragging = false;
|
||||||
bool in_rect = false;
|
bool in_rect = false;
|
||||||
@@ -33,6 +35,7 @@ class Node : public Movable{
|
|||||||
bool config = false;
|
bool config = false;
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
bool erase = false;
|
bool erase = false;
|
||||||
|
bool highlighted = false;
|
||||||
|
|
||||||
int midi_out = -1;
|
int midi_out = -1;
|
||||||
|
|
||||||
@@ -60,7 +63,9 @@ class Node : public Movable{
|
|||||||
|
|
||||||
void draw(Vec2D<float> *mouse, Camera2D *cam) {
|
void draw(Vec2D<float> *mouse, Camera2D *cam) {
|
||||||
if(!dragging && !selected && !in_rect && !hovering) DrawCircle(position.x, position.y, radius, (Color){180, 210, 115, 255});
|
if(!dragging && !selected && !in_rect && !hovering) DrawCircle(position.x, position.y, radius, (Color){180, 210, 115, 255});
|
||||||
if(dragging || selected || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255});
|
if(selected || dragging || in_rect || hovering) DrawCircle(position.x, position.y, radius, (Color){108, 153, 187, 255});
|
||||||
|
if(selected) DrawCircleLinesV(position, radius+1, (Color){158, 255, 210, 255});
|
||||||
|
|
||||||
int offset = MeasureText(MIDI::Notes[midi_note].c_str(), 10);
|
int offset = MeasureText(MIDI::Notes[midi_note].c_str(), 10);
|
||||||
DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 10, WHITE );
|
DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 10, WHITE );
|
||||||
|
|
||||||
@@ -76,5 +81,6 @@ class Node : public Movable{
|
|||||||
DrawCircleLines(position.x, position.y, radius + R, (Color){108, 153, 187, (unsigned char)opacity});
|
DrawCircleLines(position.x, position.y, radius + R, (Color){108, 153, 187, (unsigned char)opacity});
|
||||||
DrawCircle(connector.x, connector.y, 8.0f, (Color){108, 153, 187, (unsigned char)opacity});
|
DrawCircle(connector.x, connector.y, 8.0f, (Color){108, 153, 187, (unsigned char)opacity});
|
||||||
}
|
}
|
||||||
|
if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+16
-14
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "connection-manager.h"
|
#include "connection-manager.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
#include "node-manager.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "midi.h"
|
#include "midi.h"
|
||||||
@@ -13,12 +14,13 @@ class SignalManager{
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SignalManager() {}
|
SignalManager() {}
|
||||||
SignalManager(ConnectionManager *cm, std::mutex *mutex) : mutex(mutex), cm(cm) {}
|
SignalManager(NodeManager *nm, ConnectionManager *cm, std::mutex *mutex) : mutex(mutex), cm(cm), nm(nm) {}
|
||||||
|
|
||||||
Midi midi;
|
Midi midi;
|
||||||
|
|
||||||
std::mutex *mutex;
|
std::mutex *mutex;
|
||||||
ConnectionManager *cm;
|
ConnectionManager *cm;
|
||||||
|
NodeManager *nm;
|
||||||
|
|
||||||
std::vector<Signal> signals;
|
std::vector<Signal> signals;
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ class SignalManager{
|
|||||||
|
|
||||||
void reset(){
|
void reset(){
|
||||||
for(auto &s : signals){
|
for(auto &s : signals){
|
||||||
s.position = s.start->position + Vec2D<float>{0.1, 0.1};
|
s.position = nm->nodes[s.start].position + Vec2D<float>{0.1, 0.1};
|
||||||
s.next = s.start;
|
s.next = s.start;
|
||||||
s.last = s.start;
|
s.last = s.start;
|
||||||
}
|
}
|
||||||
@@ -56,12 +58,12 @@ class SignalManager{
|
|||||||
loop = false;
|
loop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSignalAtNode(Node *node){
|
void addSignalAtNode(int node_id){
|
||||||
Color c = {(unsigned char)(232 - (rand() % 120)), (unsigned char)(125 + (int)(rand() % 120)), 62, 255};
|
Color c = {(unsigned char)(232 - (rand() % 120)), 50, (unsigned char)(20 + (int)(rand() % 120)), 255};
|
||||||
signals.emplace(signals.end(), Signal(node->position.x+1, node->position.y+1, 5.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
signals.emplace(signals.end(), Signal(nm->nodes[node_id].position.x+1, nm->nodes[node_id].position.y+1, 5.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
||||||
signals.back().next = node;
|
signals.back().next = node_id;
|
||||||
signals.back().last = node;
|
signals.back().last = node_id;
|
||||||
signals.back().start = node;
|
signals.back().start = node_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeSignal(int n){
|
void removeSignal(int n){
|
||||||
@@ -76,14 +78,14 @@ class SignalManager{
|
|||||||
mutex->lock();
|
mutex->lock();
|
||||||
if(play){
|
if(play){
|
||||||
for(auto& s : signals){
|
for(auto& s : signals){
|
||||||
s.direction = (s.next->position - s.position).norm();
|
s.direction = (nm->nodes[s.next].position - s.position).norm();
|
||||||
s.update(diff.count());
|
s.update(diff.count());
|
||||||
if(s.position.dist(&s.next->position) < 1.0f) {
|
if(s.position.dist(&nm->nodes[s.next].position) < 1.0f) {
|
||||||
Node* n = cm->next(s.next, s.last);
|
int n = cm->next(s.next, s.last);
|
||||||
|
|
||||||
if(n != s.next && n != nullptr) {
|
if(n != s.next && n != -1) {
|
||||||
for(auto &m : s.next->midi_outs){
|
for(auto &m : nm->nodes[s.next].midi_outs){
|
||||||
if(m.second.enabled) midi.note(m.second.i, s.next->midi_channel, s.next->midi_note, s.next->midi_velocity, s.next->midi_gate);
|
if(m.second.enabled) midi.note(m.second.i, nm->nodes[s.next].midi_channel, nm->nodes[s.next].midi_note, nm->nodes[s.next].midi_velocity, nm->nodes[s.next].midi_gate);
|
||||||
}
|
}
|
||||||
s.last = s.next;
|
s.last = s.next;
|
||||||
s.next = n;
|
s.next = n;
|
||||||
|
|||||||
+3
-4
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "moveable.h"
|
#include "moveable.h"
|
||||||
#include "node.h"
|
|
||||||
|
|
||||||
class Signal : public Movable{
|
class Signal : public Movable{
|
||||||
public:
|
public:
|
||||||
@@ -14,10 +13,10 @@ class Signal : public Movable{
|
|||||||
|
|
||||||
int id = 0;
|
int id = 0;
|
||||||
|
|
||||||
Node *next;
|
int next;
|
||||||
Node *last;
|
int last;
|
||||||
|
|
||||||
Node *start;
|
int start;
|
||||||
|
|
||||||
bool at_target = false;
|
bool at_target = false;
|
||||||
int target_node_id = 1;
|
int target_node_id = 1;
|
||||||
|
|||||||
+65
-2
@@ -1,15 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "connection.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "node-manager.h"
|
#include "node-manager.h"
|
||||||
#include "connection-manager.h"
|
#include "connection-manager.h"
|
||||||
#include "signal-manager.h"
|
#include "signal-manager.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <ranges>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class AppState{
|
class AppState{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AppState() : sm(&cm, &mutex), ui(&settings, &nm, &cm, &sm) {}
|
AppState() : cm(&nm), sm(&nm, &cm, &mutex), ui(&settings, &nm, &cm, &sm) {}
|
||||||
|
|
||||||
enum States {IDLE, CONFIG};
|
enum States {IDLE, CONFIG};
|
||||||
|
|
||||||
@@ -26,7 +32,7 @@ class AppState{
|
|||||||
AppUI ui;
|
AppUI ui;
|
||||||
|
|
||||||
void updateMidiPorts(){
|
void updateMidiPorts(){
|
||||||
for(auto&n : nm.nodes){
|
for(auto&n : nm.nodes | std::views::values){
|
||||||
for(auto& mo : sm.midi.midi_out_ports){
|
for(auto& mo : sm.midi.midi_out_ports){
|
||||||
if(!n.midi_outs.contains(mo.number) && mo.enabled){
|
if(!n.midi_outs.contains(mo.number) && mo.enabled){
|
||||||
n.midi_outs[mo.number] = {mo.number, mo.port.port_name, false};
|
n.midi_outs[mo.number] = {mo.number, mo.port.port_name, false};
|
||||||
@@ -38,6 +44,63 @@ class AppState{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void removeNodes(){
|
||||||
|
|
||||||
|
for(auto &n : nm.nodes){
|
||||||
|
n.second.highlighted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto erase_nodes = nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.erase;});
|
||||||
|
|
||||||
|
std::vector<int> erase_nodes_ids;
|
||||||
|
for(auto &e : erase_nodes){
|
||||||
|
erase_nodes_ids.push_back(e.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto erase_connections = cm.connections | std::ranges::views::filter([erase_nodes_ids](Connection c){ return std::ranges::contains(erase_nodes_ids, c.v1) || std::ranges::contains(erase_nodes_ids, c.v2);});
|
||||||
|
|
||||||
|
std::vector<int> adjacent_nodes_ids;
|
||||||
|
|
||||||
|
for(auto &c : erase_connections){
|
||||||
|
if(!nm.nodes.at(c.v1).selected) adjacent_nodes_ids.push_back(c.v1);
|
||||||
|
if(!nm.nodes.at(c.v2).selected) adjacent_nodes_ids.push_back(c.v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::ranges::for_each(adjacent_nodes_ids, [this](int id){ nm.nodes.at(id).highlighted = true;} );
|
||||||
|
|
||||||
|
auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
||||||
|
return std::ranges::contains(erase_nodes_ids, s.next);
|
||||||
|
});
|
||||||
|
|
||||||
|
for(auto &s : reroute_signals){
|
||||||
|
float dist = 10000000;
|
||||||
|
int next_id = -1;
|
||||||
|
for(int i : adjacent_nodes_ids){
|
||||||
|
if(nm.nodes.at(i).position.dist(&s.position) < dist) {
|
||||||
|
dist = nm.nodes.at(i).position.dist(&s.position);
|
||||||
|
next_id = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.next = next_id;
|
||||||
|
s.last = next_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rebase_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
||||||
|
return std::ranges::contains(erase_nodes_ids, s.start);
|
||||||
|
});
|
||||||
|
|
||||||
|
for(auto &s : rebase_signals){
|
||||||
|
s.start = s.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &n : erase_nodes){
|
||||||
|
std::erase_if(cm.connections, [n](Connection c){ return c.v1 == n.id || c.v2 == n.id;});
|
||||||
|
}
|
||||||
|
std::erase_if(nm.nodes, [](std::pair<int, Node> n){ return n.second.erase;});
|
||||||
|
nm.keys.clear();
|
||||||
|
std::ranges::copy(nm.nodes | std::ranges::views::keys, std::back_inserter(nm.keys));
|
||||||
|
}
|
||||||
|
|
||||||
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
|
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
updateMidiPorts();
|
updateMidiPorts();
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class AppUI{
|
|||||||
for(auto &midis : sm->midi.midi_out_ports){
|
for(auto &midis : sm->midi.midi_out_ports){
|
||||||
if(midis.enabled){
|
if(midis.enabled){
|
||||||
for(auto &n : nm->nodes){
|
for(auto &n : nm->nodes){
|
||||||
n.setMidiPort(midis.number, true);
|
n.second.setMidiPort(midis.number, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,8 @@ class AppUI{
|
|||||||
int s_signal = s_midi + 90 + i*20;
|
int s_signal = s_midi + 90 + i*20;
|
||||||
GuiLabel((Rectangle){20, (float)s_signal, 240, 20}, "SIGNALS");
|
GuiLabel((Rectangle){20, (float)s_signal, 240, 20}, "SIGNALS");
|
||||||
if(GuiButton((Rectangle){20, (float)s_signal + 35, 240, 20}, "ADD RANDOM SIGNAL")){
|
if(GuiButton((Rectangle){20, (float)s_signal + 35, 240, 20}, "ADD RANDOM SIGNAL")){
|
||||||
int ni = rand() % nm->nodes.size();
|
int ni = nm->getRandomNode();
|
||||||
sm->addSignalAtNode(&nm->nodes[ni]);
|
sm->addSignalAtNode(ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
int signal_configs = 0;
|
int signal_configs = 0;
|
||||||
@@ -81,7 +81,8 @@ class AppUI{
|
|||||||
int s_nodes = s_signal + 60 + signal_configs*20;
|
int s_nodes = s_signal + 60 + signal_configs*20;
|
||||||
GuiLabel((Rectangle){20, (float)s_nodes + 30, 240, 20}, "NODES");
|
GuiLabel((Rectangle){20, (float)s_nodes + 30, 240, 20}, "NODES");
|
||||||
if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){
|
if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){
|
||||||
nm->nodes.emplace_back(200.0f, 200.0f, 15.0f);
|
nm->addNode(200.0f, 200.0f);
|
||||||
|
// nm->nodes.emplace_back(200.0f, 200.0f, 15.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawFPS(20, settings->height - 30);
|
DrawFPS(20, settings->height - 30);
|
||||||
@@ -89,7 +90,7 @@ class AppUI{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void drawPerNodeConfig(Camera2D *camera){
|
void drawPerNodeConfig(Camera2D *camera){
|
||||||
for(auto& n : nm->nodes | std::ranges::views::filter([](Node n){ return n.config; })){
|
for(auto& n : nm->nodes | std::ranges::views::values | std::views::filter([](Node n){ return n.config; })){
|
||||||
Vector2 np = GetWorldToScreen2D((Vector2){n.position.x, n.position.y}, *camera);
|
Vector2 np = GetWorldToScreen2D((Vector2){n.position.x, n.position.y}, *camera);
|
||||||
|
|
||||||
n.config = !GuiWindowBox((Rectangle){np.x + 10, np.y + 10, 240, 440}, "config");
|
n.config = !GuiWindowBox((Rectangle){np.x + 10, np.y + 10, 240, 440}, "config");
|
||||||
@@ -100,7 +101,7 @@ class AppUI{
|
|||||||
|
|
||||||
GuiLabel((Rectangle){np.x + 20, np.y + 65, 220, 20}, "SIGNALS");
|
GuiLabel((Rectangle){np.x + 20, np.y + 65, 220, 20}, "SIGNALS");
|
||||||
if(GuiButton((Rectangle){np.x + 20, np.y + 90, 220, 20}, "ADD SIGNAL")){
|
if(GuiButton((Rectangle){np.x + 20, np.y + 90, 220, 20}, "ADD SIGNAL")){
|
||||||
sm->addSignalAtNode(&n);
|
sm->addSignalAtNode(n.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
int y_midi = 120;
|
int y_midi = 120;
|
||||||
|
|||||||
Reference in New Issue
Block a user