From 10b506152f3bc4a73049d58916eb22d94dd59cee Mon Sep 17 00:00:00 2001 From: lachrymaLF Date: Tue, 25 Jun 2024 00:41:34 -0400 Subject: [PATCH] comps --- Keishiki/Graphics.cpp | 2 +- Keishiki/Keishiki.cpp | 63 +++++---------------- Keishiki/UI.cpp | 104 +++++++++++++++++++++++++++-------- Keishiki/include/Graphics.h | 2 +- Keishiki/include/Keishiki.h | 11 ++-- Keishiki/include/Plugboard.h | 2 +- Keishiki/include/UI.h | 6 +- TODO.md | 1 + 8 files changed, 109 insertions(+), 82 deletions(-) diff --git a/Keishiki/Graphics.cpp b/Keishiki/Graphics.cpp index 3262c7b..cb3bd8e 100644 --- a/Keishiki/Graphics.cpp +++ b/Keishiki/Graphics.cpp @@ -137,7 +137,7 @@ namespace { } namespace K::Graphics { - bool Init(u16 width, u16 height) { + bool Init() { error = FT_Init_FreeType(&library); if (error) { LogError("FreeType init error: " + std::to_string(error)); diff --git a/Keishiki/Keishiki.cpp b/Keishiki/Keishiki.cpp index fc5377a..54d5bf3 100644 --- a/Keishiki/Keishiki.cpp +++ b/Keishiki/Keishiki.cpp @@ -15,11 +15,6 @@ #include "backends/imgui_impl_sdl3.h" #include -namespace { - K::CompState state; - const K::Resource::Resource *logo; -} - namespace K { K::AppState app_state; @@ -31,7 +26,7 @@ namespace K { app_state.window = SDL_CreateWindow("Keishiki", app_state.window_width, app_state.window_height, - 0); + SDL_WINDOW_RESIZABLE); if (app_state.window == nullptr) { LogError(SDL_GetError()); @@ -54,6 +49,7 @@ namespace K { 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); @@ -63,6 +59,7 @@ namespace K { 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 @@ -72,58 +69,21 @@ namespace K { return false; } - bgfx::setDebug(BGFX_DEBUG_TEXT); - bgfx::setViewRect(K::Graphics::K_VIEW_LOGO, 0, 0, app_state.window_width, app_state.window_height); - float view[16]; - bx::mtxTranslate(view, 0.f, 0.f, 1.0f); - float proj[16]; - bx::mtxOrtho(proj, 0.0f, app_state.window_width, 0.0f, app_state.window_height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); - bgfx::setViewTransform(K::Graphics::K_VIEW_LOGO, view, proj); - K::Resource::Init(); K::UI::Init(app_state.window); - if (!K::Graphics::Init(app_state.window_width, app_state.window_height)) { + if (!K::Graphics::Init()) { LogError("Graphics init failed"); return false; } - logo = Resource::Load("Keishiki.png"); - - state.width = 1280; - state.height = 550; - state.current_frame = 0; - state.fps = 30.0f; - state.frame_max = 200; - - K::UI::SetupViewport(state); + 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]); return true; } - void Render() { - K::Graphics::DrawTextureImageAlpha(K::Graphics::K_VIEW_LOGO, logo, app_state.window_width - logo->w + 10, 0, .4f); - - UI::Draw(app_state.bgfx_frame, state); - - const bgfx::Stats *stat = bgfx::getStats(); - const bgfx::Caps *caps = bgfx::getCaps(); - bgfx::dbgTextClear(); - 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", - caps->supported & BGFX_CAPS_RENDERER_MULTITHREADED ? "Multithreaded" : "Singlethreaded", - app_state.n_views, caps->limits.maxViews, caps->limits.maxFrameBuffers, - caps->limits.maxTextureSamplers, caps->supported & BGFX_CAPS_TEXTURE_BLIT ? "OK" : "NO", - SDL_GetCurrentVideoDriver(), - stat->cpuTimerFreq / stat->cpuTimeFrame); - bgfx::dbgTextPrintf(0, app_state.window_height/16 - 7, 0xf8, - " Project Keishiki :: %s :: Build %s %s :: SDL %i.%i.%i :: bgfx 1.%i :: Dear ImGui %s :: %s", - BX_COMPILER_NAME, __DATE__, __TIME__, SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, - BGFX_API_VERSION, ImGui::GetVersion(), bgfx::getRendererName(bgfx::getRendererType())); - - app_state.bgfx_frame = bgfx::frame(); - } - void Run() { app_state.init_time = SDL_GetTicks(); app_state.last_time = app_state.init_time; @@ -138,9 +98,14 @@ namespace K { app_state.running.store(false); 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); + UI::SetLogoView(); + } } - Render(); + UI::Draw(); app_state.last_time = app_state.current_time; } @@ -148,7 +113,7 @@ namespace K { void Shutdown() { K::Graphics::Shutdown(); - K::UI::Shutdown(state); + K::UI::Shutdown(); K::Resource::Shutdown(); bgfx::shutdown(); diff --git a/Keishiki/UI.cpp b/Keishiki/UI.cpp index 7c12d98..9b7b9bb 100644 --- a/Keishiki/UI.cpp +++ b/Keishiki/UI.cpp @@ -19,12 +19,13 @@ #include namespace { + const K::Resource::Resource *logo; + // Panels bool draw_viewport = true, draw_layer = true, draw_comp = true, draw_interpolation = true, -// draw_properties = true, draw_assets = true; const f32 row_height = 20.0f; @@ -37,10 +38,11 @@ namespace { save = BGFX_INVALID_HANDLE; bgfx::FrameBufferHandle composite_fb[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE }, render_fb = BGFX_INVALID_HANDLE; - K::VisualTrack bg{}; f32 proj[16], transform[16], view[16]; + + K::VisualTrack bg{}; K::Byte *save_buffer; - bool save_called = false; + K::CompState *comp_save_called = nullptr; u32 ready_frame; } @@ -57,6 +59,14 @@ namespace ImGui { } namespace K::UI { + void SetLogoView() { + bgfx::setViewRect(Graphics::K_VIEW_LOGO, 0, 0, app_state.window_width, app_state.window_height); + float view[16]; + bx::mtxTranslate(view, 0.f, 0.f, 1.0f); + float proj[16]; + bx::mtxOrtho(proj, 0.0f, app_state.window_width, 0.0f, app_state.window_height, 0.1f, 100.0f, 0.f, bgfx::getCaps()->homogeneousDepth); + bgfx::setViewTransform(K::Graphics::K_VIEW_LOGO, view, proj); + } void AddTransformLayer(CompState& s, const String& name) { auto l = Layer{ @@ -107,7 +117,7 @@ namespace K::UI { s.layers.push_back(std::move(l)); } - void MainMenuBar(const CompState& s) { + void MainMenuBar() { if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("Edit")) { // if (ImGui::MenuItem("Undo", "CTRL+Z")) {} @@ -393,11 +403,11 @@ namespace K::UI { ImGui::Text("%ux%u", s.width, s.height); ImGui::SameLine(); - ImGui::BeginDisabled(save_called); + ImGui::BeginDisabled(comp_save_called == nullptr); if (ImGui::Button("Save to frame.png")) { bgfx::blit(Graphics::K_VIEW_COMP_COMPOSITE + view_count, save, 0, 0, composite[layers_done % 2]); ready_frame = bgfx::readTexture(save, save_buffer); - save_called = true; + comp_save_called = &s; } ImGui::EndDisabled(); @@ -476,7 +486,7 @@ namespace K::UI { node_delete_requested = false; } - if (!ImGui::Begin("Composition", &draw_comp, ImGuiWindowFlags_NoScrollbar)) { + if (!ImGui::Begin(("Composition: " + s.name).c_str(), &draw_comp, ImGuiWindowFlags_NoScrollbar)) { ImGui::End(); return; } @@ -485,7 +495,7 @@ namespace K::UI { if (ImGui::Shortcut(ImGuiKey_Space)) TogglePlay(); - static u32 node_current{}; + static u32 node_current = 0; if (ImGui::Button("Add")) { s.plugboard.nodes.Store(static_cast(node_current)); } @@ -1383,15 +1393,20 @@ namespace K::UI { ImPlot::Annotation(p3x, p3y, {1.0f, 1.0f, 1.0f, 1.0f}, {15.0f, 0.0f}, true); static f32 x_tmp, y_tmp; + static f32 cap_l, cap_r; ImGui::SetCursorScreenPos(ImPlot::PlotToPixels(p2x, p2y) - ImVec2{10.0f / 2.0f, 10.0f / 2.0f}); ImGui::Button("##p2", {10.0f, 10.0f}); if (ImGui::IsItemClicked()) { x_tmp = segment.v[0]; y_tmp = segment.v[1]; + auto cp1 = segment.v[2] + 1.0f; + auto d_sqrt = std::sqrt(cp1 * cp1 - 4.0f * segment.v[2] * segment.v[2]); + cap_l = (cp1 - d_sqrt) / 2.0f; + cap_r = (cp1 + d_sqrt) / 2.0f; } if (ImGui::IsItemActive()) { - segment.v[0] = std::clamp(x_tmp + static_cast(drag_off_x) / (static_cast(frame_nxt) - static_cast(frame)), 0.0f, 1.0f); + segment.v[0] = std::clamp(x_tmp + static_cast(drag_off_x) / (static_cast(frame_nxt) - static_cast(frame)), segment.v[2] >= 0.0f ? 0.0f : cap_l, cap_r); segment.v[1] = y_tmp + static_cast(drag_off_y / (v_nxt - v)); } @@ -1400,9 +1415,12 @@ namespace K::UI { if (ImGui::IsItemClicked()) { x_tmp = segment.v[2]; y_tmp = segment.v[3]; + auto d_sqrt = std::sqrt(4.0f * segment.v[0] - 3.0f * segment.v[0] * segment.v[0]); + cap_l = (segment.v[0] - d_sqrt) / 2.0f; + cap_r = (segment.v[0] + d_sqrt) / 2.0f; } if (ImGui::IsItemActive()) { - segment.v[2] = std::clamp(x_tmp + static_cast(drag_off_x) / (static_cast(frame_nxt) - static_cast(frame)), 0.0f, 1.0f); + segment.v[2] = std::clamp(x_tmp + static_cast(drag_off_x) / (static_cast(frame_nxt) - static_cast(frame)), cap_l, segment.v[0] <= 1.0f ? 1.0f : cap_r); segment.v[3] = y_tmp + static_cast(drag_off_y / (v_nxt - v)); } @@ -1764,9 +1782,8 @@ namespace K::UI { ImGui::End(); } - void Assets(CompState& s) { + void Assets() { if (ImGui::Begin("Assets", &draw_assets)) { - ImGui::TextUnformatted("Loaded assets:"); if (ImGui::BeginTable("Assets", 3, ImGuiTableFlags_Borders)) { ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed); @@ -1774,6 +1791,16 @@ namespace K::UI { ImGui::TableHeadersRow(); i32 i = 0; + for (auto& comp : app_state.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) { ImGui::TableNextRow(); ImGui::PushID(i++); @@ -1813,31 +1840,55 @@ namespace K::UI { ImGui::End(); } - void Draw(u32 frame, CompState& s) { + void Draw() { ImGui_ImplSDL3_NewFrame(); ImGui_Implbgfx_NewFrame(); ImGui::NewFrame(); + Graphics::DrawTextureImageAlpha(K::Graphics::K_VIEW_LOGO, logo, app_state.window_width - logo->w + 10, 0, .4f); + ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); ImGui::ShowDemoWindow(); - MainMenuBar(s); - if (draw_viewport) Viewport(s); // Must go before comp! - if (draw_layer) Layer(s); - if (draw_comp) Composition(s); - if (draw_interpolation) Interpolation(s); - if (draw_assets) Assets(s); + MainMenuBar(); - if (save_called && ready_frame <= frame) { - stbi_write_png("frame.png", static_cast(s.width), static_cast(s.height), 4, save_buffer, static_cast(s.width) * 4); - save_called = false; + if (draw_assets) Assets(); + + auto& comp = app_state.compositions[app_state.inspecting_composition]; + if (draw_viewport) Viewport(comp); + if (draw_layer) Layer(comp); + if (draw_comp) Composition(comp); + if (draw_interpolation) Interpolation(comp); + + if (comp_save_called != nullptr && ready_frame <= app_state.bgfx_frame) { + stbi_write_png("frame.png", static_cast(comp_save_called->width), static_cast(comp_save_called->height), 4, save_buffer, static_cast(comp_save_called->width) * 4); + comp_save_called = nullptr; } ImGui::Render(); ImGui_Implbgfx_RenderDrawLists(ImGui::GetDrawData()); + + const bgfx::Stats *stat = bgfx::getStats(); + const bgfx::Caps *caps = bgfx::getCaps(); + bgfx::dbgTextClear(); + 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", + caps->supported & BGFX_CAPS_RENDERER_MULTITHREADED ? "Multithreaded" : "Singlethreaded", + app_state.n_views, caps->limits.maxViews, caps->limits.maxFrameBuffers, + caps->limits.maxTextureSamplers, caps->supported & BGFX_CAPS_TEXTURE_BLIT ? "OK" : "NO", + SDL_GetCurrentVideoDriver(), + stat->cpuTimerFreq / stat->cpuTimeFrame); + bgfx::dbgTextPrintf(0, app_state.window_height/16 - 7, 0xf8, + " Project Keishiki :: %s :: Build %s %s :: SDL %i.%i.%i :: bgfx 1.%i :: Dear ImGui %s :: %s", + BX_COMPILER_NAME, __DATE__, __TIME__, SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, + BGFX_API_VERSION, ImGui::GetVersion(), bgfx::getRendererName(bgfx::getRendererType())); + + app_state.bgfx_frame = bgfx::frame(); } void Init(SDL_Window *window) { + bgfx::setDebug(BGFX_DEBUG_TEXT); + ImGui::CreateContext(); ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); @@ -1845,6 +1896,7 @@ namespace K::UI { io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; ImGui_Implbgfx_Init(Graphics::K_VIEW_UI); bgfx::setViewClear(Graphics::K_VIEW_UI, BGFX_CLEAR_COLOR); + SetLogoView(); switch (bgfx::getRendererType()) { case bgfx::RendererType::Noop: @@ -1867,13 +1919,17 @@ namespace K::UI { bg.pg = Resource::Load("Checkerboard")->pg; bg.AddUniform("f_hw", ShaderGraph::Type::T_XYZ); + + logo = Resource::Load("Keishiki.png"); } - void Shutdown(CompState& s) { + void Shutdown() { bgfx::destroy(bg.uniforms[0].handle); bg.uniforms.erase(bg.uniforms.begin()); - DestroyViewport(s); + for (auto& comp : app_state.compositions) + DestroyViewport(comp); + ImGui_Implbgfx_Shutdown(); ImGui_ImplSDL3_Shutdown(); ImPlot::DestroyContext(); diff --git a/Keishiki/include/Graphics.h b/Keishiki/include/Graphics.h index 6e6575b..838f773 100644 --- a/Keishiki/include/Graphics.h +++ b/Keishiki/include/Graphics.h @@ -18,7 +18,7 @@ namespace K::Graphics { K_VIEW_COMP_COMPOSITE }; - bool Init(u16 width, u16 height); + bool Init(); void Shutdown(); void DrawQuad(u32 view_id, f32 mtx[16], u64 state, const bgfx::ProgramHandle& pg); diff --git a/Keishiki/include/Keishiki.h b/Keishiki/include/Keishiki.h index 75015b0..d1ed116 100644 --- a/Keishiki/include/Keishiki.h +++ b/Keishiki/include/Keishiki.h @@ -9,8 +9,6 @@ namespace K { void Run(); void Shutdown(); - void Render(); - struct Layer { VisualTrack track; String name; @@ -19,6 +17,7 @@ namespace K { }; struct CompState { + String name; // Time u64 current_frame; u64 frame_max; @@ -36,12 +35,16 @@ namespace K { extern struct AppState { SDL_Window *window = nullptr; - u16 window_width = 2300, + i32 window_width = 2300, window_height = 1300; + std::atomic_bool running {true}; + u64 init_time{}, last_time{}, current_time{}, delta_t{}; u32 bgfx_frame{}; u32 n_views{}; - std::atomic_bool running {true}; + + i32 inspecting_composition = -1; + Vector compositions{}; } app_state; // global ! } diff --git a/Keishiki/include/Plugboard.h b/Keishiki/include/Plugboard.h index 7e98f1c..bbf160a 100644 --- a/Keishiki/include/Plugboard.h +++ b/Keishiki/include/Plugboard.h @@ -373,7 +373,7 @@ namespace K::Plugboard { T_Map::type FetchNegate(const CompState& s, const Negate& n); struct Negate { - const static char constexpr *name = static_cast("Add"); + const static char constexpr *name = static_cast("Negate"); std::array in = { InSocket{"a", T_Float } }; std::array out = { OutSocket{ "-a", T_Float } }; std::array::type (*)(const CompState&, const Negate&), 1> fetch = { FetchNegate }; diff --git a/Keishiki/include/UI.h b/Keishiki/include/UI.h index dfa41f4..b88345c 100644 --- a/Keishiki/include/UI.h +++ b/Keishiki/include/UI.h @@ -4,7 +4,9 @@ namespace K::UI { void Init(SDL_Window *window); - void Draw(u32 frame, CompState& s); - void Shutdown(CompState& s); + void Draw(); + void Shutdown(); void SetupViewport(CompState& s); + void DestroyViewport(CompState& s); + void SetLogoView(); } diff --git a/TODO.md b/TODO.md index 2abafde..f679b00 100644 --- a/TODO.md +++ b/TODO.md @@ -10,6 +10,7 @@ - Pre-compose/Layer Groups - Undo's - Node groups + - Motion blur - Text (idea: index-based evaluation in plugboard)