diff --git a/Keishiki/Graphics.cpp b/Keishiki/Graphics.cpp index ea30c17..b06504a 100644 --- a/Keishiki/Graphics.cpp +++ b/Keishiki/Graphics.cpp @@ -1,4 +1,5 @@ #include "Graphics.h" +#include #include #include #include FT_FREETYPE_H @@ -351,15 +352,15 @@ namespace K::Graphics { return pos_x; } - void Composite(u32 view_id, bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]) { + void Composite(bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]) { static f32 pack[4]{}; pack[3] = pack[2] = pack[1] = pack[0] = static_cast(mode); - bgfx::setViewMode(view_id, bgfx::ViewMode::Sequential); - bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR); - bgfx::setViewFrameBuffer(view_id, fb); - bgfx::setViewTransform(view_id, composite_view, proj); - bgfx::setViewRect(view_id, 0, 0, w, h); + bgfx::setViewMode(app_state.render_view, bgfx::ViewMode::Sequential); + bgfx::setViewClear(app_state.render_view, BGFX_CLEAR_COLOR); + bgfx::setViewFrameBuffer(app_state.render_view, fb); + bgfx::setViewTransform(app_state.render_view, composite_view, proj); + bgfx::setViewRect(app_state.render_view, 0, 0, w, h); bgfx::setTransform(transform); bgfx::setVertexBuffer(0, vbh); @@ -368,6 +369,6 @@ namespace K::Graphics { bgfx::setTexture(1, composite_B, composite); // B bgfx::setUniform(composite_mode, pack); // A over B bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A); - bgfx::submit(view_id, composite_pg); + bgfx::submit(app_state.render_view++, composite_pg); } } diff --git a/Keishiki/Keishiki.cpp b/Keishiki/Keishiki.cpp index 179ce61..8250a1e 100644 --- a/Keishiki/Keishiki.cpp +++ b/Keishiki/Keishiki.cpp @@ -46,9 +46,9 @@ namespace K { if (std::ranges::find(disabled, i) != disabled.end()) continue; if (current_frame > layers[i].out || current_frame < layers[i].in) continue; - layers[i].track.GetFrame(*this, app_state.render_view++, render_fb, width, + layers[i].track.GetFrame(*this, render_fb, width, height, proj, view, transform); - Graphics::Composite(app_state.render_view++, composite_fb[(layers_done + 1) % 2], composite[layers_done % 2], render, layers[i].mode, width, height, proj, transform); + Graphics::Composite(composite_fb[(layers_done + 1) % 2], composite[layers_done % 2], render, layers[i].mode, width, height, proj, transform); layers_done++; } @@ -57,6 +57,10 @@ namespace K { } void CompositionState::Destroy() { + for (auto& layer : layers) { + layer.track.Clear(); + } + bgfx::destroy(composite_fb[0]); bgfx::destroy(composite_fb[1]); bgfx::destroy(composite[0]); diff --git a/Keishiki/UI.cpp b/Keishiki/UI.cpp index 7d44970..be67d37 100644 --- a/Keishiki/UI.cpp +++ b/Keishiki/UI.cpp @@ -30,7 +30,7 @@ namespace { draw_interpolation = true, draw_assets = true; - const f32 row_height = 20.0f; + constexpr f32 row_height = 26.0f; // Viewport K::VisualTrack bg{}; @@ -41,6 +41,15 @@ namespace { K::Byte *save_buffer; K::CompositionState *comp_save_called = nullptr; u32 ready_frame; + + enum DeleteRequest { + K_DR_Selected_Compositions, + K_DR_Selected_Layers, + K_DR_Selected_Keys, + K_DR_Selected_Nodes, + K_DR_Count + }; + bool delete_requests[K_DR_Count]{}; } @@ -252,7 +261,7 @@ namespace K::UI { template void PlugboardDrawNode(CompositionState& s, N& n, ImVec2& view_pos, ImGuiIO& io, ImGuiStyle& style, - bool& dragging_on_socket, ImVec2& source, bool& delete_request, Dict& links_pos) { + bool& dragging_on_socket, ImVec2& source, Dict& links_pos) { Plugboard::NodeInstanceP ptr{&n}; bool selected = std::ranges::find(s.plugboard.selected_nodes, ptr) != s.plugboard.selected_nodes.end(); const auto& pos = n.pos; @@ -270,7 +279,7 @@ namespace K::UI { ImGui::Button(name, {100.0f , 0.0f}); if (ImGui::BeginPopupContextItem()) { if (!s.plugboard.selected_nodes.empty() && ImGui::Button("Delete")) { - delete_request = true; + delete_requests[K_DR_Selected_Nodes] = true; ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -337,9 +346,9 @@ namespace K::UI { bgfx::TextureHandle present = BGFX_INVALID_HANDLE; if (do_bg) { - bg.GetFrame(s, app_state.render_view++, s.render_fb, s.width, s.height, s.proj, s.view, s.transform); + bg.GetFrame(s, s.render_fb, s.width, s.height, s.proj, s.view, s.transform); - Graphics::Composite(app_state.render_view++, s.composite_fb[1 - result_index], + Graphics::Composite(s.composite_fb[1 - result_index], s.render, s.composite[result_index], Graphics::K_V_AlphaOver, s.width, s.height, s.proj, s.transform); present = s.composite[1 - result_index]; @@ -392,51 +401,6 @@ namespace K::UI { }; void Composition(CompositionState& s) { - static bool layer_delete_requested = false; - if (layer_delete_requested) { - if (std::ranges::find(s.selected, s.active) != s.selected.end()) // unset active if active is selected - s.active = -1; - u32 deleted = 0, before_active = 0; // stupid counting tricks - const u32 sz = s.layers.size(); - for (u32 j = 0; j < sz; j++) { // im sure this isn't the best way to go about this - if (std::ranges::find(s.selected, j) != s.selected.end()) { - s.layers[j - deleted].track.Clear(); - for (auto& u : s.layers[j - deleted].track.uniforms) - VisualTrack::HideUniform(s, u); - s.layers.erase(s.layers.begin() + j - deleted); - std::erase(s.disabled, j); - if (static_cast(j) < s.active) - before_active++; - deleted++; - } - else if (auto it = std::ranges::find(s.disabled, j); it != s.disabled.end()) - *it -= deleted; - } - s.selected.clear(); - if (s.active != -1) - s.active -= static_cast(before_active); - - layer_delete_requested = false; - } - - static bool node_delete_requested = false; - if (node_delete_requested) { - for (auto p : s.plugboard.selected_nodes) { - std::visit([&s](auto&& arg){ - for (u32 i = 0; i < arg->in.size(); i++) - Plugboard::Disconnect(arg, i); - for (auto& socket : arg->out) - for (Plugboard::ConnectInfo& connection : socket.outgoing) - Plugboard::Disconnect(connection.p, connection.index); - - s.plugboard.nodes.Remove(arg); - }, p); - s.plugboard.RecollectChains(); - } - s.plugboard.selected_nodes.clear(); - node_delete_requested = false; - } - if (!ImGui::Begin("Composition", nullptr, ImGuiWindowFlags_NoScrollbar)) { ImGui::End(); return; @@ -462,7 +426,6 @@ namespace K::UI { if (ImGui::Selectable(s.plugboard.nodes.GetName(static_cast(n)), is_selected)) node_current = n; - // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) ImGui::SetItemDefaultFocus(); } @@ -536,7 +499,7 @@ namespace K::UI { (([&](auto&& arg){ for (auto& node : arg) { PlugboardDrawNode>(s, node, nodes_view_pos, io, style, dragging_on_socket, - drag_source, node_delete_requested, links_pos); + drag_source, links_pos); } }(args)), ...); }, s.plugboard.nodes.nodes); @@ -583,7 +546,7 @@ namespace K::UI { static Vector keys_selected_by_bg_drag{}; auto tl_bg_handler = [&view_width, &style, &view_amt, &s, &mouse_tl_x, &io](f32 h = 0.0f, f32 w = 0.0f) { static f32 pan_x, view_left_old, view_right_old; - ImGui::InvisibleButton("##TL_BG", ImVec2{ w == 0.0f ? view_width + style.CellPadding.x * 2 : w, h == 0.0f ? row_height + style.CellPadding.y : h}); + ImGui::InvisibleButton("##TL_BG", ImVec2{ w == 0.0f ? view_width + style.CellPadding.x * 2 : w, h == 0.0f ? row_height : h}); if (ImGui::IsItemClicked()) { tl_clear_selection_request = !(io.KeyCtrl || io.KeyShift); bg_drag_select_active = !io.KeyShift; @@ -616,14 +579,7 @@ namespace K::UI { } } if (ImGui::IsKeyPressed(ImGuiKey_Delete) && ImGui::IsItemHovered()) { - for (auto& chain : s.plugboard.selected_nodes) { - if (auto *c = std::get_if(&chain)) { - auto& [segments, selected] = (*c)->extra.chain; - for (u32 i : selected) - segments.erase(segments.begin() + i); - selected.clear(); - } - } + delete_requests[K_DR_Selected_Keys] = true; } }; @@ -681,6 +637,10 @@ namespace K::UI { } }; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{}); + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2{}); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{2, 0}); if (ImGui::BeginTable("Layers", 5, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) { ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible ImGui::TableSetupColumn("#", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_IndentDisable); @@ -690,18 +650,13 @@ namespace K::UI { ImGui::TableSetupColumn("##Timeline", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthStretch); - ImGui::TableNextRow(ImGuiTableRowFlags_Headers, row_height); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers, view_height); for (int column = 0; column < 4; column++) { ImGui::TableSetColumnIndex(column); ImGui::TableHeader(ImGui::TableGetColumnName(column)); } - // Timeline controls - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{}); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2{}); - ImGui::TableSetColumnIndex(4); auto *window = ImGui::GetCurrentWindow(); @@ -765,9 +720,8 @@ namespace K::UI { {tl_init_pos.x + view_width * view_left, tl_init_pos.y + view_height * .2f}, {tl_init_pos.x + view_width * view_right, tl_init_pos.y + view_height * .8f}, 0x33FFFFFF, 2.0f); - ImGui::PopStyleVar(3); ImGui::SameLine(); - ImGui::TableHeader(""); + ImGui::TableHeader(""); // TL header // Main rows i32 move_from = -1, move_to = -1; @@ -798,16 +752,15 @@ namespace K::UI { auto flags = base_flags; if (selected) flags |= ImGuiTreeNodeFlags_Selected; - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, - {0.0f, (row_height - ImGui::GetTextLineHeight()) / 2.0f}); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0.0f, (row_height - ImGui::GetTextLineHeight()) / 2.0f}); bool layer_open = ImGui::TreeNodeEx(current_layer.name.c_str(), flags); if (ImGui::BeginPopupContextItem()) { if (!s.selected.empty()) { if (ImGui::Button("Delete")) { - layer_delete_requested = true; + delete_requests[K_DR_Selected_Layers] = true; ImGui::CloseCurrentPopup(); } - if (ImGui::Button("Make Sub-composition")) { + if (ImGui::Button("Make Subcomposition")) { CompositionState new_comp{.width = s.width, .height = s.height}; u32 index_in_new_comp = 0; u64 frame_min = -1, frame_max = 0; @@ -822,8 +775,8 @@ namespace K::UI { new_comp.frame_max = frame_max - frame_min; for (auto& layer : new_comp.layers) layer.in -= frame_min; - layer_delete_requested = true; - app_state.project.compositions.push_back(std::move(new_comp)); + delete_requests[K_DR_Selected_Layers] = true; + app_state.project.compositions.insert(std::move(new_comp)); /* todo make comp */ ImGui::CloseCurrentPopup(); } @@ -900,10 +853,6 @@ namespace K::UI { f32 init_y = ImGui::GetCursorScreenPos().y; if (!show_curve_editor) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{}); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2{}); - const static f32 layer_bound_width = 5.0f; const bool l_le_right_extr = static_cast(current_layer.in) / static_cast(s.frame_max + 1) <= view_right, @@ -923,7 +872,7 @@ namespace K::UI { ImGui::SetCursorPosX(ImGui::GetCursorPosX() + in_pos); static f32 l_in_old; ImGui::PushStyleColor(ImGuiCol_Button, 0xFF666666); - ImGui::Button("##Layer_L", {layer_bound_width, view_height}); + ImGui::Button("##Layer_L", {layer_bound_width, row_height}); if (ImGui::IsItemClicked()) { l_in_old = in_pos; } @@ -943,7 +892,7 @@ namespace K::UI { if (l_le_right_extr && l_ge_left_extr) { ImGui::Button(current_layer.name.c_str(), {std::min(out_pos + fr_step, view_width) - static_cast(l_in) * in_pos - - layer_bound_width * static_cast(l_in + l_out), view_height}); + layer_bound_width * static_cast(l_in + l_out), row_height}); static u32 in_old, out_old; if (ImGui::IsItemClicked()) { in_old = current_layer.in; @@ -960,7 +909,7 @@ namespace K::UI { static f32 r_out_old; ImGui::SameLine(0.0f, 0.0f); ImGui::PushStyleColor(ImGuiCol_Button, 0xFF666666); - ImGui::Button("##Layer_R", {layer_bound_width, view_height}); + ImGui::Button("##Layer_R", {layer_bound_width, row_height}); if (ImGui::IsItemClicked()) { r_out_old = out_pos; } @@ -976,18 +925,11 @@ namespace K::UI { } ImGui::PopStyleColor(); } + + ImGui::SetCursorScreenPos(ImVec2{tl_init_pos.x, init_y}); + tl_bg_handler(); + ImGui::PopID(); - - ImGui::SetCursorScreenPos(ImVec2{tl_init_pos.x, init_y} - style.CellPadding); - ImGui::InvisibleButton("##TL_BG", ImVec2{view_width + style.CellPadding.x * 2, - row_height + style.CellPadding.y}); - if (ImGui::IsItemActive()) { - s.current_frame = TimelineScreenViewToFrame(view_left, view_amt, view_width, - std::clamp(mouse_tl_x, 0.0f, view_width), - s.frame_max); - } - - ImGui::PopStyleVar(3); } if (layer_open) { @@ -1309,6 +1251,7 @@ namespace K::UI { ImGui::EndTable(); } + ImGui::PopStyleVar(4); ImGui::SetCursorScreenPos(nodes_begin); if (ImGui::BeginChild("Node Connection Overlay", {table_left - ImGui::GetWindowPos().x, 0.0f}, false, ImGuiWindowFlags_NoInputs)) { @@ -1331,7 +1274,7 @@ namespace K::UI { } ImGui::EndChild(); - ImVec2 tl_grid_cursor_pos = {tl_init_pos.x, tl_init_pos.y + row_height}; + ImVec2 tl_grid_cursor_pos = {tl_init_pos.x, tl_init_pos.y + view_height}; if (show_curve_editor) { ImGui::SetCursorScreenPos(tl_grid_cursor_pos); ImGui::PushStyleColor(ImGuiCol_ChildBg, 0xFF111111); @@ -1526,10 +1469,7 @@ namespace K::UI { static_cast(s.frame_max + 1), tl_init_pos.y}, {tl_init_pos.x + view_width * static_cast(s.current_frame) / static_cast(s.frame_max + 1), - tl_init_pos.y + view_height}, 0xFF3333FF, 2.0f); - - ImGui::SetCursorScreenPos(tl_init_pos - style.CellPadding); - ImGui::InvisibleButton("##TL_BG", ImVec2{ view_width + style.CellPadding.x * 2, row_height + style.CellPadding.y}); + tl_init_pos.y}, 0xFF3333FF, 2.0f); // Frame Grid static f32 frame_grid_min_width = 20.0f; @@ -1539,14 +1479,14 @@ namespace K::UI { std::ceil(view_left * static_cast(s.frame_max + 1)), s.frame_max) + tl_init_pos.x; fr < tl_init_pos.x + view_width; fr += grid_step) - window->DrawList->AddLine({fr, tl_init_pos.y + row_height}, + window->DrawList->AddLine({fr, tl_init_pos.y}, {fr, ImGui::GetWindowSize().y + tl_init_pos.y}, 0x11FFFFFF, 1.0f); if (TimelineFrameInView(view_left, view_right, s.current_frame, s.frame_max)) { f32 fr = TimelineFrameToScreenView(view_left, view_amt, view_width, s.current_frame, s.frame_max) + tl_init_pos.x; window->DrawList->AddLine( - {fr, tl_init_pos.y + row_height}, + {fr, tl_init_pos.y}, {fr, ImGui::GetWindowSize().y + tl_init_pos.y}, 0x773333FF, 1.0f); } if (bg_drag_select_active) { @@ -1683,15 +1623,37 @@ namespace K::UI { ImGui::TableNextColumn(); ImGui::Text("%s%s", it->name.c_str(), "_dims"); ImGui::TableNextColumn(); - if (ImGui::BeginCombo("##source", it->resource->filename.c_str())) { + const char *r_name = std::visit([](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v*>) { + return arg->filename.c_str(); + } + else if constexpr (std::is_same_v) { + return arg->name.c_str(); + } + }, it->resource); + if (ImGui::BeginCombo("##source", r_name)) { for (auto& [file, res_v] : Resource::resources) if (auto *res = std::get_if>(&res_v)) { - const bool is_selected = it->resource == res; + const bool is_selected = r_name == res->filename.c_str(); // lol if (ImGui::Selectable(file.c_str(), is_selected)) { it->resource = res; it->dims->val = ShaderGraph::XY{static_cast(res->w), static_cast(res->h)}; } + + if (is_selected) + ImGui::SetItemDefaultFocus(); } + for (auto& comp : app_state.project.compositions) { + const bool is_selected = r_name == comp.name.c_str(); // lol + if (ImGui::Selectable(comp.name.c_str(), is_selected)) { + it->resource = ∁ + it->dims->val = ShaderGraph::XY{static_cast(comp.width), static_cast(comp.height)}; + } + + if (is_selected) + ImGui::SetItemDefaultFocus(); + } ImGui::EndCombo(); } ImGui::TableNextColumn(); @@ -1876,8 +1838,7 @@ namespace K::UI { } if (ImGui::Button("OK", ImVec2(120, 0)) && !name.empty()) { - app_state.project.compositions.emplace_back(name, 0, frames, fps, dims[0], dims[1]); - app_state.project.compositions.back().Setup(); + app_state.project.compositions.emplace(name, 0, frames, fps, dims[0], dims[1])->Setup(); ImGui::CloseCurrentPopup(); } ImGui::SetItemDefaultFocus(); @@ -1897,23 +1858,22 @@ namespace K::UI { ImGui::TableSetupColumn("FPS", ImGuiTableColumnFlags_WidthFixed); ImGui::TableHeadersRow(); - for (u32 j = 0; j < app_state.project.compositions.size(); j++) { + for (auto& comp : app_state.project.compositions) { ImGui::TableNextRow(); - ImGui::PushID(j); + ImGui::PushID(&comp); ImGui::TableNextColumn(); - auto& comp = app_state.project.compositions[j]; - bool sel = app_state.project.inspecting_composition == j; + bool sel = app_state.project.inspecting_composition == ∁ if (ImGui::Selectable(comp.name.c_str(), sel, ImGuiSelectableFlags_SpanAllColumns) && !sel) { - app_state.project.inspecting_composition = static_cast(j); + app_state.project.inspecting_composition = ∁ bg.uniforms[0].val = ShaderGraph::XYZ{ - static_cast(app_state.project.compositions[app_state.project.inspecting_composition].width), - static_cast(app_state.project.compositions[app_state.project.inspecting_composition].height), + static_cast(comp.width), + static_cast(comp.height), 0.0f }; } if (sel && ImGui::BeginPopupContextItem()) { if (ImGui::Button("Delete")) { - /* todo this is gonna be rough... */ + delete_requests[K_DR_Selected_Compositions] = true; ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -2013,6 +1973,88 @@ namespace K::UI { ImGui::End(); } + void ProcessDeleteRequests(CompositionState& s) { + if (delete_requests[K_DR_Selected_Compositions]) { + decltype(app_state.project.compositions)::iterator it = app_state.project.compositions.end(); + // comp deletions should be rare, so this should be fine -- change to cache if this becomes a problem + for (auto itt = app_state.project.compositions.begin(); itt != app_state.project.compositions.end(); itt++) { + if (&(*itt) == &s) { + it = itt; + continue; + } + for (auto& layer : itt->layers) + for (auto& sampler : layer.track.samplers) { + sampler.resource = Resource::fallback_still; + sampler.dims->val = ShaderGraph::T_Map::type{ + static_cast(Resource::fallback_still->w), + static_cast(Resource::fallback_still->h) + }; + } + } + it->Destroy(); + if (app_state.project.inspecting_composition == &(*it)) + app_state.project.inspecting_composition = nullptr; + app_state.project.compositions.erase(it); + + delete_requests[K_DR_Selected_Compositions] = false; + } + + if (delete_requests[K_DR_Selected_Layers]) { + if (std::ranges::find(s.selected, s.active) != s.selected.end()) // unset active if active is selected + s.active = -1; + u32 deleted = 0, before_active = 0; // stupid counting tricks + const u32 sz = s.layers.size(); + for (u32 j = 0; j < sz; j++) { // im sure this isn't the best way to go about this + if (std::ranges::find(s.selected, j) != s.selected.end()) { + s.layers[j - deleted].track.Clear(); + for (auto &u: s.layers[j - deleted].track.uniforms) + VisualTrack::HideUniform(s, u); + s.layers.erase(s.layers.begin() + j - deleted); + std::erase(s.disabled, j); + if (static_cast(j) < s.active) + before_active++; + deleted++; + } else if (auto it = std::ranges::find(s.disabled, j); it != s.disabled.end()) + *it -= deleted; + } + s.selected.clear(); + if (s.active != -1) + s.active -= static_cast(before_active); + + delete_requests[K_DR_Selected_Layers] = false; + } + + if (delete_requests[K_DR_Selected_Nodes]) { + for (auto p: s.plugboard.selected_nodes) { + std::visit([&s](auto &&arg) { + for (u32 i = 0; i < arg->in.size(); i++) + Plugboard::Disconnect(arg, i); + for (auto &socket: arg->out) + for (Plugboard::ConnectInfo &connection: socket.outgoing) + Plugboard::Disconnect(connection.p, connection.index); + + s.plugboard.nodes.Remove(arg); + }, p); + s.plugboard.RecollectChains(); + } + s.plugboard.selected_nodes.clear(); + + delete_requests[K_DR_Selected_Nodes] = false; + } + + + if (delete_requests[K_DR_Selected_Keys]) { + for (auto& chain : s.plugboard.selected_nodes) { + if (auto *c = std::get_if(&chain)) { + auto& [segments, selected] = (*c)->extra.chain; + for (u32 i : selected) + segments.erase(segments.begin() + i); + selected.clear(); + } + } + } + } + void Draw() { ImGui_ImplSDL3_NewFrame(); ImGui_Implbgfx_NewFrame(); @@ -2027,8 +2069,8 @@ namespace K::UI { if (draw_assets) Assets(); - if (app_state.project.inspecting_composition >= 0) { - auto &comp = app_state.project.compositions[app_state.project.inspecting_composition]; + if (app_state.project.inspecting_composition != nullptr) { + auto &comp = *app_state.project.inspecting_composition; if (draw_viewport) Viewport(comp); if (draw_layer) Layer(comp); if (draw_comp) Composition(comp); @@ -2040,6 +2082,8 @@ namespace K::UI { static_cast(comp_save_called->width) * 4); comp_save_called = nullptr; } + + ProcessDeleteRequests(comp); } ImGui::Render(); @@ -2125,11 +2169,11 @@ namespace K::UI { bgfx::destroy(bg.uniforms[0].handle); bg.uniforms.erase(bg.uniforms.begin()); - for (auto& comp : app_state.project.compositions) + for (auto& comp : app_state.project.compositions) { for (auto& layer : comp.layers) layer.track.Clear(); - - app_state.project.compositions[app_state.project.inspecting_composition].Destroy(); + comp.Destroy(); + } ImGui_Implbgfx_Shutdown(); ImGui_ImplSDL3_Shutdown(); diff --git a/Keishiki/VisualTrack.cpp b/Keishiki/VisualTrack.cpp index 15e250e..cb8077e 100644 --- a/Keishiki/VisualTrack.cpp +++ b/Keishiki/VisualTrack.cpp @@ -36,14 +36,29 @@ namespace K { },val); } - void VisualTrack::GetFrame(const CompositionState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], + void VisualTrack::GetFrame(const CompositionState& s, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], f32 view[16], f32 transform[16]) { - bgfx::setViewMode(view_id, bgfx::ViewMode::Sequential); - bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR); - bgfx::setViewFrameBuffer(view_id, fb); + std::shared_lock lk{Resource::resource_lock}; + u32 sampler_stage = 0; + for (auto& [_name, handle, res, _u] : samplers) { + bgfx::TextureHandle tx = std::visit([](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v*>) + return arg->tex; + else if constexpr (std::is_same_v) { + i32 slot = arg->GetFrame(0); + return arg->composite[slot]; + } + }, res); + bgfx::setTexture(sampler_stage++, handle, tx, BGFX_SAMPLER_UVW_BORDER); + } - bgfx::setViewTransform(view_id, view, proj); - bgfx::setViewRect(view_id, 0, 0, w, h); + bgfx::setViewMode(app_state.render_view, bgfx::ViewMode::Sequential); + bgfx::setViewClear(app_state.render_view, BGFX_CLEAR_COLOR); + bgfx::setViewFrameBuffer(app_state.render_view, fb); + + bgfx::setViewTransform(app_state.render_view, view, proj); + bgfx::setViewRect(app_state.render_view, 0, 0, w, h); for (auto& u : uniforms) { f32 pack[4]{}; @@ -56,8 +71,8 @@ namespace K { if constexpr (std::is_same_v) { bool good; val_target = PlugboardValToShader(Plugboard::ConvertValue(Plugboard::Eval(s, arg), - static_cast(u.val.index()), // todo DANGEROUS !! - good)); + static_cast(u.val.index()), // todo DANGEROUS !! + good)); } else if constexpr (std::is_same_v::type>) val_target = PlugboardValToShader(arg); @@ -86,13 +101,7 @@ namespace K { bgfx::setUniform(u.handle, pack); } - std::shared_lock lk{Resource::resource_lock}; - u32 sampler_stage = 0; - for (auto& [_name, handle, res, _u] : samplers) { - bgfx::setTexture(sampler_stage++, handle, res->tex, BGFX_SAMPLER_UVW_BORDER); - } - - Graphics::DrawQuad(view_id, transform, BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A, pg); + Graphics::DrawQuad(app_state.render_view++, transform, BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A, pg); } void VisualTrack::Compile() { diff --git a/Keishiki/include/Graphics.h b/Keishiki/include/Graphics.h index 838f773..1222fbd 100644 --- a/Keishiki/include/Graphics.h +++ b/Keishiki/include/Graphics.h @@ -117,7 +117,7 @@ namespace K::Graphics { "Invalid" }; - void Composite(u32 view_id, bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]); + void Composite(bgfx::FrameBufferHandle fb, bgfx::TextureHandle composite, bgfx::TextureHandle from, Blending mode, u16 w, u16 h, f32 proj[16], f32 transform[16]); constexpr static bool CubicRealAccept(f64 t) { return 0.0 <= t && t <= 1.0; diff --git a/Keishiki/include/Keishiki.h b/Keishiki/include/Keishiki.h index b9096cd..2b4533d 100644 --- a/Keishiki/include/Keishiki.h +++ b/Keishiki/include/Keishiki.h @@ -3,6 +3,7 @@ #include "Plugboard.h" #include "VisualTrack.h" #include +#include namespace K { struct Layer { @@ -41,8 +42,8 @@ namespace K { }; struct ProjectState { - i32 inspecting_composition = -1; - Vector compositions{}; + CompositionState *inspecting_composition; + plf::colony compositions{}; }; extern struct AppState { diff --git a/Keishiki/include/VisualTrack.h b/Keishiki/include/VisualTrack.h index 30e0b0d..f815a65 100644 --- a/Keishiki/include/VisualTrack.h +++ b/Keishiki/include/VisualTrack.h @@ -26,7 +26,7 @@ namespace K { struct Sampler { String name; bgfx::UniformHandle handle; - Resource::Resource *resource; + std::variant*, CompositionState*> resource; Uniform *dims; }; @@ -40,7 +40,7 @@ namespace K { String shader; Vector uniforms; Vector samplers; - void GetFrame(const CompositionState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], + void GetFrame(const CompositionState& s, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], f32 view[16], f32 transform[16]); static void ExposeUniform(CompositionState& s, Uniform& uu); void ExposeUniform(CompositionState& s, u32 i);