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 { namespace K {
K::AppState app_state; 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)}; 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}; 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()) }; return PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type{ static_cast<f32>(SDL_GetTicks64()) };
} }

View file

@ -1,6 +1,30 @@
#include <PlugboardGraph.h> #include <PlugboardGraph.h>
#include <PlugboardNodes.h>
namespace K::PlugboardGraph { 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) { String VarToString(const T_Map<T_Count>::type& var) {
return std::visit([](auto&& arg) -> String { return std::visit([](auto&& arg) -> String {
using T = std::decay_t<decltype(arg)>; using T = std::decay_t<decltype(arg)>;
@ -24,8 +48,18 @@ namespace K::PlugboardGraph {
return table[i]; return table[i];
} }
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) {
return info.p->node->fetch[info.index](s, *info.p); 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) { 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::Begin("Viewport", &draw_viewport)) {
if (ImGui::Shortcut(ImGuiKey_Space)) { if (ImGui::Shortcut(ImGuiKey_Space))
TogglePlay(); TogglePlay();
}
// Perform rendering
u32 view_count = 0, layers_done = 0; 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::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); 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; CompState ss = i.s;
ss.current_frame = static_cast<u64>(std::round(x)); ss.current_frame = static_cast<u64>(std::round(x));
bool good; 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); }, &info, info.samples);
ImPlot::EndPlot(); ImPlot::EndPlot();
} }
@ -984,116 +985,130 @@ namespace K::UI {
draw_tl_bg_drag_area(); draw_tl_bg_drag_area();
if (uniform_open && (connected_v.index() == 1) && std::get<1>(connected_v).p->node == &PlugboardNodes::Chain) { if (uniform_open && connected_v.index() == 1) {
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height); for (auto info: u.show_nodes) {
ImGui::TableSetColumnIndex(0); ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(0);
ImGui::Indent(); ImGui::TableSetColumnIndex(1);
ImGui::TreeNodeEx(std::get<1>(connected_v).p->node->name.c_str(), ImGui::Indent();
ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_FramePadding); ImGui::TreeNodeEx(info.p->node->name.c_str(),
ImGui::TableSetColumnIndex(2); ImGuiTreeNodeFlags_SpanFullWidth |
auto *m = std::any_cast<std::map<u32, PlugboardNodes::ChainSegment>>(&std::get<1>(connected_v).p->extra); ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Leaf |
bool m_empty = m->empty(); ImGuiTreeNodeFlags_FramePadding);
ImGui::BeginDisabled(m_empty || m->begin()->first >= s.current_frame); ImGui::TableSetColumnIndex(2);
if (ImGui::Button("<")) { auto *m = std::any_cast<std::map<u32, PlugboardNodes::ChainSegment>>(
auto it = std::prev(m->upper_bound(s.current_frame)); &info.p->extra);
s.current_frame = (it->first == s.current_frame ? std::prev(it) : it)->first; bool m_empty = m->empty();
} ImGui::BeginDisabled(m_empty || m->begin()->first >= s.current_frame);
ImGui::SameLine(); if (ImGui::Button("<")) {
ImGui::EndDisabled(); auto it = std::prev(m->upper_bound(s.current_frame));
f32 v = std::get<PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type>(PlugboardGraph::Eval(s, std::get<1>(connected_v))), copy = v; s.current_frame = (it->first == s.current_frame ? std::prev(it) : it)->first;
ImGui::DragFloat("##value", &v); }
ImGui::SameLine(); ImGui::SameLine();
if (v != copy) { ImGui::EndDisabled();
auto l = m->lower_bound(s.current_frame); f32 v = std::get<PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type>(
auto interp = l == m->end() ? PlugboardNodes::K_I_Linear : l->second.interp.interp; PlugboardGraph::Eval(s, info)), copy = v;
m->insert_or_assign(s.current_frame, PlugboardNodes::ChainSegment{ ImGui::DragFloat("##value", &v);
.value = v, ImGui::SameLine();
.interp = { if (v != copy) {
.interp = interp 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,
ImGui::BeginDisabled(m_empty || m->rbegin()->first <= s.current_frame); .interp = {
if (ImGui::Button(">")) { .interp = interp
s.current_frame = m->upper_bound(s.current_frame)->first; }
} });
ImGui::EndDisabled(); }
ImGui::TableSetColumnIndex(3); ImGui::BeginDisabled(m_empty || m->rbegin()->first <= s.current_frame);
ImGui::Text("%lu", m->size()); if (ImGui::Button(">")) {
ImGui::TableSetColumnIndex(4); s.current_frame = m->upper_bound(s.current_frame)->first;
ImVec2 begin_tl = ImGui::GetCursorScreenPos(); }
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 std::map<u32, PlugboardNodes::ChainSegment> m_copy{};
static u32 dragging{}; static u32 dragging{};
static decltype(m) drag_m = nullptr; static decltype(m) drag_m = nullptr;
static i64 drag_og = -1; static i64 drag_og = -1;
if (drag_m != m || drag_og == -1) { // premature optimization is the root of good performance !! if (drag_m != m ||
f32 *last_val = nullptr; drag_og == -1) { // premature optimization is the root of good performance !!
u32 last_x = 0; f32 *last_val = nullptr;
for (auto& [k, segment] : *m) { u32 last_x = 0;
ImGui::PushID(k); for (auto &[k, segment]: *m) {
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::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(); ImGui::PopID();
} }
last_val = &segment.value; } else {
last_x = k; m->clear();
for (auto &[k, segment]: m_copy) {
ImGui::SetCursorScreenPos( ImGui::PushID(k);
{TimelineFrameToScreenView(view_left, view_amt, view_width, k, if (drag_og != k) {
s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); if (TimelineFrameInView(view_left, view_right, k, s.frame_max)) {
bool d; ImGui::SetCursorScreenPos(
ImGui::Button("k", {0.0f, row_height * .8f}); {TimelineFrameToScreenView(view_left, view_amt, view_width, k,
if (ImGui::IsItemClicked()) { s.frame_max) + begin_tl.x - 2.5f,
m_copy = *m; begin_tl.y});
drag_og = k; ImGui::Button("k", {0.0f, row_height * .8f});
drag_m = m; m->emplace(k, segment);
} }
ImGui::PopID(); } else {
}
}
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( ImGui::SetCursorScreenPos(
{TimelineFrameToScreenView(view_left, view_amt, view_width, k, {TimelineFrameToScreenView(view_left, view_amt, view_width,
s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); dragging,
s.frame_max) + begin_tl.x - 2.5f,
begin_tl.y});
ImGui::Button("k", {0.0f, row_height * .8f}); 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(); ImGui::PopID();
j++; j++;
} }
@ -1117,7 +1132,6 @@ namespace K::UI {
if (move_from != -1 && move_to != -1) { if (move_from != -1 && move_to != -1) {
if (no_selection) if (no_selection)
std::swap(s.layers[move_to], s.layers[move_from]); std::swap(s.layers[move_to], s.layers[move_from]);
else { else {
const u32 n = s.selected.size(); const u32 n = s.selected.size();
u32 inserted = 0; u32 inserted = 0;
@ -1399,10 +1413,8 @@ namespace K::UI {
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
ImGui::ShowDemoWindow(); ImGui::ShowDemoWindow();
// static ImGuiStyle& style = ImGui::GetStyle();
// style.GrabRounding = style.FrameRounding = 5.0f;
MainMenuBar(s); MainMenuBar(s);
if (draw_viewport) Viewport(s); if (draw_viewport) Viewport(s); // Must go before comp!
if (draw_layer) Layer(s); if (draw_layer) Layer(s);
if (draw_comp) Composition(s); if (draw_comp) Composition(s);
if (draw_interpolation) Interpolation(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], 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::setViewMode(view_id, bgfx::ViewMode::Sequential);
bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL); bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH | BGFX_CLEAR_STENCIL);
bgfx::setViewFrameBuffer(view_id, fb); bgfx::setViewFrameBuffer(view_id, fb);
@ -55,7 +55,8 @@ namespace K {
using T = std::decay_t<decltype(arg)>; using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>) { if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>) {
bool good; 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 !! static_cast<PlugboardGraph::Type>(u.val.index()), // todo DANGEROUS !!
good)); good));
} }

View file

@ -62,17 +62,6 @@ namespace K::PlugboardGraph {
}; };
struct NodeInstance; 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 { struct ConnectInfo {
NodeInstance *p; // NOTE: so NodeInstances must be stored in a list, otherwise vector realloc leads to UAF 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 ? 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 { struct ConnectInfoHasher {
std::size_t operator()(const ConnectInfo& k) const std::size_t operator()(const ConnectInfo& k) const
{ {
@ -97,28 +99,8 @@ namespace K::PlugboardGraph {
std::any extra; std::any extra;
void connect(u32 input_index, NodeInstance *to, u32 to_out_index) { void connect(u32 input_index, NodeInstance *to, u32 to_out_index);
inputs_fed[input_index] = ConnectInfo{to, to_out_index}; void disconnect(u32 input_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);
}
}; };
@ -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 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 { struct LinksFromSource {
ImVec2 source; ImVec2 source;

View file

@ -8,12 +8,12 @@
namespace { namespace {
template <K::PlugboardGraph::Type type> 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; 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)>; using U = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<U, K::PlugboardGraph::ConnectInfo>) 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 else
return arg; return arg;
}, n.inputs_fed[index]), type, good)); }, n.inputs_fed[index]), type, good));
@ -25,245 +25,25 @@ namespace {
} }
namespace K::PlugboardNodes { namespace K::PlugboardNodes {
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchAdd(const CompState& s, const PlugboardGraph::NodeInstance& n) { extern PlugboardGraph::Node Add;
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0), extern PlugboardGraph::Node Negate;
y = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 1); extern PlugboardGraph::Node Subtract;
return x + y; extern PlugboardGraph::Node Multiply;
} extern PlugboardGraph::Node Divide;
extern PlugboardGraph::Node Sign;
PlugboardGraph::Node Add = { extern PlugboardGraph::Node Sin;
.name = "Add", extern PlugboardGraph::Node Cos;
.in = { {"a", PlugboardGraph::T_Float }, {"b", PlugboardGraph::T_Float } }, extern PlugboardGraph::Node Tan;
.out = { { "a+b", PlugboardGraph::T_Float } }, extern PlugboardGraph::Node Arcsin;
.fetch = { FetchAdd } extern PlugboardGraph::Node Arccos;
}; extern PlugboardGraph::Node Arctan;
extern PlugboardGraph::Node Atan2;
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchNegate(const CompState& s, const PlugboardGraph::NodeInstance& n) { extern PlugboardGraph::Node Minimum;
f32 x = GetNodeInputArg<PlugboardGraph::T_Float>(s, n, 0); extern PlugboardGraph::Node Maximum;
return -x; extern PlugboardGraph::Node Power;
} extern PlugboardGraph::Node SquareRoot;
extern PlugboardGraph::Node NaturalLogarithm;
PlugboardGraph::Node Negate = { extern PlugboardGraph::Node AbsoluteValue;
.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 }
};
enum K_Interpolation { enum K_Interpolation {
K_I_CubicBezier, K_I_CubicBezier,
@ -315,261 +95,21 @@ namespace K::PlugboardNodes {
K_I_Count K_I_Count
}; };
extern const char *K_Interpolation_Names[];
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"
};
struct InterpolationExtra { struct InterpolationExtra {
K_Interpolation interp; K_Interpolation interp;
f32 v[4]; f32 v[4];
}; };
f32 EvalInterpolation(f32 x, const InterpolationExtra& extra) { extern PlugboardGraph::Node Interpolation;
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
};
struct ChainSegment { struct ChainSegment {
f32 value; f32 value;
InterpolationExtra interp; InterpolationExtra interp;
}; };
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type FetchChain(const CompState& s, const PlugboardGraph::NodeInstance& n) { extern PlugboardGraph::Node Chain;
u32 frame = GetNodeInputArg<PlugboardGraph::T_Int>(s, n, 0);
auto *v = std::any_cast<std::map<u32, ChainSegment>>(&n.extra); extern std::array<PlugboardGraph::Node*, 20> Nodes;
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
});
} }

