fishy loss of changes here...
This commit is contained in:
+2
-1
@@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
#include "graph-item.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "raylib.h"
|
#include "raylib.h"
|
||||||
|
|
||||||
class Connection{
|
class Connection : public GraphItem{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Connection(std::map<int, Node> *nodes, int v1, int v2) : v1(v1), v2(v2), nodes(nodes) {}
|
Connection(std::map<int, Node> *nodes, int v1, int v2) : v1(v1), v2(v2), nodes(nodes) {}
|
||||||
|
|||||||
@@ -166,6 +166,11 @@ struct AppSettings{
|
|||||||
int gui_selected_midi_out;
|
int gui_selected_midi_out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Graph
|
||||||
|
|
||||||
|
inline enum GraphItemType {NODE, EDGE} type;
|
||||||
|
|
||||||
// MIDI
|
// MIDI
|
||||||
|
|
||||||
struct MidiOutPort{
|
struct MidiOutPort{
|
||||||
@@ -180,6 +185,7 @@ struct MidiOut{
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace MIDI{
|
namespace MIDI{
|
||||||
|
inline std::vector<std::string> Fractions = {"1/32","1/16","3/32","1/8","5/32","3/16","7/32","1/4","9/32","5/16","11/32","3/8","13/32","7/16","15/32","1/2","17/32","9/16","19/32","5/8","21/32","11/16","23/32","3/4","25/32","13/16","27/32","7/8","29/32","15/16","31/32","1/1"};
|
||||||
inline std::vector<std::string> Notes = {
|
inline std::vector<std::string> Notes = {
|
||||||
"C-1", "C#-1", "D-1", "D#-1", "E-1", "F-1", "F#-1", "G-1",
|
"C-1", "C#-1", "D-1", "D#-1", "E-1", "F-1", "F#-1", "G-1",
|
||||||
"G#-1", "A-1", "A#-1", "B-1", "C0", "C#0", "D0", "D#0",
|
"G#-1", "A-1", "A#-1", "B-1", "C0", "C#0", "D0", "D#0",
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class GraphItem{
|
||||||
|
|
||||||
|
public:
|
||||||
|
int id;
|
||||||
|
GraphItemType type;
|
||||||
|
std::vector<int> connections;
|
||||||
|
|
||||||
|
};
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "connection.h"
|
||||||
|
#include <map>
|
||||||
|
#include <random>
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
class GraphManager{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
GraphManager() {}
|
||||||
|
|
||||||
|
std::map<int, Node> nodes;
|
||||||
|
std::vector<Connection> connections;
|
||||||
|
|
||||||
|
std::vector<int> keys;
|
||||||
|
int iterator = 0;
|
||||||
|
|
||||||
|
std::map<int, int> counter;
|
||||||
|
|
||||||
|
int getRandomNode(){
|
||||||
|
std::vector<int> o;
|
||||||
|
std::ranges::sample(keys, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
||||||
|
return o.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyNodes(Vec2D<float> position){
|
||||||
|
for(auto n: nodes | std::ranges::views::filter([](std::pair<int, Node> n){ return n.second.copied;})){
|
||||||
|
n.second.position = position + n.second.drag_offset;
|
||||||
|
n.second.id = iterator;
|
||||||
|
n.second.copied = false;
|
||||||
|
n.second.selected = true;
|
||||||
|
nodes.insert(std::make_pair(iterator, n.second));
|
||||||
|
keys.push_back(iterator);
|
||||||
|
iterator++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int copyNode(int id, Vec2D<float> position){
|
||||||
|
Node n = nodes.at(id);
|
||||||
|
n.position = position;
|
||||||
|
n.id = iterator;
|
||||||
|
nodes.insert(std::make_pair(iterator, n));
|
||||||
|
keys.push_back(iterator);
|
||||||
|
iterator++;
|
||||||
|
return iterator - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNodeMode(int mode){
|
||||||
|
for(auto &n : nodes | std::ranges::views::values){
|
||||||
|
n.mode = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int addNode(float x, float y){
|
||||||
|
return addNode(Vec2D<float>(x,y));
|
||||||
|
}
|
||||||
|
|
||||||
|
int addNode(Vec2D<float> position){
|
||||||
|
nodes.emplace(std::make_pair(iterator, Node(iterator, position, 15.0f)));
|
||||||
|
keys.push_back(iterator);
|
||||||
|
iterator++;
|
||||||
|
return iterator - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void triggerNode(int node){
|
||||||
|
nodes.at(node).trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(){
|
||||||
|
counter.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int next(int current, int last){
|
||||||
|
std::vector<Connection*> possible_connections;
|
||||||
|
std::vector<int> next_node_ids;
|
||||||
|
|
||||||
|
for(auto& c : connections){
|
||||||
|
if((c.v1 == current && c.v1_v2) || (c.v2 == current && c.v2_v1)) {
|
||||||
|
c.active = false;
|
||||||
|
possible_connections.push_back(&c);
|
||||||
|
next_node_ids.push_back( c.v1 == current ? c.v2 : c.v1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(possible_connections.empty()) return -1;
|
||||||
|
|
||||||
|
int return_path = 0;
|
||||||
|
float angle = -1;
|
||||||
|
if(nodes.at(current).distributionMode == Distribution::GEOMETRIC){
|
||||||
|
Vec2D<float> coming_from = (nodes.at(current).position - nodes.at(last).position).norm();
|
||||||
|
int i = 0;
|
||||||
|
for(auto n : possible_connections){
|
||||||
|
int next_position = n->v1 == current ? n->v2 : n->v1;
|
||||||
|
float angle_v1_v2 = coming_from.norm().dot((nodes.at(next_position).position - nodes.at(current).position).norm());
|
||||||
|
if(angle_v1_v2 > angle) {
|
||||||
|
return_path = i;
|
||||||
|
angle = angle_v1_v2;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nodes.at(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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nodes.at(current).distributionMode == Distribution::RANDOM){
|
||||||
|
return_path = rand() % possible_connections.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
possible_connections.at(return_path)->active = true;
|
||||||
|
return possible_connections.at(return_path)->v1 == current ? possible_connections.at(return_path)->v2 : possible_connections.at(return_path)->v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addConnection(int from, int to){
|
||||||
|
connections.emplace_back(&nodes, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
||||||
|
std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
||||||
|
for(auto& c : connections){
|
||||||
|
c.draw(mouse_pos, cam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void drawNodes(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||||
|
auto neighbors = nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){ return !n.dragging && !n.selected;}) | std::ranges::to<std::vector<Node>>();
|
||||||
|
float min_d = 480;
|
||||||
|
for(auto& n : nodes | std::ranges::views::values ){
|
||||||
|
if(n.dragging){
|
||||||
|
std::sort(neighbors.begin(), neighbors.end(), [n](Node na, Node nb){ return na.position.dist(n.position) < nb.position.dist(n.position);});
|
||||||
|
if(neighbors.size() > 1){
|
||||||
|
min_d = neighbors.front().position.dist(n.position);
|
||||||
|
n.neighbor = &nodes.at(neighbors.at(1).id);
|
||||||
|
int i = 0;
|
||||||
|
for(auto it = (neighbors.begin()); it != neighbors.end(); it++, i++){
|
||||||
|
float d = it->position.dist(n.position);
|
||||||
|
if(d > 0 && d < min_d*1.5 && d < 960) {
|
||||||
|
std::string frac = MIDI::Fractions.at((int)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);
|
||||||
|
|
||||||
|
Vec2D<float> middle_handle = it->position + (n.position - it->position) * ((d - text_length.x)*0.5f)/d;
|
||||||
|
Vec2D<float> middle_handle_frac = it->position + (n.position - it->position) * ((d - text_length_frac.x)*0.5f)/d;
|
||||||
|
Vec2D<float> text_position = middle_handle + (it->position - n.position).norm().orth() * 12.0f;
|
||||||
|
Vec2D<float> text_position_frac = middle_handle_frac - (it->position - n.position).norm().orth() * 4.0f;
|
||||||
|
|
||||||
|
float rotation = Vector2Angle((Vector2){1,0}, (n.position - it->position)) * RAD2DEG;
|
||||||
|
DrawTextPro(GetFontDefault(), std::format("{:.1f}",d).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
|
||||||
|
if(i == 0 && IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
|
||||||
|
DrawLineV(n.position, it->position, VS_COLOR_PINK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.draw(mouse_pos, camera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
+4
-5
@@ -4,6 +4,7 @@
|
|||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
#include "graph-item.h"
|
||||||
#include "moveable.h"
|
#include "moveable.h"
|
||||||
#include "raymath.h"
|
#include "raymath.h"
|
||||||
|
|
||||||
@@ -15,19 +16,17 @@ struct NodeMidiOut{
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Node : public Movable{
|
class Node : public Movable, public GraphItem{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Node() {}
|
Node() {}
|
||||||
Node(int id, float x, float y, float r) : Movable(Vec2D<float>(x, y), 0.0f), radius(r), id(id) {}
|
Node(int id, float x, float y, float r) : Movable(Vec2D<float>(x, y), 0.0f), GraphItem(id), radius(r) {}
|
||||||
Node(int id, Vec2D<float> p, float r) : Movable(p, 0.0f), radius(r), id(id) {}
|
Node(int id, Vec2D<float> p, float r) : Movable(p, 0.0f), GraphItem(id), radius(r) {}
|
||||||
|
|
||||||
Node *neighbor = nullptr;
|
Node *neighbor = nullptr;
|
||||||
|
|
||||||
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;
|
||||||
|
|||||||
+14
-17
@@ -1,10 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "connection-manager.h"
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "node-manager.h"
|
#include "graph-manager.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "node.h"
|
|
||||||
#include "midi.h"
|
#include "midi.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -14,13 +12,12 @@ class SignalManager{
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
SignalManager() {}
|
SignalManager() {}
|
||||||
SignalManager(NodeManager *nm, ConnectionManager *cm, std::mutex *mutex) : mutex(mutex), cm(cm), nm(nm) {}
|
SignalManager(GraphManager *gm, std::mutex *mutex) : mutex(mutex), gm(gm), nm(nm) {}
|
||||||
|
|
||||||
Midi midi;
|
Midi midi;
|
||||||
|
|
||||||
std::mutex *mutex;
|
std::mutex *mutex;
|
||||||
ConnectionManager *cm;
|
GraphManager *gm;
|
||||||
NodeManager *nm;
|
|
||||||
|
|
||||||
std::vector<Signal> signals;
|
std::vector<Signal> signals;
|
||||||
|
|
||||||
@@ -42,11 +39,11 @@ class SignalManager{
|
|||||||
|
|
||||||
void reset(){
|
void reset(){
|
||||||
for(auto &s : signals){
|
for(auto &s : signals){
|
||||||
s.position = nm->nodes[s.start].position + Vec2D<float>{0.1, 0.1};
|
s.position = gm->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;
|
||||||
}
|
}
|
||||||
cm->reset();
|
gm->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void startSignalThread(){
|
void startSignalThread(){
|
||||||
@@ -60,7 +57,7 @@ class SignalManager{
|
|||||||
|
|
||||||
void addSignalAtNode(int node_id){
|
void addSignalAtNode(int node_id){
|
||||||
Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200};
|
Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200};
|
||||||
signals.emplace(signals.end(), Signal(nm->nodes[node_id].position.x+1, nm->nodes[node_id].position.y+1, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
signals.emplace(signals.end(), Signal(gm->nodes[node_id].position.x+1, gm->nodes[node_id].position.y+1, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
||||||
signals.back().next = node_id;
|
signals.back().next = node_id;
|
||||||
signals.back().last = node_id;
|
signals.back().last = node_id;
|
||||||
signals.back().start = node_id;
|
signals.back().start = node_id;
|
||||||
@@ -78,18 +75,18 @@ class SignalManager{
|
|||||||
mutex->lock();
|
mutex->lock();
|
||||||
if(play){
|
if(play){
|
||||||
for(auto& s : signals){
|
for(auto& s : signals){
|
||||||
s.direction = (nm->nodes[s.next].position - s.position).norm();
|
s.direction = (gm->node(s.next).position - s.position).norm();
|
||||||
s.update(diff.count());
|
s.update(diff.count());
|
||||||
if(s.position.dist(&nm->nodes[s.next].position) < 0.6f) {
|
if(s.position.dist(&gm->nodes[s.next].position) < 0.6f) {
|
||||||
int n = cm->next(s.next, s.last);
|
int n = gm->next(s.next, s.last);
|
||||||
nm->nodes[s.next].trigger();
|
gm->triggerNode(s.next);
|
||||||
|
|
||||||
if(n != s.next && n != -1) {
|
if(n != s.next && n != -1) {
|
||||||
for(auto &m : nm->nodes[s.next].midi_outs){
|
for(auto &m : gm->nodes[s.next].midi_outs){
|
||||||
if(m.second.enabled) {
|
if(m.second.enabled) {
|
||||||
if(nm->nodes[s.next].send_note) midi.note(m.second.i, nm->nodes[s.next].midi_note_channel, nm->nodes[s.next].midi_note, nm->nodes[s.next].midi_velocity, nm->nodes[s.next].midi_gate);
|
if(gm->nodes[s.next].send_note) midi.note(m.second.i, gm->nodes[s.next].midi_note_channel, gm->nodes[s.next].midi_note, gm->nodes[s.next].midi_velocity, gm->nodes[s.next].midi_gate);
|
||||||
if(nm->nodes[s.next].send_cc) midi.cc(m.second.i, nm->nodes[s.next].midi_cc_channel, nm->nodes[s.next].midi_cc, nm->nodes[s.next].midi_cc_value);
|
if(gm->nodes[s.next].send_cc) midi.cc(m.second.i, gm->nodes[s.next].midi_cc_channel, gm->nodes[s.next].midi_cc, gm->nodes[s.next].midi_cc_value);
|
||||||
if(nm->nodes[s.next].send_pitch_bend) midi.pitch_bend(m.second.i, nm->nodes[s.next].midi_pitch_bend_channel, nm->nodes[s.next].midi_pitch_bend);
|
if(gm->nodes[s.next].send_pitch_bend) midi.pitch_bend(m.second.i, gm->nodes[s.next].midi_pitch_bend_channel, gm->nodes[s.next].midi_pitch_bend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.last = s.next;
|
s.last = s.next;
|
||||||
|
|||||||
+23
-25
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#include "connection.h"
|
#include "connection.h"
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "node-manager.h"
|
#include "graph-manager.h"
|
||||||
#include "connection-manager.h"
|
|
||||||
#include "signal-manager.h"
|
#include "signal-manager.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@
|
|||||||
class AppState{
|
class AppState{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AppState() : cm(&nm), sm(&nm, &cm, &mutex), ui(&settings, &nm, &cm, &sm) {}
|
AppState() : sm(&gm, &mutex), ui(&settings, &sm, &gm) {}
|
||||||
|
|
||||||
enum States {IDLE, CONFIG};
|
enum States {IDLE, CONFIG};
|
||||||
|
|
||||||
@@ -25,14 +24,13 @@ class AppState{
|
|||||||
|
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
|
|
||||||
ConnectionManager cm;
|
GraphManager gm;
|
||||||
SignalManager sm;
|
SignalManager sm;
|
||||||
NodeManager nm;
|
|
||||||
|
|
||||||
AppUI ui;
|
AppUI ui;
|
||||||
|
|
||||||
void updateMidiPorts(){
|
void updateMidiPorts(){
|
||||||
for(auto&n : nm.nodes | std::views::values){
|
for(auto&n : gm.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};
|
||||||
@@ -45,16 +43,16 @@ class AppState{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void copyNodesAndConnections(Vec2D<float> position){
|
void copyNodesAndConnections(Vec2D<float> position){
|
||||||
auto copy_nodes_ids = nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.copied;}) | std::views::transform([](Node n){return n.id;}) | std::ranges::to<std::vector<int>>();
|
auto copy_nodes_ids = gm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.copied;}) | std::views::transform([](Node n){return n.id;}) | std::ranges::to<std::vector<int>>();
|
||||||
|
|
||||||
std::vector<Connection> copy_connections;
|
std::vector<Connection> copy_connections;
|
||||||
std::ranges::copy_if(cm.connections, std::back_inserter(copy_connections), [copy_nodes_ids](Connection c){return std::ranges::contains(copy_nodes_ids, c.v1) && std::ranges::contains(copy_nodes_ids, c.v2);});
|
std::ranges::copy_if(gm.connections, std::back_inserter(copy_connections), [copy_nodes_ids](Connection c){return std::ranges::contains(copy_nodes_ids, c.v1) && std::ranges::contains(copy_nodes_ids, c.v2);});
|
||||||
|
|
||||||
for(auto &n : copy_nodes_ids){
|
for(auto &n : copy_nodes_ids){
|
||||||
int old_id = n;
|
int old_id = n;
|
||||||
int new_id = nm.copyNode(n, position + nm.nodes[n].drag_offset);
|
int new_id = gm.copyNode(n, position + gm.nodes[n].drag_offset);
|
||||||
nm.nodes[new_id].copied = false;
|
gm.nodes[new_id].copied = false;
|
||||||
nm.nodes[new_id].selected = true;
|
gm.nodes[new_id].selected = true;
|
||||||
|
|
||||||
for(auto &c : copy_connections){
|
for(auto &c : copy_connections){
|
||||||
if(c.v1 == old_id) c.v1 = new_id;
|
if(c.v1 == old_id) c.v1 = new_id;
|
||||||
@@ -62,29 +60,29 @@ class AppState{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cm.connections.insert(cm.connections.end(), copy_connections.cbegin(), copy_connections.cend());
|
gm.connections.insert(gm.connections.end(), copy_connections.cbegin(), copy_connections.cend());
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeNodes(){
|
void removeNodes(){
|
||||||
|
|
||||||
for(auto &n : nm.nodes){
|
for(auto &n : gm.nodes){
|
||||||
n.second.highlighted = false;
|
n.second.highlighted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto erase_nodes = nm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.erase;});
|
auto erase_nodes = gm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.erase;});
|
||||||
|
|
||||||
std::vector<int> erase_nodes_ids;
|
std::vector<int> erase_nodes_ids;
|
||||||
for(auto &e : erase_nodes){
|
for(auto &e : erase_nodes){
|
||||||
erase_nodes_ids.push_back(e.id);
|
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);});
|
auto erase_connections = gm.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;
|
std::vector<int> adjacent_nodes_ids;
|
||||||
|
|
||||||
for(auto &c : erase_connections){
|
for(auto &c : erase_connections){
|
||||||
if(!nm.nodes.at(c.v1).selected) adjacent_nodes_ids.push_back(c.v1);
|
if(!gm.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);
|
if(!gm.nodes.at(c.v2).selected) adjacent_nodes_ids.push_back(c.v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
auto reroute_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
||||||
@@ -95,8 +93,8 @@ class AppState{
|
|||||||
float dist = 10000000;
|
float dist = 10000000;
|
||||||
int next_id = -1;
|
int next_id = -1;
|
||||||
for(int i : adjacent_nodes_ids){
|
for(int i : adjacent_nodes_ids){
|
||||||
if(nm.nodes.at(i).position.dist(&s.position) < dist) {
|
if(gm.nodes.at(i).position.dist(&s.position) < dist) {
|
||||||
dist = nm.nodes.at(i).position.dist(&s.position);
|
dist = gm.nodes.at(i).position.dist(&s.position);
|
||||||
next_id = i;
|
next_id = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,19 +111,19 @@ class AppState{
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(auto &n : erase_nodes){
|
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(gm.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;});
|
std::erase_if(gm.nodes, [](std::pair<int, Node> n){ return n.second.erase;});
|
||||||
nm.keys.clear();
|
gm.keys.clear();
|
||||||
std::ranges::copy(nm.nodes | std::ranges::views::keys, std::back_inserter(nm.keys));
|
std::ranges::copy(gm.nodes | std::ranges::views::keys, std::back_inserter(gm.keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
|
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
updateMidiPorts();
|
updateMidiPorts();
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
nm.drawNodes(mouse_pos, camera);
|
gm.drawNodes(mouse_pos, camera);
|
||||||
cm.drawConnections(mouse_pos, camera);
|
gm.drawConnections(mouse_pos, camera);
|
||||||
sm.drawSignals(mouse_pos, camera);
|
sm.drawSignals(mouse_pos, camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "raylib.h"
|
||||||
#include "raygui/raygui.h"
|
#include "raygui/raygui.h"
|
||||||
#include "raygui/dark/style_dark.h"
|
#include "raygui/dark/style_dark.h"
|
||||||
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
#include "graph-manager.h"
|
||||||
#include "connection-manager.h"
|
|
||||||
#include "node-manager.h"
|
|
||||||
#include "raylib.h"
|
|
||||||
#include "signal-manager.h"
|
#include "signal-manager.h"
|
||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
class AppUI{
|
class AppUI{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AppUI(AppSettings *settings, NodeManager *nm, ConnectionManager *cm, SignalManager *sm) : settings(settings), nm(nm), sm(sm), cm(cm) {}
|
AppUI(AppSettings *settings, SignalManager *sm, GraphManager *gm) : settings(settings), gm(gm), sm(sm) {}
|
||||||
|
|
||||||
AppSettings *settings;
|
AppSettings *settings;
|
||||||
NodeManager *nm;
|
GraphManager *gm;
|
||||||
SignalManager *sm;
|
SignalManager *sm;
|
||||||
ConnectionManager *cm;
|
|
||||||
|
|
||||||
void init(){
|
void init(){
|
||||||
GuiLoadStyleDark();
|
GuiLoadStyleDark();
|
||||||
@@ -54,7 +52,7 @@ class AppUI{
|
|||||||
if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) {
|
if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) {
|
||||||
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 : gm->nodes){
|
||||||
n.second.setMidiPort(midis.number, true);
|
n.second.setMidiPort(midis.number, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +62,7 @@ class AppUI{
|
|||||||
int s_signal = s_midi + 100 + i*20;
|
int s_signal = s_midi + 100 + 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 = nm->getRandomNode();
|
int ni = gm->getRandomNode();
|
||||||
sm->addSignalAtNode(ni);
|
sm->addSignalAtNode(ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +81,14 @@ class AppUI{
|
|||||||
int s_nodes = s_signal + 70 + signal_configs*20;
|
int s_nodes = s_signal + 70 + 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->addNode(200.0f, 200.0f);
|
gm->addNode(200.0f, 200.0f);
|
||||||
}
|
}
|
||||||
DrawText(std::format("{}", nm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE);
|
DrawText(std::format("{}", gm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE);
|
||||||
DrawFPS(20, settings->height - 30);
|
DrawFPS(20, settings->height - 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawPerNodeConfig(Camera2D *camera){
|
void drawPerNodeConfig(Camera2D *camera){
|
||||||
for(auto& n : nm->nodes | std::ranges::views::values | std::views::filter([](Node n){ return n.config; })){
|
for(auto& n : gm->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");
|
||||||
|
|||||||
Reference in New Issue
Block a user