temp solution for loops and chains

This commit is contained in:
lachrymaLF 2024-06-12 22:52:34 -04:00
parent 4b6296c697
commit e51e684875
9 changed files with 708 additions and 657 deletions

View file

@ -20,13 +20,13 @@ namespace {
namespace K {
K::AppState app_state;
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchCompFrame(const CompState& s, const PlugboardGraph::NodeInstance& n) {
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchCompFrame(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes = nullptr) {
return PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type{static_cast<i32>(s.current_frame)};
}
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchCompTime(const CompState& s, const PlugboardGraph::NodeInstance& n) {
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchCompTime(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes = nullptr) {
return PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type{static_cast<f32>(s.current_frame) / s.fps};
}
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchAppTicks(const CompState& s, const PlugboardGraph::NodeInstance& n) {
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchAppTicks(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes = nullptr) {
return PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type{ static_cast<f32>(SDL_GetTicks64()) };
}

View file

@ -1,6 +1,30 @@
#include <PlugboardGraph.h>
#include <PlugboardNodes.h>
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<decltype(arg)>;
if constexpr (std::is_same_v<T, ConnectInfo>) {
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<T, T_Map<Type::T_Count>::type>)
;
}, inputs_fed[input_index]);
inputs_fed[input_index] = expand_type(node->in[input_index].type);
}
String VarToString(const T_Map<T_Count>::type& var) {
return std::visit([](auto&& arg) -> String {
using T = std::decay_t<decltype(arg)>;
@ -24,8 +48,18 @@ namespace K::PlugboardGraph {
return table[i];
}
T_Map<T_Count>::type Eval(const CompState& s, const ConnectInfo& info) {
return info.p->node->fetch[info.index](s, *info.p);
T_Map<T_Count>::type Eval(const CompState& s, const ConnectInfo& info, Vector<ConnectInfo> *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) {

490
Keishiki/PlugboardNodes.cpp Normal file
View file

@ -0,0 +1,490 @@
#include <PlugboardNodes.h>
namespace K::PlugboardNodes {
std::array<PlugboardGraph::Node*, 20> Nodes = std::to_array<PlugboardGraph::Node*>({
&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<PlugboardGraph::T_Count>::type FetchAdd(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchNegate(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSubtract(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchMultiply(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchDivide(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSign(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSin(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchCos(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchTan(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchArcsin(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchArccos(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchArctan(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchAtan2(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 y = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchMinimum(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 y = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchMaximum(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 y = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchPower(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSquareRoot(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchNaturalLogarithm(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchAbsoluteValue(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<f32>(Graphics::CubicBezier(0.0f, p2y, p3y, 1.0f, t));
}
default:
return {};
}
}
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchInterpolation(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
auto *e = std::any_cast<InterpolationExtra>(&n.extra);
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0, show_nodes);
return EvalInterpolation(x, *e);
}
void DrawInterpolation(PlugboardGraph::NodeInstance& n) {
auto *v = std::any_cast<InterpolationExtra>(&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<K_Interpolation>(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<PlugboardGraph::T_Count>::type FetchChain(const CompState& s, const PlugboardGraph::NodeInstance& n, Vector<PlugboardGraph::ConnectInfo> *show_nodes) {
u32 frame = GetNodeInputArg<PlugboardGraph::T_Int>(s, n, 0, show_nodes);
auto *v = std::any_cast<std::map<u32, ChainSegment>>(&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<f32>(frame - x1) / static_cast<f32>(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<u32, ChainSegment>{};
}
PlugboardGraph::Node Chain = {
.name = "Chain",
.in = { {"In", PlugboardGraph::T_Int } },
.out = { { "Out", PlugboardGraph::T_Float } },
.fetch = { FetchChain },
.special_draw = nullptr,
.extra_setup = SetUpChain
};
}

View file

@ -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<u64>(std::round(x));
bool good;
return {x, std::get<PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type>(PlugboardGraph::ConvertValue(PlugboardGraph::Eval(ss, i.connected_v), PlugboardGraph::T_Float, good))};
Vector<PlugboardGraph::ConnectInfo> info;
return {x, std::get<PlugboardGraph::T_Map<PlugboardGraph::T_Float>::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::map<u32, PlugboardNodes::ChainSegment>>(&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<PlugboardGraph::T_Map<PlugboardGraph::T_Float>::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<std::map<u32, PlugboardNodes::ChainSegment>>(
&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<PlugboardGraph::T_Map<PlugboardGraph::T_Float>::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<u32, PlugboardNodes::ChainSegment> 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<u32, PlugboardNodes::ChainSegment> 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);

View file

@ -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<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>) {
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<PlugboardGraph::Type>(u.val.index()), // todo DANGEROUS !!
good));
}

View file

@ -62,17 +62,6 @@ namespace K::PlugboardGraph {
};
struct NodeInstance;
struct Node {
String name; // will likely get SSO for most stuff
Vector<Socket> in;
Vector<Socket> out;
Vector<T_Map<T_Count>::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<Socket> in;
Vector<Socket> out;
Vector<T_Map<T_Count>::type(*)(const CompState&, const NodeInstance&, Vector<ConnectInfo>*)> 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<decltype(arg)>;
if constexpr (std::is_same_v<T, ConnectInfo>) {
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<T, T_Map<Type::T_Count>::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<T_Count>::type ConvertValue(const T_Map<T_Count>::type& v, Type target, bool& good);
T_Map<T_Count>::type Eval(const CompState& s, const ConnectInfo& info);
T_Map<T_Count>::type Eval(const CompState& s, const ConnectInfo& info, Vector<ConnectInfo> *show_nodes = nullptr);
struct LinksFromSource {
ImVec2 source;

View file

@ -8,12 +8,12 @@
namespace {
template <K::PlugboardGraph::Type type>
typename K::PlugboardGraph::T_Map<type>::type GetNodeInputArg(const K::CompState& s, const K::PlugboardGraph::NodeInstance& n, u32 index) {
typename K::PlugboardGraph::T_Map<type>::type GetNodeInputArg(const K::CompState& s, const K::PlugboardGraph::NodeInstance& n, u32 index, K::Vector<K::PlugboardGraph::ConnectInfo> *show_nodes) {
bool good;
typename K::PlugboardGraph::T_Map<type>::type v = std::get<typename K::PlugboardGraph::T_Map<type>::type>(K::PlugboardGraph::ConvertValue(std::visit([&s](auto&& arg) {
typename K::PlugboardGraph::T_Map<type>::type v = std::get<typename K::PlugboardGraph::T_Map<type>::type>(K::PlugboardGraph::ConvertValue(std::visit([&show_nodes, &s](auto&& arg) {
using U = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<U, K::PlugboardGraph::ConnectInfo>)
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<PlugboardGraph::T_Count>::type FetchAdd(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchNegate(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSubtract(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchMultiply(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchDivide(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSign(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSin(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchCos(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchTan(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchArcsin(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchArccos(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchArctan(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchAtan2(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 y = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchMinimum(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 y = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchMaximum(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 y = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchPower(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0),
y = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchSquareRoot(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchNaturalLogarithm(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<PlugboardGraph::T_Count>::type FetchAbsoluteValue(const CompState& s, const PlugboardGraph::NodeInstance& n) {
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(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<f32>(Graphics::CubicBezier(0.0f, p2y, p3y, 1.0f, t));
}
default:
return {};
}
}
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchInterpolation(const CompState& s, const PlugboardGraph::NodeInstance& n) {
auto *e = std::any_cast<InterpolationExtra>(&n.extra);
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0);
return EvalInterpolation(x, *e);
}
void DrawInterpolation(PlugboardGraph::NodeInstance& n) {
auto *v = std::any_cast<InterpolationExtra>(&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<K_Interpolation>(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<PlugboardGraph::T_Count>::type FetchChain(const CompState& s, const PlugboardGraph::NodeInstance& n) {
u32 frame = GetNodeInputArg<PlugboardGraph::T_Int>(s, n, 0);
extern PlugboardGraph::Node Chain;
auto *v = std::any_cast<std::map<u32, ChainSegment>>(&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<f32>(frame - x1) / static_cast<f32>(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<u32, ChainSegment>{};
}
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<PlugboardGraph::Node*>({
&Add,
&Subtract,
&Multiply,
&Divide,
&Negate,
&NaturalLogarithm,
&SquareRoot,
&Power,
&AbsoluteValue,
&Sign,
&Minimum,
&Maximum,
&Sin,
&Cos,
&Tan,
&Arcsin,
&Arccos,
&Arctan,
&Atan2,
&Interpolation
});
extern std::array<PlugboardGraph::Node*, 20> Nodes;
}

View file

@ -8,24 +8,12 @@
#include "PlugboardGraph.h"
namespace K {
/*
template <typename T>
struct Varying {
static_assert(std::is_arithmetic<T>::value);
u64 begin = 0, duration = 0;
std::function<T(f64)> interp;
T get(u64 current_time) const {
return interp(std::fmin(1.0f, std::fmax(0.0f, current_time - begin)) / static_cast<f64>(duration));
}
};
*/
struct Uniform {
String name;
bgfx::UniformHandle handle;
ShaderGraph::T_Map<ShaderGraph::T_Count>::type val;
PlugboardGraph::ConnectInfo connection;
Vector<PlugboardGraph::ConnectInfo> show_nodes;
};
struct Sampler {
@ -45,7 +33,7 @@ namespace K {
Vector<Uniform> uniforms;
Vector<Sampler> 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);

24
TODO.md
View file

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