From ec5c51f54c6b144185eb8683f67a7b3a9f3ab4f2 Mon Sep 17 00:00:00 2001 From: Hyper <34012267+hyperbx@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:18:41 +0000 Subject: [PATCH] Migrate game.cpp to categorised source files (#3) * Migrate game.cpp to categorised source files Co-Authored-By: Skyth (Asilkan) <19259897+blueskythlikesclouds@users.noreply.github.com> Co-Authored-By: Michael <15317421+ActualMandM@users.noreply.github.com> * Move motion blur hook to video_patches.cpp --------- Co-authored-by: Skyth (Asilkan) <19259897+blueskythlikesclouds@users.noreply.github.com> Co-authored-by: Michael <15317421+ActualMandM@users.noreply.github.com> --- UnleashedRecomp/CMakeLists.txt | 11 +- UnleashedRecomp/game.cpp | 388 ------------------- UnleashedRecomp/patches/fps_patches.cpp | 60 +++ UnleashedRecomp/patches/misc_patches.cpp | 71 ++++ UnleashedRecomp/patches/object_patches.cpp | 12 + UnleashedRecomp/patches/player_patches.cpp | 91 +++++ UnleashedRecomp/patches/resident_patches.cpp | 75 ++++ UnleashedRecomp/patches/video_patches.cpp | 59 +++ UnleashedRecomp/ui/window.cpp | 4 +- 9 files changed, 380 insertions(+), 391 deletions(-) delete mode 100644 UnleashedRecomp/game.cpp create mode 100644 UnleashedRecomp/patches/fps_patches.cpp create mode 100644 UnleashedRecomp/patches/misc_patches.cpp create mode 100644 UnleashedRecomp/patches/object_patches.cpp create mode 100644 UnleashedRecomp/patches/player_patches.cpp create mode 100644 UnleashedRecomp/patches/resident_patches.cpp create mode 100644 UnleashedRecomp/patches/video_patches.cpp diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 7a4f95b..1beca68 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -57,13 +57,21 @@ set(SWA_HID_CXX_SOURCES "hid/driver/sdl_hid.cpp" ) +set(SWA_PATCHES_CXX_SOURCES + "patches/fps_patches.cpp" + "patches/misc_patches.cpp" + "patches/object_patches.cpp" + "patches/player_patches.cpp" + "patches/resident_patches.cpp" + "patches/video_patches.cpp" +) + set(SWA_UI_CXX_SOURCES "ui/window.cpp" ) set(SWA_CXX_SOURCES "config.cpp" - "game.cpp" "main.cpp" "misc_impl.cpp" "stdafx.cpp" @@ -73,6 +81,7 @@ set(SWA_CXX_SOURCES ${SWA_GPU_CXX_SOURCES} ${SWA_APU_CXX_SOURCES} ${SWA_HID_CXX_SOURCES} + ${SWA_PATCHES_CXX_SOURCES} ${SWA_UI_CXX_SOURCES} ) diff --git a/UnleashedRecomp/game.cpp b/UnleashedRecomp/game.cpp deleted file mode 100644 index 3a99ca6..0000000 --- a/UnleashedRecomp/game.cpp +++ /dev/null @@ -1,388 +0,0 @@ -#include -#include "api/SWA.h" -#include "ui/window.h" -#include "config.h" - -constexpr float m_baseAspectRatio = 16.0f / 9.0f; - -const char* m_pStageID; - -uint32_t m_lastCheckpointScore = 0; - -float m_lastDarkGaiaEnergy = 0.0f; - -bool m_isUnleashCancelled = false; - -#pragma region Aspect Ratio Hooks - -bool CameraAspectRatioMidAsmHook(PPCRegister& r31) -{ - auto pCamera = (SWA::CCamera*)g_memory.Translate(r31.u32); - auto newAspectRatio = (float)Window::s_width / (float)Window::s_height; - - // Dynamically adjust horizontal aspect ratio to window dimensions. - pCamera->m_HorzAspectRatio = newAspectRatio; - - if (auto s_pVertAspectRatio = (be*)g_memory.Translate(0x82028FE0)) - { - // Dynamically adjust vertical aspect ratio for VERT+. - *s_pVertAspectRatio = 2.0f * atan(tan(45.0f / 2.0f) * (m_baseAspectRatio / newAspectRatio)); - } - - // Jump to 4:3 code for VERT+ adjustments if using a narrow aspect ratio. - return newAspectRatio < m_baseAspectRatio; -} - -void CameraBoostAspectRatioMidAsmHook(PPCRegister& r31, PPCRegister& f0) -{ - auto pCamera = (SWA::CCamera*)g_memory.Translate(r31.u32); - - if (Window::s_width < Window::s_height) - { - // Use horizontal FOV for narrow aspect ratios. - f0.f32 = pCamera->m_HorzFieldOfView; - } - else - { - // Use vertical FOV for wide aspect ratios. - f0.f32 = pCamera->m_VertFieldOfView; - } -} - -void CSDAspectRatioMidAsmHook(PPCRegister& f1, PPCRegister& f2) -{ - auto newAspectRatio = (float)Window::s_width / (float)Window::s_height; - - if (newAspectRatio > m_baseAspectRatio) - { - f1.f64 = 1280.0f / ((newAspectRatio * 720.0f) / 1280.0f); - } - else if (newAspectRatio < m_baseAspectRatio) - { - f2.f64 = 720.0f / ((1280.0f / newAspectRatio) / 720.0f); - } -} - -#pragma endregion - -#pragma region Score Hooks - -/* Hook function for when checkpoints are activated - to preserve the current checkpoint score. */ -PPC_FUNC_IMPL(__imp__sub_82624308); -PPC_FUNC(sub_82624308) -{ - __imp__sub_82624308(ctx, base); - - if (Config::ScoreBehaviour != EScoreBehaviour::CheckpointRetain) - return; - - auto pGameDocument = SWA::CGameDocument::GetInstance(); - - if (!pGameDocument) - return; - - m_lastCheckpointScore = pGameDocument->m_pMember->m_Score; -} - -/* Hook function that resets the score - and restore the last checkpoint score. */ -PPC_FUNC_IMPL(__imp__sub_8245F048); -PPC_FUNC(sub_8245F048) -{ - __imp__sub_8245F048(ctx, base); - - if (Config::ScoreBehaviour != EScoreBehaviour::CheckpointRetain) - return; - - auto pGameDocument = SWA::CGameDocument::GetInstance(); - - if (!pGameDocument) - return; - - printf("[*] Resetting score to %d\n", m_lastCheckpointScore); - - pGameDocument->m_pMember->m_Score = m_lastCheckpointScore; -} - -void ResetScoreOnRestartMidAsmHook() -{ - m_lastCheckpointScore = 0; -} - -#pragma endregion - -#pragma region Loading Hooks - -// Loading screen hook. -PPC_FUNC_IMPL(__imp__sub_824DCF38); -PPC_FUNC(sub_824DCF38) -{ - /* Force the Werehog transition ID - to use a different transition. */ - if (!Config::WerehogHubTransformVideo) - { - /* - 0 - Tails Electric NOW LOADING - 1 - No Transition - 2 - Werehog Transition - 3 - Tails Electric NOW LOADING w/ Info (requires context) - 4 - Arrows In/Out - 5 - NOW LOADING - 6 - Event Gallery - 7 - NOW LOADING - 8 - Black Screen - */ - if (ctx.r4.u32 == 2) - ctx.r4.u32 = 4; - } - - if (m_pStageID) - { - /* Fix restarting Eggmanland as the Werehog - erroneously using the Event Gallery transition. */ - if (ctx.r4.u32 == 6 && !strcmp(m_pStageID, "Act_EggmanLand")) - ctx.r4.u32 = 5; - } - - __imp__sub_824DCF38(ctx, base); -} - -#pragma endregion - -#pragma region Player Hooks - -// Dark Gaia energy change hook. -PPC_FUNC_IMPL(__imp__sub_823AF7A8); -PPC_FUNC(sub_823AF7A8) -{ - auto pEvilSonicContext = (SWA::Player::CEvilSonicContext*)g_memory.Translate(ctx.r3.u32); - - m_lastDarkGaiaEnergy = pEvilSonicContext->m_DarkGaiaEnergy; - - // Don't drain energy if out of control. - if (!Config::UnleashOutOfControlDrain && pEvilSonicContext->m_OutOfControlCount && ctx.f1.f64 < 0.0) - return; - - __imp__sub_823AF7A8(ctx, base); - - if (!Config::UnleashCancel) - return; - - auto pInputState = SWA::CInputState::GetInstance(); - - // Don't allow cancelling Unleash if the intro anim is still playing. - if (!pInputState || pEvilSonicContext->m_AnimationID == 39) - return; - - if (pInputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper)) - { - pEvilSonicContext->m_DarkGaiaEnergy = 0.0f; - m_isUnleashCancelled = true; - } -} - -void PostUnleashMidAsmHook(PPCRegister& r30) -{ - if (m_isUnleashCancelled) - { - if (auto pEvilSonicContext = (SWA::Player::CEvilSonicContext*)g_memory.Translate(r30.u32)) - pEvilSonicContext->m_DarkGaiaEnergy = m_lastDarkGaiaEnergy; - - m_isUnleashCancelled = false; - } -} - -#pragma endregion - -#pragma region Miscellaneous Hooks - -bool DisableHintsMidAsmHook() -{ - return !Config::Hints; -} - -bool DisableControlTutorialMidAsmHook() -{ - return !Config::ControlTutorial; -} - -bool DisableEvilControlTutorialMidAsmHook(PPCRegister& r4, PPCRegister& r5) -{ - if (Config::ControlTutorial) - return true; - - // Only allow enemy QTE prompts to get through. - return r4.u32 == 1 && r5.u32 == 1; -} - -void WerehogBattleMusicMidAsmHook(PPCRegister& r11) -{ - if (Config::WerehogBattleMusic) - return; - - // Swap CStateBattle for CStateNormal. - if (r11.u8 == 4) - r11.u8 = 3; -} - -void SetXButtonHomingMidAsmHook(PPCRegister& r30) -{ - r30.u32 = Config::XButtonHoming; -} - -/* Hook function that gets the game region - and force result to zero for Japanese - to display the correct logos. */ -PPC_FUNC_IMPL(__imp__sub_825197C0); -PPC_FUNC(sub_825197C0) -{ - if (Config::Language == ELanguage::Japanese) - { - ctx.r3.u64 = 0; - return; - } - - __imp__sub_825197C0(ctx, base); -} - -void GetStageIDMidAsmHook(PPCRegister& r5) -{ - m_pStageID = *(xpointer*)g_memory.Translate(r5.u32); -} - -// Logo skip -PPC_FUNC_IMPL(__imp__sub_82547DF0); -PPC_FUNC(sub_82547DF0) -{ - if (Config::LogoSkip) - { - ctx.r4.u64 = 0; - ctx.r5.u64 = 0; - ctx.r6.u64 = 1; - ctx.r7.u64 = 0; - sub_825517C8(ctx, base); - } - else - { - __imp__sub_82547DF0(ctx, base); - } -} - -bool MotionBlurMidAsmHook() -{ - return Config::MotionBlur; -} - -#pragma endregion - -#pragma region DLC Hooks - -// CApplicationDocument::LoadArchiveDatabases -PPC_FUNC_IMPL(__imp__sub_824EFD28); -PPC_FUNC(sub_824EFD28) -{ - auto r3 = ctx.r3; - - // CSigninXenon::InitializeDLC - ctx.r3.u64 = PPC_LOAD_U32(r3.u32 + 4) + 200; - ctx.r4.u64 = 0; - sub_822C57D8(ctx, base); - - ctx.r3 = r3; - __imp__sub_824EFD28(ctx, base); -} - -// CFileReaderXenon_DLC::InitializeParallel -PPC_FUNC(sub_822C3778) -{ - if (!PPC_LOAD_U8(0x83361F10)) // ms_DLCInitialized - { - // CFileReaderXenon_DLC::InitializeSerial - sub_822C2CF0(ctx, base); - } -} - -// HasAnyDLC -// NOTE: This is not used outside title screen outro, so it's safe to hook. -PPC_FUNC(sub_82BD06C8) -{ - ctx.r3.u64 = 0; -} - -#pragma endregion - -#pragma region Object Bug Fixes - -// CObjFlame::CObjFlame -// A field is not zero initialized, -// causing collisions to constantly get created -// and slow down the game. -PPC_FUNC_IMPL(__imp__sub_82608E60); -PPC_FUNC(sub_82608E60) -{ - memset(base + ctx.r3.u32, 0, 0x154); - __imp__sub_82608E60(ctx, base); -} - -#pragma endregion - -#pragma region HFR Patches - -void HighFrameRateDeltaTimeFixMidAsmHook(PPCRegister& f1) -{ - // Having 60 FPS threshold ensures we still retain - // the original game behavior when locked to 30/60 FPS. - constexpr double threshold = 1.0 / 60.0; - - if (f1.f64 < threshold) - f1.f64 = threshold; -} - -void CameraDeltaTimeFixMidAsmHook(PPCRegister& dest, PPCRegister& src) -{ - dest.f64 = src.f64 / 30.0; -} - -void CameraDeltaTimeFixMidAsmHook(PPCRegister& dest) -{ - dest.f64 /= 30.0; -} - -static double ComputeLerpFactor(double t, double deltaTime) -{ - // This type of lerp still falls behind when - // playing catch with a constantly moving position. - // The bias helps with approximately bringing it closer. - double fps = 1.0 / deltaTime; - double bias = t * 60.0; - return 1.0 - pow(1.0 - t, (30.0 + bias) / (fps + bias)); -} - -void CameraLerpFixMidAsmHook(PPCRegister& t, PPCRegister& deltaTime) -{ - t.f64 = ComputeLerpFactor(t.f64, deltaTime.f64); -} - -void CameraTargetSideOffsetLerpFixMidAsmHook(PPCVRegister& v13, PPCVRegister& v62, PPCRegister& deltaTime) -{ - float factor = float(ComputeLerpFactor(double(v13.f32[0] * v62.f32[0]), deltaTime.f64)); - - for (size_t i = 0; i < 4; i++) - { - v62.f32[i] = factor; - v13.f32[i] = 1.0f; - } -} - -void Camera2DLerpFixMidAsmHook(PPCRegister& t, PPCRegister& deltaTime) -{ - t.f64 = ComputeLerpFactor(std::min(1.0, t.f64 * 2.0), deltaTime.f64 / 60.0); -} - -void Camera2DSlopeLerpFixMidAsmHook(PPCRegister& t, PPCRegister& deltaTime) -{ - t.f64 = ComputeLerpFactor(t.f64, deltaTime.f64 / 60.0); -} - -#pragma endregion diff --git a/UnleashedRecomp/patches/fps_patches.cpp b/UnleashedRecomp/patches/fps_patches.cpp new file mode 100644 index 0000000..5de2f40 --- /dev/null +++ b/UnleashedRecomp/patches/fps_patches.cpp @@ -0,0 +1,60 @@ +#include +#include "api/SWA.h" +#include "ui/window.h" +#include "config.h" + +void HighFrameRateDeltaTimeFixMidAsmHook(PPCRegister& f1) +{ + // Having 60 FPS threshold ensures we still retain + // the original game behavior when locked to 30/60 FPS. + constexpr double threshold = 1.0 / 60.0; + + if (f1.f64 < threshold) + f1.f64 = threshold; +} + +void CameraDeltaTimeFixMidAsmHook(PPCRegister& dest, PPCRegister& src) +{ + dest.f64 = src.f64 / 30.0; +} + +void CameraDeltaTimeFixMidAsmHook(PPCRegister& dest) +{ + dest.f64 /= 30.0; +} + +static double ComputeLerpFactor(double t, double deltaTime) +{ + // This type of lerp still falls behind when + // playing catch with a constantly moving position. + // The bias helps with approximately bringing it closer. + double fps = 1.0 / deltaTime; + double bias = t * 60.0; + return 1.0 - pow(1.0 - t, (30.0 + bias) / (fps + bias)); +} + +void CameraLerpFixMidAsmHook(PPCRegister& t, PPCRegister& deltaTime) +{ + t.f64 = ComputeLerpFactor(t.f64, deltaTime.f64); +} + +void CameraTargetSideOffsetLerpFixMidAsmHook(PPCVRegister& v13, PPCVRegister& v62, PPCRegister& deltaTime) +{ + float factor = float(ComputeLerpFactor(double(v13.f32[0] * v62.f32[0]), deltaTime.f64)); + + for (size_t i = 0; i < 4; i++) + { + v62.f32[i] = factor; + v13.f32[i] = 1.0f; + } +} + +void Camera2DLerpFixMidAsmHook(PPCRegister& t, PPCRegister& deltaTime) +{ + t.f64 = ComputeLerpFactor(std::min(1.0, t.f64 * 2.0), deltaTime.f64 / 60.0); +} + +void Camera2DSlopeLerpFixMidAsmHook(PPCRegister& t, PPCRegister& deltaTime) +{ + t.f64 = ComputeLerpFactor(t.f64, deltaTime.f64 / 60.0); +} diff --git a/UnleashedRecomp/patches/misc_patches.cpp b/UnleashedRecomp/patches/misc_patches.cpp new file mode 100644 index 0000000..616ee73 --- /dev/null +++ b/UnleashedRecomp/patches/misc_patches.cpp @@ -0,0 +1,71 @@ +#include +#include "api/SWA.h" +#include "ui/window.h" +#include "config.h" + +bool DisableHintsMidAsmHook() +{ + return !Config::Hints; +} + +bool DisableControlTutorialMidAsmHook() +{ + return !Config::ControlTutorial; +} + +bool DisableEvilControlTutorialMidAsmHook(PPCRegister& r4, PPCRegister& r5) +{ + if (Config::ControlTutorial) + return true; + + // Only allow enemy QTE prompts to get through. + return r4.u32 == 1 && r5.u32 == 1; +} + +void WerehogBattleMusicMidAsmHook(PPCRegister& r11) +{ + if (Config::WerehogBattleMusic) + return; + + // Swap CStateBattle for CStateNormal. + if (r11.u8 == 4) + r11.u8 = 3; +} + +void SetXButtonHomingMidAsmHook(PPCRegister& r30) +{ + r30.u32 = Config::XButtonHoming; +} + +/* Hook function that gets the game region + and force result to zero for Japanese + to display the correct logos. */ +PPC_FUNC_IMPL(__imp__sub_825197C0); +PPC_FUNC(sub_825197C0) +{ + if (Config::Language == ELanguage::Japanese) + { + ctx.r3.u64 = 0; + return; + } + + __imp__sub_825197C0(ctx, base); +} + +// Logo skip +PPC_FUNC_IMPL(__imp__sub_82547DF0); +PPC_FUNC(sub_82547DF0) +{ + if (Config::LogoSkip) + { + ctx.r4.u64 = 0; + ctx.r5.u64 = 0; + ctx.r6.u64 = 1; + ctx.r7.u64 = 0; + sub_825517C8(ctx, base); + } + else + { + __imp__sub_82547DF0(ctx, base); + } +} diff --git a/UnleashedRecomp/patches/object_patches.cpp b/UnleashedRecomp/patches/object_patches.cpp new file mode 100644 index 0000000..31b6361 --- /dev/null +++ b/UnleashedRecomp/patches/object_patches.cpp @@ -0,0 +1,12 @@ +#include + +// CObjFlame::CObjFlame +// A field is not zero initialized, +// causing collisions to constantly get created +// and slow down the game. +PPC_FUNC_IMPL(__imp__sub_82608E60); +PPC_FUNC(sub_82608E60) +{ + memset(base + ctx.r3.u32, 0, 0x154); + __imp__sub_82608E60(ctx, base); +} diff --git a/UnleashedRecomp/patches/player_patches.cpp b/UnleashedRecomp/patches/player_patches.cpp new file mode 100644 index 0000000..a926a31 --- /dev/null +++ b/UnleashedRecomp/patches/player_patches.cpp @@ -0,0 +1,91 @@ +#include +#include "api/SWA.h" +#include "config.h" + +uint32_t m_lastCheckpointScore = 0; +float m_lastDarkGaiaEnergy = 0.0f; +bool m_isUnleashCancelled = false; + +/* Hook function for when checkpoints are activated + to preserve the current checkpoint score. */ +PPC_FUNC_IMPL(__imp__sub_82624308); +PPC_FUNC(sub_82624308) +{ + __imp__sub_82624308(ctx, base); + + if (Config::ScoreBehaviour != EScoreBehaviour::CheckpointRetain) + return; + + auto pGameDocument = SWA::CGameDocument::GetInstance(); + + if (!pGameDocument) + return; + + m_lastCheckpointScore = pGameDocument->m_pMember->m_Score; +} + +/* Hook function that resets the score + and restore the last checkpoint score. */ +PPC_FUNC_IMPL(__imp__sub_8245F048); +PPC_FUNC(sub_8245F048) +{ + __imp__sub_8245F048(ctx, base); + + if (Config::ScoreBehaviour != EScoreBehaviour::CheckpointRetain) + return; + + auto pGameDocument = SWA::CGameDocument::GetInstance(); + + if (!pGameDocument) + return; + + printf("[*] Resetting score to %d\n", m_lastCheckpointScore); + + pGameDocument->m_pMember->m_Score = m_lastCheckpointScore; +} + +void ResetScoreOnRestartMidAsmHook() +{ + m_lastCheckpointScore = 0; +} + +// Dark Gaia energy change hook. +PPC_FUNC_IMPL(__imp__sub_823AF7A8); +PPC_FUNC(sub_823AF7A8) +{ + auto pEvilSonicContext = (SWA::Player::CEvilSonicContext*)g_memory.Translate(ctx.r3.u32); + + m_lastDarkGaiaEnergy = pEvilSonicContext->m_DarkGaiaEnergy; + + // Don't drain energy if out of control. + if (!Config::UnleashOutOfControlDrain && pEvilSonicContext->m_OutOfControlCount && ctx.f1.f64 < 0.0) + return; + + __imp__sub_823AF7A8(ctx, base); + + if (!Config::UnleashCancel) + return; + + auto pInputState = SWA::CInputState::GetInstance(); + + // Don't allow cancelling Unleash if the intro anim is still playing. + if (!pInputState || pEvilSonicContext->m_AnimationID == 39) + return; + + if (pInputState->GetPadState().IsTapped(SWA::eKeyState_RightBumper)) + { + pEvilSonicContext->m_DarkGaiaEnergy = 0.0f; + m_isUnleashCancelled = true; + } +} + +void PostUnleashMidAsmHook(PPCRegister& r30) +{ + if (m_isUnleashCancelled) + { + if (auto pEvilSonicContext = (SWA::Player::CEvilSonicContext*)g_memory.Translate(r30.u32)) + pEvilSonicContext->m_DarkGaiaEnergy = m_lastDarkGaiaEnergy; + + m_isUnleashCancelled = false; + } +} diff --git a/UnleashedRecomp/patches/resident_patches.cpp b/UnleashedRecomp/patches/resident_patches.cpp new file mode 100644 index 0000000..36264d0 --- /dev/null +++ b/UnleashedRecomp/patches/resident_patches.cpp @@ -0,0 +1,75 @@ +#include +#include "config.h" + +const char* m_pStageID; + +void GetStageIDMidAsmHook(PPCRegister& r5) +{ + m_pStageID = *(xpointer*)g_memory.Translate(r5.u32); +} + +// Loading screen hook. +PPC_FUNC_IMPL(__imp__sub_824DCF38); +PPC_FUNC(sub_824DCF38) +{ + /* Force the Werehog transition ID + to use a different transition. */ + if (!Config::WerehogHubTransformVideo) + { + /* + 0 - Tails Electric NOW LOADING + 1 - No Transition + 2 - Werehog Transition + 3 - Tails Electric NOW LOADING w/ Info (requires context) + 4 - Arrows In/Out + 5 - NOW LOADING + 6 - Event Gallery + 7 - NOW LOADING + 8 - Black Screen + */ + if (ctx.r4.u32 == 2) + ctx.r4.u32 = 4; + } + + if (m_pStageID) + { + /* Fix restarting Eggmanland as the Werehog + erroneously using the Event Gallery transition. */ + if (ctx.r4.u32 == 6 && !strcmp(m_pStageID, "Act_EggmanLand")) + ctx.r4.u32 = 5; + } + + __imp__sub_824DCF38(ctx, base); +} + +// CApplicationDocument::LoadArchiveDatabases +PPC_FUNC_IMPL(__imp__sub_824EFD28); +PPC_FUNC(sub_824EFD28) +{ + auto r3 = ctx.r3; + + // CSigninXenon::InitializeDLC + ctx.r3.u64 = PPC_LOAD_U32(r3.u32 + 4) + 200; + ctx.r4.u64 = 0; + sub_822C57D8(ctx, base); + + ctx.r3 = r3; + __imp__sub_824EFD28(ctx, base); +} + +// CFileReaderXenon_DLC::InitializeParallel +PPC_FUNC(sub_822C3778) +{ + if (!PPC_LOAD_U8(0x83361F10)) // ms_DLCInitialized + { + // CFileReaderXenon_DLC::InitializeSerial + sub_822C2CF0(ctx, base); + } +} + +// HasAnyDLC +// NOTE: This is not used outside title screen outro, so it's safe to hook. +PPC_FUNC(sub_82BD06C8) +{ + ctx.r3.u64 = 0; +} diff --git a/UnleashedRecomp/patches/video_patches.cpp b/UnleashedRecomp/patches/video_patches.cpp new file mode 100644 index 0000000..8e931b7 --- /dev/null +++ b/UnleashedRecomp/patches/video_patches.cpp @@ -0,0 +1,59 @@ +#include +#include "api/SWA.h" +#include "ui/window.h" +#include "config.h" + +constexpr float m_baseAspectRatio = 16.0f / 9.0f; + +bool CameraAspectRatioMidAsmHook(PPCRegister& r31) +{ + auto pCamera = (SWA::CCamera*)g_memory.Translate(r31.u32); + auto newAspectRatio = (float)Window::s_width / (float)Window::s_height; + + // Dynamically adjust horizontal aspect ratio to window dimensions. + pCamera->m_HorzAspectRatio = newAspectRatio; + + if (auto s_pVertAspectRatio = (be*)g_memory.Translate(0x82028FE0)) + { + // Dynamically adjust vertical aspect ratio for VERT+. + *s_pVertAspectRatio = 2.0f * atan(tan(45.0f / 2.0f) * (m_baseAspectRatio / newAspectRatio)); + } + + // Jump to 4:3 code for VERT+ adjustments if using a narrow aspect ratio. + return newAspectRatio < m_baseAspectRatio; +} + +void CameraBoostAspectRatioMidAsmHook(PPCRegister& r31, PPCRegister& f0) +{ + auto pCamera = (SWA::CCamera*)g_memory.Translate(r31.u32); + + if (Window::s_width < Window::s_height) + { + // Use horizontal FOV for narrow aspect ratios. + f0.f32 = pCamera->m_HorzFieldOfView; + } + else + { + // Use vertical FOV for wide aspect ratios. + f0.f32 = pCamera->m_VertFieldOfView; + } +} + +void CSDAspectRatioMidAsmHook(PPCRegister& f1, PPCRegister& f2) +{ + auto newAspectRatio = (float)Window::s_width / (float)Window::s_height; + + if (newAspectRatio > m_baseAspectRatio) + { + f1.f64 = 1280.0f / ((newAspectRatio * 720.0f) / 1280.0f); + } + else if (newAspectRatio < m_baseAspectRatio) + { + f2.f64 = 720.0f / ((1280.0f / newAspectRatio) / 720.0f); + } +} + +bool MotionBlurMidAsmHook() +{ + return Config::MotionBlur; +} diff --git a/UnleashedRecomp/ui/window.cpp b/UnleashedRecomp/ui/window.cpp index 0ef1ea7..85f87c2 100644 --- a/UnleashedRecomp/ui/window.cpp +++ b/UnleashedRecomp/ui/window.cpp @@ -155,10 +155,10 @@ void Window::Update() { if (!Window::IsFullscreen() && !Window::IsMaximised()) { - Config::WindowWidth = Window::s_width; - Config::WindowHeight = Window::s_height; Config::WindowX = Window::s_x; Config::WindowY = Window::s_y; + Config::WindowWidth = Window::s_width; + Config::WindowHeight = Window::s_height; } }