From 96bc50ee263adc4ec40ba885edc57c317215594e Mon Sep 17 00:00:00 2001 From: Silent Date: Fri, 17 May 2024 17:35:46 +0200 Subject: [PATCH] VC: Disabled backface culling on detached car parts Fixes #25 --- SilentPatch/RWGTA.cpp | 40 ++++++---- SilentPatch/RWGTA.h | 1 - SilentPatch/RWUtils.hpp | 11 ++- SilentPatchIII/SilentPatchIII.vcxproj | 1 - SilentPatchIII/SilentPatchIII.vcxproj.filters | 3 - SilentPatchSA/GeneralSA.cpp | 4 +- SilentPatchSA/GeneralSA.h | 2 +- SilentPatchSA/PedSA.cpp | 2 +- SilentPatchSA/SilentPatchSA.cpp | 18 ++--- SilentPatchSA/SilentPatchSA.vcxproj | 2 +- SilentPatchSA/SilentPatchSA.vcxproj.filters | 6 +- SilentPatchVC/SilentPatchVC.cpp | 77 +++++++++++++++++++ SilentPatchVC/SilentPatchVC.vcxproj | 2 +- SilentPatchVC/SilentPatchVC.vcxproj.filters | 6 +- 14 files changed, 129 insertions(+), 46 deletions(-) delete mode 100644 SilentPatch/RWGTA.h diff --git a/SilentPatch/RWGTA.cpp b/SilentPatch/RWGTA.cpp index b746bbd..21e35de 100644 --- a/SilentPatch/RWGTA.cpp +++ b/SilentPatch/RWGTA.cpp @@ -1,5 +1,3 @@ -#include "RWGTA.h" - #include "Utils/MemoryMgr.h" #include "Utils/Patterns.h" @@ -17,21 +15,25 @@ void** rwengine = []() -> void** { // Thanks Steam III... // Locate RwRenderStateSet - auto renderStateSetPtr = hook::get_pattern( "D1 7C 24 2C", 4 ); - auto renderStateSet = reinterpret_cast(Memory::ReadCallFrom( renderStateSetPtr )); - - // Test III 1.0/1.1/VC - if ( *reinterpret_cast(renderStateSet) == 0xA1 ) + try { - return *reinterpret_cast(renderStateSet + 1); - } + auto renderStateSetPtr = hook::txn::get_pattern( "D1 7C 24 2C", 4 ); + auto renderStateSet = reinterpret_cast(Memory::ReadCallFrom( renderStateSetPtr )); - // Test III Steam - renderStateSet += 3; - if ( *reinterpret_cast(renderStateSet) == 0xA1 ) - { - return *reinterpret_cast(renderStateSet + 1); + // Test III 1.0/1.1/VC + if ( *reinterpret_cast(renderStateSet) == 0xA1 ) + { + return *reinterpret_cast(renderStateSet + 1); + } + + // Test III Steam + renderStateSet += 3; + if ( *reinterpret_cast(renderStateSet) == 0xA1 ) + { + return *reinterpret_cast(renderStateSet + 1); + } } + TXN_CATCH(); assert(!"Could not locate RwEngineInstance!"); return nullptr; @@ -52,5 +54,15 @@ RwReal RwIm2DGetNearScreenZ() return RWSRCGLOBAL(dOpenDevice).zBufferNear; } +RwBool RwRenderStateGet(RwRenderState state, void *value) +{ + return RWSRCGLOBAL(dOpenDevice).fpRenderStateGet(state, value); +} + +RwBool RwRenderStateSet(RwRenderState state, void *value) +{ + return RWSRCGLOBAL(dOpenDevice).fpRenderStateSet(state, value); +} + // Unreachable stub RwBool RwMatrixDestroy(RwMatrix* mpMat) { assert(!"Unreachable!"); return TRUE; } diff --git a/SilentPatch/RWGTA.h b/SilentPatch/RWGTA.h deleted file mode 100644 index 6f70f09..0000000 --- a/SilentPatch/RWGTA.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/SilentPatch/RWUtils.hpp b/SilentPatch/RWUtils.hpp index 9e7e96a..5b8344d 100644 --- a/SilentPatch/RWUtils.hpp +++ b/SilentPatch/RWUtils.hpp @@ -3,26 +3,25 @@ #include #include +template class RwScopedRenderState { public: - RwScopedRenderState( RwRenderState state ) - : m_state( state ) + explicit RwScopedRenderState() { - [[maybe_unused]] RwBool result = RwRenderStateGet( m_state, &m_value ); + [[maybe_unused]] RwBool result = RwRenderStateGet( State, &m_value ); assert( result != FALSE ); } ~RwScopedRenderState() { - [[maybe_unused]] RwBool result = RwRenderStateSet( m_state, m_value ); + [[maybe_unused]] RwBool result = RwRenderStateSet( State, m_value ); assert( result != FALSE ); } -private: RwScopedRenderState( const RwScopedRenderState& ) = delete; - const RwRenderState m_state; +private: void* m_value = nullptr; }; diff --git a/SilentPatchIII/SilentPatchIII.vcxproj b/SilentPatchIII/SilentPatchIII.vcxproj index 8f4ccc7..cc97395 100644 --- a/SilentPatchIII/SilentPatchIII.vcxproj +++ b/SilentPatchIII/SilentPatchIII.vcxproj @@ -66,7 +66,6 @@ - diff --git a/SilentPatchIII/SilentPatchIII.vcxproj.filters b/SilentPatchIII/SilentPatchIII.vcxproj.filters index 4a511ce..37f3274 100644 --- a/SilentPatchIII/SilentPatchIII.vcxproj.filters +++ b/SilentPatchIII/SilentPatchIII.vcxproj.filters @@ -89,9 +89,6 @@ Header Files - - Header Files - Header Files diff --git a/SilentPatchSA/GeneralSA.cpp b/SilentPatchSA/GeneralSA.cpp index 773defc..95dae9b 100644 --- a/SilentPatchSA/GeneralSA.cpp +++ b/SilentPatchSA/GeneralSA.cpp @@ -69,10 +69,10 @@ void CObject::Render() std::pair materialRestoreData[256]; size_t numMaterialsToRestore = 0; - RwScopedRenderState cullState(rwRENDERSTATECULLMODE); + RwScopedRenderState cullState; const int32_t carPartModelIndex = m_wCarPartModelIndex.Get(); - if ( carPartModelIndex != -1 && m_objectCreatedBy == TEMP_OBJECT && bObjectFlag7 && RwObjectGetType(m_pRwObject) == rpATOMIC ) + if ( carPartModelIndex != -1 && m_objectCreatedBy == TEMP_OBJECT && bUseVehicleColours && RwObjectGetType(m_pRwObject) == rpATOMIC ) { auto* pData = materialRestoreData; diff --git a/SilentPatchSA/GeneralSA.h b/SilentPatchSA/GeneralSA.h index fd1ed76..2b082dc 100644 --- a/SilentPatchSA/GeneralSA.h +++ b/SilentPatchSA/GeneralSA.h @@ -260,7 +260,7 @@ public: bool bObjectFlag4 : 1; bool bObjectFlag5 : 1; bool m_bIsExploded : 1; - bool bObjectFlag7 : 1; + bool bUseVehicleColours : 1; bool m_bIsLampPost : 1; bool m_bIsTargetable : 1; bool m_bIsBroken : 1; diff --git a/SilentPatchSA/PedSA.cpp b/SilentPatchSA/PedSA.cpp index ece35c5..63b308c 100644 --- a/SilentPatchSA/PedSA.cpp +++ b/SilentPatchSA/PedSA.cpp @@ -68,7 +68,7 @@ void CPed::RenderWeapon(bool bWeapon, bool bMuzzleFlash, bool bForShadow) if ( bMuzzleFlash && m_pMuzzleFlashFrame != nullptr ) { - RwScopedRenderState zWrite(rwRENDERSTATEZWRITEENABLE); + RwScopedRenderState zWrite; RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE); SetGunFlashAlpha(bRightGun); diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index f0e51ea..33d5524 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -375,7 +375,7 @@ static RpAtomic* RenderAtomic(RpAtomic* pAtomic, float fComp) static RpAtomic* StaticPropellerRender(RpAtomic* pAtomic) { - RwScopedRenderState alphaRef(rwRENDERSTATEALPHATESTFUNCTIONREF); + RwScopedRenderState alphaRef; RwRenderStateSet(rwRENDERSTATEALPHATESTFUNCTIONREF, 0); pAtomic = AtomicDefaultRenderCallBack(pAtomic); @@ -385,8 +385,8 @@ static RpAtomic* StaticPropellerRender(RpAtomic* pAtomic) static RpAtomic* MovingPropellerRender(RpAtomic* pAtomic) { - RwScopedRenderState alphaRef(rwRENDERSTATEALPHATESTFUNCTIONREF); - RwScopedRenderState vertexAlpha(rwRENDERSTATEVERTEXALPHAENABLE); + RwScopedRenderState alphaRef; + RwScopedRenderState vertexAlpha; RwRenderStateSet(rwRENDERSTATEALPHATESTFUNCTIONREF, 0); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(TRUE)); @@ -430,9 +430,9 @@ void RenderWeapon(CPed* pPed) void RenderWeaponPedsForPC() { - RwScopedRenderState vertexAlpha(rwRENDERSTATEVERTEXALPHAENABLE); - RwScopedRenderState zWrite(rwRENDERSTATEZWRITEENABLE); - RwScopedRenderState fogEnable(rwRENDERSTATEFOGENABLE); + RwScopedRenderState vertexAlpha; + RwScopedRenderState zWrite; + RwScopedRenderState fogEnable; RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast(TRUE)); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, reinterpret_cast(TRUE)); @@ -1869,7 +1869,7 @@ namespace StaticShadowAlphaFix static void (*orgRenderStaticShadows)(); static void RenderStaticShadows_StateFix() { - RwScopedRenderState state(rwRENDERSTATEALPHATESTFUNCTION); + RwScopedRenderState state; RwRenderStateSet( rwRENDERSTATEALPHATESTFUNCTION, (void*)rwALPHATESTFUNCTIONALWAYS ); orgRenderStaticShadows(); @@ -1878,7 +1878,7 @@ namespace StaticShadowAlphaFix static void (*orgRenderStoredShadows)(); static void RenderStoredShadows_StateFix() { - RwScopedRenderState state(rwRENDERSTATEALPHATESTFUNCTION); + RwScopedRenderState state; RwRenderStateSet( rwRENDERSTATEALPHATESTFUNCTION, (void*)rwALPHATESTFUNCTIONALWAYS ); orgRenderStoredShadows(); @@ -1935,7 +1935,7 @@ namespace MoonphasesFix return mask; } (); - RwScopedRenderState alphaTest( rwRENDERSTATEALPHATESTFUNCTION ); + RwScopedRenderState alphaTest; if ( gpMoonMask != nullptr ) { diff --git a/SilentPatchSA/SilentPatchSA.vcxproj b/SilentPatchSA/SilentPatchSA.vcxproj index 3a98b0b..c278440 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj +++ b/SilentPatchSA/SilentPatchSA.vcxproj @@ -247,6 +247,7 @@ copy /y "$(TargetPath)" "H:\Rockstar Games\Grand Theft Auto San Andreas\SilentPa + @@ -264,7 +265,6 @@ copy /y "$(TargetPath)" "H:\Rockstar Games\Grand Theft Auto San Andreas\SilentPa - diff --git a/SilentPatchSA/SilentPatchSA.vcxproj.filters b/SilentPatchSA/SilentPatchSA.vcxproj.filters index 3429350..d15dbdf 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj.filters +++ b/SilentPatchSA/SilentPatchSA.vcxproj.filters @@ -140,9 +140,6 @@ Header Files - - Header Files - Header Files\Utils @@ -164,6 +161,9 @@ Header Files + + Header Files + diff --git a/SilentPatchVC/SilentPatchVC.cpp b/SilentPatchVC/SilentPatchVC.cpp index 38b21fd..6677dc7 100644 --- a/SilentPatchVC/SilentPatchVC.cpp +++ b/SilentPatchVC/SilentPatchVC.cpp @@ -714,6 +714,63 @@ namespace VariableResets } +// ============= Disabled backface culling on detached car parts ============= +namespace CarPartsBackfaceCulling +{ + // Only the parts of CObject we need + enum // m_objectCreatedBy + { + GAME_OBJECT = 1, + MISSION_OBJECT = 2, + TEMP_OBJECT = 3, + }; + + struct Object + { + std::byte __pad[364]; + uint8_t m_objectCreatedBy; + bool bObjectFlag0 : 1; + bool bObjectFlag1 : 1; + bool bObjectFlag2 : 1; + bool bObjectFlag3 : 1; + bool bObjectFlag4 : 1; + bool bObjectFlag5 : 1; + bool m_bIsExploded : 1; + bool bUseVehicleColours : 1; + std::byte __pad2[22]; + FLAUtils::int16 m_wCarPartModelIndex; + }; + + static void* ObjectRender_Prologue_JumpBack; + __declspec(naked) static void __fastcall ObjectRender_Original(Object*) + { + _asm + { + push ebx + push esi + mov ebx, ecx + push edi + jmp [ObjectRender_Prologue_JumpBack] + } + } + + // If CObject::Render is re-routed by another mod, we overwrite this later + static void (__fastcall *orgObjectRender)(Object* obj) = &ObjectRender_Original; + + static void __fastcall ObjectRender_BackfaceCulling(Object* obj) + { + RwScopedRenderState cullState; + + if (obj->m_wCarPartModelIndex.Get() != -1 && obj->m_objectCreatedBy == TEMP_OBJECT && obj->bUseVehicleColours) + { + RwRenderStateSet(rwRENDERSTATECULLMODE, reinterpret_cast(rwCULLMODECULLNONE)); + } + + orgObjectRender(obj); + } +} + + void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModulePath ) { using namespace Memory; @@ -1613,6 +1670,26 @@ void Patch_VC_Common() Nop(comment_delay_id2.get(3), 4); } TXN_CATCH(); + + + // Disabled backface culling on detached car parts + try + { + using namespace CarPartsBackfaceCulling; + + auto object_render = pattern("55 83 EC 68 8A 43 54").get_one(); + + ObjectRender_Prologue_JumpBack = object_render.get(); + + // Check if CObject::Render is already re-routed by something else + if (*object_render.get(-5) == 0xE9) + { + ReadCall(object_render.get(-5), orgObjectRender); + } + + InjectHook(object_render.get(-5), ObjectRender_BackfaceCulling, HookType::Jump); + } + TXN_CATCH(); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) diff --git a/SilentPatchVC/SilentPatchVC.vcxproj b/SilentPatchVC/SilentPatchVC.vcxproj index eda5695..5d26fd8 100644 --- a/SilentPatchVC/SilentPatchVC.vcxproj +++ b/SilentPatchVC/SilentPatchVC.vcxproj @@ -170,7 +170,7 @@ - + diff --git a/SilentPatchVC/SilentPatchVC.vcxproj.filters b/SilentPatchVC/SilentPatchVC.vcxproj.filters index cda3132..6f9c906 100644 --- a/SilentPatchVC/SilentPatchVC.vcxproj.filters +++ b/SilentPatchVC/SilentPatchVC.vcxproj.filters @@ -51,9 +51,6 @@ Header Files - - Header Files - Header Files @@ -66,6 +63,9 @@ Header Files + + Header Files +