im scared now

This commit is contained in:
lachrymaLF 2024-06-24 08:32:01 -04:00
parent 68d06aa660
commit 2438b8b89d
12 changed files with 190 additions and 164 deletions

View file

@ -16,7 +16,7 @@ add_executable (Keishiki ${IMGUI_SRC} ${IMPLOT_SRC}
set_property(TARGET Keishiki PROPERTY CXX_STANDARD 23) set_property(TARGET Keishiki PROPERTY CXX_STANDARD 23)
include_directories ("include" "include/ext" "ext/imgui" "ext/implot") include_directories ("include" "include/ext" "ext/imgui" "ext/implot" "ext/plf_colony")
add_subdirectory("ext/freetype") add_subdirectory("ext/freetype")
add_subdirectory("ext/bgfx") add_subdirectory("ext/bgfx")

View file

@ -4,7 +4,7 @@
namespace K::Plugboard { namespace K::Plugboard {
bool DetectCycle(const NodeInstanceP n, Vector<NodeInstanceP> nodes) { // true if cycle found bool DetectCycle(const NodeInstanceP n, Vector<NodeInstanceP> nodes) { // true if cycle found
return !DFS(n, [&nodes](ConnectInfo info){ return !DFS(n, [&nodes](ConnectInfo info){
if (std::find(nodes.begin(), nodes.end(), info.p) == nodes.end()) { if (std::ranges::find(nodes, info.p) == nodes.end()) {
nodes.push_back(info.p); nodes.push_back(info.p);
return true; return true;
} }
@ -37,57 +37,11 @@ namespace K::Plugboard {
} }
void Disconnect(NodeInstanceP from_instance, u8 input_index) { void Disconnect(NodeInstanceP from_instance, u8 input_index) {
std::visit([&](auto&& from) { std::visit([&input_index](auto&& from) {
std::visit([&](auto &&arg) { Disconnect(*from, input_index);
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ConnectInfo>) {
std::visit([&](auto&& a) {
auto& v = a->out[arg.index].outgoing;
for (auto it = v.begin(); it != v.end(); it++) {
if (it->p == from_instance) {
v.erase(it);
break;
}
}
}, arg.p);
from->in[input_index].value = ExpandVariant(from->in[input_index].type);
}
else if constexpr (std::is_same_v<T, T_Map<Type::T_Count>::type>)
; // already disconnected
}, from->in[input_index].value);
}, from_instance); }, from_instance);
} }
/* NodeInstance MakeInstance(K_P_Nodes i) {
static NodeInstance table[] = {
Add{},
Negate{},
Subtract{},
Multiply{},
Divide{},
Sign{},
Sin{},
Cos{},
Tan{},
Arcsin{},
Arccos{},
Arctan{},
Atan2{},
Minimum{},
Maximum{},
Power{},
SquareRoot{},
NaturalLogarithm{},
AbsoluteValue{},
Interpolation{},
Chain{},
CompositionIn{},
CompositionOut{}
};
static_assert(sizeof(table)/sizeof(table[0]) == K_P_Count);
return table[i];
}*/
T_Map<T_Count>::type ExpandVariant(u32 i) { T_Map<T_Count>::type ExpandVariant(u32 i) {
static T_Map<T_Count>::type table[] = { f32{}, i32{}, RGBA{}, XY{}, XYZ{}, String{} }; static T_Map<T_Count>::type table[] = { f32{}, i32{}, RGBA{}, XY{}, XYZ{}, String{} };
return table[i]; return table[i];

View file

@ -58,7 +58,7 @@ namespace ImGui {
namespace K::UI { namespace K::UI {
void AddTransformLayer(CompState& s, const std::string& name) { void AddTransformLayer(CompState& s, const String& name) {
auto l = Layer{ auto l = Layer{
VisualTrack{}, VisualTrack{},
name, name,
@ -188,8 +188,7 @@ namespace K::UI {
template <Plugboard::Node N> template <Plugboard::Node N>
void PlugboardNodeDrawSockets(CompState& s, N& n, ImGuiStyle& style, void PlugboardNodeDrawSockets(CompState& s, N& n, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& link_pos, bool& dragging_on_socket, ImVec2& source, bool dummy = true) {
bool dummy = true) {
i32 row = 1; i32 row = 1;
for (u32 out = 0; out < n.out.size(); out++, row++) { for (u32 out = 0; out < n.out.size(); out++, row++) {
ImGui::PushID(row); ImGui::PushID(row);
@ -224,7 +223,7 @@ namespace K::UI {
// Update link info if needed // Update link info if needed
if (!n.out[out].outgoing.empty()) {\ if (!n.out[out].outgoing.empty()) {\
link_pos[{&n, out}].source = ImGui::GetCursorScreenPos() + ImVec2{ImGui::GetFrameHeight() / 2, s.plugboard.links_pos[{&n, out}].source = ImGui::GetCursorScreenPos() + ImVec2{ImGui::GetFrameHeight() / 2,
-ImGui::GetFrameHeight() / 2 - -ImGui::GetFrameHeight() / 2 -
style.ItemInnerSpacing.y}; style.ItemInnerSpacing.y};
} }
@ -255,13 +254,13 @@ namespace K::UI {
ImGui::TextUnformatted(n.in[in].name.c_str()); ImGui::TextUnformatted(n.in[in].name.c_str());
// Update link info // Update link info
std::visit([&socket_link_pos, &dragging_on_socket, &source, &link_pos](auto&& arg) { std::visit([&socket_link_pos, &dragging_on_socket, &source, &s](auto&& arg) {
using T = std::decay_t<decltype(arg)>; using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) { if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) {
if (ImGui::IsItemActive()) if (ImGui::IsItemActive())
link_pos[arg].sinks.push_back(ImGui::GetMousePos()); s.plugboard.links_pos[arg].sinks.push_back(ImGui::GetMousePos());
else else
link_pos[arg].sinks.push_back(socket_link_pos); s.plugboard.links_pos[arg].sinks.push_back(socket_link_pos);
} }
else if (ImGui::IsItemActive()) { else if (ImGui::IsItemActive()) {
dragging_on_socket = true; dragging_on_socket = true;
@ -279,15 +278,16 @@ namespace K::UI {
} }
template <Plugboard::Node N> template <Plugboard::Node N>
bool PlugboardDrawNode(CompState& s, N& n, ImVec2& view_pos, ImGuiIO& io, ImGuiStyle& style, void PlugboardDrawNode(CompState& s, N& n, ImVec2& view_pos, ImGuiIO& io, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& link_pos) { bool& dragging_on_socket, ImVec2& source, bool& delete_request) {
bool stat = false; Plugboard::NodeInstanceP ptr{&n};
bool selected = std::ranges::find(s.plugboard.selected_nodes, ptr) != s.plugboard.selected_nodes.end();
const auto& pos = n.pos; const auto& pos = n.pos;
const auto& name = n.name; const auto& name = n.name;
ImGui::SetCursorPos(view_pos + pos); ImGui::SetCursorPos(view_pos + pos);
ImGui::PushID(&n); ImGui::PushID(&n);
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0xAA080813); ImGui::PushStyleColor(ImGuiCol_ChildBg, selected ? 0xAA202040 : 0xAA080813);
static ImVec2 old_pos{}; static ImVec2 old_pos{};
if (ImGui::BeginChild(name, {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Border)) { if (ImGui::BeginChild(name, {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Border)) {
if (ImGui::BeginTable(name, 3)) { if (ImGui::BeginTable(name, 3)) {
@ -295,9 +295,22 @@ namespace K::UI {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Button(name, {100.0f , 0.0f}); ImGui::Button(name, {100.0f , 0.0f});
if (ImGui::BeginPopupContextItem()) {
if (!s.plugboard.selected_nodes.empty() && ImGui::Button("Delete")) {
delete_request = true;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
old_pos = pos; old_pos = pos;
stat = true; if (io.KeyCtrl && !selected) {
s.plugboard.selected_nodes.push_back(ptr);
}
else if (!selected) {
s.plugboard.selected_nodes.clear();
s.plugboard.selected_nodes.push_back(ptr);
}
} }
if (ImGui::IsItemActive()) { if (ImGui::IsItemActive()) {
n.pos = old_pos + ImGui::GetMouseDragDelta(); n.pos = old_pos + ImGui::GetMouseDragDelta();
@ -312,7 +325,7 @@ namespace K::UI {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
} }
PlugboardNodeDrawSockets<N>(s, n, style, dragging_on_socket, source, link_pos); PlugboardNodeDrawSockets<N>(s, n, style, dragging_on_socket, source);
ImGui::EndTable(); ImGui::EndTable();
} }
@ -320,7 +333,6 @@ namespace K::UI {
ImGui::PopStyleColor(); ImGui::PopStyleColor();
ImGui::EndChild(); ImGui::EndChild();
ImGui::PopID(); ImGui::PopID();
return stat;
} }
void TogglePlay() { void TogglePlay() {
@ -352,7 +364,7 @@ namespace K::UI {
view_count++; view_count++;
for (u32 i = s.layers.size() - 1; i != u32(-1); i--) { for (u32 i = s.layers.size() - 1; i != u32(-1); i--) {
if (std::find(s.disabled.begin(), s.disabled.end(), i) != s.disabled.end()) continue; if (std::ranges::find(s.disabled, i) != s.disabled.end()) continue;
if (s.current_frame > s.layers[i].out || s.current_frame < s.layers[i].in) continue; if (s.current_frame > s.layers[i].out || s.current_frame < s.layers[i].in) continue;
s.layers[i].track.GetFrame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, render_fb, s.width, s.layers[i].track.GetFrame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, render_fb, s.width,
@ -417,6 +429,51 @@ namespace K::UI {
}; };
void Composition(CompState& s) { void Composition(CompState& 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", &draw_comp, ImGuiWindowFlags_NoScrollbar)) { if (!ImGui::Begin("Composition", &draw_comp, ImGuiWindowFlags_NoScrollbar)) {
ImGui::End(); ImGui::End();
return; return;
@ -456,38 +513,12 @@ namespace K::UI {
const bool no_selection = s.selected.empty(); const bool no_selection = s.selected.empty();
static String name{}; static String name{};
if (ImGui::Button("Add Layer") && !name.empty()) { if (ImGui::Button("Add Layer") && !name.empty())
AddTransformLayer(s, name); AddTransformLayer(s, name);
}
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(250.0f); ImGui::SetNextItemWidth(250.0f);
ImGui::InputText("##LayerName", &name); ImGui::InputText("##LayerName", &name);
ImGui::SameLine();
ImGui::BeginDisabled(no_selection);
if (ImGui::Button("Delete Layer")) { // todo unregister from plugboard beforehand
if (std::find(s.selected.begin(), s.selected.end(), s.active) != s.selected.end())
s.active = -1;
u32 deleted = 0, before_active = 0;
const u32 sz = s.layers.size();
for (u32 i = 0; i < sz; i++) {
if (std::find(s.selected.begin(), s.selected.end(), i) != s.selected.end()) {
s.layers[i - deleted].track.Clear();
s.layers.erase(s.layers.begin() + i - deleted);
std::erase(s.disabled, i);
if (static_cast<i32>(i) < s.active)
before_active++;
deleted++;
}
else if (std::find(s.disabled.begin(), s.disabled.end(), i) != s.disabled.end()) {
std::erase(s.disabled, i);
s.disabled.push_back(i - deleted);
}
}
s.selected.clear();
s.active -= static_cast<i32>(before_active);
}
ImGui::EndDisabled();
ImGui::SameLine(); ImGui::SameLine();
ImGui::Checkbox("Chain Editor", &show_curve_editor); ImGui::Checkbox("Chain Editor", &show_curve_editor);
@ -526,6 +557,8 @@ namespace K::UI {
for (f32 y = std::fmodf(view_pos.y, grid_inc); y < h; y += grid_inc) for (f32 y = std::fmodf(view_pos.y, grid_inc); y < h; y += grid_inc)
window->DrawList->AddLine(window_pos + ImVec2(0.0f, y), window_pos + ImVec2(w, y), 0xFF222222, 1.0f); window->DrawList->AddLine(window_pos + ImVec2(0.0f, y), window_pos + ImVec2(w, y), 0xFF222222, 1.0f);
// why are we re-getting positions on each frame?
// this is just convenient because sometimes we would be dragging on a socket!
s.plugboard.links_pos.clear(); s.plugboard.links_pos.clear();
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
@ -539,7 +572,7 @@ namespace K::UI {
(([&](auto&& arg){ (([&](auto&& arg){
for (auto& node : arg) { for (auto& node : arg) {
PlugboardDrawNode<std::decay_t<decltype(node)>>(s, node, view_pos, io, style, dragging_on_socket, PlugboardDrawNode<std::decay_t<decltype(node)>>(s, node, view_pos, io, style, dragging_on_socket,
drag_source, s.plugboard.links_pos); drag_source, node_delete_requested);
} }
}(args)), ...); }(args)), ...);
}, s.plugboard.nodes.nodes); }, s.plugboard.nodes.nodes);
@ -551,8 +584,7 @@ namespace K::UI {
ImGuiChildFlags_AutoResizeY); ImGuiChildFlags_AutoResizeY);
ImGui::PopStyleColor(); ImGui::PopStyleColor();
if (ImGui::BeginTable("Composition In", 3)) { if (ImGui::BeginTable("Composition In", 3)) {
PlugboardNodeDrawSockets(s, s.plugboard.in, style, dragging_on_socket, drag_source, PlugboardNodeDrawSockets(s, s.plugboard.in, style, dragging_on_socket, drag_source, false);
s.plugboard.links_pos, false);
ImGui::EndTable(); ImGui::EndTable();
} }
@ -578,15 +610,13 @@ namespace K::UI {
f32 view_amt = view_right - view_left, mouse_tl_x; f32 view_amt = view_right - view_left, mouse_tl_x;
f32 fr_step; f32 fr_step;
static Vector<Plugboard::NodeInstanceP> selected_chains{};
// Mouse Handlers // Mouse Handlers
// Drag playhead/pan // Drag playhead/pan
static bool tl_clear_selection_request = false; static bool tl_clear_selection_request = false;
bool tl_clear_selection_request_this_frame = tl_clear_selection_request; bool tl_clear_selection_request_this_frame = tl_clear_selection_request;
static bool bg_drag_select_active = false; static bool bg_drag_select_active = false;
static Vector<Plugboard::ChainSegment*> keys_selected_by_bg_drag{}; static Vector<Plugboard::ChainSegment*> keys_selected_by_bg_drag{};
auto draw_tl_bg_drag_area = [&view_width, &style, &view_amt, &s, &mouse_tl_x, &io](f32 h = 0.0f, f32 w = 0.0f) { 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; 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 + style.CellPadding.y : h});
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
@ -620,6 +650,16 @@ namespace K::UI {
view_right = 1.0f; view_right = 1.0f;
} }
} }
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();
}
}
}
}; };
constexpr static f32 knob_width = 8.0f; constexpr static f32 knob_width = 8.0f;
@ -649,7 +689,8 @@ namespace K::UI {
if (is_sel) if (is_sel)
chain.selected.push_back(pos_index); chain.selected.push_back(pos_index);
} else { }
else {
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
started_dragging = true; // setup dragging & start on next frame started_dragging = true; // setup dragging & start on next frame
@ -665,8 +706,7 @@ namespace K::UI {
&(key_loop_target->segments)[ii]); // This sucks pretty bad... &(key_loop_target->segments)[ii]); // This sucks pretty bad...
chain.selected.push_back(ii); chain.selected.push_back(ii);
} }
auto bg_drag_sel_it = std::find(keys_selected_by_bg_drag.begin(), auto bg_drag_sel_it = std::ranges::find(keys_selected_by_bg_drag,
keys_selected_by_bg_drag.end(),
&(key_loop_target->segments)[ii]); &(key_loop_target->segments)[ii]);
if (is_sel && bg_drag_sel_it != keys_selected_by_bg_drag.end() && if (is_sel && bg_drag_sel_it != keys_selected_by_bg_drag.end() &&
!drag_rect.Contains(k_pos)) { !drag_rect.Contains(k_pos)) {
@ -779,8 +819,8 @@ namespace K::UI {
for (u32 i = 0; i < s.layers.size(); i++) { for (u32 i = 0; i < s.layers.size(); i++) {
auto& current_layer = s.layers[i]; auto& current_layer = s.layers[i];
const bool selected = std::find(s.selected.begin(), s.selected.end(), i) != s.selected.end(), const bool selected = std::ranges::find(s.selected, i) != s.selected.end(),
disabled = std::find(s.disabled.begin(), s.disabled.end(), i) != s.disabled.end(); disabled = std::ranges::find(s.disabled, i) != s.disabled.end();
ImGui::PushID(static_cast<i32>(i)); ImGui::PushID(static_cast<i32>(i));
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height); ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
@ -796,6 +836,13 @@ namespace K::UI {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
{0.0f, (row_height - ImGui::GetTextLineHeight()) / 2.0f}); {0.0f, (row_height - ImGui::GetTextLineHeight()) / 2.0f});
bool layer_open = ImGui::TreeNodeEx(current_layer.name.c_str(), flags); bool layer_open = ImGui::TreeNodeEx(current_layer.name.c_str(), flags);
if (ImGui::BeginPopupContextItem()) {
if (!s.selected.empty() && ImGui::Button("Delete")) {
layer_delete_requested = true;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) { if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
if (io.KeyCtrl) { if (io.KeyCtrl) {
if (selected) if (selected)
@ -970,7 +1017,7 @@ namespace K::UI {
auto& c = s.plugboard.nodes.Store(Plugboard::Chain{}); auto& c = s.plugboard.nodes.Store(Plugboard::Chain{});
Plugboard::Connect(u.connection.p, u.connection.index, &c, 0); Plugboard::Connect(u.connection.p, u.connection.index, &c, 0);
Plugboard::Connect(&c, 0, &s.plugboard.in, 0); Plugboard::Connect(&c, 0, &s.plugboard.in, 0);
auto& nodes = std::get<Plugboard::CompositionOut*>(u.connection.p)->show_nodes[u.connection.index]; auto& nodes = s.plugboard.out.show_nodes[u.connection.index];
nodes.clear(); nodes.clear();
nodes.emplace_back(&c, 0); nodes.emplace_back(&c, 0);
} }
@ -993,24 +1040,12 @@ namespace K::UI {
ImGui::SetNextItemWidth(-FLT_MIN); ImGui::SetNextItemWidth(-FLT_MIN);
if (connected_v.index() == 0) if (auto *v = std::get_if<Plugboard::T_Map<Plugboard::T_Count>::type>(&connected_v))
std::visit([](auto&& arg) { DrawPlugboardVariableEditWidget(*v);
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Float>::type>)
ImGui::DragFloat("##", &arg, 0.005f);
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Int>::type>)
ImGui::DragInt("##", &arg, 0.005f);
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_RGBA>::type>)
ImGui::DragFloat4("##", &arg.r, 0.005f);
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XY>::type>)
ImGui::DragFloat2("##", &arg.x, 0.005f);
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XYZ>::type>)
ImGui::DragFloat3("##", &arg.x, 0.005f);
}, std::get<0>(connected_v));
ImGui::TableSetColumnIndex(3); ImGui::TableSetColumnIndex(3);
ImGui::TableSetColumnIndex(4); ImGui::TableSetColumnIndex(4);
auto p = ImGui::GetCursorScreenPos(); auto p = ImGui::GetCursorScreenPos(); // restored later
// plot uniform if connected // plot uniform if connected
ImPlot::PushStyleVar(ImPlotStyleVar_PlotPadding, {0.0f, 0.0f}); ImPlot::PushStyleVar(ImPlotStyleVar_PlotPadding, {0.0f, 0.0f});
@ -1049,10 +1084,10 @@ namespace K::UI {
ImGui::SetCursorScreenPos(p); ImGui::SetCursorScreenPos(p);
draw_tl_bg_drag_area(); tl_bg_handler();
if (uniform_open && connected_v.index() == 1) { if (uniform_open && connected_v.index() == 1) {
for (const auto& info: std::get<Plugboard::CompositionOut*>(u.connection.p)->show_nodes[u.connection.index]) { for (const auto& info: s.plugboard.out.show_nodes[u.connection.index]) {
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height); ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
@ -1060,15 +1095,15 @@ namespace K::UI {
auto n_flags = ImGuiTreeNodeFlags_SpanFullWidth | auto n_flags = ImGuiTreeNodeFlags_SpanFullWidth |
ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf |
ImGuiTreeNodeFlags_FramePadding; ImGuiTreeNodeFlags_FramePadding;
auto chain_sel_it = std::find(selected_chains.begin(), selected_chains.end(), info.p); auto chain_sel_it = std::ranges::find(s.plugboard.selected_nodes, info.p);
if (chain_sel_it != selected_chains.end()) if (chain_sel_it != s.plugboard.selected_nodes.end())
n_flags |= ImGuiTreeNodeFlags_Selected; n_flags |= ImGuiTreeNodeFlags_Selected;
ImGui::TreeNodeEx(std::visit([](auto&& arg){ return arg->name; }, info.p), n_flags); ImGui::TreeNodeEx(std::visit([](auto&& arg){ return arg->name; }, info.p), n_flags);
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
if (chain_sel_it != selected_chains.end()) if (chain_sel_it != s.plugboard.selected_nodes.end())
selected_chains.erase(chain_sel_it); s.plugboard.selected_nodes.erase(chain_sel_it);
else else
selected_chains.push_back(info.p); s.plugboard.selected_nodes.push_back(info.p);
} }
ImGui::TableSetColumnIndex(2); ImGui::TableSetColumnIndex(2);
@ -1094,8 +1129,8 @@ namespace K::UI {
f32 v = std::get<Plugboard::T_Map<Plugboard::T_Float>::type>( f32 v = std::get<Plugboard::T_Map<Plugboard::T_Float>::type>(
Plugboard::Eval(s, info)); Plugboard::Eval(s, info));
if (ImGui::DragFloat("##value", &v, 0.005f)) { if (ImGui::DragFloat("##value", &v, 0.005f)) {
if (std::find(selected_chains.begin(), selected_chains.end(), info.p) == selected_chains.end()) if (std::ranges::find(s.plugboard.selected_nodes, info.p) == s.plugboard.selected_nodes.end())
selected_chains.push_back(info.p); s.plugboard.selected_nodes.push_back(info.p);
auto l = std::lower_bound(chain.segments.begin(), chain.segments.end(), s.current_frame, auto l = std::lower_bound(chain.segments.begin(), chain.segments.end(), s.current_frame,
[](const Plugboard::ChainSegment& a, i32 b) { return a.frame < b; }); [](const Plugboard::ChainSegment& a, i32 b) { return a.frame < b; });
@ -1137,7 +1172,7 @@ namespace K::UI {
const auto& [k, val, segment] = (key_loop_target->segments)[ii]; const auto& [k, val, segment] = (key_loop_target->segments)[ii];
ImGui::PushID(k); ImGui::PushID(k);
auto sel_it = std::find(key_loop_target->selected.begin(), key_loop_target->selected.end(), ii); auto sel_it = std::ranges::find(key_loop_target->selected, ii);
bool is_sel = sel_it != key_loop_target->selected.end(); bool is_sel = sel_it != key_loop_target->selected.end();
i32 frame = k; i32 frame = k;
@ -1166,13 +1201,13 @@ namespace K::UI {
begin_tl.y + row_height / 2.0f - 2.0f}, {TimelineFrameToScreenView(view_left, view_amt, view_width, nit->frame, begin_tl.y + row_height / 2.0f - 2.0f}, {TimelineFrameToScreenView(view_left, view_amt, view_width, nit->frame,
s.frame_max) + begin_tl.x - kf_tab_width / 2.0f, s.frame_max) + begin_tl.x - kf_tab_width / 2.0f,
begin_tl.y + row_height / 2.0f + 2.0f}, begin_tl.y + row_height / 2.0f + 2.0f},
std::find(chain.selected.begin(), chain.selected.end(), std::distance(chain.segments.begin(), it)) != chain.selected.end() && std::ranges::find(chain.selected, std::distance(chain.segments.begin(), it)) != chain.selected.end() &&
std::find(chain.selected.begin(), chain.selected.end(), std::distance(chain.segments.begin(), nit)) != chain.selected.end() ? 0x88FFAAAA : 0x44AAAAAA); std::ranges::find(chain.selected, std::distance(chain.segments.begin(), nit)) != chain.selected.end() ? 0x88FFAAAA : 0x44AAAAAA);
} }
} }
ImGui::SetCursorScreenPos(begin_tl); ImGui::SetCursorScreenPos(begin_tl);
draw_tl_bg_drag_area(); tl_bg_handler();
} }
} }
ImGui::PopID(); ImGui::PopID();
@ -1184,7 +1219,7 @@ namespace K::UI {
std::visit([table_left, &s](auto &&arg) { std::visit([table_left, &s](auto &&arg) {
using T = std::decay_t<decltype(arg)>; using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>)
s.plugboard.links_pos[arg].sinks.push_back( s.plugboard.links_pos[arg].sinks.push_back( // make nodes connect to collapsed layer row
{table_left, ImGui::GetCursorScreenPos().y - row_height / 2.0f}); {table_left, ImGui::GetCursorScreenPos().y - row_height / 2.0f});
}, std::visit([&u](auto&& arg) -> auto& { return arg->in[u.connection.index].value; }, u.connection.p)); }, std::visit([&u](auto&& arg) -> auto& { return arg->in[u.connection.index].value; }, u.connection.p));
@ -1200,7 +1235,7 @@ namespace K::UI {
tl_end_begin = {tl_init_pos.x, ImGui::GetCursorScreenPos().y}; tl_end_begin = {tl_init_pos.x, ImGui::GetCursorScreenPos().y};
if (move_from != -1 && move_to != -1) { if (move_from != -1 && move_to != -1) { // do layer move
if (no_selection) if (no_selection)
std::swap(s.layers[move_to], s.layers[move_from]); std::swap(s.layers[move_to], s.layers[move_from]);
else { else {
@ -1243,7 +1278,7 @@ namespace K::UI {
ImGui::SetCursorScreenPos(tl_end_begin); ImGui::SetCursorScreenPos(tl_end_begin);
if (ImGui::BeginChild("TL Bottom Unfilled Drag Overlay")) { if (ImGui::BeginChild("TL Bottom Unfilled Drag Overlay")) {
draw_tl_bg_drag_area(ImGui::GetContentRegionAvail().y); tl_bg_handler(ImGui::GetContentRegionAvail().y);
} }
ImGui::EndChild(); ImGui::EndChild();
@ -1275,9 +1310,12 @@ namespace K::UI {
dragging = false; dragging = false;
} }
u32 keys = 0; u32 keys = 0;
for (const auto& n : selected_chains) { for (const auto& n : s.plugboard.selected_nodes) {
Plugboard::ConnectInfo i {n, 0}; // it's a chain -- 0 is out if (!std::holds_alternative<Plugboard::Chain*>(n))
continue;
auto& [chain, chain_copy] = std::get<Plugboard::Chain*>(n)->extra; auto& [chain, chain_copy] = std::get<Plugboard::Chain*>(n)->extra;
Plugboard::ConnectInfo i {n, 0}; // it's a chain -- 0 is out
if (started_dragging) if (started_dragging)
chain_copy = chain; chain_copy = chain;
@ -1293,9 +1331,9 @@ namespace K::UI {
auto& [k, val, segment] = (key_loop_target->segments)[ii]; auto& [k, val, segment] = (key_loop_target->segments)[ii];
ImGui::PushID(keys++); ImGui::PushID(keys++);
auto sel_it = std::find(key_loop_target->selected.begin(), key_loop_target->selected.end(), ii); auto sel_it = std::ranges::find(key_loop_target->selected, ii);
bool is_sel = sel_it != key_loop_target->selected.end(); bool is_sel = sel_it != key_loop_target->selected.end();
bool is_nxt_sel = ii + 1 < key_loop_target->segments.size() && std::find(key_loop_target->selected.begin(), key_loop_target->selected.end(), ii + 1) != key_loop_target->selected.end(); bool is_nxt_sel = ii + 1 < key_loop_target->segments.size() && std::ranges::find(key_loop_target->selected, ii + 1) != key_loop_target->selected.end();
i32 frame = k; i32 frame = k;
f64 v = val; f64 v = val;
@ -1401,7 +1439,7 @@ namespace K::UI {
ImPlot::PopStyleColor(3); ImPlot::PopStyleColor(3);
ImPlot::PopStyleVar(2); ImPlot::PopStyleVar(2);
ImGui::SetCursorScreenPos(ImGui::GetCursorStartPos()); ImGui::SetCursorScreenPos(ImGui::GetCursorStartPos());
draw_tl_bg_drag_area(ImGui::GetContentRegionAvail().y, ImGui::GetContentRegionAvail().x); tl_bg_handler(ImGui::GetContentRegionAvail().y, ImGui::GetContentRegionAvail().x);
} }
ImGui::EndChild(); ImGui::EndChild();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
@ -1602,12 +1640,12 @@ namespace K::UI {
if (ImGui::Button("Apply")) if (ImGui::Button("Apply"))
for (auto& layer : s.layers) for (auto& layer : s.layers)
for (auto& u : layer.track.uniforms) for (auto& u : layer.track.uniforms)
for (auto& n : std::get<Plugboard::CompositionOut*>(u.connection.p)->show_nodes[u.connection.index]) { for (auto& n : s.plugboard.out.show_nodes[u.connection.index]) {
auto& [chain, _] = std::get<Plugboard::Chain*>(n.p)->extra; auto& [chain, _] = std::get<Plugboard::Chain*>(n.p)->extra;
for (auto it = chain.segments.begin(); it != chain.segments.end(); it++) { for (auto it = chain.segments.begin(); it != chain.segments.end(); it++) {
auto nit = std::next(it); auto nit = std::next(it);
if (nit != chain.segments.end() && std::find(chain.selected.begin(), chain.selected.end(), std::distance(chain.segments.begin(), it)) != chain.selected.end() && if (nit != chain.segments.end() && std::ranges::find(chain.selected, std::distance(chain.segments.begin(), it)) != chain.selected.end() &&
std::find(chain.selected.begin(), chain.selected.end(), std::distance(chain.segments.begin(), nit)) != chain.selected.end()) { std::ranges::find(chain.selected, std::distance(chain.segments.begin(), nit)) != chain.selected.end()) {
it->interp = {type_current, {p2.x, p2.y, p3.x, p3.y}}; it->interp = {type_current, {p2.x, p2.y, p3.x, p3.y}};
} }
} }

View file

@ -192,17 +192,22 @@ namespace K {
ExposeUniform(s, uniforms[i]); ExposeUniform(s, uniforms[i]);
} }
/* void VisualTrack::HideUniform(CompState& s, Uniform& uu) { void VisualTrack::HideUniform(CompState& s, Uniform& uu) {
uu.connection.p->disconnect(uu.connection.index); Plugboard::Disconnect(uu.connection.p, uu.connection.index);
// decrement indices of uniforms referencing CompositionOut whose index is greater
for (auto& l : s.layers) for (auto& l : s.layers)
for (auto& u_other : l.track.uniforms) for (auto& u_other : l.track.uniforms)
if (u_other.connection.index > uu.connection.index) if (u_other.connection.index > uu.connection.index)
u_other.connection.index--; u_other.connection.index--;
s.plugboard.comp_out.in.erase(s.plugboard.out_instance.node->in.begin() + uu.connection.index);
s.plugboard.out_instance.inputs_fed.erase(s.plugboard.out_instance.inputs_fed.begin() + uu.connection.index); if (std::holds_alternative<Plugboard::ConnectInfo>(s.plugboard.out.in[uu.connection.index].value)) {
uu.connection = {nullptr, 0}; Plugboard::Disconnect(s.plugboard.out, uu.connection.index);
}*/ }
s.plugboard.out.in.erase(s.plugboard.out.in.begin() + uu.connection.index);
uu.connection = {(Plugboard::Add*)(nullptr), 0};
}
void VisualTrack::AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val) { void VisualTrack::AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val) {
for (auto& u : uniforms) for (auto& u : uniforms)

@ -1 +1 @@
Subproject commit fdc084f532189fda8474079f79e74fa5e3541c9f Subproject commit 7237d3e5c3a6b837b7b457460877cf5eea8c3745

@ -0,0 +1 @@
Subproject commit fbc8483fb785c431dc4410396815abf886728c40

View file

@ -22,7 +22,7 @@ namespace K {
using String = std::string; using String = std::string;
using Byte = u8; using Byte = u8;
using Char = char; using Char = char;
template <typename T> using Vector = std::vector<T>; template <typename T, typename... Ts> using Vector = std::vector<T, Ts...>;
template <typename... Ts> using Dict = std::unordered_map<Ts...>; template <typename... Ts> using Dict = std::unordered_map<Ts...>;
inline void LogBase(const std::string_view& s, u8 level) { inline void LogBase(const std::string_view& s, u8 level) {

View file

@ -4,6 +4,7 @@
#include <Resource.h> #include <Resource.h>
#include <SDL.h> #include <SDL.h>
#include <numbers> #include <numbers>
#include <cmath>
#include <bgfx/bgfx.h> #include <bgfx/bgfx.h>
@ -129,11 +130,11 @@ namespace K::Graphics {
Qcubed = Q * Q * Q, Qcubed = Q * Q * Q,
D = Qcubed - R * R; D = Qcubed - R * R;
f64 theta = acos(R / sqrt(Qcubed)); f64 theta = acos(R / std::sqrt(Qcubed));
f64 sqrtQ = sqrt(Q); f64 sqrtQ = std::sqrt(Q);
f64 r1 = -2.0 * sqrtQ * cos( theta / 3.0) - a1 / 3.0, f64 r1 = -2.0 * sqrtQ * std::cos( theta / 3.0) - a1 / 3.0,
r2 = -2.0 * sqrtQ * cos((theta + 2.0 * std::numbers::pi) / 3.0) - a1 / 3.0, r2 = -2.0 * sqrtQ * std::cos((theta + 2.0 * std::numbers::pi) / 3.0) - a1 / 3.0,
r3 = -2.0 * sqrtQ * cos((theta + 4.0 * std::numbers::pi) / 3.0) - a1 / 3.0; r3 = -2.0 * sqrtQ * std::cos((theta + 4.0 * std::numbers::pi) / 3.0) - a1 / 3.0;
f64 e = std::pow(std::sqrt(-D) + std::abs(R), 1.0 / 3.0); f64 e = std::pow(std::sqrt(-D) + std::abs(R), 1.0 / 3.0);
e = (R > 0.0) ? -e : e; e = (R > 0.0) ? -e : e;
return Q == 0.0 && D == 0.0 ? -a1 / 3. : (D >= 0 ? CubicRealAccept(r1) ? r1 : (CubicRealAccept(r2) ? r2 : r3) : (e + Q / e) - a1 / 3.); return Q == 0.0 && D == 0.0 ? -a1 / 3. : (D >= 0 ? CubicRealAccept(r1) ? r1 : (CubicRealAccept(r2) ? r2 : r3) : (e + Q / e) - a1 / 3.);

View file

@ -3,7 +3,7 @@
#include "Graphics.h" #include "Graphics.h"
#include <functional> #include <functional>
#include <imgui.h> #include <imgui.h>
#include <list> #include <plf_colony.h>
#include <any> #include <any>
#include <bx/easing.h> #include <bx/easing.h>
#include <utility> #include <utility>
@ -583,11 +583,11 @@ namespace K::Plugboard {
template <SameAsAny<Ns...> N> template <SameAsAny<Ns...> N>
auto& Store(const N& v) { auto& Store(const N& v) {
return std::get<std::list<N>>(nodes).push_back(v); return std::get<plf::colony<N>>(nodes).insert(v);
} }
template <SameAsAny<Ns...> N> template <SameAsAny<Ns...> N>
auto& Store(N&& v) { auto& Store(N&& v) {
return std::get<std::list<N>>(nodes).emplace_back(std::forward<N>(v)); return *std::get<plf::colony<N>>(nodes).emplace(std::forward<N>(v));
} }
auto& Store(const std::variant<Ns...>& v) { auto& Store(const std::variant<Ns...>& v) {
return std::visit([this](auto&& arg) { return store(arg); }, v); return std::visit([this](auto&& arg) { return store(arg); }, v);
@ -596,7 +596,13 @@ namespace K::Plugboard {
return std::visit([this](auto&& arg) { return store(std::forward<decltype(arg)>(arg)); }, std::move(v)); return std::visit([this](auto&& arg) { return store(std::forward<decltype(arg)>(arg)); }, std::move(v));
} }
std::tuple<std::list<Ns>...> nodes; template <SameAsAny<Ns...> N>
auto Remove(N *p) {
auto& colony = std::get<plf::colony<N>>(nodes);
return colony.erase(colony.get_iterator(p));
}
std::tuple<plf::colony<Ns>...> nodes;
template<int N, typename... Ts> using NthTypeOf = template<int N, typename... Ts> using NthTypeOf =
typename std::tuple_element<N, std::tuple<Ts...>>::type; typename std::tuple_element<N, std::tuple<Ts...>>::type;
@ -653,11 +659,31 @@ namespace K::Plugboard {
Dict<ConnectInfo, LinksFromSource, ConnectInfoHasher> links_pos; // this is hilariously bad Dict<ConnectInfo, LinksFromSource, ConnectInfoHasher> links_pos; // this is hilariously bad
CompositionIn in; CompositionIn in;
CompositionOut out; CompositionOut out;
Vector<NodeInstanceP> selected_nodes{};
void RecollectChains(); void RecollectChains();
}; };
void Connect(NodeInstanceP from_instance, u8 input_index, NodeInstanceP to_instance, u8 to_out_index); void Connect(NodeInstanceP from_instance, u8 input_index, NodeInstanceP to_instance, u8 to_out_index);
template <Node N>
void Disconnect(N& instance, u8 input_index) {
if (auto *info = std::get_if<ConnectInfo>(&instance.in[input_index].value)) {
std::visit([&](auto&& a) {
auto& v = a->out[info->index].outgoing;
for (auto it = v.begin(); it != v.end(); it++) {
if (N **p = std::get_if<N*>(&it->p)) {
if (*p == &instance) {
v.erase(it);
break;
}
}
}
}, info->p);
instance.in[input_index].value = ExpandVariant(instance.in[input_index].type);
}
}
void Disconnect(NodeInstanceP from_instance, u8 input_index); void Disconnect(NodeInstanceP from_instance, u8 input_index);

View file

@ -35,7 +35,7 @@ namespace K {
f32 view[16], f32 transform[16]); f32 view[16], f32 transform[16]);
static void ExposeUniform(CompState& s, Uniform& uu); static void ExposeUniform(CompState& s, Uniform& uu);
void ExposeUniform(CompState& s, u32 i); void ExposeUniform(CompState& s, u32 i);
// static void HideUniform(CompState& s, Uniform& uu); static void HideUniform(CompState& s, Uniform& uu);
void AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val); void AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val);
void AddSampler(const String& s); void AddSampler(const String& s);

View file

@ -11,6 +11,7 @@
- [SDL2](https://www.libsdl.org/) - [SDL2](https://www.libsdl.org/)
- [stb](https://github.com/nothings/stb) - [stb](https://github.com/nothings/stb)
- [SRELL](https://www.akenotsuki.com/misc/srell/en/) - [SRELL](https://www.akenotsuki.com/misc/srell/en/)
- [plf::colony](https://plflib.org/colony.htm)
## Runtime Dependency ## Runtime Dependency
- [ffmpeg](https://ffmpeg.org/) - [ffmpeg](https://ffmpeg.org/)

View file

@ -7,11 +7,11 @@
- Blender previews resource - Blender previews resource
- Data models - Data models
- Dump and read back state, (de)serialization!!! - Dump and read back state, (de)serialization!!!
- Pre-compose/Layer Groups (jokes -- can be completely UI side) - Pre-compose/Layer Groups
- Undo's - Undo's
- Node groups - Node groups
- Deleting layers/nodes/keys/etc upkeep
- Motion blur - Motion blur
- Text (idea: index-based evaluation in plugboard) - Text (idea: index-based evaluation in plugboard)
- Shapes (idea: embed glisp :mmtroll:, need to inquire -- still a lot of friction for simple shapes if we don't also get the glisp gizmos) - Shapes (idea: embed glisp :mmtroll:, need to inquire -- still a lot of friction for simple shapes if we don't also get the glisp gizmos)
- External data driving (csv, json or something else?) -- use a node to select source - External data driving (csv, json or something else?) -- use a node to select source