#include #include #include #include #include #include #ifdef JULIET_ENABLE_IMGUI #include #include extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); namespace Juliet::ImGuiService { namespace { ImGuiContext* g_ImGuiContext = nullptr; bool g_Initialized = false; struct FreeNode { size_t Size; FreeNode* Next; }* FirstFreeNode = nullptr; // Dedicated Paged Arena for ImGui // Sharing the same underlying Engine Pool for blocks, but separate Arena chain. Arena* g_ImGuiArena = {}; void* ImGuiAllocWrapper(size_t size, void* /*user_data*/) { Assert(size); // I trust Dear Imgui but just in case // Let's make FreeNode a part of each alloc. size_t sizeOfHeader = sizeof(FreeNode); size_t totalSize = AlignPow2(size + sizeOfHeader, 16); FreeNode** previous = &FirstFreeNode; FreeNode* current = FirstFreeNode; // Find a free node if there is one big enough while (current != nullptr) { if (current->Size >= totalSize) { *previous = current->Next; return current + 1; } previous = ¤t->Next; current = current->Next; } auto* ptr = ArenaPushSize(g_ImGuiArena, totalSize, 8, false JULIET_DEBUG_PARAM("ImGuiAlloc {}", totalSize)); FreeNode* node = static_cast(ptr); node->Size = totalSize; node->Next = nullptr; return node + 1; } void ImGuiFreeWrapper(void* ptr, void* /*user_data*/) { Assert(ptr); // I trust Dear Imgui but just in case FreeNode* node = reinterpret_cast(static_cast(ptr) - sizeof(FreeNode)); node->Next = FirstFreeNode; FirstFreeNode = node; } } // namespace void Initialize(NonNullPtr window) { Assert(!g_Initialized); // Initialize ImGui Arena using Engine Pool g_ImGuiArena = ArenaAllocate({ .Name = "Juliet" }); // Setup Allocator ImGui::SetAllocatorFunctions(ImGuiAllocWrapper, ImGuiFreeWrapper, nullptr); IMGUI_CHECKVERSION(); g_ImGuiContext = ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls // io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls ImGui::StyleColorsDark(); // Platform Init auto* win32State = static_cast(window->State); ImGui_ImplWin32_Init(win32State->Handle); g_Initialized = true; } void Shutdown() { Assert(g_Initialized); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(g_ImGuiContext); g_ImGuiContext = nullptr; g_Initialized = false; } void NewFrame() { Assert(g_Initialized); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); } void Render() { Assert(g_Initialized); ImGui::Render(); } bool IsInitialized() { return g_Initialized; } ImGuiContext* GetContext() { return g_ImGuiContext; } void RunTests() { printf("ImGuiService: Running Unit Tests...\n"); Juliet::UnitTest::TestImGui(); } } // namespace Juliet::ImGuiService #endif // JULIET_ENABLE_IMGUI