From e51e684875b4de9532ca44524c89362dfc5b0fde Mon Sep 17 00:00:00 2001 From: lachrymaLF Date: Wed, 12 Jun 2024 22:52:34 -0400 Subject: [PATCH] temp solution for loops and chains --- Keishiki/Keishiki.cpp | 6 +- Keishiki/PlugboardGraph.cpp | 38 ++- Keishiki/PlugboardNodes.cpp | 490 ++++++++++++++++++++++++++++ Keishiki/UI.cpp | 224 ++++++------- Keishiki/VisualTrack.cpp | 5 +- Keishiki/include/PlugboardGraph.h | 50 +-- Keishiki/include/PlugboardNodes.h | 512 ++---------------------------- Keishiki/include/VisualTrack.h | 16 +- TODO.md | 24 +- 9 files changed, 708 insertions(+), 657 deletions(-) create mode 100644 Keishiki/PlugboardNodes.cpp diff --git a/Keishiki/Keishiki.cpp b/Keishiki/Keishiki.cpp index 6105ebf..c73b3aa 100644 --- a/Keishiki/Keishiki.cpp +++ b/Keishiki/Keishiki.cpp @@ -20,13 +20,13 @@ namespace { namespace K { K::AppState app_state; - PlugboardGraph::T_Map::type FetchCompFrame(const CompState& s, const PlugboardGraph::NodeInstance& n) { + PlugboardGraph::T_Map::type FetchCompFrame(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes = nullptr) { return PlugboardGraph::T_Map::type{static_cast(s.current_frame)}; } - PlugboardGraph::T_Map::type FetchCompTime(const CompState& s, const PlugboardGraph::NodeInstance& n) { + PlugboardGraph::T_Map::type FetchCompTime(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes = nullptr) { return PlugboardGraph::T_Map::type{static_cast(s.current_frame) / s.fps}; } - PlugboardGraph::T_Map::type FetchAppTicks(const CompState& s, const PlugboardGraph::NodeInstance& n) { + PlugboardGraph::T_Map::type FetchAppTicks(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes = nullptr) { return PlugboardGraph::T_Map::type{ static_cast(SDL_GetTicks64()) }; } diff --git a/Keishiki/PlugboardGraph.cpp b/Keishiki/PlugboardGraph.cpp index 2aa226a..0d494a9 100644 --- a/Keishiki/PlugboardGraph.cpp +++ b/Keishiki/PlugboardGraph.cpp @@ -1,6 +1,30 @@ #include +#include namespace K::PlugboardGraph { + void NodeInstance::connect(u32 input_index, NodeInstance *to, u32 to_out_index) { + inputs_fed[input_index] = ConnectInfo{to, to_out_index}; + to->outputs_going[to_out_index].push_back({this, input_index}); + } + + void NodeInstance::disconnect(u32 input_index) { + std::visit([this](auto&& arg){ + using T = std::decay_t; + if constexpr (std::is_same_v) { + for (auto it = arg.p->outputs_going[arg.index].begin(); + it != arg.p->outputs_going[arg.index].end(); it++) { + if (it->p == this) { + arg.p->outputs_going[arg.index].erase(it); + break; + } + } + } + else if constexpr (std::is_same_v::type>) + ; + }, inputs_fed[input_index]); + inputs_fed[input_index] = expand_type(node->in[input_index].type); + } + String VarToString(const T_Map::type& var) { return std::visit([](auto&& arg) -> String { using T = std::decay_t; @@ -24,8 +48,18 @@ namespace K::PlugboardGraph { return table[i]; } - T_Map::type Eval(const CompState& s, const ConnectInfo& info) { - return info.p->node->fetch[info.index](s, *info.p); + T_Map::type Eval(const CompState& s, const ConnectInfo& info, Vector *show_nodes) { + auto p = *info.p; + auto n = p.node; + if (show_nodes != nullptr) { + if (std::find(show_nodes->begin(), show_nodes->end(), info) != show_nodes->end()) { + Log("Failure to evaluate plugboard tree: loop detected!"); + return {}; // tree contains cycle -- abort + } + if (n == &PlugboardNodes::Chain) + show_nodes->push_back(info); + } + return n->fetch[info.index](s, p, show_nodes); } NodeInstance MakeInstance(Node& n) { diff --git a/Keishiki/PlugboardNodes.cpp b/Keishiki/PlugboardNodes.cpp new file mode 100644 index 0000000..c5ca9a7 --- /dev/null +++ b/Keishiki/PlugboardNodes.cpp @@ -0,0 +1,490 @@ +#include + +namespace K::PlugboardNodes { + std::array Nodes = std::to_array({ + &Add, + &Subtract, + &Multiply, + &Divide, + &Negate, + + &NaturalLogarithm, + &SquareRoot, + &Power, + + &AbsoluteValue, + &Sign, + &Minimum, + &Maximum, + + &Sin, + &Cos, + &Tan, + &Arcsin, + &Arccos, + &Arctan, + &Atan2, + + &Interpolation + }); + + const char *K_Interpolation_Names[] = { + "Cubic Bezier", + "In Constant", + "Out Constant", + "Linear", + "Step", + "Smooth Step", + "In Quadratic", + "Out Quadratic", + "In Out Quadratic", + "Out In Quadratic", + "In Cubic", + "Out Cubic", + "In Out Cubic", + "Out In Cubic", + "In Quartic", + "Out Quartic", + "In Out Quartic", + "Out In Quartic", + "In Quintic", + "Out Quintic", + "In Out Quintic", + "Out In Quintic", + "In Sine", + "Out Sine", + "In Out Sine", + "Out In Sine", + "In Exponential", + "Out Exponential", + "In Out Exponential", + "Out In Exponential", + "In Circular", + "Out Circular", + "In Out Circular", + "Out In Circular", + "In Elastic", + "Out Elastic", + "In Out Elastic", + "Out In Elastic", + "In Back", + "Out Back", + "In Out Back", + "Out In Back", + "In Bounce", + "Out Bounce", + "In Out Bounce", + "Out In Bounce", + "Invalid" + }; + + PlugboardGraph::T_Map::type FetchAdd(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes), + y = GetNodeInputArg(s, n, 1, show_nodes); + return x + y; + } + + PlugboardGraph::Node Add = { + .name = "Add", + .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, + .out = { { "a+b", PlugboardGraph::T_Float } }, + .fetch = { FetchAdd } + }; + + PlugboardGraph::T_Map::type FetchNegate(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return -x; + } + + PlugboardGraph::Node Negate = { + .name = "Negate", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "-a", PlugboardGraph::T_Float } }, + .fetch = { FetchNegate } + }; + + PlugboardGraph::T_Map::type FetchSubtract(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes), + y = GetNodeInputArg(s, n, 1, show_nodes); + return x-y; + } + + PlugboardGraph::Node Subtract = { + .name = "Subtract", + .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, + .out = { { "a-b", PlugboardGraph::T_Float } }, + .fetch = { FetchSubtract } + }; + + PlugboardGraph::T_Map::type FetchMultiply(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes), + y = GetNodeInputArg(s, n, 1, show_nodes); + return x*y; + } + + PlugboardGraph::Node Multiply = { + .name = "Multiply", + .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, + .out = { { "a*b", PlugboardGraph::T_Float } }, + .fetch = {FetchMultiply } + }; + + PlugboardGraph::T_Map::type FetchDivide(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes), + y = GetNodeInputArg(s, n, 1, show_nodes); + return x/y; + } + + PlugboardGraph::Node Divide = { + .name = "Divide", + .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, + .out = { { "a/b", PlugboardGraph::T_Float } }, + .fetch = { FetchDivide } + }; + + PlugboardGraph::T_Map::type FetchSign(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::signbit(x) ? -1.0f : 1.0f; + } + + PlugboardGraph::Node Sign = { + .name = "Sign", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "sgn(a)", PlugboardGraph::T_Float } }, + .fetch = { FetchSign } + }; + + PlugboardGraph::T_Map::type FetchSin(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::sin(x); + } + + PlugboardGraph::Node Sin = { + .name = "Sin", + .in = { {"a (rad)", PlugboardGraph::T_Float } }, + .out = { { "sin(a)", PlugboardGraph::T_Float } }, + .fetch = { FetchSin } + }; + + + PlugboardGraph::T_Map::type FetchCos(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::cos(x); + } + + PlugboardGraph::Node Cos = { + .name = "Cos", + .in = { {"a (rad)", PlugboardGraph::T_Float } }, + .out = { { "cos(a)", PlugboardGraph::T_Float } }, + .fetch = { FetchCos } + }; + + + PlugboardGraph::T_Map::type FetchTan(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::tan(x); + } + + PlugboardGraph::Node Tan = { + .name = "Tan", + .in = { {"a (rad)", PlugboardGraph::T_Float } }, + .out = { { "tan(a)", PlugboardGraph::T_Float } }, + .fetch = { FetchTan } + }; + + + PlugboardGraph::T_Map::type FetchArcsin(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::asin(x); + } + + PlugboardGraph::Node Arcsin = { + .name = "Arcsin", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "arcsin(a) (rad)", PlugboardGraph::T_Float } }, + .fetch = { FetchArcsin } + }; + + + PlugboardGraph::T_Map::type FetchArccos(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::acos(x); + } + + PlugboardGraph::Node Arccos = { + .name = "Arccos", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "arccos(a) (rad)", PlugboardGraph::T_Float } }, + .fetch = { FetchArccos } + }; + + PlugboardGraph::T_Map::type FetchArctan(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::atan(x); + } + + PlugboardGraph::Node Arctan = { + .name = "Arctan", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "arctan(a) (rad)", PlugboardGraph::T_Float } }, + .fetch = { FetchArctan } + }; + + PlugboardGraph::T_Map::type FetchAtan2(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 y = GetNodeInputArg(s, n, 0, show_nodes), + x = GetNodeInputArg(s, n, 1, show_nodes); + return std::atan2(y, x); + } + + PlugboardGraph::Node Atan2 = { + .name = "Atan2", + .in = { {"y", PlugboardGraph::T_Float }, {"x", PlugboardGraph::T_Float } }, + .out = { { "atan2(y, x) (rad)", PlugboardGraph::T_Float } }, + .fetch = { FetchAtan2 } + }; + + PlugboardGraph::T_Map::type FetchMinimum(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 y = GetNodeInputArg(s, n, 0, show_nodes), + x = GetNodeInputArg(s, n, 1, show_nodes); + return std::min(y, x); + } + + PlugboardGraph::Node Minimum = { + .name = "Minimum", + .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, + .out = { { "min(a, b)", PlugboardGraph::T_Float } }, + .fetch = { FetchMinimum } + }; + + PlugboardGraph::T_Map::type FetchMaximum(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 y = GetNodeInputArg(s, n, 0, show_nodes), + x = GetNodeInputArg(s, n, 1, show_nodes); + return std::max(y, x); + } + + PlugboardGraph::Node Maximum = { + .name = "Maximum", + .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, + .out = { { "max(a, b)", PlugboardGraph::T_Float } }, + .fetch = {FetchMaximum } + }; + + PlugboardGraph::T_Map::type FetchPower(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes), + y = GetNodeInputArg(s, n, 1, show_nodes); + return std::pow(x, y); + } + + PlugboardGraph::Node Power = { + .name = "Power", + .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, + .out = { { "a^b", PlugboardGraph::T_Float } }, + .fetch = {FetchPower } + }; + + PlugboardGraph::T_Map::type FetchSquareRoot(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::sqrt(x); + } + + PlugboardGraph::Node SquareRoot = { + .name = "Square Root", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "sqrt(a)", PlugboardGraph::T_Float } }, + .fetch = { FetchSquareRoot } + }; + + PlugboardGraph::T_Map::type FetchNaturalLogarithm(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::log(x); + } + + PlugboardGraph::Node NaturalLogarithm = { + .name = "Natural Logarithm", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "log(a)", PlugboardGraph::T_Float } }, + .fetch = {FetchNaturalLogarithm } + }; + + PlugboardGraph::T_Map::type FetchAbsoluteValue(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return std::log(x); + } + + PlugboardGraph::Node AbsoluteValue = { + .name = "Absolute Value", + .in = { {"a", PlugboardGraph::T_Float } }, + .out = { { "|a|", PlugboardGraph::T_Float } }, + .fetch = { FetchAbsoluteValue } + }; + + f32 EvalInterpolation(f32 x, const InterpolationExtra& extra) { + switch (extra.interp) { + case K_I_InConstant: + return 0.0f; + case K_I_OutConstant: + return 1.0f; + case K_I_Linear: + return x; + case K_I_Step: + return bx::getEaseFunc(bx::Easing::Step)(x); + case K_I_SmoothStep: + return bx::getEaseFunc(bx::Easing::SmoothStep)(x); + case K_I_InQuadratic: + return bx::getEaseFunc(bx::Easing::InQuad)(x); + case K_I_OutQuadratic: + return bx::getEaseFunc(bx::Easing::OutQuad)(x); + case K_I_InOutQuadratic: + return bx::getEaseFunc(bx::Easing::InOutQuad)(x); + case K_I_OutInQuadratic: + return bx::getEaseFunc(bx::Easing::OutInQuad)(x); + case K_I_InCubic: + return bx::getEaseFunc(bx::Easing::InCubic)(x); + case K_I_OutCubic: + return bx::getEaseFunc(bx::Easing::OutCubic)(x); + case K_I_InOutCubic: + return bx::getEaseFunc(bx::Easing::InOutCubic)(x); + case K_I_OutInCubic: + return bx::getEaseFunc(bx::Easing::OutInCubic)(x); + case K_I_InQuartic: + return bx::getEaseFunc(bx::Easing::InQuart)(x); + case K_I_OutQuartic: + return bx::getEaseFunc(bx::Easing::OutQuart)(x); + case K_I_InOutQuartic: + return bx::getEaseFunc(bx::Easing::InOutQuart)(x); + case K_I_OutInQuartic: + return bx::getEaseFunc(bx::Easing::OutInQuart)(x); + case K_I_InQuintic: + return bx::getEaseFunc(bx::Easing::InQuint)(x); + case K_I_OutQuintic: + return bx::getEaseFunc(bx::Easing::OutInQuint)(x); + case K_I_InOutQuintic: + return bx::getEaseFunc(bx::Easing::InOutQuint)(x); + case K_I_OutInQuintic: + return bx::getEaseFunc(bx::Easing::OutInQuint)(x); + case K_I_InSine: + return bx::getEaseFunc(bx::Easing::InSine)(x); + case K_I_OutSine: + return bx::getEaseFunc(bx::Easing::OutSine)(x); + case K_I_InOutSine: + return bx::getEaseFunc(bx::Easing::InOutSine)(x); + case K_I_OutInSine: + return bx::getEaseFunc(bx::Easing::OutInSine)(x); + case K_I_InExponential: + return bx::getEaseFunc(bx::Easing::InExpo)(x); + case K_I_OutExponential: + return bx::getEaseFunc(bx::Easing::OutExpo)(x); + case K_I_InOutExponential: + return bx::getEaseFunc(bx::Easing::InOutExpo)(x); + case K_I_OutInExponential: + return bx::getEaseFunc(bx::Easing::OutInExpo)(x); + case K_I_InCircular: + return bx::getEaseFunc(bx::Easing::InCirc)(x); + case K_I_OutCircular: + return bx::getEaseFunc(bx::Easing::OutCirc)(x); + case K_I_InOutCircular: + return bx::getEaseFunc(bx::Easing::InOutCirc)(x); + case K_I_OutInCircular: + return bx::getEaseFunc(bx::Easing::OutInCirc)(x); + case K_I_InElastic: + return bx::getEaseFunc(bx::Easing::InElastic)(x); + case K_I_OutElastic: + return bx::getEaseFunc(bx::Easing::OutElastic)(x); + case K_I_InOutElastic: + return bx::getEaseFunc(bx::Easing::InOutElastic)(x); + case K_I_OutInElastic: + return bx::getEaseFunc(bx::Easing::OutInElastic)(x); + case K_I_InBack: + return bx::getEaseFunc(bx::Easing::InBack)(x); + case K_I_OutBack: + return bx::getEaseFunc(bx::Easing::OutBack)(x); + case K_I_InOutBack: + return bx::getEaseFunc(bx::Easing::InOutBack)(x); + case K_I_OutInBack: + return bx::getEaseFunc(bx::Easing::OutInBack)(x); + case K_I_InBounce: + return bx::getEaseFunc(bx::Easing::InBounce)(x); + case K_I_OutBounce: + return bx::getEaseFunc(bx::Easing::OutBounce)(x); + case K_I_InOutBounce: + return bx::getEaseFunc(bx::Easing::InOutBounce)(x); + case K_I_OutInBounce: + return bx::getEaseFunc(bx::Easing::OutInBounce)(x); + case K_I_CubicBezier: { + f32 p2x = extra.v[0], p2y = extra.v[1], p3x = extra.v[2], p3y = extra.v[3]; + f32 a = 0.0f, b = p2x, c = p3x, d = 1.0f; + f64 t = Graphics::GetCubicUniqueReal(-a+3.0f*b-3.0f*c+d, 3.0f*a-6.0f*b+3.0f*c, -3.0f*a+3.0f*b,a-x); + return static_cast(Graphics::CubicBezier(0.0f, p2y, p3y, 1.0f, t)); + } + default: + return {}; + } + } + + PlugboardGraph::T_Map::type FetchInterpolation(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + auto *e = std::any_cast(&n.extra); + f32 x = GetNodeInputArg(s, n, 0, show_nodes); + return EvalInterpolation(x, *e); + } + + void DrawInterpolation(PlugboardGraph::NodeInstance& n) { + auto *v = std::any_cast(&n.extra); + ImGui::SetNextItemWidth(-FLT_MIN); + if (ImGui::BeginCombo("##Interp", K_Interpolation_Names[v->interp], ImGuiComboFlags_None)) { + for (u32 i = 0; i < K_Interpolation::K_I_Count; i++) { + const bool is_selected = (v->interp == i); + if (ImGui::Selectable(K_Interpolation_Names[i], is_selected)) + v->interp = static_cast(i); + + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + } + + void SetUpInterpolation(PlugboardGraph::NodeInstance& n) { + n.extra = InterpolationExtra{}; + } + + PlugboardGraph::Node Interpolation = { + .name = "Interpolation", + .in = { {"t", PlugboardGraph::T_Float } }, + .out = { { "Value", PlugboardGraph::T_Float } }, + .fetch = { FetchInterpolation }, + .special_draw = DrawInterpolation, + .extra_setup = SetUpInterpolation + }; + + PlugboardGraph::T_Map::type FetchChain(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector *show_nodes) { + u32 frame = GetNodeInputArg(s, n, 0, show_nodes); + + auto *v = std::any_cast>(&n.extra); + if (v->empty()) + return 0.0f; + if (frame <= v->begin()->first) + return v->begin()->second.value; + if (frame >= v->rbegin()->first) + return v->rbegin()->second.value; + + auto nit = v->upper_bound(frame), it = std::prev(nit); + u32 x1 = it->first, x2 = nit->first; + f32 t = static_cast(frame - x1) / static_cast(x2 - x1); + f32 normalized_val = EvalInterpolation(t, it->second.interp); + + return it->second.value + normalized_val * (nit->second.value - it->second.value); + } + + void SetUpChain(PlugboardGraph::NodeInstance& n) { + n.extra = std::map{}; + } + + PlugboardGraph::Node Chain = { + .name = "Chain", + .in = { {"In", PlugboardGraph::T_Int } }, + .out = { { "Out", PlugboardGraph::T_Float } }, + .fetch = { FetchChain }, + .special_draw = nullptr, + .extra_setup = SetUpChain + }; +} diff --git a/Keishiki/UI.cpp b/Keishiki/UI.cpp index 0d4a867..cfdb901 100644 --- a/Keishiki/UI.cpp +++ b/Keishiki/UI.cpp @@ -332,10 +332,10 @@ namespace K::UI { } if (ImGui::Begin("Viewport", &draw_viewport)) { - if (ImGui::Shortcut(ImGuiKey_Space)) { + if (ImGui::Shortcut(ImGuiKey_Space)) TogglePlay(); - } + // Perform rendering u32 view_count = 0, layers_done = 0; bgfx::setViewFrameBuffer(Graphics::K_VIEW_COMP_COMPOSITE + view_count, composite_fb[0]); // the other fb will be cleared in composite bgfx::setViewClear(Graphics::K_VIEW_COMP_COMPOSITE + view_count, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL, 0x00000000); @@ -973,7 +973,8 @@ namespace K::UI { CompState ss = i.s; ss.current_frame = static_cast(std::round(x)); bool good; - return {x, std::get::type>(PlugboardGraph::ConvertValue(PlugboardGraph::Eval(ss, i.connected_v), PlugboardGraph::T_Float, good))}; + Vector info; + return {x, std::get::type>(PlugboardGraph::ConvertValue(PlugboardGraph::Eval(ss, i.connected_v, &info), PlugboardGraph::T_Float, good))}; }, &info, info.samples); ImPlot::EndPlot(); } @@ -984,116 +985,130 @@ namespace K::UI { draw_tl_bg_drag_area(); - if (uniform_open && (connected_v.index() == 1) && std::get<1>(connected_v).p->node == &PlugboardNodes::Chain) { - ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height); - ImGui::TableSetColumnIndex(0); - ImGui::TableSetColumnIndex(1); - ImGui::Indent(); - ImGui::TreeNodeEx(std::get<1>(connected_v).p->node->name.c_str(), - ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_FramePadding); - ImGui::TableSetColumnIndex(2); - auto *m = std::any_cast>(&std::get<1>(connected_v).p->extra); - bool m_empty = m->empty(); - ImGui::BeginDisabled(m_empty || m->begin()->first >= s.current_frame); - if (ImGui::Button("<")) { - auto it = std::prev(m->upper_bound(s.current_frame)); - s.current_frame = (it->first == s.current_frame ? std::prev(it) : it)->first; - } - ImGui::SameLine(); - ImGui::EndDisabled(); - f32 v = std::get::type>(PlugboardGraph::Eval(s, std::get<1>(connected_v))), copy = v; - ImGui::DragFloat("##value", &v); - ImGui::SameLine(); - if (v != copy) { - auto l = m->lower_bound(s.current_frame); - auto interp = l == m->end() ? PlugboardNodes::K_I_Linear : l->second.interp.interp; - m->insert_or_assign(s.current_frame, PlugboardNodes::ChainSegment{ - .value = v, - .interp = { - .interp = interp - } - }); - } - ImGui::BeginDisabled(m_empty || m->rbegin()->first <= s.current_frame); - if (ImGui::Button(">")) { - s.current_frame = m->upper_bound(s.current_frame)->first; - } - ImGui::EndDisabled(); - ImGui::TableSetColumnIndex(3); - ImGui::Text("%lu", m->size()); - ImGui::TableSetColumnIndex(4); - ImVec2 begin_tl = ImGui::GetCursorScreenPos(); + if (uniform_open && connected_v.index() == 1) { + for (auto info: u.show_nodes) { + ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height); + ImGui::TableSetColumnIndex(0); + ImGui::TableSetColumnIndex(1); + ImGui::Indent(); + ImGui::TreeNodeEx(info.p->node->name.c_str(), + ImGuiTreeNodeFlags_SpanFullWidth | + ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | + ImGuiTreeNodeFlags_FramePadding); + ImGui::TableSetColumnIndex(2); + auto *m = std::any_cast>( + &info.p->extra); + bool m_empty = m->empty(); + ImGui::BeginDisabled(m_empty || m->begin()->first >= s.current_frame); + if (ImGui::Button("<")) { + auto it = std::prev(m->upper_bound(s.current_frame)); + s.current_frame = (it->first == s.current_frame ? std::prev(it) : it)->first; + } + ImGui::SameLine(); + ImGui::EndDisabled(); + f32 v = std::get::type>( + PlugboardGraph::Eval(s, info)), copy = v; + ImGui::DragFloat("##value", &v); + ImGui::SameLine(); + if (v != copy) { + auto l = m->lower_bound(s.current_frame); + auto interp = l == m->end() ? PlugboardNodes::K_I_Linear : l->second.interp.interp; + m->insert_or_assign(s.current_frame, PlugboardNodes::ChainSegment{ + .value = v, + .interp = { + .interp = interp + } + }); + } + ImGui::BeginDisabled(m_empty || m->rbegin()->first <= s.current_frame); + if (ImGui::Button(">")) { + s.current_frame = m->upper_bound(s.current_frame)->first; + } + ImGui::EndDisabled(); + ImGui::TableSetColumnIndex(3); + ImGui::Text("%lu", m->size()); + ImGui::TableSetColumnIndex(4); + ImVec2 begin_tl = ImGui::GetCursorScreenPos(); - static std::map m_copy{}; - static u32 dragging{}; - static decltype(m) drag_m = nullptr; - static i64 drag_og = -1; - if (drag_m != m || drag_og == -1) { // premature optimization is the root of good performance !! - f32 *last_val = nullptr; - u32 last_x = 0; - for (auto& [k, segment] : *m) { - ImGui::PushID(k); - if (last_val != nullptr && *last_val != segment.value) { - ImGui::SameLine(0.0f, 0.0f); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + row_height / 2.5f); + static std::map m_copy{}; + static u32 dragging{}; + static decltype(m) drag_m = nullptr; + static i64 drag_og = -1; + if (drag_m != m || + drag_og == -1) { // premature optimization is the root of good performance !! + f32 *last_val = nullptr; + u32 last_x = 0; + for (auto &[k, segment]: *m) { ImGui::PushID(k); - ImGui::Button("##strip", {TimelineFrameToScreenView(view_left, view_amt, view_width, k, s.frame_max) - TimelineFrameToScreenView(view_left, view_amt, view_width, last_x, s.frame_max), row_height * .2f}); + if (last_val != nullptr && *last_val != segment.value) { + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + row_height / 2.5f); + ImGui::PushID(k); + ImGui::Button("##strip", + {TimelineFrameToScreenView(view_left, view_amt, view_width, k, + s.frame_max) - + TimelineFrameToScreenView(view_left, view_amt, view_width, + last_x, s.frame_max), + row_height * .2f}); + ImGui::PopID(); + } + last_val = &segment.value; + last_x = k; + + ImGui::SetCursorScreenPos( + {TimelineFrameToScreenView(view_left, view_amt, view_width, k, + s.frame_max) + begin_tl.x - 2.5f, + begin_tl.y}); + bool d; + ImGui::Button("k", {0.0f, row_height * .8f}); + if (ImGui::IsItemClicked()) { + m_copy = *m; + drag_og = k; + drag_m = m; + } ImGui::PopID(); } - last_val = &segment.value; - last_x = k; - - ImGui::SetCursorScreenPos( - {TimelineFrameToScreenView(view_left, view_amt, view_width, k, - s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); - bool d; - ImGui::Button("k", {0.0f, row_height * .8f}); - if (ImGui::IsItemClicked()) { - m_copy = *m; - drag_og = k; - drag_m = m; - } - ImGui::PopID(); - } - } - else { - m->clear(); - for (auto& [k, segment] : m_copy) { - ImGui::PushID(k); - if (drag_og != k) { - if (TimelineFrameInView(view_left, view_right, k, s.frame_max)) { + } else { + m->clear(); + for (auto &[k, segment]: m_copy) { + ImGui::PushID(k); + if (drag_og != k) { + if (TimelineFrameInView(view_left, view_right, k, s.frame_max)) { + ImGui::SetCursorScreenPos( + {TimelineFrameToScreenView(view_left, view_amt, view_width, k, + s.frame_max) + begin_tl.x - 2.5f, + begin_tl.y}); + ImGui::Button("k", {0.0f, row_height * .8f}); + m->emplace(k, segment); + } + } else { ImGui::SetCursorScreenPos( - {TimelineFrameToScreenView(view_left, view_amt, view_width, k, - s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); + {TimelineFrameToScreenView(view_left, view_amt, view_width, + dragging, + s.frame_max) + begin_tl.x - 2.5f, + begin_tl.y}); ImGui::Button("k", {0.0f, row_height * .8f}); - m->emplace(k, segment); + if (ImGui::IsItemActive()) { + dragging = TimelineScreenViewToFrame(view_left, view_amt, view_width, + std::clamp(ImGui::GetMousePos().x - + tl_init_pos.x, 0.0f, + view_width), + s.frame_max); + m->emplace(dragging, segment); + } + if (drag_og == k && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { + m->emplace(dragging, segment); + drag_og = -1; + drag_m = nullptr; + } } + ImGui::PopID(); } - else { - ImGui::SetCursorScreenPos( - {TimelineFrameToScreenView(view_left, view_amt, view_width, dragging, - s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); - ImGui::Button("k", {0.0f, row_height * .8f}); - if (ImGui::IsItemActive()) { - dragging = TimelineScreenViewToFrame(view_left, view_amt, view_width, - std::clamp(ImGui::GetMousePos().x - - tl_init_pos.x, 0.0f, - view_width), s.frame_max); - m->emplace(dragging, segment); - } - if (drag_og == k && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { - m->emplace(dragging, segment); - drag_og = -1; - drag_m = nullptr; - } - } - ImGui::PopID(); } + ImGui::SetCursorScreenPos(begin_tl); + draw_tl_bg_drag_area(); } - ImGui::SetCursorScreenPos(begin_tl); - draw_tl_bg_drag_area(); } - ImGui::PopID(); j++; } @@ -1117,7 +1132,6 @@ namespace K::UI { if (move_from != -1 && move_to != -1) { if (no_selection) std::swap(s.layers[move_to], s.layers[move_from]); - else { const u32 n = s.selected.size(); u32 inserted = 0; @@ -1399,10 +1413,8 @@ namespace K::UI { ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); ImGui::ShowDemoWindow(); -// static ImGuiStyle& style = ImGui::GetStyle(); -// style.GrabRounding = style.FrameRounding = 5.0f; MainMenuBar(s); - if (draw_viewport) Viewport(s); + if (draw_viewport) Viewport(s); // Must go before comp! if (draw_layer) Layer(s); if (draw_comp) Composition(s); if (draw_interpolation) Interpolation(s); diff --git a/Keishiki/VisualTrack.cpp b/Keishiki/VisualTrack.cpp index 421925d..79edb27 100644 --- a/Keishiki/VisualTrack.cpp +++ b/Keishiki/VisualTrack.cpp @@ -37,7 +37,7 @@ namespace K { } void VisualTrack::GetFrame(const CompState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], - f32 view[16], f32 transform[16]) const { + f32 view[16], f32 transform[16]) { bgfx::setViewMode(view_id, bgfx::ViewMode::Sequential); bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL); bgfx::setViewFrameBuffer(view_id, fb); @@ -55,7 +55,8 @@ namespace K { using T = std::decay_t; if constexpr (std::is_same_v) { bool good; - val_target = PlugboardValToShader(PlugboardGraph::ConvertValue(PlugboardGraph::Eval(s, arg), + u.show_nodes.clear(); + val_target = PlugboardValToShader(PlugboardGraph::ConvertValue(PlugboardGraph::Eval(s, arg, &u.show_nodes), static_cast(u.val.index()), // todo DANGEROUS !! good)); } diff --git a/Keishiki/include/PlugboardGraph.h b/Keishiki/include/PlugboardGraph.h index 5c80496..bc71755 100644 --- a/Keishiki/include/PlugboardGraph.h +++ b/Keishiki/include/PlugboardGraph.h @@ -62,17 +62,6 @@ namespace K::PlugboardGraph { }; struct NodeInstance; - struct Node { - String name; // will likely get SSO for most stuff - - Vector in; - Vector out; - - Vector::type(*)(const CompState&, const NodeInstance&)> fetch; // todo investigate how you might wanna jit this instead of evaluating a tree for each output at runtime esp. when a project is set for rendering - void (*special_draw)(NodeInstance&); - void (*extra_setup)(NodeInstance&); - }; - struct ConnectInfo { NodeInstance *p; // NOTE: so NodeInstances must be stored in a list, otherwise vector realloc leads to UAF @@ -80,6 +69,19 @@ namespace K::PlugboardGraph { auto operator<=>(const ConnectInfo&) const = default; // too-modern c++ black magic ? }; + struct Node { + String name; // will likely get SSO for most stuff + + Vector in; + Vector out; + + Vector::type(*)(const CompState&, const NodeInstance&, Vector*)> fetch; // todo investigate how you might wanna jit this instead of evaluating a tree for each output at runtime esp. when a project is set for rendering + void (*special_draw)(NodeInstance&); + void (*extra_setup)(NodeInstance&); + }; + + + struct ConnectInfoHasher { std::size_t operator()(const ConnectInfo& k) const { @@ -97,28 +99,8 @@ namespace K::PlugboardGraph { std::any extra; - void connect(u32 input_index, NodeInstance *to, u32 to_out_index) { - inputs_fed[input_index] = ConnectInfo{to, to_out_index}; - to->outputs_going[to_out_index].push_back({this, input_index}); - } - - void disconnect(u32 input_index) { - std::visit([this](auto&& arg){ - using T = std::decay_t; - if constexpr (std::is_same_v) { - for (auto it = arg.p->outputs_going[arg.index].begin(); - it != arg.p->outputs_going[arg.index].end(); it++) { - if (it->p == this) { - arg.p->outputs_going[arg.index].erase(it); - break; - } - } - } - else if constexpr (std::is_same_v::type>) - ; - }, inputs_fed[input_index]); - inputs_fed[input_index] = expand_type(node->in[input_index].type); - } + void connect(u32 input_index, NodeInstance *to, u32 to_out_index); + void disconnect(u32 input_index); }; @@ -126,7 +108,7 @@ namespace K::PlugboardGraph { T_Map::type ConvertValue(const T_Map::type& v, Type target, bool& good); - T_Map::type Eval(const CompState& s, const ConnectInfo& info); + T_Map::type Eval(const CompState& s, const ConnectInfo& info, Vector *show_nodes = nullptr); struct LinksFromSource { ImVec2 source; diff --git a/Keishiki/include/PlugboardNodes.h b/Keishiki/include/PlugboardNodes.h index cb1c4f9..436f89b 100644 --- a/Keishiki/include/PlugboardNodes.h +++ b/Keishiki/include/PlugboardNodes.h @@ -8,12 +8,12 @@ namespace { template - typename K::PlugboardGraph::T_Map::type GetNodeInputArg(const K::CompState& s, const K::PlugboardGraph::NodeInstance& n, u32 index) { + typename K::PlugboardGraph::T_Map::type GetNodeInputArg(const K::CompState& s, const K::PlugboardGraph::NodeInstance& n, u32 index, K::Vector *show_nodes) { bool good; - typename K::PlugboardGraph::T_Map::type v = std::get::type>(K::PlugboardGraph::ConvertValue(std::visit([&s](auto&& arg) { + typename K::PlugboardGraph::T_Map::type v = std::get::type>(K::PlugboardGraph::ConvertValue(std::visit([&show_nodes, &s](auto&& arg) { using U = std::decay_t; if constexpr (std::is_same_v) - return K::PlugboardGraph::Eval(s, arg); + return K::PlugboardGraph::Eval(s, arg, show_nodes); else return arg; }, n.inputs_fed[index]), type, good)); @@ -25,245 +25,25 @@ namespace { } namespace K::PlugboardNodes { - PlugboardGraph::T_Map::type FetchAdd(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0), - y = GetNodeInputArg(s, n, 1); - return x + y; - } - - PlugboardGraph::Node Add = { - .name = "Add", - .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, - .out = { { "a+b", PlugboardGraph::T_Float } }, - .fetch = { FetchAdd } - }; - - PlugboardGraph::T_Map::type FetchNegate(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return -x; - } - - PlugboardGraph::Node Negate = { - .name = "Negate", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "-a", PlugboardGraph::T_Float } }, - .fetch = { FetchNegate } - }; - - PlugboardGraph::T_Map::type FetchSubtract(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0), - y = GetNodeInputArg(s, n, 1); - return x-y; - } - - PlugboardGraph::Node Subtract = { - .name = "Subtract", - .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, - .out = { { "a-b", PlugboardGraph::T_Float } }, - .fetch = { FetchSubtract } - }; - - PlugboardGraph::T_Map::type FetchMultiply(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0), - y = GetNodeInputArg(s, n, 1); - return x*y; - } - - PlugboardGraph::Node Multiply = { - .name = "Multiply", - .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, - .out = { { "a*b", PlugboardGraph::T_Float } }, - .fetch = {FetchMultiply } - }; - - PlugboardGraph::T_Map::type FetchDivide(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0), - y = GetNodeInputArg(s, n, 1); - return x/y; - } - - PlugboardGraph::Node Divide = { - .name = "Divide", - .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, - .out = { { "a/b", PlugboardGraph::T_Float } }, - .fetch = { FetchDivide } - }; - - PlugboardGraph::T_Map::type FetchSign(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::signbit(x) ? -1.0f : 1.0f; - } - - PlugboardGraph::Node Sign = { - .name = "Sign", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "sgn(a)", PlugboardGraph::T_Float } }, - .fetch = { FetchSign } - }; - - PlugboardGraph::T_Map::type FetchSin(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::sin(x); - } - - PlugboardGraph::Node Sin = { - .name = "Sin", - .in = { {"a (rad)", PlugboardGraph::T_Float } }, - .out = { { "sin(a)", PlugboardGraph::T_Float } }, - .fetch = { FetchSin } - }; - - - PlugboardGraph::T_Map::type FetchCos(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::cos(x); - } - - PlugboardGraph::Node Cos = { - .name = "Cos", - .in = { {"a (rad)", PlugboardGraph::T_Float } }, - .out = { { "cos(a)", PlugboardGraph::T_Float } }, - .fetch = { FetchCos } - }; - - - PlugboardGraph::T_Map::type FetchTan(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::tan(x); - } - - PlugboardGraph::Node Tan = { - .name = "Tan", - .in = { {"a (rad)", PlugboardGraph::T_Float } }, - .out = { { "tan(a)", PlugboardGraph::T_Float } }, - .fetch = { FetchTan } - }; - - - PlugboardGraph::T_Map::type FetchArcsin(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::asin(x); - } - - PlugboardGraph::Node Arcsin = { - .name = "Arcsin", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "arcsin(a) (rad)", PlugboardGraph::T_Float } }, - .fetch = { FetchArcsin } - }; - - - PlugboardGraph::T_Map::type FetchArccos(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::acos(x); - } - - PlugboardGraph::Node Arccos = { - .name = "Arccos", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "arccos(a) (rad)", PlugboardGraph::T_Float } }, - .fetch = { FetchArccos } - }; - - PlugboardGraph::T_Map::type FetchArctan(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::atan(x); - } - - PlugboardGraph::Node Arctan = { - .name = "Arctan", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "arctan(a) (rad)", PlugboardGraph::T_Float } }, - .fetch = { FetchArctan } - }; - - PlugboardGraph::T_Map::type FetchAtan2(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 y = GetNodeInputArg(s, n, 0), - x = GetNodeInputArg(s, n, 1); - return std::atan2(y, x); - } - - PlugboardGraph::Node Atan2 = { - .name = "Atan2", - .in = { {"y", PlugboardGraph::T_Float }, {"x", PlugboardGraph::T_Float } }, - .out = { { "atan2(y, x) (rad)", PlugboardGraph::T_Float } }, - .fetch = { FetchAtan2 } - }; - - PlugboardGraph::T_Map::type FetchMinimum(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 y = GetNodeInputArg(s, n, 0), - x = GetNodeInputArg(s, n, 1); - return std::min(y, x); - } - - PlugboardGraph::Node Minimum = { - .name = "Minimum", - .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, - .out = { { "min(a, b)", PlugboardGraph::T_Float } }, - .fetch = { FetchMinimum } - }; - - PlugboardGraph::T_Map::type FetchMaximum(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 y = GetNodeInputArg(s, n, 0), - x = GetNodeInputArg(s, n, 1); - return std::max(y, x); - } - - PlugboardGraph::Node Maximum = { - .name = "Maximum", - .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, - .out = { { "max(a, b)", PlugboardGraph::T_Float } }, - .fetch = {FetchMaximum } - }; - - PlugboardGraph::T_Map::type FetchPower(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0), - y = GetNodeInputArg(s, n, 1); - return std::pow(x, y); - } - - PlugboardGraph::Node Power = { - .name = "Power", - .in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, - .out = { { "a^b", PlugboardGraph::T_Float } }, - .fetch = {FetchPower } - }; - - PlugboardGraph::T_Map::type FetchSquareRoot(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::sqrt(x); - } - - PlugboardGraph::Node SquareRoot = { - .name = "Square Root", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "sqrt(a)", PlugboardGraph::T_Float } }, - .fetch = { FetchSquareRoot } - }; - - PlugboardGraph::T_Map::type FetchNaturalLogarithm(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::log(x); - } - - PlugboardGraph::Node NaturalLogarithm = { - .name = "Natural Logarithm", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "log(a)", PlugboardGraph::T_Float } }, - .fetch = {FetchNaturalLogarithm } - }; - - PlugboardGraph::T_Map::type FetchAbsoluteValue(const CompState& s, const PlugboardGraph::NodeInstance& n) { - f32 x = GetNodeInputArg(s, n, 0); - return std::log(x); - } - - PlugboardGraph::Node AbsoluteValue = { - .name = "Absolute Value", - .in = { {"a", PlugboardGraph::T_Float } }, - .out = { { "|a|", PlugboardGraph::T_Float } }, - .fetch = { FetchAbsoluteValue } - }; + extern PlugboardGraph::Node Add; + extern PlugboardGraph::Node Negate; + extern PlugboardGraph::Node Subtract; + extern PlugboardGraph::Node Multiply; + extern PlugboardGraph::Node Divide; + extern PlugboardGraph::Node Sign; + extern PlugboardGraph::Node Sin; + extern PlugboardGraph::Node Cos; + extern PlugboardGraph::Node Tan; + extern PlugboardGraph::Node Arcsin; + extern PlugboardGraph::Node Arccos; + extern PlugboardGraph::Node Arctan; + extern PlugboardGraph::Node Atan2; + extern PlugboardGraph::Node Minimum; + extern PlugboardGraph::Node Maximum; + extern PlugboardGraph::Node Power; + extern PlugboardGraph::Node SquareRoot; + extern PlugboardGraph::Node NaturalLogarithm; + extern PlugboardGraph::Node AbsoluteValue; enum K_Interpolation { K_I_CubicBezier, @@ -315,261 +95,21 @@ namespace K::PlugboardNodes { K_I_Count }; - - const char *K_Interpolation_Names[] { - "Cubic Bezier", - "In Constant", - "Out Constant", - "Linear", - "Step", - "Smooth Step", - "In Quadratic", - "Out Quadratic", - "In Out Quadratic", - "Out In Quadratic", - "In Cubic", - "Out Cubic", - "In Out Cubic", - "Out In Cubic", - "In Quartic", - "Out Quartic", - "In Out Quartic", - "Out In Quartic", - "In Quintic", - "Out Quintic", - "In Out Quintic", - "Out In Quintic", - "In Sine", - "Out Sine", - "In Out Sine", - "Out In Sine", - "In Exponential", - "Out Exponential", - "In Out Exponential", - "Out In Exponential", - "In Circular", - "Out Circular", - "In Out Circular", - "Out In Circular", - "In Elastic", - "Out Elastic", - "In Out Elastic", - "Out In Elastic", - "In Back", - "Out Back", - "In Out Back", - "Out In Back", - "In Bounce", - "Out Bounce", - "In Out Bounce", - "Out In Bounce", - "Invalid" - }; + extern const char *K_Interpolation_Names[]; struct InterpolationExtra { K_Interpolation interp; f32 v[4]; }; - f32 EvalInterpolation(f32 x, const InterpolationExtra& extra) { - switch (extra.interp) { - case K_I_InConstant: - return 0.0f; - case K_I_OutConstant: - return 1.0f; - case K_I_Linear: - return x; - case K_I_Step: - return bx::getEaseFunc(bx::Easing::Step)(x); - case K_I_SmoothStep: - return bx::getEaseFunc(bx::Easing::SmoothStep)(x); - case K_I_InQuadratic: - return bx::getEaseFunc(bx::Easing::InQuad)(x); - case K_I_OutQuadratic: - return bx::getEaseFunc(bx::Easing::OutQuad)(x); - case K_I_InOutQuadratic: - return bx::getEaseFunc(bx::Easing::InOutQuad)(x); - case K_I_OutInQuadratic: - return bx::getEaseFunc(bx::Easing::OutInQuad)(x); - case K_I_InCubic: - return bx::getEaseFunc(bx::Easing::InCubic)(x); - case K_I_OutCubic: - return bx::getEaseFunc(bx::Easing::OutCubic)(x); - case K_I_InOutCubic: - return bx::getEaseFunc(bx::Easing::InOutCubic)(x); - case K_I_OutInCubic: - return bx::getEaseFunc(bx::Easing::OutInCubic)(x); - case K_I_InQuartic: - return bx::getEaseFunc(bx::Easing::InQuart)(x); - case K_I_OutQuartic: - return bx::getEaseFunc(bx::Easing::OutQuart)(x); - case K_I_InOutQuartic: - return bx::getEaseFunc(bx::Easing::InOutQuart)(x); - case K_I_OutInQuartic: - return bx::getEaseFunc(bx::Easing::OutInQuart)(x); - case K_I_InQuintic: - return bx::getEaseFunc(bx::Easing::InQuint)(x); - case K_I_OutQuintic: - return bx::getEaseFunc(bx::Easing::OutInQuint)(x); - case K_I_InOutQuintic: - return bx::getEaseFunc(bx::Easing::InOutQuint)(x); - case K_I_OutInQuintic: - return bx::getEaseFunc(bx::Easing::OutInQuint)(x); - case K_I_InSine: - return bx::getEaseFunc(bx::Easing::InSine)(x); - case K_I_OutSine: - return bx::getEaseFunc(bx::Easing::OutSine)(x); - case K_I_InOutSine: - return bx::getEaseFunc(bx::Easing::InOutSine)(x); - case K_I_OutInSine: - return bx::getEaseFunc(bx::Easing::OutInSine)(x); - case K_I_InExponential: - return bx::getEaseFunc(bx::Easing::InExpo)(x); - case K_I_OutExponential: - return bx::getEaseFunc(bx::Easing::OutExpo)(x); - case K_I_InOutExponential: - return bx::getEaseFunc(bx::Easing::InOutExpo)(x); - case K_I_OutInExponential: - return bx::getEaseFunc(bx::Easing::OutInExpo)(x); - case K_I_InCircular: - return bx::getEaseFunc(bx::Easing::InCirc)(x); - case K_I_OutCircular: - return bx::getEaseFunc(bx::Easing::OutCirc)(x); - case K_I_InOutCircular: - return bx::getEaseFunc(bx::Easing::InOutCirc)(x); - case K_I_OutInCircular: - return bx::getEaseFunc(bx::Easing::OutInCirc)(x); - case K_I_InElastic: - return bx::getEaseFunc(bx::Easing::InElastic)(x); - case K_I_OutElastic: - return bx::getEaseFunc(bx::Easing::OutElastic)(x); - case K_I_InOutElastic: - return bx::getEaseFunc(bx::Easing::InOutElastic)(x); - case K_I_OutInElastic: - return bx::getEaseFunc(bx::Easing::OutInElastic)(x); - case K_I_InBack: - return bx::getEaseFunc(bx::Easing::InBack)(x); - case K_I_OutBack: - return bx::getEaseFunc(bx::Easing::OutBack)(x); - case K_I_InOutBack: - return bx::getEaseFunc(bx::Easing::InOutBack)(x); - case K_I_OutInBack: - return bx::getEaseFunc(bx::Easing::OutInBack)(x); - case K_I_InBounce: - return bx::getEaseFunc(bx::Easing::InBounce)(x); - case K_I_OutBounce: - return bx::getEaseFunc(bx::Easing::OutBounce)(x); - case K_I_InOutBounce: - return bx::getEaseFunc(bx::Easing::InOutBounce)(x); - case K_I_OutInBounce: - return bx::getEaseFunc(bx::Easing::OutInBounce)(x); - case K_I_CubicBezier: { - f32 p2x = extra.v[0], p2y = extra.v[1], p3x = extra.v[2], p3y = extra.v[3]; - f32 a = 0.0f, b = p2x, c = p3x, d = 1.0f; - f64 t = Graphics::GetCubicUniqueReal(-a+3.0f*b-3.0f*c+d, 3.0f*a-6.0f*b+3.0f*c, -3.0f*a+3.0f*b,a-x); - return static_cast(Graphics::CubicBezier(0.0f, p2y, p3y, 1.0f, t)); - } - default: - return {}; - } - } - - PlugboardGraph::T_Map::type FetchInterpolation(const CompState& s, const PlugboardGraph::NodeInstance& n) { - auto *e = std::any_cast(&n.extra); - f32 x = GetNodeInputArg(s, n, 0); - return EvalInterpolation(x, *e); - } - - void DrawInterpolation(PlugboardGraph::NodeInstance& n) { - auto *v = std::any_cast(&n.extra); - ImGui::SetNextItemWidth(-FLT_MIN); - if (ImGui::BeginCombo("##Interp", K_Interpolation_Names[v->interp], ImGuiComboFlags_None)) { - for (u32 i = 0; i < K_Interpolation::K_I_Count; i++) { - const bool is_selected = (v->interp == i); - if (ImGui::Selectable(K_Interpolation_Names[i], is_selected)) - v->interp = static_cast(i); - - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - } - - void SetUpInterpolation(PlugboardGraph::NodeInstance& n) { - n.extra = InterpolationExtra{}; - } - - PlugboardGraph::Node Interpolation = { - .name = "Interpolation", - .in = { {"t", PlugboardGraph::T_Float } }, - .out = { { "Value", PlugboardGraph::T_Float } }, - .fetch = { FetchInterpolation }, - .special_draw = DrawInterpolation, - .extra_setup = SetUpInterpolation - }; + extern PlugboardGraph::Node Interpolation; struct ChainSegment { f32 value; InterpolationExtra interp; }; - PlugboardGraph::T_Map::type FetchChain(const CompState& s, const PlugboardGraph::NodeInstance& n) { - u32 frame = GetNodeInputArg(s, n, 0); + extern PlugboardGraph::Node Chain; - auto *v = std::any_cast>(&n.extra); - if (v->empty()) - return 0.0f; - if (frame <= v->begin()->first) - return v->begin()->second.value; - if (frame >= v->rbegin()->first) - return v->rbegin()->second.value; - - auto nit = v->upper_bound(frame), it = std::prev(nit); - u32 x1 = it->first, x2 = nit->first; - f32 t = static_cast(frame - x1) / static_cast(x2 - x1); - f32 normalized_val = EvalInterpolation(t, it->second.interp); - - return it->second.value + normalized_val * (nit->second.value - it->second.value); - } - - void SetUpChain(PlugboardGraph::NodeInstance& n) { - n.extra = std::map{}; - } - - PlugboardGraph::Node Chain = { - .name = "Chain", - .in = { {"In", PlugboardGraph::T_Int } }, - .out = { { "Out", PlugboardGraph::T_Float } }, - .fetch = { FetchChain }, - .special_draw = nullptr, - .extra_setup = SetUpChain - }; - - auto Nodes = std::to_array({ - &Add, - &Subtract, - &Multiply, - &Divide, - &Negate, - - &NaturalLogarithm, - &SquareRoot, - &Power, - - &AbsoluteValue, - &Sign, - &Minimum, - &Maximum, - - &Sin, - &Cos, - &Tan, - &Arcsin, - &Arccos, - &Arctan, - &Atan2, - - &Interpolation - }); + extern std::array Nodes; } diff --git a/Keishiki/include/VisualTrack.h b/Keishiki/include/VisualTrack.h index 1d190eb..722dffc 100644 --- a/Keishiki/include/VisualTrack.h +++ b/Keishiki/include/VisualTrack.h @@ -8,24 +8,12 @@ #include "PlugboardGraph.h" namespace K { -/* - template - struct Varying { - static_assert(std::is_arithmetic::value); - u64 begin = 0, duration = 0; - std::function interp; - - T get(u64 current_time) const { - return interp(std::fmin(1.0f, std::fmax(0.0f, current_time - begin)) / static_cast(duration)); - } - }; -*/ - struct Uniform { String name; bgfx::UniformHandle handle; ShaderGraph::T_Map::type val; PlugboardGraph::ConnectInfo connection; + Vector show_nodes; }; struct Sampler { @@ -45,7 +33,7 @@ namespace K { Vector uniforms; Vector samplers; void GetFrame(const CompState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], - f32 view[16], f32 transform[16]) const; + f32 view[16], f32 transform[16]); static void ExposeUniform(CompState& s, Uniform& uu); void ExposeUniform(CompState& s, u32 i); static void HideUniform(CompState& s, Uniform& uu); diff --git a/TODO.md b/TODO.md index 98816fc..4484f60 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,14 @@ # NOW ## UI -- Key selection in comp panel -- Graph editor -- Node loop detection (separate DFS (extra work) or be smart in recursion) - - detect time-sensitive nodes in tree and display on timeline - Undo's + - Once this is done we can move the plugboard loop detection/chain finding out of the eval loop +- Keys + - selection in comp panel + - deletion + - copy&paste +- Graph editor +- Node groups +- Simple export ## Compositor - Video! @@ -15,18 +19,18 @@ - Data models - Dump and read back state, (de)serialization!!! - Pre-compose/Layer Groups (jokes -- can be completely UI side) +- Resource + - Deletion - Motion blur -- Non-negotiable - Text (idea: index-based evaluation in plugboard) -- Non-negotiable - 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) -- Non-negotiable - External data driving (csv, json or something else?) -- use a node to select source - -## Chores -- Node groups +- 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) +- External data driving (csv, json or something else?) -- use a node to select source # Later ## IO - File dialogues pending SDL3 - https://wiki.libsdl.org/SDL3/CategoryDialog +- Clipboard pending SDL3 - OIIO output for more than PNG's - don't care about video export -- leave it for ffmpeg