diff --git a/.gitmodules b/.gitmodules index 0982fa9..7966777 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "Keishiki/ext/freetype"] path = Keishiki/ext/freetype url = https://github.com/freetype/freetype.git -[submodule "Keishiki/ext/ImNodeFlow"] - path = Keishiki/ext/ImNodeFlow - url = https://github.com/Fattorino/ImNodeFlow.git diff --git a/Keishiki/UI.cpp b/Keishiki/UI.cpp index 27dd04e..2a321de 100644 --- a/Keishiki/UI.cpp +++ b/Keishiki/UI.cpp @@ -19,7 +19,8 @@ namespace { draw_plugboard = true, draw_shader = true, draw_comp = true, - draw_interpolation = true; + draw_interpolation = true, + draw_properties = true; const f32 row_height = 20.0f; @@ -340,7 +341,7 @@ namespace K::UI { } void PlugboardNodeDrawSockets(PlugboardGraph::NodeInstance& n, ImGuiStyle& style, - bool& dragging_on_socket, ImVec2& source, std::unordered_map& link_pos, + bool& dragging_on_socket, ImVec2& source, std::unordered_map& link_pos, bool dummy = true) { i32 row = 1; for (u32 out = 0; out < n.node->out_names.size(); out++, row++) { @@ -374,12 +375,13 @@ namespace K::UI { ImGui::PopID(); // Update link info if needed - if (n.outputs_going[out].p != nullptr) { - auto pos = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y}; - auto& d = link_pos[std::get(n.outputs_going[out].p->inputs_fed[n.outputs_going[out].index])]; - d.w = pos.x; - d.z = pos.y; - } + if (n.outputs_going[out].p != nullptr) + std::visit([&link_pos, &style](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) + link_pos[arg].source = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y}; + }, n.outputs_going[out].p->inputs_fed[n.outputs_going[out].index]); + } for (u32 in = 0; in < n.inputs_fed.size(); in++, row++) { ImGui::PushID(row); @@ -405,12 +407,11 @@ namespace K::UI { } // Update link info if needed - if (n.inputs_fed[in].index() == 0) { - auto pos = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y}; - auto& d = link_pos[std::get(n.inputs_fed[in])]; - d.x = pos.x; - d.y = pos.y; - } + std::visit([&link_pos, &style](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) + link_pos[arg].sinks.push_back(ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y}); + }, n.inputs_fed[in]); ImGui::TableNextColumn(); ImGui::Text("%s", n.node->in_names[in].c_str()); @@ -421,10 +422,10 @@ namespace K::UI { } void PlugboardDrawNode(PlugboardGraph::NodeInstance& n, ImVec2& view_pos, i32 id, ImGuiIO& io, ImGuiStyle& style, - bool& dragging_on_socket, ImVec2& source, std::unordered_map& link_pos) { + bool& dragging_on_socket, ImVec2& source, std::unordered_map& link_pos) { ImGui::SetCursorPos(view_pos + n.pos); ImGui::PushID(id); - ImGui::PushStyleColor(ImGuiCol_ChildBg, 0xFF080813); + ImGui::PushStyleColor(ImGuiCol_ChildBg, 0xAA080813); ImGui::BeginChild(n.node->name.c_str(), {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Border); ImGui::PopStyleColor(); if (ImGui::BeginTable(n.node->name.c_str(), 3)) { @@ -498,8 +499,9 @@ namespace K::UI { view_pos = old_view_pos + (io.MousePos - io.MouseClickedPos[0]); } - for (u32 i = 0; i < s.plugboard.nodes.size(); i++) - PlugboardDrawNode(s.plugboard.nodes[i], view_pos, i, io, style, dragging_on_socket, drag_source, s.plugboard.links_pos); + u32 i = 0; + for (auto it = s.plugboard.nodes.begin(); it != s.plugboard.nodes.end(); it++, i++) + PlugboardDrawNode(*it, view_pos, i, io, style, dragging_on_socket, drag_source, s.plugboard.links_pos); ImGui::SetCursorPos({}); ImGui::PushStyleColor(ImGuiCol_ChildBg, 0x33FFFFFF); @@ -526,7 +528,8 @@ namespace K::UI { right_offset += ImGui::GetItemRectMax().x - ImGui::GetWindowWidth(); for (auto& [_, link] : s.plugboard.links_pos) - window->DrawList->AddLine({link.x, link.y}, {link.w, link.z}, 0xFFFFFFFF, 2.0f); + for (auto& sink : link.sinks) + window->DrawList->AddLine(link.source, sink, 0xFFFFFFFF, 2.0f); if (dragging_on_socket) window->DrawList->AddLine(ImGui::GetMousePos(), drag_source, 0xFFFFFFFF, 2.0f); @@ -534,7 +537,7 @@ namespace K::UI { ImGui::EndChild(); ImGui::End(); -} + } void Shader(CompState& s) { if (ImGui::Begin("Shader", &draw_shader)) { @@ -585,7 +588,7 @@ namespace K::UI { it->second.exposure = {&s.plugboard.out_instance, static_cast(s.plugboard.out_instance.node->in_names.size())}; s.plugboard.out_instance.node->in_names.push_back(id); s.plugboard.out_instance.node->in_types.push_back(PlugboardGraph::Type(it->second.val.index())); // this is shaky and bug prone -- relies on the shader types being in line with plugboard types - s.plugboard.out_instance.inputs_fed.push_back(ShaderValToPlugboard(it->second.val)); + s.plugboard.out_instance.inputs_fed.emplace_back(ShaderValToPlugboard(it->second.val)); } else { it->second.exposure.p->disconnect(it->second.exposure.index); @@ -639,6 +642,14 @@ namespace K::UI { void Interpolation(CompState& s) { if (ImGui::Begin("Interpolation", &draw_interpolation)) { + + } + ImGui::End(); + } + + void Properties(CompState& s) { + if (ImGui::Begin("Properties", &draw_properties)) { + } ImGui::End(); } @@ -650,7 +661,7 @@ namespace K::UI { ImGui::DockSpaceOverViewport(ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); -// ImGui::ShowDemoWindow(); + ImGui::ShowDemoWindow(); static ImGuiStyle& style = ImGui::GetStyle(); style.GrabRounding = style.FrameRounding = 5.0f; MainMenuBar(s); @@ -659,6 +670,7 @@ namespace K::UI { if (draw_plugboard) Plugboard(s); if (draw_comp) Composition(s); if (draw_interpolation) Interpolation(s); + if (draw_properties) Properties(s); if (save_called && ready_frame == frame) { stbi_write_png("frame.png", s.width, s.height, 4, save_buffer, s.width * 4); diff --git a/Keishiki/ext/ImNodeFlow b/Keishiki/ext/ImNodeFlow deleted file mode 160000 index 3e4ed6e..0000000 --- a/Keishiki/ext/ImNodeFlow +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3e4ed6e5b51cc9a874480b94f112d5965b0412b0 diff --git a/Keishiki/include/PlugboardGraph.h b/Keishiki/include/PlugboardGraph.h index fe70258..59bb942 100644 --- a/Keishiki/include/PlugboardGraph.h +++ b/Keishiki/include/PlugboardGraph.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace K::PlugboardGraph { enum Type { @@ -72,7 +73,8 @@ namespace K::PlugboardGraph { struct NodeInstance; struct ConnectInfo { - NodeInstance *p; u32 index; + NodeInstance *p; // NOTE: so NodeInstances must be stored in a list, otherwise vector realloc leads to UAF + u32 index; auto operator<=>(const ConnectInfo&) const = default; }; @@ -85,9 +87,9 @@ namespace K::PlugboardGraph { }; struct NodeInstance { - Node *node; + Node *node; // should be safe if we require those to be static, UAF might pop up later - Vector::type>> inputs_fed; + Vector::type, ConnectInfo>> inputs_fed; Vector outputs_going; ImVec2 pos, old_pos; @@ -111,10 +113,10 @@ namespace K::PlugboardGraph { inline NodeInstance MakeInstance(Node& n) { - Vector::type>> inp; + Vector::type, ConnectInfo>> inp; Vector out; for (auto t : n.in_types) - inp.push_back(expand_type(t)); + inp.emplace_back(expand_type(t)); for (auto t : n.out_types) out.push_back({}); return { @@ -137,16 +139,21 @@ namespace K::PlugboardGraph { return info.p->node->fetch[info.index](pack); } + struct LinksFromSource { + ImVec2 source; + Vector sinks; + }; + struct PlugboardGraph { - Vector nodes; - std::unordered_map links_pos; // this is hilariously bad + std::list nodes; // OK complexity wise since we would usually traverse the entire thing anyway, locality will likely be bad + std::unordered_map links_pos; // this is hilariously bad Node comp_in = { "Composition In", {}, {}, {"Time"}, {T_Float}, - {[](Vector::type> v) { return T_Map::type{ static_cast(SDL_GetTicks()) / 20.0f }; }} // kill me + {[](const Vector::type>& v) { return T_Map::type{ static_cast(SDL_GetTicks()) / 20.0f }; }} // kill me }, comp_out = { "Composition Out",