From 7a118ef676f9d328b1f55f65ccfb3a08bdb037e6 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 15 Jan 2026 14:55:24 +0100 Subject: [PATCH 01/50] feat(gameclient) Introduce imgui console introduces working imgui console and demo window in debug mode --- Core/CMakeLists.txt | 1 + Core/GameEngine/CMakeLists.txt | 7 + Core/GameEngine/Include/GameClient/Console.h | 36 ++ .../Source/GameClient/GUI/Console.cpp | 243 +++++++++ Core/Libraries/CMakeLists.txt | 5 + Core/Libraries/Source/ImGui/CMakeLists.txt | 62 +++ .../ImGui/dx8_backend/imgui_impl_dx8.cpp | 479 ++++++++++++++++++ .../Source/ImGui/dx8_backend/imgui_impl_dx8.h | 16 + Core/Libraries/Source/ImGui/imconfig.h | 147 ++++++ .../Source/GameClient/GameClient.cpp | 31 ++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 66 ++- GeneralsMD/Code/Main/WinMain.cpp | 11 +- cmake/config-build.cmake | 1 + 13 files changed, 1103 insertions(+), 2 deletions(-) create mode 100644 Core/GameEngine/Include/GameClient/Console.h create mode 100644 Core/GameEngine/Source/GameClient/GUI/Console.cpp create mode 100644 Core/Libraries/Source/ImGui/CMakeLists.txt create mode 100644 Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp create mode 100644 Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h create mode 100644 Core/Libraries/Source/ImGui/imconfig.h diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index ccf2513e5e6..dd3b1ba8bdd 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(corei_always INTERFACE core_utility corei_libraries_include resources + lib_imgui ) target_link_libraries(corei_always_no_pch INTERFACE core_config diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 13fa1158a01..e8e5024aa74 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -1164,6 +1164,13 @@ else() ) endif() +if(RTS_BUILD_OPTION_IMGUI) + list(APPEND GAMEENGINE_SRC + Source/GameClient/GUI/Console.cpp + Include/GameClient/Console.h + ) +endif () + add_library(corei_gameengine_private INTERFACE) add_library(corei_gameengine_public INTERFACE) diff --git a/Core/GameEngine/Include/GameClient/Console.h b/Core/GameEngine/Include/GameClient/Console.h new file mode 100644 index 00000000000..b34e32ce45e --- /dev/null +++ b/Core/GameEngine/Include/GameClient/Console.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include + +#include "imgui.h" + +class Console +{ +public: + Console(); + ~Console() = default; + + void Draw(float openFraction = 0.5f); + + // Manually execute a console command (same logic used when the user presses Enter). + void ExecCommand(const char* command_line); + + // Add a log entry (printf-style). + void AddLog(const char* fmt, ...) IM_FMTARGS(2); + + // Clear the entire log buffer. + void ClearLog(); + +private: + static int TextEditCallbackStub(ImGuiInputTextCallbackData* data); + int TextEditCallback(ImGuiInputTextCallbackData* data); + +private: + char InputBuf[256]{}; + std::vector Items; + bool ScrollToBottom; + std::vector History; + int HistoryPos; // For navigating command history via up/down keys +}; + +extern Console DevConsole; diff --git a/Core/GameEngine/Source/GameClient/GUI/Console.cpp b/Core/GameEngine/Source/GameClient/GUI/Console.cpp new file mode 100644 index 00000000000..d986c5ef3cd --- /dev/null +++ b/Core/GameEngine/Source/GameClient/GUI/Console.cpp @@ -0,0 +1,243 @@ +#include "GameClient/Console.h" +Console DevConsole; + +// Set this to your app�s version string: +static const char* VERSION_STRING = "Command and Conquer Generals Next-Gen v0.06"; + +Console::Console() + : ScrollToBottom(false) + , HistoryPos(-1) +{ + ClearLog(); + AddLog("Welcome to the Quake-Style Console!"); +} + +void Console::Draw(float openFraction) +{ + if (openFraction <= 0.0f) + return; + + if (openFraction > 1.0f) + openFraction = 1.0f; + + ImGuiIO& io = ImGui::GetIO(); + ImVec2 screenSize = io.DisplaySize; + + float consoleHeight = screenSize.y * openFraction; + ImVec2 consolePos = ImVec2(0, 0); + ImVec2 consoleSize = ImVec2(screenSize.x, consoleHeight); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.05f, 0.05f, 0.05f, 0.8f)); + + ImGui::SetNextWindowPos(consolePos); + ImGui::SetNextWindowSize(consoleSize); + ImGui::Begin("QuakeConsoleOverlay", + nullptr, + ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoMove + | ImGuiWindowFlags_NoScrollbar + | ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_NoSavedSettings + | ImGuiWindowFlags_NoBringToFrontOnFocus); + + //ImGui::PushFont(g_BigConsoleFont); + + float footerHeight = ImGui::GetTextLineHeight() + 8; // space for input + some padding + ImGui::BeginChild("ConsoleScrollingRegion", ImVec2(0, -footerHeight), false); + + // Draw existing console lines + for (int i = 0; i < (int)Items.size(); i++) + { + const char* item = Items[i].c_str(); + + if (strncmp(item, "ASSERTION FAILURE:", 18) == 0) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); + ImGui::TextUnformatted(item); + ImGui::PopStyleColor(); + } + else if (strstr(item, "[error]")) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.4f, 0.4f, 1.f)); + ImGui::TextUnformatted(item); + ImGui::PopStyleColor(); + } + else if (strncmp(item, "# ", 2) == 0) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.8f, 0.6f, 1.f)); + ImGui::TextUnformatted(item); + ImGui::PopStyleColor(); + } + else + { + ImGui::TextUnformatted(item); + } + } + + if (ScrollToBottom) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; + + ImGui::EndChild(); + + { + // Make an (almost) invisible InputText that still captures user input: + ImGui::PushItemWidth(-1); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.0f); // fully invisible + // Focus on this widget so it captures keyboard input: + if (ImGui::IsWindowAppearing()) + ImGui::SetKeyboardFocusHere(); + + // Use same callback flags for history/tab-completion as before: + if (ImGui::InputText("##HiddenConsoleInput", InputBuf, IM_ARRAYSIZE(InputBuf), + ImGuiInputTextFlags_EnterReturnsTrue + | ImGuiInputTextFlags_CallbackHistory + | ImGuiInputTextFlags_CallbackCompletion, + &TextEditCallbackStub, (void*)this)) + { + // If user pressed Enter: + char* s = InputBuf; + if (s[0] != '\0') + ExecCommand(s); + s[0] = '\0'; + } + ImGui::PopStyleVar(); // restore alpha + ImGui::PopItemWidth(); + + // Now manually render the input line on the far left: + // e.g. a Quake-like prompt: ">" or "#" etc. + ImGui::TextUnformatted("> "); + ImGui::SameLine(); + ImGui::TextUnformatted(InputBuf); + + // Then place the version text on the far right: + // We can compute how much space is left and push the text to the right: + float versionTextWidth = ImGui::CalcTextSize(VERSION_STRING).x; + float availableWidth = ImGui::GetContentRegionAvail().x; + ImGui::SameLine(std::max(0.0f, availableWidth - versionTextWidth)); + ImGui::TextUnformatted(VERSION_STRING); + } + + //ImGui::PopFont(); + ImGui::End(); // end main window + + ImGui::PopStyleColor(); + ImGui::PopStyleVar(2); + + // ------------------------------------------------------------ + // Draw the small orange line where the console ends + // ------------------------------------------------------------ + ImDrawList* fg = ImGui::GetForegroundDrawList(); + // Coordinates for a line across the entire screen at y = consoleHeight + ImVec2 start = ImVec2(0.0f, consoleHeight); + ImVec2 end = ImVec2(screenSize.x, consoleHeight); + + // Use a bright orange color; thickness = 2.0f + fg->AddLine(start, end, IM_COL32(255, 128, 0, 255), 2.0f); +} + +// ----------------------------------------------------------------------------- +// ExecCommand, AddLog, ClearLog, etc. remain the same +// ----------------------------------------------------------------------------- +void Console::ExecCommand(const char* command_line) +{ + AddLog("# %s", command_line); + + HistoryPos = -1; + for (int i = (int)History.size() - 1; i >= 0; i--) + { + if (strcmp(History[i].c_str(), command_line) == 0) + { + History.erase(History.begin() + i); + break; + } + } + History.push_back(command_line); + + if (strcmp(command_line, "CLEAR") == 0) + { + ClearLog(); + } + else if (strcmp(command_line, "HELP") == 0) + { + AddLog("Commands:"); + AddLog(" HELP"); + AddLog(" CLEAR"); + AddLog(" HISTORY"); + } + else if (strcmp(command_line, "HISTORY") == 0) + { + for (int i = (int)History.size() - 1; i >= 0; i--) + AddLog("%3d: %s", i, History[i].c_str()); + } + else + { + AddLog("Unknown command: '%s'", command_line); + } + + ScrollToBottom = true; +} + +void Console::AddLog(const char* fmt, ...) +{ + char buffer[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(buffer, IM_ARRAYSIZE(buffer), fmt, args); + buffer[IM_ARRAYSIZE(buffer) - 1] = 0; + va_end(args); + + Items.push_back(buffer); + ScrollToBottom = true; +} + +void Console::ClearLog() +{ + Items.clear(); + ScrollToBottom = true; +} + +int Console::TextEditCallbackStub(ImGuiInputTextCallbackData* data) +{ + Console* console = (Console*)data->UserData; + return console->TextEditCallback(data); +} + +int Console::TextEditCallback(ImGuiInputTextCallbackData* data) +{ + switch (data->EventFlag) + { + case ImGuiInputTextFlags_CallbackCompletion: + // Optional: handle tab-completion + break; + case ImGuiInputTextFlags_CallbackHistory: + { + const int prevHistoryPos = HistoryPos; + if (data->EventKey == ImGuiKey_UpArrow) + { + if (HistoryPos == -1) + HistoryPos = (int)History.size() - 1; + else if (HistoryPos > 0) + HistoryPos--; + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + if (HistoryPos != -1) + if (++HistoryPos >= (int)History.size()) + HistoryPos = -1; + } + + if (prevHistoryPos != HistoryPos && HistoryPos != -1) + { + const std::string& historyStr = History[HistoryPos]; + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, historyStr.c_str()); + } + break; + } + } + return 0; +} \ No newline at end of file diff --git a/Core/Libraries/CMakeLists.txt b/Core/Libraries/CMakeLists.txt index 1658bfbb9ee..51d2caf42a6 100644 --- a/Core/Libraries/CMakeLists.txt +++ b/Core/Libraries/CMakeLists.txt @@ -10,3 +10,8 @@ add_subdirectory(Source/debug) add_subdirectory(Source/EABrowserDispatch) add_subdirectory(Source/EABrowserEngine) add_subdirectory(Source/Compression) + +# Imgui library +if (RTS_BUILD_OPTION_IMGUI) + add_subdirectory(Source/ImGui) +endif () \ No newline at end of file diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt new file mode 100644 index 00000000000..ff2330ad24d --- /dev/null +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -0,0 +1,62 @@ +FetchContent_Declare( + imgui + GIT_REPOSITORY https://github.com/ocornut/imgui.git + GIT_TAG 791ad9b82db44ada9fedb3e26b2d900974ac0959 + SYSTEM +) + +FetchContent_MakeAvailable(imgui) + +# Main IMGUI sources we are going to need +set(IMGUI_BASE_SRCS + "${imgui_SOURCE_DIR}/imgui.cpp" + "${imgui_SOURCE_DIR}/imgui_draw.cpp" + "${imgui_SOURCE_DIR}/imgui_tables.cpp" + "${imgui_SOURCE_DIR}/imgui_widgets.cpp" + "${imgui_SOURCE_DIR}/imgui_demo.cpp" +) + + +# Main Win32 DX8 specific sources we are going to need we can specify moore if we need extra platforms +set(IMGUI_WIN32_DX8_IMPL_SRCS + "${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp" + "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp" +) + +# All Win32 DX8 sources +set(IMGUI_WIN32_DX8_ALL_SRCS ${IMGUI_BASE_SRCS} ${IMGUI_WIN32_DX8_IMPL_SRCS}) + +# All Include directories +set(IMGUI_INCLUDE_DIRS + "${imgui_SOURCE_DIR}" + "${imgui_SOURCE_DIR}/backends" + # DX8 override. Remove the following once we are using a standard backend + "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend" +) + +# start target build section +# we currently have a hard dependency on dx8 and win32 api +if (WIN32) + # for now we only need it in debug builds + # RTS_BUILD_OPTION_DEBUG also works since it is a Debug build profile + if ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug") ) + MESSAGE(FATAL_ERROR "ImGui integration is currently only possible in Debug build modes") + endif () + + MESSAGE(STATUS "Enabling imgui console integration") + + add_library(lib_imgui STATIC ${IMGUI_WIN32_DX8_ALL_SRCS}) + target_include_directories(lib_imgui PUBLIC ${IMGUI_INCLUDE_DIRS}) + target_link_libraries(lib_imgui PRIVATE d3d8lib) + + # use our own imconfig.h + target_compile_definitions(lib_imgui + PRIVATE IMGUI_DISABLE_DEFAULT_IMCONFIG + PRIVATE IMGUI_USER_CONFIG="${CMAKE_CURRENT_LIST_DIR}/imconfig.h" + INTERFACE RTS_IMGUI_ENABLED + ) +else () + # currently only WIN32 DX is supported + MESSAGE(FATAL_ERROR "Non-Windows platforms currently not supported for ImGui integration ${MSG_ERR_SUFFIX}") +endif () +# end target build section diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp new file mode 100644 index 00000000000..44272dbbeb6 --- /dev/null +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -0,0 +1,479 @@ +#include +#include "imgui_impl_dx8.h" + +// DirectX +#include "d3d8.h" + +// based on https://github.com/KoMaR1911/C4USMultiHack-Metin2/blob/main/EngineX-Pro/ImGui/imgui_impl_dx8.cpp + +// DirectX data +struct ImGui_ImplDX8_Data { + LPDIRECT3DDEVICE8 pd3dDevice; + LPDIRECT3DVERTEXBUFFER8 pVB; + LPDIRECT3DINDEXBUFFER8 pIB; + LPDIRECT3DVERTEXBUFFER8 maskVB; + LPDIRECT3DINDEXBUFFER8 maskIB; + LPDIRECT3DTEXTURE8 FontTexture; + int VertexBufferSize; + int IndexBufferSize; + IDirect3DSurface8* DepthBuffer; + IDirect3DSurface8* realDepthStencilBuffer; + + ImGui_ImplDX8_Data() { + memset((void*)this, 0, sizeof(*this)); + VertexBufferSize = 5000; + IndexBufferSize = 10000; + } +}; + +struct CUSTOMVERTEX { + float pos[3]; + D3DCOLOR col; + float uv[2]; +}; +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) + +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IMGUI_COL_TO_DX8_ARGB(_COL) (_COL) +#else +#define IMGUI_COL_TO_DX8_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16)) +#endif + +ImGui_ImplDX8_Data* ImGui_ImplDX8_GetBackendData() { + return ImGui::GetCurrentContext() ? (ImGui_ImplDX8_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; +} + +// Functions +void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + + IDirect3DSurface8* pSurface{}; + D3DSURFACE_DESC d3dSize{}; + if (SUCCEEDED(bd->pd3dDevice->GetRenderTarget(&pSurface)) && SUCCEEDED(pSurface->GetDesc(&d3dSize))) { + // Setup viewport + D3DVIEWPORT8 vp{}; + vp.X = vp.Y = 0; + vp.Width = d3dSize.Width; + vp.Height = d3dSize.Height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + bd->pd3dDevice->SetViewport(&vp); + } + if (pSurface) { + pSurface->Release(); + pSurface = NULL; + } + + // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. + bd->pd3dDevice->GetDepthStencilSurface(&bd->realDepthStencilBuffer); + bd->pd3dDevice->SetRenderTarget(nullptr, bd->DepthBuffer); + bd->pd3dDevice->SetPixelShader(NULL); + bd->pd3dDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX); + bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTEXF_LINEAR); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); + // This below is needed for the entire Touhou series from Touhou 6! + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + + // Setup orthographic projection matrix + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() + { + float L = draw_data->DisplayPos.x + 0.5f; + float R = draw_data->DisplayPos.x + d3dSize.Width + 0.5f; + float T = draw_data->DisplayPos.y + 0.5f; + float B = draw_data->DisplayPos.y + d3dSize.Height + 0.5f; + D3DMATRIX mat_identity = {{{ + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }}}; + D3DMATRIX mat_projection = {{{ + 2.0f / (R - L), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f / (T - B), 0.0f, 0.0f, + 0.0f, 0.0f, 0.5f, 0.0f, + (L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f, + }}}; + bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); + bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); + bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection); + } +} + +void build_mask_vbuffer(const RECT* rect) { + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + CUSTOMVERTEX* vtx_dst{}; + bd->maskVB->Lock(0, (UINT)(6 * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, 0); + vtx_dst[0].pos[0] = (float)rect->left; + vtx_dst[0].pos[1] = (float)rect->bottom; + vtx_dst[0].pos[2] = 0; + vtx_dst[1].pos[0] = (float)rect->left; + vtx_dst[1].pos[1] = (float)rect->top; + vtx_dst[1].pos[2] = 0; + vtx_dst[2].pos[0] = (float)rect->right; + vtx_dst[2].pos[1] = (float)rect->top; + vtx_dst[2].pos[2] = 0; + vtx_dst[3].pos[0] = (float)rect->left; + vtx_dst[3].pos[1] = (float)rect->bottom; + vtx_dst[3].pos[2] = 0; + vtx_dst[4].pos[0] = (float)rect->right; + vtx_dst[4].pos[1] = (float)rect->top; + vtx_dst[4].pos[2] = 0; + vtx_dst[5].pos[0] = (float)rect->right; + vtx_dst[5].pos[1] = (float)rect->bottom; + vtx_dst[5].pos[2] = 0; + vtx_dst[0].col = 0xFFFFFFFF; + vtx_dst[1].col = 0xFFFFFFFF; + vtx_dst[2].col = 0xFFFFFFFF; + vtx_dst[3].col = 0xFFFFFFFF; + vtx_dst[4].col = 0xFFFFFFFF; + vtx_dst[5].col = 0xFFFFFFFF; + vtx_dst[0].uv[0] = 0; + vtx_dst[0].uv[1] = 0; + vtx_dst[1].uv[0] = 0; + vtx_dst[1].uv[1] = 0; + vtx_dst[2].uv[0] = 0; + vtx_dst[2].uv[1] = 0; + vtx_dst[3].uv[0] = 0; + vtx_dst[3].uv[1] = 0; + vtx_dst[4].uv[0] = 0; + vtx_dst[4].uv[1] = 0; + vtx_dst[5].uv[0] = 0; + vtx_dst[5].uv[1] = 0; + bd->maskVB->Unlock(); +} + +// Render function. +void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { + // Avoid rendering when minimized + if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) + return; + + // Create and grow buffers if needed + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) { + if (bd->pVB) { + bd->pVB->Release(); + bd->pVB = nullptr; + } + bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; + if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB) < 0) + return; + } + if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) { + if (bd->pIB) { + bd->pIB->Release(); + bd->pIB = nullptr; + } + bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; + if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB) < 0) + return; + } + + if (!bd->maskVB && !bd->maskIB) { + if (bd->pd3dDevice->CreateVertexBuffer(6 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->maskVB) < 0) return; + if (bd->pd3dDevice->CreateIndexBuffer(6, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->maskIB) < 0) return; + ImDrawIdx* idx_dst{}; + bd->maskIB->Lock(0, 6 * sizeof(ImDrawIdx), (BYTE**)&idx_dst, D3DLOCK_DISCARD); + idx_dst[0] = 0; + idx_dst[1] = 1; + idx_dst[2] = 2; + idx_dst[3] = 0; + idx_dst[4] = 2; + idx_dst[5] = 3; + bd->maskIB->Unlock(); + } + + // Backup the DX8 state + DWORD d3d8_state_block; + if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d8_state_block) < 0) + return; + if (bd->pd3dDevice->CaptureStateBlock(d3d8_state_block) < 0) { + bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); + return; + } + + // Backup the DX8 transform + D3DMATRIX last_world, last_view, last_projection; + bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world); + bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view); + bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); + + // Allocate buffers + CUSTOMVERTEX* vtx_dst{}; + ImDrawIdx* idx_dst{}; + if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, D3DLOCK_DISCARD) < 0) { + bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); + return; + } + if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (BYTE**)&idx_dst, D3DLOCK_DISCARD) < 0) { + bd->pVB->Unlock(); + bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); + return; + } + + // Copy and convert all vertices into a single contiguous buffer, convert colors to DX8 default format. + for (int n = 0; n < draw_data->CmdListsCount; n++) { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { + vtx_dst->pos[0] = vtx_src->pos.x; + vtx_dst->pos[1] = vtx_src->pos.y; + vtx_dst->pos[2] = 0.0f; + vtx_dst->col = IMGUI_COL_TO_DX8_ARGB(vtx_src->col); + vtx_dst->uv[0] = vtx_src->uv.x; + vtx_dst->uv[1] = vtx_src->uv.y; + vtx_dst++; + vtx_src++; + } + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + idx_dst += cmd_list->IdxBuffer.Size; + } + bd->pVB->Unlock(); + bd->pIB->Unlock(); + bd->pd3dDevice->SetStreamSource(0, bd->pVB, sizeof(CUSTOMVERTEX)); + bd->pd3dDevice->SetIndices(bd->pIB, 0); + bd->pd3dDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX); + + // Setup desired DX state + ImGui_ImplDX8_SetupRenderState(draw_data); + + // Render command lists + // (Because we merged all buffers into a single one, we maintain our own offset into them) + int global_vtx_offset = 0; + int global_idx_offset = 0; + ImVec2 clip_off = draw_data->DisplayPos; + for (int n = 0; n < draw_data->CmdListsCount; n++) { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != nullptr) { + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplDX8_SetupRenderState(draw_data); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else { + // Project clipping rectangles into framebuffer space + ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); + ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // Apply clipping rectangle, Bind texture, Draw + const RECT r = {(LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y}; + const LPDIRECT3DTEXTURE8 texture = (LPDIRECT3DTEXTURE8)pcmd->GetTexID(); + bd->pd3dDevice->SetTexture(0, texture); + build_mask_vbuffer(&r); + bd->pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, true); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, true); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0xFF); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILMASK, 0xFF); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + bd->pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0xFF); + bd->pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0f, 0); + bd->pd3dDevice->SetStreamSource(0, bd->maskVB, sizeof(CUSTOMVERTEX)); + bd->pd3dDevice->SetIndices(bd->maskIB, 0); + bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2); + bd->pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + bd->pd3dDevice->SetStreamSource(0, bd->pVB, sizeof(CUSTOMVERTEX)); + bd->pd3dDevice->SetIndices(bd->pIB, global_vtx_offset); + bd->pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0xF); + bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, false); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, true); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILWRITEMASK, 0); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILMASK, 0xFF); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_EQUAL); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0xFF); + bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3); + } + } + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; + } + + // Restore the DX8 transform + bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world); + bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view); + bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection); + + // Restore the DX8 state + bd->pd3dDevice->SetRenderTarget(nullptr, bd->realDepthStencilBuffer); + bd->realDepthStencilBuffer->Release(); + bd->realDepthStencilBuffer = nullptr; + bd->pd3dDevice->ApplyStateBlock(d3d8_state_block); + bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); +} + +bool ImGui_ImplDX8_Init(IDirect3DDevice8* device) { + ImGuiIO& io = ImGui::GetIO(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Setup backend capabilities flags + ImGui_ImplDX8_Data* bd = IM_NEW(ImGui_ImplDX8_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_dx8"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + + bd->pd3dDevice = device; + bd->pd3dDevice->AddRef(); + + return true; +} + +void ImGui_ImplDX8_Shutdown() { + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + ImGui_ImplDX8_InvalidateDeviceObjects(); + if (bd->pd3dDevice) + bd->pd3dDevice->Release(); + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + IM_DELETE(bd); +} + +bool ImGui_ImplDX8_CreateFontsTexture() { + // Build texture atlas + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + unsigned char* pixels; + int width, height, bytes_per_pixel; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); + + // Convert RGBA32 to BGRA32 +#ifndef IMGUI_USE_BGRA_PACKED_COLOR + if (io.Fonts->TexPixelsUseColors) { + ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); + for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) + *dst = IMGUI_COL_TO_DX8_ARGB(*src); + pixels = (unsigned char*)dst_start; + } +#endif + + // Upload texture to graphics system + bd->FontTexture = nullptr; + if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture) < 0) + return false; + D3DLOCKED_RECT tex_locked_rect; + if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) + return false; + for (int y = 0; y < height; y++) + memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); + bd->FontTexture->UnlockRect(0); + + // Store our identifier + io.Fonts->SetTexID((ImTextureID)bd->FontTexture); + +#ifndef IMGUI_USE_BGRA_PACKED_COLOR + if (io.Fonts->TexPixelsUseColors) + ImGui::MemFree(pixels); +#endif + + return true; +} + +bool ImGui_ImplD3D8_CreateDepthStencilBuffer() { + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + if (bd->pd3dDevice == nullptr) { + return false; + } + if (bd->DepthBuffer == nullptr) { + IDirect3DSurface8* realDepth; + D3DSURFACE_DESC sfcDesc; + + bd->pd3dDevice->GetDepthStencilSurface(&realDepth); + if (realDepth->GetDesc(&sfcDesc) != 0) { + return false; + } + realDepth->Release(); + realDepth = nullptr; + if (bd->pd3dDevice->CreateDepthStencilSurface(sfcDesc.Width, sfcDesc.Height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, &bd->DepthBuffer) != 0) { + return false; + } + } + + return true; +} + +bool ImGui_ImplDX8_CreateDeviceObjects() { + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + if (!bd || !bd->pd3dDevice) + return false; + if (!ImGui_ImplDX8_CreateFontsTexture()) + return false; + if (!ImGui_ImplD3D8_CreateDepthStencilBuffer()) + return false; + return true; +} + +void ImGui_ImplDX8_InvalidateDeviceObjects() { + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + if (!bd || !bd->pd3dDevice) + return; + if (bd->pVB) { + bd->pVB->Release(); + bd->pVB = nullptr; + } + if (bd->pIB) { + bd->pIB->Release(); + bd->pIB = nullptr; + } + if (bd->maskVB) { + bd->maskVB->Release(); + bd->maskVB = nullptr; + } + if (bd->maskIB) { + bd->maskIB->Release(); + bd->maskIB = nullptr; + } + if (bd->DepthBuffer) { + bd->DepthBuffer->Release(); + bd->DepthBuffer = nullptr; + } + if (bd->FontTexture) { + bd->FontTexture->Release(); + bd->FontTexture = nullptr; + ImGui::GetIO().Fonts->SetTexID(0); + } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. +} + +void ImGui_ImplDX8_NewFrame() { + ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX8_Init()?"); + + if (!bd->FontTexture || !bd->DepthBuffer) + ImGui_ImplDX8_CreateDeviceObjects(); +} \ No newline at end of file diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h new file mode 100644 index 00000000000..42b90a892cd --- /dev/null +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h @@ -0,0 +1,16 @@ +// Renderer Backend for DirectX8, based on the official DirectX9 Backend from Dear ImGui +// This needs to be used along with a Platform Backend (e.g. Win32) + +#pragma once +#include // IMGUI_IMPL_API + +struct IDirect3DDevice8; + +IMGUI_IMPL_API bool ImGui_ImplDX8_Init(IDirect3DDevice8* device); +IMGUI_IMPL_API void ImGui_ImplDX8_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplDX8_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data); + +// Use if you want to reset your rendering device without losing Dear ImGui state. +IMGUI_IMPL_API bool ImGui_ImplDX8_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplDX8_InvalidateDeviceObjects(); \ No newline at end of file diff --git a/Core/Libraries/Source/ImGui/imconfig.h b/Core/Libraries/Source/ImGui/imconfig.h new file mode 100644 index 00000000000..531b147f1f5 --- /dev/null +++ b/Core/Libraries/Source/ImGui/imconfig.h @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// DEAR IMGUI COMPILE-TIME OPTIONS +// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. +// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. +//----------------------------------------------------------------------------- +// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it) +// B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template. +//----------------------------------------------------------------------------- +// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp +// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures. +// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. +// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using. +//----------------------------------------------------------------------------- + +#pragma once + +//---- Define assertion handler. Defaults to calling assert(). +// - If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. +// - Compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes. +//#define IM_ASSERT(_EXPR) MyAssert(_EXPR) +//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts + +//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows +// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. +// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. +//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export +//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import +//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden + +//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. +//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS + +//---- Disable all of Dear ImGui or don't implement standard windows/tools. +// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. +//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. +//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. +//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty. + +//---- Don't implement some functions to reduce linkage requirements. +//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) +//#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW) +//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) +//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). +//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). +//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")). +//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) +//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. +//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) +//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. +//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). +//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean/ProggyVector), remove ~9 KB + ~17 KB from output binary. AddFontDefaultXXX() functions will assert. +//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available + +//---- Enable Test Engine / Automation features. +//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details. + +//---- Include imgui_user.h at the end of imgui.h as a convenience +// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included. +//#define IMGUI_INCLUDE_IMGUI_USER_H +//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h" + +//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support. +//#define IMGUI_USE_BGRA_PACKED_COLOR + +//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate. +//#define IMGUI_USE_LEGACY_CRC32_ADLER + +//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) +//#define IMGUI_USE_WCHAR32 + +//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version +// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files. +//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" +//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" +//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined. +//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION +//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. + +//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) +// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h. +//#define IMGUI_USE_STB_SPRINTF + +//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) +// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). +// Note that imgui_freetype.cpp may be used _without_ this define, if you manually call ImFontAtlas::SetFontLoader(). The define is simply a convenience. +// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. +//#define IMGUI_ENABLE_FREETYPE + +//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT) +// Only works in combination with IMGUI_ENABLE_FREETYPE. +// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions. +// - Both require headers to be available in the include path + program to be linked with the library code (not provided). +// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) +//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG +//#define IMGUI_ENABLE_FREETYPE_LUNASVG + +//---- Use stb_truetype to build and rasterize the font atlas (default) +// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. +//#define IMGUI_ENABLE_STB_TRUETYPE + +//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. +// This will be inlined as part of ImVec2 and ImVec4 class declarations. +/* +#define IM_VEC2_CLASS_EXTRA \ + constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ + operator MyVec2() const { return MyVec2(x,y); } + +#define IM_VEC4_CLASS_EXTRA \ + constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ + operator MyVec4() const { return MyVec4(x,y,z,w); } +*/ +//---- ...Or use Dear ImGui's own very basic math operators. +//#define IMGUI_DEFINE_MATH_OPERATORS + +//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. +// Your renderer backend will need to support it (most example renderer dx8_backend support both 16/32-bit indices). +// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. +// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. +//#define ImDrawIdx unsigned int + +//---- Override ImDrawCallback signature (will need to modify renderer dx8_backend accordingly) +//struct ImDrawList; +//struct ImDrawCmd; +//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); +//#define ImDrawCallback MyImDrawCallback + +//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) +// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) +//#define IM_DEBUG_BREAK IM_ASSERT(0) +//#define IM_DEBUG_BREAK __debugbreak() + +//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set. +// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use) +//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS + +//---- Debug Tools: Enable slower asserts +//#define IMGUI_DEBUG_PARANOID + +//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) +/* +namespace ImGui +{ + void MyFunction(const char* name, MyMatrix44* mtx); +} +*/ diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 583721ff51e..a11c411640a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -32,6 +32,13 @@ #include "GameClient/GameClient.h" // USER INCLUDES ////////////////////////////////////////////////////////////// +#ifdef RTS_IMGUI_ENABLED +#include +#include +#include "imgui_impl_dx8.h" +#include "dx8wrapper.h" +#endif + #include "Common/ActionManager.h" #include "Common/GameEngine.h" #include "Common/GameState.h" @@ -48,6 +55,7 @@ #include "GameClient/CampaignManager.h" #include "GameClient/ChallengeGenerals.h" #include "GameClient/CommandXlat.h" +#include "GameClient/Console.h" #include "GameClient/ControlBar.h" #include "GameClient/Diplomacy.h" #include "GameClient/Display.h" @@ -510,6 +518,16 @@ DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + // Draw console UI + { + DevConsole.Draw(0.5f); + ImGui::ShowDemoWindow(); + } +#endif // create the FRAME_TICK message GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK ); frameMsg->appendTimestampArgument( getFrame() ); @@ -622,6 +640,9 @@ void GameClient::update( void ) // redraw all views, update the GUI TheDisplay->DRAW(); TheDisplay->UPDATE(); +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); // Prepare render data +#endif return; } @@ -727,6 +748,9 @@ void GameClient::update( void ) // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); +#endif return; } #endif @@ -750,6 +774,11 @@ void GameClient::update( void ) TheDisplay->UPDATE(); } + +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); // Prepare render data +#endif + { USE_PERF_TIMER(GameClient_draw) @@ -757,6 +786,8 @@ void GameClient::update( void ) //if(TheGameLogic->getFrame() >= 2) TheDisplay->DRAW(); + + } { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index c3f82d48ce1..dc743d9934d 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -87,6 +87,12 @@ #include "shdlib.h" +#ifdef RTS_IMGUI_ENABLED +#include "imgui.h" +#include +#include "imgui_impl_dx8.h" +#endif + const int DEFAULT_RESOLUTION_WIDTH = 640; const int DEFAULT_RESOLUTION_HEIGHT = 480; const int DEFAULT_BIT_DEPTH = 32; @@ -355,6 +361,11 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) void DX8Wrapper::Shutdown(void) { +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); +#endif if (D3DDevice) { Set_Render_Target ((IDirect3DSurface8 *)nullptr); @@ -418,6 +429,7 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) ShatterSystem::Init(); TextureLoader::Init(); + Set_Default_Global_Render_States(); } @@ -636,7 +648,23 @@ bool DX8Wrapper::Create_Device(void) return false; } } - +#ifdef RTS_IMGUI_ENABLED + // Initialize ImGui + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // Dark Style + ImGui::StyleColorsDark(); + + ImGui_ImplWin32_Init(_Hwnd); + ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); + // Font setup + io.Fonts->AddFontDefault(); + //g_BigConsoleFont = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\Arial.ttf",25.0f); + io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); +#endif dbgHelpGuard.deactivate(); /* @@ -651,6 +679,9 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) WWDEBUG_SAY(("Resetting device.")); DX8_THREAD_ASSERT(); if ((IsInitted) && (D3DDevice != nullptr)) { +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_InvalidateDeviceObjects(); +#endif // Release all non-MANAGED stuff WW3D::_Invalidate_Textures(); @@ -667,6 +698,12 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) DX8TextureManagerClass::Release_Textures(); SHD_SHUTDOWN_SHADERS; +//#ifdef RTS_IMGUI_ENABLED +// // Shutdown ImGui backend before device reset +// ImGui_ImplDX8_Shutdown(); +// ImGui_ImplWin32_Shutdown(); +//#endif + // Reset frame count to reflect the flipping chain being reset by Reset() FrameCount = 0; @@ -692,6 +729,18 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) Invalidate_Cached_Render_States(); Set_Default_Global_Render_States(); SHD_INIT_SHADERS; +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_CreateDeviceObjects(); +#endif +//#ifdef RTS_IMGUI_ENABLED +// // Reinitialize ImGui backend after device reset +// ImGui_ImplWin32_Init(_Hwnd); +// ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); +// ImGuiIO& io = ImGui::GetIO(); (void)io; +// io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); +// +//#endif + WWDEBUG_SAY(("Device reset completed")); return true; } @@ -1713,6 +1762,10 @@ void DX8_Assert() void DX8Wrapper::Begin_Scene(void) { DX8_THREAD_ASSERT(); +#if RTS_IMGUI_ENABLED + ImGui_ImplDX8_NewFrame(); + ImGui_ImplWin32_NewFrame(); +#endif #if ENABLE_EMBEDDED_BROWSER DX8WebBrowser::Update(); @@ -1720,12 +1773,23 @@ void DX8Wrapper::Begin_Scene(void) DX8CALL(BeginScene()); +#ifdef false + ImGui_ImplDX8_NewFrame(); + ImGui_ImplWin32_NewFrame(); +#endif + DX8WebBrowser::Update(); } void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); + ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); +#endif + + DX8CALL(EndScene()); DX8WebBrowser::Render(0); diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index c26688a081b..74180b49ac7 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -67,6 +67,8 @@ #include "resource.h" #include + +#include "imgui.h" #ifdef RTS_ENABLE_CRASHDUMP #include "Common/MiniDumper.h" #endif @@ -290,13 +292,20 @@ static const char *messageToString(unsigned int message) } #endif +#ifdef RTS_IMGUI_ENABLED +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); +#endif // WndProc ==================================================================== /** Window Procedure */ //============================================================================= LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { - +#ifdef RTS_IMGUI_ENABLED + if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) { + return true; + } +#endif try { // First let the IME manager do it's stuff. diff --git a/cmake/config-build.cmake b/cmake/config-build.cmake index 6401c458be0..570bac8c1c2 100644 --- a/cmake/config-build.cmake +++ b/cmake/config-build.cmake @@ -8,6 +8,7 @@ option(RTS_BUILD_OPTION_DEBUG "Build code with the \"Debug\" configuration." OFF option(RTS_BUILD_OPTION_ASAN "Build code with Address Sanitizer." OFF) option(RTS_BUILD_OPTION_VC6_FULL_DEBUG "Build VC6 with full debug info." OFF) option(RTS_BUILD_OPTION_FFMPEG "Enable FFmpeg support" OFF) +option(RTS_BUILD_OPTION_IMGUI "Enables the ImGui Quake-like console -- requires Debug mode" OFF) if(NOT RTS_BUILD_ZEROHOUR AND NOT RTS_BUILD_GENERALS) set(RTS_BUILD_ZEROHOUR TRUE) From 019af6d683b68ccc3df95239aa7b5efdcb2c76c3 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 15 Jan 2026 20:43:00 +0100 Subject: [PATCH 02/50] Fix failing Release build with imgui enabled - Finalize imgui isolation in debug modes via ifdefs - Remove Console.cpp and Console.h to focus on ImGui integration --- Core/CMakeLists.txt | 6 +- Core/GameEngine/CMakeLists.txt | 7 - Core/GameEngine/Include/GameClient/Console.h | 36 --- .../Source/GameClient/GUI/Console.cpp | 243 ------------------ .../Source/GameClient/GameClient.cpp | 4 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 5 - GeneralsMD/Code/Main/WinMain.cpp | 3 + 7 files changed, 9 insertions(+), 295 deletions(-) delete mode 100644 Core/GameEngine/Include/GameClient/Console.h delete mode 100644 Core/GameEngine/Source/GameClient/GUI/Console.cpp diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index dd3b1ba8bdd..79f29fdc9d2 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -23,8 +23,12 @@ target_link_libraries(corei_always INTERFACE core_utility corei_libraries_include resources - lib_imgui ) +# link imgui if needed +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(corei_always INTERFACE lib_imgui) +endif () + target_link_libraries(corei_always_no_pch INTERFACE core_config core_utility_no_pch diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index e8e5024aa74..13fa1158a01 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -1164,13 +1164,6 @@ else() ) endif() -if(RTS_BUILD_OPTION_IMGUI) - list(APPEND GAMEENGINE_SRC - Source/GameClient/GUI/Console.cpp - Include/GameClient/Console.h - ) -endif () - add_library(corei_gameengine_private INTERFACE) add_library(corei_gameengine_public INTERFACE) diff --git a/Core/GameEngine/Include/GameClient/Console.h b/Core/GameEngine/Include/GameClient/Console.h deleted file mode 100644 index b34e32ce45e..00000000000 --- a/Core/GameEngine/Include/GameClient/Console.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#include - -#include "imgui.h" - -class Console -{ -public: - Console(); - ~Console() = default; - - void Draw(float openFraction = 0.5f); - - // Manually execute a console command (same logic used when the user presses Enter). - void ExecCommand(const char* command_line); - - // Add a log entry (printf-style). - void AddLog(const char* fmt, ...) IM_FMTARGS(2); - - // Clear the entire log buffer. - void ClearLog(); - -private: - static int TextEditCallbackStub(ImGuiInputTextCallbackData* data); - int TextEditCallback(ImGuiInputTextCallbackData* data); - -private: - char InputBuf[256]{}; - std::vector Items; - bool ScrollToBottom; - std::vector History; - int HistoryPos; // For navigating command history via up/down keys -}; - -extern Console DevConsole; diff --git a/Core/GameEngine/Source/GameClient/GUI/Console.cpp b/Core/GameEngine/Source/GameClient/GUI/Console.cpp deleted file mode 100644 index d986c5ef3cd..00000000000 --- a/Core/GameEngine/Source/GameClient/GUI/Console.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include "GameClient/Console.h" -Console DevConsole; - -// Set this to your app�s version string: -static const char* VERSION_STRING = "Command and Conquer Generals Next-Gen v0.06"; - -Console::Console() - : ScrollToBottom(false) - , HistoryPos(-1) -{ - ClearLog(); - AddLog("Welcome to the Quake-Style Console!"); -} - -void Console::Draw(float openFraction) -{ - if (openFraction <= 0.0f) - return; - - if (openFraction > 1.0f) - openFraction = 1.0f; - - ImGuiIO& io = ImGui::GetIO(); - ImVec2 screenSize = io.DisplaySize; - - float consoleHeight = screenSize.y * openFraction; - ImVec2 consolePos = ImVec2(0, 0); - ImVec2 consoleSize = ImVec2(screenSize.x, consoleHeight); - - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.05f, 0.05f, 0.05f, 0.8f)); - - ImGui::SetNextWindowPos(consolePos); - ImGui::SetNextWindowSize(consoleSize); - ImGui::Begin("QuakeConsoleOverlay", - nullptr, - ImGuiWindowFlags_NoTitleBar - | ImGuiWindowFlags_NoResize - | ImGuiWindowFlags_NoMove - | ImGuiWindowFlags_NoScrollbar - | ImGuiWindowFlags_NoCollapse - | ImGuiWindowFlags_NoSavedSettings - | ImGuiWindowFlags_NoBringToFrontOnFocus); - - //ImGui::PushFont(g_BigConsoleFont); - - float footerHeight = ImGui::GetTextLineHeight() + 8; // space for input + some padding - ImGui::BeginChild("ConsoleScrollingRegion", ImVec2(0, -footerHeight), false); - - // Draw existing console lines - for (int i = 0; i < (int)Items.size(); i++) - { - const char* item = Items[i].c_str(); - - if (strncmp(item, "ASSERTION FAILURE:", 18) == 0) - { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f)); - ImGui::TextUnformatted(item); - ImGui::PopStyleColor(); - } - else if (strstr(item, "[error]")) - { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.4f, 0.4f, 1.f)); - ImGui::TextUnformatted(item); - ImGui::PopStyleColor(); - } - else if (strncmp(item, "# ", 2) == 0) - { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.8f, 0.6f, 1.f)); - ImGui::TextUnformatted(item); - ImGui::PopStyleColor(); - } - else - { - ImGui::TextUnformatted(item); - } - } - - if (ScrollToBottom) - ImGui::SetScrollHereY(1.0f); - ScrollToBottom = false; - - ImGui::EndChild(); - - { - // Make an (almost) invisible InputText that still captures user input: - ImGui::PushItemWidth(-1); - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.0f); // fully invisible - // Focus on this widget so it captures keyboard input: - if (ImGui::IsWindowAppearing()) - ImGui::SetKeyboardFocusHere(); - - // Use same callback flags for history/tab-completion as before: - if (ImGui::InputText("##HiddenConsoleInput", InputBuf, IM_ARRAYSIZE(InputBuf), - ImGuiInputTextFlags_EnterReturnsTrue - | ImGuiInputTextFlags_CallbackHistory - | ImGuiInputTextFlags_CallbackCompletion, - &TextEditCallbackStub, (void*)this)) - { - // If user pressed Enter: - char* s = InputBuf; - if (s[0] != '\0') - ExecCommand(s); - s[0] = '\0'; - } - ImGui::PopStyleVar(); // restore alpha - ImGui::PopItemWidth(); - - // Now manually render the input line on the far left: - // e.g. a Quake-like prompt: ">" or "#" etc. - ImGui::TextUnformatted("> "); - ImGui::SameLine(); - ImGui::TextUnformatted(InputBuf); - - // Then place the version text on the far right: - // We can compute how much space is left and push the text to the right: - float versionTextWidth = ImGui::CalcTextSize(VERSION_STRING).x; - float availableWidth = ImGui::GetContentRegionAvail().x; - ImGui::SameLine(std::max(0.0f, availableWidth - versionTextWidth)); - ImGui::TextUnformatted(VERSION_STRING); - } - - //ImGui::PopFont(); - ImGui::End(); // end main window - - ImGui::PopStyleColor(); - ImGui::PopStyleVar(2); - - // ------------------------------------------------------------ - // Draw the small orange line where the console ends - // ------------------------------------------------------------ - ImDrawList* fg = ImGui::GetForegroundDrawList(); - // Coordinates for a line across the entire screen at y = consoleHeight - ImVec2 start = ImVec2(0.0f, consoleHeight); - ImVec2 end = ImVec2(screenSize.x, consoleHeight); - - // Use a bright orange color; thickness = 2.0f - fg->AddLine(start, end, IM_COL32(255, 128, 0, 255), 2.0f); -} - -// ----------------------------------------------------------------------------- -// ExecCommand, AddLog, ClearLog, etc. remain the same -// ----------------------------------------------------------------------------- -void Console::ExecCommand(const char* command_line) -{ - AddLog("# %s", command_line); - - HistoryPos = -1; - for (int i = (int)History.size() - 1; i >= 0; i--) - { - if (strcmp(History[i].c_str(), command_line) == 0) - { - History.erase(History.begin() + i); - break; - } - } - History.push_back(command_line); - - if (strcmp(command_line, "CLEAR") == 0) - { - ClearLog(); - } - else if (strcmp(command_line, "HELP") == 0) - { - AddLog("Commands:"); - AddLog(" HELP"); - AddLog(" CLEAR"); - AddLog(" HISTORY"); - } - else if (strcmp(command_line, "HISTORY") == 0) - { - for (int i = (int)History.size() - 1; i >= 0; i--) - AddLog("%3d: %s", i, History[i].c_str()); - } - else - { - AddLog("Unknown command: '%s'", command_line); - } - - ScrollToBottom = true; -} - -void Console::AddLog(const char* fmt, ...) -{ - char buffer[1024]; - va_list args; - va_start(args, fmt); - vsnprintf(buffer, IM_ARRAYSIZE(buffer), fmt, args); - buffer[IM_ARRAYSIZE(buffer) - 1] = 0; - va_end(args); - - Items.push_back(buffer); - ScrollToBottom = true; -} - -void Console::ClearLog() -{ - Items.clear(); - ScrollToBottom = true; -} - -int Console::TextEditCallbackStub(ImGuiInputTextCallbackData* data) -{ - Console* console = (Console*)data->UserData; - return console->TextEditCallback(data); -} - -int Console::TextEditCallback(ImGuiInputTextCallbackData* data) -{ - switch (data->EventFlag) - { - case ImGuiInputTextFlags_CallbackCompletion: - // Optional: handle tab-completion - break; - case ImGuiInputTextFlags_CallbackHistory: - { - const int prevHistoryPos = HistoryPos; - if (data->EventKey == ImGuiKey_UpArrow) - { - if (HistoryPos == -1) - HistoryPos = (int)History.size() - 1; - else if (HistoryPos > 0) - HistoryPos--; - } - else if (data->EventKey == ImGuiKey_DownArrow) - { - if (HistoryPos != -1) - if (++HistoryPos >= (int)History.size()) - HistoryPos = -1; - } - - if (prevHistoryPos != HistoryPos && HistoryPos != -1) - { - const std::string& historyStr = History[HistoryPos]; - data->DeleteChars(0, data->BufTextLen); - data->InsertChars(0, historyStr.c_str()); - } - break; - } - } - return 0; -} \ No newline at end of file diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index a11c411640a..6bb52d7011b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -55,7 +55,6 @@ #include "GameClient/CampaignManager.h" #include "GameClient/ChallengeGenerals.h" #include "GameClient/CommandXlat.h" -#include "GameClient/Console.h" #include "GameClient/ControlBar.h" #include "GameClient/Diplomacy.h" #include "GameClient/Display.h" @@ -522,9 +521,8 @@ void GameClient::update( void ) ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); - // Draw console UI + // Draw ImGui Demo Window { - DevConsole.Draw(0.5f); ImGui::ShowDemoWindow(); } #endif diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index dc743d9934d..7cfac77e04d 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1773,11 +1773,6 @@ void DX8Wrapper::Begin_Scene(void) DX8CALL(BeginScene()); -#ifdef false - ImGui_ImplDX8_NewFrame(); - ImGui_ImplWin32_NewFrame(); -#endif - DX8WebBrowser::Update(); } diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index 74180b49ac7..307ee04ec50 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -68,7 +68,10 @@ #include +#ifdef RTS_IMGUI_ENABLED #include "imgui.h" +#endif + #ifdef RTS_ENABLE_CRASHDUMP #include "Common/MiniDumper.h" #endif From a7806a8614dfe6a7415c65efc6ef7da17d8abd55 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 10:52:24 +0100 Subject: [PATCH 03/50] Move ImGui Render before DRAW call for consistency --- .../Code/GameEngine/Source/GameClient/GameClient.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 6bb52d7011b..79e64d11bc5 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -635,12 +635,13 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { - // redraw all views, update the GUI - TheDisplay->DRAW(); - TheDisplay->UPDATE(); #ifdef RTS_IMGUI_ENABLED ImGui::Render(); // Prepare render data #endif + // redraw all views, update the GUI + TheDisplay->DRAW(); + TheDisplay->UPDATE(); + return; } From 38407bf82ef1de961f04694141dd867de2d06488 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 10:53:26 +0100 Subject: [PATCH 04/50] Remove redundant Frame creation in dx8wrapper --- GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 7cfac77e04d..733987f5a1c 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1762,10 +1762,6 @@ void DX8_Assert() void DX8Wrapper::Begin_Scene(void) { DX8_THREAD_ASSERT(); -#if RTS_IMGUI_ENABLED - ImGui_ImplDX8_NewFrame(); - ImGui_ImplWin32_NewFrame(); -#endif #if ENABLE_EMBEDDED_BROWSER DX8WebBrowser::Update(); From 34d99c4c724487da53bf32e8aad206ffc4839571 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 12:06:13 +0100 Subject: [PATCH 05/50] Fix configuration to also accept RTS_BUILD_OPTION_DEBUG --- Core/Libraries/Source/ImGui/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index ff2330ad24d..4f371caf809 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -37,9 +37,8 @@ set(IMGUI_INCLUDE_DIRS # start target build section # we currently have a hard dependency on dx8 and win32 api if (WIN32) - # for now we only need it in debug builds - # RTS_BUILD_OPTION_DEBUG also works since it is a Debug build profile - if ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug") ) + # for now we only need it in debug configurations + if ( NOT ( (CMAKE_BUILD_TYPE STREQUAL "Debug") OR RTS_BUILD_OPTION_DEBUG ) ) MESSAGE(FATAL_ERROR "ImGui integration is currently only possible in Debug build modes") endif () From 9865b8d1c40a63751b2c571b01a56f6af9751457 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 14:10:14 +0100 Subject: [PATCH 06/50] Add feature info for ImGui build option --- cmake/config-build.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/config-build.cmake b/cmake/config-build.cmake index 570bac8c1c2..f5f81c16ee0 100644 --- a/cmake/config-build.cmake +++ b/cmake/config-build.cmake @@ -24,6 +24,7 @@ add_feature_info(DebugBuild RTS_BUILD_OPTION_DEBUG "Building as a \"Debug\" buil add_feature_info(AddressSanitizer RTS_BUILD_OPTION_ASAN "Building with address sanitizer") add_feature_info(Vc6FullDebug RTS_BUILD_OPTION_VC6_FULL_DEBUG "Building VC6 with full debug info") add_feature_info(FFmpegSupport RTS_BUILD_OPTION_FFMPEG "Building with FFmpeg support") +add_feature_info(ImGuiSupportDebug RTS_BUILD_OPTION_IMGUI "Building with ImGui integration in debug builds") if(RTS_BUILD_ZEROHOUR) option(RTS_BUILD_ZEROHOUR_TOOLS "Build tools for Zero Hour" ON) From 821222b3728686d4582cf796107191e2a2b509f1 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 14:52:58 +0100 Subject: [PATCH 07/50] Backport ImGui integration to generals --- .../Source/GameClient/GameClient.cpp | 23 +++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 38 ++++++++++++++++++- Generals/Code/Main/WinMain.cpp | 13 ++++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index b317344c680..c0ebc990598 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -82,6 +82,11 @@ #include "GameLogic/GhostObject.h" #include "GameLogic/Object.h" #include "GameLogic/ScriptEngine.h" // For TheScriptEngine - jkmcd +#ifdef RTS_IMGUI_ENABLED +#include "imgui.h" +#include "imgui_impl_dx8.h" +#include "imgui_impl_win32.h" +#endif #define DRAWABLE_HASH_SIZE 8192 @@ -489,6 +494,15 @@ DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + // Draw ImGui Demo Window + { + ImGui::ShowDemoWindow(); + } +#endif // create the FRAME_TICK message GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK ); frameMsg->appendTimestampArgument( getFrame() ); @@ -581,6 +595,9 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); // Prepare render data +#endif // redraw all views, update the GUI TheDisplay->DRAW(); TheDisplay->UPDATE(); @@ -689,6 +706,9 @@ void GameClient::update( void ) // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); +#endif return; } #endif @@ -712,6 +732,9 @@ void GameClient::update( void ) TheDisplay->UPDATE(); } +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); // Prepare render data +#endif { USE_PERF_TIMER(GameClient_draw) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 0e20057d1f8..ffd99ed1bbe 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -82,6 +82,12 @@ #include "bound.h" #include "DbgHelpGuard.h" +#ifdef RTS_IMGUI_ENABLED +#include "imgui.h" +#include "imgui_impl_dx8.h" +#include "imgui_impl_win32.h" +#endif + const int DEFAULT_RESOLUTION_WIDTH = 640; const int DEFAULT_RESOLUTION_HEIGHT = 480; @@ -349,6 +355,11 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) void DX8Wrapper::Shutdown(void) { +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); +#endif if (D3DDevice) { Set_Render_Target ((IDirect3DSurface8 *)nullptr); @@ -588,7 +599,22 @@ bool DX8Wrapper::Create_Device(void) { return false; } - +#ifdef RTS_IMGUI_ENABLED + // Initialize ImGui + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + // Dark Style + ImGui::StyleColorsDark(); + + ImGui_ImplWin32_Init(_Hwnd); + ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); + // Font setup + io.Fonts->AddFontDefault(); + io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); +#endif dbgHelpGuard.deactivate(); /* @@ -603,6 +629,9 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) WWDEBUG_SAY(("Resetting device.")); DX8_THREAD_ASSERT(); if ((IsInitted) && (D3DDevice != nullptr)) { +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_InvalidateDeviceObjects(); +#endif // Release all non-MANAGED stuff WW3D::_Invalidate_Textures(); @@ -636,6 +665,9 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) } Invalidate_Cached_Render_States(); Set_Default_Global_Render_States(); +#ifdef RTS_IMGUI_ENABLED + ImGui_ImplDX8_CreateDeviceObjects(); +#endif WWDEBUG_SAY(("Device reset completed")); return true; } @@ -1596,6 +1628,10 @@ void DX8Wrapper::Begin_Scene(void) void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); + ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); +#endif DX8CALL(EndScene()); DX8WebBrowser::Render(0); diff --git a/Generals/Code/Main/WinMain.cpp b/Generals/Code/Main/WinMain.cpp index 528b09dbdf5..f91843f7b8e 100644 --- a/Generals/Code/Main/WinMain.cpp +++ b/Generals/Code/Main/WinMain.cpp @@ -67,7 +67,9 @@ #ifdef RTS_ENABLE_CRASHDUMP #include "Common/MiniDumper.h" #endif - +#ifdef RTS_IMGUI_ENABLED +#include "imgui.h" +#endif // GLOBALS //////////////////////////////////////////////////////////////////// HINSTANCE ApplicationHInstance = nullptr; ///< our application instance @@ -287,13 +289,20 @@ static const char *messageToString(unsigned int message) } #endif +#ifdef RTS_IMGUI_ENABLED +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); +#endif // WndProc ==================================================================== /** Window Procedure */ //============================================================================= LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { - +#ifdef RTS_IMGUI_ENABLED + if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) { + return true; + } +#endif try { // First let the IME manager do it's stuff. From f41c6d59ac738d22865fe0dc22b50c4ac6ea3bdf Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 14:55:17 +0100 Subject: [PATCH 08/50] Cleanup redundant deadcode --- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 733987f5a1c..a13dbf22c84 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -662,7 +662,6 @@ bool DX8Wrapper::Create_Device(void) ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); // Font setup io.Fonts->AddFontDefault(); - //g_BigConsoleFont = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\Arial.ttf",25.0f); io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); #endif dbgHelpGuard.deactivate(); @@ -698,12 +697,6 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) DX8TextureManagerClass::Release_Textures(); SHD_SHUTDOWN_SHADERS; -//#ifdef RTS_IMGUI_ENABLED -// // Shutdown ImGui backend before device reset -// ImGui_ImplDX8_Shutdown(); -// ImGui_ImplWin32_Shutdown(); -//#endif - // Reset frame count to reflect the flipping chain being reset by Reset() FrameCount = 0; @@ -732,15 +725,6 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) #ifdef RTS_IMGUI_ENABLED ImGui_ImplDX8_CreateDeviceObjects(); #endif -//#ifdef RTS_IMGUI_ENABLED -// // Reinitialize ImGui backend after device reset -// ImGui_ImplWin32_Init(_Hwnd); -// ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); -// ImGuiIO& io = ImGui::GetIO(); (void)io; -// io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); -// -//#endif - WWDEBUG_SAY(("Device reset completed")); return true; } @@ -1779,8 +1763,6 @@ void DX8Wrapper::End_Scene(bool flip_frames) ImGui::Render(); ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); #endif - - DX8CALL(EndScene()); DX8WebBrowser::Render(0); From 731da382f02cdd94eb4654e8271f779b0444ce70 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 16:01:18 +0100 Subject: [PATCH 09/50] Add TheSuperHackers comments according to guidlines --- .../Source/GameClient/GameClient.cpp | 18 ++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 29 ++++++++++++++++++- Generals/Code/Main/WinMain.cpp | 9 ++++++ .../Source/GameClient/GameClient.cpp | 18 ++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 9 ++++++ GeneralsMD/Code/Main/WinMain.cpp | 9 ++++++ 6 files changed, 91 insertions(+), 1 deletion(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index c0ebc990598..7dcdb193cdc 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -486,6 +486,15 @@ void GameClient::registerDrawable( Drawable *draw ) } +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ @@ -494,6 +503,8 @@ DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); @@ -595,6 +606,8 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui::Render(); // Prepare render data #endif @@ -706,6 +719,9 @@ void GameClient::update( void ) // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// Prepare ImGui renderdata before framestepping to ensure proper display +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui::Render(); #endif @@ -732,6 +748,8 @@ void GameClient::update( void ) TheDisplay->UPDATE(); } +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui::Render(); // Prepare render data #endif diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index ffd99ed1bbe..cb84725e23f 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -352,7 +352,15 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) return(true); } - +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. void DX8Wrapper::Shutdown(void) { #ifdef RTS_IMGUI_ENABLED @@ -522,6 +530,15 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) } +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. bool DX8Wrapper::Create_Device(void) { WWASSERT(D3DDevice==nullptr); // for now, once you've created a device, you're stuck with it! @@ -599,6 +616,8 @@ bool DX8Wrapper::Create_Device(void) { return false; } +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED // Initialize ImGui IMGUI_CHECKVERSION(); @@ -624,11 +643,19 @@ bool DX8Wrapper::Create_Device(void) return true; } +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: WndProc forwards input to ImGui via ImGui_ImplWin32_WndProcHandler(), DX8Wrapper manages context/backend initialization and cleanup, +// and End_Scene() renders ImGui draw data after the main scene.GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), +// while ImGui::Render() is called before DRAW() operations and critically before early returns in RTS_DEBUG mode (frame stepping) to +// ensure frames are properly closed and the demo window displays. +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. bool DX8Wrapper::Reset_Device(bool reload_assets) { WWDEBUG_SAY(("Resetting device.")); DX8_THREAD_ASSERT(); if ((IsInitted) && (D3DDevice != nullptr)) { +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui_ImplDX8_InvalidateDeviceObjects(); #endif diff --git a/Generals/Code/Main/WinMain.cpp b/Generals/Code/Main/WinMain.cpp index f91843f7b8e..4b2d46f591b 100644 --- a/Generals/Code/Main/WinMain.cpp +++ b/Generals/Code/Main/WinMain.cpp @@ -289,6 +289,15 @@ static const char *messageToString(unsigned int message) } #endif +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. #ifdef RTS_IMGUI_ENABLED extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); #endif diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 79e64d11bc5..147760eeb25 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -509,6 +509,15 @@ void GameClient::registerDrawable( Drawable *draw ) } +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ @@ -517,6 +526,8 @@ DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); @@ -635,6 +646,8 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui::Render(); // Prepare render data #endif @@ -747,6 +760,9 @@ void GameClient::update( void ) // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// Prepare ImGui renderdata before framestepping to ensure proper display +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui::Render(); #endif @@ -774,6 +790,8 @@ void GameClient::update( void ) } +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details in comment before this function's signature #ifdef RTS_IMGUI_ENABLED ImGui::Render(); // Prepare render data #endif diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index a13dbf22c84..a3e80c421ad 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -533,6 +533,15 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) } +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. bool DX8Wrapper::Create_Device(void) { WWASSERT(D3DDevice==nullptr); // for now, once you've created a device, you're stuck with it! diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index 307ee04ec50..406a29c551b 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -295,6 +295,15 @@ static const char *messageToString(unsigned int message) } #endif +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. #ifdef RTS_IMGUI_ENABLED extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); #endif From 67a4645f2836150c5b6640f4b4d89c866bd48349 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 16:39:49 +0100 Subject: [PATCH 10/50] Remove redundant Render --- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 10 +++++++++- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index cb84725e23f..48231d8cd9f 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1652,11 +1652,19 @@ void DX8Wrapper::Begin_Scene(void) DX8WebBrowser::Update(); } +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); #ifdef RTS_IMGUI_ENABLED - ImGui::Render(); ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); #endif DX8CALL(EndScene()); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index a3e80c421ad..034e27a0ca0 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1765,11 +1765,19 @@ void DX8Wrapper::Begin_Scene(void) DX8WebBrowser::Update(); } +// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) +// ImGui workflow: +// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() +// - DX8Wrapper: manages context/backend initialization and cleanup, +// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. +// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and +// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. +// +// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); #ifdef RTS_IMGUI_ENABLED - ImGui::Render(); ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); #endif DX8CALL(EndScene()); From 8f9f434f07e432914dd821b204fcd2da260c483e Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 16:47:41 +0100 Subject: [PATCH 11/50] Fix type in ImGui CMakeLists --- Core/Libraries/Source/ImGui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index 4f371caf809..cc83870b516 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -17,7 +17,7 @@ set(IMGUI_BASE_SRCS ) -# Main Win32 DX8 specific sources we are going to need we can specify moore if we need extra platforms +# Main Win32 DX8 specific sources we are going to need we can specify more if we need extra platforms set(IMGUI_WIN32_DX8_IMPL_SRCS "${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp" "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp" From 34e375246d6a71e5dd573dbf7ca74ac828121382 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 17:07:54 +0100 Subject: [PATCH 12/50] Fix NullPointer dereference in imgui_impl_dx8 --- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 44272dbbeb6..884a5ba046d 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -414,7 +414,9 @@ bool ImGui_ImplD3D8_CreateDepthStencilBuffer() { IDirect3DSurface8* realDepth; D3DSURFACE_DESC sfcDesc; - bd->pd3dDevice->GetDepthStencilSurface(&realDepth); + if (bd->pd3dDevice->GetDepthStencilSurface(&realDepth) || ! realDepth) { + return false; + } if (realDepth->GetDesc(&sfcDesc) != 0) { return false; } From dada1a4f080cf36f3cad9f076ad53d9381a55a63 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 17:21:31 +0100 Subject: [PATCH 13/50] fix missing result status check --- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 884a5ba046d..5f184bf1433 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -414,7 +414,7 @@ bool ImGui_ImplD3D8_CreateDepthStencilBuffer() { IDirect3DSurface8* realDepth; D3DSURFACE_DESC sfcDesc; - if (bd->pd3dDevice->GetDepthStencilSurface(&realDepth) || ! realDepth) { + if (bd->pd3dDevice->GetDepthStencilSurface(&realDepth) != D3D_OK || ! realDepth) { return false; } if (realDepth->GetDesc(&sfcDesc) != 0) { From 4361776cc635b9ece1c68e5c7bb76f4c3c0cffa1 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 19:24:13 +0100 Subject: [PATCH 14/50] fix second potential nullptr dereference in dx8 backend --- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 5f184bf1433..388330df1cf 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -329,8 +329,10 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { // Restore the DX8 state bd->pd3dDevice->SetRenderTarget(nullptr, bd->realDepthStencilBuffer); - bd->realDepthStencilBuffer->Release(); - bd->realDepthStencilBuffer = nullptr; + if (bd->realDepthStencilBuffer) { + bd->realDepthStencilBuffer->Release(); + bd->realDepthStencilBuffer = nullptr; + } bd->pd3dDevice->ApplyStateBlock(d3d8_state_block); bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); } From 473f9d78a21cecbf86135cfa95ccb12feb3f2345 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 19 Jan 2026 10:49:30 +0100 Subject: [PATCH 15/50] Fix crash in worldbuilder and guiedit when opening worldbuilder or guiedit ImGui has no frames to render and thus attemtimg to call RenderDrawData crashes in those applications as soon as they start this change fixes that behaviour by only rendering when we have stuff to render --- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 7 ++++++- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 48231d8cd9f..9c724d854ea 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1665,7 +1665,12 @@ void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); #ifdef RTS_IMGUI_ENABLED - ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); + { + ImDrawData* data = ImGui::GetDrawData(); + if (data && data->CmdListsCount > 0) { + ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); + } + } #endif DX8CALL(EndScene()); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 034e27a0ca0..274ec2b6e82 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1778,7 +1778,12 @@ void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); #ifdef RTS_IMGUI_ENABLED - ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); + { + ImDrawData* data = ImGui::GetDrawData(); + if (data && data->CmdListsCount > 0 ) { + ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); + } + } #endif DX8CALL(EndScene()); From dd8541ae1cf93937f187fa6bd96a1f4933c40f83 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 19 Jan 2026 10:51:57 +0100 Subject: [PATCH 16/50] Fix further nullptr deref issues in ImGui dx8backend --- .../Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 388330df1cf..db83a0c5627 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -65,7 +65,10 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { } // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. - bd->pd3dDevice->GetDepthStencilSurface(&bd->realDepthStencilBuffer); + // Check result to prevent crash when restoring depth buffer with SetRenderTarget + if (bd->pd3dDevice->GetDepthStencilSurface(&bd->realDepthStencilBuffer) != D3D_OK) { + bd->realDepthStencilBuffer = nullptr; + } bd->pd3dDevice->SetRenderTarget(nullptr, bd->DepthBuffer); bd->pd3dDevice->SetPixelShader(NULL); bd->pd3dDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX); @@ -126,7 +129,10 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { void build_mask_vbuffer(const RECT* rect) { ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); CUSTOMVERTEX* vtx_dst{}; - bd->maskVB->Lock(0, (UINT)(6 * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, 0); + // Check Lock result to prevent null pointer dereference + if (bd->maskVB->Lock(0, (UINT)(6 * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, 0) != D3D_OK) { + return; + } vtx_dst[0].pos[0] = (float)rect->left; vtx_dst[0].pos[1] = (float)rect->bottom; vtx_dst[0].pos[2] = 0; @@ -197,7 +203,10 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { if (bd->pd3dDevice->CreateVertexBuffer(6 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->maskVB) < 0) return; if (bd->pd3dDevice->CreateIndexBuffer(6, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->maskIB) < 0) return; ImDrawIdx* idx_dst{}; - bd->maskIB->Lock(0, 6 * sizeof(ImDrawIdx), (BYTE**)&idx_dst, D3DLOCK_DISCARD); + // Check Lock result to prevent null pointer dereference + if (bd->maskIB->Lock(0, 6 * sizeof(ImDrawIdx), (BYTE**)&idx_dst, D3DLOCK_DISCARD) != D3D_OK) { + return; + } idx_dst[0] = 0; idx_dst[1] = 1; idx_dst[2] = 2; @@ -480,4 +489,4 @@ void ImGui_ImplDX8_NewFrame() { if (!bd->FontTexture || !bd->DepthBuffer) ImGui_ImplDX8_CreateDeviceObjects(); -} \ No newline at end of file +} From a23ab53c44a2ddc830d1d1fe90a1d43eb181bf65 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 09:53:05 +0100 Subject: [PATCH 17/50] Fix indentation in ImGui CMakeLists.txt --- Core/Libraries/Source/ImGui/CMakeLists.txt | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index cc83870b516..940bf86aa6e 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -1,26 +1,26 @@ FetchContent_Declare( - imgui - GIT_REPOSITORY https://github.com/ocornut/imgui.git - GIT_TAG 791ad9b82db44ada9fedb3e26b2d900974ac0959 - SYSTEM + imgui + GIT_REPOSITORY https://github.com/ocornut/imgui.git + GIT_TAG 791ad9b82db44ada9fedb3e26b2d900974ac0959 + SYSTEM ) FetchContent_MakeAvailable(imgui) # Main IMGUI sources we are going to need set(IMGUI_BASE_SRCS - "${imgui_SOURCE_DIR}/imgui.cpp" - "${imgui_SOURCE_DIR}/imgui_draw.cpp" - "${imgui_SOURCE_DIR}/imgui_tables.cpp" - "${imgui_SOURCE_DIR}/imgui_widgets.cpp" - "${imgui_SOURCE_DIR}/imgui_demo.cpp" + "${imgui_SOURCE_DIR}/imgui.cpp" + "${imgui_SOURCE_DIR}/imgui_draw.cpp" + "${imgui_SOURCE_DIR}/imgui_tables.cpp" + "${imgui_SOURCE_DIR}/imgui_widgets.cpp" + "${imgui_SOURCE_DIR}/imgui_demo.cpp" ) # Main Win32 DX8 specific sources we are going to need we can specify more if we need extra platforms set(IMGUI_WIN32_DX8_IMPL_SRCS - "${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp" - "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp" + "${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp" + "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp" ) # All Win32 DX8 sources @@ -28,10 +28,10 @@ set(IMGUI_WIN32_DX8_ALL_SRCS ${IMGUI_BASE_SRCS} ${IMGUI_WIN32_DX8_IMPL_SRCS}) # All Include directories set(IMGUI_INCLUDE_DIRS - "${imgui_SOURCE_DIR}" - "${imgui_SOURCE_DIR}/backends" - # DX8 override. Remove the following once we are using a standard backend - "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend" + "${imgui_SOURCE_DIR}" + "${imgui_SOURCE_DIR}/backends" + # DX8 override. Remove the following once we are using a standard backend + "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend" ) # start target build section @@ -41,7 +41,7 @@ if (WIN32) if ( NOT ( (CMAKE_BUILD_TYPE STREQUAL "Debug") OR RTS_BUILD_OPTION_DEBUG ) ) MESSAGE(FATAL_ERROR "ImGui integration is currently only possible in Debug build modes") endif () - + MESSAGE(STATUS "Enabling imgui console integration") add_library(lib_imgui STATIC ${IMGUI_WIN32_DX8_ALL_SRCS}) @@ -50,9 +50,9 @@ if (WIN32) # use our own imconfig.h target_compile_definitions(lib_imgui - PRIVATE IMGUI_DISABLE_DEFAULT_IMCONFIG - PRIVATE IMGUI_USER_CONFIG="${CMAKE_CURRENT_LIST_DIR}/imconfig.h" - INTERFACE RTS_IMGUI_ENABLED + PRIVATE IMGUI_DISABLE_DEFAULT_IMCONFIG + PRIVATE IMGUI_USER_CONFIG="${CMAKE_CURRENT_LIST_DIR}/imconfig.h" + INTERFACE RTS_IMGUI_ENABLED ) else () # currently only WIN32 DX is supported From 0b25693b3ac857696f7cb88ed428cc07d21e748a Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 09:54:56 +0100 Subject: [PATCH 18/50] Fix cmake option description for imgui --- cmake/config-build.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/config-build.cmake b/cmake/config-build.cmake index f5f81c16ee0..4034113c75e 100644 --- a/cmake/config-build.cmake +++ b/cmake/config-build.cmake @@ -8,7 +8,7 @@ option(RTS_BUILD_OPTION_DEBUG "Build code with the \"Debug\" configuration." OFF option(RTS_BUILD_OPTION_ASAN "Build code with Address Sanitizer." OFF) option(RTS_BUILD_OPTION_VC6_FULL_DEBUG "Build VC6 with full debug info." OFF) option(RTS_BUILD_OPTION_FFMPEG "Enable FFmpeg support" OFF) -option(RTS_BUILD_OPTION_IMGUI "Enables the ImGui Quake-like console -- requires Debug mode" OFF) +option(RTS_BUILD_OPTION_IMGUI "Build with ImGui" OFF) if(NOT RTS_BUILD_ZEROHOUR AND NOT RTS_BUILD_GENERALS) set(RTS_BUILD_ZEROHOUR TRUE) From 86a06771f4d2e2187ddedea02bad2536060c36d2 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 10:58:32 +0100 Subject: [PATCH 19/50] Change RTS_IMGUI_ENABLED to RTS_HAS_IMGUI --- Core/Libraries/Source/ImGui/CMakeLists.txt | 2 +- .../Code/GameEngine/Source/GameClient/GameClient.cpp | 10 +++++----- .../Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 12 ++++++------ Generals/Code/Main/WinMain.cpp | 6 +++--- .../Code/GameEngine/Source/GameClient/GameClient.cpp | 10 +++++----- .../Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 12 ++++++------ GeneralsMD/Code/Main/WinMain.cpp | 6 +++--- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index 940bf86aa6e..40610416c3b 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -52,7 +52,7 @@ if (WIN32) target_compile_definitions(lib_imgui PRIVATE IMGUI_DISABLE_DEFAULT_IMCONFIG PRIVATE IMGUI_USER_CONFIG="${CMAKE_CURRENT_LIST_DIR}/imconfig.h" - INTERFACE RTS_IMGUI_ENABLED + INTERFACE RTS_HAS_IMGUI ) else () # currently only WIN32 DX is supported diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index 7dcdb193cdc..8e718f9fd64 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -82,7 +82,7 @@ #include "GameLogic/GhostObject.h" #include "GameLogic/Object.h" #include "GameLogic/ScriptEngine.h" // For TheScriptEngine - jkmcd -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI #include "imgui.h" #include "imgui_impl_dx8.h" #include "imgui_impl_win32.h" @@ -505,7 +505,7 @@ void GameClient::update( void ) USE_PERF_TIMER(GameClient_update) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); @@ -608,7 +608,7 @@ void GameClient::update( void ) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif // redraw all views, update the GUI @@ -722,7 +722,7 @@ void GameClient::update( void ) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // Prepare ImGui renderdata before framestepping to ensure proper display // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui::Render(); #endif return; @@ -750,7 +750,7 @@ void GameClient::update( void ) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif { diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 9c724d854ea..5837ced7f7f 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -82,7 +82,7 @@ #include "bound.h" #include "DbgHelpGuard.h" -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI #include "imgui.h" #include "imgui_impl_dx8.h" #include "imgui_impl_win32.h" @@ -363,7 +363,7 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) // See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. void DX8Wrapper::Shutdown(void) { -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); @@ -618,7 +618,7 @@ bool DX8Wrapper::Create_Device(void) } // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI // Initialize ImGui IMGUI_CHECKVERSION(); ImGui::CreateContext(); @@ -656,7 +656,7 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) if ((IsInitted) && (D3DDevice != nullptr)) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_InvalidateDeviceObjects(); #endif // Release all non-MANAGED stuff @@ -692,7 +692,7 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) } Invalidate_Cached_Render_States(); Set_Default_Global_Render_States(); -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_CreateDeviceObjects(); #endif WWDEBUG_SAY(("Device reset completed")); @@ -1664,7 +1664,7 @@ void DX8Wrapper::Begin_Scene(void) void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI { ImDrawData* data = ImGui::GetDrawData(); if (data && data->CmdListsCount > 0) { diff --git a/Generals/Code/Main/WinMain.cpp b/Generals/Code/Main/WinMain.cpp index 4b2d46f591b..133778b2ff8 100644 --- a/Generals/Code/Main/WinMain.cpp +++ b/Generals/Code/Main/WinMain.cpp @@ -67,7 +67,7 @@ #ifdef RTS_ENABLE_CRASHDUMP #include "Common/MiniDumper.h" #endif -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI #include "imgui.h" #endif @@ -298,7 +298,7 @@ static const char *messageToString(unsigned int message) // critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. // // See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); #endif // WndProc ==================================================================== @@ -307,7 +307,7 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) { return true; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 147760eeb25..2e0733f111e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -32,7 +32,7 @@ #include "GameClient/GameClient.h" // USER INCLUDES ////////////////////////////////////////////////////////////// -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI #include #include #include "imgui_impl_dx8.h" @@ -528,7 +528,7 @@ void GameClient::update( void ) USE_PERF_TIMER(GameClient_update) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); @@ -648,7 +648,7 @@ void GameClient::update( void ) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif // redraw all views, update the GUI @@ -763,7 +763,7 @@ void GameClient::update( void ) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // Prepare ImGui renderdata before framestepping to ensure proper display // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui::Render(); #endif return; @@ -792,7 +792,7 @@ void GameClient::update( void ) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // see details in comment before this function's signature -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 274ec2b6e82..ac213887b54 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -87,7 +87,7 @@ #include "shdlib.h" -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI #include "imgui.h" #include #include "imgui_impl_dx8.h" @@ -361,7 +361,7 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) void DX8Wrapper::Shutdown(void) { -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); @@ -657,7 +657,7 @@ bool DX8Wrapper::Create_Device(void) return false; } } -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI // Initialize ImGui IMGUI_CHECKVERSION(); ImGui::CreateContext(); @@ -687,7 +687,7 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) WWDEBUG_SAY(("Resetting device.")); DX8_THREAD_ASSERT(); if ((IsInitted) && (D3DDevice != nullptr)) { -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_InvalidateDeviceObjects(); #endif // Release all non-MANAGED stuff @@ -731,7 +731,7 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) Invalidate_Cached_Render_States(); Set_Default_Global_Render_States(); SHD_INIT_SHADERS; -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI ImGui_ImplDX8_CreateDeviceObjects(); #endif WWDEBUG_SAY(("Device reset completed")); @@ -1777,7 +1777,7 @@ void DX8Wrapper::Begin_Scene(void) void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI { ImDrawData* data = ImGui::GetDrawData(); if (data && data->CmdListsCount > 0 ) { diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index 406a29c551b..13102929933 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -68,7 +68,7 @@ #include -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI #include "imgui.h" #endif @@ -304,7 +304,7 @@ static const char *messageToString(unsigned int message) // critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. // // See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); #endif // WndProc ==================================================================== @@ -313,7 +313,7 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { -#ifdef RTS_IMGUI_ENABLED +#ifdef RTS_HAS_IMGUI if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) { return true; } From 34374cba2765e32d741ac1704592c882385d3e0e Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 11:29:14 +0100 Subject: [PATCH 20/50] Remove excess lines --- GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 2e0733f111e..7c182aca2ee 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -803,8 +803,6 @@ void GameClient::update( void ) //if(TheGameLogic->getFrame() >= 2) TheDisplay->DRAW(); - - } { From 3adbc7a53bb5afa85713411f55b80851b65b583d Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 11:34:52 +0100 Subject: [PATCH 21/50] Update Error messsages in CMakeLists --- Core/Libraries/Source/ImGui/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index 40610416c3b..10140faa6c0 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -39,7 +39,7 @@ set(IMGUI_INCLUDE_DIRS if (WIN32) # for now we only need it in debug configurations if ( NOT ( (CMAKE_BUILD_TYPE STREQUAL "Debug") OR RTS_BUILD_OPTION_DEBUG ) ) - MESSAGE(FATAL_ERROR "ImGui integration is currently only possible in Debug build modes") + MESSAGE(FATAL_ERROR "ImGui is currently only available in Debug build modes") endif () MESSAGE(STATUS "Enabling imgui console integration") @@ -56,6 +56,6 @@ if (WIN32) ) else () # currently only WIN32 DX is supported - MESSAGE(FATAL_ERROR "Non-Windows platforms currently not supported for ImGui integration ${MSG_ERR_SUFFIX}") + MESSAGE(FATAL_ERROR "Non-Windows platforms currently not supported for ImGui integration") endif () # end target build section From 56c92d7ea6c931db2255dc21277fbc609aec9fb1 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 11:36:32 +0100 Subject: [PATCH 22/50] Change NULL to nullptr in dx8 backend --- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index db83a0c5627..9fcedfe09bb 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -61,7 +61,7 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { } if (pSurface) { pSurface->Release(); - pSurface = NULL; + pSurface = nullptr; } // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. @@ -70,7 +70,7 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { bd->realDepthStencilBuffer = nullptr; } bd->pd3dDevice->SetRenderTarget(nullptr, bd->DepthBuffer); - bd->pd3dDevice->SetPixelShader(NULL); + bd->pd3dDevice->SetPixelShader(nullptr); bd->pd3dDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX); bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); @@ -308,7 +308,7 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { bd->pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); bd->pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); bd->pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0xFF); - bd->pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0f, 0); + bd->pd3dDevice->Clear(0, nullptr, D3DCLEAR_STENCIL, 0, 1.0f, 0); bd->pd3dDevice->SetStreamSource(0, bd->maskVB, sizeof(CUSTOMVERTEX)); bd->pd3dDevice->SetIndices(bd->maskIB, 0); bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2); From d0db383db4246e92200c8e2c11e726712997e407 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 12:10:10 +0100 Subject: [PATCH 23/50] Remove and centralize description comments --- .../Source/GameClient/GameClient.cpp | 17 ++------ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 39 ++----------------- .../Source/GameClient/GameClient.cpp | 17 ++------ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 19 --------- 4 files changed, 11 insertions(+), 81 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index 8e718f9fd64..82a90633433 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -486,15 +486,6 @@ void GameClient::registerDrawable( Drawable *draw ) } -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: -// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() -// - DX8Wrapper: manages context/backend initialization and cleanup, -// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. -// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and -// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. -// -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ @@ -504,7 +495,7 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); @@ -607,7 +598,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif @@ -721,7 +712,7 @@ void GameClient::update( void ) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // Prepare ImGui renderdata before framestepping to ensure proper display -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); #endif @@ -749,7 +740,7 @@ void GameClient::update( void ) } // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 5837ced7f7f..e1d40f1ddb7 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -352,15 +352,7 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) return(true); } -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: -// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() -// - DX8Wrapper: manages context/backend initialization and cleanup, -// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. -// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and -// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. -// -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. + void DX8Wrapper::Shutdown(void) { #ifdef RTS_HAS_IMGUI @@ -529,16 +521,6 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) } - -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: -// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() -// - DX8Wrapper: manages context/backend initialization and cleanup, -// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. -// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and -// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. -// -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. bool DX8Wrapper::Create_Device(void) { WWASSERT(D3DDevice==nullptr); // for now, once you've created a device, you're stuck with it! @@ -617,7 +599,7 @@ bool DX8Wrapper::Create_Device(void) return false; } // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI // Initialize ImGui IMGUI_CHECKVERSION(); @@ -643,19 +625,13 @@ bool DX8Wrapper::Create_Device(void) return true; } -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: WndProc forwards input to ImGui via ImGui_ImplWin32_WndProcHandler(), DX8Wrapper manages context/backend initialization and cleanup, -// and End_Scene() renders ImGui draw data after the main scene.GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), -// while ImGui::Render() is called before DRAW() operations and critically before early returns in RTS_DEBUG mode (frame stepping) to -// ensure frames are properly closed and the demo window displays. -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. bool DX8Wrapper::Reset_Device(bool reload_assets) { WWDEBUG_SAY(("Resetting device.")); DX8_THREAD_ASSERT(); if ((IsInitted) && (D3DDevice != nullptr)) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui_ImplDX8_InvalidateDeviceObjects(); #endif @@ -1652,15 +1628,6 @@ void DX8Wrapper::Begin_Scene(void) DX8WebBrowser::Update(); } -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: -// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() -// - DX8Wrapper: manages context/backend initialization and cleanup, -// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. -// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and -// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. -// -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 7c182aca2ee..7fd48f11ae8 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -509,15 +509,6 @@ void GameClient::registerDrawable( Drawable *draw ) } -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: -// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() -// - DX8Wrapper: manages context/backend initialization and cleanup, -// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. -// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and -// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. -// -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ @@ -527,7 +518,7 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); @@ -647,7 +638,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif @@ -762,7 +753,7 @@ void GameClient::update( void ) { // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) // Prepare ImGui renderdata before framestepping to ensure proper display -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); #endif @@ -791,7 +782,7 @@ void GameClient::update( void ) // TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details in comment before this function's signature +// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index ac213887b54..c3dfb0896cd 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -532,16 +532,6 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) } - -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: -// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() -// - DX8Wrapper: manages context/backend initialization and cleanup, -// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. -// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and -// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. -// -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. bool DX8Wrapper::Create_Device(void) { WWASSERT(D3DDevice==nullptr); // for now, once you've created a device, you're stuck with it! @@ -1765,15 +1755,6 @@ void DX8Wrapper::Begin_Scene(void) DX8WebBrowser::Update(); } -// ThSuperHackers @feature jurassiclizard 16/01/2026 introduce ImGui framework (PR#2127) -// ImGui workflow: -// - WndProc: forwards input to ImGui via ImGui_ImplWin32_WndProcHandler() -// - DX8Wrapper: manages context/backend initialization and cleanup, -// - DX8Wrapper: handles device reset by invalidating/recreating device objects and End_Scene() and renders ImGui draw data after the main scene. -// - GameClient: GameClient::update() starts each frame with NewFrame() calls and builds UI (ShowDemoWindow), while ImGui::Render() is called before DRAW() operations and -// critically before early returns in RTS_DEBUG mode (frame stepping) to ensure frames are properly closed and the demo window displays. -// -// See GameClient::update(), DX8Wrapper::Create_Device(), DX8Wrapper::Init(), DX8Wrapper::Shutdown(), DX8Wrapper::End_Scene(), and WndProc() for implementation details. void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); From 39de6fc73acea503dc41ae0bba79492a6f5bc38f Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 12:26:24 +0100 Subject: [PATCH 24/50] Revert "Change NULL to nullptr in dx8 backend" This reverts commit d46904053379f367f09747629c25c6cd56281260. Reason : Build failure with HRESULT IDirect3DDevice8::SetPixelShader(DWORD)': cannot convert argument 1 from 'nullptr' to 'DWORD --- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 9fcedfe09bb..db83a0c5627 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -61,7 +61,7 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { } if (pSurface) { pSurface->Release(); - pSurface = nullptr; + pSurface = NULL; } // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. @@ -70,7 +70,7 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { bd->realDepthStencilBuffer = nullptr; } bd->pd3dDevice->SetRenderTarget(nullptr, bd->DepthBuffer); - bd->pd3dDevice->SetPixelShader(nullptr); + bd->pd3dDevice->SetPixelShader(NULL); bd->pd3dDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX); bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); @@ -308,7 +308,7 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { bd->pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); bd->pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); bd->pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0xFF); - bd->pd3dDevice->Clear(0, nullptr, D3DCLEAR_STENCIL, 0, 1.0f, 0); + bd->pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0f, 0); bd->pd3dDevice->SetStreamSource(0, bd->maskVB, sizeof(CUSTOMVERTEX)); bd->pd3dDevice->SetIndices(bd->maskIB, 0); bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2); From 3f7f17ed0e46ad6a599cadd05d8d278174d6bdb6 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 12:45:31 +0100 Subject: [PATCH 25/50] Move lib_imgui linking away from corei_always now linking against gi_always and zi_always to ensure rendering targets have access --- Core/CMakeLists.txt | 4 ---- Generals/Code/CMakeLists.txt | 4 ++++ GeneralsMD/Code/CMakeLists.txt | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 79f29fdc9d2..5d69b54edd7 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -24,10 +24,6 @@ target_link_libraries(corei_always INTERFACE corei_libraries_include resources ) -# link imgui if needed -if (RTS_BUILD_OPTION_IMGUI) - target_link_libraries(corei_always INTERFACE lib_imgui) -endif () target_link_libraries(corei_always_no_pch INTERFACE core_config diff --git a/Generals/Code/CMakeLists.txt b/Generals/Code/CMakeLists.txt index e52d043e441..7adc8512715 100644 --- a/Generals/Code/CMakeLists.txt +++ b/Generals/Code/CMakeLists.txt @@ -28,6 +28,10 @@ target_link_libraries(gi_always INTERFACE gi_libraries_include corei_always # Must stay below so headers from game are included first ) +# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(gi_always INTERFACE lib_imgui) +endif () target_link_libraries(gi_always_no_pch INTERFACE gi_libraries_include corei_always_no_pch # Must stay below so headers from game are included first diff --git a/GeneralsMD/Code/CMakeLists.txt b/GeneralsMD/Code/CMakeLists.txt index d173801dc98..c1712705295 100644 --- a/GeneralsMD/Code/CMakeLists.txt +++ b/GeneralsMD/Code/CMakeLists.txt @@ -28,6 +28,10 @@ target_link_libraries(zi_always INTERFACE zi_libraries_include corei_always # Must stay below so headers from game are included first ) +# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(zi_always INTERFACE lib_imgui) +endif () target_link_libraries(zi_always_no_pch INTERFACE zi_libraries_include corei_always_no_pch # Must stay below so headers from game are included first From cec768fb7ca1fe83461a5fa5be87b68ef17711c9 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 13:01:39 +0100 Subject: [PATCH 26/50] Restore nullptr fixes --- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index db83a0c5627..8d29f611363 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -61,7 +61,7 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { } if (pSurface) { pSurface->Release(); - pSurface = NULL; + pSurface = nullptr; } // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. @@ -70,7 +70,7 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { bd->realDepthStencilBuffer = nullptr; } bd->pd3dDevice->SetRenderTarget(nullptr, bd->DepthBuffer); - bd->pd3dDevice->SetPixelShader(NULL); + bd->pd3dDevice->SetPixelShader(0); bd->pd3dDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX); bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); @@ -308,7 +308,7 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { bd->pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); bd->pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); bd->pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0xFF); - bd->pd3dDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0f, 0); + bd->pd3dDevice->Clear(0, nullptr, D3DCLEAR_STENCIL, 0, 1.0f, 0); bd->pd3dDevice->SetStreamSource(0, bd->maskVB, sizeof(CUSTOMVERTEX)); bd->pd3dDevice->SetIndices(bd->maskIB, 0); bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2); From ebc7fad69a5616c5a796579e696b3e825a449d8a Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 14:08:19 +0100 Subject: [PATCH 27/50] Fix copyright header and space issues --- .../ImGui/dx8_backend/imgui_impl_dx8.cpp | 35 ++++++++++++++++++- .../Source/ImGui/dx8_backend/imgui_impl_dx8.h | 35 +++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 8d29f611363..4e127c4f389 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -1,10 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) + * Copyright (c) 2021 KoMaR1911 + * Copyright (c) 2025 Meigyoku-Thmn + * Copyright (c) 2026 TheSuperHackers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file imgui_impl_dx8.cpp + * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend + * + * This needs to be used along with a Platform Backend (e.g. Win32) + */ + #include #include "imgui_impl_dx8.h" // DirectX #include "d3d8.h" -// based on https://github.com/KoMaR1911/C4USMultiHack-Metin2/blob/main/EngineX-Pro/ImGui/imgui_impl_dx8.cpp // DirectX data struct ImGui_ImplDX8_Data { diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h index 42b90a892cd..2e33ca9a94a 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h @@ -1,5 +1,34 @@ -// Renderer Backend for DirectX8, based on the official DirectX9 Backend from Dear ImGui -// This needs to be used along with a Platform Backend (e.g. Win32) +/* + * The MIT License (MIT) + * + * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) + * Copyright (c) 2021 KoMaR1911 + * Copyright (c) 2025 Meigyoku-Thmn + * Copyright (c) 2026 TheSuperHackers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @file imgui_impl_dx8.h + * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend + */ #pragma once #include // IMGUI_IMPL_API @@ -13,4 +42,4 @@ IMGUI_IMPL_API void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing Dear ImGui state. IMGUI_IMPL_API bool ImGui_ImplDX8_CreateDeviceObjects(); -IMGUI_IMPL_API void ImGui_ImplDX8_InvalidateDeviceObjects(); \ No newline at end of file +IMGUI_IMPL_API void ImGui_ImplDX8_InvalidateDeviceObjects(); From 15584834882edc97017f1e457bfe0bdb221e9f0d Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 14:54:19 +0100 Subject: [PATCH 28/50] Fix style issues --- Core/Libraries/Source/ImGui/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index 10140faa6c0..bd31a1cc4dc 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -16,7 +16,6 @@ set(IMGUI_BASE_SRCS "${imgui_SOURCE_DIR}/imgui_demo.cpp" ) - # Main Win32 DX8 specific sources we are going to need we can specify more if we need extra platforms set(IMGUI_WIN32_DX8_IMPL_SRCS "${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp" @@ -42,7 +41,7 @@ if (WIN32) MESSAGE(FATAL_ERROR "ImGui is currently only available in Debug build modes") endif () - MESSAGE(STATUS "Enabling imgui console integration") + MESSAGE(STATUS "Enabling ImGui") add_library(lib_imgui STATIC ${IMGUI_WIN32_DX8_ALL_SRCS}) target_include_directories(lib_imgui PUBLIC ${IMGUI_INCLUDE_DIRS}) From d288d6eb23d3a1f19c9dee7b44887c4702ccc50d Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:15:00 +0100 Subject: [PATCH 29/50] Fix ImGui dx8 style and copyright header --- .../ImGui/dx8_backend/imgui_impl_dx8.cpp | 144 ++++++++++++------ .../Source/ImGui/dx8_backend/imgui_impl_dx8.h | 3 +- 2 files changed, 96 insertions(+), 51 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 4e127c4f389..3d509c3e781 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -2,8 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) - * Copyright (c) 2021 KoMaR1911 - * Copyright (c) 2025 Meigyoku-Thmn + * Copyright (c) 2025 Meigyoku-Thmn and others * Copyright (c) 2026 TheSuperHackers * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -40,7 +39,8 @@ // DirectX data -struct ImGui_ImplDX8_Data { +struct ImGui_ImplDX8_Data +{ LPDIRECT3DDEVICE8 pd3dDevice; LPDIRECT3DVERTEXBUFFER8 pVB; LPDIRECT3DINDEXBUFFER8 pIB; @@ -59,7 +59,8 @@ struct ImGui_ImplDX8_Data { } }; -struct CUSTOMVERTEX { +struct CUSTOMVERTEX +{ float pos[3]; D3DCOLOR col; float uv[2]; @@ -72,17 +73,20 @@ struct CUSTOMVERTEX { #define IMGUI_COL_TO_DX8_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16)) #endif -ImGui_ImplDX8_Data* ImGui_ImplDX8_GetBackendData() { +ImGui_ImplDX8_Data* ImGui_ImplDX8_GetBackendData() +{ return ImGui::GetCurrentContext() ? (ImGui_ImplDX8_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } // Functions -void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { +void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) +{ ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); IDirect3DSurface8* pSurface{}; D3DSURFACE_DESC d3dSize{}; - if (SUCCEEDED(bd->pd3dDevice->GetRenderTarget(&pSurface)) && SUCCEEDED(pSurface->GetDesc(&d3dSize))) { + if (SUCCEEDED(bd->pd3dDevice->GetRenderTarget(&pSurface)) && SUCCEEDED(pSurface->GetDesc(&d3dSize))) + { // Setup viewport D3DVIEWPORT8 vp{}; vp.X = vp.Y = 0; @@ -92,14 +96,16 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { vp.MaxZ = 1.0f; bd->pd3dDevice->SetViewport(&vp); } - if (pSurface) { + if (pSurface) + { pSurface->Release(); pSurface = nullptr; } // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. // Check result to prevent crash when restoring depth buffer with SetRenderTarget - if (bd->pd3dDevice->GetDepthStencilSurface(&bd->realDepthStencilBuffer) != D3D_OK) { + if (bd->pd3dDevice->GetDepthStencilSurface(&bd->realDepthStencilBuffer) != D3D_OK) + { bd->realDepthStencilBuffer = nullptr; } bd->pd3dDevice->SetRenderTarget(nullptr, bd->DepthBuffer); @@ -159,11 +165,13 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) { } } -void build_mask_vbuffer(const RECT* rect) { +void build_mask_vbuffer(const RECT* rect) +{ ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); CUSTOMVERTEX* vtx_dst{}; // Check Lock result to prevent null pointer dereference - if (bd->maskVB->Lock(0, (UINT)(6 * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, 0) != D3D_OK) { + if (bd->maskVB->Lock(0, (UINT)(6 * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, 0) != D3D_OK) + { return; } vtx_dst[0].pos[0] = (float)rect->left; @@ -206,15 +214,18 @@ void build_mask_vbuffer(const RECT* rect) { } // Render function. -void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { +void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) +{ // Avoid rendering when minimized if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; // Create and grow buffers if needed ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); - if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) { - if (bd->pVB) { + if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) + { + if (bd->pVB) + { bd->pVB->Release(); bd->pVB = nullptr; } @@ -222,8 +233,10 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB) < 0) return; } - if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) { - if (bd->pIB) { + if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) + { + if (bd->pIB) + { bd->pIB->Release(); bd->pIB = nullptr; } @@ -232,12 +245,16 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { return; } - if (!bd->maskVB && !bd->maskIB) { - if (bd->pd3dDevice->CreateVertexBuffer(6 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->maskVB) < 0) return; - if (bd->pd3dDevice->CreateIndexBuffer(6, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->maskIB) < 0) return; + if (!bd->maskVB && !bd->maskIB) + { + if (bd->pd3dDevice->CreateVertexBuffer(6 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->maskVB) < 0) + return; + if (bd->pd3dDevice->CreateIndexBuffer(6, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->maskIB) < 0) + return; ImDrawIdx* idx_dst{}; // Check Lock result to prevent null pointer dereference - if (bd->maskIB->Lock(0, 6 * sizeof(ImDrawIdx), (BYTE**)&idx_dst, D3DLOCK_DISCARD) != D3D_OK) { + if (bd->maskIB->Lock(0, 6 * sizeof(ImDrawIdx), (BYTE**)&idx_dst, D3DLOCK_DISCARD) != D3D_OK) + { return; } idx_dst[0] = 0; @@ -253,7 +270,8 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { DWORD d3d8_state_block; if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d8_state_block) < 0) return; - if (bd->pd3dDevice->CaptureStateBlock(d3d8_state_block) < 0) { + if (bd->pd3dDevice->CaptureStateBlock(d3d8_state_block) < 0) + { bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); return; } @@ -267,21 +285,25 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { // Allocate buffers CUSTOMVERTEX* vtx_dst{}; ImDrawIdx* idx_dst{}; - if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, D3DLOCK_DISCARD) < 0) { + if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, D3DLOCK_DISCARD) < 0) + { bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); return; } - if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (BYTE**)&idx_dst, D3DLOCK_DISCARD) < 0) { + if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (BYTE**)&idx_dst, D3DLOCK_DISCARD) < 0) + { bd->pVB->Unlock(); bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); return; } // Copy and convert all vertices into a single contiguous buffer, convert colors to DX8 default format. - for (int n = 0; n < draw_data->CmdListsCount; n++) { + for (int n = 0; n < draw_data->CmdListsCount; n++) + { const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; - for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) + { vtx_dst->pos[0] = vtx_src->pos.x; vtx_dst->pos[1] = vtx_src->pos.y; vtx_dst->pos[2] = 0.0f; @@ -308,11 +330,14 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { int global_vtx_offset = 0; int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) { + for (int n = 0; n < draw_data->CmdListsCount; n++) + { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != nullptr) { + if (pcmd->UserCallback != nullptr) + { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) @@ -320,7 +345,8 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { else pcmd->UserCallback(cmd_list, pcmd); } - else { + else + { // Project clipping rectangles into framebuffer space ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); @@ -371,7 +397,8 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { // Restore the DX8 state bd->pd3dDevice->SetRenderTarget(nullptr, bd->realDepthStencilBuffer); - if (bd->realDepthStencilBuffer) { + if (bd->realDepthStencilBuffer) + { bd->realDepthStencilBuffer->Release(); bd->realDepthStencilBuffer = nullptr; } @@ -379,7 +406,8 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) { bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); } -bool ImGui_ImplDX8_Init(IDirect3DDevice8* device) { +bool ImGui_ImplDX8_Init(IDirect3DDevice8* device) +{ ImGuiIO& io = ImGui::GetIO(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); @@ -395,7 +423,8 @@ bool ImGui_ImplDX8_Init(IDirect3DDevice8* device) { return true; } -void ImGui_ImplDX8_Shutdown() { +void ImGui_ImplDX8_Shutdown() +{ ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); @@ -409,7 +438,8 @@ void ImGui_ImplDX8_Shutdown() { IM_DELETE(bd); } -bool ImGui_ImplDX8_CreateFontsTexture() { +bool ImGui_ImplDX8_CreateFontsTexture() +{ // Build texture atlas ImGuiIO& io = ImGui::GetIO(); ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); @@ -419,7 +449,8 @@ bool ImGui_ImplDX8_CreateFontsTexture() { // Convert RGBA32 to BGRA32 #ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (io.Fonts->TexPixelsUseColors) { + if (io.Fonts->TexPixelsUseColors) + { ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) *dst = IMGUI_COL_TO_DX8_ARGB(*src); @@ -449,24 +480,30 @@ bool ImGui_ImplDX8_CreateFontsTexture() { return true; } -bool ImGui_ImplD3D8_CreateDepthStencilBuffer() { +bool ImGui_ImplD3D8_CreateDepthStencilBuffer() +{ ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); - if (bd->pd3dDevice == nullptr) { + if (bd->pd3dDevice == nullptr) + { return false; } - if (bd->DepthBuffer == nullptr) { + if (bd->DepthBuffer == nullptr) + { IDirect3DSurface8* realDepth; D3DSURFACE_DESC sfcDesc; - if (bd->pd3dDevice->GetDepthStencilSurface(&realDepth) != D3D_OK || ! realDepth) { + if (bd->pd3dDevice->GetDepthStencilSurface(&realDepth) != D3D_OK || ! realDepth) + { return false; } - if (realDepth->GetDesc(&sfcDesc) != 0) { + if (realDepth->GetDesc(&sfcDesc) != 0) + { return false; } realDepth->Release(); realDepth = nullptr; - if (bd->pd3dDevice->CreateDepthStencilSurface(sfcDesc.Width, sfcDesc.Height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, &bd->DepthBuffer) != 0) { + if (bd->pd3dDevice->CreateDepthStencilSurface(sfcDesc.Width, sfcDesc.Height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, &bd->DepthBuffer) != 0) + { return false; } } @@ -474,7 +511,8 @@ bool ImGui_ImplD3D8_CreateDepthStencilBuffer() { return true; } -bool ImGui_ImplDX8_CreateDeviceObjects() { +bool ImGui_ImplDX8_CreateDeviceObjects() +{ ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); if (!bd || !bd->pd3dDevice) return false; @@ -485,38 +523,46 @@ bool ImGui_ImplDX8_CreateDeviceObjects() { return true; } -void ImGui_ImplDX8_InvalidateDeviceObjects() { +void ImGui_ImplDX8_InvalidateDeviceObjects() +{ ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); if (!bd || !bd->pd3dDevice) return; - if (bd->pVB) { + if (bd->pVB) + { bd->pVB->Release(); bd->pVB = nullptr; } - if (bd->pIB) { + if (bd->pIB) + { bd->pIB->Release(); bd->pIB = nullptr; } - if (bd->maskVB) { + if (bd->maskVB) + { bd->maskVB->Release(); bd->maskVB = nullptr; } - if (bd->maskIB) { + if (bd->maskIB) + { bd->maskIB->Release(); bd->maskIB = nullptr; } - if (bd->DepthBuffer) { + if (bd->DepthBuffer) + { bd->DepthBuffer->Release(); bd->DepthBuffer = nullptr; } - if (bd->FontTexture) { + if (bd->FontTexture) + { bd->FontTexture->Release(); bd->FontTexture = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. } -void ImGui_ImplDX8_NewFrame() { +void ImGui_ImplDX8_NewFrame() +{ ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX8_Init()?"); diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h index 2e33ca9a94a..8233c61d8ae 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h @@ -2,8 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) - * Copyright (c) 2021 KoMaR1911 - * Copyright (c) 2025 Meigyoku-Thmn + * Copyright (c) 2025 Meigyoku-Thmn and others * Copyright (c) 2026 TheSuperHackers * * Permission is hereby granted, free of charge, to any person obtaining a copy From d086853410047f0fbc9b41fe7f025b0835f224f6 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:27:34 +0100 Subject: [PATCH 30/50] unify cmake win dx8 imgui impl variables --- Core/Libraries/Source/ImGui/CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index bd31a1cc4dc..6f38148afde 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -17,14 +17,12 @@ set(IMGUI_BASE_SRCS ) # Main Win32 DX8 specific sources we are going to need we can specify more if we need extra platforms -set(IMGUI_WIN32_DX8_IMPL_SRCS +set(IMGUI_WIN32_DX8_ALL_SRCS + "${IMGUI_BASE_SRCS}" "${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp" "${CMAKE_SOURCE_DIR}/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp" ) -# All Win32 DX8 sources -set(IMGUI_WIN32_DX8_ALL_SRCS ${IMGUI_BASE_SRCS} ${IMGUI_WIN32_DX8_IMPL_SRCS}) - # All Include directories set(IMGUI_INCLUDE_DIRS "${imgui_SOURCE_DIR}" From 22b9274697c477e18f264827b9c8b6cd5522558e Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:28:37 +0100 Subject: [PATCH 31/50] remove redundant C-Style casting for ImGui Io --- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 +- GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index e1d40f1ddb7..cff02a84867 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -604,7 +604,7 @@ bool DX8Wrapper::Create_Device(void) // Initialize ImGui IMGUI_CHECKVERSION(); ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; + ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Dark Style diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index c3dfb0896cd..d12072eb419 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -651,7 +651,7 @@ bool DX8Wrapper::Create_Device(void) // Initialize ImGui IMGUI_CHECKVERSION(); ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; + ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Dark Style From ca0b995d18393e37da12d06e539e33f39919c06f Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:49:17 +0100 Subject: [PATCH 32/50] Fix SuperHackers comment alignment and redundancy --- .../Code/GameEngine/Source/GameClient/GameClient.cpp | 11 ++--------- .../Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 7 ++----- .../Code/GameEngine/Source/GameClient/GameClient.cpp | 11 ++--------- 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index 82a90633433..f9ef3603632 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -489,13 +489,13 @@ void GameClient::registerDrawable( Drawable *draw ) /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details under WinMain.cpp (WndProc()) DECLARE_PERF_TIMER(GameClient_update) DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); @@ -597,8 +597,6 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif @@ -710,9 +708,6 @@ void GameClient::update( void ) // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// Prepare ImGui renderdata before framestepping to ensure proper display -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); #endif @@ -739,8 +734,6 @@ void GameClient::update( void ) TheDisplay->UPDATE(); } -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index cff02a84867..a8a89bfc1d3 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -268,7 +268,8 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) *y += dy; } - +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details under WinMain.cpp (WndProc()) bool DX8Wrapper::Init(void * hwnd, bool lite) { WWASSERT(!IsInitted); @@ -598,8 +599,6 @@ bool DX8Wrapper::Create_Device(void) { return false; } -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI // Initialize ImGui IMGUI_CHECKVERSION(); @@ -630,8 +629,6 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) WWDEBUG_SAY(("Resetting device.")); DX8_THREAD_ASSERT(); if ((IsInitted) && (D3DDevice != nullptr)) { -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui_ImplDX8_InvalidateDeviceObjects(); #endif diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 7fd48f11ae8..0caba54dfb7 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -512,13 +512,13 @@ void GameClient::registerDrawable( Drawable *draw ) /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details under WinMain.cpp (WndProc()) DECLARE_PERF_TIMER(GameClient_update) DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); @@ -637,8 +637,6 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif @@ -751,9 +749,6 @@ void GameClient::update( void ) // need to draw the first frame, then don't draw again until TheGlobalData->m_noDraw if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// Prepare ImGui renderdata before framestepping to ensure proper display -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); #endif @@ -781,8 +776,6 @@ void GameClient::update( void ) } -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) #ifdef RTS_HAS_IMGUI ImGui::Render(); // Prepare render data #endif From ff01f4417eb249afa1f1baa443d8022c9f85a88a Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 16:00:42 +0100 Subject: [PATCH 33/50] add dx9 imgui impl header to our own dx8 impl files --- .../ImGui/dx8_backend/imgui_impl_dx8.cpp | 28 ++++++++++++++----- .../Source/ImGui/dx8_backend/imgui_impl_dx8.h | 26 +++++++++++++---- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 3d509c3e781..2e6bb14821c 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -1,7 +1,28 @@ +/** + * @file imgui_impl_dx8.cpp + * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend + */ + +// dear imgui: Renderer Backend for DirectX8 +// This needs to be used along with a Platform Backend (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE8' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + /* * The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) + * Copyright (c) 2021 KoMaR1911 * Copyright (c) 2025 Meigyoku-Thmn and others * Copyright (c) 2026 TheSuperHackers * @@ -24,13 +45,6 @@ * SOFTWARE. */ -/** - * @file imgui_impl_dx8.cpp - * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend - * - * This needs to be used along with a Platform Backend (e.g. Win32) - */ - #include #include "imgui_impl_dx8.h" diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h index 8233c61d8ae..62549c8edbb 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h @@ -1,9 +1,28 @@ +/** + * @file imgui_impl_dx8.h + * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend + */ + +// dear imgui: Renderer Backend for DirectX8 +// This needs to be used along with a Platform Backend (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE8' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + /* * The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) * Copyright (c) 2025 Meigyoku-Thmn and others - * Copyright (c) 2026 TheSuperHackers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,11 +43,6 @@ * SOFTWARE. */ -/** - * @file imgui_impl_dx8.h - * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend - */ - #pragma once #include // IMGUI_IMPL_API From e9a36e6ab38e35627286d36d18263b80706e6a0d Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 21:21:28 +0100 Subject: [PATCH 34/50] Create wrapper for ImGui Frame mgmt and integrate in WorldbuilderV --- Core/Libraries/Source/ImGui/CMakeLists.txt | 8 +++- .../ImGui/wrapper/ImGuiFrameManager.cpp | 31 +++++++++++++ .../Source/ImGui/wrapper/ImGuiFrameManager.h | 13 ++++++ .../Source/GameClient/GameClient.cpp | 13 +++--- .../Tools/WorldBuilder/include/wbview3d.h | 4 ++ .../Code/Tools/WorldBuilder/src/wbview3d.cpp | 44 ++++++++++++++++++- .../Source/GameClient/GameClient.cpp | 13 +++--- 7 files changed, 107 insertions(+), 19 deletions(-) create mode 100644 Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp create mode 100644 Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index 6f38148afde..c17904a425d 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -41,8 +41,12 @@ if (WIN32) MESSAGE(STATUS "Enabling ImGui") - add_library(lib_imgui STATIC ${IMGUI_WIN32_DX8_ALL_SRCS}) - target_include_directories(lib_imgui PUBLIC ${IMGUI_INCLUDE_DIRS}) + add_library(lib_imgui STATIC ${IMGUI_WIN32_DX8_ALL_SRCS} + "${CMAKE_CURRENT_LIST_DIR}/wrapper/ImGuiFrameManager.cpp" + ) + target_include_directories(lib_imgui + PUBLIC ${IMGUI_INCLUDE_DIRS} + PUBLIC "${CMAKE_CURRENT_LIST_DIR}/wrapper") target_link_libraries(lib_imgui PRIVATE d3d8lib) # use our own imconfig.h diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp new file mode 100644 index 00000000000..eb9bbc13183 --- /dev/null +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp @@ -0,0 +1,31 @@ +#include "ImGuiFrameManager.h" +#include "imgui.h" +#include "imgui_impl_dx8.h" +#include "imgui_impl_win32.h" + +bool ImGuiFrameManager::s_frameOpen = false; + +void ImGuiFrameManager::BeginFrame() +{ + if (s_frameOpen) { + return; + } + + ImGui_ImplDX8_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + s_frameOpen = true; +} + +void ImGuiFrameManager::EndFrame() +{ + if (!s_frameOpen) { + return; + } + + ImGui::Render(); + + s_frameOpen = false; +} + diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h new file mode 100644 index 00000000000..26cd702d293 --- /dev/null +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -0,0 +1,13 @@ +#pragma once + + +class ImGuiFrameManager +{ +public: + static void BeginFrame(); + static void EndFrame(); // Includes Render() + +private: + static bool s_frameOpen; +}; + diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index f9ef3603632..a61e515c30f 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -84,8 +84,7 @@ #include "GameLogic/ScriptEngine.h" // For TheScriptEngine - jkmcd #ifdef RTS_HAS_IMGUI #include "imgui.h" -#include "imgui_impl_dx8.h" -#include "imgui_impl_win32.h" +#include "ImGuiFrameManager.h" #endif #define DRAWABLE_HASH_SIZE 8192 @@ -497,9 +496,7 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - ImGui_ImplDX8_NewFrame(); - ImGui_ImplWin32_NewFrame(); - ImGui::NewFrame(); + ImGuiFrameManager::BeginFrame(); // Draw ImGui Demo Window { ImGui::ShowDemoWindow(); @@ -598,7 +595,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { #ifdef RTS_HAS_IMGUI - ImGui::Render(); // Prepare render data + ImGuiFrameManager::EndFrame(); #endif // redraw all views, update the GUI TheDisplay->DRAW(); @@ -709,7 +706,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGui::Render(); + ImGuiFrameManager::EndFrame(); #endif return; } @@ -735,7 +732,7 @@ void GameClient::update( void ) } #ifdef RTS_HAS_IMGUI - ImGui::Render(); // Prepare render data + ImGuiFrameManager::EndFrame(); #endif { USE_PERF_TIMER(GameClient_draw) diff --git a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h index 751eb8b2e68..475d2a5406f 100644 --- a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h @@ -76,6 +76,10 @@ class WbView3d : public WbView, public DX8_CleanupHook //{{AFX_VIRTUAL(WbView3d) protected: virtual void OnDraw(CDC* pDC); // overridden to draw this view +#ifdef RTS_HAS_IMGUI + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); +#endif //}}AFX_VIRTUAL // Implementation diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp index 97f571864f9..44987672022 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -95,6 +95,12 @@ #include +#ifdef RTS_HAS_IMGUI +#include +#include +#include +#include "ImGuiFrameManager.h" +#endif // ---------------------------------------------------------------------------- // Misc. Forward Declarations @@ -779,7 +785,9 @@ void WbView3d::resetRenderObjects() if (TheW3DShadowManager) { TheW3DShadowManager->removeAllShadows(); } - +#ifdef RTS_HAS_IMGUI + ImGui_ImplDX8_InvalidateDeviceObjects(); +#endif SceneIterator *sceneIter = m_scene->Create_Iterator(); sceneIter->First(); while(!sceneIter->Is_Done()) { @@ -826,6 +834,10 @@ void WbView3d::resetRenderObjects() updateLights(); if (m_heightMapRenderObj) m_scene->Add_Render_Object(m_heightMapRenderObj); + +#ifdef RTS_HAS_IMGUI + ImGui_ImplDX8_CreateDeviceObjects(); +#endif } // ---------------------------------------------------------------------------- @@ -1995,10 +2007,21 @@ void WbView3d::redraw(void) } // ---------------------------------------------------------------------------- +// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) +// see details under WinMain.cpp (WndProc()) void WbView3d::render() { ++m_updateCount; +#ifdef RTS_HAS_IMGUI + ImGuiFrameManager::BeginFrame(); + + // Build ImGui UI + ImGui::ShowDemoWindow(); + + ImGuiFrameManager::EndFrame(); +#endif + if (WW3D::Begin_Render(true,true,Vector3(0.5f,0.5f,0.5f), TheWaterTransparency->m_minWaterOpacity) == WW3D_ERROR_OK) { @@ -2129,6 +2152,25 @@ void WbView3d::OnDraw(CDC* pDC) // Not used. See OnPaint. } +// TheSuperHackers +#ifdef RTS_HAS_IMGUI +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); +BOOL WbView3d::PreTranslateMessage(MSG *pMsg) +{ + if (ImGui_ImplWin32_WndProcHandler(m_hWnd, pMsg->message,pMsg->wParam, pMsg->lParam)) + { + return TRUE; + } + return WbView::PreTranslateMessage(pMsg); +} + +LRESULT WbView3d::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (ImGui_ImplWin32_WndProcHandler(m_hWnd, message, wParam, lParam)) + return TRUE; + return WbView::WindowProc(message, wParam, lParam); +} +#endif // ---------------------------------------------------------------------------- // WbView3d diagnostics diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 0caba54dfb7..5715532c774 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -34,8 +34,7 @@ // USER INCLUDES ////////////////////////////////////////////////////////////// #ifdef RTS_HAS_IMGUI #include -#include -#include "imgui_impl_dx8.h" +#include "ImGuiFrameManager.h" #include "dx8wrapper.h" #endif @@ -520,9 +519,7 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - ImGui_ImplDX8_NewFrame(); - ImGui_ImplWin32_NewFrame(); - ImGui::NewFrame(); + ImGuiFrameManager::BeginFrame(); // Draw ImGui Demo Window { ImGui::ShowDemoWindow(); @@ -638,7 +635,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { #ifdef RTS_HAS_IMGUI - ImGui::Render(); // Prepare render data + ImGuiFrameManager::EndFrame(); #endif // redraw all views, update the GUI TheDisplay->DRAW(); @@ -750,7 +747,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGui::Render(); + ImGuiFrameManager::EndFrame(); #endif return; } @@ -777,7 +774,7 @@ void GameClient::update( void ) #ifdef RTS_HAS_IMGUI - ImGui::Render(); // Prepare render data + ImGuiFrameManager::EndFrame(); #endif { From 94124e3b9c2eb33ab561e9e123b3f50ab44fa4b0 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Wed, 21 Jan 2026 13:31:48 +0100 Subject: [PATCH 35/50] Finalize ImGui integration in Gen and ZH worldbuilders --- .../ImGui/wrapper/ImGuiFrameManager.cpp | 6 +-- .../Source/ImGui/wrapper/ImGuiFrameManager.h | 21 +++++----- .../Source/GameClient/GameClient.cpp | 8 ++-- .../Tools/WorldBuilder/include/wbview3d.h | 6 ++- .../Code/Tools/WorldBuilder/src/wbview3d.cpp | 12 +++--- .../Source/GameClient/GameClient.cpp | 8 ++-- .../Tools/WorldBuilder/include/wbview3d.h | 7 +++- .../Code/Tools/WorldBuilder/src/wbview3d.cpp | 39 ++++++++++++++++++- 8 files changed, 76 insertions(+), 31 deletions(-) diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp index eb9bbc13183..23fb2230cb0 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp @@ -3,9 +3,9 @@ #include "imgui_impl_dx8.h" #include "imgui_impl_win32.h" -bool ImGuiFrameManager::s_frameOpen = false; +bool ImGui::FrameManager::s_frameOpen = false; -void ImGuiFrameManager::BeginFrame() +void ImGui::FrameManager::BeginFrame() { if (s_frameOpen) { return; @@ -18,7 +18,7 @@ void ImGuiFrameManager::BeginFrame() s_frameOpen = true; } -void ImGuiFrameManager::EndFrame() +void ImGui::FrameManager::EndFrame() { if (!s_frameOpen) { return; diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index 26cd702d293..c2f05e13149 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -1,13 +1,16 @@ #pragma once -class ImGuiFrameManager -{ -public: - static void BeginFrame(); - static void EndFrame(); // Includes Render() - -private: - static bool s_frameOpen; -}; +namespace ImGui { + class FrameManager + { + public: + static void BeginFrame(); + static void EndFrame(); // Includes Render() + + private: + static bool s_frameOpen; + }; +} // namespace ImGui + diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index a61e515c30f..adf577c1d3a 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -496,7 +496,7 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::BeginFrame(); + ImGui::FrameManager::BeginFrame(); // Draw ImGui Demo Window { ImGui::ShowDemoWindow(); @@ -595,7 +595,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::EndFrame(); + ImGui::FrameManager::EndFrame(); #endif // redraw all views, update the GUI TheDisplay->DRAW(); @@ -706,7 +706,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::EndFrame(); + ImGui::FrameManager::EndFrame(); #endif return; } @@ -732,7 +732,7 @@ void GameClient::update( void ) } #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::EndFrame(); + ImGui::FrameManager::EndFrame(); #endif { USE_PERF_TIMER(GameClient_draw) diff --git a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h index 475d2a5406f..4a5a663f0b4 100644 --- a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h @@ -76,13 +76,15 @@ class WbView3d : public WbView, public DX8_CleanupHook //{{AFX_VIRTUAL(WbView3d) protected: virtual void OnDraw(CDC* pDC); // overridden to draw this view + //}}AFX_VIRTUAL + +// Function overrides needed for ImGui Mouse capture #ifdef RTS_HAS_IMGUI virtual BOOL PreTranslateMessage(MSG* pMsg); virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); #endif - //}}AFX_VIRTUAL -// Implementation + // Implementation protected: virtual ~WbView3d(); #ifdef RTS_DEBUG diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp index 44987672022..8520d87cf26 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -98,7 +98,6 @@ #ifdef RTS_HAS_IMGUI #include #include -#include #include "ImGuiFrameManager.h" #endif @@ -2014,12 +2013,11 @@ void WbView3d::render() ++m_updateCount; #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::BeginFrame(); - - // Build ImGui UI - ImGui::ShowDemoWindow(); - - ImGuiFrameManager::EndFrame(); + { + ImGui::FrameManager::BeginFrame(); + ImGui::ShowDemoWindow(); + ImGui::FrameManager::EndFrame(); + } #endif if (WW3D::Begin_Render(true,true,Vector3(0.5f,0.5f,0.5f), TheWaterTransparency->m_minWaterOpacity) == WW3D_ERROR_OK) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 5715532c774..b1b0a34397f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -519,7 +519,7 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::BeginFrame(); + ImGui::FrameManager::BeginFrame(); // Draw ImGui Demo Window { ImGui::ShowDemoWindow(); @@ -635,7 +635,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::EndFrame(); + ImGui::FrameManager::EndFrame(); #endif // redraw all views, update the GUI TheDisplay->DRAW(); @@ -747,7 +747,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::EndFrame(); + ImGui::FrameManager::EndFrame(); #endif return; } @@ -774,7 +774,7 @@ void GameClient::update( void ) #ifdef RTS_HAS_IMGUI - ImGuiFrameManager::EndFrame(); + ImGui::FrameManager::EndFrame(); #endif { diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h index f34426b6782..b52f54667f3 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h @@ -79,7 +79,12 @@ class WbView3d : public WbView, public DX8_CleanupHook virtual void OnDraw(CDC* pDC); // overridden to draw this view //}}AFX_VIRTUAL -// Implementation +// Function overrides needed for ImGui Mouse capture +#ifdef RTS_HAS_IMGUI + virtual BOOL PreTranslateMessage(MSG* pMsg); + virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); +#endif + // Implementation protected: virtual ~WbView3d(); #ifdef RTS_DEBUG diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index 5bc1fe6671d..fec01e3212f 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -96,6 +96,11 @@ #include +#ifdef RTS_HAS_IMGUI +#include +#include +#include "ImGuiFrameManager.h" +#endif // ---------------------------------------------------------------------------- // Misc. Forward Declarations // ---------------------------------------------------------------------------- @@ -800,7 +805,9 @@ void WbView3d::resetRenderObjects() if (TheW3DShadowManager) { TheW3DShadowManager->removeAllShadows(); } - +#ifdef RTS_HAS_IMGUI + ImGui_ImplDX8_InvalidateDeviceObjects(); +#endif SceneIterator *sceneIter = m_scene->Create_Iterator(); sceneIter->First(); while(!sceneIter->Is_Done()) { @@ -850,6 +857,10 @@ void WbView3d::resetRenderObjects() m_heightMapRenderObj->removeAllTrees(); m_heightMapRenderObj->removeAllProps(); } + +#ifdef RTS_HAS_IMGUI + ImGui_ImplDX8_CreateDeviceObjects(); +#endif } // ---------------------------------------------------------------------------- @@ -2078,6 +2089,14 @@ void WbView3d::render() { ++m_updateCount; +#ifdef RTS_HAS_IMGUI + { + ImGui::FrameManager::BeginFrame(); + ImGui::ShowDemoWindow(); + ImGui::FrameManager::EndFrame(); + } +#endif + if (WW3D::Begin_Render(true,true,Vector3(0.5f,0.5f,0.5f), TheWaterTransparency->m_minWaterOpacity) == WW3D_ERROR_OK) { @@ -2211,7 +2230,25 @@ void WbView3d::OnDraw(CDC* pDC) { // Not used. See OnPaint. } +// TheSuperHackers +#ifdef RTS_HAS_IMGUI +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); +BOOL WbView3d::PreTranslateMessage(MSG *pMsg) +{ + if (ImGui_ImplWin32_WndProcHandler(m_hWnd, pMsg->message,pMsg->wParam, pMsg->lParam)) + { + return TRUE; + } + return WbView::PreTranslateMessage(pMsg); +} +LRESULT WbView3d::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) +{ + if (ImGui_ImplWin32_WndProcHandler(m_hWnd, message, wParam, lParam)) + return TRUE; + return WbView::WindowProc(message, wParam, lParam); +} +#endif // ---------------------------------------------------------------------------- // WbView3d diagnostics From 34a4dc6a7302e9485d85b11b236633b18b4c3ba3 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Wed, 21 Jan 2026 17:31:08 +0100 Subject: [PATCH 36/50] Add copyright headers and fix indentation in frame mgr --- .../ImGui/wrapper/ImGuiFrameManager.cpp | 32 ++++++++++++++++--- .../Source/ImGui/wrapper/ImGuiFrameManager.h | 23 +++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp index 23fb2230cb0..afb07f857c9 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp @@ -1,3 +1,24 @@ +/** + * @file ImGuiFrameManager.cpp + * @brief Simple Frame manager for ImGui widgets + */ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2026 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ #include "ImGuiFrameManager.h" #include "imgui.h" #include "imgui_impl_dx8.h" @@ -7,25 +28,28 @@ bool ImGui::FrameManager::s_frameOpen = false; void ImGui::FrameManager::BeginFrame() { - if (s_frameOpen) { + if (s_frameOpen) + { return; } ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); - ImGui::NewFrame(); + NewFrame(); s_frameOpen = true; } void ImGui::FrameManager::EndFrame() { - if (!s_frameOpen) { + if (!s_frameOpen) + { return; } - ImGui::Render(); + Render(); s_frameOpen = false; } + diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index c2f05e13149..3852dbff24d 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -1,3 +1,25 @@ +/** + * @file ImGuiFrameManager.h + * @brief Simple Frame manager for ImGui widgets + */ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2026 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + #pragma once @@ -14,3 +36,4 @@ namespace ImGui { } // namespace ImGui + From 21171d110bb893819521c2579e1ec68d0b8fbbd3 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 22 Jan 2026 15:46:29 +0100 Subject: [PATCH 37/50] Remove imgui integration naming --- Core/Libraries/Source/ImGui/CMakeLists.txt | 2 +- cmake/config-build.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index c17904a425d..e29db8aa60d 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -57,6 +57,6 @@ if (WIN32) ) else () # currently only WIN32 DX is supported - MESSAGE(FATAL_ERROR "Non-Windows platforms currently not supported for ImGui integration") + MESSAGE(FATAL_ERROR "Non-Windows platforms currently not supported for ImGui") endif () # end target build section diff --git a/cmake/config-build.cmake b/cmake/config-build.cmake index 4034113c75e..22ad009da50 100644 --- a/cmake/config-build.cmake +++ b/cmake/config-build.cmake @@ -24,7 +24,7 @@ add_feature_info(DebugBuild RTS_BUILD_OPTION_DEBUG "Building as a \"Debug\" buil add_feature_info(AddressSanitizer RTS_BUILD_OPTION_ASAN "Building with address sanitizer") add_feature_info(Vc6FullDebug RTS_BUILD_OPTION_VC6_FULL_DEBUG "Building VC6 with full debug info") add_feature_info(FFmpegSupport RTS_BUILD_OPTION_FFMPEG "Building with FFmpeg support") -add_feature_info(ImGuiSupportDebug RTS_BUILD_OPTION_IMGUI "Building with ImGui integration in debug builds") +add_feature_info(ImGuiSupport RTS_BUILD_OPTION_IMGUI "Building with ImGui") if(RTS_BUILD_ZEROHOUR) option(RTS_BUILD_ZEROHOUR_TOOLS "Build tools for Zero Hour" ON) From 32a61c4d2be0f5007bc6f9127d962ab08de2e0c7 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 11:46:59 +0100 Subject: [PATCH 38/50] link lib_imgui to g_gameengine and z_gameengine instead of _always --- Generals/Code/CMakeLists.txt | 4 ---- Generals/Code/GameEngine/CMakeLists.txt | 5 +++++ GeneralsMD/Code/CMakeLists.txt | 4 ---- GeneralsMD/Code/GameEngine/CMakeLists.txt | 5 +++++ 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Generals/Code/CMakeLists.txt b/Generals/Code/CMakeLists.txt index 7adc8512715..e52d043e441 100644 --- a/Generals/Code/CMakeLists.txt +++ b/Generals/Code/CMakeLists.txt @@ -28,10 +28,6 @@ target_link_libraries(gi_always INTERFACE gi_libraries_include corei_always # Must stay below so headers from game are included first ) -# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) -if (RTS_BUILD_OPTION_IMGUI) - target_link_libraries(gi_always INTERFACE lib_imgui) -endif () target_link_libraries(gi_always_no_pch INTERFACE gi_libraries_include corei_always_no_pch # Must stay below so headers from game are included first diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index f4ef0c45917..f4e0fccc459 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -1098,6 +1098,11 @@ target_link_libraries(g_gameengine PUBLIC g_wwvegas ) +# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(g_gameengine PRIVATE lib_imgui) +endif () + target_precompile_headers(g_gameengine PRIVATE [["Utility/CppMacros.h"]] # Must be first, to be removed when abandoning VC6 Include/Precompiled/PreRTS.h diff --git a/GeneralsMD/Code/CMakeLists.txt b/GeneralsMD/Code/CMakeLists.txt index c1712705295..d173801dc98 100644 --- a/GeneralsMD/Code/CMakeLists.txt +++ b/GeneralsMD/Code/CMakeLists.txt @@ -28,10 +28,6 @@ target_link_libraries(zi_always INTERFACE zi_libraries_include corei_always # Must stay below so headers from game are included first ) -# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) -if (RTS_BUILD_OPTION_IMGUI) - target_link_libraries(zi_always INTERFACE lib_imgui) -endif () target_link_libraries(zi_always_no_pch INTERFACE zi_libraries_include corei_always_no_pch # Must stay below so headers from game are included first diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 189ab821ffb..23004d537d8 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -1174,6 +1174,11 @@ target_link_libraries(z_gameengine PUBLIC z_wwvegas ) +# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(z_gameengine PRIVATE lib_imgui) +endif () + target_precompile_headers(z_gameengine PRIVATE [["Utility/CppMacros.h"]] # Must be first, to be removed when abandoning VC6 Include/Precompiled/PreRTS.h From 17a3000f91eb97faf47cfbfacbbc8048a38913c1 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:20:19 +0100 Subject: [PATCH 39/50] fix copyright header order --- .../ImGui/dx8_backend/imgui_impl_dx8.cpp | 45 ++++++++++--------- .../Source/ImGui/dx8_backend/imgui_impl_dx8.h | 44 +++++++++--------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 2e6bb14821c..a3c1f9f490f 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -1,28 +1,7 @@ -/** - * @file imgui_impl_dx8.cpp - * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend - */ - -// dear imgui: Renderer Backend for DirectX8 -// This needs to be used along with a Platform Backend (e.g. Win32) - -// Implemented features: -// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE8' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. - -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - /* - * The MIT License (MIT) +* The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) - * Copyright (c) 2021 KoMaR1911 * Copyright (c) 2025 Meigyoku-Thmn and others * Copyright (c) 2026 TheSuperHackers * @@ -45,6 +24,28 @@ * SOFTWARE. */ +/** + * @file imgui_impl_dx8.cpp + * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend + */ + +// dear imgui: Renderer Backend for DirectX8 +// This needs to be used along with a Platform Backend (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE8' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + + + #include #include "imgui_impl_dx8.h" diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h index 62549c8edbb..48d40cca260 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h @@ -1,25 +1,5 @@ -/** - * @file imgui_impl_dx8.h - * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend - */ - -// dear imgui: Renderer Backend for DirectX8 -// This needs to be used along with a Platform Backend (e.g. Win32) - -// Implemented features: -// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE8' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. - -// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - /* - * The MIT License (MIT) +* The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) * Copyright (c) 2025 Meigyoku-Thmn and others @@ -43,6 +23,28 @@ * SOFTWARE. */ +/** + * @file imgui_impl_dx8.h + * @brief DirectX8 renderer backend for Dear ImGui, reverse-engineered from the official DX9 backend + */ + +// dear imgui: Renderer Backend for DirectX8 +// This needs to be used along with a Platform Backend (e.g. Win32) + +// Implemented features: +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE8' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + + + #pragma once #include // IMGUI_IMPL_API From a4957f77b35b595f66920c60d0baf4aad3d70b96 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:26:24 +0100 Subject: [PATCH 40/50] fix more style issues in imgui dx8 backend --- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index a3c1f9f490f..7a6312e168f 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -67,7 +67,8 @@ struct ImGui_ImplDX8_Data IDirect3DSurface8* DepthBuffer; IDirect3DSurface8* realDepthStencilBuffer; - ImGui_ImplDX8_Data() { + ImGui_ImplDX8_Data() + { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; From e916ac7ebbe8ecd4e6d45a0e23639e2cea27485b Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:31:54 +0100 Subject: [PATCH 41/50] remove excess spaces from ImGuiFrameManager --- Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp index afb07f857c9..bf98a968ace 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp @@ -51,5 +51,3 @@ void ImGui::FrameManager::EndFrame() s_frameOpen = false; } - - From eb434570d8cc31acb37b1633119339cdbaf09f6d Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:35:16 +0100 Subject: [PATCH 42/50] align class and namespace for ImGuiFrameManager --- .../Source/ImGui/wrapper/ImGuiFrameManager.h | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index 3852dbff24d..c39a241992a 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -24,15 +24,17 @@ namespace ImGui { - class FrameManager - { - public: - static void BeginFrame(); - static void EndFrame(); // Includes Render() - - private: - static bool s_frameOpen; - }; + +class FrameManager +{ +public: + static void BeginFrame(); + static void EndFrame(); // Includes Render() + +private: + static bool s_frameOpen; +}; + } // namespace ImGui From abe01e085ad37956262137fadb9b298bd67d6c25 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:38:04 +0100 Subject: [PATCH 43/50] remove unwanted comments --- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 1 - GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index a8a89bfc1d3..7873c0f9008 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -611,7 +611,6 @@ bool DX8Wrapper::Create_Device(void) ImGui_ImplWin32_Init(_Hwnd); ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); - // Font setup io.Fonts->AddFontDefault(); io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); #endif diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index d12072eb419..29fac177c05 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -659,7 +659,6 @@ bool DX8Wrapper::Create_Device(void) ImGui_ImplWin32_Init(_Hwnd); ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); - // Font setup io.Fonts->AddFontDefault(); io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); #endif From f142bcd8803bc43f500c4d0c4def02d788fd10e2 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:41:05 +0100 Subject: [PATCH 44/50] move comments inside conditional compilation block in wbview3d --- Generals/Code/Tools/WorldBuilder/include/wbview3d.h | 2 +- GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h index 4a5a663f0b4..7b09a8e5d14 100644 --- a/Generals/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/Generals/Code/Tools/WorldBuilder/include/wbview3d.h @@ -78,8 +78,8 @@ class WbView3d : public WbView, public DX8_CleanupHook virtual void OnDraw(CDC* pDC); // overridden to draw this view //}}AFX_VIRTUAL -// Function overrides needed for ImGui Mouse capture #ifdef RTS_HAS_IMGUI +// Function overrides needed for ImGui Mouse capture virtual BOOL PreTranslateMessage(MSG* pMsg); virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); #endif diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h index b52f54667f3..54b83328218 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h @@ -79,8 +79,8 @@ class WbView3d : public WbView, public DX8_CleanupHook virtual void OnDraw(CDC* pDC); // overridden to draw this view //}}AFX_VIRTUAL -// Function overrides needed for ImGui Mouse capture #ifdef RTS_HAS_IMGUI +// Function overrides needed for ImGui Mouse capture virtual BOOL PreTranslateMessage(MSG* pMsg); virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); #endif From 2eeab3f11b455b46e42fc103eff4c66bff21c3b3 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:43:57 +0100 Subject: [PATCH 45/50] remove superfluous superhackers comment --- Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp | 1 - GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp index 8520d87cf26..d063bfa4b21 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -2150,7 +2150,6 @@ void WbView3d::OnDraw(CDC* pDC) // Not used. See OnPaint. } -// TheSuperHackers #ifdef RTS_HAS_IMGUI extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); BOOL WbView3d::PreTranslateMessage(MSG *pMsg) diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index fec01e3212f..cda001335bc 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -2230,7 +2230,7 @@ void WbView3d::OnDraw(CDC* pDC) { // Not used. See OnPaint. } -// TheSuperHackers + #ifdef RTS_HAS_IMGUI extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND, UINT, WPARAM, LPARAM); BOOL WbView3d::PreTranslateMessage(MSG *pMsg) From 1a575dfe8b9360fa08aedaebd2f50324d5d384e9 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 13:40:43 +0100 Subject: [PATCH 46/50] partially fix regression that stopped imgui from rendering after moving link location multiple targets fail to render imgui. this has been fixed in ZH and generals but is yet to be fixed in worldbuilder --- Generals/Code/GameEngine/CMakeLists.txt | 1 - Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt | 4 ++++ Generals/Code/Main/CMakeLists.txt | 4 ++++ GeneralsMD/Code/GameEngine/CMakeLists.txt | 1 - GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt | 4 ++++ GeneralsMD/Code/Main/CMakeLists.txt | 4 ++++ 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index f4e0fccc459..4c681d55c8a 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -1098,7 +1098,6 @@ target_link_libraries(g_gameengine PUBLIC g_wwvegas ) -# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) if (RTS_BUILD_OPTION_IMGUI) target_link_libraries(g_gameengine PRIVATE lib_imgui) endif () diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index ada976f2a3c..2890c259f27 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -237,6 +237,10 @@ target_compile_definitions(g_ww3d2 PRIVATE $<$:WINVER=0x0500> ) +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(g_ww3d2 PRIVATE lib_imgui) +endif () + target_precompile_headers(g_ww3d2 PRIVATE [["Utility/CppMacros.h"]] # Must be first, to be removed when abandoning VC6 dx8wrapper.h diff --git a/Generals/Code/Main/CMakeLists.txt b/Generals/Code/Main/CMakeLists.txt index 9e14a4cbe75..b67c0cb8b25 100644 --- a/Generals/Code/Main/CMakeLists.txt +++ b/Generals/Code/Main/CMakeLists.txt @@ -7,6 +7,10 @@ else() set_target_properties(g_generals PROPERTIES OUTPUT_NAME generalsv) endif() +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(g_generals PRIVATE lib_imgui) +endif () + target_link_libraries(g_generals PRIVATE binkstub comctl32 diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 23004d537d8..986a1b6fc84 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -1174,7 +1174,6 @@ target_link_libraries(z_gameengine PUBLIC z_wwvegas ) -# Link imgui for rendering targets (dx8wrapper, gameclient, winmain) if (RTS_BUILD_OPTION_IMGUI) target_link_libraries(z_gameengine PRIVATE lib_imgui) endif () diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 59617b6b451..1296f7f6501 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -253,6 +253,10 @@ target_precompile_headers(z_ww3d2 PRIVATE ) +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(z_ww3d2 PRIVATE lib_imgui) +endif () + target_link_libraries(z_ww3d2 PRIVATE core_wwdebug corei_ww3d2 diff --git a/GeneralsMD/Code/Main/CMakeLists.txt b/GeneralsMD/Code/Main/CMakeLists.txt index d6518f442ba..a07ef3b2fdb 100644 --- a/GeneralsMD/Code/Main/CMakeLists.txt +++ b/GeneralsMD/Code/Main/CMakeLists.txt @@ -7,6 +7,10 @@ else() set_target_properties(z_generals PROPERTIES OUTPUT_NAME generalszh) endif() +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(z_generals PRIVATE lib_imgui) +endif () + target_link_libraries(z_generals PRIVATE binkstub comctl32 From 3a1828bb209ebbca30df9e9e0f423a504967bec1 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 14:14:12 +0100 Subject: [PATCH 47/50] fix worldbuilder regression with imgui not showing --- Generals/Code/Tools/WorldBuilder/CMakeLists.txt | 4 ++++ GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt index 263cc6fe32b..4f28f4758e3 100644 --- a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt @@ -212,6 +212,10 @@ target_precompile_headers(g_worldbuilder PRIVATE [["WWCommon.h"]] ) +if (RTS_BUILD_OPTION_IMGUI) + target_link_libraries(g_worldbuilder PRIVATE lib_imgui) +endif () + target_link_libraries(g_worldbuilder PRIVATE d3d8lib core_browserdispatch diff --git a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt index c6e309238db..b465aee239f 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt @@ -217,6 +217,10 @@ target_precompile_headers(z_worldbuilder PRIVATE [["WWCommon.h"]] ) +if(RTS_BUILD_OPTION_IMGUI) + target_link_libraries(z_worldbuilder PRIVATE lib_imgui) +endif () + target_link_libraries(z_worldbuilder PRIVATE core_debug core_profile From e49ef39b96d3e6b76fc8d8adf08fceba89adebf5 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 14:30:47 +0100 Subject: [PATCH 48/50] Apply Microsoft Codestyle and Allman Bracestyle to imgui codebase --- .../ImGui/dx8_backend/imgui_impl_dx8.cpp | 207 +++++++++++------- .../Source/ImGui/dx8_backend/imgui_impl_dx8.h | 22 +- .../Source/ImGui/wrapper/ImGuiFrameManager.h | 13 +- 3 files changed, 138 insertions(+), 104 deletions(-) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp index 7a6312e168f..accaec963c4 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -1,5 +1,5 @@ /* -* The MIT License (MIT) + * The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) * Copyright (c) 2025 Meigyoku-Thmn and others @@ -37,39 +37,36 @@ // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build +// the backends you need. Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq // - Getting Started https://dearimgui.com/getting-started // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp - - -#include #include "imgui_impl_dx8.h" +#include // DirectX #include "d3d8.h" - // DirectX data struct ImGui_ImplDX8_Data { - LPDIRECT3DDEVICE8 pd3dDevice; - LPDIRECT3DVERTEXBUFFER8 pVB; - LPDIRECT3DINDEXBUFFER8 pIB; - LPDIRECT3DVERTEXBUFFER8 maskVB; - LPDIRECT3DINDEXBUFFER8 maskIB; - LPDIRECT3DTEXTURE8 FontTexture; - int VertexBufferSize; - int IndexBufferSize; - IDirect3DSurface8* DepthBuffer; - IDirect3DSurface8* realDepthStencilBuffer; + LPDIRECT3DDEVICE8 pd3dDevice; + LPDIRECT3DVERTEXBUFFER8 pVB; + LPDIRECT3DINDEXBUFFER8 pIB; + LPDIRECT3DVERTEXBUFFER8 maskVB; + LPDIRECT3DINDEXBUFFER8 maskIB; + LPDIRECT3DTEXTURE8 FontTexture; + int VertexBufferSize; + int IndexBufferSize; + IDirect3DSurface8 *DepthBuffer; + IDirect3DSurface8 *realDepthStencilBuffer; ImGui_ImplDX8_Data() { - memset((void*)this, 0, sizeof(*this)); + memset((void *)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } @@ -77,29 +74,29 @@ struct ImGui_ImplDX8_Data struct CUSTOMVERTEX { - float pos[3]; + float pos[3]; D3DCOLOR col; - float uv[2]; + float uv[2]; }; -#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) +#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1) #ifdef IMGUI_USE_BGRA_PACKED_COLOR -#define IMGUI_COL_TO_DX8_ARGB(_COL) (_COL) +#define IMGUI_COL_TO_DX8_ARGB(_COL) (_COL) #else -#define IMGUI_COL_TO_DX8_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16)) +#define IMGUI_COL_TO_DX8_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16)) #endif -ImGui_ImplDX8_Data* ImGui_ImplDX8_GetBackendData() +ImGui_ImplDX8_Data *ImGui_ImplDX8_GetBackendData() { - return ImGui::GetCurrentContext() ? (ImGui_ImplDX8_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; + return ImGui::GetCurrentContext() ? (ImGui_ImplDX8_Data *)ImGui::GetIO().BackendRendererUserData : nullptr; } // Functions -void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) +void ImGui_ImplDX8_SetupRenderState(ImDrawData *draw_data) { - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); - IDirect3DSurface8* pSurface{}; + IDirect3DSurface8 *pSurface{}; D3DSURFACE_DESC d3dSize{}; if (SUCCEEDED(bd->pd3dDevice->GetRenderTarget(&pSurface)) && SUCCEEDED(pSurface->GetDesc(&d3dSize))) { @@ -118,8 +115,8 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) pSurface = nullptr; } - // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. - // Check result to prevent crash when restoring depth buffer with SetRenderTarget + // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), + // bilinear sampling. Check result to prevent crash when restoring depth buffer with SetRenderTarget if (bd->pd3dDevice->GetDepthStencilSurface(&bd->realDepthStencilBuffer) != D3D_OK) { bd->realDepthStencilBuffer = nullptr; @@ -156,24 +153,51 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) bd->pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); // Setup orthographic projection matrix - // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() + // Our visible imgui space lies from draw_data->DisplayPos (top left) to + // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. Being + // agnostic of whether or can be used, we aren't relying on + // D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or + // DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() { float L = draw_data->DisplayPos.x + 0.5f; float R = draw_data->DisplayPos.x + d3dSize.Width + 0.5f; float T = draw_data->DisplayPos.y + 0.5f; float B = draw_data->DisplayPos.y + d3dSize.Height + 0.5f; D3DMATRIX mat_identity = {{{ - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, }}}; D3DMATRIX mat_projection = {{{ - 2.0f / (R - L), 0.0f, 0.0f, 0.0f, - 0.0f, 2.0f / (T - B), 0.0f, 0.0f, - 0.0f, 0.0f, 0.5f, 0.0f, - (L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f, + 2.0f / (R - L), + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 2.0f / (T - B), + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 0.5f, + 0.0f, + (L + R) / (L - R), + (T + B) / (B - T), + 0.5f, + 1.0f, }}}; bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); @@ -181,12 +205,12 @@ void ImGui_ImplDX8_SetupRenderState(ImDrawData* draw_data) } } -void build_mask_vbuffer(const RECT* rect) +void build_mask_vbuffer(const RECT *rect) { - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); - CUSTOMVERTEX* vtx_dst{}; + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); + CUSTOMVERTEX *vtx_dst{}; // Check Lock result to prevent null pointer dereference - if (bd->maskVB->Lock(0, (UINT)(6 * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, 0) != D3D_OK) + if (bd->maskVB->Lock(0, (UINT)(6 * sizeof(CUSTOMVERTEX)), (BYTE **)&vtx_dst, 0) != D3D_OK) { return; } @@ -230,14 +254,14 @@ void build_mask_vbuffer(const RECT* rect) } // Render function. -void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) +void ImGui_ImplDX8_RenderDrawData(ImDrawData *draw_data) { // Avoid rendering when minimized if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; // Create and grow buffers if needed - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) { if (bd->pVB) @@ -246,7 +270,9 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) bd->pVB = nullptr; } bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; - if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB) < 0) + if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), + D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, + D3DPOOL_DEFAULT, &bd->pVB) < 0) return; } if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) @@ -257,19 +283,24 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) bd->pIB = nullptr; } bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; - if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB) < 0) + if (bd->pd3dDevice->CreateIndexBuffer( + bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, + sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB) < 0) return; } if (!bd->maskVB && !bd->maskIB) { - if (bd->pd3dDevice->CreateVertexBuffer(6 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->maskVB) < 0) + if (bd->pd3dDevice->CreateVertexBuffer(6 * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, + D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->maskVB) < 0) return; - if (bd->pd3dDevice->CreateIndexBuffer(6, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->maskIB) < 0) + if (bd->pd3dDevice->CreateIndexBuffer(6, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, + sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, + &bd->maskIB) < 0) return; - ImDrawIdx* idx_dst{}; + ImDrawIdx *idx_dst{}; // Check Lock result to prevent null pointer dereference - if (bd->maskIB->Lock(0, 6 * sizeof(ImDrawIdx), (BYTE**)&idx_dst, D3DLOCK_DISCARD) != D3D_OK) + if (bd->maskIB->Lock(0, 6 * sizeof(ImDrawIdx), (BYTE **)&idx_dst, D3DLOCK_DISCARD) != D3D_OK) { return; } @@ -299,14 +330,15 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); // Allocate buffers - CUSTOMVERTEX* vtx_dst{}; - ImDrawIdx* idx_dst{}; - if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (BYTE**)&vtx_dst, D3DLOCK_DISCARD) < 0) + CUSTOMVERTEX *vtx_dst{}; + ImDrawIdx *idx_dst{}; + if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (BYTE **)&vtx_dst, D3DLOCK_DISCARD) < + 0) { bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); return; } - if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (BYTE**)&idx_dst, D3DLOCK_DISCARD) < 0) + if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (BYTE **)&idx_dst, D3DLOCK_DISCARD) < 0) { bd->pVB->Unlock(); bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); @@ -316,8 +348,8 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) // Copy and convert all vertices into a single contiguous buffer, convert colors to DX8 default format. for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; + const ImDrawList *cmd_list = draw_data->CmdLists[n]; + const ImDrawVert *vtx_src = cmd_list->VtxBuffer.Data; for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { vtx_dst->pos[0] = vtx_src->pos.x; @@ -348,14 +380,15 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawList *cmd_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() - // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer + // to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplDX8_SetupRenderState(draw_data); else @@ -399,7 +432,8 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) bd->pd3dDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); bd->pd3dDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); bd->pd3dDevice->SetRenderState(D3DRS_STENCILREF, 0xFF); - bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3); + bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, (UINT)cmd_list->VtxBuffer.Size, + pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3); } } global_idx_offset += cmd_list->IdxBuffer.Size; @@ -422,16 +456,17 @@ void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data) bd->pd3dDevice->DeleteStateBlock(d3d8_state_block); } -bool ImGui_ImplDX8_Init(IDirect3DDevice8* device) +bool ImGui_ImplDX8_Init(IDirect3DDevice8 *device) { - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags - ImGui_ImplDX8_Data* bd = IM_NEW(ImGui_ImplDX8_Data)(); - io.BackendRendererUserData = (void*)bd; + ImGui_ImplDX8_Data *bd = IM_NEW(ImGui_ImplDX8_Data)(); + io.BackendRendererUserData = (void *)bd; io.BackendRendererName = "imgui_impl_dx8"; - io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing + // for large meshes. bd->pd3dDevice = device; bd->pd3dDevice->AddRef(); @@ -441,9 +476,9 @@ bool ImGui_ImplDX8_Init(IDirect3DDevice8* device) void ImGui_ImplDX8_Shutdown() { - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO &io = ImGui::GetIO(); ImGui_ImplDX8_InvalidateDeviceObjects(); if (bd->pd3dDevice) @@ -457,9 +492,9 @@ void ImGui_ImplDX8_Shutdown() bool ImGui_ImplDX8_CreateFontsTexture() { // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); - unsigned char* pixels; + ImGuiIO &io = ImGui::GetIO(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); + unsigned char *pixels; int width, height, bytes_per_pixel; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); @@ -467,22 +502,25 @@ bool ImGui_ImplDX8_CreateFontsTexture() #ifndef IMGUI_USE_BGRA_PACKED_COLOR if (io.Fonts->TexPixelsUseColors) { - ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); - for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) + ImU32 *dst_start = (ImU32 *)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); + for (ImU32 *src = (ImU32 *)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; + dst < dst_end; src++, dst++) *dst = IMGUI_COL_TO_DX8_ARGB(*src); - pixels = (unsigned char*)dst_start; + pixels = (unsigned char *)dst_start; } #endif // Upload texture to graphics system bd->FontTexture = nullptr; - if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture) < 0) + if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, + &bd->FontTexture) < 0) return false; D3DLOCKED_RECT tex_locked_rect; if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) return false; for (int y = 0; y < height; y++) - memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); + memcpy((unsigned char *)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, + pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); bd->FontTexture->UnlockRect(0); // Store our identifier @@ -498,17 +536,17 @@ bool ImGui_ImplDX8_CreateFontsTexture() bool ImGui_ImplD3D8_CreateDepthStencilBuffer() { - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); if (bd->pd3dDevice == nullptr) { return false; } if (bd->DepthBuffer == nullptr) { - IDirect3DSurface8* realDepth; + IDirect3DSurface8 *realDepth; D3DSURFACE_DESC sfcDesc; - if (bd->pd3dDevice->GetDepthStencilSurface(&realDepth) != D3D_OK || ! realDepth) + if (bd->pd3dDevice->GetDepthStencilSurface(&realDepth) != D3D_OK || !realDepth) { return false; } @@ -518,7 +556,8 @@ bool ImGui_ImplD3D8_CreateDepthStencilBuffer() } realDepth->Release(); realDepth = nullptr; - if (bd->pd3dDevice->CreateDepthStencilSurface(sfcDesc.Width, sfcDesc.Height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, &bd->DepthBuffer) != 0) + if (bd->pd3dDevice->CreateDepthStencilSurface(sfcDesc.Width, sfcDesc.Height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, + &bd->DepthBuffer) != 0) { return false; } @@ -529,7 +568,7 @@ bool ImGui_ImplD3D8_CreateDepthStencilBuffer() bool ImGui_ImplDX8_CreateDeviceObjects() { - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); if (!bd || !bd->pd3dDevice) return false; if (!ImGui_ImplDX8_CreateFontsTexture()) @@ -541,7 +580,7 @@ bool ImGui_ImplDX8_CreateDeviceObjects() void ImGui_ImplDX8_InvalidateDeviceObjects() { - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); if (!bd || !bd->pd3dDevice) return; if (bd->pVB) @@ -579,7 +618,7 @@ void ImGui_ImplDX8_InvalidateDeviceObjects() void ImGui_ImplDX8_NewFrame() { - ImGui_ImplDX8_Data* bd = ImGui_ImplDX8_GetBackendData(); + ImGui_ImplDX8_Data *bd = ImGui_ImplDX8_GetBackendData(); IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX8_Init()?"); if (!bd->FontTexture || !bd->DepthBuffer) diff --git a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h index 48d40cca260..b142abcf91c 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h @@ -1,5 +1,5 @@ /* -* The MIT License (MIT) + * The MIT License (MIT) * * Copyright (c) 2014 - 2025 Omar Cornut (Based on dx9 ImGui Backend) * Copyright (c) 2025 Meigyoku-Thmn and others @@ -36,25 +36,23 @@ // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. -// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. -// Learn about Dear ImGui: +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build +// the backends you need. Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq // - Getting Started https://dearimgui.com/getting-started // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp - - #pragma once -#include // IMGUI_IMPL_API +#include // IMGUI_IMPL_API struct IDirect3DDevice8; -IMGUI_IMPL_API bool ImGui_ImplDX8_Init(IDirect3DDevice8* device); -IMGUI_IMPL_API void ImGui_ImplDX8_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplDX8_NewFrame(); -IMGUI_IMPL_API void ImGui_ImplDX8_RenderDrawData(ImDrawData* draw_data); +IMGUI_IMPL_API bool ImGui_ImplDX8_Init(IDirect3DDevice8 *device); +IMGUI_IMPL_API void ImGui_ImplDX8_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplDX8_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplDX8_RenderDrawData(ImDrawData *draw_data); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API bool ImGui_ImplDX8_CreateDeviceObjects(); -IMGUI_IMPL_API void ImGui_ImplDX8_InvalidateDeviceObjects(); +IMGUI_IMPL_API bool ImGui_ImplDX8_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplDX8_InvalidateDeviceObjects(); diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index c39a241992a..03ae1225149 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -22,20 +22,17 @@ #pragma once - -namespace ImGui { +namespace ImGui +{ class FrameManager { -public: + public: static void BeginFrame(); static void EndFrame(); // Includes Render() -private: + private: static bool s_frameOpen; }; -} // namespace ImGui - - - +} // namespace ImGui From eb90ad16589870985d0f9b7df352cdf1bfbe08ca Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 16:34:51 +0100 Subject: [PATCH 49/50] Fix minor style and functional issues --- .../Source/ImGui/wrapper/ImGuiFrameManager.cpp | 14 +++++--------- .../Source/ImGui/wrapper/ImGuiFrameManager.h | 14 +++++++++----- .../GameEngine/Source/GameClient/GameClient.cpp | 15 +++++---------- .../Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 +- Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp | 10 +++------- .../GameEngine/Source/GameClient/GameClient.cpp | 15 +++++---------- .../Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 +- .../Code/Tools/WorldBuilder/src/wbview3d.cpp | 8 +++----- 8 files changed, 32 insertions(+), 48 deletions(-) diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp index bf98a968ace..6d9dbf95cef 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp @@ -1,7 +1,3 @@ -/** - * @file ImGuiFrameManager.cpp - * @brief Simple Frame manager for ImGui widgets - */ /* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2026 TheSuperHackers @@ -24,9 +20,9 @@ #include "imgui_impl_dx8.h" #include "imgui_impl_win32.h" -bool ImGui::FrameManager::s_frameOpen = false; +bool rts::ImGui::FrameManager::s_frameOpen = false; -void ImGui::FrameManager::BeginFrame() +void rts::ImGui::FrameManager::BeginFrame() { if (s_frameOpen) { @@ -35,19 +31,19 @@ void ImGui::FrameManager::BeginFrame() ImGui_ImplDX8_NewFrame(); ImGui_ImplWin32_NewFrame(); - NewFrame(); + ::ImGui::NewFrame(); s_frameOpen = true; } -void ImGui::FrameManager::EndFrame() +void rts::ImGui::FrameManager::EndFrame() { if (!s_frameOpen) { return; } - Render(); + ::ImGui::Render(); s_frameOpen = false; } diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index 03ae1225149..40f84ae1747 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -1,7 +1,3 @@ -/** - * @file ImGuiFrameManager.h - * @brief Simple Frame manager for ImGui widgets - */ /* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2026 TheSuperHackers @@ -22,6 +18,8 @@ #pragma once +namespace rts +{ namespace ImGui { @@ -29,10 +27,16 @@ class FrameManager { public: static void BeginFrame(); - static void EndFrame(); // Includes Render() + // TheSuperHackers @info jurassicLizard 27/01/2026 The following static function + // calls ImGui::EndFrame() and ImGui::Render() but does NOT call + // ImGui::RenderDrawData(draw_data). The latter is not part of this wrapper + // by design (separation of concerns) and must be called explicitly. This is to be done + // when sending draw data off to the GPU to be drawn on screen, which in our case happens in DX8Wrapper::End_Scene() + static void EndFrame(); private: static bool s_frameOpen; }; } // namespace ImGui +} // namespace rts \ No newline at end of file diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index adf577c1d3a..01ba47a31db 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -488,19 +488,14 @@ void GameClient::registerDrawable( Drawable *draw ) /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) DECLARE_PERF_TIMER(GameClient_update) DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::BeginFrame(); - // Draw ImGui Demo Window - { - ImGui::ShowDemoWindow(); - } + rts::ImGui::FrameManager::BeginFrame(); + ImGui::ShowDemoWindow(); #endif // create the FRAME_TICK message GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK ); @@ -595,7 +590,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameManager::EndFrame(); #endif // redraw all views, update the GUI TheDisplay->DRAW(); @@ -706,7 +701,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameManager::EndFrame(); #endif return; } @@ -732,7 +727,7 @@ void GameClient::update( void ) } #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameManager::EndFrame(); #endif { USE_PERF_TIMER(GameClient_draw) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 7873c0f9008..5135cdef4bb 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -605,7 +605,7 @@ bool DX8Wrapper::Create_Device(void) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Dark Style ImGui::StyleColorsDark(); diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp index d063bfa4b21..5f4fa2f99b0 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -2006,18 +2006,14 @@ void WbView3d::redraw(void) } // ---------------------------------------------------------------------------- -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) void WbView3d::render() { ++m_updateCount; #ifdef RTS_HAS_IMGUI - { - ImGui::FrameManager::BeginFrame(); - ImGui::ShowDemoWindow(); - ImGui::FrameManager::EndFrame(); - } + rts::ImGui::FrameManager::BeginFrame(); + ImGui::ShowDemoWindow(); + rts::ImGui::FrameManager::EndFrame(); #endif if (WW3D::Begin_Render(true,true,Vector3(0.5f,0.5f,0.5f), TheWaterTransparency->m_minWaterOpacity) == WW3D_ERROR_OK) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index b1b0a34397f..10bc58c2e57 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -511,19 +511,14 @@ void GameClient::registerDrawable( Drawable *draw ) /** ----------------------------------------------------------------------------------------------- * Redraw all views, update the GUI, play sound effects, etc. */ -// TheSuperHackers @feature jurassiclizard 16/01/2026 imgui integration (PR#2127) -// see details under WinMain.cpp (WndProc()) DECLARE_PERF_TIMER(GameClient_update) DECLARE_PERF_TIMER(GameClient_draw) void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::BeginFrame(); - // Draw ImGui Demo Window - { - ImGui::ShowDemoWindow(); - } + rts::ImGui::FrameManager::BeginFrame(); + ImGui::ShowDemoWindow(); #endif // create the FRAME_TICK message GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK ); @@ -635,7 +630,7 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameManager::EndFrame(); #endif // redraw all views, update the GUI TheDisplay->DRAW(); @@ -747,7 +742,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameManager::EndFrame(); #endif return; } @@ -774,7 +769,7 @@ void GameClient::update( void ) #ifdef RTS_HAS_IMGUI - ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameManager::EndFrame(); #endif { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 29fac177c05..8ab66487551 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -653,7 +653,7 @@ bool DX8Wrapper::Create_Device(void) ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Dark Style ImGui::StyleColorsDark(); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index cda001335bc..92cc463194b 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -2090,11 +2090,9 @@ void WbView3d::render() ++m_updateCount; #ifdef RTS_HAS_IMGUI - { - ImGui::FrameManager::BeginFrame(); - ImGui::ShowDemoWindow(); - ImGui::FrameManager::EndFrame(); - } + rts::ImGui::FrameManager::BeginFrame(); + ImGui::ShowDemoWindow(); + rts::ImGui::FrameManager::EndFrame(); #endif if (WW3D::Begin_Render(true,true,Vector3(0.5f,0.5f,0.5f), TheWaterTransparency->m_minWaterOpacity) == WW3D_ERROR_OK) From bc453caaac0aee8f5f885561706f0b30604cff8a Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 17:01:48 +0100 Subject: [PATCH 50/50] remove conditional build on Debug only modes --- Core/Libraries/Source/ImGui/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index e29db8aa60d..736cf6a4ef7 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -34,11 +34,6 @@ set(IMGUI_INCLUDE_DIRS # start target build section # we currently have a hard dependency on dx8 and win32 api if (WIN32) - # for now we only need it in debug configurations - if ( NOT ( (CMAKE_BUILD_TYPE STREQUAL "Debug") OR RTS_BUILD_OPTION_DEBUG ) ) - MESSAGE(FATAL_ERROR "ImGui is currently only available in Debug build modes") - endif () - MESSAGE(STATUS "Enabling ImGui") add_library(lib_imgui STATIC ${IMGUI_WIN32_DX8_ALL_SRCS}