Files
viseq/src/main.cpp
T

413 lines
16 KiB
C++
Raw Normal View History

2024-10-09 02:01:23 +02:00
/*
*
* VISEQ - Visual Sequencer
*
*
*/
/*Background: (46, 46, 46); #2e2e2e*/
/*Comments: (121, 121, 121); #797979*/
/*White: (214, 214, 214); #d6d6d6*/
/*Yellow: (229, 181, 103); #e5b567*/
/*Green: (180, 210, 115); #b4d273*/
/*Orange: (232, 125, 62); #e87d3e*/
/*Purple: (158, 134, 200); #9e86c8*/
/*Pink: (176, 82, 121); #b05279*/
/*Blue: (108, 153, 187); #6c99bb*/
2024-10-25 16:41:37 +02:00
#define RAYGUI_IMPLEMENTATION
2024-10-16 02:26:02 +02:00
#include "datatypes.h"
#include <ranges>
#include <raylib.h>
#include <raymath.h>
2024-10-09 02:01:23 +02:00
#include <cstdlib>
#include <stdio.h>
#include <cmath>
2024-10-25 16:41:37 +02:00
#include "state-manager.h"
AppState app;
2024-10-09 02:01:23 +02:00
Vec2D<float> mouse_pos;
Vec2D<float> drag_start;
2024-10-25 16:41:37 +02:00
Camera2D camera = { {0} };
2024-10-09 02:01:23 +02:00
bool mouse_clicked = false;
bool mouse_touched = false;
bool mouse_dragging = false;
2024-10-09 02:01:23 +02:00
2024-10-25 16:41:37 +02:00
//#include "ui.h"
2024-10-09 02:01:23 +02:00
int main(){
srand(time(NULL));
InitWindow(2560, 1440, "VISEQ");
2024-10-25 16:41:37 +02:00
app.ui.init();
int monitor = 0; //GetCurrentMonitor();
SetWindowMonitor(monitor);
2024-10-25 16:41:37 +02:00
app.settings.fps = 1.0f;
app.settings.bpm = 120.0f;
app.settings.grid = 120.0f; //round(((app.settings.fps / (app.settings.bpm / 60.0f)) * app.settings.speed) / 4.0f); // from quarter notes to 16th notes = div by 4
// app.settings.speed = round((((app.settings.fps / (app.settings.bpm / 60.0f)) / app.settings.grid) / 4.0f) / 10.0f) * 10.0f;
// 16th note = 120px (festgelegt)
// ganze note = 1920px
// ganze note bei 120bpm = 2s
// 120bpm = 960px/s
2024-10-25 16:41:37 +02:00
app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f);
app.settings.width = GetMonitorWidth(monitor);
app.settings.height = GetMonitorHeight(monitor);
SetTargetFPS(60.0f);
2024-10-25 16:41:37 +02:00
camera.target = (Vector2){ app.settings.width/2.0f, app.settings.height/2.0f };
camera.offset = (Vector2){ app.settings.width/2.0f, app.settings.height/2.0f };
camera.rotation = 0.0f;
2024-10-25 16:41:37 +02:00
camera.zoom = 1.0f;
2024-10-09 02:01:23 +02:00
for(int i = 0; i < 4; ++i){
2024-10-25 16:41:37 +02:00
app.nm.addNode((float)i * app.settings.grid + 10 * app.settings.grid, 5 * app.settings.grid);
}
for(int i = 3; i >= 0; --i){
2024-10-25 16:41:37 +02:00
app.nm.addNode((float)i * app.settings.grid + 10 * app.settings.grid, 6 * app.settings.grid);
2024-10-09 02:01:23 +02:00
}
for(int i = 0; i < 8; ++i){
2024-10-25 16:41:37 +02:00
app.cm.addConnection(&app.nm.nodes[i], &app.nm.nodes[(i+1) % 8]);
}
2024-10-25 16:41:37 +02:00
app.sm.addSignalAtNode(&app.nm.nodes.front());
2024-10-18 01:27:14 +02:00
2024-10-25 16:41:37 +02:00
app.sm.startSignalThread();
2024-10-13 15:07:19 +02:00
Vec2D<float> drag_offset;
2024-10-09 02:01:23 +02:00
2024-10-20 23:42:38 +02:00
Vec2D<float> cam_drag_offset;
Vec2D<float> cam_mouse_drag_offset;
2024-10-16 02:26:02 +02:00
double drag_timer = GetTime();
enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION};
InteractionState istate = HOVER_CANVAS;
2024-10-24 21:05:05 +02:00
Vec2D<float> select_start;
Rectangle selection;
ToggleFullscreen();
while(!WindowShouldClose()){
2024-10-09 02:01:23 +02:00
BeginDrawing();
ClearBackground((Color){46,46,46});
BeginMode2D(camera);
2024-10-25 16:41:37 +02:00
//app.settings.mutex.lock();
app.settings.speed = (app.settings.grid * 8.0f) * (app.settings.bpm / 120.f);
Vector2 mp = GetScreenToWorld2D(GetMousePosition(), camera);
2024-10-10 02:59:27 +02:00
Vec2D<float> mouse_pos = {(float)mp.x, (float)mp.y};
2024-10-20 23:42:38 +02:00
Vec2D<float> cam_pos = {camera.offset.x, camera.offset.y};
bool mouse_down = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
bool mouse_clicked = IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
bool mouse_released = IsMouseButtonReleased(MOUSE_BUTTON_LEFT);
2024-10-24 21:05:05 +02:00
bool mouse_right_down = IsMouseButtonDown(MOUSE_BUTTON_RIGHT);
bool mouse_right_clicked = IsMouseButtonPressed(MOUSE_BUTTON_RIGHT);
bool mouse_right_released = IsMouseButtonReleased(MOUSE_BUTTON_RIGHT);
2024-10-10 02:59:27 +02:00
Vec2D<float> mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
Vec2D<float> delta = mouse_delta * (-1.0f/camera.zoom);
2024-10-25 16:41:37 +02:00
auto dragging_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.dragging;});
auto connecting_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.connecting;});
auto selected_nodes = app.nm.nodes | std::ranges::views::filter([](Node n) { return n.selected && !n.dragging;});
auto hovering_nodes = app.nm.nodes | 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::filter([&mouse_pos](Node n) { return CheckCollisionPointCircle(mouse_pos, (n.position - ((n.position - mouse_pos)).norm() * (n.radius + 14.0f)), 8.0f);});
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;
2024-10-24 21:05:05 +02:00
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(!connecting_nodes.empty()) istate = InteractionState::CONNECT_NODE;
2024-10-24 21:05:05 +02:00
switch(istate){
case InteractionState::HOVER_CANVAS:
if(mouse_right_down) {
camera.target = Vector2Add(camera.target, delta);
}
break;
case InteractionState::DRAW_SELECTION:
if(mouse_clicked){
select_start = mouse_pos;
}
if(mouse_down){
Vec2D<float> select1 = {mouse_pos.x > select_start.x ? select_start.x : mouse_pos.x, mouse_pos.y > select_start.y ? select_start.y : mouse_pos.y};
Vec2D<float> select2 = {mouse_pos.x > select_start.x ? mouse_pos.x - select_start.x : select_start.x - mouse_pos.x, mouse_pos.y > select_start.y ? mouse_pos.y - select_start.y : select_start.y - mouse_pos.y};
DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});
selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};
2024-10-25 16:41:37 +02:00
for(auto& n : app.nm.nodes){
if(CheckCollisionPointRec(n.position, selection)) {
n.in_rect = true;
} else {
n.in_rect = false;
}
}
}
2024-10-24 21:05:05 +02:00
if(mouse_released){
2024-10-25 16:41:37 +02:00
for(auto& n : app.nm.nodes){
if(CheckCollisionPointRec(n.position, selection)) {
n.selected = true;
n.in_rect = false;
} else {
if(!IsKeyDown(KEY_LEFT_SHIFT)) n.selected = false;
}
}
selection = (Rectangle){0,0,0,0};
}
break;
case InteractionState::HOVER_NODE:
if(mouse_clicked) {
if(IsKeyDown(KEY_LEFT_SHIFT)) {
hovering_nodes.front().selected = true;
} else {
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;
break;
case InteractionState::DRAG_NODE:
if(IsKeyDown(KEY_LEFT_CONTROL)) {
2024-10-25 16:41:37 +02:00
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 {
dragging_nodes.front().position = mouse_pos + dragging_nodes.front().drag_offset;
}
for(auto &n : selected_nodes){
if(!n.picked_up) n.drag_offset = n.position - dragging_nodes.front().position;
n.picked_up = true;
n.position = dragging_nodes.front().position + n.drag_offset;
}
2024-10-24 21:05:05 +02:00
if(mouse_released) {
dragging_nodes.front().dragging = false;
for(auto &n : selected_nodes){
n.picked_up = false;
}
}
break;
case InteractionState::HOVER_CONNECTOR:
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);
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});
}
if(mouse_released) {
2024-10-25 16:41:37 +02:00
if(&hovering_nodes.front() != &connecting_nodes.front() && &connecting_nodes.front() != &hovering_connectors.front()){
if(!hovering_nodes.empty()){
app.cm.addConnection(&connecting_nodes.front(), &hovering_nodes.front());
} else if(!hovering_connectors.empty()){
app.cm.addConnection(&connecting_nodes.front(), &hovering_connectors.front());
} else {
app.nm.addNode(mouse_pos.x, mouse_pos.y);
app.cm.addConnection(&connecting_nodes.front(), &app.nm.nodes.back());
}
}
connecting_nodes.front().connecting = false;
}
break;
};
2024-10-20 23:42:38 +02:00
float wheel = GetMouseWheelMove();
if(wheel != 0){
if(!hovering_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL)){
2024-10-24 21:05:05 +02:00
hovering_nodes.front().midi_note += wheel;
2024-10-25 16:41:37 +02:00
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;
} else {
Vector2 mouseWorldPos = GetScreenToWorld2D(GetMousePosition(), camera);
camera.offset = GetMousePosition();
camera.target = mouseWorldPos;
float scaleFactor = 1.0f + (0.25f*fabsf(wheel));
if (wheel < 0) scaleFactor = 1.0f/scaleFactor;
camera.zoom = Clamp(camera.zoom*scaleFactor, 0.125f, 64.0f);
}
2024-10-20 23:42:38 +02:00
}
2024-10-25 16:41:37 +02:00
for(int x = -app.settings.grid*100; x < app.settings.grid*100; x+=app.settings.grid){
for(int y = -app.settings.grid*100; y < app.settings.grid*100; y+=app.settings.grid){
DrawPixel(x, y, (Color){130,130,130,200});
}
2024-10-10 02:59:27 +02:00
}
2024-10-25 16:41:37 +02:00
app.draw(&mouse_pos, &camera);
EndMode2D();
2024-10-25 16:41:37 +02:00
app.drawUI(&mouse_pos, &camera);
EndDrawing();
2024-10-09 02:01:23 +02:00
}
CloseWindow();
return 0;
2024-10-09 02:01:23 +02:00
}
2024-10-25 16:41:37 +02:00
/*void drawGUI(){*/
/**/
/* // Main Config Window*/
/* GuiWindowBox((Rectangle){0,0,280,(float)app.settings.height}, "config");*/
/* {*/
/* const int s_controls = 55;*/
/* if(GuiButton((Rectangle){20, (float)s_controls, 60, 30}, "PLAY")) sm.play ? sm.pause() : sm.start();*/
/* if(GuiButton((Rectangle){100, (float)s_controls, 60, 30}, "STOP")) sm.stop();*/
/* if(GuiButton((Rectangle){180, (float)s_controls, 60, 30}, "RESET")) sm.reset();*/
/**/
/* const int s_bpm = s_controls + 35;*/
/* GuiLabel((Rectangle){20, (float)s_bpm, 120, 20}, "TIMING");*/
/* GuiLabel((Rectangle){200, (float)s_bpm, 40, 20}, std::format("{}",app.settings.bpm).c_str());*/
/* float _bpm = (float)app.settings.bpm;*/
/* GuiSlider((Rectangle){20, (float)s_bpm + 25, 240, 20}, "", "", &_bpm, 1, 300);*/
/* app.settings.bpm = _bpm;*/
/**/
/* int s_midi = s_bpm + 55;*/
/* GuiLabel((Rectangle){20, (float)s_midi, 240, 20}, "MIDI OUT");*/
/* int i = 0;*/
/* for(auto& mo : midi.midi_out_ports){*/
/* GuiCheckBox((Rectangle){20, (float)s_midi + 25 + i*20.0f, 20, 20}, mo.port.port_name.c_str(), &mo.enabled);*/
/* i++;*/
/* }*/
/**/
/* if(GuiButton((Rectangle){20, (float)s_midi + 45 + i*20.0f, 240, 20}, "ENABLE FOR ALL")) {*/
/* for(auto &midis : midi.midi_out_ports){*/
/* if(midis.enabled){*/
/* for(auto &n : nodes){*/
/* n.midi_outs[midis.number].enabled = true;*/
/* }*/
/* }*/
/* }*/
/* }*/
/**/
/* int s_signal = s_midi + 90 + 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 = rand() % nodes.size();*/
/* sm.addSignalAtNode(&nodes[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 = app.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, 2);*/
/* s.multiplier = s_multiplier;*/
/* s.speed = app.settings.speed;*/
/* signal_configs++;*/
/* }*/
/**/
/* int s_nodes = s_signal + 60 + 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")){*/
/* nodes.emplace_back(200.0f, 200.0f, 15.0f);*/
/* }*/
/**/
/* DrawFPS(20, app.settings.height - 30);*/
/* }*/
/**/
/* // Per Node Config Windows*/
/* for(auto& n : nodes){*/
/* Vector2 np = GetWorldToScreen2D((Vector2){n.position.x, n.position.y}, camera);*/
/**/
/* for(auto& mo : 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(n.midi_outs.contains(mo.number) && !mo.enabled){*/
/* n.midi_outs.erase(mo.number);*/
/* }*/
/* }*/
/**/
/* if(n.config){*/
/* n.config = !GuiWindowBox((Rectangle){np.x + 10, np.y + 10, 240, 440}, "config");*/
/**/
/* int option = n.mode;*/
/* GuiToggleGroup((Rectangle){ np.x + 20, np.y + 40, 110, 20 }, "Round Robin;Random", &option);*/
/* n.mode = (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);*/
/* }*/
/**/
/* 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++;*/
/* }*/
/**/
/* int y_channel = y_midi + 30 + i*20;*/
/* GuiLabel((Rectangle){np.x + 20, np.y + y_channel, 220, 20}, "CHANNEL");*/
/* GuiToggleGroup((Rectangle){np.x + 20, np.y + y_channel + 30, 25, 20}, "1;2;3;4;5;6;7;8\n9;10;11;12;13;14;15;16", &n.midi_channel);*/
/**/
/* GuiLabel((Rectangle){np.x + 20, np.y + y_channel + 90, 100, 20}, "NOTE");*/
/* float v = n.midi_note;*/
/* GuiLabel((Rectangle){np.x + 210, np.y + y_channel + 90, 20, 20}, midi.midiNotes[(int)round(v)].c_str());*/
/* GuiLabel((Rectangle){np.x + 160, np.y + y_channel + 90, 40, 20}, std::format("{}",n.midi_note).c_str());*/
/* GuiSlider((Rectangle){np.x + 20, np.y + y_channel + 120, 220, 20}, "", "", &v, 0, 127);*/
/* n.midi_note = round(v);*/
/**/
/* GuiLabel((Rectangle){np.x + 20, np.y + y_channel + 150, 100, 20}, "VELOCITY");*/
/* v = n.midi_velocity;*/
/* GuiLabel((Rectangle){np.x + 210, np.y + y_channel + 150, 20, 20}, std::format("{}",n.midi_velocity).c_str());*/
/* GuiSlider((Rectangle){np.x + 20, np.y + y_channel + 180, 220, 20}, "", "", &v, 0, 127);*/
/* n.midi_velocity = round(v);*/
/**/
/* GuiLabel((Rectangle){np.x + 20, np.y + y_channel + 210, 100, 20}, "GATE");*/
/* v = n.midi_gate;*/
/* GuiLabel((Rectangle){np.x + 210, np.y + y_channel + 210, 20, 20}, std::format("{}",(float)n.midi_gate/1000.0f).c_str());*/
/* GuiSlider((Rectangle){np.x + 20, np.y + y_channel + 240, 220, 20}, "", "", &v, 0, 5000);*/
/* n.midi_gate = round(v);*/
/**/
/* //if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel + 40, 140, 20}, "VELOCITY", &n.midi_velocity, 0, 127, n.gui_midi_velocity_edit)) n.gui_midi_velocity_edit = !n.gui_midi_velocity_edit;*/
/* //if(GuiValueBox((Rectangle){n.position.x + 100, n.position.y + y_channel + 60, 140, 20}, "GATE", &n.midi_gate, 0, 5000, n.gui_midi_gate_edit)) n.gui_midi_gate_edit = !n.gui_midi_gate_edit;*/
/* }*/
/* }*/
/**/
/* for(auto& c : cm.connections){*/
/* if(c.config){*/
/* Vec2D<float> config_handle = c.v2->position - ((c.v2->position - c.v1->position))*0.75f;*/
/* c.config = !GuiWindowBox((Rectangle){config_handle.x + 10, config_handle.y + 10, 200, 300}, "connection");*/
/* GuiToggle((Rectangle){config_handle.x + 10, config_handle.y + 50, 80, 20}, "v1v2", &c.v1_v2);*/
/* GuiToggle((Rectangle){config_handle.x + 100, config_handle.y + 50, 80, 20}, "v2v1", &c.v2_v1);*/
/**/
/* }*/
/* }*/
/**/
/**/
/*}*/