finally fixed the timeline
This commit is contained in:
parent
cacc2d48ca
commit
25468bad25
7 changed files with 205 additions and 146 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
278
Keishiki/UI.cpp
278
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 <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 = ∁
|
||||
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 == ∁
|
||||
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 = ∁
|
||||
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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue