From 30735c4f78a17633646700eb89af976b347061fb Mon Sep 17 00:00:00 2001 From: lachrymaLF Date: Wed, 5 Jun 2024 16:11:13 -0400 Subject: [PATCH] plots --- .gitmodules | 3 ++ Keishiki/CMakeLists.txt | 5 +-- Keishiki/UI.cpp | 78 ++++++++++++++++++++++++++++------------- Keishiki/ext/implot | 1 + README.md | 2 ++ TODO.md | 14 ++++---- 6 files changed, 70 insertions(+), 33 deletions(-) create mode 160000 Keishiki/ext/implot diff --git a/.gitmodules b/.gitmodules index 7966777..c80fd3a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "Keishiki/ext/freetype"] path = Keishiki/ext/freetype url = https://github.com/freetype/freetype.git +[submodule "Keishiki/ext/implot"] + path = Keishiki/ext/implot + url = https://github.com/epezent/implot.git diff --git a/Keishiki/CMakeLists.txt b/Keishiki/CMakeLists.txt index 9b7a9a2..6682fd6 100644 --- a/Keishiki/CMakeLists.txt +++ b/Keishiki/CMakeLists.txt @@ -7,15 +7,16 @@ project("Main") file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp) file(GLOB IMGUI_SRC ${PROJECT_SOURCE_DIR}/ext/imgui/*.cpp) +file(GLOB IMPLOT_SRC ${PROJECT_SOURCE_DIR}/ext/implot/*.cpp) -add_executable (Keishiki ${IMGUI_SRC} +add_executable (Keishiki ${IMGUI_SRC} ${IMPLOT_SRC} "ext/imgui_impl_bgfx.cpp" "ext/imgui/backends/imgui_impl_sdl2.cpp" "ext/imgui/misc/cpp/imgui_stdlib.cpp" ${SRC_FILES}) set_property(TARGET Keishiki PROPERTY CXX_STANDARD 23) -include_directories ("include" "include/ext" "ext/imgui" "ext/ImNodeFlow/include") +include_directories ("include" "include/ext" "ext/imgui" "ext/implot") add_subdirectory("ext/freetype") add_subdirectory("ext/bgfx") diff --git a/Keishiki/UI.cpp b/Keishiki/UI.cpp index d3166d2..95b6263 100644 --- a/Keishiki/UI.cpp +++ b/Keishiki/UI.cpp @@ -10,6 +10,8 @@ #include "backends/imgui_impl_sdl2.h" #include "imgui_impl_bgfx.h" +#include + #include #define STB_IMAGE_WRITE_IMPLEMENTATION @@ -843,7 +845,36 @@ namespace K::UI { ImGui::TableSetColumnIndex(4); auto p = ImGui::GetCursorScreenPos(); - // draw on tl -- implot probably + // plot uniform + ImPlot::PushStyleVar(ImPlotStyleVar_PlotPadding, {0.0f, 0.0f}); + ImPlot::PushStyleVar(ImPlotStyleVar_FitPadding, {.1f, .1f}); + ImPlot::PushStyleColor(ImPlotCol_FrameBg, 0); + ImPlot::PushStyleColor(ImPlotCol_PlotBg, 0); + ImPlot::PushStyleColor(ImPlotCol_PlotBorder, 0); + if (connected_v.index() == 1 && ImPlot::BeginPlot("uniform", {view_width, row_height * 2.0f}, ImPlotFlags_CanvasOnly | ImPlotFlags_NoFrame | ImPlotFlags_NoInputs)) { + ImPlot::SetupAxis(ImAxis_X1, "time", ImPlotAxisFlags_NoDecorations | ImPlotAxisFlags_NoHighlight); + ImPlot::SetupAxis(ImAxis_Y1, "val", ImPlotAxisFlags_NoDecorations | ImPlotAxisFlags_NoHighlight | ImPlotAxisFlags_AutoFit); + struct PlotInfo { f32 begin, end; i32 samples; const CompState &s; PlugboardGraph::ConnectInfo &connected_v; }; + struct PlotInfo info { + .begin = view_left * static_cast(s.frame_max + 1), + .end = view_right * static_cast(s.frame_max + 1), + .samples = 50, + .s = s, + .connected_v = std::get<1>(connected_v) + }; + ImPlot::SetupAxisLimits(ImAxis_X1, info.begin, info.end, ImGuiCond_Always); + ImPlot::SetupFinish(); + ImPlot::PlotLineG("v", [](int idx, void* user_data) -> ImPlotPoint { + PlotInfo i = *(PlotInfo*)user_data; + f32 x = i.begin + (i.end - i.begin) * static_cast(idx) / static_cast(i.samples); + CompState ss = i.s; + ss.current_frame = static_cast(std::round(x)); + return {x, std::get::type>(PlugboardGraph::Eval(ss, i.connected_v))}; + }, &info, info.samples); + ImPlot::EndPlot(); + } + ImPlot::PopStyleColor(3); + ImPlot::PopStyleVar(2); ImGui::SetCursorScreenPos(p); @@ -896,26 +927,27 @@ namespace K::UI { static std::map m_copy{}; static u32 dragging{}; static i64 drag_og = -1; - if (drag_og == -1) { + if (drag_og == -1) { // premature optimization is the root of good performance !! + f32 *last_val = nullptr; + u32 last_x = 0; for (auto& [k, segment] : *m) { - if (TimelineFrameInView(view_left, view_right, k, s.frame_max)) { - ImGui::SetCursorScreenPos( - {TimelineFrameToScreenView(view_left, view_amt, view_width, k, - s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); - ImGui::Button("k", {0.0f, row_height * .8f}); - if (ImGui::IsItemClicked()) { - m_copy = *m; - drag_og = k; - } - if (ImGui::IsItemActive()) { - dragging = TimelineScreenViewToFrame(view_left, view_amt, view_width, - std::clamp(ImGui::GetMousePos().x - - tl_init_pos.x, 0.0f, - view_width), s.frame_max); - } - if (drag_og == k && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { - drag_og = -1; - } + if (last_val != nullptr && *last_val != segment.value) { + ImGui::SameLine(0.0f, 0.0f); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + row_height / 2.5f); + ImGui::PushID(k); + ImGui::Button("##strip", {TimelineFrameToScreenView(view_left, view_amt, view_width, k, s.frame_max) - TimelineFrameToScreenView(view_left, view_amt, view_width, last_x, s.frame_max), row_height * .2f}); + ImGui::PopID(); + } + last_val = &segment.value; + last_x = k; + + ImGui::SetCursorScreenPos( + {TimelineFrameToScreenView(view_left, view_amt, view_width, k, + s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); + ImGui::Button("k", {0.0f, row_height * .8f}); + if (ImGui::IsItemClicked()) { + m_copy = *m; + drag_og = k; } } } @@ -936,10 +968,6 @@ namespace K::UI { {TimelineFrameToScreenView(view_left, view_amt, view_width, dragging, s.frame_max) + begin_tl.x - 2.5f, begin_tl.y}); ImGui::Button("k", {0.0f, row_height * .8f}); - if (ImGui::IsItemClicked()) { - m_copy = *m; - drag_og = k; - } if (ImGui::IsItemActive()) { dragging = TimelineScreenViewToFrame(view_left, view_amt, view_width, std::clamp(ImGui::GetMousePos().x - @@ -1248,6 +1276,7 @@ namespace K::UI { void Init(SDL_Window *window) { ImGui::CreateContext(); + ImPlot::CreateContext(); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; @@ -1279,6 +1308,7 @@ namespace K::UI { DestroyViewport(s); ImGui_Implbgfx_Shutdown(); ImGui_ImplSDL2_Shutdown(); + ImPlot::DestroyContext(); ImGui::DestroyContext(); } } diff --git a/Keishiki/ext/implot b/Keishiki/ext/implot new file mode 160000 index 0000000..f156599 --- /dev/null +++ b/Keishiki/ext/implot @@ -0,0 +1 @@ +Subproject commit f156599faefe316f7dd20fe6c783bf87c8bb6fd9 diff --git a/README.md b/README.md index f5103b7..aa9e6fe 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ## Libraries - [bgfx](https://github.com/bkaradzic/bgfx) - [Dear ImGui](https://github.com/ocornut/imgui) +- [ImPlot](https://github.com/epezent/implot) - [FreeType](https://freetype.org/) - [imgui_impl_bgfx](https://gist.github.com/pr0g/aff79b71bf9804ddb03f39ca7c0c3bbb) - [SDL2](https://www.libsdl.org/) @@ -14,4 +15,5 @@ - [Automaton](https://github.com/0b5vr/automaton) - [Blender](https://www.blender.org/) - [Adobe After Effects](https://www.adobe.com/products/aftereffects) +- [Notch](https://www.notch.one/) - [Houdini](https://www.sidefx.com/products/houdini/) diff --git a/TODO.md b/TODO.md index f9df6cd..b3575aa 100644 --- a/TODO.md +++ b/TODO.md @@ -1,23 +1,23 @@ # NOW ## Chores -- Blending modes +- actually write the blending modes (everything is just alpha over right now) - Node groups ## Compositor +- Playback... - Manage Samplers -- (Resources in general) - - Blender previews (important) + - Blender previews (important !) - Data model for comps - Dump and read back state, (de)serialization!!! - Non-negotiables: - Text (idea: index-based evaluation in plugboard) - - Shapes (idea: embed glisp :mmtroll:, need to inquire -- still a lot of friction for simple shapes if we don't also get the glisp tools) - - External data driving (json or something else?) -- Pre-compose + - Shapes (idea: embed glisp :mmtroll:, need to inquire -- still a lot of friction for simple shapes if we don't also get the glisp gizmos) + - External data driving (csv, json or something else?) -- use a node to select source +- Pre-compose/Layer Groups (jokes -- can be completely UI side) - Motion blur -- Layer Groups (jokes -- can be completely UI side) ## UI -- Viewport gizmos (Layer-specific & nodes -- can separate into different tools?) +- Viewport gizmos (Layer-specific & nodes -- can separate into different tools?) -- Not sure how to go about this - Node loop detection (separate DFS (extra work) or be smart in recursion) - detect time-sensitive nodes in tree and display on timeline