diff --git a/SilentPatchIII/SilentPatchIII.cpp b/SilentPatchIII/SilentPatchIII.cpp index 0a98211..bef3aa3 100644 --- a/SilentPatchIII/SilentPatchIII.cpp +++ b/SilentPatchIII/SilentPatchIII.cpp @@ -99,15 +99,15 @@ static const void* SubtitlesShadowFix_JumpBack; auto WorldRemove = reinterpret_cast(hook::get_pattern("8A 43 50 56 24 07", -5)); -static const float& ResolutionWidthMult = **AddressByVersion(0x57E956, 0x57ECA6, 0x57EBA6); -inline float GetWidthMult() +float GetWidthMult() { + static const float& ResolutionWidthMult = **AddressByVersion(0x57E956, 0x57ECA6, 0x57EBA6); return ResolutionWidthMult; } -static const float& ResolutionHeightMult = **AddressByVersion(0x57E940, 0x57EC90, 0x57EB90); -inline float GetHeightMult() +float GetHeightMult() { + static const float& ResolutionHeightMult = **AddressByVersion(0x57E940, 0x57EC90, 0x57EB90); return ResolutionHeightMult; } @@ -987,6 +987,29 @@ namespace OnscreenCounterBarFixes HOOK_EACH_INIT(YPos, orgYPos, YPos_Recalculated); } +// ============= Fix credits not scaling to resolution ============= +namespace CreditsScalingFixes +{ + static const unsigned int FIXED_RES_HEIGHT_SCALE = 448; + + template + static void (*orgPrintString)(float,float,const wchar_t*); + + template + static void PrintString_ScaleY(float fX, float fY, const wchar_t* pText) + { + orgPrintString(fX, fY * GetHeightMult() * RsGlobal->MaximumHeight, pText); + } + + static void (*orgSetScale)(float X, float Y); + static void SetScale_ScaleToRes(float X, float Y) + { + orgSetScale(X * GetWidthMult() * RsGlobal->MaximumWidth, Y * GetHeightMult() * RsGlobal->MaximumHeight); + } + + HOOK_EACH_INIT(PrintString, orgPrintString, PrintString_ScaleY); +} + namespace ModelIndicesReadyHook { static void (*orgInitialiseObjectData)(const char*); @@ -1252,6 +1275,41 @@ void InjectDelayedPatches_III_Common( bool bHasDebugMenu, const wchar_t* wcModul } TXN_CATCH(); + + // Fix credits not scaling to resolution + try + { + using namespace CreditsScalingFixes; + + std::array creditPrintString = { + get_pattern("D9 1C 24 E8 ? ? ? ? 83 C4 0C 8B 03", 3), + }; + + auto setScale = get_pattern("E8 ? ? ? ? 8B 44 24 28 59 59"); + + // Credits are timed for 640x480, but the PC version scales to 640x448 internally - speed credits up a bit, + // especially since ours are longer and even the PS2 version cuts them a bit late. + float** creditsSpeed = get_pattern("D8 0D ? ? ? ? D9 5D E8", 2); + + // As we now scale everything on PrintString time, the resolution height checks need to be unscaled. + void* resHeightScales[] = { + get_pattern("DF 6C 24 08 DB 05 ? ? ? ? D8 05", 4 + 2), + get_pattern("8B 35 ? ? ? ? 03 75 F4", 2), + }; + + HookEach_PrintString(creditPrintString, InterceptCall); + InterceptCall(setScale, orgSetScale, SetScale_ScaleToRes); + + static float newSpeed = **creditsSpeed * (480.0f/448.0f); + Patch(creditsSpeed, &newSpeed); + + for (void* addr : resHeightScales) + { + Patch(addr, &FIXED_RES_HEIGHT_SCALE); + } + } + TXN_CATCH(); + FLAUtils::Init(moduleList); } diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index ed8aa13..ae9d44e 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -322,6 +322,21 @@ struct AlphaObjectInfo { return a.fCompareValue < b.fCompareValue; } }; +struct PsGlobalType; + +struct RsGlobalType +{ + const char* AppName; + signed int MaximumWidth; + signed int MaximumHeight; + unsigned int frameLimit; + BOOL quit; + PsGlobalType* ps; + void* keyboard; + void* mouse; + void* pad; +}; + // Other wrappers void (*GTAdelete)(void*) = AddressByVersion(0x82413F, 0x824EFF, 0x85E58C); const char* (*GetFrameNodeName)(RwFrame*) = AddressByVersion(0x72FB30, 0x730360, 0x769C20); @@ -345,6 +360,8 @@ auto WorldRemove = AddressByVersion(0x563280, 0, 0x57D37 // SA variables void** rwengine = *AddressByVersion(0x58FFC0, 0x53F032, 0x48C194, { "8B 48 20 53 56 57 6A 01", -5 + 1 }); +RsGlobalType* RsGlobal = *AddressByVersion(0x619602 + 2, { "33 C0 C7 05 ? ? ? ? ? ? ? ? C7 05", 2 + 2 }); + unsigned char& nGameClockDays = **AddressByVersion(0x4E841D, 0x4E886D, 0x4F3871); unsigned char& nGameClockMonths = **AddressByVersion(0x4E842D, 0x4E887D, 0x4F3861); void*& pUserTracksStuff = **AddressByVersion(0x4D9B7B, 0x4DA06C, 0x4E4A43); @@ -468,6 +485,39 @@ static CAEWaveDecoder* __stdcall CAEWaveDecoderInit(CAEDataStream* pStream) return new CAEWaveDecoder(pStream); } +namespace ScalingInternals +{ + // 1.0 - fast math uses a scaling multiplier + float ScaleX_Multiplier(float val) + { + static const float& ResolutionWidthMult = **(float**)(0x43CF57 + 2); + return val * RsGlobal->MaximumWidth * ResolutionWidthMult; + } + + float ScaleY_Multiplier(float val) + { + static const float& ResolutionHeightMult = **(float**)(0x43CF47 + 2); + return val * RsGlobal->MaximumHeight * ResolutionHeightMult; + } + + // New binaries - precise math uses a scaling divisor + float ScaleX_Divisor(float val) + { + static const double& ResolutionWidthDiv = **hook::get_pattern("DC 35 ? ? ? ? DC 0D ? ? ? ? DE E9 D9 5D F0", 2); + return static_cast(val * RsGlobal->MaximumWidth / ResolutionWidthDiv); + } + + float ScaleY_Divisor(float val) + { + static const double& ResolutionHeightDiv = **hook::get_pattern("50 DC 35 ? ? ? ? DC 0D", 1 + 2); + return static_cast(val * RsGlobal->MaximumHeight / ResolutionHeightDiv); + } +} + +// Default to 1.0, update these pointers with a pointer to the new binaries function if needed +auto ScaleX = &ScalingInternals::ScaleX_Multiplier; +auto ScaleY = &ScalingInternals::ScaleY_Multiplier; + namespace ScriptFixes { @@ -2759,6 +2809,38 @@ namespace NewResolutionSelectionDialog } +// ============= Fix credits not scaling to resolution ============= +// Also makes the shadow scale properly, as they haven't done that either... +// But since this seems to be the only place, don't pull in the fix from Vice City, +// fix it here instead +namespace CreditsScalingFixes +{ + static const unsigned int FIXED_RES_HEIGHT_SCALE = 448; + + template + static void (*orgPrintString)(float,float,const wchar_t*); + + template + static void PrintString_ScaleY(float fX, float fY, const wchar_t* pText) + { + if constexpr (Index == 1) + { + // Fix the shadow X scale - the Y scale will be fixed below + fX = fX + 1.0f - ScaleX(1.0f); + } + orgPrintString(fX, ScaleY(fY), pText); + } + + static void (*orgSetScale)(float X, float Y); + static void SetScale_ScaleToRes(float X, float Y) + { + orgSetScale(ScaleX(X), ScaleY(Y)); + } + + HOOK_EACH_INIT(PrintString, orgPrintString, PrintString_ScaleY); +} + + // ============= LS-RP Mode stuff ============= namespace LSRPMode { @@ -5614,6 +5696,29 @@ void Patch_SA_10(HINSTANCE hInstance) } + // Fix credits not scaling to resolution + { + using namespace CreditsScalingFixes; + + std::array creditPrintString = { 0x5A8707, 0x5A8785 }; + + HookEach_PrintString(creditPrintString, InterceptCall); + InterceptCall(0x5A86C0, orgSetScale, SetScale_ScaleToRes); + + // Fix the credits cutting off on the bottom early, they don't do that in III + // but it regressed in VC and SA + static const float topMargin = 1.0f; + static const float bottomMargin = -(**(float**)(0x5A869A + 2)); + + Patch(0x5A8689 + 2, &topMargin); + Patch(0x5A869A + 2, &bottomMargin); + + // As we now scale everything on PrintString time, the resolution height checks need to be unscaled. + Patch(0x5A8660 + 2, &FIXED_RES_HEIGHT_SCALE); + Patch(0x5AF8C9 + 2, &FIXED_RES_HEIGHT_SCALE); + } + + #if FULL_PRECISION_D3D // Test - full precision D3D device Patch( 0x7F672B+1, *(uint8_t*)(0x7F672B+1) | D3DCREATE_FPU_PRESERVE ); @@ -6374,6 +6479,9 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) using namespace Memory; using namespace hook::txn; + ScaleX = &ScalingInternals::ScaleX_Divisor; + ScaleY = &ScalingInternals::ScaleY_Divisor; + try { void* isAlreadyRunning = get_pattern( "85 C0 74 08 33 C0 8B E5 5D C2 10 00", -5 ); @@ -7635,6 +7743,40 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance) InjectHook(rwEngineGetCurrentSubSystem, RwEngineGetCurrentSubSystem_FromSettings); } TXN_CATCH(); + + + // Fix credits not scaling to resolution + { + using namespace CreditsScalingFixes; + + std::array creditPrintString = { + get_pattern("E8 ? ? ? ? 83 C4 0C 80 7D 1C 00"), + get_pattern("D9 1C 24 E8 ? ? ? ? DD 05 ? ? ? ? 83 C4 0C 5E", 3), + }; + + auto setScale = get_pattern("D9 1C 24 E8 ? ? ? ? 83 C4 08 68 FF 00 00 00 6A 00 6A 00 6A 00", 3); + + // Fix the credits cutting off on the bottom early, they don't do that in III + // but it regressed in VC and SA + auto positionOffset = get_pattern("DE C2 D9 45 18 DE EA D9 C9 D9 5D 14 D9 05", 12 + 2); + + // As we now scale everything on PrintString time, the resolution height checks need to be unscaled. + void* resHeightScales[] = { + get_pattern("DB 05 ? ? ? ? 57 8B 7D 14", 2), + get_pattern("A1 ? ? ? ? 03 45 FC 89 45 F4", 1) + }; + + static const float topMargin = 1.0f; + Patch(positionOffset, &topMargin); + + HookEach_PrintString(creditPrintString, InterceptCall); + InterceptCall(setScale, orgSetScale, SetScale_ScaleToRes); + + for (void* addr : resHeightScales) + { + Patch(addr, &FIXED_RES_HEIGHT_SCALE); + } + } } diff --git a/SilentPatchVC/SilentPatchVC.cpp b/SilentPatchVC/SilentPatchVC.cpp index 956ef76..5bc4adf 100644 --- a/SilentPatchVC/SilentPatchVC.cpp +++ b/SilentPatchVC/SilentPatchVC.cpp @@ -72,13 +72,13 @@ void* (*GetModelInfo)(const char*, int*); CVehicleModelInfo**& ms_modelInfoPtrs = *hook::get_pattern("8B 15 ? ? ? ? 8D 04 24", 2); int32_t& numModelInfos = *hook::get_pattern("81 FD ? ? ? ? 7C B7", 2); -inline float GetWidthMult() +float GetWidthMult() { static const float& ResolutionWidthMult = **AddressByVersion(0x5FA15E, 0x5FA17E, 0x5F9DBE); return ResolutionWidthMult; } -inline float GetHeightMult() +float GetHeightMult() { static const float& ResolutionHeightMult = **AddressByVersion(0x5FA148, 0x5FA168, 0x5F9DA8); return ResolutionHeightMult; @@ -176,6 +176,21 @@ namespace PrintStringShadows } }; + template + struct XMinus + { + static inline void (*orgPrintString)(float,float,const wchar_t*); + static void PrintString(float fX, float fY, const wchar_t* pText) + { + PrintString_Internal(orgPrintString, fX, fY, -(**margin), 0.0f, pText); + } + + static void Hook(uintptr_t addr) + { + Memory::DynBase::InterceptCall(addr, orgPrintString, PrintString); + } + }; + template struct Y { @@ -384,7 +399,7 @@ namespace RadarTraceOutlineFixes } -// ============= Fix the loading bar outline not scaling to resolution============= +// ============= Fix the loading bar outline not scaling to resolution ============= namespace LoadingBarOutlineFixes { template @@ -429,6 +444,28 @@ namespace LoadingBarOutlineFixes HOOK_EACH_INIT(YPos, orgYPos, YPos_Recalculated); } +// ============= Fix credits not scaling to resolution ============= +namespace CreditsScalingFixes +{ + static const unsigned int FIXED_RES_HEIGHT_SCALE = 448; + + template + static void (*orgPrintString)(float,float,const wchar_t*); + + template + static void PrintString_ScaleY(float fX, float fY, const wchar_t* pText) + { + orgPrintString(fX, fY * GetHeightMult() * RsGlobal->MaximumHeight, pText); + } + + static void (*orgSetScale)(float X, float Y); + static void SetScale_ScaleToRes(float X, float Y) + { + orgSetScale(X * GetWidthMult() * RsGlobal->MaximumWidth, Y * GetHeightMult() * RsGlobal->MaximumHeight); + } + + HOOK_EACH_INIT(PrintString, orgPrintString, PrintString_ScaleY); +} float FixedRefValue() { @@ -1555,6 +1592,42 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule TXN_CATCH(); + // Fix credits not scaling to resolution + try + { + using namespace CreditsScalingFixes; + + std::array creditPrintString = { + get_pattern("E8 ? ? ? ? 83 C4 0C 8D 4C 24 14"), + get_pattern("E8 ? ? ? ? 83 C4 0C 8B 03"), + }; + + auto setScale = get_pattern("E8 ? ? ? ? 59 59 8D 4C 24 10"); + + // Fix the credits cutting off on the bottom early, they don't do that in III + // but it regressed in VC and SA + auto positionOffset = pattern("D8 1D ? ? ? ? DF E0 F6 C4 45 0F 85 ? ? ? ? 89 4C 24 08 DB 44 24 08 D8 25").get_one(); + + // As we now scale everything on PrintString time, the resolution height checks need to be unscaled. + void* resHeightScales[] = { + get_pattern("8B 0D ? ? ? ? 8B 03", 2), + get_pattern("8B 0D ? ? ? ? C7 44 24 ? ? ? ? ? 03 4C 24 14 ", 2), + }; + + static const float floatStorage[2] = { 1.0f, -(**positionOffset.get(0x19 + 2)) }; + Patch(positionOffset.get(2), &floatStorage[0]); + Patch(positionOffset.get(0x19 + 2), &floatStorage[0]); + + HookEach_PrintString(creditPrintString, InterceptCall); + InterceptCall(setScale, orgSetScale, SetScale_ScaleToRes); + + for (void* addr : resHeightScales) + { + Patch(addr, &FIXED_RES_HEIGHT_SCALE); + } + } + TXN_CATCH(); + FLAUtils::Init(moduleList); } @@ -1600,7 +1673,7 @@ void Patch_VC_10(uint32_t width, uint32_t height) using namespace PrintStringShadows; XY<0x5FA1F6, 0x5FA1D5>::Hook(0x5FA1FD); - XYMinus<0x544727, 0x544727>::Hook(0x54474D); + XMinus<0x544727/*, 0x544727*/>::Hook(0x54474D); // Don't patch Y as we're doing it in the credits scale fix } // Mouse fucking fix! @@ -1688,7 +1761,7 @@ void Patch_VC_11(uint32_t width, uint32_t height) using namespace PrintStringShadows; XY<0x5FA216, 0x5FA1F5>::Hook(0x5FA21D); - XYMinus<0x544747, 0x544747>::Hook(0x54476D); + XMinus<0x544747/*, 0x544747*/>::Hook(0x54476D); // Don't patch Y as we're doing it in the credits scale fix } // Mouse fucking fix! @@ -1775,7 +1848,7 @@ void Patch_VC_Steam(uint32_t width, uint32_t height) using namespace PrintStringShadows; XY<0x5F9E56, 0x5F9E35>::Hook(0x5F9E5D); - XYMinus<0x544617, 0x544617>::Hook(0x54463D); + XMinus<0x544617/*, 0x544617*/>::Hook(0x54463D); // Don't patch Y as we're doing it in the credits scale fix } // Mouse fucking fix!