plugboard init

This commit is contained in:
lachrymaLF 2024-05-27 12:06:15 -04:00
parent 0d713b6da6
commit 5f6adef565
13 changed files with 479 additions and 163 deletions

View file

@ -14,8 +14,8 @@
namespace {
SDL_Window *window;
u16 window_width = 1920;
u16 window_height = 1080;
u16 window_width = 2200;
u16 window_height = 1200;
u64 init_time, last_time, current_time, delta_t;
u32 frame;

View file

@ -0,0 +1,21 @@
#include <PlugboardGraph.h>
namespace K::PlugboardGraph {
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);
}
}

View file

@ -1,5 +1,4 @@
#include <ShaderGraph.h>
#include <format>
#include "srell.hpp"
namespace {

View file

@ -1,6 +1,8 @@
#include "UI.h"
#include "Graphics.h"
#include "VisualTrack.h"
#include "PlugboardNodes.h"
#include "ext/imgui/misc/cpp/imgui_stdlib.h"
#include <imgui.h>
#include <imgui_internal.h>
#include <misc/cpp/imgui_stdlib.h>
@ -85,7 +87,7 @@ namespace K::UI {
bg.pg = K::Graphics::load_shader_program("Checkerboard");
bg.add_uniform("f_hw", ShaderGraph::Type::T_XYZ);
bg.uniforms.begin()->second.second = ShaderGraph::XYZ{ static_cast<f32>(s.width), static_cast<f32>(s.height), 0.0f };
bg.uniforms.begin()->second.val = ShaderGraph::XYZ{ static_cast<f32>(s.width), static_cast<f32>(s.height), 0.0f };
bx::mtxOrtho(proj, 0.0f, static_cast<f32>(s.width), 0.0f, static_cast<f32>(s.height),
0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth);
@ -107,7 +109,7 @@ namespace K::UI {
std::free(save_buffer);
bgfx::destroy(bg.pg);
bgfx::destroy(bg.uniforms.begin()->second.first);
bgfx::destroy(bg.uniforms.begin()->second.handle);
bg.uniforms.erase(bg.uniforms.begin());
for (auto& layer : s.layers)
@ -116,7 +118,7 @@ namespace K::UI {
void Viewport(CompState& s) {
if (ImGui::Begin("Viewport", &draw_viewport)) {
ImTextureID idx = nullptr;
ImTextureID idx;
bg.get_frame(composite_fb, s.width, s.height, proj, view, transform);
bgfx::blit(Graphics::K_VIEW_COMP_COMPOSITE, composite_blit, 0, 0, composite);
@ -134,14 +136,13 @@ namespace K::UI {
ImGui::SameLine();
auto cp = save_called;
if (cp) ImGui::BeginDisabled();
ImGui::BeginDisabled(save_called);
if (ImGui::Button("Save to frame.png")) {
bgfx::blit(Graphics::K_VIEW_COMP_SAVE, save, 0, 0, composite);
ready_frame = bgfx::readTexture(save, save_buffer);
save_called = true;
}
if (cp) ImGui::EndDisabled();
ImGui::EndDisabled();
}
ImGui::End();
@ -164,21 +165,21 @@ namespace K::UI {
};
l.track.add_uniform("aspect_ratio", ShaderGraph::expand_type(ShaderGraph::T_XY));
if (s.width > s.height)
l.track.uniforms["aspect_ratio"].second = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(static_cast<f32>(s.width)/static_cast<f32>(s.height), 1.0f);
l.track.uniforms["aspect_ratio"].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(static_cast<f32>(s.width)/static_cast<f32>(s.height), 1.0f);
else
l.track.uniforms["aspect_ratio"].second = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(1.0f, static_cast<f32>(s.height)/static_cast<f32>(s.width));
l.track.uniforms["aspect_ratio"].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(1.0f, static_cast<f32>(s.height)/static_cast<f32>(s.width));
l.track.add_uniform("opacity", ShaderGraph::expand_type(ShaderGraph::T_Float));
l.track.uniforms["opacity"].second = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(1.0f);
l.track.uniforms["opacity"].val = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(1.0f);
l.track.add_uniform("rot", ShaderGraph::expand_type(ShaderGraph::T_Float));
l.track.uniforms["rot"].second = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(.0f);
l.track.uniforms["rot"].val = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(.0f);
l.track.add_uniform("scale", ShaderGraph::expand_type(ShaderGraph::T_XY));
l.track.uniforms["scale"].second = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(1.0f, 1.0f);
l.track.uniforms["scale"].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(1.0f, 1.0f);
l.track.add_uniform("translate", ShaderGraph::expand_type(ShaderGraph::T_XY));
l.track.uniforms["translate"].second = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(.0f, .0f);
l.track.uniforms["translate"].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type(.0f, .0f);
l.track.shader = "void main() {\n"
"\tfloat angle = -rot * M_PI / 180.0f;\n"
@ -266,7 +267,7 @@ namespace K::UI {
if (!no_selection) source_flags |= ImGuiDragDropFlags_SourceNoPreviewTooltip;
if ((no_selection || s.selected.contains(i)) && ImGui::BeginDragDropSource(source_flags)) {
if (s.selected.empty()) ImGui::Text("Swap with #%u %s", i, s.layers[i].name.c_str());
ImGui::SetDragDropPayload("DND_DEMO_NAME", &i, sizeof(u32));
ImGui::SetDragDropPayload("K_COMP_REORDER", &i, sizeof(u32));
ImGui::EndDragDropSource();
}
if ((no_selection || !s.selected.contains(i)) && ImGui::BeginDragDropTarget()) {
@ -278,7 +279,7 @@ namespace K::UI {
ImGui::SetTooltip("Before #%u %s", i, s.layers[i].name.c_str());
}
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("DND_DEMO_NAME")) {
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("K_COMP_REORDER")) {
move_from = *(const int*)payload->Data;
move_to = i;
}
@ -338,160 +339,197 @@ namespace K::UI {
ImGui::End();
}
void PlugboardNodeDrawSockets(PlugboardGraph::NodeInstance& n, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, std::unordered_map<PlugboardGraph::ConnectInfo, ImVec4, PlugboardGraph::_ConnectInfoHasher>& link_pos,
bool dummy = true) {
i32 row = 1;
for (u32 out = 0; out < n.node->out_names.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_names[out].c_str()).x - style.ItemSpacing.x, 0.0f});
ImGui::SameLine();
ImGui::Text("%s", n.node->out_names[out].c_str());
ImGui::TableNextColumn();
ImGui::RadioButton("##Out", false);
if (ImGui::IsItemActive()) {
dragging_on_socket = true;
source = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y};
}
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
PlugboardGraph::ConnectInfo d{ &n, 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);
}
ImGui::EndDragDropTarget();
}
ImGui::PopID();
// Update link info if needed
if (n.outputs_going[out].p != nullptr) {
auto pos = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y};
auto& d = link_pos[std::get<PlugboardGraph::ConnectInfo>(n.outputs_going[out].p->inputs_fed[n.outputs_going[out].index])];
d.w = pos.x;
d.z = pos.y;
}
}
for (u32 in = 0; in < n.inputs_fed.size(); in++, row++) {
ImGui::PushID(row);
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::RadioButton("##In", false);
if (ImGui::IsItemActive()) {
dragging_on_socket = true;
source = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y};
}
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
PlugboardGraph::ConnectInfo d{ &n, 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);
}
ImGui::EndDragDropTarget();
}
// Update link info if needed
if (n.inputs_fed[in].index() == 0) {
auto pos = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y};
auto& d = link_pos[std::get<PlugboardGraph::ConnectInfo>(n.inputs_fed[in])];
d.x = pos.x;
d.y = pos.y;
}
ImGui::TableNextColumn();
ImGui::Text("%s", n.node->in_names[in].c_str());
ImGui::TableNextColumn();
ImGui::PopID();
}
}
void PlugboardDrawNode(PlugboardGraph::NodeInstance& n, ImVec2& view_pos, i32 id, ImGuiIO& io, ImGuiStyle& style,
bool& dragging_on_socket, ImVec2& source, std::unordered_map<PlugboardGraph::ConnectInfo, ImVec4, PlugboardGraph::_ConnectInfoHasher>& link_pos) {
ImGui::SetCursorPos(view_pos + n.pos);
ImGui::PushID(id);
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0xFF080813);
ImGui::BeginChild(n.node->name.c_str(), {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Border);
ImGui::PopStyleColor();
if (ImGui::BeginTable(n.node->name.c_str(), 3)) {
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Button(n.node->name.c_str(), {100.0f , 0.0f});
if (ImGui::IsItemClicked()) {
n.old_pos = n.pos;
}
if (ImGui::IsItemActive()) {
n.pos = n.old_pos + (io.MousePos - io.MouseClickedPos[0]);
}
ImGui::TableNextColumn();
PlugboardNodeDrawSockets(n, style, dragging_on_socket, source, link_pos);
ImGui::EndTable();
}
ImGui::EndChild();
ImGui::PopID();
}
void Plugboard(CompState& s) {
if (!ImGui::Begin("Plugboard", &draw_plugboard)) {
ImGui::End();
return;
}
if (ImGui::Button("Add Sine"))
s.plugboard.nodes.push_back(PlugboardGraph::MakeInstance(PlugboardNodes::Sine));
ImGuiIO& io = ImGui::GetIO();
ImGuiStyle style = ImGui::GetStyle();
static f32 view_scale = 1.0f;
static ImVec2 view_pos{}, old_view_pos{};
bool dragging_on_socket{};
static ImVec2 drag_source{};
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0xFF100500);
ImGui::BeginChild("view_port", ImGui::GetContentRegionAvail(), 0, ImGuiWindowFlags_NoMove);
ImGui::BeginChild("Nodes", ImGui::GetContentRegionAvail(), 0, ImGuiWindowFlags_NoMove);
ImGui::PopStyleColor();
if (ImGui::IsMouseClicked(0)) {
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("K_PLUG_IN_TO_OUT")) {
PlugboardGraph::ConnectInfo in = *(const PlugboardGraph::ConnectInfo*)payload->Data;
in.p->disconnect(in.index);
}
ImGui::EndDragDropTarget();
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("K_PLUG_OUT_TO_IN")) {
PlugboardGraph::ConnectInfo out = *(const PlugboardGraph::ConnectInfo*)payload->Data;
auto& in = out.p->outputs_going[out.index];
in.p->disconnect(in.index);
}
ImGui::EndDragDropTarget();
}
ImGuiWindow* window = ImGui::GetCurrentWindow();
s.plugboard.links_pos.clear();
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
old_view_pos = view_pos;
}
if (ImGui::IsItemActive()) {
view_pos = old_view_pos + (io.MousePos - io.MouseClickedPos[0]);
}
static ImVec2 out{}, in{}, out2{}, in2{};
static ImVec2 pos{}, old_pos{};
ImGui::SetCursorPos(view_pos + pos);
static bool active{};
ImGui::PushID(1);
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0xFF080813);
ImGui::BeginChild("sad", {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_Border);
ImGui::PopStyleColor();
if (ImGui::BeginTable("s", 3)) {
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Button("Asdf", {100.0f , 0.0f});
if (ImGui::IsItemClicked()) {
old_pos = pos;
}
if (ImGui::IsItemActive()) {
pos = old_pos + (io.MousePos - io.MouseClickedPos[0]);
}
ImGui::TableNextColumn();
ImGui::PushID(1);
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Dummy({100.0f - ImGui::CalcTextSize("asd").x - style.ItemSpacing.x, 0.0f});
ImGui::SameLine();
ImGui::Text("qq");
ImGui::TableNextColumn();
ImGui::RadioButton("##asd", active);
out = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y };
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::RadioButton("##asd", active);
in2 = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y };
ImGui::TableNextColumn();
ImGui::Text("asd");
ImGui::TableNextColumn();
ImGui::PopID();
ImGui::EndTable();
}
/*
if (ImGui::IsItemActive()) {
}
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
OutToIn d{ &n, u };
ImGui::SetDragDropPayload("K_SHADER_OUT_TO_IN", &d, sizeof(d));
ImGui::Text("asdf");
ImGui::EndDragDropSource();
}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("K_SHADER_IN_TO_OUT")) {
InSlot* in = *(InSlot**)payload->Data;
}
ImGui::EndDragDropTarget();
}
*/
/* for (InSlot& s : n.inputs) {
ImGui::PushID(i);
bool active = s.node != nullptr;
if (active) {
window->DrawList->AddLine(window->DC.CursorPos, io.MousePos, 0xFFAAAAAA, 2.0f);
}
ImGui::RadioButton((s.name).c_str(), active);
if (ImGui::IsItemActive())
window->DrawList->AddLine(io.MouseClickedPos[0], io.MousePos, 0xFFAAAAAA, 2.0f);
//if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
// const InSlot* ptr = &s;
// ImGui::SetDragDropPayload("K_SHADER_IN_TO_OUT", &ptr, sizeof(ptr));
// ImGui::Text("%s", Type_To_Str[s.type]);
// ImGui::EndDragDropSource();
//}
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("K_SHADER_OUT_TO_IN")) {
OutToIn out = *(const OutToIn*)payload->Data;
if (out.node->out[out.index].first == s.type) {
s.node = out.node;
s.out_index = out.index;
}
}
ImGui::EndDragDropTarget();
}
ImGui::PopID();
i++;
}*/
ImGui::EndChild();
ImGui::PopID();
for (u32 i = 0; i < s.plugboard.nodes.size(); i++)
PlugboardDrawNode(s.plugboard.nodes[i], view_pos, i, io, style, dragging_on_socket, drag_source, s.plugboard.links_pos);
ImGui::SetCursorPos({});
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0x33FFFFFF);
ImGui::BeginChild("asdasd", {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY );
ImGui::BeginChild(s.plugboard.comp_in.name.c_str(), {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY );
ImGui::PopStyleColor();
if (ImGui::BeginTable("Source", 2)) {
ImGui::PushID(1);
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::Text("Time");
ImGui::TableNextColumn();
ImGui::RadioButton("##asd", active);
out2 = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y };
ImGui::PopID();
if (ImGui::BeginTable(s.plugboard.comp_in.name.c_str(), 3)) {
PlugboardNodeDrawSockets(s.plugboard.in_instance, style, dragging_on_socket, drag_source, s.plugboard.links_pos, false);
ImGui::EndTable();
}
ImGui::EndChild();
ImGui::SetCursorPos({ImGui::GetContentRegionAvail().x - 100.0f, 0.0f});
static f32 right_offset = 0.0f; // check after drawing this frame, so next frame will be correct
ImGui::SetCursorPos({ImGui::GetContentRegionAvail().x - right_offset, 0.0f});
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0x33FFFFFF);
ImGui::BeginChild("ert", {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY);
ImGui::BeginChild(s.plugboard.comp_out.name.c_str(), {}, ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY);
ImGui::PopStyleColor();
if (ImGui::BeginTable("Source", 1)) {
ImGui::PushID(1);
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
ImGui::TableNextColumn();
ImGui::RadioButton("asfnjklanf", active);
in = ImGui::GetCursorScreenPos() + ImVec2{ ImGui::GetFrameHeight() / 2, -ImGui::GetFrameHeight() / 2 - style.ItemInnerSpacing.y };
ImGui::PopID();
if (ImGui::BeginTable(s.plugboard.comp_out.name.c_str(), 3)) {
PlugboardNodeDrawSockets(s.plugboard.out_instance, style, dragging_on_socket, drag_source, s.plugboard.links_pos, false);
ImGui::EndTable();
}
ImGui::EndChild();
ImGui::GetCurrentWindow()->DrawList->AddLine(in, out, 0xFFFFFFFF, 2.0f);
ImGui::GetCurrentWindow()->DrawList->AddLine(in2, out2, 0xFFAAAAAA, 2.0f);
right_offset += ImGui::GetItemRectMax().x - ImGui::GetWindowWidth();
for (auto& [_, link] : s.plugboard.links_pos)
window->DrawList->AddLine({link.x, link.y}, {link.w, link.z}, 0xFFFFFFFF, 2.0f);
if (dragging_on_socket)
window->DrawList->AddLine(ImGui::GetMousePos(), drag_source, 0xFFFFFFFF, 2.0f);
ImGui::EndChild();
@ -537,13 +575,36 @@ namespace K::UI {
ImGui::TableNextColumn();
ImGui::Text("%s", it->first.c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", ShaderGraph::Type_To_Str[it->second.second.index()]);
ImGui::Text("%s", ShaderGraph::Type_To_Str[it->second.val.index()]);
ImGui::TableNextColumn();
bool temp{};
ImGui::Checkbox("##Expose", &temp);
bool d = it->second.exposure.p != nullptr, cp = d;
ImGui::Checkbox("##Expose", &d);
if (d != cp) {
if (d) {
String id = s.layers[s.active].name + "." + it->first;
it->second.exposure = {&s.plugboard.out_instance, static_cast<u32>(s.plugboard.out_instance.node->in_names.size())};
s.plugboard.out_instance.node->in_names.push_back(id);
s.plugboard.out_instance.node->in_types.push_back(PlugboardGraph::Type(it->second.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.push_back(ShaderValToPlugboard(it->second.val));
}
else {
it->second.exposure.p->disconnect(it->second.exposure.index);
for (auto& l : s.layers)
for (auto& u : l.track.uniforms)
if (u.second.exposure.index > it->second.exposure.index)
u.second.exposure.index--;
s.plugboard.comp_out.in_names.erase(s.plugboard.out_instance.node->in_names.begin() + it->second.exposure.index);
s.plugboard.comp_out.in_types.erase(s.plugboard.out_instance.node->in_types.begin() + it->second.exposure.index);
s.plugboard.out_instance.inputs_fed.erase(s.plugboard.out_instance.inputs_fed.begin() + it->second.exposure.index);
it->second.exposure = {nullptr, 0};
}
}
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(-FLT_MIN);
std::visit([it](auto&& arg) {
ImGui::BeginDisabled(it->second.exposure.p != nullptr);
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_Float>::type>)
ImGui::DragFloat("##", &arg, 0.005f);
@ -555,10 +616,11 @@ namespace K::UI {
ImGui::DragFloat2("##", &arg.x, 0.005f);
else if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_XYZ>::type>)
ImGui::DragFloat3("##", &arg.x, 0.005f);
}, it->second.second);
}, it->second.val);
ImGui::EndDisabled();
ImGui::TableNextColumn();
if (ImGui::Button("X")) {
bgfx::destroy(it->second.first);
bgfx::destroy(it->second.handle);
it = s.layers[s.active].track.uniforms.erase(it);
}
else it++;
@ -632,7 +694,7 @@ namespace K::UI {
break;
default:
LogError("Unsupported Renderer");
};
}
}
void Shutdown(CompState& s) {

View file

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

View file

@ -3,6 +3,7 @@
#include "VisualTrack.h"
#include <set>
#include <unordered_set>
#include "PlugboardGraph.h"
namespace K {
bool Init();
@ -18,13 +19,19 @@ namespace K {
};
struct CompState {
// Time
u64 current_frame;
u64 frame_max;
u32 fps;
u32 fps;
u32 width, height;
Vector<Layer> layers;
i32 active = -1; // index for layers
std::set<u32> selected; // indices for layers
std::unordered_set<u32> disabled; // indices for layers
PlugboardGraph::PlugboardGraph plugboard;
};
}

View file

@ -0,0 +1,162 @@
#pragma once
#include "Common.h"
#include "Graphics.h"
#include <variant>
#include <functional>
#include <imgui.h>
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>;
};
String VarToString(const T_Map<T_Count>::type& var);
inline T_Map<T_Count>::type expand_type(Type i) {
static T_Map<T_Count>::type table[] = {f32{}, i32{}, PlugboardGraph::RGBA{}, PlugboardGraph::XY{}, PlugboardGraph::XYZ{}, String{}};
return table[i];
}
struct Node {
String name;
Vector<String> in_names;
Vector<Type> in_types;
Vector<String> out_names;
Vector<Type> out_types;
Vector<std::function<T_Map<T_Count>::type(Vector<T_Map<T_Count>::type>)>> fetch; // maybe change to a function pointer later
// todo investigate how you might wanna jit this instead of evaluating a tree for each output at runtime
};
struct NodeInstance;
struct ConnectInfo {
NodeInstance *p; u32 index;
auto operator<=>(const ConnectInfo&) const = default;
};
struct _ConnectInfoHasher
{
std::size_t operator()(const ConnectInfo& k) const
{
return std::hash<NodeInstance *>()(k.p);
}
};
struct NodeInstance {
Node *node;
Vector<std::variant<ConnectInfo, T_Map<Type::T_Count>::type>> inputs_fed;
Vector<ConnectInfo> outputs_going;
ImVec2 pos, old_pos;
void connect(u32 input_index, NodeInstance *to, u32 to_out_index) {
inputs_fed[input_index] = ConnectInfo{to, to_out_index};
to->outputs_going[to_out_index] = {this, input_index};
}
void disconnect(u32 input_index) {
std::visit([](auto&& arg){
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ConnectInfo>)
arg.p->outputs_going[arg.index] = {nullptr, 0};
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_types[input_index]);
}
};
inline NodeInstance MakeInstance(Node& n) {
Vector<std::variant<ConnectInfo, T_Map<Type::T_Count>::type>> inp;
Vector<ConnectInfo> out;
for (auto t : n.in_types)
inp.push_back(expand_type(t));
for (auto t : n.out_types)
out.push_back({});
return {
.node = &n,
.inputs_fed = std::move(inp),
.outputs_going = std::move(out)
};
}
inline T_Map<T_Count>::type Eval(const ConnectInfo& info) {
Vector<T_Map<T_Count>::type> pack;
for (auto& v : info.p->inputs_fed)
std::visit([&pack](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ConnectInfo>)
pack.push_back(Eval(arg));
else if constexpr (std::is_same_v<T, T_Map<Type::T_Count>::type>)
pack.push_back(arg);
}, v);
return info.p->node->fetch[info.index](pack);
}
struct PlugboardGraph {
Vector<NodeInstance> nodes;
std::unordered_map<ConnectInfo, ImVec4, _ConnectInfoHasher> links_pos; // this is hilariously bad
Node comp_in = {
"Composition In",
{},
{},
{"Time"},
{T_Float},
{[](Vector<T_Map<T_Count>::type> v) { return T_Map<T_Count>::type{ static_cast<f32>(SDL_GetTicks()) / 20.0f }; }} // kill me
},
comp_out = {
"Composition Out",
{},
{},
{},
{},
{}
};
NodeInstance in_instance = {&comp_in, {}, {{nullptr, 0}}}, out_instance = {&comp_out};
};
}

