From c4aacbcdd22108d48f2a1ab844f12e3860335d2a Mon Sep 17 00:00:00 2001 From: Torhan Bartel Date: Wed, 21 Oct 2026 00:10:30 +0200 Subject: [PATCH] Hide menu pictures only inside the menu frames The hidden-texture list stayed active in a game; a game texture made at the address of a freed menu picture was skipped (rendering glitches in-game). Hiding now applies only while the main menu's frame or the in-game options draw over the menu background. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/mods/hud.cpp | 19 +++++++++++++++++-- src/mods/hud.h | 5 +++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/mods/hud.cpp b/src/mods/hud.cpp index 2b45fab..55f3671 100644 --- a/src/mods/hud.cpp +++ b/src/mods/hud.cpp @@ -409,10 +409,22 @@ DrawPrimitiveFn g_drawPrimitive = nullptr; DrawIndexedPrimitiveFn g_drawIndexedPrimitive = nullptr; // Textures not drawn (SetHiddenTextures): the surface bound to stage 0 is -// tracked per thread (each thread draws with its own device calls). +// tracked per thread (each thread draws with its own device calls). Only +// inside a frame drawn over the menu background (g_hidingPictures: the main +// menu's, the options' in a game): the list keeps surfaces the cache may +// have freed since, and a game texture made at the same address was skipped +// in the world view (user, 2026-10-21: "rendering glitches ingame"). constexpr int kHiddenTextureMax = 64; std::atomic g_hiddenTextures[kHiddenTextureMax] = {}; thread_local void* g_boundTexture = nullptr; +thread_local int g_hidingPictures = 0; + +struct HidingPictures { + HidingPictures() { ++g_hidingPictures; } + ~HidingPictures() { --g_hidingPictures; } + HidingPictures(const HidingPictures&) = delete; + HidingPictures& operator=(const HidingPictures&) = delete; +}; using SetTextureFn = HRESULT(__stdcall*)(void* device, DWORD stage, void* surface); SetTextureFn g_setTexture = nullptr; @@ -425,7 +437,7 @@ HRESULT __stdcall SetTextureTracked(void* device, DWORD stage, void* surface) { } bool BoundTextureHidden() { - if (!g_boundTexture) { + if (!g_boundTexture || g_hidingPictures == 0) { return false; } for (const auto& hidden : g_hiddenTextures) { @@ -521,9 +533,11 @@ public: Viewport7 frame = {static_cast(dx), 0, kLayoutWidth, 768, previous_.minZ, previous_.maxZ}; device_ = device; g_setViewport(device, &frame); + ++g_hidingPictures; } ~FrameScope() { if (device_) { + --g_hidingPictures; g_setViewport(device_, &previous_); } } @@ -872,6 +886,7 @@ int RenderMenuFrame(void* device, bool framed, int (*body)(void* context), void* const int width = mods::widescreen::RenderWidth(); const int dx = framed && width > kLayoutWidth ? (width - kLayoutWidth) / 2 : 0; g_menuFrameDx = dx; + HidingPictures hiding; Viewport7 previous; auto getViewport = device ? reinterpret_cast((*static_cast(device))[kVtableGetViewport]) : nullptr; diff --git a/src/mods/hud.h b/src/mods/hud.h index 1184833..a924835 100644 --- a/src/mods/hud.h +++ b/src/mods/hud.h @@ -48,8 +48,9 @@ int HandleCanvas(void* event, int (*body)(void* context), void* context); int RenderMenuFrame(void* device, bool framed, int (*body)(void* context), void* context); int MenuFrameOffsetX(); -// Quads drawn with one of these textures (Direct3D surfaces) are left out, -// on every thread, until the list changes (at most 64). +// Quads drawn with one of these textures (Direct3D surfaces) are left out +// inside the frames drawn over the menu background (RenderMenuFrame, the +// in-game options), until the list changes (at most 64). void SetHiddenTextures(void* const* surfaces, int count); } // namespace mods::hud