static dispatch
This commit is contained in:
parent
faaa0f8e6f
commit
dec9cb0497
16 changed files with 1221 additions and 1116 deletions
|
@ -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
414
Keishiki/Plugboard.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
};
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
281
Keishiki/UI.cpp
281
Keishiki/UI.cpp
|
@ -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,23 +428,25 @@ 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++) {
|
||||
const bool is_selected = (node_current == n);
|
||||
if (ImGui::Selectable(PlugboardNodes::Nodes[n]->name.c_str(), is_selected))
|
||||
node_current = 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(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)
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
|
||||
if (is_selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
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))
|
||||
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,18 +1447,30 @@ 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) {
|
||||
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;
|
||||
view_right = center + new_view_amt / 2.0f - (mouse_tl_x / view_width - .5f) * new_view_amt;
|
||||
if (view_left < 0.0f) {
|
||||
view_right -= view_left;
|
||||
view_left = 0.0f;
|
||||
}
|
||||
else if (view_right > 1.0f) {
|
||||
view_left -= (view_right - 1.0f);
|
||||
view_right = 1.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;
|
||||
view_right = center + new_view_amt / 2.0f - (mouse_tl_x / view_width - .5f) * new_view_amt;
|
||||
if (view_left < 0.0f) {
|
||||
view_right -= view_left;
|
||||
view_left = 0.0f;
|
||||
}
|
||||
else if (view_right > 1.0f) {
|
||||
view_left -= (view_right - 1.0f);
|
||||
view_right = 1.0f;
|
||||
}
|
||||
}
|
||||
if (show_curve_editor) {
|
||||
if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) {
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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([](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::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]);
|
||||
std::visit([&it](auto&& n) {
|
||||
std::visit([](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Plugboard::T_Map<Plugboard::Type::T_Count>::type>)
|
||||
DrawPlugboardVariableEditWidget(arg);
|
||||
else
|
||||
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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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 {
|
||||
|
|
605
Keishiki/include/Plugboard.h
Normal file
605
Keishiki/include/Plugboard.h
Normal 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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue