From e25a28f3bf3847b297b99ac656b62e3735cfa923 Mon Sep 17 00:00:00 2001 From: BadQuanta Date: Thu, 14 May 2026 01:15:58 +0000 Subject: [PATCH] First commit. --- CMakeLists.txt | 47 ++++++++++++++++++ README.md | 10 ++++ examples/CMakeLists.txt | 3 ++ examples/is3r-basics.cpp | 105 +++++++++++++++++++++++++++++++++++++++ include/hdk/is3r.hpp | 55 ++++++++++++++++++++ tests/CMakeLists.txt | 0 6 files changed, 220 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 examples/CMakeLists.txt create mode 100644 examples/is3r-basics.cpp create mode 100644 include/hdk/is3r.hpp create mode 100644 tests/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0bcd4f7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.20) + +project(hdk-imgui-sdl-renderer + VERSION 0.0.1 + LANGUAGES CXX +) + +option(HDK_IMGUI_SDL_RENDERER_TESTS "Build hdk-imgui-sdl-renderer tests" ${HDK_TESTS}) +option(HDK_IMGUI_SDL_RENDERER_EXAMPLES "Build hdk-imgui-sdl-renderer examples" ${HDK_EXAMPLES}) + +if(HDK_IMGUI_SDL_RENDERER_EXAMPLES) + add_subdirectory(examples) +endif() + +if(HDK_IMGUI_SDL_RENDERER_TESTS) + add_subdirectory(tests) +endif() + +find_package(SDL3 REQUIRED) + +include(FetchContent) +FetchContent_Declare(imgui + GIT_REPOSITORY https://github.com/ocornut/imgui + GIT_TAG docking +) +FetchContent_MakeAvailable(imgui) + +set(HDK_IMGUI_SDL_RENDERER_SOURCES + ${imgui_SOURCE_DIR}/imgui.cpp + ${imgui_SOURCE_DIR}/imgui_demo.cpp + ${imgui_SOURCE_DIR}/imgui_draw.cpp + ${imgui_SOURCE_DIR}/imgui_tables.cpp + ${imgui_SOURCE_DIR}/imgui_widgets.cpp + ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp + ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp +) + +add_library(hdk-is3r STATIC ${HDK_IMGUI_SDL_RENDERER_SOURCES}) +target_link_libraries(hdk-is3r PUBLIC hdk-sdl SDL3::SDL3) +target_include_directories(hdk-is3r PUBLIC + $ + $ + $ + $ +) + +target_compile_features(hdk-is3r PUBLIC cxx_std_17) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1931c0d --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# imgui-sdl-renderer + +This is the glue library required to have an ImGui renderer implementation for SDL's rendering API. + +As simple as it sounds but it may get split into three libraries in the future: +- `imgui-sdl-renderer`: Just the SDL Renderer glue for ImGui +- `imgui-sdl`: General SDL glue for ImGui (input handling, clipboard, etc.) +- 'imgui': Core ImGUI code that has no dependencies on any backend. + +This will be so that we can very easily add `imgui-sdl-opengl` and `imgui-sdl-vulkan`, etc. in the future without having to duplicate the SDL glue or ImGUI core code. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..8f2b822 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_executable(is3r-basics is3r-basics.cpp) +target_link_libraries(is3r-basics PRIVATE hdk-is3r) \ No newline at end of file diff --git a/examples/is3r-basics.cpp b/examples/is3r-basics.cpp new file mode 100644 index 0000000..de51d91 --- /dev/null +++ b/examples/is3r-basics.cpp @@ -0,0 +1,105 @@ +#include +#include +#include + +#include "hdk/is3r.hpp" + +namespace simui_example { + using namespace hdk; + + class SimGuiApp : public is3r::Is3rApp { + public: + grid::eps::TapScope taps; + const sdl::evt::EventConduit::Callback_t LOG_EVENT = [&](SDL_Event* event) { + auto description = sdl::Event::GetDescription<1024>(event); + AppLog.Debug("Event received: %s", description.c_str()); + }; + + sdl::Window window { nullptr }; + sdl::Renderer renderer { nullptr }; + sdl::Surface surface { nullptr }; + sdl::Texture texture { nullptr }; + + float main_scale = 1.0f; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + void InitIMUI() { + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + // ImGui::StyleColorsLight(); + + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style + // scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi + = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically + // overrides this for every window depending on the current monitor) + + // Setup Platform/Renderer backends + ImGui_ImplSDL3_InitForSDLRenderer(window, renderer); + ImGui_ImplSDLRenderer3_Init(renderer); + } + + virtual SDL_AppResult Init(int argc, char* argv[]) override { + SDL_SetAppMetadata("SimGui Example", "0.0.1", "institute.ufp.hdk.simui.examples.simgui"); + sdl::Log::SetPriorities(SDL_LOG_PRIORITY_DEBUG); + auto [w, r] = sdl::CreateWindowAndRenderer("SimGui Example", 800, 600, 0); + window = w; + renderer = r; + if (!window || !renderer) { + SDL_Log("Failed to create window or renderer: %s", SDL_GetError()); + return AppStatus = SDL_APP_FAILURE; + } + InitIMUI(); + + taps << events.Quit.Attach([&](SDL_Event* event) { + AppStatus = SDL_APP_SUCCESS; + printf("Quit event received, exiting...\n"); + }); + + return AppStatus; + } + + virtual SDL_AppResult Iterate() override { + + // Start the Dear ImGui frame + ImGui_ImplSDLRenderer3_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + { + ImGui::Begin("ImGUI SDL Renderer Basics Example"); + ImGui::Text("Hello, world!"); + ImGui::Button("Quit") && (AppStatus = SDL_APP_SUCCESS); + ImGui::ColorEdit3("clear color", (float*)&clear_color); + ImGui::End(); + } + ImGui::Render(); + ImGuiIO& io = ImGui::GetIO(); + renderer.SetScale(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + renderer.SetDrawColorFloat(clear_color.x, clear_color.y, clear_color.z, clear_color.w); + renderer.Clear(); + ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); + renderer.Present(); + return AppStatus; + } + + virtual void Quit(SDL_AppResult code) override { + ImGui_ImplSDLRenderer3_Shutdown(); + ImGui_ImplSDL3_Shutdown(); + ImGui::DestroyContext(); + renderer = nullptr; + window = nullptr; + } + }; +} + +HDK_SDL_MAIN_CLASS(simui_example::SimGuiApp) \ No newline at end of file diff --git a/include/hdk/is3r.hpp b/include/hdk/is3r.hpp new file mode 100644 index 0000000..2cc8b9e --- /dev/null +++ b/include/hdk/is3r.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace hdk::is3r { + class Is3rWindowContext; + class Is3rApp : public sdl::ProtectedApp { + public: + virtual SDL_AppResult Event(SDL_Event* event) override { + ImGui_ImplSDL3_ProcessEvent(event); + return ProtectedApp::Event(event); + } + + Is3rWindowContext CreateWindow(const char* title, int width, int height, SDL_WindowFlags flags); + }; + + struct Is3rWindowData { + sdl::Window window { nullptr }; + sdl::Renderer renderer { nullptr }; + sdl::evt::WindowEvents window_events; + grid::eps::Conduit<> on_iterate; + grid::eps::Conduit<> on_frame; + grid::eps::TapScope taps; + }; + + class Is3rWindowContext : public grid::SharedPtrWrapper { + public: + using SharedPtrWrapper::SharedPtrWrapper; + + static Is3rWindowContext Create(const char* title, int width, int height, SDL_WindowFlags flags) { + auto [window, renderer] = sdl::CreateWindowAndRenderer(title, width, height, flags); + if (!window || !renderer) { + SDL_Log("Failed to create window or renderer: %s", SDL_GetError()); + return Is3rWindowContext(nullptr); + } + auto* data = new Is3rWindowData{.window = window, .renderer = renderer}; + auto context = Is3rWindowContext(get_or_cache(data, [](Is3rWindowData* data) { delete data; })); + return context; + } + }; + + inline Is3rWindowContext Is3rApp::CreateWindow(const char* title, int width, int height, SDL_WindowFlags flags) { + auto ctx = Is3rWindowContext::Create(title, width, height, flags); + auto wid = ctx->window.GetID(); + ctx->taps << events.Window[wid] % ctx->window_events; + ctx->taps << OnIterate % ctx->on_iterate; + return ctx; + } + +} \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..e69de29