polar snapping (almost bug free)

This commit is contained in:
Sebastian
2024-10-29 00:50:39 +01:00
parent fc48c2e7ed
commit c63eeed1b4
5 changed files with 106 additions and 67 deletions
+21 -1
View File
@@ -16,6 +16,7 @@
/*Pink: (176, 82, 121); #b05279*/
/*Blue: (108, 153, 187); #6c99bb*/
#include <algorithm>
#define RAYGUI_IMPLEMENTATION
#include "datatypes.h"
@@ -127,12 +128,17 @@ int main(){
auto hovering_nodes = app.nm.nodes | std::ranges::views::values| std::ranges::views::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, n.position, n.radius);});
auto hovering_connectors = app.nm.nodes | std::ranges::views::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.nm.nodes | std::ranges::views::values){
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;
if((mouse_clicked || mouse_down || mouse_released) && !mouse_right_down && dragging_nodes.empty() && connecting_nodes.empty() && hovering_nodes.empty() && hovering_connectors.empty()) istate = InteractionState::DRAW_SELECTION;
if(!hovering_nodes.empty() && !mouse_down && !mouse_right_down) istate = InteractionState::HOVER_NODE;
if(!dragging_nodes.empty()) istate = InteractionState::DRAG_NODE;
if(!hovering_connectors.empty() && istate == InteractionState::HOVER_CANVAS) istate = InteractionState::HOVER_CONNECTOR;
if(!hovering_connectors.empty() && !mouse_right_down && istate == InteractionState::HOVER_CANVAS) istate = InteractionState::HOVER_CONNECTOR;
if(!connecting_nodes.empty()) istate = InteractionState::CONNECT_NODE;
if(!selected_nodes.empty() && IsKeyPressed(KEY_DELETE)) istate = InteractionState::DELETE_SELECTED_NODES;
@@ -207,6 +213,10 @@ int main(){
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};
} else if(IsKeyDown(KEY_LEFT_SHIFT)){
float steps = round(dragging_nodes.front().neighbor->position.dist(mouse_pos) / 60.0f) * 60.0f;
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;
}
@@ -230,8 +240,10 @@ int main(){
}
case InteractionState::HOVER_CONNECTOR:
{
if(!hovering_connectors.empty()){
hovering_connectors.front().hover_connect = true;
if(mouse_clicked) hovering_connectors.front().connecting = true;
}
break;
}
case InteractionState::CONNECT_NODE:
@@ -240,8 +252,16 @@ int main(){
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;
}
if(!hovering_connectors.empty()) {
hovering_connectors.front().hovering = true;
hovering_connectors.front().hover_connect = 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()){
+1
View File
@@ -60,6 +60,7 @@ class Midi {
void enumerate(){
std::cout << (int)obs.get_current_api() << std::endl;
int i = 0;
midi_out_ports.clear();
for(const libremidi::output_port& port : obs.get_output_ports()){
midi_out_ports.push_back({port, i, false});
i++;
+25 -8
View File
@@ -20,6 +20,8 @@ class NodeManager{
std::vector<int> keys;
int iterator = 0;
std::vector<std::string> fractions = {"1/32","1/16","3/32","1/8","5/32","3/16","7/32","1/4","9/32","5/16","11/32","3/8","13/32","7/16","15/32","1/2","17/32","9/16","19/32","5/8","21/32","11/16","23/32","3/4","25/32","13/16","27/32","7/8","29/32","15/16","31/32","1/1"};
int getRandomNode(){
std::vector<int> o;
std::ranges::sample(keys, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
@@ -60,18 +62,33 @@ class NodeManager{
}
void drawNodes(Vec2D<float> *mouse_pos, Camera2D *camera){
auto flat_nodes = nodes | std::ranges::views::values | std::ranges::to<std::vector<Node>>();
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(flat_nodes.begin(), flat_nodes.end(), [n](Node na, Node nb){ return na.position.dist(n.position) < nb.position.dist(n.position);});
float d = flat_nodes.at(1).position.dist(n.position);
if(d > 0 && d < 240) {
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 = 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);
Vec2D<float> middle_handle = flat_nodes.at(1).position + (n.position - flat_nodes.at(1).position) * ((d - text_length.x)*0.5f)/d;
Vec2D<float> text_position = middle_handle + (flat_nodes.at(1).position - n.position).norm().orth() * 12.0f;
float rotation = Vector2Angle((Vector2){1,0}, (n.position - flat_nodes.at(1).position)) * RAD2DEG;
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);
DrawLineV(n.position, flat_nodes.at(1).position, VS_COLOR_PINK);
if(i == 0 && IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
DrawLineV(n.position, it->position, VS_COLOR_PINK);
}
}
}
}
n.draw(mouse_pos, camera);
+4 -1
View File
@@ -22,6 +22,9 @@ class Node : public Movable{
Node(int id, float x, float y, float r) : Movable(Vec2D<float>(x, y), 0.0f), radius(r), id(id) {}
Node(int id, Vec2D<float> p, float r) : Movable(p, 0.0f), radius(r), id(id) {}
Node *neighbor = nullptr;
float radius;
int id;
@@ -86,6 +89,7 @@ class Node : public Movable{
DrawRing(position, radius, radius+4, 0, 360, 24, (Color){60, 60, 60, 255});
DrawRing(position, radius, radius+4, 0.0f - 90.0f, (360.0f/127.0f) * midi_velocity - 90.0f, 24, (Color){158, 134, 200, 255});
DrawCircleLinesV(position, radius + 4, (Color){100, 100, 100, 255});
if(mode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, VS_COLOR_PINK);
float midi_gate_map = round((255.f / midi_gate) * fade);
Color gate_color = ColorAlphaBlend(VS_COLOR_RED, (Color){180, 210, 115, (unsigned char)Clamp(255 - midi_gate_map, 0, 255)}, WHITE);
@@ -102,7 +106,6 @@ class Node : public Movable{
int offset = MeasureText(MIDI::Notes[midi_note].c_str(), 12);
DrawText(MIDI::Notes[midi_note].c_str(), position.x-offset/2.0f, position.y-5, 12, WHITE );
}
if(mode == Distribution::RANDOM) DrawCircle(position.x, position.y, radius/2.0f, (Color){229, 181, 103, 255});
Vec2D<float> connector = position - ((position - *mouse)).norm() * (radius + R);
float opacity = 150.0f - Clamp(position.dist(mouse), 0.0f, 150.0f);
+6 -8
View File
@@ -28,23 +28,22 @@ class AppUI{
void drawSideBar(){
GuiPanel((Rectangle){-1,-30,280,(float)settings->height + 31}, "");
{
const int s_controls = 20;
const int s_controls = 25;
//GuiSetStyle(BUTTON, STATE_FOCUSED, 0xFF0000FF);
if(GuiButton((Rectangle){20, (float)s_controls, 80, 30}, "PLAY")) sm->play ? sm->pause() : sm->start();
if(GuiButton((Rectangle){120, (float)s_controls, 60, 30}, "STOP")) sm->stop();
if(GuiButton((Rectangle){200, (float)s_controls, 60, 30}, "RESET")) sm->reset();
const int s_bpm = s_controls + 35;
const int s_bpm = s_controls + 45;
GuiLabel((Rectangle){20, (float)s_bpm, 120, 20}, "TIMING");
GuiLabel((Rectangle){200, (float)s_bpm, 40, 20}, std::format("{}",settings->bpm).c_str());
float _bpm = (float)settings->bpm;
GuiSlider((Rectangle){20, (float)s_bpm + 25, 240, 20}, "", "", &_bpm, 1, 300);
settings->bpm = _bpm;
int s_midi = s_bpm + 55;
int s_midi = s_bpm + 75;
GuiLabel((Rectangle){20, (float)s_midi, 240, 20}, "MIDI OUT");
if(GuiButton((Rectangle){20, (float)s_midi, 60, 30}, "REload")) sm->midi.enumerate();
if(GuiButton((Rectangle){200, (float)s_midi, 60, 20}, "RELOAD")) sm->midi.enumerate();
int i = 0;
for(auto& mo : sm->midi.midi_out_ports){
@@ -62,7 +61,7 @@ class AppUI{
}
}
int s_signal = s_midi + 90 + i*20;
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 = nm->getRandomNode();
@@ -81,7 +80,7 @@ class AppUI{
signal_configs++;
}
int s_nodes = s_signal + 60 + signal_configs*20;
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")){
nm->addNode(200.0f, 200.0f);
@@ -89,7 +88,6 @@ class AppUI{
DrawText(std::format("{}", nm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE);
DrawFPS(20, settings->height - 30);
}
}
void drawPerNodeConfig(Camera2D *camera){
for(auto& n : nm->nodes | std::ranges::views::values | std::views::filter([](Node n){ return n.config; })){