static dispatch

This commit is contained in:
lachrymaLF 2024-06-22 07:19:34 -04:00
parent faaa0f8e6f
commit dec9cb0497
16 changed files with 1221 additions and 1116 deletions

View file

@ -20,16 +20,6 @@ namespace {
namespace K {
K::AppState app_state;
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, 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, Vector<PlugboardGraph::ConnectInfo> *show_nodes = nullptr) {
return PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type{ static_cast<f32>(SDL_GetTicks64()) };
}
bool Init() {
if (SDL_Init(SDL_INIT_VIDEO)) {
LogError(SDL_GetError());
@ -101,22 +91,8 @@ namespace K {
state.current_frame = 0;
state.fps = 30.0f;
state.frame_max = 200;
state.plugboard.comp_in = PlugboardGraph::Node{
"Composition In",
{},
{{"Frame", PlugboardGraph::T_Int}, {"Time (s)", PlugboardGraph::T_Float}, {"App Ticks", PlugboardGraph::T_Float}},
{
FetchCompFrame, FetchCompTime, FetchAppTicks
}
};
state.plugboard.comp_out = PlugboardGraph::Node{
"Composition Out",
{},
{},
{}
};
state.plugboard.in_instance = PlugboardGraph::MakeInstance(state.plugboard.comp_in);
state.plugboard.out_instance = PlugboardGraph::MakeInstance(state.plugboard.comp_in);
state.plugboard.in = Plugboard::MakeInstance(Plugboard::K_P_CompositionIn);
state.plugboard.out = Plugboard::MakeInstance(Plugboard::K_P_CompositionOut);
K::UI::SetupViewport(state);
return true;

414
Keishiki/Plugboard.cpp Normal file
View file

@ -0,0 +1,414 @@
#include <Plugboard.h>
#include <Keishiki.h>
namespace K::Plugboard {
bool DetectCycle(const NodeInstance& n, Vector<NodeInstance*>& nodes) { // true if cycle found
return !DFS(n, [&nodes](ConnectInfo info){
if (std::find(nodes.begin(), nodes.end(), info.p) == nodes.end()) {
nodes.push_back(info.p);
return true;
}
else return false;
});
}
void CollectChains(ConnectInfo& in, Vector<ConnectInfo>& chains) {
chains.clear();
if (std::holds_alternative<Chain>(*in.p))
chains.push_back(in);
DFS(*in.p, [&chains](ConnectInfo info){
if (std::holds_alternative<Chain>(*info.p))
chains.push_back(info);
return true;
});
}
void Connect(NodeInstance& from_instance, u8 input_index, NodeInstance& to_instance, u8 to_out_index) {
Vector<NodeInstance*> nodes{&from_instance};
if (!DetectCycle(to_instance, nodes)) // no cycle
std::visit([&](auto&& from, auto&& to) {
from.in[input_index].value = ConnectInfo{&to_instance, to_out_index};
to.out[to_out_index].outgoing.push_back({&from_instance, input_index});
}, from_instance, to_instance);
else
Log("Connect failed -- Cycle detected");
}
void Disconnect(NodeInstance& from_instance, u8 input_index) {
std::visit([&](auto&& from) {
std::visit([&](auto &&arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ConnectInfo>) {
std::visit([&](auto&& a) {
auto& v = a.out[arg.index].outgoing;
for (auto it = v.begin(); it != v.end(); it++) {
if (it->p == &from_instance) {
v.erase(it);
break;
}
}
}, *arg.p);
from.in[input_index].value = ExpandVariant(from.in[input_index].type);
}
else if constexpr (std::is_same_v<T, T_Map<Type::T_Count>::type>)
; // already disconnected
}, from.in[input_index].value);
}, from_instance);
}
NodeInstance MakeInstance(K_P_Nodes i) {
static NodeInstance table[] = {
Add{},
Negate{},
Subtract{},
Multiply{},
Divide{},
Sign{},
Sin{},
Cos{},
Tan{},
Arcsin{},
Arccos{},
Arctan{},
Atan2{},
Minimum{},
Maximum{},
Power{},
SquareRoot{},
NaturalLogarithm{},
AbsoluteValue{},
Interpolation{},
Chain{},
CompositionIn{},
CompositionOut{}
};
static_assert(sizeof(table)/sizeof(table[0]) == K_P_Count);
return table[i];
}
T_Map<T_Count>::type ExpandVariant(u32 i) {
static T_Map<T_Count>::type table[] = { f32{}, i32{}, RGBA{}, XY{}, XYZ{}, String{} };
return table[i];
}
template <Type type>
typename T_Map<type>::type GetNodeInputArg(const CompState& s, const InSocket& socket) {
bool good;
typename T_Map<type>::type v = std::get<typename T_Map<type>::type>(ConvertValue(std::visit([&s](auto&& arg) {
using U = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<U, ConnectInfo>)
return Eval(s, arg);
else
return arg;
}, socket.value), type, good));
if (!good)
K::LogError("Type mismatch on plugboard evaluation!");
return v;
}
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"
};
T_Map<T_Count>::type FetchAdd(const CompState& s, const Add& n) {
return GetNodeInputArg<T_Float>(s, n.in[0]) + GetNodeInputArg<T_Float>(s, n.in[1]);
}
T_Map<T_Count>::type FetchNegate(const CompState& s, const Negate& n) {
return -GetNodeInputArg<T_Float>(s, n.in[0]);
}
T_Map<T_Count>::type FetchSubtract(const CompState& s, const Subtract& n) {
return GetNodeInputArg<T_Float>(s, n.in[0]) - GetNodeInputArg<T_Float>(s, n.in[1]);
}
T_Map<T_Count>::type FetchMultiply(const CompState& s, const Multiply& n) {
return GetNodeInputArg<T_Float>(s, n.in[0]) * GetNodeInputArg<T_Float>(s, n.in[1]);
}
T_Map<T_Count>::type FetchDivide(const CompState& s, const Divide& n) {
return GetNodeInputArg<T_Float>(s, n.in[0]) / GetNodeInputArg<T_Float>(s, n.in[1]);
}
T_Map<T_Count>::type FetchSign(const CompState& s, const Sign& n) {
return std::signbit(GetNodeInputArg<T_Float>(s, n.in[0])) ? -1.0f : 1.0f;
}
T_Map<T_Count>::type FetchSin(const CompState& s, const Sin& n) {
return std::sin(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchCos(const CompState& s, const Cos& n) {
return std::cos(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchTan(const CompState& s, const Tan& n) {
return std::tan(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchArcsin(const CompState& s, const Arcsin& n) {
return std::asin(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchArccos(const CompState& s, const Arccos& n) {
return std::acos(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchArctan(const CompState& s, const Arctan& n) {
return std::atan(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchAtan2(const CompState& s, const Atan2& n) {
return std::atan2(GetNodeInputArg<T_Float>(s, n.in[0]), GetNodeInputArg<T_Float>(s, n.in[1]));
}
T_Map<T_Count>::type FetchMinimum(const CompState& s, const Minimum& n) {
return std::min(GetNodeInputArg<T_Float>(s, n.in[0]), GetNodeInputArg<T_Float>(s, n.in[1]));
}
T_Map<T_Count>::type FetchMaximum(const CompState& s, const Maximum& n) {
return std::max(GetNodeInputArg<T_Float>(s, n.in[0]), GetNodeInputArg<T_Float>(s, n.in[1]));
}
T_Map<T_Count>::type FetchPower(const CompState& s, const Power& n) {
return std::pow(GetNodeInputArg<T_Float>(s, n.in[0]), GetNodeInputArg<T_Float>(s, n.in[1]));
}
T_Map<T_Count>::type FetchSquareRoot(const CompState& s, const SquareRoot& n) {
return std::sqrt(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchNaturalLogarithm(const CompState& s, const NaturalLogarithm& n) {
return std::log(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchAbsoluteValue(const CompState& s, const AbsoluteValue& n) {
return std::abs(GetNodeInputArg<T_Float>(s, n.in[0]));
}
T_Map<T_Count>::type FetchInterpolation(const CompState& s, const Interpolation& n) {
return EvalInterpolation(GetNodeInputArg<T_Float>(s, n.in[0]), n.extra);
}
void Interpolation::Draw() {
ImGui::SetNextItemWidth(-FLT_MIN);
if (ImGui::BeginCombo("##Interp", K_Interpolation_Names[extra.interp], ImGuiComboFlags_None)) {
for (u32 i = 0; i < K_Interpolation::K_I_Count; i++) {
const bool is_selected = (extra.interp == i);
if (ImGui::Selectable(K_Interpolation_Names[i], is_selected))
extra.interp = static_cast<K_Interpolation>(i);
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
}
T_Map<T_Count>::type FetchChain(const CompState& s, const Chain& n) {
i32 frame = static_cast<i32>(GetNodeInputArg<T_Int>(s, n.in[0]));
auto& v = n.extra.chain.segments;
if (v.empty())
return 0.0f;
if (v.back().frame <= frame)
return v.back().value;
if (v.front().frame >= frame)
return v.front().value;
auto nit = std::upper_bound(v.cbegin(), v.cend(), frame,
[](i32 a, const ChainSegment& b) {
return a < b.frame;
}), it = std::prev(nit);
i32 x1 = it->frame, x2 = nit->frame;
f32 t = static_cast<f32>(frame - x1) / static_cast<f32>(x2 - x1);
f32 normalized_val = EvalInterpolation(t, it->interp);
return it->value + normalized_val * (nit->value - it->value);
}
constexpr String VarToString(const T_Map<T_Count>::type& var) {
return std::visit([](auto&& arg) -> String {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, T_Map<T_Float>::type>)
return std::to_string(arg) + "f";
else if constexpr (std::is_same_v<T, T_Map<T_Int>::type>)
return std::to_string(arg);
else if constexpr (std::is_same_v<T, T_Map<T_RGBA>::type>)
return "vec4(" + std::to_string(arg.r) + "," + std::to_string(arg.g) + "," + std::to_string(arg.b) + "," + std::to_string(arg.a) + ")";
else if constexpr (std::is_same_v<T, T_Map<T_XY>::type>)
return "vec2(" + std::to_string(arg.x) + "," + std::to_string(arg.y) + ")";
else if constexpr (std::is_same_v<T, T_Map<T_XYZ>::type>)
return "vec3(" + std::to_string(arg.x) + "," + std::to_string(arg.y) + "," + std::to_string(arg.z) + ")";
else if constexpr (std::is_same_v<T, T_Map<T_String>::type>)
return arg;
}, var);
}
T_Map<T_Count>::type Eval(const CompState& s, const ConnectInfo& info) {
return std::visit([&info, &s](auto&& arg) { return arg.fetch[info.index](s, arg); }, *info.p);
}
T_Map<T_Count>::type ConvertValue(const T_Map<T_Count>::type& v, Type target, bool& good) {
good = true;
return std::visit([&good, target](auto&& arg) -> T_Map<T_Count>::type {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, T_Map<T_Float>::type>) {
switch (target) {
case T_Float:
return arg;
case T_Int:
return static_cast<T_Map<T_Int>::type>(std::round(arg));
case T_RGBA:
return RGBA{ arg, arg, arg, arg };
case T_XY:
return XY{ arg, arg };
case T_XYZ:
return XYZ{ arg, arg, arg };
case T_String:
return VarToString(arg);
case T_Count:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_Int>::type>) {
auto f = static_cast<T_Map<T_Float>::type>(arg);
switch (target) {
case T_Float:
return f;
case T_Int:
return arg;
case T_RGBA:
return RGBA{ f, f, f, f };
case T_XY:
return XY{ f, f };
case T_XYZ:
return XYZ{ f, f, f };
case T_String:
return VarToString(arg);
case T_Count:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_RGBA>::type>) {
switch (target) {
case T_RGBA:
return arg;
case T_String:
return VarToString(arg);
default:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_XY>::type>) {
switch (target) {
case T_XY:
return arg;
case T_String:
return VarToString(arg);
default:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_XYZ>::type>) {
switch (target) {
case T_XYZ:
return arg;
case T_String:
return VarToString(arg);
default:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_String>::type>) {
switch (target) {
case T_String:
return arg;
default:
good = false;
return {};
}
}
return {};
}, v);
}
T_Map<T_Count>::type FetchCompositionInFrame(const CompState& s, const CompositionIn& n) {
return T_Map<T_Count>::type{static_cast<i32>(s.current_frame)};
}
T_Map<T_Count>::type FetchCompositionInTime(const CompState& s, const CompositionIn& n) {
return T_Map<T_Count>::type{static_cast<f32>(s.current_frame) / s.fps};
}
T_Map<T_Count>::type FetchCompositionInAppTicks(const CompState& s, const CompositionIn& n) {
return T_Map<T_Count>::type{ static_cast<f32>(SDL_GetTicks64()) };
}
void Plugboard::RecollectChains() {
auto& node = std::get<CompositionOut>(out);
for (u32 i = 0; i < node.in.size(); i++) {
std::visit([i, &node](auto&& arg) {
if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, ConnectInfo>)
CollectChains(arg, node.show_nodes[i]);
}, node.in[i].value);
}
}
}

View file

@ -1,170 +0,0 @@
#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);
}
constexpr String VarToString(const T_Map<T_Count>::type& var) {
return std::visit([](auto&& arg) -> String {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, T_Map<T_Float>::type>)
return std::to_string(arg) + "f";
else if constexpr (std::is_same_v<T, T_Map<T_Int>::type>)
return std::to_string(arg);
else if constexpr (std::is_same_v<T, T_Map<T_RGBA>::type>)
return "vec4(" + std::to_string(arg.r) + "," + std::to_string(arg.g) + "," + std::to_string(arg.b) + "," + std::to_string(arg.a) + ")";
else if constexpr (std::is_same_v<T, T_Map<T_XY>::type>)
return "vec2(" + std::to_string(arg.x) + "," + std::to_string(arg.y) + ")";
else if constexpr (std::is_same_v<T, T_Map<T_XYZ>::type>)
return "vec3(" + std::to_string(arg.x) + "," + std::to_string(arg.y) + "," + std::to_string(arg.z) + ")";
else if constexpr (std::is_same_v<T, T_Map<T_String>::type>)
return arg;
}, var);
}
T_Map<T_Count>::type expand_type(Type i) {
static T_Map<T_Count>::type table[] = {f32{}, i32{}, RGBA{}, XY{}, XYZ{}, String{}};
return table[i];
}
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) {
Vector<std::variant<T_Map<Type::T_Count>::type, ConnectInfo>> inp;
Vector<Vector<ConnectInfo>> out;
for (const auto& t : n.in)
inp.emplace_back(expand_type(t.type));
for (auto t : n.out)
out.emplace_back();
auto instance = NodeInstance{
.node = &n,
.inputs_fed = std::move(inp),
.outputs_going = std::move(out)
};
if (n.extra_setup != nullptr)
n.extra_setup(instance);
return instance;
}
T_Map<T_Count>::type ConvertValue(const T_Map<T_Count>::type& v, Type target, bool& good) {
good = true;
return std::visit([&good, target](auto&& arg) -> T_Map<T_Count>::type {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, T_Map<T_Float>::type>) {
switch (target) {
case T_Float:
return arg;
case T_Int:
return static_cast<T_Map<T_Int>::type>(std::round(arg));
case T_RGBA:
return RGBA{ arg, arg, arg, arg };
case T_XY:
return XY{ arg, arg };
case T_XYZ:
return XYZ{ arg, arg, arg };
case T_String:
return VarToString(arg);
case T_Count:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_Int>::type>) {
auto f = static_cast<T_Map<T_Float>::type>(arg);
switch (target) {
case T_Float:
return f;
case T_Int:
return arg;
case T_RGBA:
return RGBA{ f, f, f, f };
case T_XY:
return XY{ f, f };
case T_XYZ:
return XYZ{ f, f, f };
case T_String:
return VarToString(arg);
case T_Count:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_RGBA>::type>) {
switch (target) {
case T_RGBA:
return arg;
case T_String:
return VarToString(arg);
default:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_XY>::type>) {
switch (target) {
case T_XY:
return arg;
case T_String:
return VarToString(arg);
default:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_XYZ>::type>) {
switch (target) {
case T_XYZ:
return arg;
case T_String:
return VarToString(arg);
default:
good = false;
return {};
}
}
else if constexpr (std::is_same_v<T, T_Map<T_String>::type>) {
switch (target) {
case T_String:
return arg;
default:
good = false;
return {};
}
}
return {};
}, v);
}
}

View file

@ -1,394 +0,0 @@
#include <PlugboardNodes.h>
#include <algorithm>
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 }
};
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) {
i32 frame = static_cast<i32>(GetNodeInputArg<PlugboardGraph::T_Int>(s, n, 0, show_nodes));
auto& [chain, _] = *std::any_cast<ChainExtra>(&n.extra);
auto& v = chain.segments;
if (v.empty())
return 0.0f;
if (v.back().frame <= frame)
return v.back().value;
if (v.front().frame >= frame)
return v.front().value;
auto nit = std::upper_bound(v.cbegin(), v.cend(), frame,
[](i32 a, const PlugboardNodes::ChainSegment& b) {
return a < b.frame;
}), it = std::prev(nit);
i32 x1 = it->frame, x2 = nit->frame;
f32 t = static_cast<f32>(frame - x1) / static_cast<f32>(x2 - x1);
f32 normalized_val = EvalInterpolation(t, it->interp);
return it->value + normalized_val * (nit->value - it->value);
}
void SetUpChain(PlugboardGraph::NodeInstance& n) {
n.extra = ChainExtra{};
}
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

@ -49,7 +49,7 @@ namespace K::Resource {
K::LogError("Image loading failed for " + p.string());
return nullptr;
}
const bgfx::Memory *ref = bgfx::makeRef(res.buf, res.w * res.h * res.channels * sizeof(u8));
const bgfx::Memory *ref = bgfx::makeRef(res.buf, res.w * res.h * res.channels * sizeof(Byte));
res.format = res.channels == 4 ? bgfx::TextureFormat::RGBA8 : bgfx::TextureFormat::RGB8;
res.tex = bgfx::createTexture2D(
res.w,
@ -105,12 +105,12 @@ namespace K::Resource {
if constexpr (std::is_same_v<T, Resource<K_R_Still>>) {
i32 w, h, channels;
u8 *buf = stbi_load(path.c_str(), &w, &h, &channels, 0);
Byte *buf = stbi_load(path.c_str(), &w, &h, &channels, 0);
if (buf == nullptr) {
K::LogError("Image loading failed for " + path.string());
return;
}
const bgfx::Memory *ref = bgfx::makeRef(buf, w * h * channels * sizeof(u8));
const bgfx::Memory *ref = bgfx::makeRef(buf, w * h * channels * sizeof(Byte));
auto format = channels == 4 ? bgfx::TextureFormat::RGBA8 : bgfx::TextureFormat::RGB8;
auto tex = bgfx::createTexture2D(
w,

View file

@ -17,6 +17,10 @@ namespace {
}
namespace K::ShaderGraph {
T_Map<T_Count>::type ExpandVariant(u32 i) {
static T_Map<T_Count>::type table[] = { f32{}, i32{}, RGBA{}, XY{}, XYZ{} };
return table[i];
}
String VarToString(const T_Map<T_Count>::type& var) {
return std::visit([](auto&& arg) -> String {
using T = std::decay_t<decltype(arg)>;
@ -32,13 +36,8 @@ namespace K::ShaderGraph {
return "vec3(" + std::to_string(arg.x) + "," + std::to_string(arg.y) + "," + std::to_string(arg.z) + ")";
}, var);
}
String ShaderGraph::generate_shader() const {
String ShaderGraph::GenerateShader() const {
if (RGBA_node->node->out_types[RGBA_node_out_index] != Type::T_RGBA) return {};
return BuildNode(*RGBA_node);
}
T_Map<T_Count>::type expand_type(Type i) {
static constexpr T_Map<T_Count>::type table[] = {f32{}, i32{}, RGBA{}, XY{}, XYZ{}};
return table[i];
}
}

View file

@ -1,7 +1,6 @@
#include "UI.h"
#include "Graphics.h"
#include "VisualTrack.h"
#include "PlugboardNodes.h"
#include <imgui.h>
#include <imgui_internal.h>
@ -67,22 +66,22 @@ namespace K::UI {
0UL,
s.frame_max
};
l.track.AddUniform("u_aspect_ratio", ShaderGraph::expand_type(ShaderGraph::T_XY));
l.track.AddUniform("u_aspect_ratio", ShaderGraph::ExpandVariant(ShaderGraph::T_XY));
if (s.width > s.height)
l.track.uniforms[0].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type{static_cast<f32>(s.width)/static_cast<f32>(s.height), 1.0f};
else
l.track.uniforms[0].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type{1.0f, static_cast<f32>(s.height)/static_cast<f32>(s.width)};
l.track.AddUniform("u_opacity", ShaderGraph::expand_type(ShaderGraph::T_Float));
l.track.AddUniform("u_opacity", ShaderGraph::ExpandVariant(ShaderGraph::T_Float));
l.track.uniforms[1].val = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(1.0f);
l.track.AddUniform("u_rot", ShaderGraph::expand_type(ShaderGraph::T_Float));
l.track.AddUniform("u_rot", ShaderGraph::ExpandVariant(ShaderGraph::T_Float));
l.track.uniforms[2].val = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(.0f);
l.track.AddUniform("u_scale", ShaderGraph::expand_type(ShaderGraph::T_XY));
l.track.AddUniform("u_scale", ShaderGraph::ExpandVariant(ShaderGraph::T_XY));
l.track.uniforms[3].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type{1.0f, 1.0f};
l.track.AddUniform("u_translate", ShaderGraph::expand_type(ShaderGraph::T_XY));
l.track.AddUniform("u_translate", ShaderGraph::ExpandVariant(ShaderGraph::T_XY));
l.track.uniforms[4].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type{.0f, .0f};
l.track.shader = "void main() {\n"
@ -171,35 +170,36 @@ namespace K::UI {
layer.track.Clear();
}
void DrawPlugboardVariableEditWidget(PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type& var) {
void DrawPlugboardVariableEditWidget(Plugboard::T_Map<Plugboard::T_Count>::type& var) {
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type>)
if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Float>::type>)
ImGui::DragFloat("##", &arg, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Int>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Int>::type>)
ImGui::DragInt("##", &arg, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_RGBA>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_RGBA>::type>)
ImGui::DragFloat4("##", &arg.r, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_XY>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XY>::type>)
ImGui::DragFloat2("##", &arg.x, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_XYZ>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XYZ>::type>)
ImGui::DragFloat3("##", &arg.x, 0.005f);
}, var);
}
void PlugboardNodeDrawSockets(PlugboardGraph::NodeInstance& n, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, std::unordered_map<PlugboardGraph::ConnectInfo, PlugboardGraph::LinksFromSource, PlugboardGraph::ConnectInfoHasher>& link_pos,
template <Plugboard::Node N>
void PlugboardNodeDrawSockets(CompState& s, N& n, Plugboard::NodeInstance& instance, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& link_pos,
bool dummy = true) {
i32 row = 1;
for (u32 out = 0; out < n.node->out.size(); out++, row++) {
for (u32 out = 0; out < n.out.size(); out++, row++) {
ImGui::PushID(row);
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
if (dummy)
ImGui::Dummy({100.0f - ImGui::CalcTextSize(n.node->out[out].name.c_str()).x - style.ItemSpacing.x, 0.0f});
ImGui::Dummy({100.0f - ImGui::CalcTextSize(n.out[out].name.c_str()).x - style.ItemSpacing.x, 0.0f});
ImGui::SameLine();
ImGui::TextUnformatted(n.node->out[out].name.c_str());
ImGui::TextUnformatted(n.out[out].name.c_str());
ImGui::TableNextColumn();
ImGui::RadioButton("##Out", false);
if (ImGui::IsItemActive()) {
@ -208,41 +208,43 @@ namespace K::UI {
}
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
PlugboardGraph::ConnectInfo d{ &n, out };
Plugboard::ConnectInfo d{ &instance, out };
ImGui::SetDragDropPayload("K_PLUG_OUT_TO_IN", &d, sizeof(d));
ImGui::EndDragDropSource();
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("K_PLUG_IN_TO_OUT")) {
PlugboardGraph::ConnectInfo in = *(const PlugboardGraph::ConnectInfo*)payload->Data;
in.p->connect(in.index, &n, out);
Plugboard::ConnectInfo in = *(const Plugboard::ConnectInfo*)payload->Data;
Plugboard::Connect(*in.p, in.index, instance, out);
s.plugboard.RecollectChains();
}
ImGui::EndDragDropTarget();
}
ImGui::PopID();
// Update link info if needed
if (!n.outputs_going[out].empty()) {\
link_pos[{&n, out}].source = ImGui::GetCursorScreenPos() + ImVec2{ImGui::GetFrameHeight() / 2,
if (!n.out[out].outgoing.empty()) {\
link_pos[{&instance, out}].source = ImGui::GetCursorScreenPos() + ImVec2{ImGui::GetFrameHeight() / 2,
-ImGui::GetFrameHeight() / 2 -
style.ItemInnerSpacing.y};
}
}
for (u32 in = 0; in < n.inputs_fed.size(); in++, row++) {
for (u32 in = 0; in < n.in.size(); in++, row++) {
ImGui::PushID(row);
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::RadioButton("##In", false);
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
PlugboardGraph::ConnectInfo d{ &n, in };
Plugboard::ConnectInfo d{ &instance, in };
ImGui::SetDragDropPayload("K_PLUG_IN_TO_OUT", &d, sizeof(d));
ImGui::EndDragDropSource();
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("K_PLUG_OUT_TO_IN")) {
PlugboardGraph::ConnectInfo out = *(const PlugboardGraph::ConnectInfo*)payload->Data;
n.connect(in, out.p, out.index);
Plugboard::ConnectInfo out = *(const Plugboard::ConnectInfo*)payload->Data;
Plugboard::Connect(instance, in, *out.p, out.index);
s.plugboard.RecollectChains();
}
ImGui::EndDragDropTarget();
}
@ -250,12 +252,12 @@ namespace K::UI {
auto socket_link_pos = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y};
ImGui::TableNextColumn();
ImGui::TextUnformatted(n.node->in[in].name.c_str());
ImGui::TextUnformatted(n.in[in].name.c_str());
// Update link info
std::visit([&socket_link_pos, &dragging_on_socket, &source, &link_pos](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>) {
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) {
if (ImGui::IsItemActive())
link_pos[arg].sinks.push_back(ImGui::GetMousePos());
else
@ -265,33 +267,36 @@ namespace K::UI {
dragging_on_socket = true;
source = socket_link_pos;
}
if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::Type::T_Count>::type>) {
if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::Type::T_Count>::type>) {
ImGui::SameLine();
DrawPlugboardVariableEditWidget(arg);
}
}, n.inputs_fed[in]);
}, n.in[in].value);
ImGui::TableNextColumn();
ImGui::PopID();
}
}
bool PlugboardDrawNode(PlugboardGraph::NodeInstance& n, ImVec2& view_pos, i32 id, ImGuiIO& io, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, std::unordered_map<PlugboardGraph::ConnectInfo, PlugboardGraph::LinksFromSource, PlugboardGraph::ConnectInfoHasher>& link_pos, bool selected) {
template <Plugboard::Node N>
bool PlugboardDrawNode(CompState& s, N& n, Plugboard::NodeInstance& instance, ImVec2& view_pos, i32 id, ImGuiIO& io, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& link_pos, bool selected) {
bool stat = false;
ImGui::SetCursorPos(view_pos + n.pos);
const auto& pos = n.pos;
const auto& name = n.name;
ImGui::SetCursorPos(view_pos + pos);
ImGui::PushID(id);
ImGui::PushStyleColor(ImGuiCol_ChildBg, selected ? 0xAA202040 : 0xAA080813);
static ImVec2 old_pos{};
if (ImGui::BeginChild(n.node->name.c_str(), {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Border)) {
if (ImGui::BeginTable(n.node->name.c_str(), 3)) {
if (ImGui::BeginChild(name, {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Border)) {
if (ImGui::BeginTable(name, 3)) {
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Button(n.node->name.c_str(), {100.0f , 0.0f});
ImGui::Button(name, {100.0f , 0.0f});
if (ImGui::IsItemClicked()) {
old_pos = n.pos;
old_pos = pos;
stat = true;
}
if (ImGui::IsItemActive()) {
@ -299,15 +304,15 @@ namespace K::UI {
}
ImGui::TableNextColumn();
if (n.node->special_draw != nullptr) {
if constexpr (std::is_same_v<N, Plugboard::Interpolation>) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
n.node->special_draw(n);
n.Draw();
ImGui::TableNextColumn();
}
PlugboardNodeDrawSockets(n, style, dragging_on_socket, source, link_pos);
PlugboardNodeDrawSockets<N>(s, n, instance, style, dragging_on_socket, source, link_pos);
ImGui::EndTable();
}
@ -408,7 +413,7 @@ namespace K::UI {
f32 begin, end;
i32 samples;
const CompState &s;
PlugboardGraph::ConnectInfo &connected_v;
Plugboard::ConnectInfo &connected_v;
};
void Composition(CompState& s) {
@ -423,15 +428,16 @@ namespace K::UI {
static u32 node_current{};
if (ImGui::Button("Add")) {
auto n = PlugboardGraph::MakeInstance(*PlugboardNodes::Nodes[node_current]);
auto n = Plugboard::MakeInstance(Plugboard::K_P_Nodes(node_current));
s.plugboard.nodes.push_back(std::move(n));
}
ImGui::SameLine();
ImGui::SetNextItemWidth(150.0f);
if (ImGui::BeginCombo("##Node", PlugboardNodes::Nodes[node_current]->name.c_str(), ImGuiComboFlags_None)) {
for (int n = 0; n < PlugboardNodes::Nodes.size(); n++) {
std::visit([](auto&& arg) {
if (ImGui::BeginCombo("##Node", arg.name, ImGuiComboFlags_None)) {
for (u32 n = 0; n < Plugboard::K_P_Count; n++) {
const bool is_selected = (node_current == n);
if (ImGui::Selectable(PlugboardNodes::Nodes[n]->name.c_str(), is_selected))
if (ImGui::Selectable(std::visit([](auto&& a) { return a.name; }, Plugboard::MakeInstance(Plugboard::K_P_Nodes(node_current))), is_selected))
node_current = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
@ -440,6 +446,7 @@ namespace K::UI {
}
ImGui::EndCombo();
}
}, Plugboard::MakeInstance(Plugboard::K_P_Nodes(node_current))); // COPIES!!!
ImGui::SameLine();
if (ImGui::Button(playing ? "Pause" : "Play"))
@ -510,8 +517,8 @@ namespace K::UI {
if (ImGui::BeginDragDropTargetCustom(window->ContentRegionRect, window->ID)) {
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("K_PLUG_IN_TO_OUT")) {
PlugboardGraph::ConnectInfo in = *(const PlugboardGraph::ConnectInfo *) payload->Data;
in.p->disconnect(in.index);
Plugboard::ConnectInfo in = *(const Plugboard::ConnectInfo *) payload->Data;
Plugboard::Disconnect(*in.p, in.index);
}
ImGui::EndDragDropTarget();
}
@ -535,17 +542,20 @@ namespace K::UI {
u32 i = 0;
for (auto it = s.plugboard.nodes.begin(); it != s.plugboard.nodes.end(); it++, i++)
if (PlugboardDrawNode(*it, view_pos, static_cast<i32>(i), io, style, dragging_on_socket, drag_source, s.plugboard.links_pos, selected == i))
std::visit([&it, &i, &io, &style, &dragging_on_socket, &drag_source, &s](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if (PlugboardDrawNode<T>(s, arg, *it, view_pos, static_cast<i32>(i), io, style, dragging_on_socket,
drag_source, s.plugboard.links_pos, selected == i))
selected = i;
}, *it);
ImGui::SetCursorPos({});
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0x33FFFFFF);
ImGui::BeginChild(s.plugboard.comp_in.name.c_str(), {},
ImGui::BeginChild("Composition In", {},
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX |
ImGuiChildFlags_AutoResizeY);
ImGui::PopStyleColor();
if (ImGui::BeginTable(s.plugboard.comp_in.name.c_str(), 3)) {
PlugboardNodeDrawSockets(s.plugboard.in_instance, style, dragging_on_socket, drag_source,
if (ImGui::BeginTable("Composition In", 3)) {
PlugboardNodeDrawSockets<Plugboard::CompositionIn>(s, std::get<Plugboard::CompositionIn>(s.plugboard.in), s.plugboard.in, style, dragging_on_socket, drag_source,
s.plugboard.links_pos, false);
ImGui::EndTable();
}
@ -572,14 +582,14 @@ namespace K::UI {
f32 view_amt = view_right - view_left, mouse_tl_x;
f32 fr_step;
static Vector<PlugboardGraph::NodeInstance*> selected_chains{};
static Vector<Plugboard::NodeInstance*> selected_chains{};
// Mouse Handlers
// Drag playhead/pan
static bool tl_clear_selection_request = false;
bool tl_clear_selection_request_this_frame = tl_clear_selection_request;
static bool bg_drag_select_active = false;
static Vector<PlugboardNodes::ChainSegment*> keys_selected_by_bg_drag{};
static Vector<Plugboard::ChainSegment*> keys_selected_by_bg_drag{};
auto draw_tl_bg_drag_area = [&view_width, &style, &view_amt, &s, &mouse_tl_x, &io](f32 h = 0.0f, f32 w = 0.0f) {
static f32 pan_x, view_left_old, view_right_old;
ImGui::InvisibleButton("##TL_BG", ImVec2{ w == 0.0f ? view_width + style.CellPadding.x * 2 : w, h == 0.0f ? row_height + style.CellPadding.y : h});
@ -620,11 +630,11 @@ namespace K::UI {
constexpr static f32 kf_tab_width = 6.0f;
auto kf_drag_btn_handler = [&io, &drag_rect](
PlugboardNodes::ChainSel *key_loop_target, bool dragging, PlugboardNodes::ChainSel& chain, i32 frame, bool is_sel,
Vector<u32>::iterator sel_it, const PlugboardNodes::InterpolationExtra& segment, f64 v, u32 ii, bool& started_dragging, const ImVec2& k_pos) {
Plugboard::ChainSel *key_loop_target, bool dragging, Plugboard::ChainSel& chain, i32 frame, bool is_sel,
Vector<u32>::iterator sel_it, const Plugboard::InterpolationExtra& segment, f64 v, u32 ii, bool& started_dragging, const ImVec2& k_pos) {
if (dragging) {
auto pos = std::lower_bound(chain.segments.begin(), chain.segments.end(), frame,
[](const PlugboardNodes::ChainSegment &a, i32 b) {
[](const Plugboard::ChainSegment &a, i32 b) {
return a.frame < b;
});
@ -939,16 +949,18 @@ namespace K::UI {
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("K_PLUG_OUT_TO_IN")) {
auto out = *(const PlugboardGraph::ConnectInfo *) payload->Data;
u.connection.p->connect(u.connection.index, out.p, out.index);
auto out = *(const Plugboard::ConnectInfo *) payload->Data;
Plugboard::Connect(*u.connection.p, u.connection.index, *out.p, out.index);
s.plugboard.RecollectChains();
}
ImGui::EndDragDropTarget();
}
auto& connected_v = u.connection.p->inputs_fed[u.connection.index];
auto& connected_v = std::visit([&u](auto&& arg) -> auto& { return arg.in[u.connection.index].value; }, *u.connection.p);
std::visit([&u, &dragging_on_socket, &drag_source, &s, &style, &io](auto &&arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>) {
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) {
if (ImGui::IsItemActive())
s.plugboard.links_pos[arg].sinks.push_back(io.MousePos);
else
@ -959,10 +971,13 @@ namespace K::UI {
}
else if (ImGui::IsItemActive()) {
if (ImGui::IsKeyPressed(ImGuiKey_LeftShift)) {
s.plugboard.nodes.push_back(PlugboardGraph::MakeInstance(PlugboardNodes::Chain));
s.plugboard.nodes.push_back(Plugboard::MakeInstance(Plugboard::K_P_Chain));
auto it = s.plugboard.nodes.rbegin();
u.connection.p->connect(u.connection.index, &*it, 0);
it->connect(0, &s.plugboard.in_instance, 0);
Plugboard::Connect(*u.connection.p, u.connection.index, *it, 0);
Plugboard::Connect(*it, 0, s.plugboard.in, 0);
auto& nodes = std::get<Plugboard::CompositionOut>(*u.connection.p).show_nodes[u.connection.index];
nodes.clear();
nodes.emplace_back(&*it, 0);
}
else {
dragging_on_socket = true;
@ -986,15 +1001,15 @@ namespace K::UI {
if (connected_v.index() == 0)
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type>)
if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Float>::type>)
ImGui::DragFloat("##", &arg, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Int>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Int>::type>)
ImGui::DragInt("##", &arg, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_RGBA>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_RGBA>::type>)
ImGui::DragFloat4("##", &arg.r, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_XY>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XY>::type>)
ImGui::DragFloat2("##", &arg.x, 0.005f);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_XYZ>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XYZ>::type>)
ImGui::DragFloat3("##", &arg.x, 0.005f);
}, std::get<0>(connected_v));
@ -1026,8 +1041,8 @@ namespace K::UI {
CompState ss = i.s;
ss.current_frame = static_cast<u64>(std::round(x));
bool 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))};
Vector<Plugboard::ConnectInfo> info;
return {x, std::get<Plugboard::T_Map<Plugboard::T_Float>::type>(Plugboard::ConvertValue(Plugboard::Eval(ss, i.connected_v), Plugboard::T_Float, good))};
}, &info, info.samples);
ImPlot::EndPlot();
}
@ -1042,7 +1057,7 @@ namespace K::UI {
draw_tl_bg_drag_area();
if (uniform_open && connected_v.index() == 1) {
for (auto info: u.show_nodes) {
for (const auto& info: std::get<Plugboard::CompositionOut>(*u.connection.p).show_nodes[u.connection.index]) {
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableSetColumnIndex(0);
ImGui::TableSetColumnIndex(1);
@ -1053,7 +1068,7 @@ namespace K::UI {
auto chain_sel_it = std::find(selected_chains.begin(), selected_chains.end(), info.p);
if (chain_sel_it != selected_chains.end())
n_flags |= ImGuiTreeNodeFlags_Selected;
ImGui::TreeNodeEx(info.p->node->name.c_str(), n_flags);
ImGui::TreeNodeEx(std::visit([](auto&& arg){ return arg.name; }, *info.p), n_flags);
if (ImGui::IsItemClicked()) {
if (chain_sel_it != selected_chains.end())
selected_chains.erase(chain_sel_it);
@ -1062,7 +1077,7 @@ namespace K::UI {
}
ImGui::TableSetColumnIndex(2);
auto& [chain, chain_copy] = *std::any_cast<PlugboardNodes::ChainExtra>(&info.p->extra);
auto& [chain, chain_copy] = std::get<Plugboard::Chain>(*info.p).extra;
if (tl_clear_selection_request)
chain.selected.clear();
@ -1073,7 +1088,7 @@ namespace K::UI {
if (ImGui::Button("<")) {
s.current_frame = std::prev(std::lower_bound(chain.segments.begin(), chain.segments.end(),
s.current_frame,
[](const PlugboardNodes::ChainSegment &a, i32 b) {
[](const Plugboard::ChainSegment &a, i32 b) {
return a.frame < b;
}))->frame;
}
@ -1081,22 +1096,22 @@ namespace K::UI {
ImGui::SameLine();
f32 v = std::get<PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type>(
PlugboardGraph::Eval(s, info));
f32 v = std::get<Plugboard::T_Map<Plugboard::T_Float>::type>(
Plugboard::Eval(s, info));
if (ImGui::DragFloat("##value", &v, 0.005f)) {
if (std::find(selected_chains.begin(), selected_chains.end(), info.p) == selected_chains.end())
selected_chains.push_back(info.p);
auto l = std::lower_bound(chain.segments.begin(), chain.segments.end(), s.current_frame,
[](const PlugboardNodes::ChainSegment& a, i32 b) { return a.frame < b; });
[](const Plugboard::ChainSegment& a, i32 b) { return a.frame < b; });
if (l != chain.segments.end() && l->frame == static_cast<i32>(s.current_frame))
l->value = v;
else {
for (auto& sel : chain.selected)
if (sel >= std::distance(chain.segments.begin(), l))
sel++;
chain.segments.emplace(l, s.current_frame, v, PlugboardNodes::InterpolationExtra{
m_has_before ? std::prev(l)->interp.interp : PlugboardNodes::K_I_Linear
chain.segments.emplace(l, s.current_frame, v, Plugboard::InterpolationExtra{
m_has_before ? std::prev(l)->interp.interp : Plugboard::K_I_Linear
});
}
}
@ -1106,7 +1121,7 @@ namespace K::UI {
ImGui::BeginDisabled(m_empty || chain.segments.back().frame <= s.current_frame);
if (ImGui::Button(">"))
s.current_frame = std::upper_bound(chain.segments.begin(), chain.segments.end(), s.current_frame,
[](i32 a, const PlugboardNodes::ChainSegment& b) { return a < b.frame; })->frame;
[](i32 a, const Plugboard::ChainSegment& b) { return a < b.frame; })->frame;
ImGui::EndDisabled();
ImGui::TableSetColumnIndex(3);
@ -1173,10 +1188,10 @@ namespace K::UI {
else for (auto &u: current_layer.track.uniforms)
std::visit([table_left, &s](auto &&arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>)
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>)
s.plugboard.links_pos[arg].sinks.push_back(
{table_left, ImGui::GetCursorScreenPos().y - row_height / 2.0f});
}, u.connection.p->inputs_fed[u.connection.index]);
}, std::visit([&u](auto&& arg) -> auto& { return arg.in[u.connection.index].value; }, *u.connection.p));
ImGui::PopStyleVar(); // FramePadding
@ -1266,8 +1281,8 @@ namespace K::UI {
}
u32 keys = 0;
for (const auto& n : selected_chains) {
PlugboardGraph::ConnectInfo i {n, 0}; // it's a chain -- 0 is out
auto& [chain, chain_copy] = *std::any_cast<PlugboardNodes::ChainExtra>(&n->extra);
Plugboard::ConnectInfo i {n, 0}; // it's a chain -- 0 is out
auto& [chain, chain_copy] = std::get<Plugboard::Chain>(*n).extra;
if (started_dragging)
chain_copy = chain;
@ -1313,7 +1328,7 @@ namespace K::UI {
kf_drag_btn_handler(key_loop_target, dragging, chain, frame, is_sel,
sel_it, segment, v, ii, started_dragging, k_pos);
if (segment.interp == PlugboardNodes::K_I_CubicBezier && ii + 1 < key_loop_target->segments.size()) {
if (segment.interp == Plugboard::K_I_CubicBezier && ii + 1 < key_loop_target->segments.size()) {
const auto& [k_nxt, val_nxt, _] = (key_loop_target->segments)[ii + 1];
i32 frame_nxt = k_nxt;
f64 v_nxt = val_nxt;
@ -1377,10 +1392,10 @@ namespace K::UI {
CompState ss = i.s;
ss.current_frame = static_cast<u64>(x);
bool 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))};
Vector<Plugboard::ConnectInfo> info;
return {x, std::get<Plugboard::T_Map<Plugboard::T_Float>::type>(
Plugboard::ConvertValue(Plugboard::Eval(ss, i.connected_v),
Plugboard::T_Float, good))};
}, &info, info.samples);
}
ImPlot::EndPlot();
@ -1432,7 +1447,9 @@ namespace K::UI {
window->DrawList->AddRectFilled(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos, 0x55AA5555);
window->DrawList->AddRect(io.MouseClickedPos[ImGuiMouseButton_Left], io.MousePos, 0xAAAA7777);
}
if (window->Rect().Contains(io.MousePos) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && mouse_tl_x >= 0 && mouse_tl_x < view_width && io.MouseWheel != 0.0f) {
if (window->Rect().Contains(io.MousePos) && mouse_tl_x >= 0 && mouse_tl_x < view_width) {
if (io.MouseWheel != 0.0f) {
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) {
f32 center = mouse_tl_x / view_width * view_amt + view_left;
f32 new_view_amt = std::clamp(view_amt - 0.05f * io.MouseWheel, 0.05f, 1.0f);
view_left = center - new_view_amt / 2.0f - (mouse_tl_x / view_width - .5f) * new_view_amt;
@ -1446,6 +1463,16 @@ namespace K::UI {
view_right = 1.0f;
}
}
if (show_curve_editor) {
if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) {
}
else {
}
}
}
}
}
ImGui::EndChild();
@ -1470,7 +1497,7 @@ namespace K::UI {
static i32 type_current = 0;
static String name{};
if (ImGui::Button("Add Uniform") && !name.empty() && !isdigit(name[0]) && !(name[0] == 'f' && name.length() == 1)) {
s.layers[s.active].track.AddUniform(name, ShaderGraph::expand_type(
s.layers[s.active].track.AddUniform(name, ExpandVariant(
static_cast<ShaderGraph::Type>(type_current)));
VisualTrack::ExposeUniform(s, s.layers[s.active].track.uniforms.back());
}
@ -1502,13 +1529,15 @@ namespace K::UI {
ImGui::TextUnformatted(ShaderGraph::Type_To_Str[it->val.index()]);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-FLT_MIN);
std::visit([&it](auto&& n) {
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::Type::T_Count>::type>)
if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::Type::T_Count>::type>)
DrawPlugboardVariableEditWidget(arg);
else
ImGui::Text("Plugged into %s!", arg.p->node->name.c_str());
}, it->connection.p->inputs_fed[it->connection.index]);
ImGui::Text("Plugged into %s!", std::visit([](auto&& d) { return d.name; }, *arg.p));
}, n.in[it->connection.index].value);
}, *it->connection.p);
ImGui::TableNextColumn();
if (ImGui::Button("X")) {
bgfx::destroy(it->handle);
@ -1570,7 +1599,7 @@ namespace K::UI {
if (ImGui::Begin("Interpolation", &draw_interpolation, ImGuiWindowFlags_NoScrollbar)) {
ImGuiIO& io = ImGui::GetIO();
static PlugboardNodes::K_Interpolation type_current = PlugboardNodes::K_I_CubicBezier;
static Plugboard::K_Interpolation type_current = Plugboard::K_I_CubicBezier;
static const ImVec2 p1 { 0.0f, 0.0f}, p4 {1.0f, 1.0f};
static ImVec2 p2{1.0f, 0.0f}, p3{0.0f, 1.0f}, p2_old = p2, p3_old = p3;
@ -1578,8 +1607,8 @@ namespace K::UI {
if (ImGui::Button("Apply"))
for (auto& layer : s.layers)
for (auto& u : layer.track.uniforms)
for (auto& n : u.show_nodes) {
auto& [chain, _] = *std::any_cast<PlugboardNodes::ChainExtra>(&n.p->extra);
for (auto& n : std::get<Plugboard::CompositionOut>(*u.connection.p).show_nodes[u.connection.index]) {
auto& [chain, _] = std::get<Plugboard::Chain>(*n.p).extra;
for (auto it = chain.segments.begin(); it != chain.segments.end(); it++) {
auto nit = std::next(it);
if (nit != chain.segments.end() && std::find(chain.selected.begin(), chain.selected.end(), std::distance(chain.segments.begin(), it)) != chain.selected.end() &&
@ -1591,10 +1620,10 @@ namespace K::UI {
ImGui::SameLine();
ImGui::Combo("##Type", (i32*)&type_current, PlugboardNodes::K_Interpolation_Names, PlugboardNodes::K_I_Count);
ImGui::Combo("##Type", (i32*)&type_current, Plugboard::K_Interpolation_Names, Plugboard::K_I_Count);
f32 w_window = std::min(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y);
if (type_current == PlugboardNodes::K_I_CubicBezier) {
if (type_current == Plugboard::K_I_CubicBezier) {
f32 y_max = std::max(std::max(p2.y, p3.y), p4.y),
y_min = std::min(std::min(p1.y, p2.y), p3.y),
y_range = y_max - y_min;
@ -1666,7 +1695,7 @@ namespace K::UI {
ImPlot::SetupFinish();
constexpr static u32 samples = 100;
if (type_current == PlugboardNodes::K_I_CubicBezier) {
if (type_current == Plugboard::K_I_CubicBezier) {
f64 p2x = p2.x, p2y = p2.y, p3x = p3.x, p3y= p3.y;
if (ImPlot::DragPoint(0, &p2x, &p2y, {1.0f, 1.0f, 1.0f, 1.0f})) {
p2.x = static_cast<f32>(std::clamp(p2x, 0.0, 1.0));
@ -1680,7 +1709,7 @@ namespace K::UI {
ImPlot::PlotLineG("v", [](i32 idx, void* user_data) {
f32 t = static_cast<f32>(idx) / static_cast<f32>(samples);
return ImPlotPoint{t, PlugboardNodes::EvalInterpolation(t, {.interp = type_current, .v = {p2.x,p2.y, p3.x, p3.y}})};
return ImPlotPoint{t, Plugboard::EvalInterpolation(t, {.interp = type_current, .v = {p2.x,p2.y, p3.x, p3.y}})};
}, nullptr, samples);
ImPlot::EndPlot();

View file

@ -2,36 +2,36 @@
#include "Keishiki.h"
namespace K {
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type ShaderValToPlugboard(const ShaderGraph::T_Map<ShaderGraph::T_Count>::type& val) {
return std::visit([](auto&& arg) -> PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type {
Plugboard::T_Map<Plugboard::T_Count>::type ShaderValToPlugboard(const ShaderGraph::T_Map<ShaderGraph::T_Count>::type& val) {
return std::visit([](auto&& arg) -> Plugboard::T_Map<Plugboard::T_Count>::type {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_Float>::type>)
return PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type(arg);
return Plugboard::T_Map<Plugboard::T_Float>::type(arg);
else if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_Int>::type>)
return PlugboardGraph::T_Map<PlugboardGraph::T_Int>::type(arg);
return Plugboard::T_Map<Plugboard::T_Int>::type(arg);
else if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_RGBA>::type>)
return PlugboardGraph::T_Map<PlugboardGraph::T_RGBA>::type{arg.r, arg.g, arg.b, arg.a};
return Plugboard::T_Map<Plugboard::T_RGBA>::type{arg.r, arg.g, arg.b, arg.a};
else if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_XY>::type>)
return PlugboardGraph::T_Map<PlugboardGraph::T_XY>::type{arg.x, arg.y};
return Plugboard::T_Map<Plugboard::T_XY>::type{arg.x, arg.y};
else if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_XYZ>::type>)
return PlugboardGraph::T_Map<PlugboardGraph::T_XYZ>::type{arg.x, arg.y, arg.z};
return Plugboard::T_Map<Plugboard::T_XYZ>::type{arg.x, arg.y, arg.z};
},val);
}
ShaderGraph::T_Map<ShaderGraph::T_Count>::type PlugboardValToShader(const PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type& val) {
ShaderGraph::T_Map<ShaderGraph::T_Count>::type PlugboardValToShader(const Plugboard::T_Map<Plugboard::T_Count>::type& val) {
return std::visit([](auto&& arg) -> ShaderGraph::T_Map<ShaderGraph::T_Count>::type {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Float>::type>)
if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Float>::type>)
return ShaderGraph::T_Map<ShaderGraph::T_Float>::type(arg);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Int>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Int>::type>)
return ShaderGraph::T_Map<ShaderGraph::T_Int>::type(arg);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_RGBA>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_RGBA>::type>)
return ShaderGraph::T_Map<ShaderGraph::T_RGBA>::type{arg.r, arg.g, arg.b, arg.a};
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_XY>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XY>::type>)
return ShaderGraph::T_Map<ShaderGraph::T_XY>::type{arg.x, arg.y};
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_XYZ>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_XYZ>::type>)
return ShaderGraph::T_Map<ShaderGraph::T_XYZ>::type{arg.x, arg.y, arg.z};
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_String>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_String>::type>)
return ShaderGraph::T_Map<ShaderGraph::T_Count>::type{};
},val);
}
@ -53,16 +53,15 @@ namespace K {
else {
std::visit([&u, &s, &val_target](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>) {
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) {
bool good;
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 !!
val_target = PlugboardValToShader(Plugboard::ConvertValue(Plugboard::Eval(s, arg),
static_cast<Plugboard::Type>(u.val.index()), // todo DANGEROUS !!
good));
}
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type>)
else if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::T_Count>::type>)
val_target = PlugboardValToShader(arg);
}, u.connection.p->inputs_fed[u.connection.index]);
}, std::visit([&u](auto&& arg) { return arg.in[u.connection.index].value; }, *u.connection.p));
}
std::visit([&pack](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
@ -183,16 +182,18 @@ namespace K {
}
void VisualTrack::ExposeUniform(CompState& s, Uniform& uu) {
uu.connection = {&s.plugboard.out_instance, static_cast<u32>(s.plugboard.out_instance.node->in.size())};
s.plugboard.out_instance.node->in.push_back({ uu.name, PlugboardGraph::Type(uu.val.index())}); // this is shaky and bug prone -- relies on the shader types being in line with plugboard types
s.plugboard.out_instance.inputs_fed.emplace_back(ShaderValToPlugboard(uu.val));
auto& n = std::get<Plugboard::CompositionOut>(s.plugboard.out);
uu.connection = {&s.plugboard.out, static_cast<u32>(n.in.size())};
// this is shaky and bug prone -- relies on the shader types being in line with plugboard types
n.in.push_back(Plugboard::InSocket{ uu.name, Plugboard::Type(uu.val.index()), ShaderValToPlugboard(uu.val)});
n.show_nodes.push_back({});
}
void VisualTrack::ExposeUniform(CompState& s, u32 i) {
ExposeUniform(s, uniforms[i]);
}
void VisualTrack::HideUniform(CompState& s, Uniform& uu) {
/* void VisualTrack::HideUniform(CompState& s, Uniform& uu) {
uu.connection.p->disconnect(uu.connection.index);
for (auto& l : s.layers)
@ -202,7 +203,7 @@ namespace K {
s.plugboard.comp_out.in.erase(s.plugboard.out_instance.node->in.begin() + uu.connection.index);
s.plugboard.out_instance.inputs_fed.erase(s.plugboard.out_instance.inputs_fed.begin() + uu.connection.index);
uu.connection = {nullptr, 0};
}
}*/
void VisualTrack::AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val) {
for (auto& u : uniforms)

View file

@ -23,7 +23,7 @@ namespace K {
using Byte = u8;
using Char = char;
template <typename T> using Vector = std::vector<T>;
template <typename T, typename U> using Dict = std::unordered_map<T, U>;
template <typename... Ts> using Dict = std::unordered_map<Ts...>;
inline void LogBase(const std::string_view& s, u8 level) {
static const char *levels[] = {

View file

@ -1,6 +1,6 @@
#pragma once
#include "Common.h"
#include "PlugboardGraph.h"
#include "Plugboard.h"
#include "VisualTrack.h"
#include <atomic>
@ -31,7 +31,7 @@ namespace K {
Vector<u32> selected; // indices for layers
Vector<u32> disabled; // indices for layers
PlugboardGraph::PlugboardGraph plugboard;
Plugboard::Plugboard plugboard;
};
extern struct AppState {

View file

@ -0,0 +1,605 @@
#pragma once
#include "Common.h"
#include "Graphics.h"
#include <functional>
#include <imgui.h>
#include <list>
#include <any>
#include <bx/easing.h>
#include <utility>
#include <variant>
namespace K::Plugboard {
enum Type {
T_Float,
T_Int,
T_RGBA,
T_XY,
T_XYZ,
T_String,
T_Count
};
static const char *Type_To_Str[] = {
"Float",
"Int",
"RGBA",
"XY",
"XYZ",
"String",
"Error"
};
struct RGBA { f32 r, g, b, a; };
struct XYZ { f32 x, y, z; };
struct XY { f32 x, y; };
template<Type> struct T_Map;
template<> struct T_Map<T_Float> {
using type = f32;
};
template<> struct T_Map<T_Int> {
using type = i32;
};
template<> struct T_Map<T_RGBA> {
using type = RGBA;
};
template<> struct T_Map<T_XY> {
using type = XY;
};
template<> struct T_Map<T_XYZ> {
using type = XYZ;
};
template<> struct T_Map<T_String> {
using type = String;
};
template<> struct T_Map<T_Count> {
using type = std::variant<f32, i32, RGBA, XY, XYZ, String>;
};
constexpr String VarToString(const T_Map<T_Count>::type& var);
T_Map<T_Count>::type ExpandVariant(u32 i);
struct Add;
struct Negate;
struct Subtract;
struct Multiply;
struct Divide;
struct Sign;
struct Sin;
struct Cos;
struct Tan;
struct Arcsin;
struct Arccos;
struct Arctan;
struct Atan2;
struct Minimum;
struct Maximum;
struct Power;
struct SquareRoot;
struct NaturalLogarithm;
struct AbsoluteValue;
struct Interpolation;
struct Chain;
struct CompositionIn;
struct CompositionOut;
using NodeInstance = std::variant<
Add,
Negate,
Subtract,
Multiply,
Divide,
Sign,
Sin,
Cos,
Tan,
Arcsin,
Arccos,
Arctan,
Atan2,
Minimum,
Maximum,
Power,
SquareRoot,
NaturalLogarithm,
AbsoluteValue,
Interpolation,
Chain,
CompositionIn,
CompositionOut
>;
enum K_P_Nodes {
K_P_Add = 0,
K_P_Negate,
K_P_Subtract,
K_P_Multiply,
K_P_Divide,
K_P_Sign,
K_P_Sin,
K_P_Cos,
K_P_Tan,
K_P_Arcsin,
K_P_Arccos,
K_P_Arctan,
K_P_Atan2,
K_P_Minimum,
K_P_Maximum,
K_P_Power,
K_P_SquareRoot,
K_P_NaturalLogarithm,
K_P_AbsoluteValue,
K_P_Interpolation,
K_P_Chain,
K_P_CompositionIn,
K_P_CompositionOut,
K_P_Count
};
NodeInstance MakeInstance(K_P_Nodes i);
enum K_Interpolation {
K_I_CubicBezier,
K_I_InConstant,
K_I_OutConstant,
K_I_Linear,
K_I_Step,
K_I_SmoothStep,
K_I_InQuadratic,
K_I_OutQuadratic,
K_I_InOutQuadratic,
K_I_OutInQuadratic,
K_I_InCubic,
K_I_OutCubic,
K_I_InOutCubic,
K_I_OutInCubic,
K_I_InQuartic,
K_I_OutQuartic,
K_I_InOutQuartic,
K_I_OutInQuartic,
K_I_InQuintic,
K_I_OutQuintic,
K_I_InOutQuintic,
K_I_OutInQuintic,
K_I_InSine,
K_I_OutSine,
K_I_InOutSine,
K_I_OutInSine,
K_I_InExponential,
K_I_OutExponential,
K_I_InOutExponential,
K_I_OutInExponential,
K_I_InCircular,
K_I_OutCircular,
K_I_InOutCircular,
K_I_OutInCircular,
K_I_InElastic,
K_I_OutElastic,
K_I_InOutElastic,
K_I_OutInElastic,
K_I_InBack,
K_I_OutBack,
K_I_InOutBack,
K_I_OutInBack,
K_I_InBounce,
K_I_OutBounce,
K_I_InOutBounce,
K_I_OutInBounce,
K_I_Count
};
extern const char *K_Interpolation_Names[];
struct InterpolationExtra {
K_Interpolation interp;
f32 v[4]; // currently used only for bezier tangent points -- between [0,1]^2 fitted to segment
};
constexpr 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));
}
case K_I_Count:
std::unreachable();
}
std::unreachable();
}
struct ChainSegment {
i32 frame;
f32 value;
InterpolationExtra interp;
};
struct ChainSel {
Vector<ChainSegment> segments;
Vector<u32> selected; // indices
};
struct ChainExtra {
ChainSel chain,
temp; // for UI -- does not represent any state
};
struct ConnectInfo {
NodeInstance *p; // NOTE: so NodeInstances must be stored in a list, otherwise vector realloc leads to UAF
u32 index;
auto operator<=>(const ConnectInfo&) const = default; // too-modern c++ black magic ?
};
struct InSocket {
String name;
Type type;
std::variant<T_Map<Type::T_Count>::type, ConnectInfo> value;
};
struct OutSocket {
String name;
Type type;
Vector<ConnectInfo> outgoing;
};
template <typename F>
requires requires(F func, ConnectInfo p) {
{ func(p) } -> std::same_as<bool>; // abort condition -- continue if true
}
bool DFS(const NodeInstance& n, F&& f) { // returns false if aborted
return std::visit([&f](auto&& node) {
for (const auto& socket : node.in)
if (!std::visit([&f](auto&& info) {
if constexpr (std::is_same_v<std::decay_t<decltype(info)>, ConnectInfo>) {
if (f(info))
return DFS(*info.p, f);
else
return false;
}
else return true;
}, socket.value))
return false;
return true;
}, n);
}
void CollectChains(ConnectInfo& in, Vector<ConnectInfo>& chains);
template <typename T>
concept Node = requires(T node) {
{ T::name } -> std::same_as<const char* const&>;
{ node.in.size() } -> std::convertible_to<std::size_t>;
{ node.out.size() } -> std::convertible_to<std::size_t>;
{ node.fetch.size() } -> std::convertible_to<std::size_t>; // in the future enforce same_as<tuple_size<fetch>, tuple_size<out>> if both are static arrays
{ node.pos } -> std::convertible_to<ImVec2&>;
};
struct ConnectInfoHasher {
std::size_t operator()(const ConnectInfo& k) const
{
return std::hash<NodeInstance *>()(k.p) ^ std::hash<u32>()(k.index);
}
};
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);
struct LinksFromSource {
ImVec2 source;
Vector<ImVec2> sinks;
};
T_Map<T_Count>::type FetchAdd(const CompState& s, const Add& n);
struct Add {
const static char constexpr *name = static_cast<const char*>("Add");
std::array<InSocket, 2> in = { InSocket{"a", T_Float }, InSocket{"b", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "a+b", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Add&), 1> fetch = { FetchAdd };
ImVec2 pos;
};
T_Map<T_Count>::type FetchNegate(const CompState& s, const Negate& n);
struct Negate {
const static char constexpr *name = static_cast<const char*>("Add");
std::array<InSocket, 2> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "-a", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Negate&), 1> fetch = { FetchNegate };
ImVec2 pos;
};
T_Map<T_Count>::type FetchSubtract(const CompState& s, const Subtract& n);
struct Subtract {
const static char constexpr *name = static_cast<const char*>("Subtract");
std::array<InSocket, 2> in = { InSocket{"a", T_Float }, InSocket{"b", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "a-b", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Subtract&), 1>fetch = { FetchSubtract };
ImVec2 pos;
};
T_Map<T_Count>::type FetchMultiply(const CompState& s, const Multiply& n);
struct Multiply {
const static char constexpr *name = static_cast<const char*>("Multiply");
std::array<InSocket, 2> in = { InSocket{"a", T_Float }, InSocket{"b", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "a*b", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Multiply&), 1> fetch = { FetchMultiply };
ImVec2 pos;
};
T_Map<T_Count>::type FetchDivide(const CompState& s, const Divide& n);
struct Divide {
const static char constexpr *name = static_cast<const char*>("Divide");
std::array<InSocket, 2> in = { InSocket{"a", T_Float }, InSocket{"b", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "a/b", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Divide&), 1> fetch = { FetchDivide };
ImVec2 pos;
};
T_Map<T_Count>::type FetchSign(const CompState& s, const Sign& n);
struct Sign {
const static char constexpr *name = static_cast<const char*>("Sign");
std::array<InSocket, 1> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "sgn(a)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Sign&), 1> fetch = { FetchSign };
ImVec2 pos;
};
T_Map<T_Count>::type FetchSin(const CompState& s, const Sin& n);
struct Sin {
const static char constexpr *name = static_cast<const char*>("Sin");
std::array<InSocket, 1> in = { InSocket{"a (rad)", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "sin(a)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Sin&), 1> fetch = { FetchSin };
ImVec2 pos;
};
T_Map<T_Count>::type FetchCos(const CompState& s, const Cos& n);
struct Cos {
const static char constexpr *name = static_cast<const char*>("Cos");
std::array<InSocket, 1> in = { InSocket{"a (rad)", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "cos(a)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Cos&), 1> fetch = { FetchCos };
ImVec2 pos;
};
T_Map<T_Count>::type FetchTan(const CompState& s, const Tan& n);
struct Tan {
const static char constexpr *name = static_cast<const char*>("Tan");
std::array<InSocket, 1> in = { InSocket{"a (rad)", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "tan(a)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Tan&), 1> fetch = { FetchTan };
ImVec2 pos;
};
T_Map<T_Count>::type FetchArcsin(const CompState& s, const Arcsin& n);
struct Arcsin {
const static char constexpr *name = static_cast<const char*>("Arcsin");
std::array<InSocket, 1> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "arcsin(a) (rad)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Arcsin&), 1> fetch = { FetchArcsin };
ImVec2 pos;
};
T_Map<T_Count>::type FetchArccos(const CompState& s, const Arccos& n);
struct Arccos {
const static char constexpr *name = static_cast<const char*>("Arccos");
std::array<InSocket, 1> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "arccos(a) (rad)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Arccos&), 1> fetch = { FetchArccos };
ImVec2 pos;
};
T_Map<T_Count>::type FetchArctan(const CompState& s, const Arctan& n);
struct Arctan {
const static char constexpr *name = static_cast<const char*>("Arctan");
std::array<InSocket, 1> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "arctan(a) (rad)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Arctan&), 1> fetch = { FetchArctan };
ImVec2 pos;
};
T_Map<T_Count>::type FetchAtan2(const CompState& s, const Atan2& n);
struct Atan2 {
const static char constexpr *name = static_cast<const char*>("Atan2");
std::array<InSocket, 2> in = { InSocket{"y", T_Float }, InSocket{"x", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "atan2(y, x) (rad)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Atan2&), 1> fetch = { FetchAtan2 };
ImVec2 pos;
};
T_Map<T_Count>::type FetchMinimum(const CompState& s, const Minimum& n);
struct Minimum {
const static char constexpr *name = static_cast<const char*>("Minimum");
std::array<InSocket, 2> in = { InSocket{"a", T_Float }, InSocket{"b", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "min(a, b)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Minimum&), 1> fetch = { FetchMinimum };
ImVec2 pos;
};
T_Map<T_Count>::type FetchMaximum(const CompState& s, const Maximum& n);
struct Maximum {
const static char constexpr *name = static_cast<const char*>("Maximum");
std::array<InSocket, 2> in = { InSocket{"a", T_Float }, InSocket{"b", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "max(a, b)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Maximum&), 1> fetch = { FetchMaximum };
ImVec2 pos;
};
T_Map<T_Count>::type FetchPower(const CompState& s, const Power& n);
struct Power {
const static char constexpr *name = static_cast<const char*>("Power");
std::array<InSocket, 2> in = { InSocket{"a", T_Float }, InSocket{"b", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "a^b", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Power&), 1> fetch = { FetchPower };
ImVec2 pos;
};
T_Map<T_Count>::type FetchSquareRoot(const CompState& s, const SquareRoot& n);
struct SquareRoot {
const static char constexpr *name = static_cast<const char*>("Square Root");
std::array<InSocket, 1> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "sqrt(a)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const SquareRoot&), 1> fetch = { FetchSquareRoot };
ImVec2 pos;
};
T_Map<T_Count>::type FetchNaturalLogarithm(const CompState& s, const NaturalLogarithm& n);
struct NaturalLogarithm {
const static char constexpr *name = static_cast<const char*>("Natural Logarithm");
std::array<InSocket, 1> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "log(a)", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const NaturalLogarithm&), 1> fetch = { FetchNaturalLogarithm };
ImVec2 pos;
};
T_Map<T_Count>::type FetchAbsoluteValue(const CompState& s, const AbsoluteValue& n);
struct AbsoluteValue {
const static char constexpr *name = static_cast<const char*>("Absolute Value");
std::array<InSocket, 1> in = { InSocket{"a", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "|a|", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const AbsoluteValue&), 1> fetch = { FetchAbsoluteValue };
ImVec2 pos;
};
T_Map<T_Count>::type FetchInterpolation(const CompState& s, const Interpolation& n);
struct Interpolation {
const static char constexpr *name = static_cast<const char*>("Interpolation");
std::array<InSocket, 1> in = { InSocket{"t", T_Float } };
std::array<OutSocket, 1> out = { OutSocket{ "Value", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Interpolation&), 1> fetch = { FetchInterpolation };
ImVec2 pos;
InterpolationExtra extra{};
void Draw();
};
T_Map<T_Count>::type FetchChain(const CompState& s, const Chain& n);
struct Chain {
const static char constexpr *name = static_cast<const char*>("Chain");
std::array<InSocket, 1> in = { InSocket{"In", T_Int } };
std::array<OutSocket, 1> out = { OutSocket{ "Out", T_Float } };
std::array<T_Map<T_Count>::type (*)(const CompState&, const Chain&), 1> fetch = { FetchChain };
ImVec2 pos;
ChainExtra extra{};
};
T_Map<T_Count>::type FetchCompositionInFrame(const CompState& s, const CompositionIn& n);
T_Map<T_Count>::type FetchCompositionInTime(const CompState& s, const CompositionIn& n);
T_Map<T_Count>::type FetchCompositionInAppTicks(const CompState& s, const CompositionIn& n);
struct CompositionIn {
const static char constexpr *name = static_cast<const char*>("Composition In");
std::array<InSocket, 0> in = {};
std::array<OutSocket, 3> out = { OutSocket{"Frame", T_Int}, OutSocket{"Time (s)", T_Float}, OutSocket{"App Ticks", T_Float} };
std::array<T_Map<T_Count>::type (*)(const CompState&, const CompositionIn&), 3> fetch = { FetchCompositionInFrame, FetchCompositionInTime, FetchCompositionInAppTicks };
ImVec2 pos;
};
struct CompositionOut {
const static char constexpr *name = static_cast<const char*>("Composition Out");
Vector<InSocket> in = {};
Vector<Vector<ConnectInfo>> show_nodes;
std::array<OutSocket, 0> out = {};
std::array<T_Map<T_Count>::type (*)(const CompState&, const CompositionOut&), 0> fetch = {};
ImVec2 pos;
};
struct Plugboard {
std::list<NodeInstance> nodes; // OK complexity wise since we would usually traverse the entire thing anyway, locality will likely be bad
Dict<ConnectInfo, LinksFromSource, ConnectInfoHasher> links_pos; // this is hilariously bad
NodeInstance in, out;
void RecollectChains();
};
void Connect(NodeInstance& from_instance, u8 input_index, NodeInstance& to_instance, u8 to_out_index);
void Disconnect(NodeInstance& from_instance, u8 input_index);
}

View file

@ -1,123 +0,0 @@
#pragma once
#include "Common.h"
#include "Graphics.h"
#include <variant>
#include <functional>
#include <imgui.h>
#include <list>
#include <any>
namespace K::PlugboardGraph {
enum Type {
T_Float,
T_Int,
T_RGBA,
T_XY,
T_XYZ,
T_String,
T_Count
};
static const char *Type_To_Str[] = {
"Float",
"Int",
"RGBA",
"XY",
"XYZ",
"String",
"Error"
};
struct RGBA { f32 r, g, b, a; };
struct XYZ { f32 x, y, z; };
struct XY { f32 x, y; };
template<Type> struct T_Map;
template<> struct T_Map<T_Float> {
using type = f32;
};
template<> struct T_Map<T_Int> {
using type = i32;
};
template<> struct T_Map<T_RGBA> {
using type = RGBA;
};
template<> struct T_Map<T_XY> {
using type = XY;
};
template<> struct T_Map<T_XYZ> {
using type = XYZ;
};
template<> struct T_Map<T_String> {
using type = String;
};
template<> struct T_Map<T_Count> {
using type = std::variant<f32, i32, RGBA, XY, XYZ, String>;
};
constexpr String VarToString(const T_Map<T_Count>::type& var);
T_Map<T_Count>::type expand_type(Type i);
struct Socket {
String name;
Type type;
};
struct NodeInstance;
struct ConnectInfo {
NodeInstance *p; // NOTE: so NodeInstances must be stored in a list, otherwise vector realloc leads to UAF
u32 index;
auto operator<=>(const ConnectInfo&) const = default; // 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
{
return std::hash<NodeInstance *>()(k.p) ^ std::hash<u32>()(k.index);
}
};
struct NodeInstance {
Node *node; // should be safe if we require those to be static, UAF might pop up later
Vector<std::variant<T_Map<Type::T_Count>::type, ConnectInfo>> inputs_fed;
Vector<Vector<ConnectInfo>> outputs_going;
ImVec2 pos, old_pos;
std::any extra;
void connect(u32 input_index, NodeInstance *to, u32 to_out_index);
void disconnect(u32 input_index);
};
NodeInstance MakeInstance(Node& n);
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, Vector<ConnectInfo> *show_nodes = nullptr);
struct LinksFromSource {
ImVec2 source;
Vector<ImVec2> sinks;
};
struct PlugboardGraph {
std::list<NodeInstance> nodes; // OK complexity wise since we would usually traverse the entire thing anyway, locality will likely be bad
std::unordered_map<ConnectInfo, LinksFromSource, ConnectInfoHasher> links_pos; // this is hilariously bad
Node comp_in, comp_out;
NodeInstance in_instance, out_instance;
};
}

View file

@ -1,229 +0,0 @@
#pragma once
#include "Common.h"
#include "PlugboardGraph.h"
#include <map>
#include <numbers>
#include <array>
#include <bx/easing.h>
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, 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([&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, show_nodes);
else
return arg;
}, n.inputs_fed[index]), type, good));
if (!good)
K::LogError("Type mismatch on plugboard evaluation!");
return v;
}
}
namespace K::PlugboardNodes {
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,
K_I_InConstant,
K_I_OutConstant,
K_I_Linear,
K_I_Step,
K_I_SmoothStep,
K_I_InQuadratic,
K_I_OutQuadratic,
K_I_InOutQuadratic,
K_I_OutInQuadratic,
K_I_InCubic,
K_I_OutCubic,
K_I_InOutCubic,
K_I_OutInCubic,
K_I_InQuartic,
K_I_OutQuartic,
K_I_InOutQuartic,
K_I_OutInQuartic,
K_I_InQuintic,
K_I_OutQuintic,
K_I_InOutQuintic,
K_I_OutInQuintic,
K_I_InSine,
K_I_OutSine,
K_I_InOutSine,
K_I_OutInSine,
K_I_InExponential,
K_I_OutExponential,
K_I_InOutExponential,
K_I_OutInExponential,
K_I_InCircular,
K_I_OutCircular,
K_I_InOutCircular,
K_I_OutInCircular,
K_I_InElastic,
K_I_OutElastic,
K_I_InOutElastic,
K_I_OutInElastic,
K_I_InBack,
K_I_OutBack,
K_I_InOutBack,
K_I_OutInBack,
K_I_InBounce,
K_I_OutBounce,
K_I_InOutBounce,
K_I_OutInBounce,
K_I_Count
};
extern const char *K_Interpolation_Names[];
struct InterpolationExtra {
K_Interpolation interp;
f32 v[4]; // currently used only for bezier tangent points -- between [0,1]^2 fitted to segment
};
constexpr 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 {};
}
}
extern PlugboardGraph::Node Interpolation;
struct ChainSegment {
i32 frame;
f32 value;
InterpolationExtra interp;
};
struct ChainSel {
Vector<ChainSegment> segments;
Vector<u32> selected; // indices
};
struct ChainExtra {
ChainSel chain,
temp; // for UI -- does not represent any state
};
extern PlugboardGraph::Node Chain;
extern std::array<PlugboardGraph::Node*, 20> Nodes;
}

View file

@ -3,7 +3,6 @@
#include <bgfx/bgfx.h>
#include <filesystem>
#include <shared_mutex>
#include <variant>
namespace K::Resource {
extern std::filesystem::path ffmpeg_path;
@ -33,7 +32,7 @@ namespace K::Resource {
std::filesystem::path filename;
std::filesystem::file_time_type last_updated;
bgfx::TextureHandle tex;
u8 *buf;
Byte *buf;
i32 h, w, channels;
bgfx::TextureFormat::Enum format;
};

View file

@ -1,7 +1,6 @@
#pragma once
#include "Common.h"
#include "Graphics.h"
#include <variant>
// todo a lot of problems in this unit can lead to very bad performance
namespace K::ShaderGraph {
@ -46,7 +45,7 @@ namespace K::ShaderGraph {
};
String VarToString(const T_Map<T_Count>::type& var);
T_Map<T_Count>::type expand_type(Type i);
T_Map<T_Count>::type ExpandVariant(u32 i);
struct Node;
struct InSlot {
@ -73,6 +72,6 @@ namespace K::ShaderGraph {
Vector<NodeInstance> nodes;
NodeInstance *RGBA_node;
u16 RGBA_node_out_index;
String generate_shader() const;
[[nodiscard]] String GenerateShader() const;
};
}

View file

@ -5,15 +5,14 @@
#include <functional>
#include <bx/math.h>
#include <fstream>
#include "PlugboardGraph.h"
#include "Plugboard.h"
namespace K {
struct Uniform {
String name;
bgfx::UniformHandle handle;
ShaderGraph::T_Map<ShaderGraph::T_Count>::type val;
PlugboardGraph::ConnectInfo connection;
Vector<PlugboardGraph::ConnectInfo> show_nodes;
Plugboard::ConnectInfo connection;
};
struct Sampler {
@ -22,9 +21,9 @@ namespace K {
Resource::Resource<Resource::K_R_Still> *resource;
};
ShaderGraph::T_Map<ShaderGraph::T_Count>::type PlugboardValToShader(const PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type& val);
ShaderGraph::T_Map<ShaderGraph::T_Count>::type PlugboardValToShader(const Plugboard::T_Map<Plugboard::T_Count>::type& val);
PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type ShaderValToPlugboard(const ShaderGraph::T_Map<ShaderGraph::T_Count>::type& val);
Plugboard::T_Map<Plugboard::T_Count>::type ShaderValToPlugboard(const ShaderGraph::T_Map<ShaderGraph::T_Count>::type& val);
struct VisualTrack {
ShaderGraph::ShaderGraph tree;
@ -36,7 +35,7 @@ namespace K {
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);
// static void HideUniform(CompState& s, Uniform& uu);
void AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val);
void AddSampler(const String& s);