diff --git a/UnleashedRecomp/api/SWA.h b/UnleashedRecomp/api/SWA.h new file mode 100644 index 0000000..cf04961 --- /dev/null +++ b/UnleashedRecomp/api/SWA.h @@ -0,0 +1,8 @@ +#pragma once + +#include "SWA/Camera/Camera.h" +#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h" +#include "SWA/System/ApplicationDocument.h" +#include "SWA/System/GameDocument.h" +#include "SWA/System/InputState.h" +#include "SWA/System/PadState.h" diff --git a/UnleashedRecomp/api/SWA.inl b/UnleashedRecomp/api/SWA.inl new file mode 100644 index 0000000..005c0c8 --- /dev/null +++ b/UnleashedRecomp/api/SWA.inl @@ -0,0 +1,9 @@ +#pragma once + +#include + +#define SWA__CONCAT2(x, y) x##y +#define SWA_CONCAT2(x, y) _CONCAT(x, y) + +#define SWA_INSERT_PADDING(length) \ + uint8_t SWA_CONCAT2(pad, __LINE__)[length] diff --git a/UnleashedRecomp/api/SWA/Camera/Camera.h b/UnleashedRecomp/api/SWA/Camera/Camera.h new file mode 100644 index 0000000..7737d9c --- /dev/null +++ b/UnleashedRecomp/api/SWA/Camera/Camera.h @@ -0,0 +1,19 @@ +#pragma once + +#include "SWA.inl" + +namespace SWA +{ + class CCamera // : public CGameObject, public Hedgehog::Universe::TStateMachine + { + public: + SWA_INSERT_PADDING(0x184); + be m_VertAspectRatio; + SWA_INSERT_PADDING(0x48); + be m_HorzAspectRatio; + SWA_INSERT_PADDING(0x178); + be m_FieldOfView; + be m_VertFieldOfView; + be m_HorzFieldOfView; + }; +} diff --git a/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/EvilSonicContext.h b/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/EvilSonicContext.h new file mode 100644 index 0000000..cd7cce5 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/EvilSonicContext.h @@ -0,0 +1,15 @@ +#pragma once + +#include "SWA.inl" + +namespace SWA::Player +{ + class CEvilSonicContext // : public CPlayerContext + { + public: + SWA_INSERT_PADDING(0x688); + be m_DarkGaiaEnergy; + SWA_INSERT_PADDING(0x138); + be m_AnimationID; + }; +} diff --git a/UnleashedRecomp/api/SWA/System/ApplicationDocument.h b/UnleashedRecomp/api/SWA/System/ApplicationDocument.h new file mode 100644 index 0000000..8dcda66 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/ApplicationDocument.h @@ -0,0 +1,19 @@ +#pragma once + +namespace SWA +{ + class CApplicationDocument // : public Hedgehog::Base::CSynchronizedObject + { + public: + // TODO: Hedgehog::Base::TSynchronizedPtr* + inline static xpointer* ms_pInstance = (xpointer*)g_memory.Translate(0x833678A0); + + // TODO: Hedgehog::Base::TSynchronizedPtr + static CApplicationDocument* GetInstance(); + + SWA_INSERT_PADDING(0x18); + be m_Region; + }; +} + +#include "ApplicationDocument.inl" diff --git a/UnleashedRecomp/api/SWA/System/ApplicationDocument.inl b/UnleashedRecomp/api/SWA/System/ApplicationDocument.inl new file mode 100644 index 0000000..c18e0bc --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/ApplicationDocument.inl @@ -0,0 +1,8 @@ +namespace SWA +{ + // TODO: Hedgehog::Base::TSynchronizedPtr + inline CApplicationDocument* CApplicationDocument::GetInstance() + { + return *ms_pInstance; + } +} \ No newline at end of file diff --git a/UnleashedRecomp/api/SWA/System/GameDocument.h b/UnleashedRecomp/api/SWA/System/GameDocument.h new file mode 100644 index 0000000..78b6e05 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameDocument.h @@ -0,0 +1,26 @@ +#pragma once + +namespace SWA +{ + class CGameDocument // : public Hedgehog::Base::CSynchronizedObject + { + public: + class CMember + { + public: + SWA_INSERT_PADDING(0x20C); + be m_Score; + }; + + // TODO: Hedgehog::Base::TSynchronizedPtr* + inline static xpointer* ms_pInstance = (xpointer*)g_memory.Translate(0x83367900); + + // TODO: Hedgehog::Base::TSynchronizedPtr + static CGameDocument* GetInstance(); + + SWA_INSERT_PADDING(0x08); + xpointer m_pMember; + }; +} + +#include "GameDocument.inl" diff --git a/UnleashedRecomp/api/SWA/System/GameDocument.inl b/UnleashedRecomp/api/SWA/System/GameDocument.inl new file mode 100644 index 0000000..fff5b16 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameDocument.inl @@ -0,0 +1,8 @@ +namespace SWA +{ + // TODO: Hedgehog::Base::TSynchronizedPtr + inline CGameDocument* CGameDocument::GetInstance() + { + return *ms_pInstance; + } +} \ No newline at end of file diff --git a/UnleashedRecomp/api/SWA/System/InputState.h b/UnleashedRecomp/api/SWA/System/InputState.h new file mode 100644 index 0000000..d5dea02 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/InputState.h @@ -0,0 +1,26 @@ +#pragma once + +#include "SWA.inl" +#include "PadState.h" + +namespace SWA +{ + class CInputState // : public Hedgehog::Base::CSynchronizedObject + { + public: + // TODO: Hedgehog::Base::TSynchronizedPtr* + inline static xpointer* ms_pInstance = (xpointer*)g_memory.Translate(0x833671EC); + + // TODO: Hedgehog::Base::TSynchronizedPtr + static CInputState* GetInstance(); + + SPadState m_PadStates[40]; + SWA_INSERT_PADDING(0x50); + be m_CurrentPadStateIndex; + SWA_INSERT_PADDING(0x04); + + const SPadState& GetPadState() const; + }; +} + +#include "InputState.inl" diff --git a/UnleashedRecomp/api/SWA/System/InputState.inl b/UnleashedRecomp/api/SWA/System/InputState.inl new file mode 100644 index 0000000..16b0c99 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/InputState.inl @@ -0,0 +1,13 @@ +namespace SWA +{ + // TODO: Hedgehog::Base::TSynchronizedPtr + inline CInputState* CInputState::GetInstance() + { + return *ms_pInstance; + } + + inline const SPadState& CInputState::GetPadState() const + { + return m_PadStates[m_CurrentPadStateIndex]; + } +} \ No newline at end of file diff --git a/UnleashedRecomp/api/SWA/System/PadState.h b/UnleashedRecomp/api/SWA/System/PadState.h new file mode 100644 index 0000000..eca4a5a --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/PadState.h @@ -0,0 +1,77 @@ +#pragma once + +#include "SWA.inl" + +namespace SWA +{ + enum EKeyState : uint32_t + { + eKeyState_None = 0x0, + + eKeyState_A = 0x1, + eKeyState_B = 0x2, + eKeyState_X = 0x8, + eKeyState_Y = 0x10, + + eKeyState_DpadUp = 0x40, + eKeyState_DpadDown = 0x80, + eKeyState_DpadLeft = 0x100, + eKeyState_DpadRight = 0x200, + + eKeyState_Start = 0x400, + eKeyState_Select = 0x800, + + eKeyState_LeftBumper = 0x1000, + eKeyState_RightBumper = 0x2000, + + eKeyState_LeftTrigger = 0x4000, + eKeyState_RightTrigger = 0x8000, + + eKeyState_LeftStick = 0x10000, + eKeyState_RightStick = 0x20000, + + eKeyState_LeftStickUp = 0x40000, + eKeyState_LeftStickDown = 0x80000, + eKeyState_LeftStickLeft = 0x100000, + eKeyState_LeftStickRight = 0x200000, + + eKeyState_RightStickUp = 0x400000, + eKeyState_RightStickDown = 0x800000, + eKeyState_RightStickLeft = 0x1000000, + eKeyState_RightStickRight = 0x2000000 + }; + + struct SPadState + { + SWA_INSERT_PADDING(0x20); + + be DownState; + be UpState; + be TappedState; + be ReleasedState; + + SWA_INSERT_PADDING(0x04); + + be LeftStickHorizontal; + be LeftStickVertical; + + SWA_INSERT_PADDING(0x04); + + be RightStickHorizontal; + be RightStickVertical; + + SWA_INSERT_PADDING(0x04); + + be LeftTrigger; + be RightTrigger; + + SWA_INSERT_PADDING(0x20); + + bool IsDown(const EKeyState in_Keys) const; + bool IsUp(const EKeyState in_Keys) const; + bool IsTapped(const EKeyState in_Keys) const; + bool IsReleased(const EKeyState in_Keys) const; + }; +} + +#include "PadState.inl" diff --git a/UnleashedRecomp/api/SWA/System/PadState.inl b/UnleashedRecomp/api/SWA/System/PadState.inl new file mode 100644 index 0000000..483bcd1 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/PadState.inl @@ -0,0 +1,22 @@ +namespace SWA +{ + inline bool SPadState::IsDown(const EKeyState in_Keys) const + { + return (DownState & in_Keys) == in_Keys; + } + + inline bool SPadState::IsUp(const EKeyState in_Keys) const + { + return (UpState & in_Keys) == in_Keys; + } + + inline bool SPadState::IsTapped(const EKeyState in_Keys) const + { + return (TappedState & in_Keys) == in_Keys; + } + + inline bool SPadState::IsReleased(const EKeyState in_Keys) const + { + return (ReleasedState & in_Keys) == in_Keys; + } +} \ No newline at end of file diff --git a/UnleashedRecomp/game.cpp b/UnleashedRecomp/game.cpp index cedf0d0..1ae3d0f 100644 --- a/UnleashedRecomp/game.cpp +++ b/UnleashedRecomp/game.cpp @@ -1,5 +1,10 @@ +#include +#include "api/SWA.h" +#include "ui/window.h" #include "game.h" +constexpr float m_baseAspectRatio = 16.0f / 9.0f; + void Game::Exit() { s_isSignalExit = true; @@ -10,3 +15,31 @@ bool GracefulLoopExitMidAsmHook() // TODO (Sajid): investigate XAM handle closing causing assertion failure here. return Game::s_isSignalExit; } + +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 aspect ratio to window dimensions. + pCamera->m_HorzAspectRatio = 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 normal aspect ratios. + f0.f32 = pCamera->m_VertFieldOfView; + } +} diff --git a/UnleashedRecomp/stdafx.h b/UnleashedRecomp/stdafx.h index e081888..bd19ddf 100644 --- a/UnleashedRecomp/stdafx.h +++ b/UnleashedRecomp/stdafx.h @@ -1,6 +1,7 @@ #pragma once #define NOMINMAX + #include #include #include @@ -14,5 +15,5 @@ #include #include "framework.h" -#include "Mutex.h" -#include "Config.h" +#include "mutex.h" +#include "config.h" diff --git a/UnleashedRecomp/ui/window.cpp b/UnleashedRecomp/ui/window.cpp index 3e00a32..226ee8d 100644 --- a/UnleashedRecomp/ui/window.cpp +++ b/UnleashedRecomp/ui/window.cpp @@ -87,7 +87,7 @@ void Window::Init() SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); SDL_AddEventWatch(Window_OnSDLEvent, s_window); - s_window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE); + s_window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Window::s_width, Window::s_height, SDL_WINDOW_RESIZABLE); if (auto icon = GetIconSurface()) { @@ -95,6 +95,7 @@ void Window::Init() SDL_FreeSurface(icon); } + SetWindowDimensions(); SetFullscreen(Config::Fullscreen); SDL_SysWMinfo info; diff --git a/UnleashedRecomp/ui/window.h b/UnleashedRecomp/ui/window.h index ab4d45b..8743981 100644 --- a/UnleashedRecomp/ui/window.h +++ b/UnleashedRecomp/ui/window.h @@ -13,8 +13,8 @@ public: inline static bool s_isFocused; - inline static int s_width; - inline static int s_height; + inline static int s_width = 1280; + inline static int s_height = 720; static SDL_Surface* GetIconSurface(void* pIconBmp = nullptr, size_t iconSize = 0) { @@ -81,7 +81,7 @@ public: } } - static void SetWindowDimensions(int w, int h) + static void SetWindowDimensions(int w = -1, int h = -1) { auto width = w <= 0 ? Config::Width : w; auto height = h <= 0 ? Config::Height : h; @@ -97,6 +97,9 @@ public: SDL_SetWindowMinimumSize(s_window, 640, 480); SDL_SetWindowPosition(s_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + s_width = width; + s_height = height; + if (!isPendingMaximise) return; diff --git a/UnleashedRecompLib/config/SWA.toml b/UnleashedRecompLib/config/SWA.toml index 432ae41..820dd50 100644 --- a/UnleashedRecompLib/config/SWA.toml +++ b/UnleashedRecompLib/config/SWA.toml @@ -107,4 +107,16 @@ registers = ["f13"] [[midasm_hook]] name = "GracefulLoopExitMidAsmHook" address = 0x822C1018 -return_on_true = true \ No newline at end of file +return_on_true = true + +[[midasm_hook]] +name = "CameraAspectRatioMidAsmHook" +address = 0x82468E84 +registers = ["r31"] +jump_address_on_true = 0x82468E88 +jump_address_on_false = 0x82468EE0 + +[[midasm_hook]] +name = "CameraBoostAspectRatioMidAsmHook" +address = 0x8246BDA8 +registers = ["r31", "f0"] \ No newline at end of file