polar snapping now very goood!
This commit is contained in:
@@ -25,6 +25,27 @@
|
|||||||
|
|
||||||
enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM};
|
enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM};
|
||||||
|
|
||||||
|
// Types
|
||||||
|
|
||||||
|
class GraphItem;
|
||||||
|
class Node;
|
||||||
|
class Edge;
|
||||||
|
class Signal;
|
||||||
|
|
||||||
|
#define RANGE_FILTER(L) std::ranges::views::filter(L)
|
||||||
|
|
||||||
|
typedef std::shared_ptr<GraphItem> SPTR_GraphItem;
|
||||||
|
typedef std::shared_ptr<Node> SPTR_Node;
|
||||||
|
typedef std::shared_ptr<Edge> SPTR_Edge;
|
||||||
|
|
||||||
|
typedef std::shared_ptr<Signal> SPTR_Signal;
|
||||||
|
|
||||||
|
typedef std::vector<SPTR_GraphItem> VEC_SPTR_GraphItem;
|
||||||
|
typedef std::vector<SPTR_Node> VEC_SPTR_Node;
|
||||||
|
typedef std::vector<SPTR_Edge> VEC_SPTR_Edge;
|
||||||
|
typedef std::vector<SPTR_Signal> VEC_SPTR_Signal;
|
||||||
|
|
||||||
|
|
||||||
// 2D Vectors
|
// 2D Vectors
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -155,6 +176,16 @@ Vec2D<T> operator*(const Vec2D<T> left, T scalar){
|
|||||||
return Vec2D<T>(left.x * scalar, left.y * scalar);
|
return Vec2D<T>(left.x * scalar, left.y * scalar);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Vec2D<T> cartesianToPolar(T x, T y) {
|
||||||
|
return Vec2D<T>{sqrt(x * x + y * y), atan(y / x)}; // r,theta
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Vec2D<T> polarToCartesian(T r, T q) {
|
||||||
|
return Vec2D<T>{r * cos(q), r * sin(q)};
|
||||||
|
}
|
||||||
|
|
||||||
// App Settings
|
// App Settings
|
||||||
struct AppSettings{
|
struct AppSettings{
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
|
|||||||
+10
-8
@@ -1,24 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
#include "graph-item.h"
|
#include "graph-item.h"
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class Node;
|
|
||||||
|
|
||||||
class Edge : public GraphItem{
|
class Edge : public GraphItem{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Edge() {}
|
Edge() {}
|
||||||
Edge(std::shared_ptr<Node> start, std::shared_ptr<Node> end) : start(start), end(end) {}
|
Edge(SPTR_Node start, SPTR_Node end) : start(start), end(end) {}
|
||||||
|
|
||||||
std::shared_ptr<Node> start;
|
SPTR_Node start;
|
||||||
std::shared_ptr<Node> end;
|
SPTR_Node end;
|
||||||
|
|
||||||
bool pass_forward = true;
|
bool pass_forward = true;
|
||||||
bool pass_backward = true;
|
bool pass_backward = true;
|
||||||
|
|
||||||
bool active = false;
|
bool active = false;
|
||||||
bool remove = false;
|
|
||||||
bool config = false;
|
bool config = false;
|
||||||
bool split = false;
|
bool split = false;
|
||||||
|
|
||||||
@@ -27,11 +24,16 @@ class Edge : public GraphItem{
|
|||||||
|
|
||||||
virtual bool GActive() {return active;}
|
virtual bool GActive() {return active;}
|
||||||
|
|
||||||
std::shared_ptr<Node> getNextNode(std::shared_ptr<Node> origin){
|
SPTR_Node getNextNode(SPTR_Node origin){
|
||||||
return start == origin ? end : start;
|
return start == origin ? end : start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Vec2D<float> mouse_pos, Camera2D cam) {
|
void draw(Vec2D<float> mouse_pos, Camera2D cam) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remove(){
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
+79
-59
@@ -1,14 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "button.h"
|
|
||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
|
#include "raylib.h"
|
||||||
|
#include "raymath.h"
|
||||||
|
|
||||||
|
#include "button.h"
|
||||||
#include "graph-item.h"
|
#include "graph-item.h"
|
||||||
#include "midi-node.h"
|
#include "midi-node.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "edge.h"
|
#include "edge.h"
|
||||||
#include "raymath.h"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <cstdio>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -22,24 +26,26 @@ class GraphManager{
|
|||||||
|
|
||||||
GraphManager() {}
|
GraphManager() {}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Node>> nodes;
|
VEC_SPTR_Node nodes;
|
||||||
std::vector<std::shared_ptr<Edge>> edges;
|
VEC_SPTR_Edge edges;
|
||||||
|
|
||||||
std::map<std::shared_ptr<Node>, int> counter;
|
VEC_SPTR_Edge remove_edges;
|
||||||
|
|
||||||
std::shared_ptr<Node> getRandomNode(){
|
std::map<SPTR_Node, int> counter;
|
||||||
std::vector<std::shared_ptr<GraphItem>> o;
|
|
||||||
|
SPTR_Node getRandomNode(){
|
||||||
|
VEC_SPTR_GraphItem o;
|
||||||
std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
||||||
return std::dynamic_pointer_cast<Node>(o.front());
|
return std::dynamic_pointer_cast<Node>(o.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Edge> getRandomEdge(){
|
SPTR_Edge getRandomEdge(){
|
||||||
std::vector<std::shared_ptr<GraphItem>> o;
|
VEC_SPTR_GraphItem o;
|
||||||
std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
std::ranges::sample(edges, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
||||||
return std::dynamic_pointer_cast<Edge>(o.front());
|
return std::dynamic_pointer_cast<Edge>(o.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyNodes(std::vector<std::shared_ptr<Node>> nodes, Vec2D<float> position){
|
void copyNodes(VEC_SPTR_Node nodes, Vec2D<float> position){
|
||||||
for(auto n: nodes){
|
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->position = position + nc->drag_offset;
|
||||||
@@ -57,7 +63,7 @@ class GraphManager{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> copyNode(std::shared_ptr<Node> n, Vec2D<float> position){
|
SPTR_Node copyNode(SPTR_Node n, Vec2D<float> position){
|
||||||
auto nc = std::make_shared<Node>(*n);
|
auto nc = std::make_shared<Node>(*n);
|
||||||
nc->setPosition(position);
|
nc->setPosition(position);
|
||||||
nodes.push_back(nc);
|
nodes.push_back(nc);
|
||||||
@@ -71,16 +77,7 @@ class GraphManager{
|
|||||||
return nc;
|
return nc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*std::shared_ptr<Node> addNode(float x, float y){*/
|
SPTR_Node addMidiNode(Vec2D<float> position){
|
||||||
/* 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));
|
nodes.emplace_back(std::make_shared<MidiNode>(position));
|
||||||
return nodes.back();
|
return nodes.back();
|
||||||
}
|
}
|
||||||
@@ -95,12 +92,12 @@ class GraphManager{
|
|||||||
counter.clear();
|
counter.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Node> next(std::shared_ptr<Node> current, std::shared_ptr<Node> last){
|
SPTR_Node next(SPTR_Node current, SPTR_Node last){
|
||||||
std::vector<std::shared_ptr<Edge>> possible_connections = current->connections | std::ranges::views::filter([current](std::shared_ptr<Edge> c){
|
VEC_SPTR_Edge possible_connections = current->connections | RANGE_FILTER([current](SPTR_Edge c){
|
||||||
return (c->start == current && c->pass_forward) || (c->end == current && c->pass_backward);
|
return (c->start == current && c->pass_forward) || (c->end == current && c->pass_backward);
|
||||||
}) | std::ranges::to<std::vector<std::shared_ptr<Edge>>>();
|
}) | std::ranges::to<VEC_SPTR_Edge>();
|
||||||
|
|
||||||
if(possible_connections.empty()) return std::shared_ptr<Node>(nullptr);
|
if(possible_connections.empty()) return SPTR_Node(nullptr);
|
||||||
|
|
||||||
int return_path = 0;
|
int return_path = 0;
|
||||||
float angle = -1;
|
float angle = -1;
|
||||||
@@ -108,7 +105,7 @@ class GraphManager{
|
|||||||
Vec2D<float> coming_from = (current->position - last->position).norm();
|
Vec2D<float> coming_from = (current->position - last->position).norm();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(auto n : possible_connections){
|
for(auto n : possible_connections){
|
||||||
std::shared_ptr<Node> next_node = n->getNextNode(current);
|
SPTR_Node next_node = n->getNextNode(current);
|
||||||
float angle_v1_v2 = coming_from.norm().dot((next_node->position - current->position).norm());
|
float angle_v1_v2 = coming_from.norm().dot((next_node->position - current->position).norm());
|
||||||
if(angle_v1_v2 > angle) {
|
if(angle_v1_v2 > angle) {
|
||||||
return_path = i;
|
return_path = i;
|
||||||
@@ -131,11 +128,11 @@ class GraphManager{
|
|||||||
return_path = rand() % possible_connections.size();
|
return_path = rand() % possible_connections.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
possible_connections.at(return_path)->active = true;
|
//possible_connections.at(return_path)->active = true;
|
||||||
return possible_connections.at(return_path)->getNextNode(current);
|
return possible_connections.at(return_path)->getNextNode(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConnection(std::shared_ptr<Node> from, std::shared_ptr<Node> to){
|
void addConnection(SPTR_Node from, SPTR_Node to){
|
||||||
edges.emplace_back(std::make_shared<Edge>());
|
edges.emplace_back(std::make_shared<Edge>());
|
||||||
edges.back()->start = from;
|
edges.back()->start = from;
|
||||||
edges.back()->end = to;
|
edges.back()->end = to;
|
||||||
@@ -143,8 +140,25 @@ class GraphManager{
|
|||||||
to->connections.push_back(edges.back());
|
to->connections.push_back(edges.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void splitEdge(SPTR_Edge edge){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeEdge(SPTR_Edge edge){
|
||||||
|
remove_edges.push_back(edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeEdges(){
|
||||||
|
for(auto edge : remove_edges){
|
||||||
|
std::erase(edge->start->connections, edge);
|
||||||
|
std::erase(edge->end->connections, edge);
|
||||||
|
std::erase(edges, edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void drawEdges(Vec2D<float> mouse_pos, Camera2D cam){
|
void drawEdges(Vec2D<float> mouse_pos, Camera2D cam){
|
||||||
// std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
// std::erase_if(connections, [](Connection c){ return c.remove == true;});
|
||||||
|
if(!remove_edges.empty()) removeEdges();
|
||||||
for(auto& c : edges){
|
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> 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);
|
Vec2D<float> v2_position = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->connector_offset);
|
||||||
@@ -179,55 +193,61 @@ class GraphManager{
|
|||||||
unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f);
|
unsigned char opacity_from = 250.0f - Clamp(from_to_handle.dist(mouse_pos), 0.0f, 220.0f);
|
||||||
unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f);
|
unsigned char opacity_to = 250.0f - Clamp(to_from_handle.dist(mouse_pos), 0.0f, 220.0f);
|
||||||
|
|
||||||
// On/Off switches on both sides
|
if(!c->start->dragging && !c->end->dragging){
|
||||||
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;
|
// On/Off switches on both sides
|
||||||
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(ViButton(mouse_pos, from_to_handle.x, from_to_handle.y, 8.0f, c->pass_forward ? (Color){120, 210, 115, opacity_from} : (Color){232, 50, 32, opacity_from} )) c->pass_forward = !c->pass_forward;
|
||||||
|
if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c->pass_backward ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c->pass_backward = !c->pass_backward;
|
||||||
|
|
||||||
if(!c->pass_forward){
|
if(!c->pass_forward){
|
||||||
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle;
|
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;
|
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});
|
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from});
|
||||||
|
}
|
||||||
|
|
||||||
|
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} )) removeEdge(c);
|
||||||
|
if(ViButton(mouse_pos, flip_handle_2.x, flip_handle_2.y, 8.0f, (Color){232, 125, 62, opacity} )) splitEdge(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawNodes(Vec2D<float> mouse_pos, Camera2D camera){
|
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>>>();
|
auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->dragging && !n->selected;}) | std::ranges::to<VEC_SPTR_Node>();
|
||||||
float min_d = 480;
|
float min_d = 480;
|
||||||
for(auto n : nodes){
|
for(auto n : nodes){
|
||||||
if(n->dragging){
|
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);});
|
std::sort(neighbors.begin(), neighbors.end(), [n, mouse_pos](SPTR_Node na, SPTR_Node nb){ return na->position.dist(mouse_pos) < nb->position.dist(mouse_pos);});
|
||||||
if(neighbors.size() > 1){
|
if(neighbors.size() > 1){
|
||||||
min_d = neighbors.front()->position.dist(n->position);
|
min_d = neighbors.front()->position.dist(mouse_pos);
|
||||||
n->neighbor = neighbors.at(1);
|
n->neighbor = neighbors.front();
|
||||||
int i = 0;
|
DrawCircleLinesV(n->neighbor->position, 20.0f, VS_COLOR_PINK);
|
||||||
for(auto nb : neighbors){
|
for(auto nb : neighbors){
|
||||||
float d = nb->position.dist(n->position);
|
float d = nb->position.dist(mouse_pos);
|
||||||
|
float dn = nb->position.dist(n->position);
|
||||||
if(d > 0 && d < min_d*1.5 && d < 960) {
|
if(d > 0 && d < min_d*1.5 && d < 960) {
|
||||||
std::string frac = MIDI::Fractions.at((int)Clamp(round(d/60) - 1, 0, 31));
|
std::string frac = MIDI::Fractions.at((int)Clamp(round(dn/60) - 1, 0, 31));
|
||||||
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",d).c_str(), 10.0f, 2.0f);
|
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",dn).c_str(), 10.0f, 2.0f);
|
||||||
Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f);
|
Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f);
|
||||||
|
|
||||||
Vec2D<float> middle_handle = nb->position + (n->position - nb->position) * ((d - text_length.x)*0.5f)/d;
|
Vec2D<float> middle_handle = nb->position + (n->position - nb->position) * ((dn - text_length.x)*0.5f)/dn;
|
||||||
Vec2D<float> middle_handle_frac = nb->position + (n->position - nb->position) * ((d - text_length_frac.x)*0.5f)/d;
|
Vec2D<float> middle_handle_frac = nb->position + (n->position - nb->position) * ((dn - text_length_frac.x)*0.5f)/dn;
|
||||||
Vec2D<float> text_position = middle_handle + (nb->position - n->position).norm().orth() * 12.0f;
|
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;
|
Vec2D<float> text_position_frac = middle_handle_frac - (nb->position - n->position).norm().orth() * 4.0f;
|
||||||
|
|
||||||
float rotation = Vector2Angle((Vector2){1,0}, (n->position - nb->position)) * RAD2DEG;
|
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);
|
DrawTextPro(GetFontDefault(), std::format("{:.1f}",dn).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);
|
if(nb == neighbors.front() && 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, nb->position, VS_COLOR_PINK);
|
Vec2D<float> n_position = n->position - ((n->position - nb->position)).norm() * 20.0f;
|
||||||
|
Vec2D<float> nb_position = nb->position - ((nb->position - n->position)).norm() * 20.0f;
|
||||||
|
DrawLineV(n_position, nb_position, VS_COLOR_PINK);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-19
@@ -38,8 +38,7 @@ int main(){
|
|||||||
|
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
|
InitWindow(1920, 1080, "VISEQ - The Visual Sequencer");
|
||||||
InitWindow(1920, 1080, "VISEQ");
|
|
||||||
|
|
||||||
int current_monitor = GetCurrentMonitor();
|
int current_monitor = GetCurrentMonitor();
|
||||||
int monitor_width = GetMonitorWidth(current_monitor);
|
int monitor_width = GetMonitorWidth(current_monitor);
|
||||||
@@ -71,10 +70,10 @@ int main(){
|
|||||||
camera.zoom = 1.0f;
|
camera.zoom = 1.0f;
|
||||||
|
|
||||||
for(int i = 0; i < 4; ++i){
|
for(int i = 0; i < 4; ++i){
|
||||||
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 5 * app.settings.grid, 5 * app.settings.grid*4});
|
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 2 * app.settings.grid*4});
|
||||||
}
|
}
|
||||||
for(int i = 3; i >= 0; --i){
|
for(int i = 3; i >= 0; --i){
|
||||||
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 5 * app.settings.grid, 6 * app.settings.grid*4});
|
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 3 * app.settings.grid*4});
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 8; ++i){
|
for(int i = 0; i < 8; ++i){
|
||||||
@@ -92,7 +91,7 @@ int main(){
|
|||||||
Vec2D<float> select_start;
|
Vec2D<float> select_start;
|
||||||
Rectangle selection;
|
Rectangle selection;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Node>> copied_nodes;
|
VEC_SPTR_Node copied_nodes;
|
||||||
|
|
||||||
while(!WindowShouldClose()){
|
while(!WindowShouldClose()){
|
||||||
|
|
||||||
@@ -117,11 +116,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.gm.nodes | std::ranges::views::filter([](std::shared_ptr<Node> n) { return n->dragging;});
|
auto dragging_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->dragging;});
|
||||||
auto connecting_nodes = app.gm.nodes | std::ranges::views::filter([](std::shared_ptr<Node> n) { return n->connecting;});
|
auto connecting_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_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 selected_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->selected && !n->dragging;}) | std::ranges::to<VEC_SPTR_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_nodes = app.gm.nodes | RANGE_FILTER([&mouse_pos](SPTR_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 hovering_connectors = app.gm.nodes | RANGE_FILTER([&mouse_pos](SPTR_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 ){
|
for(auto &n : app.gm.nodes ){
|
||||||
if(hovering_nodes.empty()) n->hovering = false;
|
if(hovering_nodes.empty()) n->hovering = false;
|
||||||
@@ -206,23 +205,29 @@ int main(){
|
|||||||
case InteractionState::DRAG_NODE:
|
case InteractionState::DRAG_NODE:
|
||||||
{
|
{
|
||||||
if(!dragging_nodes.empty()){
|
if(!dragging_nodes.empty()){
|
||||||
|
SPTR_Node dragNode = dragging_nodes.front();
|
||||||
|
|
||||||
for(auto &n : selected_nodes){
|
for(auto &n : selected_nodes){
|
||||||
if(!n->picked_up) n->drag_offset = n->position - dragging_nodes.front()->position;
|
if(!n->picked_up) n->drag_offset = n->position - dragNode->position;
|
||||||
n->picked_up = true;
|
n->picked_up = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsKeyDown(KEY_LEFT_CONTROL)) {
|
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};
|
dragNode->position.x = round((mouse_pos.x + dragNode->drag_offset.x) / app.settings.grid) * app.settings.grid;
|
||||||
|
dragNode->position.y = round((mouse_pos.y + dragNode->drag_offset.y) / app.settings.grid) * app.settings.grid;
|
||||||
} else if(IsKeyDown(KEY_LEFT_SHIFT)){
|
} else if(IsKeyDown(KEY_LEFT_SHIFT)){
|
||||||
float steps = round(dragging_nodes.front()->neighbor->position.dist(mouse_pos) / app.settings.grid) * app.settings.grid;
|
float steps = round((dragNode->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;
|
float pol_r = steps;
|
||||||
dragging_nodes.front()->position = polar;
|
float pol_theta = Vector2Angle(Vec2D<float>{1,0},(mouse_pos - dragNode->neighbor->position));
|
||||||
|
|
||||||
|
Vec2D<float> polar = polarToCartesian(pol_r, pol_theta);
|
||||||
|
dragNode->position = dragNode->neighbor->position + polar;
|
||||||
} else {
|
} else {
|
||||||
dragging_nodes.front()->position = mouse_pos + dragging_nodes.front()->drag_offset;
|
dragNode->position = mouse_pos + dragNode->drag_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto &n : selected_nodes){
|
for(auto &n : selected_nodes){
|
||||||
n->position = dragging_nodes.front()->position + n->drag_offset;
|
n->position = dragNode->position + n->drag_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mouse_released) {
|
if(mouse_released) {
|
||||||
@@ -269,7 +274,7 @@ int main(){
|
|||||||
} else if(!hovering_connectors.empty()){
|
} else if(!hovering_connectors.empty()){
|
||||||
app.gm.addConnection(connecting_nodes.front(), hovering_connectors.front());
|
app.gm.addConnection(connecting_nodes.front(), hovering_connectors.front());
|
||||||
} else {
|
} else {
|
||||||
std::shared_ptr<Node> new_node = app.gm.addMidiNode(mouse_pos);
|
SPTR_Node new_node = app.gm.addMidiNode(mouse_pos);
|
||||||
app.gm.addConnection(connecting_nodes.front(), new_node);
|
app.gm.addConnection(connecting_nodes.front(), new_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,7 +285,7 @@ int main(){
|
|||||||
}
|
}
|
||||||
case InteractionState::DELETE_SELECTED_NODES:
|
case InteractionState::DELETE_SELECTED_NODES:
|
||||||
{
|
{
|
||||||
app.removeNodes(selected_nodes | std::ranges::to<std::vector<std::shared_ptr<Node>>>());
|
app.removeNodes(selected_nodes | std::ranges::to<VEC_SPTR_Node>());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InteractionState::COPY_SELECTED_NODES:
|
case InteractionState::COPY_SELECTED_NODES:
|
||||||
|
|||||||
+2
-3
@@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
|
|
||||||
#include "edge.h"
|
#include "edge.h"
|
||||||
@@ -17,9 +16,9 @@ class Node : public Movable, public GraphItem{
|
|||||||
|
|
||||||
NodeType nodeType;
|
NodeType nodeType;
|
||||||
|
|
||||||
std::shared_ptr<Node> neighbor;
|
SPTR_Node neighbor;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Edge>> connections;
|
VEC_SPTR_Edge connections;
|
||||||
|
|
||||||
Distribution distributionMode = Distribution::GEOMETRIC;
|
Distribution distributionMode = Distribution::GEOMETRIC;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SignalManager{
|
|||||||
std::mutex *mutex;
|
std::mutex *mutex;
|
||||||
GraphManager *gm;
|
GraphManager *gm;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Signal>> signals;
|
VEC_SPTR_Signal signals;
|
||||||
|
|
||||||
bool loop = true;
|
bool loop = true;
|
||||||
bool play = false;
|
bool play = false;
|
||||||
@@ -57,9 +57,9 @@ class SignalManager{
|
|||||||
loop = false;
|
loop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSignalAtNode(std::shared_ptr<Node> node){
|
void addSignalAtNode(SPTR_Node node){
|
||||||
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_back(std::make_shared<Signal>(node->position, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
signals.emplace_back(std::make_shared<Signal>(node->position + Vec2D<float>{0.5f, 0.5f}, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
||||||
signals.back()->next = node;
|
signals.back()->next = node;
|
||||||
signals.back()->last = node;
|
signals.back()->last = node;
|
||||||
signals.back()->start = node;
|
signals.back()->start = node;
|
||||||
@@ -80,10 +80,10 @@ class SignalManager{
|
|||||||
s->direction = (s->next->position - s->position).norm();
|
s->direction = (s->next->position - s->position).norm();
|
||||||
s->update(diff.count());
|
s->update(diff.count());
|
||||||
if(s->position.dist(s->next->position) < 0.6f) {
|
if(s->position.dist(s->next->position) < 0.6f) {
|
||||||
std::shared_ptr<Node> next_node = gm->next(s->next, s->last);
|
SPTR_Node next_node = gm->next(s->next, s->last);
|
||||||
s->next->trigger();
|
s->next->trigger();
|
||||||
|
|
||||||
if(next_node != s->next && next_node != std::shared_ptr<Node>(nullptr) && s->next->getNodeType() == NodeType::MIDINODE) {
|
if(next_node != s->next && next_node != SPTR_Node(nullptr) && s->next->getNodeType() == NodeType::MIDINODE) {
|
||||||
auto midinode = std::dynamic_pointer_cast<MidiNode>(s->next);
|
auto midinode = std::dynamic_pointer_cast<MidiNode>(s->next);
|
||||||
for(auto &m : midinode->midi_outs){
|
for(auto &m : midinode->midi_outs){
|
||||||
if(m.second.enabled) {
|
if(m.second.enabled) {
|
||||||
|
|||||||
+4
-6
@@ -1,11 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
|
|
||||||
#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:
|
||||||
@@ -13,11 +11,11 @@ class Signal : public Movable{
|
|||||||
Signal();
|
Signal();
|
||||||
Signal(Vec2D<float> position, float r, float _speed, Color color) : Movable(position, 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) {}
|
||||||
|
|
||||||
std::shared_ptr<Node> next;
|
SPTR_Node next;
|
||||||
std::shared_ptr<Node> last;
|
SPTR_Node last;
|
||||||
std::shared_ptr<Edge> edge;
|
SPTR_Edge edge;
|
||||||
|
|
||||||
std::shared_ptr<Node> start;
|
SPTR_Node start;
|
||||||
|
|
||||||
bool at_target = false;
|
bool at_target = false;
|
||||||
|
|
||||||
|
|||||||
+14
-14
@@ -32,7 +32,7 @@ class AppState{
|
|||||||
AppUI ui;
|
AppUI ui;
|
||||||
|
|
||||||
void updateMidiPorts(){
|
void updateMidiPorts(){
|
||||||
for(auto&n : gm.nodes | std::ranges::views::filter([](std::shared_ptr<Node> n){return n->getNodeType() == NodeType::MIDINODE;})){
|
for(auto&n : gm.nodes | RANGE_FILTER([](SPTR_Node n){return n->getNodeType() == NodeType::MIDINODE;})){
|
||||||
auto nc = std::dynamic_pointer_cast<MidiNode>(n);
|
auto nc = std::dynamic_pointer_cast<MidiNode>(n);
|
||||||
for(auto& mo : sm.midi.midi_out_ports){
|
for(auto& mo : sm.midi.midi_out_ports){
|
||||||
if(!nc->midi_outs.contains(mo.number) && mo.enabled){
|
if(!nc->midi_outs.contains(mo.number) && mo.enabled){
|
||||||
@@ -45,16 +45,16 @@ class AppState{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyNodesAndConnections(std::vector<std::shared_ptr<Node>> nodes, Vec2D<float> position){
|
void copyNodesAndConnections(VEC_SPTR_Node nodes, Vec2D<float> position){
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Edge>> copy_connections;
|
VEC_SPTR_Edge copy_connections;
|
||||||
for(auto n : nodes){
|
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);});
|
std::ranges::copy_if(n->connections.begin(), n->connections.end(), std::back_inserter(copy_connections), [nodes](SPTR_Edge e){ return std::ranges::contains(nodes, e->start) && std::ranges::contains(nodes, e->end);});
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto n : nodes){
|
for(auto n : nodes){
|
||||||
std::shared_ptr<Node> old_node = n;
|
SPTR_Node old_node = n;
|
||||||
std::shared_ptr<Node> new_node = gm.copyNode(n, position + n->drag_offset);
|
SPTR_Node new_node = gm.copyNode(n, position + n->drag_offset);
|
||||||
new_node->copied = false;
|
new_node->copied = false;
|
||||||
new_node->selected = true;
|
new_node->selected = true;
|
||||||
|
|
||||||
@@ -67,26 +67,26 @@ class AppState{
|
|||||||
gm.edges.insert(gm.edges.end(), copy_connections.cbegin(), copy_connections.cend());
|
gm.edges.insert(gm.edges.end(), copy_connections.cbegin(), copy_connections.cend());
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeNodes(std::vector<std::shared_ptr<Node>> nodes){
|
void removeNodes(VEC_SPTR_Node nodes){
|
||||||
|
|
||||||
for(auto n : gm.nodes){
|
for(auto n : gm.nodes){
|
||||||
n->highlighted = false;
|
n->highlighted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);});
|
auto erase_connections = gm.edges | RANGE_FILTER([nodes](SPTR_Edge c){ return std::ranges::contains(nodes, c->start) || std::ranges::contains(nodes, c->end);});
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Node>> adjacent_nodes;
|
VEC_SPTR_Node adjacent_nodes;
|
||||||
|
|
||||||
for(auto c : erase_connections){
|
for(auto c : erase_connections){
|
||||||
if(!c->start->selected) adjacent_nodes.push_back(c->start);
|
if(!c->start->selected) adjacent_nodes.push_back(c->start);
|
||||||
if(!c->end->selected) adjacent_nodes.push_back(c->end);
|
if(!c->end->selected) adjacent_nodes.push_back(c->end);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto reroute_signals = sm.signals | std::ranges::views::filter([nodes](std::shared_ptr<Signal> s){return std::ranges::contains(nodes, s->next);});
|
auto reroute_signals = sm.signals | RANGE_FILTER([nodes](SPTR_Signal s){return std::ranges::contains(nodes, s->next);});
|
||||||
|
|
||||||
for(auto s : reroute_signals){
|
for(auto s : reroute_signals){
|
||||||
float dist = 10000000;
|
float dist = 10000000;
|
||||||
std::shared_ptr<Node> next_node;
|
SPTR_Node next_node;
|
||||||
for(auto n : adjacent_nodes){
|
for(auto n : adjacent_nodes){
|
||||||
if(n->position.dist(s->position) < dist) {
|
if(n->position.dist(s->position) < dist) {
|
||||||
dist = n->position.dist(s->position);
|
dist = n->position.dist(s->position);
|
||||||
@@ -97,16 +97,16 @@ class AppState{
|
|||||||
s->last = next_node;
|
s->last = next_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rebase_signals = sm.signals | std::ranges::views::filter([nodes](std::shared_ptr<Signal> s){return std::ranges::contains(nodes, s->start);});
|
auto rebase_signals = sm.signals | RANGE_FILTER([nodes](SPTR_Signal s){return std::ranges::contains(nodes, s->start);});
|
||||||
|
|
||||||
for(auto s : rebase_signals){
|
for(auto s : rebase_signals){
|
||||||
s->start = s->next;
|
s->start = s->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto n : nodes){
|
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.edges, [n](SPTR_Edge c){ return c->start == n || c->end == n;});
|
||||||
}
|
}
|
||||||
std::erase_if(gm.nodes, [nodes](std::shared_ptr<Node> n){ return std::ranges::contains(nodes, n);});
|
std::erase_if(gm.nodes, [nodes](SPTR_Node n){ return std::ranges::contains(nodes, n);});
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Vec2D<float> mouse_pos, Camera2D camera){
|
void draw(Vec2D<float> mouse_pos, Camera2D camera){
|
||||||
|
|||||||
Reference in New Issue
Block a user