From a6b3e21099365a753d2e2c26b0cc727a94b67e83 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 15 Jan 2026 14:55:24 +0100 Subject: [PATCH 01/60] 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 7c1269d1db9..d94df1c91d0 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -25,6 +25,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 50636fc397f..c876cee902d 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 1c6c5e8e9d1..78eb63be635 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" @@ -511,6 +519,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() ); @@ -623,6 +641,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; } @@ -728,6 +749,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 @@ -751,6 +775,11 @@ void GameClient::update( void ) TheDisplay->UPDATE(); } + +#ifdef RTS_IMGUI_ENABLED + ImGui::Render(); // Prepare render data +#endif + { USE_PERF_TIMER(GameClient_draw) @@ -758,6 +787,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 fbb5b41b304a9b6896e62039a5cf8ffabf08e25a Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 15 Jan 2026 20:43:00 +0100 Subject: [PATCH 02/60] 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 d94df1c91d0..06a879afd40 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -25,8 +25,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 c876cee902d..50636fc397f 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 78eb63be635..1bb5c2c47a2 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" @@ -523,9 +522,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 723a818065b135b92bec436a2bb08065c5cc1505 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 10:52:24 +0100 Subject: [PATCH 03/60] 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 1bb5c2c47a2..ca946f83cf3 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -636,12 +636,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 bb5b0b87e2d227c0b0a573578c4563d585c757ab Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 10:53:26 +0100 Subject: [PATCH 04/60] 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 fdd99b09a48e3a4861f58ebad50e5b7acbcac9eb Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 12:06:13 +0100 Subject: [PATCH 05/60] 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 8b7d906e47a130921789e678602d4358e3eb727c Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 14:10:14 +0100 Subject: [PATCH 06/60] 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 0baa0b73f6dc5f404e68a72328f33341ca692ecd Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 14:52:58 +0100 Subject: [PATCH 07/60] 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 a4b304949d1..9bc595ec067 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 @@ -490,6 +495,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() ); @@ -582,6 +596,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(); @@ -690,6 +707,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 @@ -713,6 +733,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 1fc3ef5433c84b970e049fdc2c9cb05a40d1b8b0 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 14:55:17 +0100 Subject: [PATCH 08/60] 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 9d7e57180c0a2e3f1ee13a7a8d081e3a296bb6a1 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 16:01:18 +0100 Subject: [PATCH 09/60] 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 9bc595ec067..bf2d8859221 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -487,6 +487,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. */ @@ -495,6 +504,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(); @@ -596,6 +607,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 @@ -707,6 +720,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 @@ -733,6 +749,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 ca946f83cf3..e5dc414498a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -510,6 +510,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. */ @@ -518,6 +527,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(); @@ -636,6 +647,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 @@ -748,6 +761,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 @@ -775,6 +791,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 3d91be90ff7e7bee47e045b2e9db56684259a467 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 16:39:49 +0100 Subject: [PATCH 10/60] 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 f8b1e74bda60b1ecefe9c581b5be49ab5f524752 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 16:47:41 +0100 Subject: [PATCH 11/60] 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 5edeb4f27a9f7c95aa06ea31fc51e0abf4b57cfa Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 17:07:54 +0100 Subject: [PATCH 12/60] 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 2ddf162b3ed3b5ce69d242829e9fe354efdf5d1d Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 17:21:31 +0100 Subject: [PATCH 13/60] 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 8b4dede4b1d25189c1c67686de3c9c00984185a4 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Fri, 16 Jan 2026 19:24:13 +0100 Subject: [PATCH 14/60] 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 a62f923f9d33850c77d29e2baba3aacc145d747a Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 19 Jan 2026 10:49:30 +0100 Subject: [PATCH 15/60] 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 ccc8397f299985bbfb68651486a2100a9bc787c0 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 19 Jan 2026 10:51:57 +0100 Subject: [PATCH 16/60] 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 969eaee8c7aa76fcb41a78b0aba38cebb4f84c69 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 09:53:05 +0100 Subject: [PATCH 17/60] 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 93e0ac75b0ab615c3069add15f85017dac4f4d2b Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 09:54:56 +0100 Subject: [PATCH 18/60] 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 85f8c8afeb5caf85e509a1bd2d1cdf2cd78164cc Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 10:58:32 +0100 Subject: [PATCH 19/60] 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 bf2d8859221..bea04af9687 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" @@ -506,7 +506,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(); @@ -609,7 +609,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 @@ -723,7 +723,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; @@ -751,7 +751,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 e5dc414498a..dedfa6a7fb9 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" @@ -529,7 +529,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(); @@ -649,7 +649,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 @@ -764,7 +764,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; @@ -793,7 +793,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 4e83737cf733babafcb05bbb022d7716851cd357 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 11:29:14 +0100 Subject: [PATCH 20/60] 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 dedfa6a7fb9..b9c8f5d11b7 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -804,8 +804,6 @@ void GameClient::update( void ) //if(TheGameLogic->getFrame() >= 2) TheDisplay->DRAW(); - - } { From 2b26d77fa7c56bf362556ffa3801818298a01510 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 11:34:52 +0100 Subject: [PATCH 21/60] 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 8c871263e68fb7554f13f3941ee15c6d1ff0236c Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 11:36:32 +0100 Subject: [PATCH 22/60] 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 1dea931dd415f0ab43003ddfec286f7a03f76709 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 12:10:10 +0100 Subject: [PATCH 23/60] 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 bea04af9687..0db84c323e9 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -487,15 +487,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. */ @@ -505,7 +496,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(); @@ -608,7 +599,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 @@ -722,7 +713,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 @@ -750,7 +741,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 b9c8f5d11b7..f30428c2649 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -510,15 +510,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. */ @@ -528,7 +519,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(); @@ -648,7 +639,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 @@ -763,7 +754,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 @@ -792,7 +783,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 8f2dd3b3b8a7ecead0fee22e862f4c0ec08860ab Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 12:26:24 +0100 Subject: [PATCH 24/60] 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 6cb1cce8e6d676b3a085c070e73c2b77cd63e420 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 12:45:31 +0100 Subject: [PATCH 25/60] 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 06a879afd40..0335c0fb4de 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -26,10 +26,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 85838bb94d6..bf361118483 100644 --- a/Generals/Code/CMakeLists.txt +++ b/Generals/Code/CMakeLists.txt @@ -21,6 +21,10 @@ target_link_libraries(gi_gameengine_include INTERFACE target_link_libraries(gi_always INTERFACE 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 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 a713dcc7c2b..1623c01d4e6 100644 --- a/GeneralsMD/Code/CMakeLists.txt +++ b/GeneralsMD/Code/CMakeLists.txt @@ -21,6 +21,10 @@ target_link_libraries(zi_gameengine_include INTERFACE target_link_libraries(zi_always INTERFACE 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 corei_always_no_pch # Must stay below so headers from game are included first ) From 2f400bc9f7bc0d9d8f3cc6496a860725e4053fb0 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 13:01:39 +0100 Subject: [PATCH 26/60] 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 86450c2d502bad4236a775b168edb037fc358041 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 14:08:19 +0100 Subject: [PATCH 27/60] 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 359a7045409df272818207348ac41c371cc46053 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 14:54:19 +0100 Subject: [PATCH 28/60] 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 c7237bc06ac1496d3f1e3b731a8fe3b8b5fe9e32 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:15:00 +0100 Subject: [PATCH 29/60] 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 cb5d1fddc6aeec6a45908f0e3d9458efc1f48d62 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:27:34 +0100 Subject: [PATCH 30/60] 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 5ead1e53511ad3898fc744950f985e14b4d11a3f Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:28:37 +0100 Subject: [PATCH 31/60] 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 3e3fac8d8750da997fd6ec15457cba514b1ba0bd Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 15:49:17 +0100 Subject: [PATCH 32/60] 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 0db84c323e9..d61a559e398 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -490,13 +490,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(); @@ -598,8 +598,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 @@ -711,9 +709,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 @@ -740,8 +735,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 f30428c2649..861e3ec4c5c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -513,13 +513,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(); @@ -638,8 +638,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 @@ -752,9 +750,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 @@ -782,8 +777,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 38ce93310c18383426c48fcfe55728d5fadd4951 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 16:00:42 +0100 Subject: [PATCH 33/60] 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 e473a09421acb27a7d0f48236a9ebd471c307094 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 20 Jan 2026 21:21:28 +0100 Subject: [PATCH 34/60] 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 d61a559e398..cf8f4ed289e 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 @@ -498,9 +497,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(); @@ -599,7 +596,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(); @@ -710,7 +707,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGui::Render(); + ImGuiFrameManager::EndFrame(); #endif return; } @@ -736,7 +733,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 7508a17af66..3c3b8b8169b 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 861e3ec4c5c..1d5c588bf83 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 @@ -521,9 +520,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(); @@ -639,7 +636,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(); @@ -751,7 +748,7 @@ void GameClient::update( void ) if (TheGlobalData->m_noDraw > TheGameLogic->getFrame() && TheGameLogic->getFrame() > 0) { #ifdef RTS_HAS_IMGUI - ImGui::Render(); + ImGuiFrameManager::EndFrame(); #endif return; } @@ -778,7 +775,7 @@ void GameClient::update( void ) #ifdef RTS_HAS_IMGUI - ImGui::Render(); // Prepare render data + ImGuiFrameManager::EndFrame(); #endif { From 3e615104459a8f74765ea335f32dee3f91f83aa7 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Wed, 21 Jan 2026 13:31:48 +0100 Subject: [PATCH 35/60] 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 cf8f4ed289e..3365e8cf19e 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -497,7 +497,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(); @@ -596,7 +596,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(); @@ -707,7 +707,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; } @@ -733,7 +733,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 3c3b8b8169b..f6ea11e8a5e 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 1d5c588bf83..62781249ee6 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -520,7 +520,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(); @@ -636,7 +636,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(); @@ -748,7 +748,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; } @@ -775,7 +775,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 91d6c315ec0..ea373be30e1 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 ea6264af3edfe1c18916da34b0e1f59048e7663f Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Wed, 21 Jan 2026 17:31:08 +0100 Subject: [PATCH 36/60] 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 c406ff714c56bc654c446dceb32d356ea3deac60 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 22 Jan 2026 15:46:29 +0100 Subject: [PATCH 37/60] 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 9680c785d3cd7ade2a99e984ca821f60b2296db7 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 11:46:59 +0100 Subject: [PATCH 38/60] 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 bf361118483..85838bb94d6 100644 --- a/Generals/Code/CMakeLists.txt +++ b/Generals/Code/CMakeLists.txt @@ -21,10 +21,6 @@ target_link_libraries(gi_gameengine_include INTERFACE target_link_libraries(gi_always INTERFACE 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 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 217d7dcecba..a5b67f4f04d 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 1623c01d4e6..a713dcc7c2b 100644 --- a/GeneralsMD/Code/CMakeLists.txt +++ b/GeneralsMD/Code/CMakeLists.txt @@ -21,10 +21,6 @@ target_link_libraries(zi_gameengine_include INTERFACE target_link_libraries(zi_always INTERFACE 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 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 d6990fc097c..deca0b46ae7 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 0dde4001b0a72671823ddc84336426b07710387f Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:20:19 +0100 Subject: [PATCH 39/60] 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 d3fee46d83531ca7953e1b5d6f65323fc0636897 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:26:24 +0100 Subject: [PATCH 40/60] 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 d89458e2de45426ca3347e50c1cabaa579de71fa Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:31:54 +0100 Subject: [PATCH 41/60] 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 72ae8e7c3c4df11b0f266a8ecf5b4561ed34a368 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:35:16 +0100 Subject: [PATCH 42/60] 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 88d0ea5849082378fb2edd7a0e2bdaba3d3ff631 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:38:04 +0100 Subject: [PATCH 43/60] 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 ba687b7fd20c09038060555624152be39eafedd7 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:41:05 +0100 Subject: [PATCH 44/60] 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 30c0b2a3c74c77f2c2ff3eb3f4e601d587a4bb77 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 12:43:57 +0100 Subject: [PATCH 45/60] 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 f6ea11e8a5e..f6d07cb465d 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 ea373be30e1..e7963fb767f 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 0cc678bccbc15790e76ed2f4382436eb01cb8fac Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Mon, 26 Jan 2026 13:40:43 +0100 Subject: [PATCH 46/60] 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 a5b67f4f04d..216b3d1a266 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 deca0b46ae7..03058222473 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 fb220b96167e9be4fe07225b71f6c8794811c0ee Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 14:14:12 +0100 Subject: [PATCH 47/60] 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 7c00995fb6089b399f0d05aeb96495c00816ee63 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 14:30:47 +0100 Subject: [PATCH 48/60] 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 54af2b1b56c5e7a927a97991919a577a8532f06d Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 16:34:51 +0100 Subject: [PATCH 49/60] 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 3365e8cf19e..f4788b9d4ab 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -489,19 +489,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 ); @@ -596,7 +591,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(); @@ -707,7 +702,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; } @@ -733,7 +728,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 f6d07cb465d..9e910529a1b 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 62781249ee6..612eb3c7654 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -512,19 +512,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 ); @@ -636,7 +631,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(); @@ -748,7 +743,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; } @@ -775,7 +770,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 e7963fb767f..128a193d751 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 eb5f3f1a8ec1bb8c8485f1cf9ee1697f5874ca38 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Tue, 27 Jan 2026 17:01:48 +0100 Subject: [PATCH 50/60] 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} From 992acc7863ef75047487496781266446f7868097 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 29 Jan 2026 15:48:07 +0100 Subject: [PATCH 51/60] fix various style issues --- Core/CMakeLists.txt | 1 - Core/Libraries/Source/ImGui/CMakeLists.txt | 2 +- .../Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp | 8 +------- Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h | 5 ----- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 3 --- Generals/Code/Main/WinMain.cpp | 2 +- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 3 +-- GeneralsMD/Code/Main/WinMain.cpp | 2 +- GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h | 2 +- 9 files changed, 6 insertions(+), 22 deletions(-) diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 0335c0fb4de..7c1269d1db9 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -26,7 +26,6 @@ target_link_libraries(corei_always INTERFACE corei_libraries_include resources ) - target_link_libraries(corei_always_no_pch INTERFACE core_config core_utility_no_pch diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index 736cf6a4ef7..e1c3e7b460e 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -39,6 +39,7 @@ if (WIN32) 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") @@ -54,4 +55,3 @@ else () # currently only WIN32 DX is supported MESSAGE(FATAL_ERROR "Non-Windows platforms currently not supported for ImGui") 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 index accaec963c4..3ff5b1ab9e5 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.cpp @@ -24,11 +24,6 @@ * 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) @@ -332,8 +327,7 @@ 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; 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 b142abcf91c..6ca3de94582 100644 --- a/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h +++ b/Core/Libraries/Source/ImGui/dx8_backend/imgui_impl_dx8.h @@ -23,11 +23,6 @@ * 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) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 5135cdef4bb..023520edecb 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -268,8 +268,6 @@ 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); @@ -606,7 +604,6 @@ bool DX8Wrapper::Create_Device(void) ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - // Dark Style ImGui::StyleColorsDark(); ImGui_ImplWin32_Init(_Hwnd); diff --git a/Generals/Code/Main/WinMain.cpp b/Generals/Code/Main/WinMain.cpp index 133778b2ff8..746efdeb8d5 100644 --- a/Generals/Code/Main/WinMain.cpp +++ b/Generals/Code/Main/WinMain.cpp @@ -309,7 +309,7 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, { #ifdef RTS_HAS_IMGUI if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) { - return true; + return 1; } #endif try diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 8ab66487551..4c0421a0ae6 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -429,7 +429,6 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) ShatterSystem::Init(); TextureLoader::Init(); - Set_Default_Global_Render_States(); } @@ -532,6 +531,7 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) } + bool DX8Wrapper::Create_Device(void) { WWASSERT(D3DDevice==nullptr); // for now, once you've created a device, you're stuck with it! @@ -654,7 +654,6 @@ bool DX8Wrapper::Create_Device(void) ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - // Dark Style ImGui::StyleColorsDark(); ImGui_ImplWin32_Init(_Hwnd); diff --git a/GeneralsMD/Code/Main/WinMain.cpp b/GeneralsMD/Code/Main/WinMain.cpp index 13102929933..e50f359e421 100644 --- a/GeneralsMD/Code/Main/WinMain.cpp +++ b/GeneralsMD/Code/Main/WinMain.cpp @@ -315,7 +315,7 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT message, { #ifdef RTS_HAS_IMGUI if (ImGui_ImplWin32_WndProcHandler(hWnd, message, wParam, lParam)) { - return true; + return 1; } #endif try diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h index 54b83328218..1ca09b5a89f 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h @@ -80,7 +80,7 @@ class WbView3d : public WbView, public DX8_CleanupHook //}}AFX_VIRTUAL #ifdef RTS_HAS_IMGUI -// Function overrides needed for ImGui Mouse capture + // Function overrides needed for ImGui Mouse capture virtual BOOL PreTranslateMessage(MSG* pMsg); virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); #endif From 4c4cd7933be8600b4b7a20ca1fcbf65441a57ac4 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 29 Jan 2026 16:37:38 +0100 Subject: [PATCH 52/60] modify handling of frame management in ZH --- .../Source/ImGui/wrapper/ImGuiFrameManager.cpp | 6 ++++++ .../Source/ImGui/wrapper/ImGuiFrameManager.h | 1 + .../Source/GameClient/GameClient.cpp | 18 +++++++++++------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 14 ++++++-------- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp index 6d9dbf95cef..793a84a11d0 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp @@ -45,5 +45,11 @@ void rts::ImGui::FrameManager::EndFrame() ::ImGui::Render(); + ImDrawData* data = ::ImGui::GetDrawData(); + if (data && data->CmdListsCount >0) + { + ImGui_ImplDX8_RenderDrawData(data); + } + s_frameOpen = false; } diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index 40f84ae1747..1ab0ee392f2 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -38,5 +38,6 @@ class FrameManager static bool s_frameOpen; }; + } // namespace ImGui } // namespace rts \ 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 612eb3c7654..ab9dc60e449 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -519,7 +519,11 @@ void GameClient::update( void ) USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI rts::ImGui::FrameManager::BeginFrame(); - ImGui::ShowDemoWindow(); + static bool show_demo = true; + if (show_demo) + { + ImGui::ShowDemoWindow(&show_demo); + } #endif // create the FRAME_TICK message GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK ); @@ -630,13 +634,13 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { -#ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::EndFrame(); -#endif // redraw all views, update the GUI TheDisplay->DRAW(); TheDisplay->UPDATE(); +#ifdef RTS_HAS_IMGUI + rts::ImGui::FrameManager::EndFrame(); +#endif return; } @@ -769,9 +773,6 @@ void GameClient::update( void ) } -#ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::EndFrame(); -#endif { USE_PERF_TIMER(GameClient_draw) @@ -796,6 +797,9 @@ void GameClient::update( void ) // update the in game UI TheInGameUI->UPDATE(); } +#ifdef RTS_HAS_IMGUI + rts::ImGui::FrameManager::EndFrame(); +#endif } void GameClient::step() diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 4c0421a0ae6..9e7923c184e 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -91,6 +91,7 @@ #include "imgui.h" #include #include "imgui_impl_dx8.h" +#include #endif const int DEFAULT_RESOLUTION_WIDTH = 640; @@ -1744,6 +1745,9 @@ void DX8Wrapper::Begin_Scene(void) { DX8_THREAD_ASSERT(); +#ifdef RTS_HAS_IMGUI + rts::ImGui::FrameManager::BeginFrame(); +#endif #if ENABLE_EMBEDDED_BROWSER DX8WebBrowser::Update(); #endif @@ -1756,14 +1760,8 @@ void DX8Wrapper::Begin_Scene(void) void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); -#ifdef RTS_HAS_IMGUI - { - ImDrawData* data = ImGui::GetDrawData(); - if (data && data->CmdListsCount > 0 ) { - ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); - } - } -#endif + + rts::ImGui::FrameManager::EndFrame(); DX8CALL(EndScene()); DX8WebBrowser::Render(0); From 823901bed9777dfe07006c445f719bcdaeae8916 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 29 Jan 2026 17:05:28 +0100 Subject: [PATCH 53/60] simplify frame management and apply changes to GeneralsV --- .../Source/ImGui/wrapper/ImGuiFrameManager.h | 15 +++++++++++++++ .../GameEngine/Source/GameClient/GameClient.cpp | 17 ++++++----------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 13 +++++++------ .../Code/Tools/WorldBuilder/src/wbview3d.cpp | 8 +++++--- .../GameEngine/Source/GameClient/GameClient.cpp | 11 +---------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 3 +++ .../Code/Tools/WorldBuilder/src/wbview3d.cpp | 8 +++++--- 7 files changed, 42 insertions(+), 33 deletions(-) diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index 1ab0ee392f2..4d9a20d2d26 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -38,6 +38,21 @@ class FrameManager static bool s_frameOpen; }; +class FrameGuard { +public: + FrameGuard() { + FrameManager::BeginFrame(); + } + ~FrameGuard() { + FrameManager::EndFrame(); + } + +// TODO change this to rule of 5 and use delete instead of declaring without definition once +// we are using a C++11 or higher C++ Standard +private: + FrameGuard(const FrameGuard&); + FrameGuard& operator=(const FrameGuard&); +}; } // 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 f4788b9d4ab..514ae8aae2f 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -495,8 +495,12 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::BeginFrame(); - ImGui::ShowDemoWindow(); + rts::ImGui::FrameGuard frame_guard; + static bool show_demo = true; + if (show_demo) + { + ImGui::ShowDemoWindow(&show_demo); + } #endif // create the FRAME_TICK message GameMessage *frameMsg = TheMessageStream->appendMessage( GameMessage::MSG_FRAME_TICK ); @@ -590,9 +594,6 @@ void GameClient::update( void ) if(TheGlobalData->m_playIntro || TheGlobalData->m_afterIntro) { -#ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::EndFrame(); -#endif // redraw all views, update the GUI TheDisplay->DRAW(); TheDisplay->UPDATE(); @@ -701,9 +702,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) { -#ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::EndFrame(); -#endif return; } #endif @@ -727,9 +725,6 @@ void GameClient::update( void ) TheDisplay->UPDATE(); } -#ifdef RTS_HAS_IMGUI - 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 023520edecb..efef322a7ee 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -86,6 +86,7 @@ #include "imgui.h" #include "imgui_impl_dx8.h" #include "imgui_impl_win32.h" +#include "ImGuiFrameManager.h" #endif @@ -1612,6 +1613,9 @@ void DX8Wrapper::Begin_Scene(void) { DX8_THREAD_ASSERT(); +#if RTS_HAS_IMGUI + rts::ImGui::FrameManager::BeginFrame(); +#endif #if ENABLE_EMBEDDED_BROWSER DX8WebBrowser::Update(); #endif @@ -1624,14 +1628,11 @@ void DX8Wrapper::Begin_Scene(void) void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); + #ifdef RTS_HAS_IMGUI - { - ImDrawData* data = ImGui::GetDrawData(); - if (data && data->CmdListsCount > 0) { - ImGui_ImplDX8_RenderDrawData(ImGui::GetDrawData()); - } - } + rts::ImGui::FrameManager::EndFrame(); #endif + DX8CALL(EndScene()); DX8WebBrowser::Render(0); diff --git a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp index 9e910529a1b..c0626faee9b 100644 --- a/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -2011,9 +2011,11 @@ void WbView3d::render() ++m_updateCount; #ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::BeginFrame(); - ImGui::ShowDemoWindow(); - rts::ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameGuard frame_guard; + static bool show_demo = true; + if (show_demo) { + ImGui::ShowDemoWindow(&show_demo); + } #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 ab9dc60e449..a963d74fb9b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -518,7 +518,7 @@ void GameClient::update( void ) { USE_PERF_TIMER(GameClient_update) #ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::BeginFrame(); + rts::ImGui::FrameGuard frame_guard; static bool show_demo = true; if (show_demo) { @@ -638,9 +638,6 @@ void GameClient::update( void ) TheDisplay->DRAW(); TheDisplay->UPDATE(); -#ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::EndFrame(); -#endif return; } @@ -746,9 +743,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) { -#ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::EndFrame(); -#endif return; } #endif @@ -797,9 +791,6 @@ void GameClient::update( void ) // update the in game UI TheInGameUI->UPDATE(); } -#ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::EndFrame(); -#endif } void GameClient::step() diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 9e7923c184e..5f884f5716c 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1761,7 +1761,10 @@ void DX8Wrapper::End_Scene(bool flip_frames) { DX8_THREAD_ASSERT(); +#ifdef RTS_HAS_IMGUI rts::ImGui::FrameManager::EndFrame(); +#endif + DX8CALL(EndScene()); DX8WebBrowser::Render(0); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp index 128a193d751..b4562ac9f82 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/wbview3d.cpp @@ -2090,9 +2090,11 @@ void WbView3d::render() ++m_updateCount; #ifdef RTS_HAS_IMGUI - rts::ImGui::FrameManager::BeginFrame(); - ImGui::ShowDemoWindow(); - rts::ImGui::FrameManager::EndFrame(); + rts::ImGui::FrameGuard frame_guard; + static bool show_demo = true; + if (show_demo) { + ImGui::ShowDemoWindow(&show_demo); + } #endif if (WW3D::Begin_Render(true,true,Vector3(0.5f,0.5f,0.5f), TheWaterTransparency->m_minWaterOpacity) == WW3D_ERROR_OK) From 3fc6c4f84622daab3ca18cc2686acab0d1b0cb88 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 29 Jan 2026 17:47:23 +0100 Subject: [PATCH 54/60] simplify imgui context management via self-contained class --- Core/Libraries/Source/ImGui/CMakeLists.txt | 1 + .../ImGui/wrapper/ImGuiContextManager.cpp | 58 +++++++++++++++++++ .../ImGui/wrapper/ImGuiContextManager.h | 44 ++++++++++++++ .../ImGui/wrapper/ImGuiFrameManager.cpp | 4 +- .../Source/ImGui/wrapper/ImGuiFrameManager.h | 28 ++++----- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 20 ++----- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 20 ++----- 7 files changed, 125 insertions(+), 50 deletions(-) create mode 100644 Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.cpp create mode 100644 Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.h diff --git a/Core/Libraries/Source/ImGui/CMakeLists.txt b/Core/Libraries/Source/ImGui/CMakeLists.txt index e1c3e7b460e..504ebc2159c 100644 --- a/Core/Libraries/Source/ImGui/CMakeLists.txt +++ b/Core/Libraries/Source/ImGui/CMakeLists.txt @@ -38,6 +38,7 @@ if (WIN32) add_library(lib_imgui STATIC ${IMGUI_WIN32_DX8_ALL_SRCS} "${CMAKE_CURRENT_LIST_DIR}/wrapper/ImGuiFrameManager.cpp" + "${CMAKE_CURRENT_LIST_DIR}/wrapper/ImGuiContextManager.cpp" ) target_include_directories(lib_imgui diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.cpp new file mode 100644 index 00000000000..30e5524d6f2 --- /dev/null +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.cpp @@ -0,0 +1,58 @@ +/* +** 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 "ImGuiContextManager.h" +#include "imgui.h" +#include "imgui_impl_dx8.h" +#include "imgui_impl_win32.h" +#include +#include + +rts::ImGui::ContextManager::ContextManager() : m_initialized(false) {} + +rts::ImGui::ContextManager::~ContextManager() +{ + if (m_initialized) + { + ImGui_ImplDX8_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ::ImGui::DestroyContext(); + } +} + +void rts::ImGui::ContextManager::Init(void *hwnd, void *device) +{ + if (m_initialized) + { + return; + } + + ::IMGUI_CHECKVERSION(); + ::ImGui::CreateContext(); + ImGuiIO &io = ::ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; + + ::ImGui::StyleColorsDark(); + + ImGui_ImplWin32_Init(static_cast(hwnd)); + ImGui_ImplDX8_Init(static_cast(device)); + + io.Fonts->AddFontDefault(); + + m_initialized = true; +} diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.h new file mode 100644 index 00000000000..1d112fdb4e1 --- /dev/null +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiContextManager.h @@ -0,0 +1,44 @@ +/* +** 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 + +namespace rts +{ +namespace ImGui +{ + +class ContextManager +{ + public: + ContextManager(); + ~ContextManager(); + + void Init(void *hwnd, void *device); + + private: + bool m_initialized; + + // TODO change this to rule of 5 and use delete instead of declaring without + // definition once we are using a C++11 or higher C++ Standard + ContextManager(const ContextManager &); + ContextManager &operator=(const ContextManager &); +}; + +} // namespace ImGui +} // namespace rts diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp index 793a84a11d0..59fc8c767ff 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.cpp @@ -45,8 +45,8 @@ void rts::ImGui::FrameManager::EndFrame() ::ImGui::Render(); - ImDrawData* data = ::ImGui::GetDrawData(); - if (data && data->CmdListsCount >0) + ImDrawData *data = ::ImGui::GetDrawData(); + if (data && data->CmdListsCount > 0) { ImGui_ImplDX8_RenderDrawData(data); } diff --git a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h index 4d9a20d2d26..38c6f40c408 100644 --- a/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h +++ b/Core/Libraries/Source/ImGui/wrapper/ImGuiFrameManager.h @@ -27,32 +27,24 @@ class FrameManager { public: static void BeginFrame(); - // 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; }; -class FrameGuard { -public: - FrameGuard() { - FrameManager::BeginFrame(); - } +class FrameGuard +{ + public: + FrameGuard() { FrameManager::BeginFrame(); } - ~FrameGuard() { - FrameManager::EndFrame(); - } + ~FrameGuard() { FrameManager::EndFrame(); } -// TODO change this to rule of 5 and use delete instead of declaring without definition once -// we are using a C++11 or higher C++ Standard -private: - FrameGuard(const FrameGuard&); - FrameGuard& operator=(const FrameGuard&); + // TODO change this to rule of 5 and use delete instead of declaring without + // definition once we are using a C++11 or higher C++ Standard + private: + FrameGuard(const FrameGuard &); + FrameGuard &operator=(const FrameGuard &); }; } // namespace ImGui } // namespace rts \ No newline at end of file diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index efef322a7ee..a89950d650d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -87,6 +87,7 @@ #include "imgui_impl_dx8.h" #include "imgui_impl_win32.h" #include "ImGuiFrameManager.h" +#include "ImGuiContextManager.h" #endif @@ -105,6 +106,9 @@ int DX8Wrapper_PreserveFPU = 0; ** DX8Wrapper Static Variables ** ***********************************************************************************/ +#ifdef RTS_HAS_IMGUI +static rts::ImGui::ContextManager g_imguiContextManager; +#endif static HWND _Hwnd = nullptr; bool DX8Wrapper::IsInitted = false; @@ -355,11 +359,6 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) void DX8Wrapper::Shutdown(void) { -#ifdef RTS_HAS_IMGUI - ImGui_ImplDX8_Shutdown(); - ImGui_ImplWin32_Shutdown(); - ImGui::DestroyContext(); -#endif if (D3DDevice) { Set_Render_Target ((IDirect3DSurface8 *)nullptr); @@ -599,17 +598,8 @@ bool DX8Wrapper::Create_Device(void) return false; } #ifdef RTS_HAS_IMGUI - // Initialize ImGui - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); + g_imguiContextManager.Init(_Hwnd, DX8Wrapper::_Get_D3D_Device8()); ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - ImGui::StyleColorsDark(); - - ImGui_ImplWin32_Init(_Hwnd); - ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); - io.Fonts->AddFontDefault(); io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); #endif dbgHelpGuard.deactivate(); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 5f884f5716c..5a342c87083 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -92,6 +92,7 @@ #include #include "imgui_impl_dx8.h" #include +#include #endif const int DEFAULT_RESOLUTION_WIDTH = 640; @@ -109,6 +110,9 @@ int DX8Wrapper_PreserveFPU = 0; ** DX8Wrapper Static Variables ** ***********************************************************************************/ +#ifdef RTS_HAS_IMGUI +static rts::ImGui::ContextManager g_imguiContextManager; +#endif static HWND _Hwnd = nullptr; bool DX8Wrapper::IsInitted = false; @@ -362,11 +366,6 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) void DX8Wrapper::Shutdown(void) { -#ifdef RTS_HAS_IMGUI - ImGui_ImplDX8_Shutdown(); - ImGui_ImplWin32_Shutdown(); - ImGui::DestroyContext(); -#endif if (D3DDevice) { Set_Render_Target ((IDirect3DSurface8 *)nullptr); @@ -649,17 +648,8 @@ bool DX8Wrapper::Create_Device(void) } } #ifdef RTS_HAS_IMGUI - // Initialize ImGui - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); + g_imguiContextManager.Init(_Hwnd, DX8Wrapper::_Get_D3D_Device8()); ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - ImGui::StyleColorsDark(); - - ImGui_ImplWin32_Init(_Hwnd); - ImGui_ImplDX8_Init(DX8Wrapper::_Get_D3D_Device8()); - io.Fonts->AddFontDefault(); io.DisplaySize = ImVec2(ResolutionWidth,ResolutionHeight); #endif dbgHelpGuard.deactivate(); From daba8a2c9161407787bdfff891c86f9a848fe13c Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 29 Jan 2026 18:07:56 +0100 Subject: [PATCH 55/60] streamline cmakelists integration via empty interface library --- Core/Libraries/CMakeLists.txt | 2 ++ Generals/Code/GameEngine/CMakeLists.txt | 6 +++--- Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt | 6 +++--- Generals/Code/Main/CMakeLists.txt | 5 +---- Generals/Code/Tools/WorldBuilder/CMakeLists.txt | 5 +---- GeneralsMD/Code/GameEngine/CMakeLists.txt | 6 +++--- .../Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt | 6 +++--- GeneralsMD/Code/Main/CMakeLists.txt | 5 +---- GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt | 5 +---- 9 files changed, 18 insertions(+), 28 deletions(-) diff --git a/Core/Libraries/CMakeLists.txt b/Core/Libraries/CMakeLists.txt index 51d2caf42a6..4c5655f4102 100644 --- a/Core/Libraries/CMakeLists.txt +++ b/Core/Libraries/CMakeLists.txt @@ -14,4 +14,6 @@ add_subdirectory(Source/Compression) # Imgui library if (RTS_BUILD_OPTION_IMGUI) add_subdirectory(Source/ImGui) +else () + add_library(lib_imgui INTERFACE) endif () \ No newline at end of file diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index 216b3d1a266..5340291dfd0 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -1098,9 +1098,9 @@ target_link_libraries(g_gameengine PUBLIC g_wwvegas ) -if (RTS_BUILD_OPTION_IMGUI) - target_link_libraries(g_gameengine PRIVATE lib_imgui) -endif () +target_link_libraries(g_gameengine PRIVATE + lib_imgui +) target_precompile_headers(g_gameengine PRIVATE [["Utility/CppMacros.h"]] # Must be first, to be removed when abandoning VC6 diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 2890c259f27..0d336711238 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -237,9 +237,9 @@ target_compile_definitions(g_ww3d2 PRIVATE $<$:WINVER=0x0500> ) -if (RTS_BUILD_OPTION_IMGUI) - target_link_libraries(g_ww3d2 PRIVATE lib_imgui) -endif () +target_link_libraries(g_ww3d2 PRIVATE + lib_imgui +) target_precompile_headers(g_ww3d2 PRIVATE [["Utility/CppMacros.h"]] # Must be first, to be removed when abandoning VC6 diff --git a/Generals/Code/Main/CMakeLists.txt b/Generals/Code/Main/CMakeLists.txt index b67c0cb8b25..3572afe6ad6 100644 --- a/Generals/Code/Main/CMakeLists.txt +++ b/Generals/Code/Main/CMakeLists.txt @@ -7,10 +7,6 @@ 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 @@ -25,6 +21,7 @@ target_link_libraries(g_generals PRIVATE milesstub vfw32 winmm + lib_imgui ) # TODO Originally referred to build host and user, replace with git info perhaps? diff --git a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt index 4f28f4758e3..359a7ced757 100644 --- a/Generals/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/Generals/Code/Tools/WorldBuilder/CMakeLists.txt @@ -212,10 +212,6 @@ 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 @@ -225,6 +221,7 @@ target_link_libraries(g_worldbuilder PRIVATE imm32 vfw32 winmm + lib_imgui ) if(WIN32 OR "${CMAKE_SYSTEM}" MATCHES "Windows") diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index 03058222473..ca400680a12 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -1174,9 +1174,9 @@ target_link_libraries(z_gameengine PUBLIC z_wwvegas ) -if (RTS_BUILD_OPTION_IMGUI) - target_link_libraries(z_gameengine PRIVATE lib_imgui) -endif () +target_link_libraries(z_gameengine PRIVATE + lib_imgui +) target_precompile_headers(z_gameengine PRIVATE [["Utility/CppMacros.h"]] # Must be first, to be removed when abandoning VC6 diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 1296f7f6501..2c3d5fddca9 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -253,9 +253,9 @@ 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 + lib_imgui +) target_link_libraries(z_ww3d2 PRIVATE core_wwdebug diff --git a/GeneralsMD/Code/Main/CMakeLists.txt b/GeneralsMD/Code/Main/CMakeLists.txt index a07ef3b2fdb..f708f497b14 100644 --- a/GeneralsMD/Code/Main/CMakeLists.txt +++ b/GeneralsMD/Code/Main/CMakeLists.txt @@ -7,10 +7,6 @@ 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 @@ -27,6 +23,7 @@ target_link_libraries(z_generals PRIVATE z_gameengine z_gameenginedevice zi_always + lib_imgui ) # TODO Originally referred to build host and user, replace with git info perhaps? diff --git a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt index b465aee239f..ea51119faa5 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt +++ b/GeneralsMD/Code/Tools/WorldBuilder/CMakeLists.txt @@ -217,10 +217,6 @@ 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 @@ -232,6 +228,7 @@ target_link_libraries(z_worldbuilder PRIVATE z_gameengine z_gameenginedevice zi_always + lib_imgui ) if(WIN32 OR "${CMAKE_SYSTEM}" MATCHES "Windows") From 0feef8bc8678a74011a990bb7ccd9a4f7c652832 Mon Sep 17 00:00:00 2001 From: "Salem B." <46156444+jurassicLizard@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:25:24 +0100 Subject: [PATCH 56/60] Update GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 5a342c87083..eace74db6b7 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -89,9 +89,8 @@ #ifdef RTS_HAS_IMGUI #include "imgui.h" -#include #include "imgui_impl_dx8.h" -#include +#include "imgui_impl_win32.h" #include #endif From 37b432c6c69371eb880f565542433c1d4f8d579a Mon Sep 17 00:00:00 2001 From: "Salem B." <46156444+jurassicLizard@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:26:01 +0100 Subject: [PATCH 57/60] Update GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index a963d74fb9b..9a38ba72f78 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -33,7 +33,7 @@ // USER INCLUDES ////////////////////////////////////////////////////////////// #ifdef RTS_HAS_IMGUI -#include +#include "imgui.h" #include "ImGuiFrameManager.h" #include "dx8wrapper.h" #endif From 3099847c187ec9fd5097e49fbd20b1bd53af6dc0 Mon Sep 17 00:00:00 2001 From: "Salem B." <46156444+jurassicLizard@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:26:47 +0100 Subject: [PATCH 58/60] Update GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 9a38ba72f78..bf45cf90ae5 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -35,7 +35,6 @@ #ifdef RTS_HAS_IMGUI #include "imgui.h" #include "ImGuiFrameManager.h" -#include "dx8wrapper.h" #endif #include "Common/ActionManager.h" From 8b33e41c9f27e8181be59158933867859c05d972 Mon Sep 17 00:00:00 2001 From: "Salem B." <46156444+jurassicLizard@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:27:18 +0100 Subject: [PATCH 59/60] Update GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index bf45cf90ae5..278beedbd93 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -766,7 +766,6 @@ void GameClient::update( void ) } - { USE_PERF_TIMER(GameClient_draw) From df277e486d0e7e3492a8c44aa8cc76a338b76bf6 Mon Sep 17 00:00:00 2001 From: "Salem B." Date: Thu, 29 Jan 2026 18:38:09 +0100 Subject: [PATCH 60/60] address greptile issues --- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 1 - GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp | 6 +----- .../Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 5 ++--- GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index a89950d650d..0564ffd6ee0 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -85,7 +85,6 @@ #ifdef RTS_HAS_IMGUI #include "imgui.h" #include "imgui_impl_dx8.h" -#include "imgui_impl_win32.h" #include "ImGuiFrameManager.h" #include "ImGuiContextManager.h" #endif diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index a963d74fb9b..bd8800f4908 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -33,9 +33,8 @@ // USER INCLUDES ////////////////////////////////////////////////////////////// #ifdef RTS_HAS_IMGUI -#include +#include "imgui.h" #include "ImGuiFrameManager.h" -#include "dx8wrapper.h" #endif #include "Common/ActionManager.h" @@ -637,7 +636,6 @@ void GameClient::update( void ) // redraw all views, update the GUI TheDisplay->DRAW(); TheDisplay->UPDATE(); - return; } @@ -766,8 +764,6 @@ void GameClient::update( void ) TheDisplay->UPDATE(); } - - { USE_PERF_TIMER(GameClient_draw) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 5a342c87083..4d8d58707e1 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -89,10 +89,9 @@ #ifdef RTS_HAS_IMGUI #include "imgui.h" -#include #include "imgui_impl_dx8.h" -#include -#include +#include "ImGuiFrameManager.h" +#include "ImGuiContextManager.h" #endif const int DEFAULT_RESOLUTION_WIDTH = 640; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h index 1ca09b5a89f..1ce59348089 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h +++ b/GeneralsMD/Code/Tools/WorldBuilder/include/wbview3d.h @@ -83,7 +83,7 @@ class WbView3d : public WbView, public DX8_CleanupHook // Function overrides needed for ImGui Mouse capture virtual BOOL PreTranslateMessage(MSG* pMsg); virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); -#endif +#endif // RTS_HAS_IMGUI // Implementation protected: virtual ~WbView3d();