diff --git a/BunnymodXT/cvars.hpp b/BunnymodXT/cvars.hpp index 84bae792..20b8fe30 100644 --- a/BunnymodXT/cvars.hpp +++ b/BunnymodXT/cvars.hpp @@ -18,7 +18,8 @@ X(skill) \ X(host_framerate) \ X(sensitivity) \ - X(coop) + X(coop) \ + X(r_shadows) #define DEFINE_CVARS(X) \ X(_bxt_taslog, "0") \ diff --git a/BunnymodXT/modules/HwDLL.cpp b/BunnymodXT/modules/HwDLL.cpp index 55d0377a..c9010c0a 100644 --- a/BunnymodXT/modules/HwDLL.cpp +++ b/BunnymodXT/modules/HwDLL.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "../sptlib-wrapper.hpp" #include #include @@ -314,6 +313,11 @@ extern "C" void __cdecl R_SetFrustum() HwDLL::HOOKED_R_SetFrustum(); } +extern "C" void __cdecl studioapi_GL_StudioDrawShadow() +{ + HwDLL::HOOKED_studioapi_GL_StudioDrawShadow(); +} + extern "C" void __cdecl SPR_Set(HSPRITE_HL hSprite, int r, int g, int b) { HwDLL::HOOKED_SPR_Set(hSprite, r, g, b); @@ -466,6 +470,7 @@ void HwDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* modul MemUtils::MarkAsExecutable(ORIG_BUsesSDLInput); MemUtils::MarkAsExecutable(ORIG_R_StudioRenderModel); MemUtils::MarkAsExecutable(ORIG_R_SetFrustum); + MemUtils::MarkAsExecutable(ORIG_studioapi_GL_StudioDrawShadow); MemUtils::MarkAsExecutable(ORIG_SPR_Set); MemUtils::MarkAsExecutable(ORIG_DrawCrosshair); MemUtils::MarkAsExecutable(ORIG_Draw_FillRGBA); @@ -535,6 +540,7 @@ void HwDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* modul ORIG_BUsesSDLInput, HOOKED_BUsesSDLInput, ORIG_R_StudioRenderModel, HOOKED_R_StudioRenderModel, ORIG_R_SetFrustum, HOOKED_R_SetFrustum, + ORIG_studioapi_GL_StudioDrawShadow, HOOKED_studioapi_GL_StudioDrawShadow, ORIG_SPR_Set, HOOKED_SPR_Set, ORIG_DrawCrosshair, HOOKED_DrawCrosshair, ORIG_Draw_FillRGBA, HOOKED_Draw_FillRGBA, @@ -630,6 +636,7 @@ void HwDLL::Unhook() ORIG_BUsesSDLInput, ORIG_R_StudioRenderModel, ORIG_R_SetFrustum, + ORIG_studioapi_GL_StudioDrawShadow, ORIG_SPR_Set, ORIG_DrawCrosshair, ORIG_Draw_FillRGBA, @@ -729,6 +736,7 @@ void HwDLL::Clear() ORIG_BUsesSDLInput = nullptr; ORIG_R_StudioRenderModel = nullptr; ORIG_R_SetFrustum = nullptr; + ORIG_studioapi_GL_StudioDrawShadow = nullptr; ORIG_SPR_Set = nullptr; ORIG_DrawCrosshair = nullptr; ORIG_Draw_FillRGBA = nullptr; @@ -788,6 +796,8 @@ void HwDLL::Clear() frametime_remainder = nullptr; pstudiohdr = nullptr; scr_fov_value = nullptr; + r_shadows = nullptr; + qglDepthMask = nullptr; framesTillExecuting = 0; executing = false; insideCbuf_Execute = false; @@ -1330,6 +1340,27 @@ void HwDLL::FindStuff() EngineDevWarning("[hw dll] Could not find R_SetFrustum.\n"); } + ORIG_studioapi_GL_StudioDrawShadow = reinterpret_cast<_studioapi_GL_StudioDrawShadow>(MemUtils::GetSymbolAddress(m_Handle, "studioapi_GL_StudioDrawShadow")); + if (ORIG_studioapi_GL_StudioDrawShadow) { + EngineDevMsg("[hw dll] Found studioapi_GL_StudioDrawShadow at %p.\n", ORIG_studioapi_GL_StudioDrawShadow); + } else { + EngineDevWarning("[hw dll] Could not find studioapi_GL_StudioDrawShadow.\n"); + } + + r_shadows = reinterpret_cast(MemUtils::GetSymbolAddress(m_Handle, "r_shadows")); + if (r_shadows) { + EngineDevMsg("[hw dll] Found r_shadows at %p.\n", r_shadows); + } else { + EngineDevWarning("[hw dll] Could not find r_shadows.\n"); + } + + qglDepthMask = reinterpret_cast(MemUtils::GetSymbolAddress(m_Handle, "qglDepthMask")); + if (qglDepthMask) { + EngineDevMsg("[hw dll] Found qglDepthMask at %p.\n", qglDepthMask); + } else { + EngineDevWarning("[hw dll] Could not find qglDepthMask.\n"); + } + g_sv_delta = reinterpret_cast(MemUtils::GetSymbolAddress(m_Handle, "g_sv_delta")); if (g_sv_delta) EngineDevMsg("[hw dll] Found g_sv_delta at %p.\n", g_sv_delta); @@ -1590,6 +1621,19 @@ void HwDLL::FindStuff() } }); + auto fstudioapi_GL_StudioDrawShadow = FindAsync( + ORIG_studioapi_GL_StudioDrawShadow, + patterns::engine::studioapi_GL_StudioDrawShadow, + [&](auto pattern) { + switch (pattern - patterns::engine::studioapi_GL_StudioDrawShadow.cbegin()) + { + case 0: // HL-SteamPipe + r_shadows = reinterpret_cast(*reinterpret_cast(reinterpret_cast(ORIG_studioapi_GL_StudioDrawShadow) + 0xE) - offsetof(cvar_t, value)); + qglDepthMask = reinterpret_cast(*reinterpret_cast(reinterpret_cast(ORIG_studioapi_GL_StudioDrawShadow) + 0x8)); + break; + } + }); + auto fSeedRandomNumberGenerator = FindAsync( ORIG_SeedRandomNumberGenerator, patterns::engine::SeedRandomNumberGenerator, @@ -2125,6 +2169,17 @@ void HwDLL::FindStuff() } } + { + auto pattern = fstudioapi_GL_StudioDrawShadow.get(); + if (ORIG_studioapi_GL_StudioDrawShadow) { + EngineDevMsg("[hw dll] Found studioapi_GL_StudioDrawShadow at %p (using the %s pattern).\n", ORIG_studioapi_GL_StudioDrawShadow, pattern->name()); + EngineDevMsg("[hw dll] Found r_shadows at %p.\n", r_shadows); + EngineDevMsg("[hw dll] Found qglDepthMask at %p.\n", qglDepthMask); + } else { + EngineDevWarning("[hw dll] Could not find studioapi_GL_StudioDrawShadow.\n"); + } + } + { auto pattern = fHost_ValidSave.get(); if (ORIG_Host_ValidSave) { @@ -5706,6 +5761,13 @@ void HwDLL::RegisterCVarsAndCommandsIfNeeded() return; registeredVarsAndCmds = true; + + if (r_shadows) + { + ORIG_Cvar_RegisterVariable(r_shadows); + CVars::r_shadows.Assign(r_shadows); + } + RegisterCVar(CVars::_bxt_taslog); RegisterCVar(CVars::_bxt_min_frametime); RegisterCVar(CVars::_bxt_tas_script_generation); @@ -8355,3 +8417,47 @@ HOOK_DEF_1(HwDLL, void, __cdecl, LoadThisDll, const char*, szDllFilename) ORIG_LoadThisDll(szDllFilename); } + +/* + _Smiley: + + The original shadows have a issue with depth fighting. + Well in the beginning of original function, glDepthMask(GL_TRUE) is called. + I found that if we change it to GL_FALSE and return GL_TRUE at the end of the function, then we can get rid of this issue. + + I preferred to hook the QGL pointer for this, because accessing glDepthMask from system libraries will be more environment dependent, although of course it does not require finding with patterns/offsets. + QGL pointer functions are engine wrappers for GL functions made with the development of Quake 2. + + Of course, we could also use byte patching instead, but this is a dubious solution and generally more limited in actions, although it is simpler to implement. + + The logic behind all this code is so simple: we redirect the QGL pointer to our own wrapper, in which we do what we want, and at the end of the function we return everything back to original state. +*/ + +void APIENTRY_HL DepthMask(GLboolean flag) +{ + auto& hw = HwDLL::GetInstance(); + + if (hw.inside_studioapi_GL_StudioDrawShadow) + flag = GL_FALSE; + + hw.orig_qglDepthMask(flag); +} + +HOOK_DEF_0(HwDLL, void, __cdecl, studioapi_GL_StudioDrawShadow) +{ + if (!qglDepthMask || !r_shadows || !CVars::r_shadows.GetBool()) + { + ORIG_studioapi_GL_StudioDrawShadow(); + return; + } + + orig_qglDepthMask = *qglDepthMask; // Save the original pointer. + *qglDepthMask = DepthMask; // Redirect to our own wrapper. + + inside_studioapi_GL_StudioDrawShadow = true; + ORIG_studioapi_GL_StudioDrawShadow(); + inside_studioapi_GL_StudioDrawShadow = false; + + *qglDepthMask = orig_qglDepthMask; // Restore the original pointer. + orig_qglDepthMask(GL_TRUE); // We call qglDepthMask(GL_TRUE) back, since we changed it to GL_FALSE only for the duration of this function. +} diff --git a/BunnymodXT/modules/HwDLL.hpp b/BunnymodXT/modules/HwDLL.hpp index e759818a..6e59b372 100644 --- a/BunnymodXT/modules/HwDLL.hpp +++ b/BunnymodXT/modules/HwDLL.hpp @@ -6,6 +6,9 @@ #include "taslogger/writer.hpp" #include "../input_editor.hpp" #include "../shared.hpp" +#include + +typedef void (APIENTRY_HL *qglDepthMask_def)(GLboolean flag); enum class TASEditorMode { DISABLED, @@ -87,6 +90,7 @@ class HwDLL : public IHookableNameFilterOrdered HOOK_DECL(qboolean, __cdecl, ValidStuffText, char* buf) HOOK_DECL(qboolean, __cdecl, CL_ReadDemoMessage_OLD) HOOK_DECL(void, __cdecl, LoadThisDll, const char* szDllFilename) + HOOK_DECL(void, __cdecl, studioapi_GL_StudioDrawShadow) #ifdef HLSDK10_BUILD struct server_static_t @@ -555,7 +559,13 @@ class HwDLL : public IHookableNameFilterOrdered bool ducktap; edict_t **sv_player; + + bool inside_studioapi_GL_StudioDrawShadow = false; + qglDepthMask_def orig_qglDepthMask; protected: + cvar_t *r_shadows; + qglDepthMask_def *qglDepthMask; + void KeyDown(Key& btn); void KeyUp(Key& btn); void SaveInitialDataToDemo(); diff --git a/BunnymodXT/patterns.hpp b/BunnymodXT/patterns.hpp index 452ae705..027e34d2 100644 --- a/BunnymodXT/patterns.hpp +++ b/BunnymodXT/patterns.hpp @@ -7,6 +7,11 @@ namespace patterns { namespace engine { + PATTERNS(studioapi_GL_StudioDrawShadow, + "HL-SteamPipe", + "55 8B EC 51 6A 01 FF 15 ?? ?? ?? ?? D9 05 ?? ?? ?? ?? D8 1D ?? ?? ?? ?? DF E0 F6 C4 44 0F 8B ?? ?? ?? ?? 83 3D ?? ?? ?? ?? 05" // + 0x8 = qglDepthMask, + 0xE = r_shadows.value + ); + PATTERNS(LoadAndDecryptHwDLL, "HL-NGHL", "8B 0D ?? ?? ?? ?? 53 56 33 DB 8B 01 57 53 68 ?? ?? ?? ?? FF 74 24 18 FF 50 28 8B 0D ?? ?? ?? ?? 8B F0 6A 02 53 8B 01 56 FF 50 30 8B 0D", diff --git a/BunnymodXT/shared.hpp b/BunnymodXT/shared.hpp index 6e898817..88545e87 100644 --- a/BunnymodXT/shared.hpp +++ b/BunnymodXT/shared.hpp @@ -45,3 +45,11 @@ constexpr int kRenderFxTrigger = 241; // DO NOT CHANGE THIS VALUE OR YOU WILL BR // - Other constants constexpr steamid_t STEAMID64_CONST = 76561197960265728; // 0x110000100000000 + +// - Custom macros + +#ifdef _WIN32 +#define APIENTRY_HL APIENTRY +#else +#define APIENTRY_HL +#endif \ No newline at end of file