/* * * VISEQ - The Visual Sequencer * 2024 Sebastian Kujas * */ #include "canvas.h" #include "state.h" #include "datatypes.h" #include "graph-manager.h" #include "node.h" #include "vmath.h" #include #include #define RAYGUI_IMPLEMENTATION #include #include #include "app-manager.h" #include "datatypes.h" #include "midi-node.h" #include "nlohmann/json.hpp" #include #include #include #include #include using json = nlohmann::json; VISEQ::APP::CANVAS::Canvas canvas; VISEQ::APP::AppManager app; std::shared_ptr state = VISEQ::APP::State::get(); Vec2Df mouse_pos; Vec2Df drag_start; //Vec2Df global_mouse; bool mouse_clicked = false; bool mouse_touched = false; bool mouse_dragging = false; int main(){ srand(time(NULL)); InitWindow(1920, 1080, "VISEQ - The Visual Sequencer"); int current_monitor = GetCurrentMonitor(); int monitor_width = GetMonitorWidth(current_monitor); int monitor_height = GetMonitorHeight(current_monitor); SetWindowMonitor(current_monitor); SetWindowState(FLAG_WINDOW_RESIZABLE); SetWindowSize(monitor_width - 300, monitor_height - 300); //ToggleFullscreen(); app.ui.init(); state->settings.fps = 60.0f; state->settings.bpm = 120.0f; state->settings.grid = 60.0f; // 120px for a 16th note state->settings.speed = (state->settings.grid * 16.0f) * (state->settings.bpm / 120.f); state->settings.width = monitor_width - 300; state->settings.height = monitor_height - 300; SetTargetFPS(state->settings.fps); canvas.camera.target = (Vector2){ state->settings.width/2.0f, state->settings.height/2.0f }; canvas.camera.offset = (Vector2){ state->settings.width/2.0f, state->settings.height/2.0f }; canvas.camera.rotation = 0.0f; canvas.camera.zoom = 1.0f; if(std::filesystem::exists("state.json")){ std::ifstream f("state.json"); json graph = json::parse(f); // state->settings = graph.at("settings"); int highest_id = 0; std::shared_ptr hid; for(auto n : graph.at("graphmanager").at("nodes")){ std::shared_ptr mn = n; if(mn->id > highest_id) { highest_id = mn->id; hid = mn; } } for(auto e : graph.at("graphmanager").at("edges")){ if(e.at("id") > highest_id){ highest_id = e.at("id"); } } for(auto n : graph.at("graphmanager").at("nodes")){ std::shared_ptr mn = n; app.gm.addNode(mn); //app.gm.nodes.push_back(mn); std::cout << std::format("adding node {}", mn->id) << std::endl; } for(auto e : graph.at("graphmanager").at("edges")){ int start_id = e.at("start").get(); int end_id = e.at("end").get(); VEC_SPTR_Node start = app.gm.nodes | RANGE_FILTER([start_id](SPTR_Node n){return n->id == start_id;}) | std::ranges::to(); VEC_SPTR_Node end = app.gm.nodes | RANGE_FILTER([end_id](SPTR_Node n){return n->id == end_id;}) | std::ranges::to(); if(!start.empty() && !end.empty()) { std::cout << std::format("connection {} to {}", start_id, end_id) << std::endl; app.gm.addConnection(start.front(), end.front()); } } app.gm.edges.back()->newId(highest_id); // set static id counter in base class to highest value from json file for(auto s : graph.at("signalmanager").at("signals")){ int start_id = s.at("start").get(); int next_id = s.at("next").get(); int last_id = s.at("last").get(); std::shared_ptr ms = s; VEC_SPTR_Node start = app.gm.nodes | RANGE_FILTER([start_id](SPTR_Node n){return n->id == start_id;}) | std::ranges::to(); VEC_SPTR_Node last = app.gm.nodes | RANGE_FILTER([last_id](SPTR_Node n){return n->id == last_id;}) | std::ranges::to(); VEC_SPTR_Node next = app.gm.nodes | RANGE_FILTER([next_id](SPTR_Node n){return n->id == next_id;}) | std::ranges::to(); ms->start = start.front(); ms->next = next.front(); ms->last = last.front(); app.sm.signals.push_back(ms); std::cout << std::format("adding signal with start node {}", start_id) << std::endl; } } else { for(int i = 0; i < 4; ++i){ app.gm.addMidiNode(Vec2Df{(float)i * state->settings.grid*4 + 7 * state->settings.grid, 2 * state->settings.grid*4}); } for(int i = 3; i >= 0; --i){ app.gm.addMidiNode(Vec2Df{(float)i * state->settings.grid*4 + 7 * state->settings.grid, 3 * state->settings.grid*4}); } for(int i = 0; i < 8; ++i){ app.gm.addConnection(app.gm.nodes[i], app.gm.nodes[(i+1) % 8]); } app.sm.addSignalAtNode(app.gm.nodes.front()); } app.sm.startSignalThread(); enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, ADD_NODES_MENU, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION, SCALE_SELECTION, DELETE_SELECTED_NODES, COPY_SELECTED_NODES, PASTE_SELECTED_NODES}; InteractionState istate = HOVER_CANVAS; Vec2Df node_menu_position; Vec2Df select_start; Rectangle selection; Vec2Df scale_start; Vec2Df scale_rectangle; float drag_distance = 0; VEC_SPTR_Node copied_nodes; while(!WindowShouldClose()){ BeginDrawing(); ClearBackground((Color){46,46,46}); canvas.drawStart(); state->update(canvas.camera); /*else if(IsKeyDown(KEY_LEFT_SHIFT)){*/ /* float steps = round((dragNode->neighbors.front()->position.dist(mouse_pos)) / state->settings.grid) * state->settings.grid;*/ /* if(dragNode->neighbors.size() > 1){*/ /* Vec2Df dn1 = dragNode->neighbors[0]->position;*/ /* Vec2Df dn2 = dragNode->neighbors[1]->position;*/ /* Vec2Df v1_orth = dn1.center(dn2);*/ /**/ /* if(dn1.x < dn2.x) std::swap(dn1,dn2);*/ /**/ /* float dist = dn1.dist(dn2);*/ /* float dist_orth = std::sqrt(std::pow(steps,2) - std::pow(dist/2,2));*/ /**/ /* if(mouse_pos.y < v1_orth.y) dist_orth *= -1;*/ /**/ /* Vec2Df v1_orth_t = v1_orth + (dn1-dn2).norm().orth() * dist_orth;*/ /* DrawLineV(dn1, dn2, VS_COLOR_RED);*/ /* DrawLineV(v1_orth, v1_orth_t, VS_COLOR_RED);*/ /* DrawCircleV(v1_orth, 3.0f, VS_COLOR_RED);*/ /* dragNode->position = v1_orth_t;*/ /* } else if(!dragNode->neighbors.empty()){*/ /* float pol_r = steps;*/ /* float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - dragNode->neighbors.front()->position));*/ /* Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); */ /* dragNode->position = dragNode->neighbors.front()->position + polar;*/ /* }*/ // auto dragging_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->dragging;}); /*auto connecting_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->connecting;});*/ /*auto selected_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->selected && !n->picked_up;}) | std::ranges::to();*/ /*auto hovering_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->hovering();});*/ /*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 ){*/ /* if(hovering_connectors.empty()) n->hover_connect = false;*/ /*}*/ /**/ /*if(istate != InteractionState::ADD_NODES_MENU && !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::SCALE_SELECTION) 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() && !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;*/ /*if(!selected_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_C)) istate = InteractionState::COPY_SELECTED_NODES;*/ /**/ /*if(!copied_nodes.empty() && IsKeyDown(KEY_LEFT_CONTROL) && IsKeyPressed(KEY_V)) istate = InteractionState::PASTE_SELECTED_NODES;*/ /**/ /*if(IsKeyPressed(KEY_TAB)) {*/ /* state->settings.mode = (state->settings.mode + 1) % 3;*/ /* app.gm.setNodeMode(state->settings.mode);*/ /*}*/ /*if(!selected_nodes.empty()){*/ /* float offset = 30;*/ /* Vec2Df corner_tl = {50000, 50000};*/ /* Vec2Df corner_br = {-50000, -50000};*/ /* std::shared_ptr node_tl;*/ /* std::shared_ptr node_br;*/ /**/ /* for(auto n : selected_nodes){*/ /* float x = n->position.x;*/ /* float y = n->position.y;*/ /**/ /* if(x < corner_tl.x && y < corner_tl.y) node_tl = n;*/ /* if(x > corner_br.x && y > corner_br.y) node_br = n;*/ /**/ /* if(x <= corner_tl.x) corner_tl.x = x;*/ /* if(x >= corner_br.x) corner_br.x = x;*/ /* if(y <= corner_tl.y) corner_tl.y = y;*/ /* if(y >= corner_br.y) corner_br.y = y;*/ /* }*/ /* corner_tl -= Vec2Df(offset, offset);*/ /* corner_br += Vec2Df(offset, offset);*/ /**/ /* DrawRectangleLines(corner_tl.x, corner_tl.y, (corner_br.x - corner_tl.x), (corner_br.y - corner_tl.y), VS_COLOR_LIGHTGREY);*/ /* DrawCircleV(corner_br, 5, YELLOW);*/ /**/ /* if(istate == InteractionState::SCALE_SELECTION && mouse_released){*/ /* istate = InteractionState::HOVER_CANVAS;*/ /* }*/ /* if(mouse_clicked && corner_br.dist(mouse_pos) < 10){*/ /* scale_start = (corner_br - corner_tl);*/ /* for(auto n : selected_nodes){*/ /* n->drag_offset = n->position - node_tl->position;*/ /* }*/ /* istate = InteractionState::SCALE_SELECTION;*/ /* }*/ /* if(istate == InteractionState::SCALE_SELECTION && mouse_down){*/ /* Vec2Df scale = (mouse_pos - corner_tl) / scale_start;*/ /* if(IsKeyDown(KEY_LEFT_SHIFT)) scale.y = scale.x;*/ /* DrawText(std::format("{:.2f} {:.2f}", scale.x, scale.y).c_str(), corner_br.x+5, corner_br.y+5, 10, RED);*/ /* for(auto n : selected_nodes){*/ /* n->position = node_tl->position + (n->drag_offset * scale);*/ /* }*/ /* istate = InteractionState::SCALE_SELECTION;*/ /* }*/ /*}*/ /*switch(istate){*/ /* case InteractionState::SCALE_SELECTION:*/ /* case InteractionState::HOVER_CANVAS:*/ /* {*/ /* for(auto &n : app.gm.nodes){ */ /* n->hover_connect = false;*/ /* }*/ /* if(mouse_right_clicked){*/ /* drag_distance = 0;*/ /* }*/ /* if(mouse_right_down) {*/ /* canvas.camera.target = Vector2Add(canvas.camera.target, delta);*/ /* drag_distance += delta.length();*/ /* }*/ /* if(mouse_right_released && drag_distance < 5) {*/ /* node_menu_position = mouse_pos;*/ /* istate = InteractionState::ADD_NODES_MENU;*/ /* }*/ /* break;*/ /* }*/ /* case InteractionState::ADD_NODES_MENU:*/ /* {*/ /* DrawCircleV(node_menu_position, 30, VS_COLOR_LIGHTGREY);*/ /* DrawCircleLines(node_menu_position.x, node_menu_position.y, 32, VS_COLOR_DARKGREY);*/ /**/ /* }*/ /* case InteractionState::DRAW_SELECTION:*/ /* {*/ /* if(mouse_clicked){*/ /* select_start = mouse_pos;*/ /* }*/ /* if(mouse_down){*/ /* Vec2Df 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};*/ /* Vec2Df 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};*/ /**/ /* for(auto& n : app.gm.nodes){*/ /* if(CheckCollisionPointRec(n->position, selection)) {*/ /* n->in_rect = true;*/ /* } else {*/ /* n->in_rect = false;*/ /* }*/ /* }*/ /* }*/ /**/ /* if(mouse_released){ */ /* int n_selected = 0;*/ /* for(auto& n : app.gm.nodes){*/ /* if(CheckCollisionPointRec(n->position, selection)) {*/ /* n->selected = true;*/ /* n->in_rect = false;*/ /* n_selected++;*/ /* } else {*/ /* if(!IsKeyDown(KEY_LEFT_SHIFT)) n->selected = false;*/ /* }*/ /* }*/ /* if(n_selected > 0) copied_nodes.clear();*/ /* 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(!dragging_nodes.empty()){*/ /* SPTR_Node dragNode = dragging_nodes.front();*/ /**/ /* for(auto &n : selected_nodes){*/ /* if(!n->picked_up) n->drag_offset = n->position - dragNode->position;*/ /* n->picked_up = true;*/ /* }*/ /**/ /* if(IsKeyDown(KEY_LEFT_CONTROL)) {*/ /* dragNode->position.x = round((mouse_pos.x + dragNode->drag_offset.x) / state->settings.grid) * state->settings.grid;*/ /* dragNode->position.y = round((mouse_pos.y + dragNode->drag_offset.y) / state->settings.grid) * state->settings.grid;*/ /* } else if(IsKeyDown(KEY_LEFT_SHIFT)){*/ /* float steps = round((dragNode->neighbors.front()->position.dist(mouse_pos)) / state->settings.grid) * state->settings.grid;*/ /* if(dragNode->neighbors.size() > 1){*/ /* Vec2Df dn1 = dragNode->neighbors[0]->position;*/ /* Vec2Df dn2 = dragNode->neighbors[1]->position;*/ /* Vec2Df v1_orth = dn1.center(dn2);*/ /**/ /* if(dn1.x < dn2.x) std::swap(dn1,dn2);*/ /**/ /* float dist = dn1.dist(dn2);*/ /* float dist_orth = std::sqrt(std::pow(steps,2) - std::pow(dist/2,2));*/ /**/ /* if(mouse_pos.y < v1_orth.y) dist_orth *= -1;*/ /**/ /* Vec2Df v1_orth_t = v1_orth + (dn1-dn2).norm().orth() * dist_orth;*/ /* DrawLineV(dn1, dn2, VS_COLOR_RED);*/ /* DrawLineV(v1_orth, v1_orth_t, VS_COLOR_RED);*/ /* DrawCircleV(v1_orth, 3.0f, VS_COLOR_RED);*/ /* dragNode->position = v1_orth_t;*/ /* } else if(!dragNode->neighbors.empty()){*/ /* float pol_r = steps;*/ /* float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - dragNode->neighbors.front()->position));*/ /* Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); */ /* dragNode->position = dragNode->neighbors.front()->position + polar;*/ /* }*/ /* } else {*/ /* dragNode->position = mouse_pos + dragNode->drag_offset;*/ /* }*/ /**/ /* for(auto &n : selected_nodes){*/ /* n->position = dragNode->position + n->drag_offset;*/ /* }*/ /**/ /* if(mouse_released) {*/ /* for(auto &n : dragging_nodes){*/ /* n->dragging = false;*/ /* n->picked_up = false;*/ /* }*/ /* for(auto &n : selected_nodes){*/ /* n->picked_up = false;*/ /* n->dragging = false;*/ /* }*/ /* }*/ /* }*/ /* break;*/ /* }*/ /* 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:*/ /* {*/ /* Vec2Df connector_position = connecting_nodes.front()->position - ((connecting_nodes.front()->position - mouse_pos)).norm() * (connecting_nodes.front()->radius + 14.0f);*/ /* Vec2Df target_position = mouse_pos;*/ /**/ /* if(IsKeyDown(KEY_LEFT_CONTROL)) {*/ /* target_position.x = round((mouse_pos.x) / state->settings.grid) * state->settings.grid;*/ /* target_position.y = round((mouse_pos.y) / state->settings.grid) * state->settings.grid;*/ /* } else if(IsKeyDown(KEY_LEFT_SHIFT)){*/ /* std::shared_ptr closest = app.gm.getClosestNode(mouse_pos);*/ /* float steps = round((closest->position.dist(mouse_pos)) / state->settings.grid) * state->settings.grid;*/ /* float pol_r = steps;*/ /* float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - closest->position));*/ /**/ /* Vec2Df polar = VISEQ::VMATH::polarToCartesian(pol_r, pol_theta); */ /* target_position = closest->position + polar;*/ /* } else {*/ /* target_position = mouse_pos;*/ /* }*/ /**/ /* if(connecting_nodes.front()->connecting && mouse_down){*/ /* DrawLine(connector_position.x, connector_position.y, target_position.x, target_position.y, (Color){229, 181, 103, 255});*/ /* connecting_nodes.front()->hover_connect = true;*/ /* }*/ /**/ /* if(!hovering_connectors.empty()) {*/ /* hovering_connectors.front()->hover_connect = 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(), hovering_nodes.front());*/ /* } else if(!hovering_connectors.empty()){*/ /* app.gm.addConnection(connecting_nodes.front(), hovering_connectors.front());*/ /* } else {*/ /* SPTR_Node new_node = app.gm.copyNode(std::dynamic_pointer_cast(connecting_nodes.front()), target_position);*/ /* new_node->connecting = false;*/ /* app.gm.addConnection(connecting_nodes.front(), new_node);*/ /* }*/ /* }*/ /* connecting_nodes.front()->connecting = false;*/ /* istate = InteractionState::HOVER_CANVAS;*/ /* }*/ /* break;*/ /* }*/ /* case InteractionState::DELETE_SELECTED_NODES:*/ /* {*/ /* app.removeNodes(selected_nodes | std::ranges::to());*/ /* break;*/ /* }*/ /* case InteractionState::COPY_SELECTED_NODES:*/ /* {*/ /* std::ranges::copy(selected_nodes.begin(), selected_nodes.end(), std::back_inserter(copied_nodes));*/ /* std::ranges::for_each(selected_nodes.begin(), selected_nodes.end(), [](SPTR_Node n){n->selected = false;});*/ /* selected_nodes.clear();*/ /* break;*/ /* }*/ /* case InteractionState::PASTE_SELECTED_NODES:*/ /* {*/ /* for(auto n: copied_nodes){*/ /* n->drag_offset = (n->position - copied_nodes.front()->position);*/ /* }*/ /* app.copyNodesAndConnections(copied_nodes, mouse_pos);*/ /* //copied_nodes.clear();*/ /* break;*/ /* }*/ /*};*/ canvas.update(); app.update(); canvas.draw(); app.draw(SCREEN_MOUSE, canvas.camera); canvas.drawEnd(); app.drawUI(SCREEN_MOUSE, canvas.camera); EndDrawing(); } std::ofstream file("state.json"); file << json(app); std::cout << std::setw(4) << json(app) << std::endl; CloseWindow(); return 0; }