finally fixed the timeline

This commit is contained in:
lachrymaLF 2024-06-28 19:34:07 -04:00
parent cacc2d48ca
commit 25468bad25
7 changed files with 205 additions and 146 deletions

View file

@ -1,4 +1,5 @@
#include "Graphics.h"
#include <Keishiki.h>
#include <Resource.h>
#include <ft2build.h>
#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<f32>(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);
}
}

View file

@ -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]);

View file

@ -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 <Plugboard::Node N>
void PlugboardDrawNode(CompositionState& s, N& n, ImVec2& view_pos, ImGuiIO& io, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, bool& delete_request, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& links_pos) {
bool& dragging_on_socket, ImVec2& source, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& 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<i32>(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<i32>(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<Plugboard::K_P_Nodes>(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<std::decay_t<decltype(node)>>(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<Plugboard::ChainSegment*> 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<Plugboard::Chain*>(&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<f32>(current_layer.in) / static_cast<f32>(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<f32>(l_in) * in_pos -
layer_bound_width * static_cast<f32>(l_in + l_out), view_height});
layer_bound_width * static_cast<f32>(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<f32>(s.frame_max + 1), tl_init_pos.y},
{tl_init_pos.x + view_width * static_cast<f32>(s.current_frame) /
static_cast<f32>(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<f32>(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<decltype(arg)>;
if constexpr (std::is_same_v<T, Resource::Resource<Resource::K_R_Still>*>) {
return arg->filename.c_str();
}
else if constexpr (std::is_same_v<T, CompositionState*>) {
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<Resource::Resource<Resource::K_R_Still>>(&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<f32>(res->w), static_cast<f32>(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 = &comp;
it->dims->val = ShaderGraph::XY{static_cast<f32>(comp.width), static_cast<f32>(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 == &comp;
if (ImGui::Selectable(comp.name.c_str(), sel, ImGuiSelectableFlags_SpanAllColumns) && !sel) {
app_state.project.inspecting_composition = static_cast<i32>(j);
app_state.project.inspecting_composition = &comp;
bg.uniforms[0].val = ShaderGraph::XYZ{
static_cast<f32>(app_state.project.compositions[app_state.project.inspecting_composition].width),
static_cast<f32>(app_state.project.compositions[app_state.project.inspecting_composition].height),
static_cast<f32>(comp.width),
static_cast<f32>(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<ShaderGraph::T_XY>::type{
static_cast<f32>(Resource::fallback_still->w),
static_cast<f32>(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<i32>(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<i32>(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<Plugboard::Chain*>(&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<i32>(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();

View file

@ -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<decltype(arg)>;
if constexpr (std::is_same_v<T, Resource::Resource<Resource::K_R_Still>*>)
return arg->tex;
else if constexpr (std::is_same_v<T, CompositionState*>) {
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<T, Plugboard::ConnectInfo>) {
bool good;
val_target = PlugboardValToShader(Plugboard::ConvertValue(Plugboard::Eval(s, arg),
static_cast<Plugboard::Type>(u.val.index()), // todo DANGEROUS !!
good));
static_cast<Plugboard::Type>(u.val.index()), // todo DANGEROUS !!
good));
}
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Count>::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() {

View file

@ -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;

View file

@ -3,6 +3,7 @@
#include "Plugboard.h"
#include "VisualTrack.h"
#include <atomic>
#include <plf_colony.h>
namespace K {
struct Layer {
@ -41,8 +42,8 @@ namespace K {
};
struct ProjectState {
i32 inspecting_composition = -1;
Vector<CompositionState> compositions{};
CompositionState *inspecting_composition;
plf::colony<CompositionState> compositions{};
};
extern struct AppState {

View file

@ -26,7 +26,7 @@ namespace K {
struct Sampler {
String name;
bgfx::UniformHandle handle;
Resource::Resource<Resource::K_R_Still> *resource;
std::variant<Resource::Resource<Resource::K_R_Still>*, CompositionState*> resource;
Uniform *dims;
};
@ -40,7 +40,7 @@ namespace K {
String shader;
Vector<Uniform> uniforms;
Vector<Sampler> 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);