comps ok
This commit is contained in:
parent
5ca9c91098
commit
cacc2d48ca
11 changed files with 427 additions and 361 deletions
136
Keishiki/Entry.cpp
Normal file
136
Keishiki/Entry.cpp
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
#include "Keishiki.h"
|
||||||
|
#include "Graphics.h"
|
||||||
|
#include "UI.h"
|
||||||
|
|
||||||
|
#if BX_PLATFORM_LINUX && WL_EGL_PLATFORM
|
||||||
|
#include <wayland-egl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_timer.h>
|
||||||
|
|
||||||
|
#include <bgfx/bgfx.h>
|
||||||
|
#include <bgfx/platform.h>
|
||||||
|
|
||||||
|
#include "backends/imgui_impl_sdl3.h"
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
namespace K {
|
||||||
|
|
||||||
|
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_HIGH_PIXEL_DENSITY);
|
||||||
|
SDL_SetWindowResizable(app_state.window, true);
|
||||||
|
|
||||||
|
if (app_state.window == nullptr) {
|
||||||
|
Log(K_L_Error, "{}", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bgfx::Init bgfxInit;
|
||||||
|
bgfxInit.type = bgfx::RendererType::Count; // Automatically choose a renderer.
|
||||||
|
bgfxInit.resolution.width = app_state.window_width;
|
||||||
|
bgfxInit.resolution.height = app_state.window_height;
|
||||||
|
bgfxInit.resolution.reset = BGFX_RESET_VSYNC;
|
||||||
|
|
||||||
|
#if BX_PLATFORM_WINDOWS
|
||||||
|
bgfxInit.platformData.nwh = SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
||||||
|
#elif BX_PLATFORM_OSX
|
||||||
|
bgfxInit.platformData.nwh = SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
|
||||||
|
bgfx::renderFrame();
|
||||||
|
#elif BX_PLATFORM_LINUX
|
||||||
|
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
|
||||||
|
bgfxInit.platformData.ndt = SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
|
||||||
|
bgfxInit.platformData.nwh = (void*)SDL_GetNumberProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||||
|
}
|
||||||
|
#if WL_EGL_PLATFORM
|
||||||
|
else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
|
||||||
|
bgfxInit.platformData.type = bgfx::NativeWindowHandleType::Wayland;
|
||||||
|
bgfxInit.platformData.ndt = SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
||||||
|
bgfxInit.platformData.nwh = SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER, NULL);
|
||||||
|
if (!bgfxInit.platformData.nwh) {
|
||||||
|
bgfxInit.platformData.nwh = wl_egl_window_create((struct wl_surface *)SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL), app_state.window_width, app_state.window_height);
|
||||||
|
SDL_SetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER, (void*)(uintptr_t)bgfxInit.platformData.nwh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#elif BX_PLATFORM_EMSCRIPTEN
|
||||||
|
bgfxInit.platformData.nwh = (void*)"#canvas";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!bgfx::init(bgfxInit)) {
|
||||||
|
Log(K_L_Error, "bgfx initialization failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!K::Resource::Init())
|
||||||
|
return false;
|
||||||
|
UI::Init(app_state.window);
|
||||||
|
|
||||||
|
if (!K::Graphics::Init()) {
|
||||||
|
Log(K_L_Error, "Graphics init failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Run() {
|
||||||
|
app_state.init_time = SDL_GetTicks();
|
||||||
|
app_state.last_time = app_state.init_time;
|
||||||
|
|
||||||
|
while (app_state.running.load()) {
|
||||||
|
app_state.current_time = SDL_GetTicks();
|
||||||
|
app_state.delta_t = app_state.current_time - app_state.last_time;
|
||||||
|
|
||||||
|
for (SDL_Event current_event; SDL_PollEvent(¤t_event) != 0;) {
|
||||||
|
ImGui_ImplSDL3_ProcessEvent(¤t_event);
|
||||||
|
if (current_event.type == SDL_EVENT_QUIT) {
|
||||||
|
app_state.running.store(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (current_event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UI::Draw();
|
||||||
|
|
||||||
|
app_state.last_time = app_state.current_time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shutdown() {
|
||||||
|
K::Graphics::Shutdown();
|
||||||
|
K::UI::Shutdown();
|
||||||
|
K::Resource::Shutdown();
|
||||||
|
bgfx::shutdown();
|
||||||
|
|
||||||
|
#if !(BX_PLATFORM_LINUX && WL_EGL_PLATFORM)
|
||||||
|
SDL_DestroyWindow(app_state.window);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (!K::Init())
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
K::Run();
|
||||||
|
|
||||||
|
K::Shutdown();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -1,140 +1,67 @@
|
||||||
#include "Keishiki.h"
|
#include "Keishiki.h"
|
||||||
#include "Graphics.h"
|
|
||||||
#include "UI.h"
|
|
||||||
|
|
||||||
#if BX_PLATFORM_LINUX && WL_EGL_PLATFORM
|
|
||||||
#include <wayland-egl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <SDL3/SDL_timer.h>
|
|
||||||
|
|
||||||
#include <bgfx/bgfx.h>
|
|
||||||
#include <bgfx/platform.h>
|
|
||||||
|
|
||||||
#include "backends/imgui_impl_sdl3.h"
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
namespace K {
|
namespace K {
|
||||||
K::AppState app_state;
|
K::AppState app_state;
|
||||||
|
|
||||||
bool Init() {
|
void CompositionState::Setup() {
|
||||||
#if !WL_EGL_PLATFORM
|
composite[0] = bgfx::createTexture2D(width, height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT);
|
||||||
SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "x11");
|
composite[1] = bgfx::createTexture2D(width, height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT);
|
||||||
#endif
|
render = bgfx::createTexture2D(width, height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_RT);
|
||||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
bgfx::Attachment comp{}, comp2{}, ren{};
|
||||||
Log(K_L_Error, "{}", SDL_GetError());
|
comp.init(composite[0], bgfx::Access::Write); // DX 11 requires Write only
|
||||||
return false;
|
comp2.init(composite[1], bgfx::Access::Write); // DX 11 requires Write only
|
||||||
|
ren.init(render, bgfx::Access::ReadWrite);
|
||||||
|
composite_fb[0] = bgfx::createFrameBuffer(1, &comp);
|
||||||
|
composite_fb[1] = bgfx::createFrameBuffer(1, &comp2);
|
||||||
|
render_fb = bgfx::createFrameBuffer(1, &ren);
|
||||||
|
|
||||||
|
bx::mtxOrtho(proj, 0.0f, static_cast<f32>(width), 0.0f, static_cast<f32>(height),
|
||||||
|
0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth);
|
||||||
|
f32 mtx1[16], mtx2[16];
|
||||||
|
bx::mtxTranslate(mtx1, 0, 0, 0.0f);
|
||||||
|
bx::mtxScale(mtx2, static_cast<f32>(width), static_cast<f32>(height), 1.0f);
|
||||||
|
bx::mtxMul(transform, mtx2, mtx1);
|
||||||
|
bx::mtxTranslate(view, 0.f, 0.f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
app_state.window = SDL_CreateWindow("Keishiki", app_state.window_width, app_state.window_height, SDL_WINDOW_HIGH_PIXEL_DENSITY);
|
i32 CompositionState::GetFrame(u32 frame) {
|
||||||
SDL_SetWindowResizable(app_state.window, true);
|
if (frame > frame_max) {
|
||||||
|
Log(K_L_Error, "Comp {} frame out of range! Requesting {}, max {}", name, frame, frame_max);
|
||||||
if (app_state.window == nullptr) {
|
return -1;
|
||||||
Log(K_L_Error, "{}", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bgfx::Init bgfxInit;
|
u64 tmp = current_frame;
|
||||||
bgfxInit.type = bgfx::RendererType::Count; // Automatically choose a renderer.
|
current_frame = frame;
|
||||||
bgfxInit.resolution.width = app_state.window_width;
|
|
||||||
bgfxInit.resolution.height = app_state.window_height;
|
|
||||||
bgfxInit.resolution.reset = BGFX_RESET_VSYNC;
|
|
||||||
|
|
||||||
#if BX_PLATFORM_WINDOWS
|
// Get clean alpha backdrop
|
||||||
bgfxInit.platformData.nwh = SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
bgfx::setViewFrameBuffer(app_state.render_view, composite_fb[0]); // the other fb will be cleared in composite
|
||||||
#elif BX_PLATFORM_OSX
|
bgfx::setViewClear(app_state.render_view, BGFX_CLEAR_COLOR, 0x00000000);
|
||||||
bgfxInit.platformData.nwh = SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL);
|
bgfx::setViewRect(app_state.render_view, 0, 0, width, height);
|
||||||
bgfx::renderFrame();
|
bgfx::touch(app_state.render_view);
|
||||||
#elif BX_PLATFORM_LINUX
|
app_state.render_view++;
|
||||||
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
|
|
||||||
bgfxInit.platformData.ndt = SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
|
|
||||||
bgfxInit.platformData.nwh = (void*)SDL_GetNumberProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
|
||||||
}
|
|
||||||
#if WL_EGL_PLATFORM
|
|
||||||
else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
|
|
||||||
bgfxInit.platformData.type = bgfx::NativeWindowHandleType::Wayland;
|
|
||||||
bgfxInit.platformData.ndt = SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
|
||||||
bgfxInit.platformData.nwh = SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER, NULL);
|
|
||||||
if (!bgfxInit.platformData.nwh) {
|
|
||||||
bgfxInit.platformData.nwh = wl_egl_window_create((struct wl_surface *)SDL_GetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL), app_state.window_width, app_state.window_height);
|
|
||||||
SDL_SetProperty(SDL_GetWindowProperties(app_state.window), SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER, (void*)(uintptr_t)bgfxInit.platformData.nwh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#elif BX_PLATFORM_EMSCRIPTEN
|
|
||||||
bgfxInit.platformData.nwh = (void*)"#canvas";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!bgfx::init(bgfxInit)) {
|
// Render & Composite
|
||||||
Log(K_L_Error, "bgfx initialization failed");
|
i32 layers_done = 0;
|
||||||
return false;
|
for (u32 i = layers.size() - 1; i != u32(-1); i--) {
|
||||||
|
if (std::ranges::find(disabled, i) != disabled.end()) continue;
|
||||||
|
if (current_frame > layers[i].out || current_frame < layers[i].in) continue;
|
||||||
|
|
||||||
|
layers[i].track.GetFrame(*this, app_state.render_view++, render_fb, width,
|
||||||
|
height, proj, view, transform);
|
||||||
|
Graphics::Composite(app_state.render_view++, composite_fb[(layers_done + 1) % 2], composite[layers_done % 2], render, layers[i].mode, width, height, proj, transform);
|
||||||
|
layers_done++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!K::Resource::Init())
|
current_frame = tmp;
|
||||||
return false;
|
return layers_done % 2; // result available in composite[layers_done % 2]
|
||||||
UI::Init(app_state.window);
|
|
||||||
|
|
||||||
if (!K::Graphics::Init()) {
|
|
||||||
Log(K_L_Error, "Graphics init failed");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app_state.project.compositions.emplace_back("default project", 0, 100, 30.0f, 1280, 550);
|
void CompositionState::Destroy() {
|
||||||
app_state.project.inspecting_composition = 0;
|
bgfx::destroy(composite_fb[0]);
|
||||||
UI::SetupViewport(app_state.project.compositions[app_state.project.inspecting_composition]);
|
bgfx::destroy(composite_fb[1]);
|
||||||
|
bgfx::destroy(composite[0]);
|
||||||
return true;
|
bgfx::destroy(composite[1]);
|
||||||
}
|
bgfx::destroy(render_fb);
|
||||||
|
bgfx::destroy(render);
|
||||||
void Run() {
|
|
||||||
app_state.init_time = SDL_GetTicks();
|
|
||||||
app_state.last_time = app_state.init_time;
|
|
||||||
|
|
||||||
while (app_state.running.load()) {
|
|
||||||
app_state.current_time = SDL_GetTicks();
|
|
||||||
app_state.delta_t = app_state.current_time - app_state.last_time;
|
|
||||||
|
|
||||||
for (SDL_Event current_event; SDL_PollEvent(¤t_event) != 0;) {
|
|
||||||
ImGui_ImplSDL3_ProcessEvent(¤t_event);
|
|
||||||
if (current_event.type == SDL_EVENT_QUIT) {
|
|
||||||
app_state.running.store(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (current_event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::Draw();
|
|
||||||
|
|
||||||
app_state.last_time = app_state.current_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown() {
|
|
||||||
K::Graphics::Shutdown();
|
|
||||||
K::UI::Shutdown();
|
|
||||||
K::Resource::Shutdown();
|
|
||||||
bgfx::shutdown();
|
|
||||||
|
|
||||||
#if !(BX_PLATFORM_LINUX && WL_EGL_PLATFORM)
|
|
||||||
SDL_DestroyWindow(app_state.window);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SDL_Quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
if (!K::Init())
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
|
|
||||||
K::Run();
|
|
||||||
|
|
||||||
K::Shutdown();
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
|
@ -243,77 +243,4 @@ namespace K::Resource {
|
||||||
}
|
}
|
||||||
}, r.second);
|
}, 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
325
Keishiki/UI.cpp
325
Keishiki/UI.cpp
|
@ -33,16 +33,11 @@ namespace {
|
||||||
const f32 row_height = 20.0f;
|
const f32 row_height = 20.0f;
|
||||||
|
|
||||||
// Viewport
|
// Viewport
|
||||||
|
K::VisualTrack bg{};
|
||||||
bool playing;
|
bool playing;
|
||||||
u64 last_frame_tick;
|
u64 last_frame_tick;
|
||||||
bgfx::TextureHandle composite[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE },
|
|
||||||
render = BGFX_INVALID_HANDLE,
|
|
||||||
save = BGFX_INVALID_HANDLE;
|
|
||||||
bgfx::FrameBufferHandle composite_fb[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE },
|
|
||||||
render_fb = BGFX_INVALID_HANDLE;
|
|
||||||
f32 proj[16], transform[16], view[16];
|
|
||||||
|
|
||||||
K::VisualTrack bg{};
|
bgfx::TextureHandle save = BGFX_INVALID_HANDLE;
|
||||||
K::Byte *save_buffer;
|
K::Byte *save_buffer;
|
||||||
K::CompositionState *comp_save_called = nullptr;
|
K::CompositionState *comp_save_called = nullptr;
|
||||||
u32 ready_frame;
|
u32 ready_frame;
|
||||||
|
@ -148,47 +143,6 @@ namespace K::UI {
|
||||||
ImGui::EndMainMenuBar();
|
ImGui::EndMainMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
bgfx::Attachment comp{}, comp2{}, ren{};
|
|
||||||
comp.init(composite[0], bgfx::Access::Write); // DX 11 requires Write only
|
|
||||||
comp2.init(composite[1], bgfx::Access::Write); // DX 11 requires Write only
|
|
||||||
ren.init(render, bgfx::Access::ReadWrite);
|
|
||||||
composite_fb[0] = bgfx::createFrameBuffer(1, &comp);
|
|
||||||
composite_fb[1] = bgfx::createFrameBuffer(1, &comp2);
|
|
||||||
render_fb = bgfx::createFrameBuffer(1, &ren);
|
|
||||||
|
|
||||||
save = bgfx::createTexture2D(s.width, s.height, false, 1, bgfx::TextureFormat::RGBA8, BGFX_TEXTURE_READ_BACK | BGFX_TEXTURE_BLIT_DST);
|
|
||||||
save_buffer = static_cast<Byte *>(std::malloc(s.width * s.height * 4));
|
|
||||||
|
|
||||||
bg.uniforms[0].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);
|
|
||||||
f32 mtx1[16], mtx2[16];
|
|
||||||
bx::mtxTranslate(mtx1, 0, 0, 0.0f);
|
|
||||||
bx::mtxScale(mtx2, static_cast<f32>(s.width), static_cast<f32>(s.height), 1.0f);
|
|
||||||
bx::mtxMul(transform, mtx2, mtx1);
|
|
||||||
bx::mtxTranslate(view, 0.f, 0.f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DestroyViewport(CompositionState& s) {
|
|
||||||
bgfx::destroy(composite_fb[0]);
|
|
||||||
bgfx::destroy(composite_fb[1]);
|
|
||||||
bgfx::destroy(composite[0]);
|
|
||||||
bgfx::destroy(composite[1]);
|
|
||||||
bgfx::destroy(render_fb);
|
|
||||||
bgfx::destroy(render);
|
|
||||||
|
|
||||||
bgfx::destroy(save);
|
|
||||||
std::free(save_buffer);
|
|
||||||
|
|
||||||
for (auto& layer : s.layers)
|
|
||||||
layer.track.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawPlugboardVariableEditWidget(Plugboard::T_Map<Plugboard::T_Count>::type& var) {
|
void DrawPlugboardVariableEditWidget(Plugboard::T_Map<Plugboard::T_Count>::type& var) {
|
||||||
std::visit([](auto&& arg) {
|
std::visit([](auto&& arg) {
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
@ -371,59 +325,47 @@ namespace K::UI {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Begin("Viewport")) {
|
if (ImGui::Begin("Viewport")) {
|
||||||
|
static bool do_bg = true;
|
||||||
|
|
||||||
if (ImGui::Shortcut(ImGuiKey_Space))
|
if (ImGui::Shortcut(ImGuiKey_Space))
|
||||||
TogglePlay();
|
TogglePlay();
|
||||||
|
|
||||||
// Perform rendering
|
app_state.render_view = Graphics::K_VIEW_COMP_COMPOSITE;
|
||||||
u32 view_count = 0, layers_done = 0;
|
|
||||||
bgfx::setViewFrameBuffer(Graphics::K_VIEW_COMP_COMPOSITE + view_count, composite_fb[0]); // the other fb will be cleared in composite
|
|
||||||
bgfx::setViewClear(Graphics::K_VIEW_COMP_COMPOSITE + view_count, BGFX_CLEAR_COLOR, 0x00000000);
|
|
||||||
bgfx::setViewRect(Graphics::K_VIEW_COMP_COMPOSITE + view_count, 0, 0, s.width, s.height);
|
|
||||||
bgfx::touch(Graphics::K_VIEW_COMP_COMPOSITE + view_count);
|
|
||||||
view_count++;
|
|
||||||
|
|
||||||
for (u32 i = s.layers.size() - 1; i != u32(-1); i--) {
|
i32 result_index = s.GetFrame(s.current_frame);
|
||||||
if (std::ranges::find(s.disabled, i) != s.disabled.end()) continue;
|
|
||||||
if (s.current_frame > s.layers[i].out || s.current_frame < s.layers[i].in) continue;
|
|
||||||
|
|
||||||
s.layers[i].track.GetFrame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, render_fb, s.width,
|
bgfx::TextureHandle present = BGFX_INVALID_HANDLE;
|
||||||
s.height, proj, view, transform);
|
|
||||||
Graphics::Composite(Graphics::K_VIEW_COMP_COMPOSITE + view_count++, composite_fb[(layers_done + 1) % 2], composite[layers_done % 2], render, s.layers[i].mode, s.width, s.height, proj, transform);
|
|
||||||
layers_done++;
|
|
||||||
}
|
|
||||||
if (layers_done != 0) {
|
|
||||||
bg.GetFrame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, render_fb, s.width, s.height, proj, view,
|
|
||||||
transform);
|
|
||||||
Graphics::Composite(Graphics::K_VIEW_COMP_COMPOSITE + view_count++, composite_fb[(layers_done + 1) % 2],
|
|
||||||
render, composite[layers_done % 2], Graphics::K_V_AlphaOver, s.width, s.height,
|
|
||||||
proj, transform);
|
|
||||||
layers_done++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bg.GetFrame(s, Graphics::K_VIEW_COMP_COMPOSITE + view_count++, composite_fb[0], s.width, s.height, proj,
|
|
||||||
view,
|
|
||||||
transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImTextureID idx = ImGui::toId(composite[layers_done % 2], 1, 0);
|
if (do_bg) {
|
||||||
|
bg.GetFrame(s, app_state.render_view++, s.render_fb, s.width, s.height, s.proj, s.view, s.transform);
|
||||||
|
|
||||||
|
Graphics::Composite(app_state.render_view++, s.composite_fb[1 - result_index],
|
||||||
|
s.render, s.composite[result_index], Graphics::K_V_AlphaOver, s.width, s.height,
|
||||||
|
s.proj, s.transform);
|
||||||
|
present = s.composite[1 - result_index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
present = s.composite[result_index];
|
||||||
|
|
||||||
|
ImTextureID idx = ImGui::toId(present, 1, 0);
|
||||||
if (idx != nullptr)
|
if (idx != nullptr)
|
||||||
ImGui::Image(idx, ImVec2{ static_cast<f32>(s.width), static_cast<f32>(s.height) });
|
ImGui::Image(idx, ImVec2{ static_cast<f32>(s.width), static_cast<f32>(s.height) });
|
||||||
|
|
||||||
ImGui::Text("%ux%u", s.width, s.height);
|
ImGui::Text("%ux%u", s.width, s.height);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
ImGui::BeginDisabled(comp_save_called == nullptr);
|
/* ImGui::BeginDisabled(comp_save_called != nullptr);
|
||||||
if (ImGui::Button("Save to frame.png")) {
|
if (ImGui::Button("Save to frame.png")) {
|
||||||
bgfx::blit(Graphics::K_VIEW_COMP_COMPOSITE + view_count, save, 0, 0, composite[layers_done % 2]);
|
bgfx::blit(Graphics::K_VIEW_COMP_COMPOSITE + view_count, save, 0, 0, composite[layers_done % 2]);
|
||||||
ready_frame = bgfx::readTexture(save, save_buffer);
|
ready_frame = bgfx::readTexture(save, save_buffer);
|
||||||
comp_save_called = &s;
|
comp_save_called = &s;
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();*/
|
||||||
|
|
||||||
app_state.n_views = Graphics::K_VIEW_COMP_COMPOSITE + view_count;
|
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(50.0f);
|
ImGui::SetNextItemWidth(50.0f);
|
||||||
ImGui::DragFloat("FPS", &s.fps, 1.0f, 1.0f, 120.0f);
|
ImGui::DragFloat("FPS", &s.fps, 1.0f, 1.0f, 120.0f);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("BG", &do_bg);
|
||||||
|
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
@ -495,7 +437,7 @@ namespace K::UI {
|
||||||
node_delete_requested = false;
|
node_delete_requested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ImGui::Begin(("Composition: " + s.name).c_str(), nullptr, ImGuiWindowFlags_NoScrollbar)) {
|
if (!ImGui::Begin("Composition", nullptr, ImGuiWindowFlags_NoScrollbar)) {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -504,9 +446,12 @@ namespace K::UI {
|
||||||
if (ImGui::Shortcut(ImGuiKey_Space))
|
if (ImGui::Shortcut(ImGuiKey_Space))
|
||||||
TogglePlay();
|
TogglePlay();
|
||||||
|
|
||||||
|
static f32 nodes_view_scale = 1.0f;
|
||||||
|
static ImVec2 nodes_view_pos{}, nodes_old_view_pos{}, nodes_begin{};
|
||||||
|
|
||||||
static u32 node_current = 0;
|
static u32 node_current = 0;
|
||||||
if (ImGui::Button("Add")) {
|
if (ImGui::Button("Add")) {
|
||||||
s.plugboard.nodes.Store(static_cast<Plugboard::K_P_Nodes>(node_current));
|
s.plugboard.nodes.Store(static_cast<Plugboard::K_P_Nodes>(node_current), ImVec2{-nodes_view_pos.x + 70.0f, -nodes_view_pos.y + 70.0f});
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(150.0f);
|
ImGui::SetNextItemWidth(150.0f);
|
||||||
|
@ -550,9 +495,6 @@ namespace K::UI {
|
||||||
drag_rect.Add(io.MouseClickedPos[ImGuiMouseButton_Left]);
|
drag_rect.Add(io.MouseClickedPos[ImGuiMouseButton_Left]);
|
||||||
ImGuiStyle style = ImGui::GetStyle();
|
ImGuiStyle style = ImGui::GetStyle();
|
||||||
|
|
||||||
static f32 view_scale = 1.0f;
|
|
||||||
static ImVec2 view_pos{}, old_view_pos{}, nodes_begin{};
|
|
||||||
|
|
||||||
bool dragging_on_socket{};
|
bool dragging_on_socket{};
|
||||||
ImVec2 drag_source{};
|
ImVec2 drag_source{};
|
||||||
|
|
||||||
|
@ -574,26 +516,26 @@ namespace K::UI {
|
||||||
// Grid
|
// Grid
|
||||||
const f32 grid_inc = 20.0f;
|
const f32 grid_inc = 20.0f;
|
||||||
const f32 w = window->ContentRegionRect.GetWidth(), h = window->ContentRegionRect.GetHeight();
|
const f32 w = window->ContentRegionRect.GetWidth(), h = window->ContentRegionRect.GetHeight();
|
||||||
for (f32 x = std::fmodf(view_pos.x, grid_inc); x < w; x += grid_inc)
|
for (f32 x = std::fmodf(nodes_view_pos.x, grid_inc); x < w; x += grid_inc)
|
||||||
window->DrawList->AddLine(window_pos + ImVec2(x, 0.0f), window_pos + ImVec2(x, h), 0xFF222222, 1.0f);
|
window->DrawList->AddLine(window_pos + ImVec2(x, 0.0f), window_pos + ImVec2(x, h), 0xFF222222, 1.0f);
|
||||||
for (f32 y = std::fmodf(view_pos.y, grid_inc); y < h; y += grid_inc)
|
for (f32 y = std::fmodf(nodes_view_pos.y, grid_inc); y < h; y += grid_inc)
|
||||||
window->DrawList->AddLine(window_pos + ImVec2(0.0f, y), window_pos + ImVec2(w, y), 0xFF222222, 1.0f);
|
window->DrawList->AddLine(window_pos + ImVec2(0.0f, y), window_pos + ImVec2(w, y), 0xFF222222, 1.0f);
|
||||||
|
|
||||||
// why are we re-getting positions on each frame?
|
// why are we re-getting positions on each frame?
|
||||||
// this is just convenient because sometimes we would be dragging on a socket!
|
// because it's just convenient because sometimes we would be dragging on a socket!
|
||||||
links_pos.clear();
|
links_pos.clear();
|
||||||
|
|
||||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||||
old_view_pos = view_pos;
|
nodes_old_view_pos = nodes_view_pos;
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemActive()) {
|
if (ImGui::IsItemActive()) {
|
||||||
view_pos = old_view_pos + ImGui::GetMouseDragDelta();
|
nodes_view_pos = nodes_old_view_pos + ImGui::GetMouseDragDelta();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::apply([&](auto&&... args) {
|
std::apply([&](auto&&... args) {
|
||||||
(([&](auto&& arg){
|
(([&](auto&& arg){
|
||||||
for (auto& node : arg) {
|
for (auto& node : arg) {
|
||||||
PlugboardDrawNode<std::decay_t<decltype(node)>>(s, node, view_pos, io, style, dragging_on_socket,
|
PlugboardDrawNode<std::decay_t<decltype(node)>>(s, node, nodes_view_pos, io, style, dragging_on_socket,
|
||||||
drag_source, node_delete_requested, links_pos);
|
drag_source, node_delete_requested, links_pos);
|
||||||
}
|
}
|
||||||
}(args)), ...);
|
}(args)), ...);
|
||||||
|
@ -601,15 +543,16 @@ namespace K::UI {
|
||||||
|
|
||||||
ImGui::SetCursorPos({});
|
ImGui::SetCursorPos({});
|
||||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0x33FFFFFF);
|
ImGui::PushStyleColor(ImGuiCol_ChildBg, 0x33FFFFFF);
|
||||||
ImGui::BeginChild("Composition In", {},
|
if (ImGui::BeginChild("Composition In", {},
|
||||||
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX |
|
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeX |
|
||||||
ImGuiChildFlags_AutoResizeY);
|
ImGuiChildFlags_AutoResizeY)) {
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
if (ImGui::BeginTable("Composition In", 3)) {
|
if (ImGui::BeginTable("Composition In", 3)) {
|
||||||
PlugboardNodeDrawSockets(s, s.plugboard.in_instance, style, dragging_on_socket, drag_source, links_pos, false);
|
PlugboardNodeDrawSockets(s, s.plugboard.in_instance, style, dragging_on_socket, drag_source,
|
||||||
|
links_pos, false);
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
|
@ -685,7 +628,7 @@ namespace K::UI {
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr static f32 knob_width = 8.0f;
|
constexpr static f32 knob_width = 8.0f;
|
||||||
constexpr static f32 kf_tab_width = 6.0f;
|
constexpr static f32 kf_tab_width = 12.0f;
|
||||||
|
|
||||||
auto kf_drag_btn_handler = [&io, &drag_rect](
|
auto kf_drag_btn_handler = [&io, &drag_rect](
|
||||||
Plugboard::ChainSel *key_loop_target, bool dragging, Plugboard::ChainSel& chain, i32 frame, bool is_sel,
|
Plugboard::ChainSel *key_loop_target, bool dragging, Plugboard::ChainSel& chain, i32 frame, bool is_sel,
|
||||||
|
@ -741,8 +684,8 @@ namespace K::UI {
|
||||||
if (ImGui::BeginTable("Layers", 5, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) {
|
if (ImGui::BeginTable("Layers", 5, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) {
|
||||||
ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
|
ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
|
||||||
ImGui::TableSetupColumn("#", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_IndentDisable);
|
ImGui::TableSetupColumn("#", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_IndentDisable);
|
||||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoSort);
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoSort, 140.0f);
|
||||||
ImGui::TableSetupColumn("Blending", ImGuiTableColumnFlags_NoSort, 100.0f);
|
ImGui::TableSetupColumn("Blending", ImGuiTableColumnFlags_NoSort, 120.0f);
|
||||||
ImGui::TableSetupColumn("##Enable", ImGuiTableColumnFlags_NoSort);
|
ImGui::TableSetupColumn("##Enable", ImGuiTableColumnFlags_NoSort);
|
||||||
ImGui::TableSetupColumn("##Timeline",
|
ImGui::TableSetupColumn("##Timeline",
|
||||||
ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthStretch);
|
ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
@ -859,10 +802,32 @@ namespace K::UI {
|
||||||
{0.0f, (row_height - ImGui::GetTextLineHeight()) / 2.0f});
|
{0.0f, (row_height - ImGui::GetTextLineHeight()) / 2.0f});
|
||||||
bool layer_open = ImGui::TreeNodeEx(current_layer.name.c_str(), flags);
|
bool layer_open = ImGui::TreeNodeEx(current_layer.name.c_str(), flags);
|
||||||
if (ImGui::BeginPopupContextItem()) {
|
if (ImGui::BeginPopupContextItem()) {
|
||||||
if (!s.selected.empty() && ImGui::Button("Delete")) {
|
if (!s.selected.empty()) {
|
||||||
|
if (ImGui::Button("Delete")) {
|
||||||
layer_delete_requested = true;
|
layer_delete_requested = true;
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
if (ImGui::Button("Make Sub-composition")) {
|
||||||
|
CompositionState new_comp{.width = s.width, .height = s.height};
|
||||||
|
u32 index_in_new_comp = 0;
|
||||||
|
u64 frame_min = -1, frame_max = 0;
|
||||||
|
for (auto j : s.selected) {
|
||||||
|
new_comp.layers.emplace_back(std::move(s.layers[j]));
|
||||||
|
if (std::ranges::find(s.disabled, j) != s.disabled.end())
|
||||||
|
new_comp.disabled.push_back(index_in_new_comp);
|
||||||
|
frame_min = std::min(frame_min, s.layers[j].in);
|
||||||
|
frame_max = std::max(frame_max, s.layers[j].out);
|
||||||
|
index_in_new_comp++;
|
||||||
|
}
|
||||||
|
new_comp.frame_max = frame_max - frame_min;
|
||||||
|
for (auto& layer : new_comp.layers)
|
||||||
|
layer.in -= frame_min;
|
||||||
|
layer_delete_requested = true;
|
||||||
|
app_state.project.compositions.push_back(std::move(new_comp));
|
||||||
|
/* todo make comp */
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
|
if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) {
|
||||||
|
@ -1172,6 +1137,8 @@ namespace K::UI {
|
||||||
ImGui::TableSetColumnIndex(2);
|
ImGui::TableSetColumnIndex(2);
|
||||||
|
|
||||||
auto& [chain, chain_copy] = std::get<Plugboard::Chain*>(info.p)->extra;
|
auto& [chain, chain_copy] = std::get<Plugboard::Chain*>(info.p)->extra;
|
||||||
|
if (tl_clear_selection_request)
|
||||||
|
chain.selected.clear();
|
||||||
|
|
||||||
bool m_empty = chain.segments.empty(), m_has_before = !m_empty && chain.segments.begin()->frame < s.current_frame;
|
bool m_empty = chain.segments.empty(), m_has_before = !m_empty && chain.segments.begin()->frame < s.current_frame;
|
||||||
|
|
||||||
|
@ -1198,9 +1165,11 @@ namespace K::UI {
|
||||||
if (l != chain.segments.end() && l->frame == static_cast<i32>(s.current_frame))
|
if (l != chain.segments.end() && l->frame == static_cast<i32>(s.current_frame))
|
||||||
l->value = v;
|
l->value = v;
|
||||||
else {
|
else {
|
||||||
|
auto d = std::distance(chain.segments.begin(), l);
|
||||||
for (auto& sel : chain.selected)
|
for (auto& sel : chain.selected)
|
||||||
if (sel >= std::distance(chain.segments.begin(), l))
|
if (sel >= d)
|
||||||
sel++;
|
sel++;
|
||||||
|
chain.selected.push_back(d);
|
||||||
chain.segments.emplace(l, s.current_frame, v, Plugboard::InterpolationExtra{
|
chain.segments.emplace(l, s.current_frame, v, Plugboard::InterpolationExtra{
|
||||||
m_has_before ? std::prev(l)->interp.interp : Plugboard::K_I_Linear
|
m_has_before ? std::prev(l)->interp.interp : Plugboard::K_I_Linear
|
||||||
});
|
});
|
||||||
|
@ -1251,7 +1220,11 @@ namespace K::UI {
|
||||||
|
|
||||||
ImGui::SetCursorScreenPos(draw_pos);
|
ImGui::SetCursorScreenPos(draw_pos);
|
||||||
|
|
||||||
ImGui::Button(is_sel ? "s" : "k", {kf_tab_width, row_height * .8f});
|
ImGui::PushStyleColor(ImGuiCol_Button, 0x00000000);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.0f, 0));
|
||||||
|
ImGui::Button((const char*)(is_sel ? u8"\u25c8" : u8"\u25c7"), {kf_tab_width, row_height * .8f});
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
kf_drag_btn_handler(key_loop_target, dragging, chain, frame, is_sel,
|
kf_drag_btn_handler(key_loop_target, dragging, chain, frame, is_sel,
|
||||||
sel_it, segment, val, ii, started_dragging,
|
sel_it, segment, val, ii, started_dragging,
|
||||||
|
@ -1265,13 +1238,11 @@ namespace K::UI {
|
||||||
window->DrawList->AddRectFilled(
|
window->DrawList->AddRectFilled(
|
||||||
{TimelineFrameToScreenView(view_left, view_amt, view_width,
|
{TimelineFrameToScreenView(view_left, view_amt, view_width,
|
||||||
it->frame,
|
it->frame,
|
||||||
s.frame_max) + begin_tl.x +
|
s.frame_max) + begin_tl.x,
|
||||||
kf_tab_width / 2.0f,
|
|
||||||
begin_tl.y + row_height / 2.0f - 2.0f},
|
begin_tl.y + row_height / 2.0f - 2.0f},
|
||||||
{TimelineFrameToScreenView(view_left, view_amt, view_width,
|
{TimelineFrameToScreenView(view_left, view_amt, view_width,
|
||||||
nit->frame,
|
nit->frame,
|
||||||
s.frame_max) + begin_tl.x -
|
s.frame_max) + begin_tl.x,
|
||||||
kf_tab_width / 2.0f,
|
|
||||||
begin_tl.y + row_height / 2.0f + 2.0f},
|
begin_tl.y + row_height / 2.0f + 2.0f},
|
||||||
std::ranges::find(chain.selected,
|
std::ranges::find(chain.selected,
|
||||||
std::distance(chain.segments.begin(), it)) !=
|
std::distance(chain.segments.begin(), it)) !=
|
||||||
|
@ -1295,11 +1266,11 @@ namespace K::UI {
|
||||||
else for (auto& u: current_layer.track.uniforms) {
|
else for (auto& u: current_layer.track.uniforms) {
|
||||||
if (u.status != K_U_Exposed)
|
if (u.status != K_U_Exposed)
|
||||||
continue;
|
continue;
|
||||||
std::visit([table_left](auto &&arg) {
|
std::visit([table_left, &init_y](auto &&arg) {
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>)
|
if constexpr (std::is_same_v<T, Plugboard::ConnectInfo>)
|
||||||
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});
|
{table_left, init_y + row_height / 2.0f});
|
||||||
}, std::visit([&u](auto&& arg) -> auto& { return arg->in[u.connection.index].value; }, u.connection.p));
|
}, std::visit([&u](auto&& arg) -> auto& { return arg->in[u.connection.index].value; }, u.connection.p));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1536,6 +1507,12 @@ namespace K::UI {
|
||||||
ImPlot::PopStyleVar(2);
|
ImPlot::PopStyleVar(2);
|
||||||
ImGui::SetCursorScreenPos(ImGui::GetCursorStartPos());
|
ImGui::SetCursorScreenPos(ImGui::GetCursorStartPos());
|
||||||
tl_bg_handler(ImGui::GetContentRegionAvail().y, ImGui::GetContentRegionAvail().x);
|
tl_bg_handler(ImGui::GetContentRegionAvail().y, ImGui::GetContentRegionAvail().x);
|
||||||
|
if (tl_clear_selection_request)
|
||||||
|
for (auto& p : s.plugboard.selected_nodes)
|
||||||
|
if (auto *n = std::get_if<Plugboard::Chain*>(&p)){
|
||||||
|
auto& [chain, _] = (*n)->extra;
|
||||||
|
chain.selected.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
|
@ -1602,13 +1579,6 @@ namespace K::UI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tl_clear_selection_request)
|
|
||||||
for (auto& p : s.plugboard.selected_nodes)
|
|
||||||
if (auto *n = std::get_if<Plugboard::Chain*>(&p)){
|
|
||||||
auto& [chain, _] = (*n)->extra;
|
|
||||||
chain.selected.clear();
|
|
||||||
}
|
|
||||||
if (tl_clear_selection_request_this_frame && tl_clear_selection_request)
|
if (tl_clear_selection_request_this_frame && tl_clear_selection_request)
|
||||||
tl_clear_selection_request = false;
|
tl_clear_selection_request = false;
|
||||||
}
|
}
|
||||||
|
@ -1739,7 +1709,7 @@ namespace K::UI {
|
||||||
}
|
}
|
||||||
ImGui::EndTabBar();
|
ImGui::EndTabBar();
|
||||||
}
|
}
|
||||||
ImGui::InputTextMultiline("##source", &s.layers[s.active].track.shader, ImVec2(-FLT_MIN, ImGui::GetContentRegionAvail().y - 25.0f), ImGuiInputTextFlags_AllowTabInput);
|
ImGui::InputTextMultiline("##source", &s.layers[s.active].track.shader, ImVec2(-FLT_MIN, ImGui::GetContentRegionAvail().y - 30.0f), ImGuiInputTextFlags_AllowTabInput);
|
||||||
if (ImGui::Button("Submit Shader"))
|
if (ImGui::Button("Submit Shader"))
|
||||||
s.layers[s.active].track.Compile();
|
s.layers[s.active].track.Compile();
|
||||||
}
|
}
|
||||||
|
@ -1882,6 +1852,84 @@ namespace K::UI {
|
||||||
|
|
||||||
void Assets() {
|
void Assets() {
|
||||||
if (ImGui::Begin("Assets", &draw_assets)) {
|
if (ImGui::Begin("Assets", &draw_assets)) {
|
||||||
|
if (ImGui::Button("New Composition"))
|
||||||
|
ImGui::OpenPopup("New Composition");
|
||||||
|
|
||||||
|
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
||||||
|
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||||
|
if (ImGui::BeginPopupModal("New Composition", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||||
|
static String name("Comp");
|
||||||
|
ImGui::InputText("Name", &name);
|
||||||
|
|
||||||
|
static i32 frames = 100;
|
||||||
|
if (ImGui::InputInt("Frames", &frames, 1))
|
||||||
|
frames = std::max(frames, 1);
|
||||||
|
|
||||||
|
static f32 fps = 30.0f;
|
||||||
|
if (ImGui::InputFloat("FPS", &fps, 1.0f, 5.0f, "%.1f"))
|
||||||
|
fps = std::clamp(fps, 1.0f, 120.0f);
|
||||||
|
|
||||||
|
static i32 dims[2] = { 1280, 720 };
|
||||||
|
if (ImGui::InputInt2("Dimensions", dims)) {
|
||||||
|
dims[0] = std::max(1, dims[0]);
|
||||||
|
dims[1] = std::max(1, dims[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("OK", ImVec2(120, 0)) && !name.empty()) {
|
||||||
|
app_state.project.compositions.emplace_back(name, 0, frames, fps, dims[0], dims[1]);
|
||||||
|
app_state.project.compositions.back().Setup();
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Cancel", ImVec2(120, 0))) {
|
||||||
|
name.clear();
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("Compositions", 4, ImGuiTableFlags_Borders)) {
|
||||||
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableSetupColumn("Frames", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
ImGui::TableSetupColumn("Dimensions", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
ImGui::TableSetupColumn("FPS", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
for (u32 j = 0; j < app_state.project.compositions.size(); j++) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::PushID(j);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
auto& comp = app_state.project.compositions[j];
|
||||||
|
bool sel = app_state.project.inspecting_composition == j;
|
||||||
|
if (ImGui::Selectable(comp.name.c_str(), sel, ImGuiSelectableFlags_SpanAllColumns) && !sel) {
|
||||||
|
app_state.project.inspecting_composition = static_cast<i32>(j);
|
||||||
|
bg.uniforms[0].val = ShaderGraph::XYZ{
|
||||||
|
static_cast<f32>(app_state.project.compositions[app_state.project.inspecting_composition].width),
|
||||||
|
static_cast<f32>(app_state.project.compositions[app_state.project.inspecting_composition].height),
|
||||||
|
0.0f };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel && ImGui::BeginPopupContextItem()) {
|
||||||
|
if (ImGui::Button("Delete")) {
|
||||||
|
/* todo this is gonna be rough... */
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%lu", comp.frame_max);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%ux%u", comp.width, comp.height);
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%.1f", comp.fps);
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::Button("Load")) {
|
if (ImGui::Button("Load")) {
|
||||||
static const SDL_DialogFileFilter import_filters[] = {
|
static const SDL_DialogFileFilter import_filters[] = {
|
||||||
{ "PNG images", "png" },
|
{ "PNG images", "png" },
|
||||||
|
@ -1918,6 +1966,7 @@ namespace K::UI {
|
||||||
|
|
||||||
SDL_ShowOpenFileDialog(ImportCallback::f, nullptr, app_state.window, import_filters, 3, nullptr, true);
|
SDL_ShowOpenFileDialog(ImportCallback::f, nullptr, app_state.window, import_filters, 3, nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginTable("Assets", 3, ImGuiTableFlags_Borders)) {
|
if (ImGui::BeginTable("Assets", 3, ImGuiTableFlags_Borders)) {
|
||||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
|
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
@ -1925,16 +1974,6 @@ namespace K::UI {
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
i32 i = 0;
|
i32 i = 0;
|
||||||
for (auto& comp : app_state.project.compositions) {
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::PushID(i++);
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("%s", comp.name.c_str());
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::Text("Composition");
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
|
||||||
for (auto& [name, res] : Resource::resources) {
|
for (auto& [name, res] : Resource::resources) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::PushID(i++);
|
ImGui::PushID(i++);
|
||||||
|
@ -1988,6 +2027,7 @@ namespace K::UI {
|
||||||
|
|
||||||
if (draw_assets) Assets();
|
if (draw_assets) Assets();
|
||||||
|
|
||||||
|
if (app_state.project.inspecting_composition >= 0) {
|
||||||
auto &comp = app_state.project.compositions[app_state.project.inspecting_composition];
|
auto &comp = app_state.project.compositions[app_state.project.inspecting_composition];
|
||||||
if (draw_viewport) Viewport(comp);
|
if (draw_viewport) Viewport(comp);
|
||||||
if (draw_layer) Layer(comp);
|
if (draw_layer) Layer(comp);
|
||||||
|
@ -1995,9 +2035,12 @@ namespace K::UI {
|
||||||
if (draw_interpolation) Interpolation(comp);
|
if (draw_interpolation) Interpolation(comp);
|
||||||
|
|
||||||
if (comp_save_called != nullptr && ready_frame <= app_state.bgfx_frame) {
|
if (comp_save_called != nullptr && ready_frame <= app_state.bgfx_frame) {
|
||||||
stbi_write_png("frame.png", static_cast<i32>(comp_save_called->width), static_cast<i32>(comp_save_called->height), 4, save_buffer, static_cast<i32>(comp_save_called->width) * 4);
|
stbi_write_png("frame.png", static_cast<i32>(comp_save_called->width),
|
||||||
|
static_cast<i32>(comp_save_called->height), 4, save_buffer,
|
||||||
|
static_cast<i32>(comp_save_called->width) * 4);
|
||||||
comp_save_called = nullptr;
|
comp_save_called = nullptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_Implbgfx_RenderDrawLists(ImGui::GetDrawData());
|
ImGui_Implbgfx_RenderDrawLists(ImGui::GetDrawData());
|
||||||
|
@ -2008,7 +2051,7 @@ namespace K::UI {
|
||||||
bgfx::dbgTextPrintf(0, app_state.window_height/16 - 8, 0xf8,
|
bgfx::dbgTextPrintf(0, app_state.window_height/16 - 8, 0xf8,
|
||||||
" lachrymal.net :: %s Renderer :: %u/%u Views :: %u FBs :: %u Samplers :: Blit %s :: %s :: %u FPS",
|
" lachrymal.net :: %s Renderer :: %u/%u Views :: %u FBs :: %u Samplers :: Blit %s :: %s :: %u FPS",
|
||||||
caps->supported & BGFX_CAPS_RENDERER_MULTITHREADED ? "Multithreaded" : "Singlethreaded",
|
caps->supported & BGFX_CAPS_RENDERER_MULTITHREADED ? "Multithreaded" : "Singlethreaded",
|
||||||
app_state.n_views, caps->limits.maxViews, caps->limits.maxFrameBuffers,
|
app_state.render_view, caps->limits.maxViews, caps->limits.maxFrameBuffers,
|
||||||
caps->limits.maxTextureSamplers, caps->supported & BGFX_CAPS_TEXTURE_BLIT ? "OK" : "NO",
|
caps->limits.maxTextureSamplers, caps->supported & BGFX_CAPS_TEXTURE_BLIT ? "OK" : "NO",
|
||||||
SDL_GetCurrentVideoDriver(),
|
SDL_GetCurrentVideoDriver(),
|
||||||
stat->cpuTimerFreq / stat->cpuTimeFrame);
|
stat->cpuTimerFreq / stat->cpuTimeFrame);
|
||||||
|
@ -2028,6 +2071,27 @@ namespace K::UI {
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||||
|
|
||||||
|
ImVector<ImWchar> ranges;
|
||||||
|
ImFontGlyphRangesBuilder builder;
|
||||||
|
builder.AddChar(0x25C7);
|
||||||
|
builder.AddChar(0x25C8);
|
||||||
|
builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
|
||||||
|
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese());
|
||||||
|
builder.AddRanges(io.Fonts->GetGlyphRangesChineseFull());
|
||||||
|
builder.AddRanges(io.Fonts->GetGlyphRangesKorean());
|
||||||
|
builder.BuildRanges(&ranges);
|
||||||
|
io.Fonts->AddFontFromFileTTF("SourceHanSans-Regular.ttc", 16, nullptr, ranges.Data);
|
||||||
|
io.Fonts->Build();
|
||||||
|
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
style.WindowBorderSize = 0.0f;
|
||||||
|
style.DockingSeparatorSize = 1.0f;
|
||||||
|
style.ScrollbarRounding = 0.0f;
|
||||||
|
style.TabRounding = 0.0f;
|
||||||
|
style.ScrollbarSize = 8.0f;
|
||||||
|
style.FramePadding.y = 2.0f;
|
||||||
|
|
||||||
ImGui_Implbgfx_Init(Graphics::K_VIEW_UI);
|
ImGui_Implbgfx_Init(Graphics::K_VIEW_UI);
|
||||||
bgfx::setViewClear(Graphics::K_VIEW_UI, BGFX_CLEAR_COLOR);
|
bgfx::setViewClear(Graphics::K_VIEW_UI, BGFX_CLEAR_COLOR);
|
||||||
SetLogoView();
|
SetLogoView();
|
||||||
|
@ -2062,7 +2126,10 @@ namespace K::UI {
|
||||||
bg.uniforms.erase(bg.uniforms.begin());
|
bg.uniforms.erase(bg.uniforms.begin());
|
||||||
|
|
||||||
for (auto& comp : app_state.project.compositions)
|
for (auto& comp : app_state.project.compositions)
|
||||||
DestroyViewport(comp);
|
for (auto& layer : comp.layers)
|
||||||
|
layer.track.Clear();
|
||||||
|
|
||||||
|
app_state.project.compositions[app_state.project.inspecting_composition].Destroy();
|
||||||
|
|
||||||
ImGui_Implbgfx_Shutdown();
|
ImGui_Implbgfx_Shutdown();
|
||||||
ImGui_ImplSDL3_Shutdown();
|
ImGui_ImplSDL3_Shutdown();
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 701d84c2227e9219ad44c760e75c3c6f24a2cff0
|
Subproject commit c2b7416a58a8610eecba5f6e3940e30c1b64e1f9
|
|
@ -1 +1 @@
|
||||||
Subproject commit 73720c7c9958e87b3d134a7574d1720ad2d24442
|
Subproject commit bab9564a979d1f15f39f047b9035f92a37ed8317
|
|
@ -1 +1 @@
|
||||||
Subproject commit cec502d0c0f2052d07df4b0d488f7e3e23818b9d
|
Subproject commit 3ffd379050bfd0d83664ac469c2495cbff2c8446
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7237d3e5c3a6b837b7b457460877cf5eea8c3745
|
Subproject commit 10a5a857f5b5cd6eae7f86461b939ec05e9235b2
|
|
@ -5,10 +5,6 @@
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
namespace K {
|
namespace K {
|
||||||
bool Init();
|
|
||||||
void Run();
|
|
||||||
void Shutdown();
|
|
||||||
|
|
||||||
struct Layer {
|
struct Layer {
|
||||||
VisualTrack track;
|
VisualTrack track;
|
||||||
String name;
|
String name;
|
||||||
|
@ -31,6 +27,17 @@ namespace K {
|
||||||
Vector<u32> disabled; // indices for layers
|
Vector<u32> disabled; // indices for layers
|
||||||
|
|
||||||
Plugboard::Plugboard plugboard;
|
Plugboard::Plugboard plugboard;
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
bgfx::TextureHandle composite[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE },
|
||||||
|
render = BGFX_INVALID_HANDLE;
|
||||||
|
bgfx::FrameBufferHandle composite_fb[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE },
|
||||||
|
render_fb = BGFX_INVALID_HANDLE;
|
||||||
|
f32 proj[16], transform[16], view[16];
|
||||||
|
|
||||||
|
void Setup();
|
||||||
|
i32 GetFrame(u32 frame);
|
||||||
|
void Destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProjectState {
|
struct ProjectState {
|
||||||
|
@ -47,7 +54,7 @@ namespace K {
|
||||||
|
|
||||||
u64 init_time{}, last_time{}, current_time{}, delta_t{};
|
u64 init_time{}, last_time{}, current_time{}, delta_t{};
|
||||||
u32 bgfx_frame{};
|
u32 bgfx_frame{};
|
||||||
u32 n_views{};
|
u32 render_view{};
|
||||||
|
|
||||||
ProjectState project{};
|
ProjectState project{};
|
||||||
} app_state; // global !
|
} app_state; // global !
|
||||||
|
|
|
@ -582,8 +582,10 @@ namespace K::Plugboard {
|
||||||
return std::get<plf::colony<N>>(nodes).insert(v);
|
return std::get<plf::colony<N>>(nodes).insert(v);
|
||||||
}
|
}
|
||||||
template <SameAsAny<Ns...> N>
|
template <SameAsAny<Ns...> N>
|
||||||
auto& Store(N&& v) {
|
auto& Store(N&& v, const ImVec2& pos = {}) {
|
||||||
return *std::get<plf::colony<N>>(nodes).emplace(std::forward<N>(v));
|
auto n = std::get<plf::colony<N>>(nodes).emplace(std::forward<N>(v));
|
||||||
|
n->pos = pos;
|
||||||
|
return *n;
|
||||||
}
|
}
|
||||||
auto& Store(const std::variant<Ns...>& v) {
|
auto& Store(const std::variant<Ns...>& v) {
|
||||||
return std::visit([this](auto&& arg) { return store(arg); }, v);
|
return std::visit([this](auto&& arg) { return store(arg); }, v);
|
||||||
|
@ -604,12 +606,12 @@ namespace K::Plugboard {
|
||||||
typename std::tuple_element<N, std::tuple<Ts...>>::type;
|
typename std::tuple_element<N, std::tuple<Ts...>>::type;
|
||||||
|
|
||||||
template <std::size_t... Is>
|
template <std::size_t... Is>
|
||||||
void Store(K_P_Nodes i, std::index_sequence<Is...>) {
|
void Store(K_P_Nodes i, std::index_sequence<Is...>, const ImVec2& pos = {}) {
|
||||||
((Is == i ? Store(NthTypeOf<Is, Ns...>{}) : NthTypeOf<Is, Ns...>{}), ...);
|
((Is == i ? Store(NthTypeOf<Is, Ns...>{}, pos) : NthTypeOf<Is, Ns...>{}), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Store(K_P_Nodes i) {
|
void Store(K_P_Nodes i, const ImVec2& pos = {}) {
|
||||||
Store(i, std::index_sequence_for<Ns...>{});
|
Store(i, std::index_sequence_for<Ns...>{}, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t... Is>
|
template <std::size_t... Is>
|
||||||
|
|
Loading…
Add table
Reference in a new issue