conversion to smart pointers done but still buggy
This commit is contained in:
+2
-4
@@ -4,14 +4,12 @@
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
|
||||
inline bool ViButton(Vec2D<float> *mouse_pos, float x, float y, float radius, Color color){
|
||||
Vector2 mp = {mouse_pos->x, mouse_pos->y}; //GetMousePosition(); TODO: Refactor my own vectors to raylib vectors
|
||||
inline bool ViButton(Vec2D<float> mp, float x, float y, float radius, Color color){
|
||||
DrawCircle(x,y,radius, color);
|
||||
return (Vector2Distance(mp, (Vector2){x,y}) < radius && IsMouseButtonPressed(MOUSE_BUTTON_LEFT));
|
||||
}
|
||||
|
||||
inline bool ViSegButton(Vec2D<float> *mouse_pos, float x, float y, float start_angle, float end_angle, float radius, Color color){
|
||||
Vector2 mp = {mouse_pos->x, mouse_pos->y}; //GetMousePosition(); TODO: Refactor my own vectors to raylib vectors
|
||||
inline bool ViSegButton(Vec2D<float> mp, float x, float y, float start_angle, float end_angle, float radius, Color color){
|
||||
DrawCircleSector((Vector2){x,y},radius, start_angle, end_angle, 5, color);
|
||||
return (Vector2Distance(mp, (Vector2){x,y}) < radius && IsMouseButtonPressed(MOUSE_BUTTON_LEFT));
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "edge.h"
|
||||
#include "node-manager.h"
|
||||
#include "raylib.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class ConnectionManager{
|
||||
|
||||
public:
|
||||
|
||||
ConnectionManager(NodeManager *nm) : nm(nm) {}
|
||||
|
||||
NodeManager *nm;
|
||||
|
||||
std::vector<Connection> connections;
|
||||
|
||||
std::map<int, int> counter;
|
||||
|
||||
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.node_id_start == current && c.start_end) || (c.node_id_end == current && c.end_start)) {
|
||||
c.active = false;
|
||||
possible_connections.push_back(&c);
|
||||
next_node_ids.push_back( c.node_id_start == current ? c.node_id_end : c.node_id_start );
|
||||
}
|
||||
}
|
||||
|
||||
if(possible_connections.empty()) return -1;
|
||||
|
||||
int return_path = 0;
|
||||
float angle = -1;
|
||||
if(nm->nodes.at(current).distributionMode == Distribution::GEOMETRIC){
|
||||
Vec2D<float> coming_from = (nm->nodes.at(current).position - nm->nodes.at(last).position).norm();
|
||||
int i = 0;
|
||||
for(auto n : possible_connections){
|
||||
int next_position = n->node_id_start == current ? n->node_id_end : n->node_id_start;
|
||||
float angle_v1_v2 = coming_from.norm().dot((nm->nodes.at(next_position).position - nm->nodes.at(current).position).norm());
|
||||
if(angle_v1_v2 > angle) {
|
||||
return_path = i;
|
||||
angle = angle_v1_v2;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if(nm->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(nm->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)->node_id_start == current ? possible_connections.at(return_path)->node_id_end : possible_connections.at(return_path)->node_id_start;
|
||||
}
|
||||
|
||||
void addConnection(int from, int to){
|
||||
connections.emplace_back(nm, from, to);
|
||||
}
|
||||
|
||||
void splitConnection(Connection *c){
|
||||
Vec2D<float> center = c->node_start->position.center(c->node_end->position);
|
||||
|
||||
}
|
||||
|
||||
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
||||
std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
||||
for(auto& c : connections){
|
||||
if(c.split) splitConnection(&c);
|
||||
c.draw(mouse_pos, cam);
|
||||
}
|
||||
}
|
||||
};
|
||||
+2
-3
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
//#include "connection-manager.h"
|
||||
//#include "signal-manager.h"
|
||||
#ifdef _WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
@@ -172,7 +170,8 @@ struct AppSettings{
|
||||
|
||||
// Graph
|
||||
|
||||
inline enum GraphItemType {NODE, EDGE} type;
|
||||
enum GraphItemType {NODE, EDGE};
|
||||
enum NodeType {OSCNODE, MIDINODE};
|
||||
|
||||
// MIDI
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ class Node;
|
||||
class Edge : public GraphItem{
|
||||
|
||||
public:
|
||||
Edge() {}
|
||||
Edge(std::shared_ptr<Node> start, std::shared_ptr<Node> end) : start(start), end(end) {}
|
||||
|
||||
std::shared_ptr<Node> start;
|
||||
@@ -24,7 +25,13 @@ class Edge : public GraphItem{
|
||||
float connector_offset = 8.0f;
|
||||
float switches_offset = 25.0f;
|
||||
|
||||
virtual bool GActive() {return active;}
|
||||
|
||||
std::shared_ptr<Node> getNextNode(std::shared_ptr<Node> origin){
|
||||
return start == origin ? end : start;
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> mouse_pos, Camera2D cam) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,9 @@ class GraphItem{
|
||||
public:
|
||||
std::vector<std::shared_ptr<GraphItem>> neighbors;
|
||||
|
||||
GraphItemType graphItemType;
|
||||
|
||||
virtual void draw(Vec2D<float> mouse, Camera2D cam) = 0;
|
||||
virtual GraphItemType getType() {return graphItemType;}
|
||||
virtual ~GraphItem() = default;
|
||||
};
|
||||
|
||||
+68
-38
@@ -1,10 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "button.h"
|
||||
#include "datatypes.h"
|
||||
#include "graph-item.h"
|
||||
#include "midi-node.h"
|
||||
#include "node.h"
|
||||
#include "edge.h"
|
||||
#include "raymath.h"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -37,31 +41,53 @@ class GraphManager{
|
||||
|
||||
void copyNodes(std::vector<std::shared_ptr<Node>> nodes, Vec2D<float> position){
|
||||
for(auto n: nodes){
|
||||
auto nc = std::make_shared<Node>(n);
|
||||
auto nc = std::make_shared<Node>(*n);
|
||||
nc->position = position + nc->drag_offset;
|
||||
nc->selected = true;
|
||||
nodes.push_back(nc);
|
||||
}
|
||||
}
|
||||
|
||||
void copyNode(std::shared_ptr<Node> n, Vec2D<float> position){
|
||||
auto nc = std::make_shared<Node>(n);
|
||||
void copyNodes(std::vector<std::shared_ptr<MidiNode>> nodes, Vec2D<float> position){
|
||||
for(auto n: nodes){
|
||||
std::shared_ptr<MidiNode> nc = std::make_shared<MidiNode>(*n);
|
||||
nc->position = position + nc->drag_offset;
|
||||
nc->selected = true;
|
||||
nodes.push_back(nc);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> copyNode(std::shared_ptr<Node> n, Vec2D<float> position){
|
||||
auto nc = std::make_shared<Node>(*n);
|
||||
nc->setPosition(position);
|
||||
nodes.push_back(nc);
|
||||
return nc;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> addNode(float x, float y){
|
||||
return addNode(Vec2D<float>(x,y));
|
||||
std::shared_ptr<MidiNode> copyNode(std::shared_ptr<MidiNode> n, Vec2D<float> position){
|
||||
auto nc = std::make_shared<MidiNode>(*n);
|
||||
nc->setPosition(position);
|
||||
nodes.push_back(nc);
|
||||
return nc;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> addNode(Vec2D<float> position){
|
||||
nodes.emplace_back(std::make_shared<Node>(position));
|
||||
/*std::shared_ptr<Node> addNode(float x, float y){*/
|
||||
/* return addNode(Vec2D<float>(x,y));*/
|
||||
/*}*/
|
||||
/**/
|
||||
/*std::shared_ptr<Node> addNode(Vec2D<float> position){*/
|
||||
/* nodes.emplace_back(std::make_shared<Node>(position));*/
|
||||
/* return nodes.back();*/
|
||||
/*}*/
|
||||
|
||||
std::shared_ptr<Node> addMidiNode(Vec2D<float> position){
|
||||
nodes.emplace_back(std::make_shared<MidiNode>(position));
|
||||
return nodes.back();
|
||||
}
|
||||
|
||||
void setNodeMode(int mode){
|
||||
for(auto n: nodes){
|
||||
n->setMode(mode);
|
||||
n->SMode(mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,22 +136,26 @@ class GraphManager{
|
||||
}
|
||||
|
||||
void addConnection(std::shared_ptr<Node> from, std::shared_ptr<Node> to){
|
||||
edges.emplace_back(std::make_shared<Edge>(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());
|
||||
}
|
||||
|
||||
void drawConnections(Vec2D<float> *mouse_pos, Camera2D *cam){
|
||||
void drawEdges(Vec2D<float> mouse_pos, Camera2D cam){
|
||||
// std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
||||
for(auto& c : edges){
|
||||
Vec2D<float> v1_position = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->connector_offset);
|
||||
Vec2D<float> 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->midi_gate, 1.f, 4.f);
|
||||
float midi_gate_v2 = Clamp((4.f / 1000.f) * c->end->midi_gate, 1.f, 4.f);
|
||||
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.active) col = {108, 153, 187, 255};
|
||||
if(c->GActive()) col = {108, 153, 187, 255};
|
||||
DrawLine(v1_position.x, v1_position.y, v2_position.x, v2_position.y, col);
|
||||
|
||||
if(midi_gate_v1 == 4.0f) col = VS_COLOR_RED;
|
||||
@@ -135,9 +165,9 @@ class GraphManager{
|
||||
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;
|
||||
Vec2D<float> from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c.switches_offset);
|
||||
Vec2D<float> to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c.switches_offset);
|
||||
if(v1_v2_distance < 100) c->switches_offset = v1_v2_distance/2.3f;
|
||||
Vec2D<float> from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->switches_offset);
|
||||
Vec2D<float> to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->switches_offset);
|
||||
Vec2D<float> middle_handle = c->end->position - ((c->end->position - c->start->position))*0.4f;
|
||||
Vec2D<float> middle_handle_2 = c->end->position - ((c->end->position - c->start->position))*0.6f;
|
||||
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);
|
||||
@@ -150,58 +180,58 @@ class GraphManager{
|
||||
unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f);
|
||||
|
||||
// On/Off switches on both sides
|
||||
if(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->start_end ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->start_end = !c->start_end;
|
||||
if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c.end_start ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c.end_start = !c.end_start;
|
||||
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->start_end){
|
||||
if(!c->pass_forward){
|
||||
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle;
|
||||
Vec2D<float> 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.end_start){
|
||||
if(!c->pass_backward){
|
||||
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle;
|
||||
Vec2D<float> 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} )) c.remove = true;
|
||||
if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 50, 32, opacity} )) c.split = true;
|
||||
if(ViButton(mouse_pos, flip_handle.x, flip_handle.y, 8.0f, (Color){232, 50, 32, opacity} )) c->remove = true;
|
||||
if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 50, 32, opacity} )) c->split = true;
|
||||
}
|
||||
}
|
||||
|
||||
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>>();
|
||||
void drawNodes(Vec2D<float> mouse_pos, Camera2D camera){
|
||||
auto neighbors = nodes | std::ranges::views::filter([](std::shared_ptr<Node> n){ return !n->dragging && !n->selected;}) | std::ranges::to<std::vector<std::shared_ptr<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);});
|
||||
for(auto n : nodes){
|
||||
if(n->dragging){
|
||||
std::sort(neighbors.begin(), neighbors.end(), [n](std::shared_ptr<Node> na, std::shared_ptr<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);
|
||||
min_d = neighbors.front()->position.dist(n->position);
|
||||
n->neighbor = neighbors.at(1);
|
||||
int i = 0;
|
||||
for(auto it = (neighbors.begin()); it != neighbors.end(); it++, i++){
|
||||
float d = it->position.dist(n.position);
|
||||
for(auto nb : neighbors){
|
||||
float d = nb->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;
|
||||
Vec2D<float> middle_handle = nb->position + (n->position - nb->position) * ((d - text_length.x)*0.5f)/d;
|
||||
Vec2D<float> middle_handle_frac = nb->position + (n->position - nb->position) * ((d - text_length_frac.x)*0.5f)/d;
|
||||
Vec2D<float> text_position = middle_handle + (nb->position - n->position).norm().orth() * 12.0f;
|
||||
Vec2D<float> text_position_frac = middle_handle_frac - (nb->position - n->position).norm().orth() * 4.0f;
|
||||
|
||||
float rotation = Vector2Angle((Vector2){1,0}, (n.position - it->position)) * RAD2DEG;
|
||||
float rotation = Vector2Angle((Vector2){1,0}, (n->position - nb->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);
|
||||
DrawLineV(n->position, nb->position, VS_COLOR_PINK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
n.draw(mouse_pos, camera);
|
||||
n->draw(mouse_pos, camera);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+111
-108
@@ -6,7 +6,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "midi-node.h"
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
|
||||
#include "datatypes.h"
|
||||
@@ -68,17 +71,19 @@ int main(){
|
||||
camera.zoom = 1.0f;
|
||||
|
||||
for(int i = 0; i < 4; ++i){
|
||||
app.gm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 5 * app.settings.grid*4);
|
||||
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 5 * app.settings.grid, 5 * app.settings.grid*4});
|
||||
}
|
||||
for(int i = 3; i >= 0; --i){
|
||||
app.gm.addNode((float)i * app.settings.grid*4 + 10 * app.settings.grid, 6 * app.settings.grid*4);
|
||||
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 5 * app.settings.grid, 6 * app.settings.grid*4});
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; ++i){
|
||||
app.gm.addConnection(app.gm.nodes[i].id, app.gm.nodes[(i+1) % 8].id);
|
||||
app.gm.addConnection(app.gm.nodes[i], app.gm.nodes[(i+1) % 8]);
|
||||
}
|
||||
|
||||
app.sm.addSignalAtNode((app.gm.nodes | std::views::values).front().id);
|
||||
std::cout << app.gm.nodes[0]->getNodeType() << std::endl;
|
||||
|
||||
app.sm.addSignalAtNode(app.gm.nodes.front());
|
||||
app.sm.startSignalThread();
|
||||
|
||||
enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION, DELETE_SELECTED_NODES, COPY_SELECTED_NODES, PASTE_SELECTED_NODES};
|
||||
@@ -87,6 +92,7 @@ int main(){
|
||||
Vec2D<float> select_start;
|
||||
Rectangle selection;
|
||||
|
||||
std::vector<std::shared_ptr<Node>> copied_nodes;
|
||||
|
||||
while(!WindowShouldClose()){
|
||||
|
||||
@@ -111,17 +117,15 @@ int main(){
|
||||
Vec2D<float> mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
|
||||
Vec2D<float> delta = mouse_delta * (-1.0f/camera.zoom);
|
||||
|
||||
std::vector<std::shared_ptr<Node>> copied_nodes;
|
||||
auto dragging_nodes = app.gm.nodes | std::ranges::views::filter([](std::shared_ptr<Node> n) { return n->dragging;});
|
||||
auto connecting_nodes = app.gm.nodes | std::ranges::views::filter([](std::shared_ptr<Node> n) { return n->connecting;});
|
||||
auto selected_nodes = app.gm.nodes | std::ranges::views::filter([](std::shared_ptr<Node> n) { return n->selected && !n->dragging;}) | std::ranges::to<std::vector<std::shared_ptr<Node>>>();
|
||||
auto hovering_nodes = app.gm.nodes | std::ranges::views::filter([&mouse_pos](std::shared_ptr<Node> n) { return CheckCollisionPointCircle(mouse_pos, n->position, n->radius);});
|
||||
auto hovering_connectors = app.gm.nodes | std::ranges::views::filter([&mouse_pos](std::shared_ptr<Node> n) { return CheckCollisionPointCircle(mouse_pos, (n->position - ((n->position - mouse_pos)).norm() * (n->radius + 14.0f)), 8.0f);});
|
||||
|
||||
auto dragging_nodes = app.gm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n) { return n.dragging;});
|
||||
auto connecting_nodes = app.gm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.connecting;});
|
||||
auto selected_nodes = app.gm.nodes | std::ranges::views::values| std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;});
|
||||
auto hovering_nodes = app.gm.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.gm.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);});
|
||||
|
||||
for(auto &n : app.gm.nodes | std::ranges::views::values){
|
||||
if(hovering_nodes.empty()) n.hovering = false;
|
||||
if(hovering_connectors.empty()) n.hover_connect = false;
|
||||
for(auto &n : app.gm.nodes ){
|
||||
if(hovering_nodes.empty()) n->hovering = false;
|
||||
if(hovering_connectors.empty()) n->hover_connect = false;
|
||||
}
|
||||
|
||||
if(!mouse_down && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::HOVER_CANVAS;
|
||||
@@ -145,8 +149,8 @@ int main(){
|
||||
switch(istate){
|
||||
case InteractionState::HOVER_CANVAS:
|
||||
{
|
||||
for(auto &n : app.gm.nodes | std::ranges::views::values){
|
||||
n.hover_connect = false;
|
||||
for(auto &n : app.gm.nodes){
|
||||
n->hover_connect = false;
|
||||
}
|
||||
if(mouse_right_down) {
|
||||
camera.target = Vector2Add(camera.target, delta);
|
||||
@@ -164,22 +168,22 @@ int main(){
|
||||
DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});
|
||||
selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};
|
||||
|
||||
for(auto& n : app.gm.nodes | std::views::values){
|
||||
if(CheckCollisionPointRec(n.position, selection)) {
|
||||
n.in_rect = true;
|
||||
for(auto& n : app.gm.nodes){
|
||||
if(CheckCollisionPointRec(n->position, selection)) {
|
||||
n->in_rect = true;
|
||||
} else {
|
||||
n.in_rect = false;
|
||||
n->in_rect = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mouse_released){
|
||||
for(auto& n : app.gm.nodes | std::views::values){
|
||||
if(CheckCollisionPointRec(n.position, selection)) {
|
||||
n.selected = true;
|
||||
n.in_rect = false;
|
||||
for(auto& n : app.gm.nodes){
|
||||
if(CheckCollisionPointRec(n->position, selection)) {
|
||||
n->selected = true;
|
||||
n->in_rect = false;
|
||||
} else {
|
||||
if(!IsKeyDown(KEY_LEFT_SHIFT)) n.selected = false;
|
||||
if(!IsKeyDown(KEY_LEFT_SHIFT)) n->selected = false;
|
||||
}
|
||||
}
|
||||
selection = (Rectangle){0,0,0,0};
|
||||
@@ -190,45 +194,45 @@ int main(){
|
||||
{
|
||||
if(mouse_clicked) {
|
||||
if(IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||
hovering_nodes.front().selected = true;
|
||||
hovering_nodes.front()->selected = true;
|
||||
} else {
|
||||
hovering_nodes.front().dragging = true;
|
||||
hovering_nodes.front().drag_offset = hovering_nodes.front().position - mouse_pos;
|
||||
hovering_nodes.front()->dragging = true;
|
||||
hovering_nodes.front()->drag_offset = hovering_nodes.front()->position - mouse_pos;
|
||||
}
|
||||
}
|
||||
if(mouse_right_clicked) hovering_nodes.front().config = true;
|
||||
if(mouse_right_clicked) hovering_nodes.front()->config = true;
|
||||
break;
|
||||
}
|
||||
case InteractionState::DRAG_NODE:
|
||||
{
|
||||
if(!dragging_nodes.empty()){
|
||||
for(auto &n : selected_nodes){
|
||||
if(!n.picked_up) n.drag_offset = n.position - dragging_nodes.front().position;
|
||||
n.picked_up = true;
|
||||
if(!n->picked_up) n->drag_offset = n->position - dragging_nodes.front()->position;
|
||||
n->picked_up = true;
|
||||
}
|
||||
|
||||
if(IsKeyDown(KEY_LEFT_CONTROL)) {
|
||||
dragging_nodes.front().position = (Vec2D<float>){round((mouse_pos.x+dragging_nodes.front().drag_offset.x)/app.settings.grid)*app.settings.grid, round((mouse_pos.y+dragging_nodes.front().drag_offset.y)/app.settings.grid)*app.settings.grid};
|
||||
dragging_nodes.front()->position = (Vec2D<float>){round((mouse_pos.x+dragging_nodes.front()->drag_offset.x)/app.settings.grid)*app.settings.grid, round((mouse_pos.y+dragging_nodes.front()->drag_offset.y)/app.settings.grid)*app.settings.grid};
|
||||
} else if(IsKeyDown(KEY_LEFT_SHIFT)){
|
||||
float steps = round(dragging_nodes.front().neighbor->position.dist(mouse_pos) / app.settings.grid) * app.settings.grid;
|
||||
Vec2D<float> polar = dragging_nodes.front().neighbor->position - (dragging_nodes.front().neighbor->position - (mouse_pos + dragging_nodes.front().drag_offset)).norm() * steps;
|
||||
dragging_nodes.front().position = polar;
|
||||
float steps = round(dragging_nodes.front()->neighbor->position.dist(mouse_pos) / app.settings.grid) * app.settings.grid;
|
||||
Vec2D<float> polar = dragging_nodes.front()->neighbor->position - (dragging_nodes.front()->neighbor->position - (mouse_pos + dragging_nodes.front()->drag_offset)).norm() * steps;
|
||||
dragging_nodes.front()->position = polar;
|
||||
} else {
|
||||
dragging_nodes.front().position = mouse_pos + dragging_nodes.front().drag_offset;
|
||||
dragging_nodes.front()->position = mouse_pos + dragging_nodes.front()->drag_offset;
|
||||
}
|
||||
|
||||
for(auto &n : selected_nodes){
|
||||
n.position = dragging_nodes.front().position + n.drag_offset;
|
||||
n->position = dragging_nodes.front()->position + n->drag_offset;
|
||||
}
|
||||
|
||||
if(mouse_released) {
|
||||
for(auto &n : dragging_nodes){
|
||||
n.dragging = false;
|
||||
n.picked_up = false;
|
||||
n->dragging = false;
|
||||
n->picked_up = false;
|
||||
}
|
||||
for(auto &n : selected_nodes){
|
||||
n.picked_up = false;
|
||||
n.dragging = false;
|
||||
n->picked_up = false;
|
||||
n->dragging = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,116 +241,115 @@ int main(){
|
||||
case InteractionState::HOVER_CONNECTOR:
|
||||
{
|
||||
if(!hovering_connectors.empty()){
|
||||
hovering_connectors.front().hover_connect = true;
|
||||
if(mouse_clicked) hovering_connectors.front().connecting = true;
|
||||
hovering_connectors.front()->hover_connect = true;
|
||||
if(mouse_clicked) hovering_connectors.front()->connecting = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InteractionState::CONNECT_NODE:
|
||||
{
|
||||
Vec2D<float> connector_position = connecting_nodes.front().position - ((connecting_nodes.front().position - mouse_pos)).norm() * (connecting_nodes.front().radius + 14.0f);
|
||||
Vec2D<float> connector_position = connecting_nodes.front()->position - ((connecting_nodes.front()->position - mouse_pos)).norm() * (connecting_nodes.front()->radius + 14.0f);
|
||||
|
||||
if(connecting_nodes.front().connecting && mouse_down){
|
||||
if(connecting_nodes.front()->connecting && mouse_down){
|
||||
DrawLine(connector_position.x, connector_position.y, mouse_pos.x, mouse_pos.y, (Color){229, 181, 103, 255});
|
||||
connecting_nodes.front().hovering = true;
|
||||
connecting_nodes.front().hover_connect = true;
|
||||
connecting_nodes.front()->hovering = true;
|
||||
connecting_nodes.front()->hover_connect = true;
|
||||
}
|
||||
|
||||
if(!hovering_connectors.empty()) {
|
||||
hovering_connectors.front().hovering = true;
|
||||
hovering_connectors.front().hover_connect = true;
|
||||
hovering_connectors.front()->hovering = true;
|
||||
hovering_connectors.front()->hover_connect = true;
|
||||
}
|
||||
if(!hovering_nodes.empty()) hovering_nodes.front().hovering = true;
|
||||
if(!hovering_nodes.empty()) hovering_nodes.front()->hovering = true;
|
||||
|
||||
if(mouse_released) {
|
||||
if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){
|
||||
if(!hovering_nodes.empty()){
|
||||
app.gm.addConnection(connecting_nodes.front().id, hovering_nodes.front().id);
|
||||
app.gm.addConnection(connecting_nodes.front(), hovering_nodes.front());
|
||||
} else if(!hovering_connectors.empty()){
|
||||
app.gm.addConnection(connecting_nodes.front().id, hovering_connectors.front().id);
|
||||
app.gm.addConnection(connecting_nodes.front(), hovering_connectors.front());
|
||||
} else {
|
||||
int id = app.gm.addNode(mouse_pos.x, mouse_pos.y);
|
||||
app.gm.addConnection(connecting_nodes.front().id, id);
|
||||
std::shared_ptr<Node> new_node = app.gm.addMidiNode(mouse_pos);
|
||||
app.gm.addConnection(connecting_nodes.front(), new_node);
|
||||
}
|
||||
}
|
||||
connecting_nodes.front().connecting = false;
|
||||
connecting_nodes.front()->connecting = false;
|
||||
istate = InteractionState::HOVER_CANVAS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InteractionState::DELETE_SELECTED_NODES:
|
||||
{
|
||||
for(auto &n : selected_nodes){
|
||||
n.erase = true;
|
||||
}
|
||||
app.removeNodes();
|
||||
app.removeNodes(selected_nodes | std::ranges::to<std::vector<std::shared_ptr<Node>>>());
|
||||
break;
|
||||
}
|
||||
case InteractionState::COPY_SELECTED_NODES:
|
||||
{
|
||||
std::copy(selected_nodes.begin(), selected_nodes.end(), copied_nodes.begin());
|
||||
std::ranges::copy(selected_nodes.begin(), selected_nodes.end(), std::back_inserter(copied_nodes));
|
||||
break;
|
||||
}
|
||||
case InteractionState::PASTE_SELECTED_NODES:
|
||||
{
|
||||
for(auto &n: copied_nodes){
|
||||
n.drag_offset = (n.position - copied_nodes.front().position);
|
||||
n->drag_offset = (n->position - copied_nodes.front()->position);
|
||||
}
|
||||
// app.gm.copyNodes(mouse_pos);
|
||||
//app.gm.copyNodes(selected_nodes, mouse_pos);
|
||||
|
||||
app.copyNodesAndConnections(mouse_pos);
|
||||
app.copyNodesAndConnections(copied_nodes, mouse_pos);
|
||||
copied_nodes.clear();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
float wheel = GetMouseWheelMove();
|
||||
if(wheel != 0){
|
||||
if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL) && !IsKeyDown(KEY_LEFT_ALT)){
|
||||
switch(app.settings.mode){
|
||||
case 0:{
|
||||
hovering_nodes.front().midi_note += wheel;
|
||||
break;}
|
||||
case 1:{
|
||||
hovering_nodes.front().midi_cc += wheel;
|
||||
break;}
|
||||
case 2:{
|
||||
hovering_nodes.front().midi_pitch_bend += wheel;
|
||||
break;}
|
||||
};
|
||||
if(hovering_nodes.front().midi_note < 0 ) hovering_nodes.front().midi_note = app.sm.midi.midiNotes.size()-1;
|
||||
if(hovering_nodes.front().midi_note >= app.sm.midi.midiNotes.size() ) hovering_nodes.front().midi_note = 0;
|
||||
if(!hovering_nodes.empty() && hovering_nodes.front()->getNodeType() == NodeType::MIDINODE) {
|
||||
std::shared_ptr<MidiNode> midiNode = std::dynamic_pointer_cast<MidiNode>(hovering_nodes.front());
|
||||
if(IsKeyDown(KEY_LEFT_CONTROL) && !IsKeyDown(KEY_LEFT_ALT)){
|
||||
switch(app.settings.mode){
|
||||
case 0:{
|
||||
midiNode->midi_note += wheel;
|
||||
break;}
|
||||
case 1:{
|
||||
midiNode->midi_cc += wheel;
|
||||
break;}
|
||||
case 2:{
|
||||
midiNode->midi_pitch_bend += wheel;
|
||||
break;}
|
||||
};
|
||||
if(midiNode->midi_note < 0 ) midiNode->midi_note = app.sm.midi.midiNotes.size()-1;
|
||||
if(midiNode->midi_note >= app.sm.midi.midiNotes.size() ) midiNode->midi_note = 0;
|
||||
|
||||
if(hovering_nodes.front().midi_cc < 0 ) hovering_nodes.front().midi_cc = 127;
|
||||
if(hovering_nodes.front().midi_cc > 127 ) hovering_nodes.front().midi_cc = 0;
|
||||
if(midiNode->midi_cc < 0 ) midiNode->midi_cc = 127;
|
||||
if(midiNode->midi_cc > 127 ) midiNode->midi_cc = 0;
|
||||
|
||||
if(hovering_nodes.front().midi_pitch_bend < 0 ) hovering_nodes.front().midi_pitch_bend = 0;
|
||||
if(hovering_nodes.front().midi_pitch_bend > 16383 ) hovering_nodes.front().midi_pitch_bend = 16383;
|
||||
if(midiNode->midi_pitch_bend < 0 ) midiNode->midi_pitch_bend = 0;
|
||||
if(midiNode->midi_pitch_bend > 16383 ) midiNode->midi_pitch_bend = 16383;
|
||||
|
||||
} else if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_SHIFT) && !IsKeyDown(KEY_LEFT_ALT)) {
|
||||
hovering_nodes.front().midi_velocity += wheel;
|
||||
if(hovering_nodes.front().midi_velocity < 0 ) hovering_nodes.front().midi_velocity = 127;
|
||||
if(hovering_nodes.front().midi_velocity > 127 ) hovering_nodes.front().midi_velocity = 0;
|
||||
} else if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_ALT)) {
|
||||
switch(app.settings.mode){
|
||||
case 0:{
|
||||
float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f);
|
||||
hovering_nodes.front().midi_gate += incr;
|
||||
if(hovering_nodes.front().midi_gate < 0 ) hovering_nodes.front().midi_gate = 0;
|
||||
break;}
|
||||
case 1:{
|
||||
hovering_nodes.front().midi_cc_value += wheel;
|
||||
if(hovering_nodes.front().midi_cc_value < 0 ) hovering_nodes.front().midi_cc_value = 0;
|
||||
if(hovering_nodes.front().midi_cc_value > 127 ) hovering_nodes.front().midi_cc_value = 127;
|
||||
break;}
|
||||
case 2:{
|
||||
float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f);
|
||||
hovering_nodes.front().midi_pitch_bend += incr;
|
||||
if(hovering_nodes.front().midi_pitch_bend < 0 ) hovering_nodes.front().midi_pitch_bend = 0;
|
||||
if(hovering_nodes.front().midi_pitch_bend > 16383 ) hovering_nodes.front().midi_pitch_bend = 16383;
|
||||
break;}
|
||||
};
|
||||
} else {
|
||||
} else if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_SHIFT) && !IsKeyDown(KEY_LEFT_ALT)) {
|
||||
midiNode->midi_velocity += wheel;
|
||||
if(midiNode->midi_velocity < 0 ) midiNode->midi_velocity = 127;
|
||||
if(midiNode->midi_velocity > 127 ) midiNode->midi_velocity = 0;
|
||||
} else if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_ALT)) {
|
||||
switch(app.settings.mode){
|
||||
case 0:{
|
||||
float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f);
|
||||
midiNode->midi_gate += incr;
|
||||
if(midiNode->midi_gate < 0 ) midiNode->midi_gate = 0;
|
||||
break;}
|
||||
case 1:{
|
||||
midiNode->midi_cc_value += wheel;
|
||||
if(midiNode->midi_cc_value < 0 ) midiNode->midi_cc_value = 0;
|
||||
if(midiNode->midi_cc_value > 127 ) midiNode->midi_cc_value = 127;
|
||||
break;}
|
||||
case 2:{
|
||||
float incr = (float)wheel * (IsKeyDown(KEY_LEFT_SHIFT) ? 100.0f : IsKeyDown(KEY_LEFT_CONTROL) ? 1000.0f : 10.0f);
|
||||
midiNode->midi_pitch_bend += incr;
|
||||
if(midiNode->midi_pitch_bend < 0 ) midiNode->midi_pitch_bend = 0;
|
||||
if(midiNode->midi_pitch_bend > 16383 ) midiNode->midi_pitch_bend = 16383;
|
||||
break;}
|
||||
};
|
||||
}
|
||||
}
|
||||
if(hovering_nodes.empty()){
|
||||
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
|
||||
camera.offset = GetMousePosition();
|
||||
camera.target = mouseWorldPos;
|
||||
@@ -362,7 +365,7 @@ int main(){
|
||||
}
|
||||
}
|
||||
|
||||
app.draw(&mouse_pos, &camera);
|
||||
app.draw(mouse_pos, camera);
|
||||
|
||||
EndMode2D();
|
||||
|
||||
|
||||
+14
-2
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "node.h"
|
||||
#include "raymath.h"
|
||||
#include <map>
|
||||
@@ -16,6 +17,11 @@ class MidiNode : public Node{
|
||||
|
||||
public:
|
||||
|
||||
MidiNode() {}
|
||||
MidiNode(Vec2D<float> position) : Node(position) {}
|
||||
|
||||
NodeType nodeType = NodeType::MIDINODE;
|
||||
|
||||
bool send_note = true;
|
||||
bool send_cc = false;
|
||||
bool send_pc = false;
|
||||
@@ -55,20 +61,26 @@ class MidiNode : public Node{
|
||||
float time = 0;
|
||||
float last = 0;
|
||||
|
||||
virtual NodeType getNodeType() override {return nodeType;}
|
||||
|
||||
void setMidiPort(int midi_port, bool state){
|
||||
midi_outs[midi_port].enabled = state;
|
||||
}
|
||||
|
||||
void trigger(){
|
||||
void trigger() override {
|
||||
triggered = true;
|
||||
start = GetTime();
|
||||
fade = midi_gate;
|
||||
}
|
||||
|
||||
void setMode(int _mode) override{
|
||||
void SMode(int _mode) override{
|
||||
mode = _mode;
|
||||
}
|
||||
|
||||
int Ggate(){
|
||||
return midi_gate;
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> mouse, Camera2D cam) override {
|
||||
last = time;
|
||||
time = GetTime();
|
||||
|
||||
@@ -32,6 +32,7 @@ class Movable{
|
||||
bool erase = false;
|
||||
|
||||
virtual void setPosition(Vec2D<float> _position) {position = _position;}
|
||||
virtual Vec2D<float> getPosition() {return position;};
|
||||
virtual void update(double frametime) {};
|
||||
virtual void update() {};
|
||||
};
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "node.h"
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class NodeManager{
|
||||
|
||||
public:
|
||||
NodeManager() {}
|
||||
|
||||
std::map<int, Node> nodes;
|
||||
std::vector<int> keys;
|
||||
int iterator = 0;
|
||||
|
||||
Node* node(int id){
|
||||
return &nodes.at(id);
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
+10
-2
@@ -15,7 +15,9 @@ class Node : public Movable, public GraphItem{
|
||||
Node(float x, float y) : Movable(Vec2D<float>(x, y), 0.0f) {}
|
||||
Node(Vec2D<float> p) : Movable(p, 0.0f) {}
|
||||
|
||||
Node *neighbor = nullptr;
|
||||
NodeType nodeType;
|
||||
|
||||
std::shared_ptr<Node> neighbor;
|
||||
|
||||
std::vector<std::shared_ptr<Edge>> connections;
|
||||
|
||||
@@ -24,5 +26,11 @@ class Node : public Movable, public GraphItem{
|
||||
float radius = 15.0f;
|
||||
bool config = false;
|
||||
|
||||
virtual void setMode(int mode) = 0;
|
||||
virtual NodeType getNodeType() {return nodeType;}
|
||||
|
||||
virtual void SMode(int mode) {};
|
||||
virtual int GGate() {return 0;};
|
||||
virtual int GActive() {return 0;};
|
||||
virtual void trigger() {};
|
||||
void draw(Vec2D<float> mouse_pos, Camera2D cam) {}
|
||||
};
|
||||
|
||||
+27
-24
@@ -2,10 +2,12 @@
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "graph-manager.h"
|
||||
#include "midi-node.h"
|
||||
#include "signal.h"
|
||||
#include "midi.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
class SignalManager{
|
||||
@@ -19,7 +21,7 @@ class SignalManager{
|
||||
std::mutex *mutex;
|
||||
GraphManager *gm;
|
||||
|
||||
std::vector<Signal> signals;
|
||||
std::vector<std::shared_ptr<Signal>> signals;
|
||||
|
||||
bool loop = true;
|
||||
bool play = false;
|
||||
@@ -39,9 +41,9 @@ class SignalManager{
|
||||
|
||||
void reset(){
|
||||
for(auto &s : signals){
|
||||
s.position = gm->node(s.start)->position + Vec2D<float>{0.1, 0.1};
|
||||
s.next = s.start;
|
||||
s.last = s.start;
|
||||
s->position = s->start->position + Vec2D<float>{0.1, 0.1};
|
||||
s->next = s->start;
|
||||
s->last = s->start;
|
||||
}
|
||||
gm->reset();
|
||||
}
|
||||
@@ -55,12 +57,12 @@ class SignalManager{
|
||||
loop = false;
|
||||
}
|
||||
|
||||
void addSignalAtNode(int node_id){
|
||||
void addSignalAtNode(std::shared_ptr<Node> node){
|
||||
Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200};
|
||||
signals.emplace(signals.end(), Signal(gm->node(node_id)->position.x+1, gm->node(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().last = node_id;
|
||||
signals.back().start = node_id;
|
||||
signals.emplace_back(std::make_shared<Signal>(node->position, 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 removeSignal(int n){
|
||||
@@ -75,22 +77,23 @@ class SignalManager{
|
||||
mutex->lock();
|
||||
if(play){
|
||||
for(auto& s : signals){
|
||||
s.direction = (gm->node(s.next)->position - s.position).norm();
|
||||
s.update(diff.count());
|
||||
if(s.position.dist(&gm->node(s.next)->position) < 0.6f) {
|
||||
int n = gm->next(s.next, s.last);
|
||||
gm->triggerNode(s.next);
|
||||
s->direction = (s->next->position - s->position).norm();
|
||||
s->update(diff.count());
|
||||
if(s->position.dist(s->next->position) < 0.6f) {
|
||||
std::shared_ptr<Node> next_node = gm->next(s->next, s->last);
|
||||
s->next->trigger();
|
||||
|
||||
if(n != s.next && n != -1) {
|
||||
for(auto &m : gm->node(s.next)->midi_outs){
|
||||
if(next_node != s->next && next_node != std::shared_ptr<Node>(nullptr) && s->next->getNodeType() == NodeType::MIDINODE) {
|
||||
auto midinode = std::dynamic_pointer_cast<MidiNode>(s->next);
|
||||
for(auto &m : midinode->midi_outs){
|
||||
if(m.second.enabled) {
|
||||
if(gm->node(s.next)->send_note) midi.note(m.second.i, gm->node(s.next)->midi_note_channel, gm->node(s.next)->midi_note, gm->node(s.next)->midi_velocity, gm->node(s.next)->midi_gate);
|
||||
if(gm->node(s.next)->send_cc) midi.cc(m.second.i, gm->node(s.next)->midi_cc_channel, gm->node(s.next)->midi_cc, gm->node(s.next)->midi_cc_value);
|
||||
if(gm->node(s.next)->send_pitch_bend) midi.pitch_bend(m.second.i, gm->node(s.next)->midi_pitch_bend_channel, gm->node(s.next)->midi_pitch_bend);
|
||||
if(midinode->send_note) midi.note(m.second.i, midinode->midi_note_channel, midinode->midi_note, midinode->midi_velocity, midinode->midi_gate);
|
||||
if(midinode->send_cc) midi.cc(m.second.i, midinode->midi_cc_channel, midinode->midi_cc, midinode->midi_cc_value);
|
||||
if(midinode->send_pitch_bend) midi.pitch_bend(m.second.i, midinode->midi_pitch_bend_channel, midinode->midi_pitch_bend);
|
||||
}
|
||||
}
|
||||
s.last = s.next;
|
||||
s.next = n;
|
||||
s->last = s->next;
|
||||
s->next = next_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,10 +105,10 @@ class SignalManager{
|
||||
}
|
||||
}
|
||||
|
||||
void drawSignals(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||
for(auto& s : signals){
|
||||
void drawSignals(Vec2D<float> mouse_pos, Camera2D camera){
|
||||
for(auto s : signals){
|
||||
mutex->lock();
|
||||
s.draw(mouse_pos, camera);
|
||||
s->draw(mouse_pos, camera);
|
||||
mutex->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
+8
-9
@@ -1,26 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <raylib.h>
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "moveable.h"
|
||||
#include "node.h"
|
||||
|
||||
class Signal : public Movable{
|
||||
public:
|
||||
|
||||
Signal();
|
||||
Signal(float x, float y, float r, float _speed, Color color) : Movable(Vec2D<float>(x, y), Vec2D<float>(0,0), _speed), radius(r), color(color) {}
|
||||
Signal(Vec2D<float> position, float r, float _speed, Color color) : Movable(position, Vec2D<float>(0,0), _speed), radius(r), color(color) {}
|
||||
|
||||
int id = 0;
|
||||
std::shared_ptr<Node> next;
|
||||
std::shared_ptr<Node> last;
|
||||
std::shared_ptr<Edge> edge;
|
||||
|
||||
int next;
|
||||
int last;
|
||||
|
||||
int start;
|
||||
std::shared_ptr<Node> start;
|
||||
|
||||
bool at_target = false;
|
||||
int target_node_id = 1;
|
||||
int source_node_id = 0;
|
||||
|
||||
float radius;
|
||||
|
||||
@@ -35,7 +34,7 @@ class Signal : public Movable{
|
||||
position += direction.norm() * speed * multiplier * (float)t_delta / 1000000.0f;
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> *mouse, Camera2D *cam) {
|
||||
void draw(Vec2D<float> mouse, Camera2D cam) {
|
||||
DrawCircle(position.x, position.y, radius, color);
|
||||
}
|
||||
};
|
||||
|
||||
+47
-56
@@ -3,11 +3,13 @@
|
||||
#include "edge.h"
|
||||
#include "datatypes.h"
|
||||
#include "graph-manager.h"
|
||||
#include "midi-node.h"
|
||||
#include "signal-manager.h"
|
||||
#include "ui.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
@@ -30,100 +32,89 @@ class AppState{
|
||||
AppUI ui;
|
||||
|
||||
void updateMidiPorts(){
|
||||
for(auto&n : gm.nodes | std::views::values){
|
||||
for(auto&n : gm.nodes | std::ranges::views::filter([](std::shared_ptr<Node> n){return n->getNodeType() == NodeType::MIDINODE;})){
|
||||
auto nc = std::dynamic_pointer_cast<MidiNode>(n);
|
||||
for(auto& mo : sm.midi.midi_out_ports){
|
||||
if(!n.midi_outs.contains(mo.number) && mo.enabled){
|
||||
n.midi_outs[mo.number] = {mo.number, mo.port.port_name, false};
|
||||
if(!nc->midi_outs.contains(mo.number) && mo.enabled){
|
||||
nc->midi_outs[mo.number] = {mo.number, mo.port.port_name, false};
|
||||
}
|
||||
if(n.midi_outs.contains(mo.number) && !mo.enabled){
|
||||
n.midi_outs.erase(mo.number);
|
||||
if(nc->midi_outs.contains(mo.number) && !mo.enabled){
|
||||
nc->midi_outs.erase(mo.number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void copyNodesAndConnections(Vec2D<float> position){
|
||||
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>>();
|
||||
void copyNodesAndConnections(std::vector<std::shared_ptr<Node>> nodes, Vec2D<float> position){
|
||||
|
||||
std::vector<Edge> copy_connections;
|
||||
std::ranges::copy_if(gm.connections, std::back_inserter(copy_connections), [copy_nodes_ids](Edge c){return std::ranges::contains(copy_nodes_ids, c.node_id_start) && std::ranges::contains(copy_nodes_ids, c.node_id_end);});
|
||||
std::vector<std::shared_ptr<Edge>> copy_connections;
|
||||
for(auto n : nodes){
|
||||
std::ranges::copy_if(n->connections.begin(), n->connections.end(), std::back_inserter(copy_connections), [nodes](std::shared_ptr<Edge> e){ return std::ranges::contains(nodes, e->start) && std::ranges::contains(nodes, e->end);});
|
||||
}
|
||||
|
||||
for(auto &n : copy_nodes_ids){
|
||||
int old_id = n;
|
||||
int new_id = gm.copyNode(n, position + gm.nodes[n].drag_offset);
|
||||
gm.nodes[new_id].copied = false;
|
||||
gm.nodes[new_id].selected = true;
|
||||
for(auto n : nodes){
|
||||
std::shared_ptr<Node> old_node = n;
|
||||
std::shared_ptr<Node> new_node = gm.copyNode(n, position + n->drag_offset);
|
||||
new_node->copied = false;
|
||||
new_node->selected = true;
|
||||
|
||||
for(auto &c : copy_connections){
|
||||
if(c.node_id_start == old_id) c.node_id_start = new_id;
|
||||
if(c.node_id_end == old_id) c.node_id_end = new_id;
|
||||
if(c->start == old_node) c->start = new_node;
|
||||
if(c->end == old_node) c->end = new_node;
|
||||
}
|
||||
}
|
||||
|
||||
gm.connections.insert(gm.connections.end(), copy_connections.cbegin(), copy_connections.cend());
|
||||
gm.edges.insert(gm.edges.end(), copy_connections.cbegin(), copy_connections.cend());
|
||||
}
|
||||
|
||||
void removeNodes(){
|
||||
void removeNodes(std::vector<std::shared_ptr<Node>> nodes){
|
||||
|
||||
for(auto &n : gm.nodes){
|
||||
n.second.highlighted = false;
|
||||
for(auto n : gm.nodes){
|
||||
n->highlighted = false;
|
||||
}
|
||||
|
||||
auto erase_nodes = gm.nodes | std::ranges::views::values | std::ranges::views::filter([](Node n){return n.erase;});
|
||||
auto erase_connections = gm.edges | std::ranges::views::filter([nodes](std::shared_ptr<Edge> c){ return std::ranges::contains(nodes, c->start) || std::ranges::contains(nodes, c->end);});
|
||||
|
||||
std::vector<int> erase_nodes_ids;
|
||||
for(auto &e : erase_nodes){
|
||||
erase_nodes_ids.push_back(e.id);
|
||||
std::vector<std::shared_ptr<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);
|
||||
}
|
||||
|
||||
auto erase_connections = gm.connections | std::ranges::views::filter([erase_nodes_ids](Edge c){ return std::ranges::contains(erase_nodes_ids, c.node_id_start) || std::ranges::contains(erase_nodes_ids, c.node_id_end);});
|
||||
auto reroute_signals = sm.signals | std::ranges::views::filter([nodes](std::shared_ptr<Signal> s){return std::ranges::contains(nodes, s->next);});
|
||||
|
||||
std::vector<int> adjacent_nodes_ids;
|
||||
|
||||
for(auto &c : erase_connections){
|
||||
if(!gm.nodes.at(c.node_id_start).selected) adjacent_nodes_ids.push_back(c.node_id_start);
|
||||
if(!gm.nodes.at(c.node_id_end).selected) adjacent_nodes_ids.push_back(c.node_id_end);
|
||||
}
|
||||
|
||||
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){
|
||||
for(auto s : reroute_signals){
|
||||
float dist = 10000000;
|
||||
int next_id = -1;
|
||||
for(int i : adjacent_nodes_ids){
|
||||
if(gm.nodes.at(i).position.dist(&s.position) < dist) {
|
||||
dist = gm.nodes.at(i).position.dist(&s.position);
|
||||
next_id = i;
|
||||
std::shared_ptr<Node> next_node;
|
||||
for(auto n : adjacent_nodes){
|
||||
if(n->position.dist(s->position) < dist) {
|
||||
dist = n->position.dist(s->position);
|
||||
next_node = n;
|
||||
}
|
||||
}
|
||||
s.next = next_id;
|
||||
s.last = next_id;
|
||||
s->next = next_node;
|
||||
s->last = next_node;
|
||||
}
|
||||
|
||||
auto rebase_signals = sm.signals | std::ranges::views::filter([erase_nodes_ids](Signal s){
|
||||
return std::ranges::contains(erase_nodes_ids, s.start);
|
||||
});
|
||||
auto rebase_signals = sm.signals | std::ranges::views::filter([nodes](std::shared_ptr<Signal> s){return std::ranges::contains(nodes, s->start);});
|
||||
|
||||
for(auto &s : rebase_signals){
|
||||
s.start = s.next;
|
||||
for(auto s : rebase_signals){
|
||||
s->start = s->next;
|
||||
}
|
||||
|
||||
for(auto &n : erase_nodes){
|
||||
std::erase_if(gm.connections, [n](Edge c){ return c.node_id_start == n.id || c.node_id_end == n.id;});
|
||||
for(auto n : nodes){
|
||||
std::erase_if(gm.edges, [n](std::shared_ptr<Edge> c){ return c->start == n || c->end == n;});
|
||||
}
|
||||
std::erase_if(gm.nodes, [](std::pair<int, Node> n){ return n.second.erase;});
|
||||
gm.keys.clear();
|
||||
std::ranges::copy(gm.nodes | std::ranges::views::keys, std::back_inserter(gm.keys));
|
||||
std::erase_if(gm.nodes, [nodes](std::shared_ptr<Node> n){ return std::ranges::contains(nodes, n);});
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||
void draw(Vec2D<float> mouse_pos, Camera2D camera){
|
||||
mutex.lock();
|
||||
updateMidiPorts();
|
||||
mutex.unlock();
|
||||
gm.drawNodes(mouse_pos, camera);
|
||||
gm.drawConnections(mouse_pos, camera);
|
||||
gm.drawEdges(mouse_pos, camera);
|
||||
sm.drawSignals(mouse_pos, camera);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "midi-node.h"
|
||||
#include "raylib.h"
|
||||
#include "raygui/raygui.h"
|
||||
#include "raygui/dark/style_dark.h"
|
||||
@@ -8,6 +9,7 @@
|
||||
#include "graph-manager.h"
|
||||
#include "signal-manager.h"
|
||||
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
|
||||
class AppUI{
|
||||
@@ -52,8 +54,8 @@ class AppUI{
|
||||
if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) {
|
||||
for(auto &midis : sm->midi.midi_out_ports){
|
||||
if(midis.enabled){
|
||||
for(auto &n : gm->nodes){
|
||||
n.second.setMidiPort(midis.number, true);
|
||||
for(auto n : gm->nodes){
|
||||
if(n->getNodeType() == NodeType::MIDINODE) std::dynamic_pointer_cast<MidiNode>(n)->setMidiPort(midis.number, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,114 +64,117 @@ class AppUI{
|
||||
int s_signal = s_midi + 100 + i*20;
|
||||
GuiLabel((Rectangle){20, (float)s_signal, 240, 20}, "SIGNALS");
|
||||
if(GuiButton((Rectangle){20, (float)s_signal + 35, 240, 20}, "ADD RANDOM SIGNAL")){
|
||||
int ni = gm->getRandomNode();
|
||||
std::shared_ptr<Node> ni = gm->getRandomNode();
|
||||
sm->addSignalAtNode(ni);
|
||||
}
|
||||
|
||||
int signal_configs = 0;
|
||||
for(auto &s : sm->signals){
|
||||
if(GuiButton((Rectangle){20,(float)s_signal+70 + signal_configs*20, 20, 20},"X")) sm->removeSignal(signal_configs);
|
||||
DrawCircle(55, s_signal+80 + signal_configs*20, 6.0F, s.color);
|
||||
float s_multiplier = round(s.multiplier*10.0f)/10.0f;
|
||||
float signal_bpm = settings->bpm * s.multiplier;
|
||||
DrawCircle(55, s_signal+80 + signal_configs*20, 6.0F, s->color);
|
||||
float s_multiplier = round(s->multiplier*10.0f)/10.0f;
|
||||
float signal_bpm = settings->bpm * s->multiplier;
|
||||
GuiSlider((Rectangle){70, (float)s_signal+70 + signal_configs*20, 160, 20}, "", std::format("{:.1f}",signal_bpm).c_str(), &s_multiplier, 0.1, 10);
|
||||
s.multiplier = s_multiplier;
|
||||
s.speed = settings->speed;
|
||||
s->multiplier = s_multiplier;
|
||||
s->speed = settings->speed;
|
||||
signal_configs++;
|
||||
}
|
||||
|
||||
int s_nodes = s_signal + 70 + signal_configs*20;
|
||||
GuiLabel((Rectangle){20, (float)s_nodes + 30, 240, 20}, "NODES");
|
||||
if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){
|
||||
gm->addNode(200.0f, 200.0f);
|
||||
gm->addMidiNode(Vec2D<float>{200.0f, 200.0f});
|
||||
}
|
||||
DrawText(std::format("{}", gm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE);
|
||||
DrawFPS(20, settings->height - 30);
|
||||
}
|
||||
|
||||
void drawPerNodeConfig(Camera2D *camera){
|
||||
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);
|
||||
for(auto& n : gm->nodes | std::views::filter([](std::shared_ptr<Node> n){ return n->config; })){
|
||||
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");
|
||||
|
||||
int option = n.distributionMode;
|
||||
int option = n->distributionMode;
|
||||
GuiToggleGroup((Rectangle){ np.x + 20, np.y + 40, 73, 20 }, "GEO;RR;RAND", &option);
|
||||
n.distributionMode = (Distribution)option;
|
||||
n->distributionMode = (Distribution)option;
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + 65, 220, 20}, "SIGNALS");
|
||||
if(GuiButton((Rectangle){np.x + 20, np.y + 90, 220, 20}, "ADD SIGNAL")){
|
||||
sm->addSignalAtNode(n.id);
|
||||
sm->addSignalAtNode(n);
|
||||
}
|
||||
|
||||
int y_midi = 120;
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_midi, 220, 20}, "MIDI OUT");
|
||||
|
||||
int i = 0;
|
||||
for(auto& mo : n.midi_outs){
|
||||
GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled);
|
||||
i++;
|
||||
}
|
||||
if(n->getNodeType() == NodeType::MIDINODE){
|
||||
std::shared_ptr<MidiNode> mn = std::dynamic_pointer_cast<MidiNode>(n);
|
||||
for(auto& mo : mn->midi_outs){
|
||||
GuiCheckBox((Rectangle){np.x + 20, np.y + y_midi + 20 + i*20.0f, 20, 20}, mo.second.name.c_str(), &mo.second.enabled);
|
||||
i++;
|
||||
}
|
||||
|
||||
int y_channel = y_midi + 30 + i*20;
|
||||
GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &n.send_note);
|
||||
GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &n.send_cc);
|
||||
GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH", &n.send_pitch_bend);
|
||||
int y_channel = y_midi + 30 + i*20;
|
||||
GuiCheckBox((Rectangle){np.x + 20, np.y + y_channel, 20, 20}, "NOTE", &mn->send_note);
|
||||
GuiCheckBox((Rectangle){np.x + 90, np.y + y_channel, 20, 20}, "CC", &mn->send_cc);
|
||||
GuiCheckBox((Rectangle){np.x + 160, np.y + y_channel, 20, 20}, "PITCH", &mn->send_pitch_bend);
|
||||
|
||||
int y_cc_note = y_channel + 120;
|
||||
switch(settings->mode){
|
||||
case 0:{
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL");
|
||||
GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &n.midi_note_channel);
|
||||
int y_cc_note = y_channel + 120;
|
||||
switch(settings->mode){
|
||||
case 0:{
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "NOTE CHANNEL");
|
||||
GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_note_channel);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE");
|
||||
float v = n.midi_note;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, sm->midi.midiNotes[(int)round(v)].c_str());
|
||||
GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",n.midi_note).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127);
|
||||
n.midi_note = round(v);
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "NOTE");
|
||||
float v = mn->midi_note;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note , 20, 20}, sm->midi.midiNotes[(int)round(v)].c_str());
|
||||
GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_note).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127);
|
||||
mn->midi_note = round(v);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "VELOCITY");
|
||||
v = n.midi_velocity;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",n.midi_velocity).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127);
|
||||
n.midi_velocity = round(v);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 120, 100, 20}, "GATE");
|
||||
v = n.midi_gate;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 120, 20, 20}, std::format("{}",(float)n.midi_gate/1000.0f).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 150, 220, 20}, "", "", &v, 0, 30000);
|
||||
n.midi_gate = round(v);
|
||||
break;}
|
||||
case 1:
|
||||
{
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "CC CHANNEL");
|
||||
GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &n.midi_cc_channel);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC");
|
||||
float v = n.midi_cc;
|
||||
GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",n.midi_cc).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127);
|
||||
n.midi_cc = round(v);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "CC VALUE");
|
||||
v = n.midi_cc_value;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",n.midi_cc_value).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127);
|
||||
n.midi_cc_value = round(v);
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "VELOCITY");
|
||||
v = mn->midi_velocity;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_velocity).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127);
|
||||
mn->midi_velocity = round(v);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 120, 100, 20}, "GATE");
|
||||
v = mn->midi_gate;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 120, 20, 20}, std::format("{}",(float)mn->midi_gate/1000.0f).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 150, 220, 20}, "", "", &v, 0, 30000);
|
||||
mn->midi_gate = round(v);
|
||||
break;}
|
||||
case 2:
|
||||
{
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "PITCH BEND CHANNEL");
|
||||
GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &n.midi_pitch_bend_channel);
|
||||
case 1:
|
||||
{
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "CC CHANNEL");
|
||||
GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_cc_channel);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC");
|
||||
float v = n.midi_pitch_bend;
|
||||
GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",n.midi_pitch_bend).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383);
|
||||
n.midi_pitch_bend = round(v);
|
||||
break;}
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC");
|
||||
float v = mn->midi_cc;
|
||||
GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_cc).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 127);
|
||||
mn->midi_cc = round(v);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note + 60, 100, 20}, "CC VALUE");
|
||||
v = mn->midi_cc_value;
|
||||
GuiLabel((Rectangle){np.x + 210, np.y + y_cc_note + 60, 20, 20}, std::format("{}",mn->midi_cc_value).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 90, 220, 20}, "", "", &v, 0, 127);
|
||||
mn->midi_cc_value = round(v);
|
||||
|
||||
break;}
|
||||
case 2:
|
||||
{
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note - 75, 220, 20}, "PITCH BEND CHANNEL");
|
||||
GuiToggleGroup((Rectangle){np.x + 20, np.y + y_cc_note - 50, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &mn->midi_pitch_bend_channel);
|
||||
|
||||
GuiLabel((Rectangle){np.x + 20, np.y + y_cc_note , 100, 20}, "CC");
|
||||
float v = mn->midi_pitch_bend;
|
||||
GuiLabel((Rectangle){np.x + 160, np.y + y_cc_note , 40, 20}, std::format("{}",mn->midi_pitch_bend).c_str());
|
||||
GuiSlider((Rectangle){np.x + 20, np.y + y_cc_note + 30, 220, 20}, "", "", &v, 0, 16383);
|
||||
mn->midi_pitch_bend = round(v);
|
||||
break;}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user