2024-10-30 14:55:24 +01:00
# pragma once
2024-11-01 14:08:27 +01:00
2024-12-07 03:44:03 +01:00
# include "config-node.h"
2024-10-30 14:55:24 +01:00
# include "datatypes.h"
2024-11-16 00:29:01 +01:00
# include "state.h"
2024-11-14 00:55:09 +01:00
# include "vmath.h"
2024-11-01 14:08:27 +01:00
# include "raylib.h"
# include "raymath.h"
2024-11-02 15:52:16 +01:00
# include "nlohmann/json.hpp"
2024-11-01 14:08:27 +01:00
# include "button.h"
2024-11-02 23:12:38 +01:00
# include "midi-node.h"
2024-10-31 01:43:00 +01:00
# include "edge.h"
2024-11-03 03:48:49 +01:00
# include "node.h"
2024-11-01 14:08:27 +01:00
2024-10-31 01:43:00 +01:00
# include <algorithm>
2024-11-01 14:08:27 +01:00
# include <cstdio>
2024-11-02 02:06:26 +01:00
# include <iostream>
2024-10-31 01:43:00 +01:00
# include <iterator>
2024-10-30 14:55:24 +01:00
# include <map>
2024-10-31 01:43:00 +01:00
# include <memory>
2024-12-07 03:44:03 +01:00
# include <ostream>
2024-10-30 14:55:24 +01:00
# include <random>
# include <ranges>
2024-10-31 01:43:00 +01:00
# include <vector>
2024-10-30 14:55:24 +01:00
2024-11-02 23:12:38 +01:00
# include "state-io.h"
2024-11-02 15:52:16 +01:00
using json = nlohmann : : json ;
2024-11-03 03:48:49 +01:00
using namespace VISEQ : : GRAPH : : NODES ;
using namespace VISEQ : : GRAPH : : EDGES ;
2024-11-02 23:12:38 +01:00
2024-11-03 03:48:49 +01:00
namespace VISEQ : : GRAPH {
2024-10-30 14:55:24 +01:00
2024-11-30 02:54:40 +01:00
class GraphManager : public std : : enable_shared_from_this < GraphManager > {
2024-12-03 01:25:49 +01:00
private :
NODES : : VEC_SPTR_Node nodes ;
EDGES : : VEC_SPTR_Edge edges ;
EDGES : : VEC_WPTR_Edge remove_edges ;
EDGES : : VEC_WPTR_Edge split_edges ;
2024-12-04 01:43:06 +01:00
VEC_SPTR_Node selected_nodes ;
2024-12-03 01:25:49 +01:00
2024-12-04 01:43:06 +01:00
std : : map < NODES : : SPTR_Node , int > counter ;
2024-12-03 01:25:49 +01:00
std : : shared_ptr < APP : : State > state = APP : : State : : get ( ) ;
2024-10-30 14:55:24 +01:00
2024-11-03 03:48:49 +01:00
public :
2024-10-30 14:55:24 +01:00
2024-11-03 03:48:49 +01:00
GraphManager ( ) { }
2024-11-01 14:08:27 +01:00
2024-11-30 02:54:40 +01:00
std : : shared_ptr < GraphManager > getPtr ( ) {
return shared_from_this ( ) ;
}
2024-12-04 01:43:06 +01:00
int getNodesSize ( ) {
return nodes . size ( ) ;
}
2024-12-05 01:25:00 +01:00
void createMidiNode ( Vec2Df position ) {
2024-11-30 02:54:40 +01:00
nodes . emplace_back ( std : : make_shared < MidiNode > ( position ) ) ;
2024-12-05 01:25:00 +01:00
nodes . back ( ) - > update ( ) ;
2024-11-30 02:54:40 +01:00
}
2024-12-04 01:43:06 +01:00
2024-12-07 03:44:03 +01:00
void createConfigNode ( Vec2Df position ) {
nodes . emplace_back ( std : : make_shared < ConfigNode > ( position ) ) ;
nodes . back ( ) - > update ( ) ;
}
2024-12-04 01:43:06 +01:00
void setMidiPortForAll ( int number , bool _state ) {
for ( auto n : nodes ) {
if ( n - > getNodeType ( ) = = NodeType : : MIDINODE ) std : : dynamic_pointer_cast < MidiNode > ( n ) - > setMidiPort ( number , _state ) ;
}
}
2024-11-16 00:29:01 +01:00
2024-11-30 02:54:40 +01:00
void addNode ( SPTR_Node node ) {
2024-12-07 03:44:03 +01:00
std : : cout < < " added node " < < node - > id < < std : : endl ;
2024-11-30 02:54:40 +01:00
nodes . insert ( nodes . end ( ) , node ) ;
2024-12-05 00:01:42 +01:00
node - > update ( ) ;
}
2024-12-03 01:25:49 +01:00
void addConnection ( WPTR_Node from , WPTR_Node to ) {
2024-12-07 15:28:33 +01:00
EdgeType et = EdgeType : : MIDIEDGE ;
if ( from . lock ( ) - > getNodeType ( ) = = NodeType : : CONFIGNODE | | to . lock ( ) - > getNodeType ( ) = = NodeType : : CONFIGNODE ) et = EdgeType : : CONFIGEDGE ;
2024-12-03 01:25:49 +01:00
if ( from . lock ( ) ! = to . lock ( ) ) {
2024-11-30 02:54:40 +01:00
edges . emplace_back ( std : : make_shared < Edge > ( ) ) ;
2024-12-07 15:28:33 +01:00
edges . back ( ) - > edgeType = et ;
2024-11-30 02:54:40 +01:00
edges . back ( ) - > start = from ;
edges . back ( ) - > end = to ;
2024-12-07 15:28:33 +01:00
edges . back ( ) - > start_conn = from . lock ( ) - > connectors . back ( ) ;
2024-12-05 00:01:42 +01:00
edges . back ( ) - > end_conn = to . lock ( ) - > connectors . back ( ) ;
2024-12-03 01:25:49 +01:00
from . lock ( ) - > connections . push_back ( edges . back ( ) ) ;
to . lock ( ) - > connections . push_back ( edges . back ( ) ) ;
2024-11-30 02:54:40 +01:00
}
2024-11-03 03:48:49 +01:00
}
2024-11-26 01:58:09 +01:00
2024-12-05 23:39:01 +01:00
void addToSelection ( ) {
auto temp_nodes = nodes | RANGE_FILTER ( [ ] ( SPTR_Node n ) { return n - > selected ; } ) | std : : ranges : : to < VEC_SPTR_Node > ( ) ;
selected_nodes . insert ( selected_nodes . end ( ) , temp_nodes . begin ( ) , temp_nodes . end ( ) ) ;
}
2024-11-26 01:58:09 +01:00
void select ( ) {
auto temp_nodes = nodes | RANGE_FILTER ( [ ] ( SPTR_Node n ) { return n - > select ( ) ; } ) | std : : ranges : : to < VEC_SPTR_Node > ( ) ;
if ( ! KEYS_DOWN . shift ) selected_nodes . clear ( ) ;
selected_nodes . insert ( selected_nodes . end ( ) , temp_nodes . begin ( ) , temp_nodes . end ( ) ) ;
2024-12-03 01:25:49 +01:00
std : : for_each ( selected_nodes . begin ( ) , selected_nodes . end ( ) , [ ] ( WPTR_Node n ) { n . lock ( ) - > selected = true ; } ) ;
2024-11-26 01:58:09 +01:00
}
void deselect ( ) {
2024-11-28 01:08:04 +01:00
std : : cout < < " deselect " < < std : : endl ;
2024-11-26 01:58:09 +01:00
for ( auto s : selected_nodes ) {
2024-12-04 01:43:06 +01:00
s - > selected = false ;
2024-11-26 01:58:09 +01:00
}
selected_nodes . clear ( ) ;
}
2024-12-04 01:43:06 +01:00
VEC_SPTR_Node getSelection ( ) {
2024-11-26 01:58:09 +01:00
return selected_nodes ;
2024-11-21 02:03:32 +01:00
}
2024-11-30 02:54:40 +01:00
2024-11-03 03:48:49 +01:00
void copyNodes ( VEC_SPTR_Node _nodes , Vec2Df position ) {
for ( auto n : _nodes ) {
nodes . insert ( nodes . end ( ) , std : : make_shared < Node > ( * n ) ) ;
2024-12-08 14:21:46 +01:00
/*if(n->getNodeType() == NodeType::MIDINODE) nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));*/
/*if(n->getNodeType() == NodeType::CONFIGNODE) nodes.insert(nodes.end(), std::make_shared<ConfigNode>(*n));*/
2024-11-03 03:48:49 +01:00
nodes . back ( ) - > setPosition ( position + nodes . back ( ) - > drag_offset ) ;
nodes . back ( ) - > selected = false ;
}
}
void copyNodes ( std : : vector < std : : shared_ptr < MidiNode > > _nodes , Vec2Df position ) {
for ( auto n : _nodes ) {
nodes . insert ( nodes . end ( ) , std : : make_shared < MidiNode > ( * n ) ) ;
nodes . back ( ) - > setPosition ( position + nodes . back ( ) - > drag_offset ) ;
nodes . back ( ) - > selected = false ;
}
}
2024-12-04 01:43:06 +01:00
VEC_SPTR_Node getCopiesOfSelectedNodes ( ) {
VEC_SPTR_Node copied_nodes ;
for ( auto n : selected_nodes ) {
copied_nodes . insert ( copied_nodes . end ( ) , std : : make_shared < Node > ( * n ) ) ;
2024-12-08 14:21:46 +01:00
/*if(n->getNodeType() == NodeType::MIDINODE) copied_nodes.insert(copied_nodes.end(), std::make_shared<MidiNode>(*n));*/
/*if(n->getNodeType() == NodeType::CONFIGNODE) copied_nodes.insert(copied_nodes.end(), std::make_shared<ConfigNode>(*n));*/
2024-12-04 01:43:06 +01:00
copied_nodes . back ( ) - > deselect ( ) ;
}
return copied_nodes ;
}
2024-11-03 03:48:49 +01:00
SPTR_Node copyNode ( SPTR_Node n , Vec2Df position ) {
std : : cout < < " copy basenode " < < std : : endl ;
2024-11-02 02:06:26 +01:00
nodes . insert ( nodes . end ( ) , std : : make_shared < Node > ( * n ) ) ;
2024-12-08 14:21:46 +01:00
/*if(n->getNodeType() == NodeType::MIDINODE) nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));*/
/*if(n->getNodeType() == NodeType::CONFIGNODE) nodes.insert(nodes.end(), std::make_shared<ConfigNode>(*n));*/
2024-11-03 03:48:49 +01:00
nodes . back ( ) - > setPosition ( position ) ;
return nodes . back ( ) ;
2024-10-30 14:55:24 +01:00
}
2024-11-03 03:48:49 +01:00
SPTR_Node copyNode ( std : : shared_ptr < MidiNode > n , Vec2Df position ) {
std : : cout < < " copy midinode " < < std : : endl ;
2024-11-02 02:06:26 +01:00
nodes . insert ( nodes . end ( ) , std : : make_shared < MidiNode > ( * n ) ) ;
2024-12-05 23:39:01 +01:00
nodes . back ( ) - > clearConnectors ( ) ;
2024-11-03 03:48:49 +01:00
nodes . back ( ) - > setPosition ( position ) ;
return nodes . back ( ) ;
2024-11-01 02:38:47 +01:00
}
2024-11-30 02:54:40 +01:00
2024-11-03 03:48:49 +01:00
void setNodeMode ( int mode ) {
for ( auto n : nodes ) {
2024-12-08 14:21:46 +01:00
n - > setMode ( mode ) ;
2024-11-03 03:48:49 +01:00
}
2024-10-31 01:43:00 +01:00
}
2024-10-30 14:55:24 +01:00
2024-11-03 03:48:49 +01:00
void reset ( ) {
counter . clear ( ) ;
}
2024-12-03 01:25:49 +01:00
WPTR_Node getNode ( int i ) {
return nodes . at ( i ) ;
}
WPTR_Node getFirstNode ( ) {
return nodes . front ( ) ;
}
2024-12-07 03:44:03 +01:00
WPTR_Node getLastNode ( ) {
return nodes . back ( ) ;
}
2024-12-03 01:25:49 +01:00
VEC_WPTR_Node getMidiNodes ( ) {
return nodes | RANGE_FILTER ( [ ] ( VISEQ : : GRAPH : : NODES : : SPTR_Node n ) { return n - > getNodeType ( ) = = NodeType : : MIDINODE ; } ) | std : : ranges : : to < VEC_WPTR_Node > ( ) ;
}
2024-10-30 14:55:24 +01:00
2024-11-30 02:54:40 +01:00
NODES : : SPTR_Node getRandomNode ( ) {
VEC_SPTR_GraphItem o ;
std : : ranges : : sample ( nodes , std : : back_inserter ( o ) , 1 , std : : mt19937 { std : : random_device { } ( ) } ) ;
return std : : dynamic_pointer_cast < VISEQ : : GRAPH : : NODES : : Node > ( o . front ( ) ) ;
}
EDGES : : SPTR_Edge getRandomEdge ( ) {
VEC_SPTR_GraphItem o ;
std : : ranges : : sample ( edges , std : : back_inserter ( o ) , 1 , std : : mt19937 { std : : random_device { } ( ) } ) ;
return std : : dynamic_pointer_cast < VISEQ : : GRAPH : : EDGES : : Edge > ( o . front ( ) ) ;
}
SPTR_Node getClosestNode ( Vec2Df position ) {
auto neighbors = nodes | RANGE_FILTER ( [ ] ( SPTR_Node n ) { return ! n - > picked_up ; } ) | std : : ranges : : to < VEC_SPTR_Node > ( ) ;
std : : sort ( neighbors . begin ( ) , neighbors . end ( ) , [ position ] ( SPTR_Node na , SPTR_Node nb ) { return na - > position . dist ( position ) < nb - > position . dist ( position ) ; } ) ;
return neighbors . front ( ) ;
2024-11-28 08:49:35 +01:00
}
2024-12-03 01:25:49 +01:00
VEC_WPTR_Node getNodesByID ( int _id ) {
return nodes | RANGE_FILTER ( [ _id ] ( SPTR_Node n ) { return n - > id = = _id ; } ) | std : : ranges : : to < VEC_WPTR_Node > ( ) ; // TODO: Multiple nodes with the same ID? Why not return only one node?
}
WPTR_Edge lastEdge ( ) {
return edges . back ( ) ;
}
2024-11-28 08:49:35 +01:00
2024-12-03 01:25:49 +01:00
WPTR_Node next ( WPTR_Node current , WPTR_Node last ) {
VEC_WPTR_Edge possible_connections = current . lock ( ) - > connections | RANGE_FILTER ( [ current ] ( WPTR_Edge c ) {
2024-12-07 15:28:33 +01:00
return ( c . lock ( ) - > getEdgeType ( ) = = EdgeType : : MIDIEDGE ) & & ( ( c . lock ( ) - > start . lock ( ) = = current . lock ( ) & & c . lock ( ) - > pass_forward ) | | ( c . lock ( ) - > end . lock ( ) = = current . lock ( ) & & c . lock ( ) - > pass_backward ) ) ;
2024-12-03 01:25:49 +01:00
} ) | std : : ranges : : to < VEC_WPTR_Edge > ( ) ;
2024-10-30 14:55:24 +01:00
2024-11-03 03:48:49 +01:00
if ( possible_connections . empty ( ) ) return SPTR_Node ( nullptr ) ;
int return_path = 0 ;
float angle = - 1 ;
2024-12-03 01:25:49 +01:00
if ( current . lock ( ) - > distributionMode = = Distribution : : GEOMETRIC ) {
Vec2Df coming_from = ( current . lock ( ) - > position - last . lock ( ) - > position ) . norm ( ) ;
2024-11-03 03:48:49 +01:00
int i = 0 ;
for ( auto n : possible_connections ) {
2024-12-03 01:25:49 +01:00
WPTR_Node next_node = n . lock ( ) - > getNextNode ( current ) ;
float angle_v1_v2 = coming_from . norm ( ) . dot ( ( next_node . lock ( ) - > position - current . lock ( ) - > position ) . norm ( ) ) ;
2024-11-03 03:48:49 +01:00
if ( angle_v1_v2 > angle ) {
return_path = i ;
angle = angle_v1_v2 ;
}
+ + i ;
}
}
2024-12-03 01:25:49 +01:00
if ( current . lock ( ) - > distributionMode = = Distribution : : ROUNDROBIN ) {
2024-12-04 01:43:06 +01:00
if ( counter . find ( current . lock ( ) ) = = counter . end ( ) ) {
counter [ current . lock ( ) ] = 0 ;
2024-11-03 03:48:49 +01:00
} else {
2024-12-04 01:43:06 +01:00
counter [ current . lock ( ) ] = ( counter [ current . lock ( ) ] + 1 ) % possible_connections . size ( ) ;
return_path = counter [ current . lock ( ) ] ;
2024-10-30 14:55:24 +01:00
}
}
2024-11-03 03:48:49 +01:00
2024-12-03 01:25:49 +01:00
if ( current . lock ( ) - > distributionMode = = Distribution : : RANDOM ) {
2024-11-03 03:48:49 +01:00
return_path = rand ( ) % possible_connections . size ( ) ;
}
2024-12-03 01:25:49 +01:00
return possible_connections . at ( return_path ) . lock ( ) - > getNextNode ( current ) ;
2024-10-30 14:55:24 +01:00
}
2024-11-03 03:48:49 +01:00
void splitEdge ( SPTR_Edge edge ) {
split_edges . push_back ( edge ) ;
2024-10-30 14:55:24 +01:00
}
2024-11-03 03:48:49 +01:00
void splitEdges ( ) {
for ( auto s : split_edges ) {
2024-12-03 01:25:49 +01:00
Vec2Df center = s . lock ( ) - > end . lock ( ) - > position . center ( s . lock ( ) - > start . lock ( ) - > position ) ;
2024-12-05 01:25:00 +01:00
SPTR_Node cn = copyNode ( std : : dynamic_pointer_cast < MidiNode > ( s . lock ( ) - > start . lock ( ) ) , center ) ; // TODO: copy connectors
2024-12-03 01:25:49 +01:00
addConnection ( s . lock ( ) - > start . lock ( ) , cn ) ;
addConnection ( cn , s . lock ( ) - > end . lock ( ) ) ;
2024-11-03 03:48:49 +01:00
remove_edges . push_back ( s ) ;
}
split_edges . clear ( ) ;
2024-11-02 02:06:26 +01:00
}
2024-11-03 03:48:49 +01:00
void removeEdge ( SPTR_Edge edge ) {
remove_edges . push_back ( edge ) ;
2024-11-02 02:06:26 +01:00
}
2024-11-03 03:48:49 +01:00
void removeEdges ( ) {
for ( auto edge : remove_edges ) {
2024-12-03 01:25:49 +01:00
edge . lock ( ) - > start . lock ( ) - > removeConnector ( edge . lock ( ) - > start_conn ) ;
edge . lock ( ) - > end . lock ( ) - > removeConnector ( edge . lock ( ) - > end_conn ) ;
std : : erase ( edge . lock ( ) - > start . lock ( ) - > connections , edge . lock ( ) ) ;
std : : erase ( edge . lock ( ) - > end . lock ( ) - > connections , edge . lock ( ) ) ;
std : : erase ( edges , edge . lock ( ) ) ;
2024-11-03 03:48:49 +01:00
}
remove_edges . clear ( ) ;
2024-11-01 14:08:27 +01:00
}
2024-11-03 03:48:49 +01:00
2024-12-03 01:25:49 +01:00
VEC_WPTR_Node getAdjacentNodes ( VEC_SPTR_Node selected_nodes ) {
2024-11-21 02:03:32 +01:00
for ( auto n : nodes ) {
n - > highlighted = false ;
}
2024-12-03 01:25:49 +01:00
auto erase_connections = edges | RANGE_FILTER ( [ selected_nodes ] ( SPTR_Edge c ) { return std : : ranges : : contains ( selected_nodes , c - > start . lock ( ) ) | | std : : ranges : : contains ( selected_nodes , c - > end . lock ( ) ) ; } ) ;
2024-11-21 02:03:32 +01:00
2024-12-03 01:25:49 +01:00
VEC_WPTR_Node adjacent_nodes ;
2024-11-21 02:03:32 +01:00
for ( auto c : erase_connections ) {
2024-12-03 01:25:49 +01:00
if ( ! c - > start . lock ( ) - > selected ) adjacent_nodes . push_back ( c - > start ) ;
if ( ! c - > end . lock ( ) - > selected ) adjacent_nodes . push_back ( c - > end ) ;
2024-11-21 02:03:32 +01:00
}
return adjacent_nodes ;
}
void removeNodesAndEdges ( VEC_SPTR_Node selected_nodes ) {
2024-12-03 01:25:49 +01:00
VEC_WPTR_Node adjacent_nodes = getAdjacentNodes ( selected_nodes ) ;
2024-11-21 02:03:32 +01:00
for ( auto n : adjacent_nodes ) {
2024-12-03 01:25:49 +01:00
std : : erase_if ( n . lock ( ) - > connections , [ n , selected_nodes ] ( VISEQ : : GRAPH : : EDGES : : WPTR_Edge c ) { return std : : ranges : : contains ( selected_nodes , c . lock ( ) - > start . lock ( ) ) | | std : : ranges : : contains ( selected_nodes , c . lock ( ) - > end . lock ( ) ) ; } ) ;
2024-11-21 02:03:32 +01:00
}
for ( auto n : selected_nodes ) {
2024-12-03 01:25:49 +01:00
std : : erase_if ( this - > edges , [ n ] ( WPTR_Edge c ) { return c . lock ( ) - > start . lock ( ) = = n | | c . lock ( ) - > end . lock ( ) = = n ; } ) ;
2024-11-21 02:03:32 +01:00
}
std : : erase_if ( this - > nodes , [ selected_nodes ] ( SPTR_Node n ) { return std : : ranges : : contains ( selected_nodes , n ) ; } ) ;
}
void pasteNodesAndEdges ( VEC_SPTR_Node nodes , Vec2Df position ) {
VEC_SPTR_Edge copy_connections ;
for ( auto c : edges ) {
2024-12-03 01:25:49 +01:00
if ( std : : ranges : : contains ( nodes , c - > start . lock ( ) ) & & std : : ranges : : contains ( nodes , c - > end . lock ( ) ) ) {
2024-11-21 02:03:32 +01:00
copy_connections . push_back ( std : : make_shared < Edge > ( * c ) ) ;
}
}
std : : cout < < copy_connections . size ( ) < < std : : endl ;
for ( auto old_node : nodes ) {
SPTR_Node new_node ;
if ( old_node - > getNodeType ( ) = = NodeType : : MIDINODE ) {
new_node = copyNode ( std : : dynamic_pointer_cast < MidiNode > ( old_node ) , position + old_node - > drag_offset ) ;
} else {
new_node = copyNode ( old_node , position + old_node - > drag_offset ) ;
}
new_node - > copied = false ;
new_node - > selected = true ;
2024-11-28 01:08:04 +01:00
//TODO copy connectors
2024-11-21 02:03:32 +01:00
for ( auto c : copy_connections ) {
2024-12-03 01:25:49 +01:00
if ( c - > start . lock ( ) = = old_node ) {
2024-11-21 02:03:32 +01:00
c - > start = new_node ;
2024-12-03 01:25:49 +01:00
c - > start . lock ( ) - > connections . push_back ( c ) ;
2024-11-21 02:03:32 +01:00
}
2024-12-03 01:25:49 +01:00
if ( c - > end . lock ( ) = = old_node ) {
2024-11-21 02:03:32 +01:00
c - > end = new_node ;
2024-12-03 01:25:49 +01:00
c - > end . lock ( ) - > connections . push_back ( c ) ;
2024-11-21 02:03:32 +01:00
}
}
}
std : : ranges : : copy ( copy_connections . begin ( ) , copy_connections . end ( ) , std : : back_inserter ( edges ) ) ;
}
2024-12-02 00:28:44 +01:00
void update ( ) {
2024-11-03 03:48:49 +01:00
if ( ! remove_edges . empty ( ) ) removeEdges ( ) ;
if ( ! split_edges . empty ( ) ) splitEdges ( ) ;
2024-12-02 00:28:44 +01:00
}
void drawEdges ( Vec2Df mouse_pos , Camera2D cam ) {
2024-11-03 03:48:49 +01:00
for ( auto c : edges ) {
2024-12-03 01:25:49 +01:00
Vec2Df v1_position = c - > start . lock ( ) - > position - ( ( c - > start . lock ( ) - > position - c - > end . lock ( ) - > position ) ) . norm ( ) * ( c - > start . lock ( ) - > radius + c - > connector_offset ) ;
Vec2Df v2_position = c - > end . lock ( ) - > position - ( ( c - > end . lock ( ) - > position - c - > start . lock ( ) - > position ) ) . norm ( ) * ( c - > end . lock ( ) - > radius + c - > connector_offset ) ;
2024-11-03 03:48:49 +01:00
float v1_v2_distance = v1_position . dist ( & v2_position ) ;
if ( v1_v2_distance < 100 ) c - > switches_offset = v1_v2_distance / 2.3f ;
2024-12-03 01:25:49 +01:00
Vec2Df from_to_handle = c - > start . lock ( ) - > position - ( ( c - > start . lock ( ) - > position - c - > end . lock ( ) - > position ) ) . norm ( ) * ( c - > start . lock ( ) - > radius + c - > switches_offset ) ;
Vec2Df to_from_handle = c - > end . lock ( ) - > position - ( ( c - > end . lock ( ) - > position - c - > start . lock ( ) - > position ) ) . norm ( ) * ( c - > end . lock ( ) - > radius + c - > switches_offset ) ;
Vec2Df middle_handle = c - > end . lock ( ) - > position - ( ( c - > end . lock ( ) - > position - c - > start . lock ( ) - > position ) ) * 0.4f ;
Vec2Df middle_handle_2 = c - > end . lock ( ) - > position - ( ( c - > end . lock ( ) - > position - c - > start . lock ( ) - > position ) ) * 0.6f ;
2024-11-03 03:48:49 +01:00
Vec2Df 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 ) ;
Vec2Df flip_handle_2 = middle_handle_2 + ( v1_position - v2_position ) . norm ( ) . orth ( ) * ( v1_v2_distance < 120.0f ? Clamp ( ( 120.0f - v1_v2_distance ) * - 0.2 , - 20.f , 0.f ) : 1.0f ) ;
2024-12-07 03:44:03 +01:00
2024-11-03 03:48:49 +01:00
// Dynamic opacity by distance to mouse
unsigned char opacity = 150.0f - Clamp ( middle_handle . dist ( mouse_pos ) , 0.0f , 150.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 ) ;
2024-12-07 03:44:03 +01:00
float midi_gate_v1 = 0.0f ;
float midi_gate_v2 = 0.0f ;
if ( c - > start . lock ( ) - > getNodeType ( ) = = NodeType : : MIDINODE ) {
2024-12-08 14:21:46 +01:00
midi_gate_v1 = Clamp ( ( 4.f / 1000.f ) * std : : dynamic_pointer_cast < MidiNode > ( c - > start . lock ( ) ) - > getNotes ( ) . gate , 1.f , 4.f ) ;
2024-12-07 03:44:03 +01:00
}
if ( c - > end . lock ( ) - > getNodeType ( ) = = NodeType : : MIDINODE ) {
2024-12-08 14:21:46 +01:00
midi_gate_v2 = Clamp ( ( 4.f / 1000.f ) * std : : dynamic_pointer_cast < MidiNode > ( c - > end . lock ( ) ) - > getNotes ( ) . gate , 1.f , 4.f ) ;
2024-12-07 03:44:03 +01:00
}
// Line with small connector circles
if ( c - > end . lock ( ) - > getNodeType ( ) = = NodeType : : MIDINODE & & c - > start . lock ( ) - > getNodeType ( ) = = NodeType : : MIDINODE ) {
Color col = { 229 , 181 , 103 , 255 } ;
if ( c - > GActive ( ) ) col = { 108 , 153 , 187 , 255 } ;
DrawLine ( v1_position . x , v1_position . y , v2_position . x , v2_position . y , col ) ;
{
float d = c - > start . lock ( ) - > position . dist ( c - > end . lock ( ) - > position ) ;
std : : string frac = MIDI : : Fractions . at ( std : : clamp < int > ( 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 ) ;
Vec2Df middle_handle = c - > start . lock ( ) - > position + ( c - > end . lock ( ) - > position - c - > start . lock ( ) - > position ) * ( ( d - text_length . x ) * 0.5f ) / d ;
Vec2Df middle_handle_frac = c - > start . lock ( ) - > position + ( c - > end . lock ( ) - > position - c - > start . lock ( ) - > position ) * ( ( d - text_length_frac . x ) * 0.5f ) / d ;
Vec2Df text_position = middle_handle + ( c - > start . lock ( ) - > position - c - > end . lock ( ) - > position ) . norm ( ) . orth ( ) * 12.0f ;
Vec2Df text_position_frac = middle_handle_frac - ( c - > start . lock ( ) - > position - c - > end . lock ( ) - > position ) . norm ( ) . orth ( ) * 4.0f ;
float rotation = Vector2Angle ( ( Vector2 ) { 1 , 0 } , ( c - > end . lock ( ) - > position - c - > start . lock ( ) - > position ) ) * RAD2DEG ;
DrawTextPro ( GetFontDefault ( ) , std : : format ( " {:.1f} " , d ) . c_str ( ) , text_position , ( Vector2 ) { 0 , 0 } , rotation , 10.0f , 2.0f , VS_COLOR_PINK ) ;
if ( ( int ) d % 60 = = 0 ) DrawTextPro ( GetFontDefault ( ) , frac . c_str ( ) , text_position_frac , ( Vector2 ) { 0 , 0 } , rotation , 10.0f , 2.0f , VS_COLOR_PINK ) ;
2024-11-03 03:48:49 +01:00
}
2024-12-07 03:44:03 +01:00
if ( midi_gate_v1 = = 4.0f ) col = VS_COLOR_RED ;
DrawCircle ( v1_position . x , v1_position . y , midi_gate_v1 , col ) ;
2024-11-03 03:48:49 +01:00
2024-12-07 03:44:03 +01:00
col = { 229 , 181 , 103 , 255 } ;
if ( midi_gate_v2 = = 4.0f ) col = VS_COLOR_RED ;
DrawCircle ( v2_position . x , v2_position . y , midi_gate_v2 , col ) ;
if ( ! c - > start . lock ( ) - > picked_up & & ! c - > end . lock ( ) - > picked_up ) {
// On/Off switches on both sides
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 ) {
Vec2Df block_point1 = ( v1_position - v2_position ) . norm ( ) . orth ( ) * 4.0f + from_to_handle ;
Vec2Df 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 - > pass_backward ) {
Vec2Df block_point1 = ( v1_position - v2_position ) . norm ( ) . orth ( ) * 4.0f + to_from_handle ;
Vec2Df 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_2 . x , flip_handle_2 . y , 8.0f , ( Color ) { 232 , 125 , 62 , opacity } ) ) splitEdge ( c ) ;
2024-11-03 03:48:49 +01:00
}
2024-11-01 14:08:27 +01:00
}
2024-12-07 03:44:03 +01:00
if ( c - > start . lock ( ) - > getNodeType ( ) = = NodeType : : CONFIGNODE | | c - > end . lock ( ) - > getNodeType ( ) = = NodeType : : CONFIGNODE ) {
DrawLine ( v1_position . x , v1_position . y , v2_position . x , v2_position . y , VS_COLOR_BLUE ) ;
}
if ( ViButton ( mouse_pos , flip_handle . x , flip_handle . y , 8.0f , ( Color ) { 232 , 50 , 32 , opacity } ) ) removeEdge ( c ) ;
2024-11-01 14:08:27 +01:00
}
2024-10-30 14:55:24 +01:00
}
2024-11-03 03:48:49 +01:00
2024-11-14 00:55:09 +01:00
void drawNeighborLines ( SPTR_Node node , Vec2Df mouse_pos , Camera2D camera ) {
2024-11-03 03:48:49 +01:00
float min_d = 480 ;
2024-11-14 00:55:09 +01:00
auto neighbors_local = nodes | RANGE_FILTER ( [ mouse_pos ] ( SPTR_Node n ) { return ! n - > picked_up & & ! n - > selected & & n - > position . dist ( mouse_pos ) < 960 ; } ) | std : : ranges : : to < VEC_SPTR_Node > ( ) ;
std : : sort ( neighbors_local . begin ( ) , neighbors_local . end ( ) , [ node , mouse_pos ] ( SPTR_Node na , SPTR_Node nb ) { return na - > position . dist ( mouse_pos ) < nb - > position . dist ( mouse_pos ) ; } ) ;
if ( ! neighbors_local . empty ( ) ) {
min_d = neighbors_local . front ( ) - > position . dist ( mouse_pos ) ;
DrawCircleLinesV ( neighbors_local . front ( ) - > position , 22.0f , VS_COLOR_PINK ) ;
node - > neighbors = neighbors_local | std : : ranges : : views : : filter ( [ mouse_pos , min_d ] ( SPTR_Node n ) { return abs ( n - > position . dist ( mouse_pos ) - min_d ) < 5 ; } ) | std : : ranges : : to < VEC_SPTR_Node > ( ) ;
for ( auto nb : node - > neighbors ) {
DrawCircleLinesV ( nb - > position , 20.0f , VS_COLOR_RED ) ;
float d = nb - > position . dist ( mouse_pos ) ;
float dn = nb - > position . dist ( node - > position ) ;
if ( d > 0 & & d < min_d * 1.5 & & d < 960 ) {
std : : string frac = MIDI : : Fractions . at ( std : : clamp < int > ( round ( dn / 60 ) - 1 , 0 , 31 ) ) ;
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 ) ;
Vec2Df middle_handle = nb - > position + ( node - > position - nb - > position ) * ( ( dn - text_length . x ) * 0.5f ) / dn ;
Vec2Df middle_handle_frac = nb - > position + ( node - > position - nb - > position ) * ( ( dn - text_length_frac . x ) * 0.5f ) / dn ;
Vec2Df text_position = middle_handle + ( nb - > position - node - > position ) . norm ( ) . orth ( ) * 12.0f ;
Vec2Df text_position_frac = middle_handle_frac - ( nb - > position - node - > position ) . norm ( ) . orth ( ) * 4.0f ;
float rotation = Vector2Angle ( ( Vector2 ) { 1 , 0 } , ( node - > position - nb - > position ) ) * RAD2DEG ;
DrawTextPro ( GetFontDefault ( ) , std : : format ( " {:.1f} " , dn ) . c_str ( ) , text_position , ( Vector2 ) { 0 , 0 } , rotation , 10.0f , 2.0f , VS_COLOR_PINK ) ;
if ( IsKeyDown ( KEY_LEFT_SHIFT ) ) DrawTextPro ( GetFontDefault ( ) , frac . c_str ( ) , text_position_frac , ( Vector2 ) { 0 , 0 } , rotation , 10.0f , 2.0f , VS_COLOR_PINK ) ;
Vec2Df n_position = node - > position - ( ( node - > position - nb - > position ) ) . norm ( ) * 20.0f ;
Vec2Df nb_position = nb - > position - ( ( nb - > position - node - > position ) ) . norm ( ) * 20.0f ;
DrawLineV ( n_position , nb_position , VS_COLOR_PINK ) ;
2024-10-30 14:55:24 +01:00
}
}
2024-11-14 00:55:09 +01:00
}
}
void drawNodes ( Vec2Df mouse_pos , Camera2D camera ) {
2024-11-19 01:04:06 +01:00
for ( auto n : nodes ) {
2024-11-25 00:53:10 +01:00
if ( KEYS_PRESSED . ctrl & & n - > hovering ( ) ) state - > selection_origin = n - > position ;
2024-11-19 01:04:06 +01:00
}
2024-11-21 23:58:35 +01:00
BASE : : Interactable : : z_hovering = - 1 ;
2024-11-14 00:55:09 +01:00
for ( auto n : nodes ) {
n - > update ( ) ;
if ( n - > picked_up ) drawNeighborLines ( n , mouse_pos , camera ) ;
2024-11-03 03:48:49 +01:00
n - > draw ( mouse_pos , camera ) ;
2024-10-30 14:55:24 +01:00
}
}
2024-12-08 02:25:57 +01:00
NLOHMANN_DEFINE_TYPE_INTRUSIVE ( GraphManager , nodes , edges , selected_nodes )
2024-11-03 03:48:49 +01:00
} ;
2024-10-30 14:55:24 +01:00
2024-11-03 03:48:49 +01:00
}