View file

@ -0,0 +1,17 @@
#pragma once
#include "Common.h"
#include "PlugboardGraph.h"
namespace K::PlugboardNodes {
PlugboardGraph::Node Sine = {
.name = "Sine",
.in_names = { "In" },
.in_types = { PlugboardGraph::T_Float },
.out_names = { "Out" },
.out_types = { PlugboardGraph::T_Float },
.fetch = {[](const Vector<PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type>& arg) {
return std::sin(std::get<PlugboardGraph::T_Float>(arg[0]));
}}
};
}

View file

@ -2,9 +2,8 @@
#include "Common.h"
#include "Graphics.h"
#include <variant>
#include "imgui.h"
#include "Graphics.h"
// todo a lot of problems in this unit can lead to very bad performance
namespace K::ShaderGraph {
enum Type {
T_Float,

View file

@ -1,8 +1,6 @@
#pragma once
#include "Common.h"
#include "Keishiki.h"
#include "Graphics.h"
#include "VisualTrack.h"
namespace K::UI {
void Init(SDL_Window *window);

View file

@ -5,6 +5,7 @@
#include <functional>
#include <bx/math.h>
#include <fstream>
#include "PlugboardGraph.h"
namespace K {
template <typename T>
@ -18,11 +19,51 @@ namespace K {
}
};
struct Uniform {
bgfx::UniformHandle handle;
ShaderGraph::T_Map<ShaderGraph::T_Count>::type val;
PlugboardGraph::ConnectInfo exposure;
};
inline ShaderGraph::T_Map<ShaderGraph::T_Count>::type PlugboardValToShader(const PlugboardGraph::T_Map<PlugboardGraph::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>)
return ShaderGraph::T_Map<ShaderGraph::T_Float>::type(arg);
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::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>)
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>)
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>)
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>)
return ShaderGraph::T_Map<ShaderGraph::T_Count>::type{};
},val);
}
inline 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 {
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);
else if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_Int>::type>)
return PlugboardGraph::T_Map<PlugboardGraph::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);
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);
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);
},val);
}
struct VisualTrack {
ShaderGraph::ShaderGraph tree;
bgfx::ProgramHandle pg = BGFX_INVALID_HANDLE;
String shader;
Dict<String, std::pair<bgfx::UniformHandle, ShaderGraph::T_Map<ShaderGraph::T_Count>::type>> uniforms;
Dict<String, Uniform> uniforms;
// Vector<String> samplers;
bgfx::TextureHandle get_frame(bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16], f32 view[16], f32 transform[16]) const {
bgfx::touch(K::Graphics::K_VIEW_COMP_COMPOSITE);
@ -35,6 +76,18 @@ namespace K {
for (auto& [_name, u] : uniforms) {
f32 pack[4]{};
ShaderGraph::T_Map<ShaderGraph::T_Count>::type val_target;
if (u.exposure.p == nullptr)
val_target = u.val;
else {
std::visit([&val_target](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, PlugboardGraph::ConnectInfo>)
val_target = PlugboardValToShader(PlugboardGraph::Eval(arg));
else if constexpr (std::is_same_v<T, PlugboardGraph::T_Map<PlugboardGraph::T_Count>::type>)
val_target = PlugboardValToShader(arg);
}, u.exposure.p->inputs_fed[u.exposure.index]);
}
std::visit([&pack](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_Float>::type> || std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_Int>::type>)
@ -54,8 +107,8 @@ namespace K {
pack[1] = arg.y;
pack[2] = arg.z;
}
}, u.second);
bgfx::setUniform(u.first, pack);
}, val_target);
bgfx::setUniform(u.handle, pack);
}
Graphics::DrawTextureWithTransform(K::Graphics::K_VIEW_COMP_COMPOSITE, Graphics::mmaker->tx, transform,
@ -65,7 +118,7 @@ namespace K {
}
void add_uniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val) {
if (!uniforms.contains(s))
uniforms.emplace(s, std::make_pair(bgfx::createUniform(("__" + s).c_str(), bgfx::UniformType::Vec4), val));
uniforms.emplace(s, Uniform{bgfx::createUniform(("__" + s).c_str(), bgfx::UniformType::Vec4), val, {nullptr, 0}});
}
void compile() {
std::ofstream f("temp.frag");
@ -88,7 +141,7 @@ namespace K {
f << ".xy";
else if constexpr (std::is_same_v<T, ShaderGraph::T_Map<ShaderGraph::T_XYZ>::type>)
f << ".xyz";
}, u.second.second);
}, u.second.val);
f << "\n";
}
f << shader;
@ -144,7 +197,7 @@ namespace K {
if (bgfx::isValid(pg))
bgfx::destroy(pg);
for (auto& uniform : uniforms) {
bgfx::destroy(uniform.second.first);
bgfx::destroy(uniform.second.handle);
}
uniforms.clear();
}

View file

@ -143,9 +143,4 @@ void main()
float alpha = _A.a + alpha_b;
gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha);
}
else if (f_mode.x == 26.0f) {
float alpha_b = _A.a * (1.0f - _B.a);
float alpha = _A.a + alpha_b;
gl_FragColor = vec4((_A.rgb * _A.a + _B.rgb * alpha_b)/alpha, alpha);
}
}

View file

@ -7,7 +7,7 @@
- Non-negotiables:
- Text (idea: index-based evaluation in plugboard)
- Shapes (idea: embed glisp :mmtroll:, need to inquire -- still a lot of friction for simple shapes if we don't also get the glisp tools)
- External data driving (json?)
- External data driving (json or something else?)
- Layer Groups (jokes -- can be completely UI side)
## UI
@ -20,6 +20,9 @@
- std::unordered_map -> std::flat_map pending compiler support
- Simple 3D engine
## UI
- Adapt nodes for shader graph -- code editor will be fine for now
## Audio
- Wait for SDL3!
- SDL_mixer will be able to do all of wav ogg flac mp3 opus, we live in good times