View file

@ -8,24 +8,12 @@
#include "PlugboardGraph.h" #include "PlugboardGraph.h"
namespace K { 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 { struct Uniform {
String name; String name;
bgfx::UniformHandle handle; bgfx::UniformHandle handle;
ShaderGraph::T_Map<ShaderGraph::T_Count>::type val; ShaderGraph::T_Map<ShaderGraph::T_Count>::type val;
PlugboardGraph::ConnectInfo connection; PlugboardGraph::ConnectInfo connection;
Vector<PlugboardGraph::ConnectInfo> show_nodes;
}; };
struct Sampler { struct Sampler {
@ -45,7 +33,7 @@ namespace K {
Vector<Uniform> uniforms; Vector<Uniform> uniforms;
Vector<Sampler> samplers; Vector<Sampler> samplers;
void GetFrame(const CompState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], 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); static void ExposeUniform(CompState& s, Uniform& uu);
void ExposeUniform(CompState& s, u32 i); void ExposeUniform(CompState& s, u32 i);
static void HideUniform(CompState& s, Uniform& uu); static void HideUniform(CompState& s, Uniform& uu);

24
TODO.md
View file

@ -1,10 +1,14 @@
# NOW # NOW
## UI ## 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 - 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 ## Compositor
- Video! - Video!
@ -15,18 +19,18 @@
- Data models - Data models
- Dump and read back state, (de)serialization!!! - Dump and read back state, (de)serialization!!!
- Pre-compose/Layer Groups (jokes -- can be completely UI side) - Pre-compose/Layer Groups (jokes -- can be completely UI side)
- Resource
- Deletion
- Motion blur - Motion blur
- Non-negotiable - Text (idea: index-based evaluation in plugboard) - 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) - 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 - External data driving (csv, json or something else?) -- use a node to select source
## Chores
- Node groups
# Later # Later
## IO ## IO
- File dialogues pending SDL3 - File dialogues pending SDL3
- https://wiki.libsdl.org/SDL3/CategoryDialog - https://wiki.libsdl.org/SDL3/CategoryDialog
- Clipboard pending SDL3
- OIIO output for more than PNG's - OIIO output for more than PNG's
- don't care about video export -- leave it for ffmpeg - don't care about video export -- leave it for ffmpeg