asdamsdk
This commit is contained in:
parent
ccadf34f4c
commit
cf0af93cac
14 changed files with 437 additions and 232 deletions
|
@ -19,9 +19,9 @@ set_property(TARGET Keishiki PROPERTY CXX_STANDARD 23)
|
|||
include_directories ("include" "include/ext" "ext/imgui" "ext/implot" "ext/plf_colony")
|
||||
|
||||
add_subdirectory("ext/fmt")
|
||||
add_subdirectory("ext/glaze")
|
||||
add_subdirectory("ext/freetype")
|
||||
|
||||
add_compile_definitions(WL_EGL_PLATFORM)
|
||||
#add_compile_definitions(WL_EGL_PLATFORM)
|
||||
add_subdirectory("ext/bgfx")
|
||||
|
||||
add_compile_definitions(IMGUI_DEFINE_MATH_OPERATORS)
|
||||
|
@ -47,5 +47,5 @@ else ()
|
|||
find_package(ECM REQUIRED NO_MODULE)
|
||||
set(CMAKE_MODULE_PATH ${ECM_FIND_MODULE_DIR})
|
||||
find_package(Wayland REQUIRED Egl)
|
||||
target_link_libraries (Keishiki PRIVATE freetype bgfx bx SDL3::SDL3 ${Wayland_LIBRARIES} fmt)
|
||||
target_link_libraries (Keishiki PRIVATE freetype bgfx bx SDL3::SDL3 ${Wayland_LIBRARIES} fmt glaze_glaze)
|
||||
endif ()
|
||||
|
|
|
@ -19,12 +19,16 @@ namespace K {
|
|||
K::AppState app_state;
|
||||
|
||||
bool Init() {
|
||||
#if !WL_EGL_PLATFORM
|
||||
SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "x11");
|
||||
#endif
|
||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||
Log(K_L_Error, "{}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
app_state.window = SDL_CreateWindow("Keishiki", app_state.window_width, app_state.window_height, SDL_WINDOW_RESIZABLE);
|
||||
app_state.window = SDL_CreateWindow("Keishiki", app_state.window_width, app_state.window_height, SDL_WINDOW_HIGH_PIXEL_DENSITY);
|
||||
SDL_SetWindowResizable(app_state.window, true);
|
||||
|
||||
if (app_state.window == nullptr) {
|
||||
Log(K_L_Error, "{}", SDL_GetError());
|
||||
|
@ -69,16 +73,16 @@ namespace K {
|
|||
|
||||
if (!K::Resource::Init())
|
||||
return false;
|
||||
K::UI::Init(app_state.window);
|
||||
UI::Init(app_state.window);
|
||||
|
||||
if (!K::Graphics::Init()) {
|
||||
Log(K_L_Error, "Graphics init failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
app_state.compositions.emplace_back("default project", 0, 100, 30.0f, 1280, 550);
|
||||
app_state.inspecting_composition = 0;
|
||||
K::UI::SetupViewport(app_state.compositions[0]);
|
||||
app_state.project.compositions.emplace_back("default project", 0, 100, 30.0f, 1280, 550);
|
||||
app_state.project.inspecting_composition = 0;
|
||||
UI::SetupViewport(app_state.project.compositions[app_state.project.inspecting_composition]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -98,8 +102,9 @@ namespace K {
|
|||
break;
|
||||
}
|
||||
if (current_event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
|
||||
SDL_GetWindowSize(app_state.window, &app_state.window_width, &app_state.window_height);
|
||||
bgfx::reset(app_state.window_width, app_state.window_height);
|
||||
app_state.window_width = current_event.window.data1;
|
||||
app_state.window_height = current_event.window.data2;
|
||||
bgfx::reset(current_event.window.data1, current_event.window.data2, BGFX_RESET_VSYNC);
|
||||
UI::SetLogoView();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace K::Plugboard {
|
|||
}
|
||||
|
||||
template <Type type>
|
||||
typename T_Map<type>::type GetNodeInputArg(const CompState& s, const InSocket& socket) {
|
||||
typename T_Map<type>::type GetNodeInputArg(const CompositionState& 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)>;
|
||||
|
@ -113,83 +113,83 @@ namespace K::Plugboard {
|
|||
"Invalid"
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchAdd(const CompState& s, const Add& n) {
|
||||
T_Map<T_Count>::type FetchAdd(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchNegate(const CompositionState& s, const Negate& n) {
|
||||
return -GetNodeInputArg<T_Float>(s, n.in[0]);
|
||||
}
|
||||
|
||||
T_Map<T_Count>::type FetchSubtract(const CompState& s, const Subtract& n) {
|
||||
T_Map<T_Count>::type FetchSubtract(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchMultiply(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchDivide(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchSign(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchSin(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchCos(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchTan(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchArcsin(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchArccos(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchArctan(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchAtan2(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchMinimum(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchMaximum(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchPower(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchSquareRoot(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchNaturalLogarithm(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchAbsoluteValue(const CompositionState& 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) {
|
||||
T_Map<T_Count>::type FetchInterpolation(const CompositionState& s, const Interpolation& n) {
|
||||
return EvalInterpolation(GetNodeInputArg<T_Float>(s, n.in[0]), n.extra);
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ namespace K::Plugboard {
|
|||
}
|
||||
}
|
||||
|
||||
T_Map<T_Count>::type FetchChain(const CompState& s, const Chain& n) {
|
||||
T_Map<T_Count>::type FetchChain(const CompositionState& s, const Chain& n) {
|
||||
i32 frame = static_cast<i32>(GetNodeInputArg<T_Int>(s, n.in[0]));
|
||||
|
||||
auto& v = n.extra.chain.segments;
|
||||
|
@ -250,7 +250,7 @@ namespace K::Plugboard {
|
|||
}, var);
|
||||
}
|
||||
|
||||
T_Map<T_Count>::type Eval(const CompState& s, const ConnectInfo& info) {
|
||||
T_Map<T_Count>::type Eval(const CompositionState& s, const ConnectInfo& info) {
|
||||
return std::visit([&info, &s](auto&& arg) { return arg->fetch[info.index](s, *arg); }, info.p);
|
||||
}
|
||||
|
||||
|
@ -343,25 +343,32 @@ namespace K::Plugboard {
|
|||
}, v);
|
||||
}
|
||||
|
||||
|
||||
T_Map<T_Count>::type FetchCompositionInFrame(const CompState& s, const CompositionIn& n) {
|
||||
T_Map<T_Count>::type FetchCompositionInFrame(const CompositionState& s, const GroupIn& 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) {
|
||||
T_Map<T_Count>::type FetchCompositionInAppTicks(const CompositionState& s, const GroupIn& n) {
|
||||
return T_Map<T_Count>::type{ static_cast<f32>(SDL_GetTicks()) };
|
||||
}
|
||||
|
||||
Plugboard::Plugboard() {
|
||||
AddOutSocket("Frame", T_Int, FetchCompositionInFrame);
|
||||
AddOutSocket("App Ticks", T_Float, FetchCompositionInAppTicks);
|
||||
AddInSocket("Frame", T_Int);
|
||||
AddInSocket("Ticks", T_Int);
|
||||
}
|
||||
void Plugboard::AddInSocket(const String& s, Type t) {
|
||||
in.emplace_back(s, t);
|
||||
}
|
||||
void Plugboard::AddOutSocket(const String& s, Type t, T_Map<T_Count>::type(*fetch)(const CompositionState&, const GroupIn&)) {
|
||||
in_instance.out.emplace_back(s, t);
|
||||
in_instance.fetch.push_back(fetch);
|
||||
}
|
||||
void Plugboard::RecollectChains() {
|
||||
for (u32 i = 0; i < out.in.size(); i++) {
|
||||
for (u32 i = 0; i < out_instance.in.size(); i++) {
|
||||
std::visit([i, this](auto&& arg) {
|
||||
if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, ConnectInfo>)
|
||||
CollectChains(arg, out.show_nodes[i]);
|
||||
}, out.in[i].value);
|
||||
CollectChains(arg, show_nodes[i]);
|
||||
}, out_instance.in[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,28 @@
|
|||
#include <Resource.h>
|
||||
#include <Keishiki.h>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <Keishiki.h>
|
||||
#include <glaze/glaze.hpp>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
template <>
|
||||
struct glz::meta<ImVec2> {
|
||||
using T = ImVec2;
|
||||
static constexpr auto value = array(&T::x, &T::y);
|
||||
};
|
||||
|
||||
namespace K::Resource {
|
||||
void SaveCurrentProject() {
|
||||
auto ec = glz::write_file_json("soon!", "./temp.json", String{});
|
||||
if (ec.ec != glz::error_code::none) {
|
||||
Log(K_L_Error, "{}", ec.includer_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
bgfx::ShaderHandle LoadShader(const std::filesystem::path& file_path) {
|
||||
FILE *file = fopen(file_path.c_str(), "rb");
|
||||
|
@ -227,4 +243,77 @@ namespace K::Resource {
|
|||
}
|
||||
}, r.second);
|
||||
}
|
||||
|
||||
static int DecodeURI(char *buf, int len) {
|
||||
/* Decodes URI escape sequences in string buf of len bytes
|
||||
(excluding the terminating NULL byte) in-place. Since
|
||||
URI-encoded characters take three times the space of
|
||||
normal characters, this should not be an issue.
|
||||
|
||||
Returns the number of decoded bytes that wound up in
|
||||
the buffer, excluding the terminating NULL byte.
|
||||
|
||||
The buffer is guaranteed to be NULL-terminated but
|
||||
may contain embedded NULL bytes.
|
||||
|
||||
On error, -1 is returned.
|
||||
*/
|
||||
int ri, wi, di;
|
||||
char decode = '\0';
|
||||
if (!buf || len < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) {
|
||||
len = SDL_strlen(buf);
|
||||
}
|
||||
for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) {
|
||||
if (di == 0) {
|
||||
/* start decoding */
|
||||
if (buf[ri] == '%') {
|
||||
decode = '\0';
|
||||
di += 1;
|
||||
continue;
|
||||
}
|
||||
/* normal write */
|
||||
buf[wi] = buf[ri];
|
||||
wi += 1;
|
||||
continue;
|
||||
} else if (di == 1 || di == 2) {
|
||||
char off = '\0';
|
||||
char isa = buf[ri] >= 'a' && buf[ri] <= 'f';
|
||||
char isA = buf[ri] >= 'A' && buf[ri] <= 'F';
|
||||
char isn = buf[ri] >= '0' && buf[ri] <= '9';
|
||||
if (!(isa || isA || isn)) {
|
||||
/* not a hexadecimal */
|
||||
int sri;
|
||||
for (sri = ri - di; sri <= ri; sri += 1) {
|
||||
buf[wi] = buf[sri];
|
||||
wi += 1;
|
||||
}
|
||||
di = 0;
|
||||
continue;
|
||||
}
|
||||
/* itsy bitsy magicsy */
|
||||
if (isn) {
|
||||
off = 0 - '0';
|
||||
} else if (isa) {
|
||||
off = 10 - 'a';
|
||||
} else if (isA) {
|
||||
off = 10 - 'A';
|
||||
}
|
||||
decode |= (buf[ri] + off) << (2 - di) * 4;
|
||||
if (di == 2) {
|
||||
buf[wi] = decode;
|
||||
wi += 1;
|
||||
di = 0;
|
||||
} else {
|
||||
di += 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
buf[wi] = '\0';
|
||||
return wi;
|
||||
}
|
||||
}
|
245
Keishiki/UI.cpp
245
Keishiki/UI.cpp
|
@ -18,6 +18,8 @@
|
|||
#include <chrono>
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
#include <SDL3/SDL_dialog.h>
|
||||
|
||||
namespace {
|
||||
const K::Resource::Resource<K::Resource::Type::K_R_Still> *logo;
|
||||
|
||||
|
@ -42,7 +44,7 @@ namespace {
|
|||
|
||||
K::VisualTrack bg{};
|
||||
K::Byte *save_buffer;
|
||||
K::CompState *comp_save_called = nullptr;
|
||||
K::CompositionState *comp_save_called = nullptr;
|
||||
u32 ready_frame;
|
||||
}
|
||||
|
||||
|
@ -68,7 +70,7 @@ namespace K::UI {
|
|||
bgfx::setViewTransform(K::Graphics::K_VIEW_LOGO, view, proj);
|
||||
}
|
||||
|
||||
void AddTransformLayer(CompState& s, const String& name) {
|
||||
void AddTransformLayer(CompositionState& s, const String& name) {
|
||||
auto l = Layer{
|
||||
VisualTrack{},
|
||||
name,
|
||||
|
@ -76,40 +78,38 @@ namespace K::UI {
|
|||
0UL,
|
||||
s.frame_max
|
||||
};
|
||||
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_resolution", ShaderGraph::ExpandVariant(ShaderGraph::T_XY), K_U_Exposed);
|
||||
l.track.uniforms[0].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type{static_cast<f32>(s.width), static_cast<f32>(s.height)};
|
||||
K::VisualTrack::ExposeUniform(s, l.track.uniforms.back());
|
||||
|
||||
l.track.AddUniform("u_opacity", ShaderGraph::ExpandVariant(ShaderGraph::T_Float));
|
||||
l.track.AddUniform("u_opacity", ShaderGraph::ExpandVariant(ShaderGraph::T_Float), K_U_Exposed);
|
||||
l.track.uniforms[1].val = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(1.0f);
|
||||
K::VisualTrack::ExposeUniform(s, l.track.uniforms.back());
|
||||
|
||||
l.track.AddUniform("u_rot", ShaderGraph::ExpandVariant(ShaderGraph::T_Float));
|
||||
l.track.AddUniform("u_rot", ShaderGraph::ExpandVariant(ShaderGraph::T_Float), K_U_Exposed);
|
||||
l.track.uniforms[2].val = ShaderGraph::T_Map<ShaderGraph::T_Float>::type(.0f);
|
||||
K::VisualTrack::ExposeUniform(s, l.track.uniforms.back());
|
||||
|
||||
l.track.AddUniform("u_scale", ShaderGraph::ExpandVariant(ShaderGraph::T_XY));
|
||||
l.track.AddUniform("u_scale", ShaderGraph::ExpandVariant(ShaderGraph::T_XY), K_U_Exposed);
|
||||
l.track.uniforms[3].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type{1.0f, 1.0f};
|
||||
K::VisualTrack::ExposeUniform(s, l.track.uniforms.back());
|
||||
|
||||
l.track.AddUniform("u_translate", ShaderGraph::ExpandVariant(ShaderGraph::T_XY));
|
||||
l.track.AddUniform("u_translate", ShaderGraph::ExpandVariant(ShaderGraph::T_XY), K_U_Exposed);
|
||||
l.track.uniforms[4].val = ShaderGraph::T_Map<ShaderGraph::T_XY>::type{.0f, .0f};
|
||||
K::VisualTrack::ExposeUniform(s, l.track.uniforms.back());
|
||||
|
||||
l.track.shader = "void main() {\n"
|
||||
"\tfloat angle = -u_rot * M_PI / 180.0f;\n"
|
||||
"\tvec2 uv = vec2(v_texcoord0.x, 1.0f - v_texcoord0.y) - .5f;\n"
|
||||
"\tuv = uv * u_aspect_ratio;\n"
|
||||
"\tuv = uv * u_resolution;\n"
|
||||
"\tuv = uv - u_translate;\n"
|
||||
"\tuv = vec2(cos(angle)*uv.x - sin(angle)*uv.y, sin(angle)*uv.x + cos(angle)*uv.y);\n"
|
||||
"\tuv = uv / s_texColor_dims;\n"
|
||||
"\tuv = uv / u_scale;\n"
|
||||
"\tuv = uv + .5f;\n\n"
|
||||
"\tvec4 tx = texture2D(s_texColor, uv);\n"
|
||||
"\tgl_FragColor = vec4(tx.rgb, tx.a * u_opacity);\n"
|
||||
"}\n";
|
||||
l.track.ExposeUniform(s, 0);
|
||||
l.track.ExposeUniform(s, 1);
|
||||
l.track.ExposeUniform(s, 2);
|
||||
l.track.ExposeUniform(s, 3);
|
||||
l.track.ExposeUniform(s, 4);
|
||||
|
||||
l.track.AddSampler("s_texColor");
|
||||
|
||||
|
@ -119,6 +119,13 @@ namespace K::UI {
|
|||
|
||||
void MainMenuBar() {
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Save Project", "CTRL+S")) {
|
||||
Resource::SaveCurrentProject();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Edit")) {
|
||||
// if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
|
||||
// if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
|
||||
|
@ -130,16 +137,18 @@ namespace K::UI {
|
|||
}
|
||||
|
||||
if (ImGui::BeginMenu("View")) {
|
||||
if (ImGui::MenuItem("Assets", "", &draw_assets)) {}
|
||||
if (ImGui::MenuItem("Viewport", "", &draw_viewport)) {}
|
||||
if (ImGui::MenuItem("Composition", "", &draw_comp)) {}
|
||||
if (ImGui::MenuItem("Shader", "", &draw_layer)) {}
|
||||
if (ImGui::MenuItem("Layer", "", &draw_layer)) {}
|
||||
if (ImGui::MenuItem("Interpolation", "", &draw_interpolation)) {}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
|
||||
void SetupViewport(CompState& s) {
|
||||
void SetupViewport(CompositionState& s) {
|
||||
composite[0] = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT);
|
||||
composite[1] = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT);
|
||||
render = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT);
|
||||
|
@ -165,7 +174,7 @@ namespace K::UI {
|
|||
bx::mtxTranslate(view, 0.f, 0.f, 1.0f);
|
||||
}
|
||||
|
||||
void DestroyViewport(CompState& s) {
|
||||
void DestroyViewport(CompositionState& s) {
|
||||
bgfx::destroy(composite_fb[0]);
|
||||
bgfx::destroy(composite_fb[1]);
|
||||
bgfx::destroy(composite[0]);
|
||||
|
@ -197,8 +206,8 @@ namespace K::UI {
|
|||
}
|
||||
|
||||
template <Plugboard::Node N>
|
||||
void PlugboardNodeDrawSockets(CompState& s, N& n, ImGuiStyle& style,
|
||||
bool& dragging_on_socket, ImVec2& source, bool dummy = true) {
|
||||
void PlugboardNodeDrawSockets(CompositionState& s, N& n, ImGuiStyle& style,
|
||||
bool& dragging_on_socket, ImVec2& source, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& links_pos, bool dummy = true) {
|
||||
i32 row = 1;
|
||||
for (u32 out = 0; out < n.out.size(); out++, row++) {
|
||||
ImGui::PushID(row);
|
||||
|
@ -233,7 +242,7 @@ namespace K::UI {
|
|||
|
||||
// Update link info if needed
|
||||
if (!n.out[out].outgoing.empty()) {\
|
||||
s.plugboard.links_pos[{&n, out}].source = ImGui::GetCursorScreenPos() + ImVec2{ImGui::GetFrameHeight() / 2,
|
||||
links_pos[{&n, out}].source = ImGui::GetCursorScreenPos() + ImVec2{ImGui::GetFrameHeight() / 2,
|
||||
-ImGui::GetFrameHeight() / 2 -
|
||||
style.ItemInnerSpacing.y};
|
||||
}
|
||||
|
@ -264,13 +273,13 @@ namespace K::UI {
|
|||
ImGui::TextUnformatted(n.in[in].name.c_str());
|
||||
|
||||
// Update link info
|
||||
std::visit([&socket_link_pos, &dragging_on_socket, &source, &s](auto&& arg) {
|
||||
std::visit([&links_pos, &socket_link_pos, &dragging_on_socket, &source, &s](auto&& arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) {
|
||||
if (ImGui::IsItemActive())
|
||||
s.plugboard.links_pos[arg].sinks.push_back(ImGui::GetMousePos());
|
||||
links_pos[arg].sinks.push_back(ImGui::GetMousePos());
|
||||
else
|
||||
s.plugboard.links_pos[arg].sinks.push_back(socket_link_pos);
|
||||
links_pos[arg].sinks.push_back(socket_link_pos);
|
||||
}
|
||||
else if (ImGui::IsItemActive()) {
|
||||
dragging_on_socket = true;
|
||||
|
@ -288,8 +297,8 @@ namespace K::UI {
|
|||
}
|
||||
|
||||
template <Plugboard::Node N>
|
||||
void PlugboardDrawNode(CompState& s, N& n, ImVec2& view_pos, ImGuiIO& io, ImGuiStyle& style,
|
||||
bool& dragging_on_socket, ImVec2& source, bool& delete_request) {
|
||||
void PlugboardDrawNode(CompositionState& s, N& n, ImVec2& view_pos, ImGuiIO& io, ImGuiStyle& style,
|
||||
bool& dragging_on_socket, ImVec2& source, bool& delete_request, Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher>& links_pos) {
|
||||
Plugboard::NodeInstanceP ptr{&n};
|
||||
bool selected = std::ranges::find(s.plugboard.selected_nodes, ptr) != s.plugboard.selected_nodes.end();
|
||||
const auto& pos = n.pos;
|
||||
|
@ -335,7 +344,7 @@ namespace K::UI {
|
|||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
PlugboardNodeDrawSockets<N>(s, n, style, dragging_on_socket, source);
|
||||
PlugboardNodeDrawSockets<N>(s, n, style, dragging_on_socket, source, links_pos);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -351,7 +360,7 @@ namespace K::UI {
|
|||
last_frame_tick = app_state.current_time;
|
||||
}
|
||||
|
||||
void Viewport(CompState& s) {
|
||||
void Viewport(CompositionState& s) {
|
||||
if (playing) {
|
||||
if (static_cast<f32>(app_state.current_time - last_frame_tick) >= 1000.0f / s.fps) {
|
||||
f32 delta = static_cast<f32>(app_state.current_time - last_frame_tick);
|
||||
|
@ -361,7 +370,7 @@ namespace K::UI {
|
|||
}
|
||||
}
|
||||
|
||||
if (ImGui::Begin("Viewport", &draw_viewport)) {
|
||||
if (ImGui::Begin("Viewport")) {
|
||||
if (ImGui::Shortcut(ImGuiKey_Space))
|
||||
TogglePlay();
|
||||
|
||||
|
@ -436,11 +445,11 @@ namespace K::UI {
|
|||
struct PlotInfo {
|
||||
f32 begin, end;
|
||||
i32 samples;
|
||||
const CompState &s;
|
||||
const CompositionState &s;
|
||||
Plugboard::ConnectInfo &connected_v;
|
||||
};
|
||||
|
||||
void Composition(CompState& s) {
|
||||
void Composition(CompositionState& s) {
|
||||
static bool layer_delete_requested = false;
|
||||
if (layer_delete_requested) {
|
||||
if (std::ranges::find(s.selected, s.active) != s.selected.end()) // unset active if active is selected
|
||||
|
@ -486,7 +495,7 @@ namespace K::UI {
|
|||
node_delete_requested = false;
|
||||
}
|
||||
|
||||
if (!ImGui::Begin(("Composition: " + s.name).c_str(), &draw_comp, ImGuiWindowFlags_NoScrollbar)) {
|
||||
if (!ImGui::Begin(("Composition: " + s.name).c_str(), nullptr, ImGuiWindowFlags_NoScrollbar)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
@ -501,6 +510,7 @@ namespace K::UI {
|
|||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(150.0f);
|
||||
static Dict<Plugboard::ConnectInfo, Plugboard::LinksFromSource, Plugboard::ConnectInfoHasher> links_pos;
|
||||
if (ImGui::BeginCombo("##Node", s.plugboard.nodes.GetName(static_cast<Plugboard::K_P_Nodes>(node_current)), ImGuiComboFlags_None)) {
|
||||
for (u32 n = 0; n < Plugboard::K_P_Count; n++) {
|
||||
const bool is_selected = (node_current == n);
|
||||
|
@ -571,7 +581,7 @@ namespace K::UI {
|
|||
|
||||
// why are we re-getting positions on each frame?
|
||||
// this is just convenient because sometimes we would be dragging on a socket!
|
||||
s.plugboard.links_pos.clear();
|
||||
links_pos.clear();
|
||||
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
old_view_pos = view_pos;
|
||||
|
@ -584,7 +594,7 @@ namespace K::UI {
|
|||
(([&](auto&& arg){
|
||||
for (auto& node : arg) {
|
||||
PlugboardDrawNode<std::decay_t<decltype(node)>>(s, node, view_pos, io, style, dragging_on_socket,
|
||||
drag_source, node_delete_requested);
|
||||
drag_source, node_delete_requested, links_pos);
|
||||
}
|
||||
}(args)), ...);
|
||||
}, s.plugboard.nodes.nodes);
|
||||
|
@ -596,7 +606,7 @@ namespace K::UI {
|
|||
ImGuiChildFlags_AutoResizeY);
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::BeginTable("Composition In", 3)) {
|
||||
PlugboardNodeDrawSockets(s, s.plugboard.in, style, dragging_on_socket, drag_source, false);
|
||||
PlugboardNodeDrawSockets(s, s.plugboard.in_instance, style, dragging_on_socket, drag_source, links_pos, false);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
|
@ -928,9 +938,13 @@ namespace K::UI {
|
|||
f32 init_y = ImGui::GetCursorScreenPos().y;
|
||||
|
||||
const static f32 layer_bound_width = 5.0f;
|
||||
i32 l_in = TimelineFrameInView(view_left, view_right, current_layer.in, s.frame_max), l_out = TimelineFrameInView(view_left, view_right, current_layer.out, s.frame_max);
|
||||
const bool l_le_right_extr = static_cast<f32>(current_layer.in) / static_cast<f32>(s.frame_max + 1) <= view_right,
|
||||
l_in = l_le_right_extr && static_cast<f32>(current_layer.in) / static_cast<f32>(s.frame_max + 1) >= view_left,
|
||||
l_ge_left_extr = static_cast<f32>(current_layer.out) / static_cast<f32>(s.frame_max + 1) >= view_left,
|
||||
l_out = l_ge_left_extr && static_cast<f32>(current_layer.out) / static_cast<f32>(s.frame_max + 1) <= view_right;
|
||||
f32 in_pos = TimelineFrameToScreenView(view_left, view_amt, view_width, current_layer.in, s.frame_max),
|
||||
out_pos = TimelineFrameToScreenView(view_left, view_amt, view_width, current_layer.out, s.frame_max);
|
||||
ImGui::PushID(0);
|
||||
if (l_in) {
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + in_pos);
|
||||
static f32 l_in_old;
|
||||
|
@ -949,21 +963,22 @@ namespace K::UI {
|
|||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(0.0f, 0.0f);
|
||||
}
|
||||
ImGui::PushID(0);
|
||||
ImGui::Button(current_layer.name.c_str(),
|
||||
{std::min(out_pos + fr_step, view_width) - static_cast<f32>(l_in) * in_pos - layer_bound_width * static_cast<f32>(l_in + l_out), view_height});
|
||||
static u32 in_old, out_old;
|
||||
if (ImGui::IsItemClicked()) {
|
||||
in_old = current_layer.in;
|
||||
out_old = current_layer.out;
|
||||
if (l_le_right_extr && l_ge_left_extr) {
|
||||
ImGui::Button(current_layer.name.c_str(),
|
||||
{std::min(out_pos + fr_step, view_width) - static_cast<f32>(l_in) * in_pos -
|
||||
layer_bound_width * static_cast<f32>(l_in + l_out), view_height});
|
||||
static u32 in_old, out_old;
|
||||
if (ImGui::IsItemClicked()) {
|
||||
in_old = current_layer.in;
|
||||
out_old = current_layer.out;
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
i32 off = static_cast<i32>(std::trunc(ImGui::GetMouseDragDelta().x / fr_step));
|
||||
off = std::max(-static_cast<i32>(in_old), off);
|
||||
current_layer.in = in_old + off;
|
||||
current_layer.out = out_old + off;
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemActive()) {
|
||||
i32 off = static_cast<i32>(std::trunc(ImGui::GetMouseDragDelta().x / fr_step));
|
||||
off = std::max(-static_cast<i32>(in_old), off);
|
||||
current_layer.in = in_old + off;
|
||||
current_layer.out = out_old + off;
|
||||
}
|
||||
ImGui::PopID();
|
||||
if (l_out) {
|
||||
static f32 r_out_old;
|
||||
ImGui::SameLine(0.0f, 0.0f);
|
||||
|
@ -980,6 +995,7 @@ namespace K::UI {
|
|||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2{tl_init_pos.x, init_y} - style.CellPadding);
|
||||
ImGui::InvisibleButton("##TL_BG", ImVec2{ view_width + style.CellPadding.x * 2, row_height + style.CellPadding.y});
|
||||
|
@ -992,6 +1008,9 @@ namespace K::UI {
|
|||
if (layer_open) {
|
||||
i32 j = 0;
|
||||
for (auto &u: current_layer.track.uniforms) {
|
||||
if (u.status != K_U_Exposed)
|
||||
continue;
|
||||
|
||||
ImGui::PushID(j);
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
|
@ -1017,9 +1036,9 @@ namespace K::UI {
|
|||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>) {
|
||||
if (ImGui::IsItemActive())
|
||||
s.plugboard.links_pos[arg].sinks.push_back(io.MousePos);
|
||||
links_pos[arg].sinks.push_back(io.MousePos);
|
||||
else
|
||||
s.plugboard.links_pos[arg].sinks.push_back(ImGui::GetCursorScreenPos() +
|
||||
links_pos[arg].sinks.push_back(ImGui::GetCursorScreenPos() +
|
||||
ImVec2{ImGui::GetFrameHeight() / 2,
|
||||
-ImGui::GetFrameHeight() / 2 -
|
||||
style.ItemInnerSpacing.y});
|
||||
|
@ -1027,9 +1046,11 @@ namespace K::UI {
|
|||
else if (ImGui::IsItemActive()) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_LeftShift)) {
|
||||
auto& c = s.plugboard.nodes.Store(Plugboard::Chain{});
|
||||
c.extra.chain.segments.emplace_back(s.current_frame, std::get<Plugboard::T_Map<Plugboard::T_Float>::type>(arg));
|
||||
c.extra.chain.selected.push_back(0);
|
||||
Plugboard::Connect(u.connection.p, u.connection.index, &c, 0);
|
||||
Plugboard::Connect(&c, 0, &s.plugboard.in, 0);
|
||||
auto& nodes = s.plugboard.out.show_nodes[u.connection.index];
|
||||
Plugboard::Connect(&c, 0, &s.plugboard.in_instance, 0);
|
||||
auto& nodes = s.plugboard.show_nodes[u.connection.index];
|
||||
nodes.clear();
|
||||
nodes.emplace_back(&c, 0);
|
||||
}
|
||||
|
@ -1044,10 +1065,10 @@ namespace K::UI {
|
|||
|
||||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
auto u_flags = ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_FramePadding;
|
||||
auto u_flags = ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_FramePadding | ImGuiTreeNodeFlags_DefaultOpen;
|
||||
if (connected_v.index() != 1)
|
||||
u_flags |= ImGuiTreeNodeFlags_Leaf;
|
||||
bool uniform_open = ImGui::TreeNodeEx(u.name.c_str(),u_flags);
|
||||
bool uniform_open = ImGui::TreeNodeEx(u.name.c_str(), u_flags);
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
|
||||
|
@ -1080,7 +1101,7 @@ namespace K::UI {
|
|||
ImPlot::PlotLineG("v", [](int idx, void* user_data) -> ImPlotPoint {
|
||||
PlotInfo i = *(PlotInfo*)user_data;
|
||||
f32 x = i.begin + (i.end - i.begin) * static_cast<f32>(idx) / static_cast<f32>(i.samples);
|
||||
CompState ss = i.s;
|
||||
CompositionState ss = i.s;
|
||||
ss.current_frame = static_cast<u64>(std::round(x));
|
||||
bool good;
|
||||
Vector<Plugboard::ConnectInfo> info;
|
||||
|
@ -1099,7 +1120,7 @@ namespace K::UI {
|
|||
tl_bg_handler();
|
||||
|
||||
if (uniform_open && connected_v.index() == 1) {
|
||||
for (const auto& info: s.plugboard.out.show_nodes[u.connection.index]) {
|
||||
for (const auto& info: s.plugboard.show_nodes[u.connection.index]) {
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_None, row_height);
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
|
@ -1227,13 +1248,16 @@ namespace K::UI {
|
|||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
else for (auto &u: current_layer.track.uniforms)
|
||||
std::visit([table_left, &s](auto &&arg) {
|
||||
else for (auto& u: current_layer.track.uniforms) {
|
||||
if (u.status != K_U_Exposed)
|
||||
continue;
|
||||
std::visit([table_left](auto &&arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>)
|
||||
s.plugboard.links_pos[arg].sinks.push_back( // make nodes connect to collapsed layer row
|
||||
links_pos[arg].sinks.push_back( // make nodes connect to collapsed layer row
|
||||
{table_left, ImGui::GetCursorScreenPos().y - row_height / 2.0f});
|
||||
}, std::visit([&u](auto&& arg) -> auto& { return arg->in[u.connection.index].value; }, u.connection.p));
|
||||
}
|
||||
|
||||
|
||||
ImGui::PopStyleVar(); // FramePadding
|
||||
|
@ -1276,7 +1300,7 @@ namespace K::UI {
|
|||
ImGui::SetCursorScreenPos(nodes_begin);
|
||||
if (ImGui::BeginChild("Node Connection Overlay", {table_left - ImGui::GetWindowPos().x, 0.0f}, false, ImGuiWindowFlags_NoInputs)) {
|
||||
auto *window = ImGui::GetCurrentWindow();
|
||||
for (auto &[_, link]: s.plugboard.links_pos)
|
||||
for (auto &[_, link]: links_pos)
|
||||
for (auto &sink: link.sinks)
|
||||
window->DrawList->AddBezierCubic(link.source,
|
||||
{link.source.x + 60.0f, link.source.y},
|
||||
|
@ -1446,7 +1470,7 @@ namespace K::UI {
|
|||
ImPlot::PlotLineG("v", [](int idx, void *user_data) -> ImPlotPoint {
|
||||
PlotInfo i = *(PlotInfo *) user_data;
|
||||
f32 x = i.begin + (i.end - i.begin) * static_cast<f32>(idx) / static_cast<f32>(i.samples);
|
||||
CompState ss = i.s;
|
||||
CompositionState ss = i.s;
|
||||
ss.current_frame = static_cast<u64>(x);
|
||||
bool good;
|
||||
Vector<Plugboard::ConnectInfo> info;
|
||||
|
@ -1536,7 +1560,7 @@ namespace K::UI {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
void Layer(CompState& s) {
|
||||
void Layer(CompositionState& s) {
|
||||
struct TextFilters { static int VariableName(ImGuiInputTextCallbackData *data) {
|
||||
return !(data->EventChar < 256 &&
|
||||
((data->EventChar >= 'a' && data->EventChar <= 'z') ||
|
||||
|
@ -1544,7 +1568,7 @@ namespace K::UI {
|
|||
(data->EventChar >= '0' && data->EventChar <= '9') ||
|
||||
data->EventChar == '_'));
|
||||
} };
|
||||
if (ImGui::Begin("Layer", &draw_layer)) {
|
||||
if (ImGui::Begin("Layer")) {
|
||||
if (s.active == -1)
|
||||
ImGui::TextUnformatted("No active layer.");
|
||||
else {
|
||||
|
@ -1554,8 +1578,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, ExpandVariant(
|
||||
static_cast<ShaderGraph::Type>(type_current)));
|
||||
s.layers[s.active].track.AddUniform("u_" + name, ExpandVariant(static_cast<ShaderGraph::Type>(type_current)), K_U_Exposed);
|
||||
VisualTrack::ExposeUniform(s, s.layers[s.active].track.uniforms.back());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
@ -1575,8 +1598,10 @@ namespace K::UI {
|
|||
ImGui::TableHeadersRow();
|
||||
i32 i = 0;
|
||||
for (auto it = s.layers[s.active].track.uniforms.begin(); it != s.layers[s.active].track.uniforms.end();) {
|
||||
if (std::visit([](auto&& arg){ return arg == nullptr; }, it->connection.p))
|
||||
if (it->status != K_U_Exposed) {
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::PushID(i++);
|
||||
|
@ -1611,14 +1636,15 @@ namespace K::UI {
|
|||
if (ImGui::BeginTabItem("Samplers")) {
|
||||
static String name{};
|
||||
if (ImGui::Button("Add Sampler") && !name.empty() && !isdigit(name[0])) {
|
||||
s.layers[s.active].track.AddSampler(name);
|
||||
s.layers[s.active].track.AddSampler("s_" + name);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##SamplerName", &name, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::VariableName);
|
||||
|
||||
if (ImGui::BeginTable("Samplers", 3, ImGuiTableFlags_Borders)) {
|
||||
if (ImGui::BeginTable("Samplers", 4, ImGuiTableFlags_Borders)) {
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("Resource", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Dims via", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("Resource", ImGuiTableColumnFlags_NoSort);
|
||||
ImGui::TableSetupColumn("##del", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableHeadersRow();
|
||||
i32 i = 0;
|
||||
|
@ -1628,7 +1654,19 @@ namespace K::UI {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(it->name.c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", it->resource->filename.c_str());
|
||||
ImGui::Text("%s%s", it->name.c_str(), "_dims");
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::BeginCombo("##source", it->resource->filename.c_str())) {
|
||||
for (auto& [file, res_v] : Resource::resources)
|
||||
if (auto *res = std::get_if<Resource::Resource<Resource::K_R_Still>>(&res_v)) {
|
||||
const bool is_selected = it->resource == res;
|
||||
if (ImGui::Selectable(file.c_str(), is_selected)) {
|
||||
it->resource = res;
|
||||
it->dims->val = ShaderGraph::XY{static_cast<f32>(res->w), static_cast<f32>(res->h)};
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Button("X")) {
|
||||
bgfx::destroy(it->handle);
|
||||
|
@ -1652,8 +1690,8 @@ namespace K::UI {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
void Interpolation(CompState& s) {
|
||||
if (ImGui::Begin("Interpolation", &draw_interpolation, ImGuiWindowFlags_NoScrollbar)) {
|
||||
void Interpolation(CompositionState& s) {
|
||||
if (ImGui::Begin("Interpolation", nullptr, ImGuiWindowFlags_NoScrollbar)) {
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
static Plugboard::K_Interpolation type_current = Plugboard::K_I_CubicBezier;
|
||||
|
@ -1663,8 +1701,10 @@ namespace K::UI {
|
|||
|
||||
if (ImGui::Button("Apply"))
|
||||
for (auto& layer : s.layers)
|
||||
for (auto& u : layer.track.uniforms)
|
||||
for (auto& n : s.plugboard.out.show_nodes[u.connection.index]) {
|
||||
for (auto& u : layer.track.uniforms) {
|
||||
if (u.status != K_U_Exposed)
|
||||
continue;
|
||||
for (auto& n : s.plugboard.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);
|
||||
|
@ -1674,6 +1714,7 @@ namespace K::UI {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
|
@ -1784,6 +1825,42 @@ namespace K::UI {
|
|||
|
||||
void Assets() {
|
||||
if (ImGui::Begin("Assets", &draw_assets)) {
|
||||
if (ImGui::Button("Load")) {
|
||||
static const SDL_DialogFileFilter import_filters[] = {
|
||||
{ "PNG images", "png" },
|
||||
{ "JPEG images", "jpg;jpeg" },
|
||||
{ "All images", "png;jpg;jpeg" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
struct ImportCallback {
|
||||
static void SDLCALL f(void *userdata, const char* const* filelist, i32 filter) {
|
||||
if (!filelist) {
|
||||
Log(K_L_Error, "{}", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
else if (!*filelist) // The user did not select any file. Most likely, the dialog was canceled.
|
||||
return;
|
||||
|
||||
while (*filelist) {
|
||||
Resource::Load<Resource::K_R_Still>(*filelist);
|
||||
filelist++;
|
||||
}
|
||||
|
||||
if (filter == -1) {
|
||||
Log(K_L_Info, "Platform does not support fetching file filters.");
|
||||
}
|
||||
else if (filter < SDL_arraysize(import_filters)) {
|
||||
SDL_Log("The filter selected by the user is '%s' (%s).",
|
||||
import_filters[filter].pattern, import_filters[filter].name);
|
||||
}
|
||||
else {
|
||||
SDL_Log("The user did not select any filter.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SDL_ShowOpenFileDialog(ImportCallback::f, nullptr, app_state.window, import_filters, 3, nullptr, true);
|
||||
}
|
||||
if (ImGui::BeginTable("Assets", 3, ImGuiTableFlags_Borders)) {
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
|
||||
|
@ -1791,7 +1868,7 @@ namespace K::UI {
|
|||
ImGui::TableHeadersRow();
|
||||
|
||||
i32 i = 0;
|
||||
for (auto& comp : app_state.compositions) {
|
||||
for (auto& comp : app_state.project.compositions) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::PushID(i++);
|
||||
ImGui::TableNextColumn();
|
||||
|
@ -1826,10 +1903,10 @@ namespace K::UI {
|
|||
}
|
||||
ImGui::TableNextColumn();
|
||||
if constexpr (std::is_same_v<T, Resource::Resource<Resource::K_R_ShaderProgram>>) {
|
||||
ImGui::Text("%s", fmt::format("{:%Y-%m-%d %X}", std::chrono::file_clock::to_sys(arg.frag_last_updated)).c_str());
|
||||
ImGui::Text("%s", fmt::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::floor<std::chrono::seconds>(std::chrono::file_clock::to_sys(arg.frag_last_updated))).c_str());
|
||||
}
|
||||
else {
|
||||
ImGui::Text("%s", fmt::format("{:%Y-%m-%d %X}", std::chrono::file_clock::to_sys(arg.last_updated)).c_str());
|
||||
ImGui::Text("%s", fmt::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::floor<std::chrono::seconds>(std::chrono::file_clock::to_sys(arg.last_updated))).c_str());
|
||||
}
|
||||
}, res);
|
||||
ImGui::PopID();
|
||||
|
@ -1854,7 +1931,7 @@ namespace K::UI {
|
|||
|
||||
if (draw_assets) Assets();
|
||||
|
||||
auto& comp = app_state.compositions[app_state.inspecting_composition];
|
||||
auto& comp = app_state.project.compositions[app_state.project.inspecting_composition];
|
||||
if (draw_viewport) Viewport(comp);
|
||||
if (draw_layer) Layer(comp);
|
||||
if (draw_comp) Composition(comp);
|
||||
|
@ -1918,7 +1995,7 @@ namespace K::UI {
|
|||
}
|
||||
|
||||
bg.pg = Resource::Load<Resource::K_R_ShaderProgram>("Checkerboard")->pg;
|
||||
bg.AddUniform("f_hw", ShaderGraph::Type::T_XYZ);
|
||||
bg.AddUniform("f_hw", ShaderGraph::Type::T_XYZ, K_U_Inactive);
|
||||
|
||||
logo = Resource::Load<Resource::K_R_Still>("Keishiki.png");
|
||||
}
|
||||
|
@ -1927,7 +2004,7 @@ namespace K::UI {
|
|||
bgfx::destroy(bg.uniforms[0].handle);
|
||||
bg.uniforms.erase(bg.uniforms.begin());
|
||||
|
||||
for (auto& comp : app_state.compositions)
|
||||
for (auto& comp : app_state.project.compositions)
|
||||
DestroyViewport(comp);
|
||||
|
||||
ImGui_Implbgfx_Shutdown();
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace K {
|
|||
},val);
|
||||
}
|
||||
|
||||
void VisualTrack::GetFrame(const CompState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16],
|
||||
void VisualTrack::GetFrame(const CompositionState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16],
|
||||
f32 view[16], f32 transform[16]) {
|
||||
bgfx::setViewMode(view_id, bgfx::ViewMode::Sequential);
|
||||
bgfx::setViewClear(view_id, BGFX_CLEAR_COLOR);
|
||||
|
@ -88,8 +88,8 @@ namespace K {
|
|||
|
||||
std::shared_lock lk{Resource::resource_lock};
|
||||
u32 sampler_stage = 0;
|
||||
for (auto& [_name, handle, res] : samplers) {
|
||||
bgfx::setTexture(sampler_stage++, handle, res->tex);
|
||||
for (auto& [_name, handle, res, _u] : samplers) {
|
||||
bgfx::setTexture(sampler_stage++, handle, res->tex, BGFX_SAMPLER_UVW_BORDER);
|
||||
}
|
||||
|
||||
Graphics::DrawQuad(view_id, transform, BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A, pg);
|
||||
|
@ -101,7 +101,7 @@ namespace K {
|
|||
"#include <bgfx_shader.sh>\n"
|
||||
"#include <shaderlib.sh>\n";
|
||||
u32 sampler_loc = 0;
|
||||
for (auto& [name, _tex, _res] : samplers) {
|
||||
for (auto& [name, _tex, _res, _u] : samplers) {
|
||||
f << "SAMPLER2D(" << name << ", " << sampler_loc++ << ");\n";
|
||||
}
|
||||
for (auto& u : uniforms) {
|
||||
|
@ -150,18 +150,21 @@ namespace K {
|
|||
samplers.clear();
|
||||
}
|
||||
|
||||
void VisualTrack::ExposeUniform(CompState& s, Uniform& uu) {
|
||||
uu.connection = {&s.plugboard.out, static_cast<u32>(s.plugboard.out.in.size())};
|
||||
void VisualTrack::ExposeUniform(CompositionState& s, Uniform& uu) {
|
||||
uu.connection = {&s.plugboard.out_instance, static_cast<u32>(s.plugboard.out_instance.in.size())};
|
||||
// this is shaky and bug prone -- relies on the shader types being in line with plugboard types
|
||||
s.plugboard.out.in.push_back(Plugboard::InSocket{ uu.name, Plugboard::Type(uu.val.index()), ShaderValToPlugboard(uu.val)});
|
||||
s.plugboard.out.show_nodes.emplace_back();
|
||||
s.plugboard.out_instance.in.push_back(Plugboard::InSocket{ uu.name, Plugboard::Type(uu.val.index()), ShaderValToPlugboard(uu.val)});
|
||||
s.plugboard.show_nodes.emplace_back();
|
||||
}
|
||||
|
||||
void VisualTrack::ExposeUniform(CompState& s, u32 i) {
|
||||
void VisualTrack::ExposeUniform(CompositionState& s, u32 i) {
|
||||
ExposeUniform(s, uniforms[i]);
|
||||
}
|
||||
|
||||
void VisualTrack::HideUniform(CompState& s, Uniform& uu) {
|
||||
void VisualTrack::HideUniform(CompositionState& s, Uniform& uu) {
|
||||
if (uu.status != K_U_Exposed)
|
||||
return;
|
||||
|
||||
Plugboard::Disconnect(uu.connection.p, uu.connection.index);
|
||||
|
||||
// decrement indices of uniforms referencing CompositionOut whose index is greater
|
||||
|
@ -170,22 +173,22 @@ namespace K {
|
|||
if (u_other.connection.index > uu.connection.index)
|
||||
u_other.connection.index--;
|
||||
|
||||
if (std::holds_alternative<Plugboard::ConnectInfo>(s.plugboard.out.in[uu.connection.index].value)) {
|
||||
Plugboard::Disconnect(s.plugboard.out, uu.connection.index);
|
||||
if (std::holds_alternative<Plugboard::ConnectInfo>(s.plugboard.out_instance.in[uu.connection.index].value)) {
|
||||
Plugboard::Disconnect(s.plugboard.out_instance, uu.connection.index);
|
||||
}
|
||||
|
||||
s.plugboard.out.in.erase(s.plugboard.out.in.begin() + uu.connection.index);
|
||||
s.plugboard.out_instance.in.erase(s.plugboard.out_instance.in.begin() + uu.connection.index);
|
||||
uu.connection = {(Plugboard::Add*)(nullptr), 0};
|
||||
}
|
||||
|
||||
void VisualTrack::AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val) {
|
||||
void VisualTrack::AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val, UniformStatus init) {
|
||||
for (auto& u : uniforms)
|
||||
if (u.name == s)
|
||||
return;
|
||||
for (auto& ss : samplers)
|
||||
if (ss.name == s)
|
||||
return;
|
||||
uniforms.emplace_back(Uniform{s, bgfx::createUniform(("__" + s).c_str(), bgfx::UniformType::Vec4), val, {{}, 0}});
|
||||
uniforms.emplace_back(Uniform{s, bgfx::createUniform(("__" + s).c_str(), bgfx::UniformType::Vec4), val, {{}, 0}, init});
|
||||
}
|
||||
|
||||
void VisualTrack::AddSampler(const String& s) {
|
||||
|
@ -195,6 +198,7 @@ namespace K {
|
|||
for (auto& ss : samplers)
|
||||
if (ss.name == s)
|
||||
return;
|
||||
samplers.emplace_back(Sampler{s, bgfx::createUniform(s.c_str(), bgfx::UniformType::Sampler), Resource::fallback_still});
|
||||
AddUniform(s + "_dims", ShaderGraph::XY{static_cast<f32>(Resource::fallback_still->w), static_cast<f32>(Resource::fallback_still->h)}, K_U_SamplerDims);
|
||||
samplers.emplace_back(Sampler{s, bgfx::createUniform(s.c_str(), bgfx::UniformType::Sampler), Resource::fallback_still, &uniforms.back()});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,10 +39,11 @@ namespace K {
|
|||
|
||||
template <typename... Ts>
|
||||
inline void Log(LogLevel level, fmt::format_string<Ts...> fmt, Ts&&... args) {
|
||||
fmt::print(level > K_L_Info ? stderr : stdout, "[{}] Keishiki: ", LogLevelNames[level]);
|
||||
fmt::print(fmt, std::forward<Ts>(args)...);
|
||||
fmt::print("\n");
|
||||
auto& t = level > K_L_Info ? stderr : stdout;
|
||||
fmt::print(t, "[{}] Keishiki: ", LogLevelNames[level]);
|
||||
fmt::print(t, fmt, std::forward<Ts>(args)...);
|
||||
fmt::print(t, "\n");
|
||||
}
|
||||
|
||||
struct CompState; // fwd declared -- Keishiki.h <-> VisualTrack.h has dependency cycle
|
||||
struct CompositionState; // fwd declared -- Keishiki.h <-> VisualTrack.h has dependency cycle
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace K {
|
|||
u64 in, out;
|
||||
};
|
||||
|
||||
struct CompState {
|
||||
struct CompositionState {
|
||||
String name;
|
||||
// Time
|
||||
u64 current_frame;
|
||||
|
@ -33,10 +33,15 @@ namespace K {
|
|||
Plugboard::Plugboard plugboard;
|
||||
};
|
||||
|
||||
struct ProjectState {
|
||||
i32 inspecting_composition = -1;
|
||||
Vector<CompositionState> compositions{};
|
||||
};
|
||||
|
||||
extern struct AppState {
|
||||
SDL_Window *window = nullptr;
|
||||
i32 window_width = 2300,
|
||||
window_height = 1300;
|
||||
i32 window_width = 2200,
|
||||
window_height = 1200;
|
||||
|
||||
std::atomic_bool running {true};
|
||||
|
||||
|
@ -44,7 +49,6 @@ namespace K {
|
|||
u32 bgfx_frame{};
|
||||
u32 n_views{};
|
||||
|
||||
i32 inspecting_composition = -1;
|
||||
Vector<CompState> compositions{};
|
||||
ProjectState project{};
|
||||
} app_state; // global !
|
||||
}
|
||||
|
|
|
@ -86,8 +86,8 @@ namespace K::Plugboard {
|
|||
struct AbsoluteValue;
|
||||
struct Interpolation;
|
||||
struct Chain;
|
||||
struct CompositionIn;
|
||||
struct CompositionOut;
|
||||
struct GroupIn;
|
||||
struct GroupOut;
|
||||
|
||||
enum K_P_Nodes {
|
||||
K_P_Add = 0,
|
||||
|
@ -144,8 +144,8 @@ namespace K::Plugboard {
|
|||
AbsoluteValue,
|
||||
Interpolation,
|
||||
Chain,
|
||||
CompositionIn,
|
||||
CompositionOut>;
|
||||
GroupIn,
|
||||
GroupOut>;
|
||||
|
||||
using NodeInstanceP = NodeVar::NodeInstanceP;
|
||||
|
||||
|
@ -353,222 +353,220 @@ namespace K::Plugboard {
|
|||
|
||||
T_Map<T_Count>::type ConvertValue(const T_Map<T_Count>::type& v, Type target, bool& good);
|
||||
|
||||
T_Map<T_Count>::type Eval(const CompState& s, const ConnectInfo& info);
|
||||
T_Map<T_Count>::type Eval(const CompositionState& s, const ConnectInfo& info);
|
||||
|
||||
struct LinksFromSource {
|
||||
ImVec2 source;
|
||||
Vector<ImVec2> sinks;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchAdd(const CompState& s, const Add& n);
|
||||
T_Map<T_Count>::type FetchAdd(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Add&), 1> fetch = {FetchAdd };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchNegate(const CompState& s, const Negate& n);
|
||||
T_Map<T_Count>::type FetchNegate(const CompositionState& s, const Negate& n);
|
||||
struct Negate {
|
||||
const static char constexpr *name = static_cast<const char*>("Negate");
|
||||
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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Negate&), 1> fetch = {FetchNegate };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchSubtract(const CompState& s, const Subtract& n);
|
||||
T_Map<T_Count>::type FetchSubtract(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Subtract&), 1>fetch = {FetchSubtract };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchMultiply(const CompState& s, const Multiply& n);
|
||||
T_Map<T_Count>::type FetchMultiply(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Multiply&), 1> fetch = {FetchMultiply };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchDivide(const CompState& s, const Divide& n);
|
||||
T_Map<T_Count>::type FetchDivide(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Divide&), 1> fetch = {FetchDivide };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchSign(const CompState& s, const Sign& n);
|
||||
T_Map<T_Count>::type FetchSign(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Sign&), 1> fetch = {FetchSign };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchSin(const CompState& s, const Sin& n);
|
||||
T_Map<T_Count>::type FetchSin(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Sin&), 1> fetch = {FetchSin };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchCos(const CompState& s, const Cos& n);
|
||||
T_Map<T_Count>::type FetchCos(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Cos&), 1> fetch = {FetchCos };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchTan(const CompState& s, const Tan& n);
|
||||
T_Map<T_Count>::type FetchTan(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Tan&), 1> fetch = {FetchTan };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchArcsin(const CompState& s, const Arcsin& n);
|
||||
T_Map<T_Count>::type FetchArcsin(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Arcsin&), 1> fetch = {FetchArcsin };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchArccos(const CompState& s, const Arccos& n);
|
||||
T_Map<T_Count>::type FetchArccos(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Arccos&), 1> fetch = {FetchArccos };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchArctan(const CompState& s, const Arctan& n);
|
||||
T_Map<T_Count>::type FetchArctan(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Arctan&), 1> fetch = {FetchArctan };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchAtan2(const CompState& s, const Atan2& n);
|
||||
T_Map<T_Count>::type FetchAtan2(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Atan2&), 1> fetch = {FetchAtan2 };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchMinimum(const CompState& s, const Minimum& n);
|
||||
T_Map<T_Count>::type FetchMinimum(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Minimum&), 1> fetch = {FetchMinimum };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchMaximum(const CompState& s, const Maximum& n);
|
||||
T_Map<T_Count>::type FetchMaximum(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Maximum&), 1> fetch = {FetchMaximum };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchPower(const CompState& s, const Power& n);
|
||||
T_Map<T_Count>::type FetchPower(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Power&), 1> fetch = {FetchPower };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchSquareRoot(const CompState& s, const SquareRoot& n);
|
||||
T_Map<T_Count>::type FetchSquareRoot(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const SquareRoot&), 1> fetch = {FetchSquareRoot };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchNaturalLogarithm(const CompState& s, const NaturalLogarithm& n);
|
||||
T_Map<T_Count>::type FetchNaturalLogarithm(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const NaturalLogarithm&), 1> fetch = {FetchNaturalLogarithm };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchAbsoluteValue(const CompState& s, const AbsoluteValue& n);
|
||||
T_Map<T_Count>::type FetchAbsoluteValue(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const AbsoluteValue&), 1> fetch = {FetchAbsoluteValue };
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchInterpolation(const CompState& s, const Interpolation& n);
|
||||
T_Map<T_Count>::type FetchInterpolation(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const Interpolation&), 1> fetch = {FetchInterpolation };
|
||||
ImVec2 pos;
|
||||
InterpolationExtra extra{};
|
||||
void Draw();
|
||||
};
|
||||
|
||||
T_Map<T_Count>::type FetchChain(const CompState& s, const Chain& n);
|
||||
T_Map<T_Count>::type FetchChain(const CompositionState& 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 };
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, 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 };
|
||||
T_Map<T_Count>::type FetchCompositionInFrame(const CompositionState& s, const GroupIn& n);
|
||||
T_Map<T_Count>::type FetchCompositionInAppTicks(const CompositionState& s, const GroupIn& n);
|
||||
struct GroupIn {
|
||||
const static char constexpr *name = static_cast<const char*>("Group In");
|
||||
std::array<InSocket, 0> in{};
|
||||
Vector<OutSocket> out{};
|
||||
Vector<T_Map<T_Count>::type (*)(const CompositionState&, const GroupIn&)> fetch;
|
||||
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 = {};
|
||||
struct GroupOut {
|
||||
const static char constexpr *name = static_cast<const char*>("Group Out");
|
||||
Vector<InSocket> in{};
|
||||
std::array<OutSocket, 0> out{};
|
||||
std::array<T_Map<T_Count>::type (*)(const CompositionState&, const GroupOut&), 0> fetch = {};
|
||||
ImVec2 pos;
|
||||
};
|
||||
|
||||
|
@ -648,18 +646,29 @@ namespace K::Plugboard {
|
|||
AbsoluteValue,
|
||||
Interpolation,
|
||||
Chain,
|
||||
CompositionIn,
|
||||
CompositionOut
|
||||
GroupIn,
|
||||
GroupOut
|
||||
>;
|
||||
|
||||
struct Plugboard {
|
||||
struct Group {
|
||||
const static char constexpr *name = static_cast<const char*>("Group");
|
||||
Vector<InSocket> in;
|
||||
Vector<OutSocket> out;
|
||||
Vector<T_Map<T_Count>::type (*)(const CompositionState&, const GroupIn&)> fetch;
|
||||
ImVec2 pos;
|
||||
|
||||
GroupIn in_instance;
|
||||
GroupOut out_instance;
|
||||
|
||||
NodeList 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
|
||||
CompositionIn in;
|
||||
CompositionOut out;
|
||||
|
||||
Vector<NodeInstanceP> selected_nodes{};
|
||||
};
|
||||
|
||||
struct Plugboard : Group {
|
||||
Vector<Vector<ConnectInfo>> show_nodes;
|
||||
Plugboard();
|
||||
void AddInSocket(const String& s, Type t);
|
||||
void AddOutSocket(const String& s, Type t, T_Map<T_Count>::type(*fetch)(const CompositionState&, const GroupIn&));
|
||||
void RecollectChains();
|
||||
};
|
||||
|
||||
|
|
|
@ -83,5 +83,7 @@ namespace K::Resource {
|
|||
Resource<T> *Load(const std::filesystem::path& p);
|
||||
|
||||
bgfx::ProgramHandle FetchUnmanagedShaderProgram(const String& shader_name);
|
||||
|
||||
void SaveCurrentProject();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace K::UI {
|
|||
void Init(SDL_Window *window);
|
||||
void Draw();
|
||||
void Shutdown();
|
||||
void SetupViewport(CompState& s);
|
||||
void DestroyViewport(CompState& s);
|
||||
void SetupViewport(CompositionState& s);
|
||||
void DestroyViewport(CompositionState& s);
|
||||
void SetLogoView();
|
||||
}
|
||||
|
|
|
@ -8,17 +8,26 @@
|
|||
#include "Plugboard.h"
|
||||
|
||||
namespace K {
|
||||
enum UniformStatus {
|
||||
K_U_Inactive = 0,
|
||||
K_U_Exposed,
|
||||
K_U_SamplerDims,
|
||||
K_U_Count
|
||||
};
|
||||
|
||||
struct Uniform {
|
||||
String name;
|
||||
bgfx::UniformHandle handle;
|
||||
ShaderGraph::T_Map<ShaderGraph::T_Count>::type val;
|
||||
Plugboard::ConnectInfo connection;
|
||||
UniformStatus status = K_U_Inactive;
|
||||
};
|
||||
|
||||
struct Sampler {
|
||||
String name;
|
||||
bgfx::UniformHandle handle;
|
||||
Resource::Resource<Resource::K_R_Still> *resource;
|
||||
Uniform *dims;
|
||||
};
|
||||
|
||||
ShaderGraph::T_Map<ShaderGraph::T_Count>::type PlugboardValToShader(const Plugboard::T_Map<Plugboard::T_Count>::type& val);
|
||||
|
@ -31,13 +40,13 @@ namespace K {
|
|||
String shader;
|
||||
Vector<Uniform> uniforms;
|
||||
Vector<Sampler> samplers;
|
||||
void GetFrame(const CompState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16],
|
||||
void GetFrame(const CompositionState& s, u32 view_id, bgfx::FrameBufferHandle fb, u32 w, u32 h, f32 proj[16],
|
||||
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 ExposeUniform(CompositionState& s, Uniform& uu);
|
||||
void ExposeUniform(CompositionState& s, u32 i);
|
||||
static void HideUniform(CompositionState& s, Uniform& uu);
|
||||
|
||||
void AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val);
|
||||
void AddUniform(const String& s, ShaderGraph::T_Map<ShaderGraph::T_Count>::type&& val, UniformStatus init);
|
||||
void AddSampler(const String& s);
|
||||
|
||||
void Compile();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
- [Dear ImGui](https://github.com/ocornut/imgui)
|
||||
- [fmt](https://github.com/fmtlib/fmt)
|
||||
- [FreeType](https://freetype.org/)
|
||||
- [Glaze](https://github.com/stephenberry/glaze)
|
||||
- [imgui_impl_bgfx](https://gist.github.com/pr0g/aff79b71bf9804ddb03f39ca7c0c3bbb)
|
||||
- [ImPlot](https://github.com/epezent/implot)
|
||||
- [SDL2](https://www.libsdl.org/)
|
||||
|
|
3
TODO.md
3
TODO.md
|
@ -23,8 +23,6 @@
|
|||
|
||||
# Later
|
||||
## IO
|
||||
- File dialogues pending SDL3
|
||||
- https://wiki.libsdl.org/SDL3/CategoryDialog
|
||||
- Clipboard pending SDL3
|
||||
- OIIO output for more than PNG's
|
||||
- don't care about video export -- leave it for ffmpeg
|
||||
|
@ -45,4 +43,3 @@
|
|||
- Wait for SDL3!
|
||||
- SDL_mixer will be able to do all of wav ogg flac mp3 opus, we live in good times
|
||||
- output needs to be handled differently (if we care at all -- likely not)
|
||||
z
|
Loading…
Add table
Reference in a new issue