From 5006de25dc88673b2dd372702df297da0437685a Mon Sep 17 00:00:00 2001 From: Indra Date: Mon, 29 Jan 2024 00:28:14 +0100 Subject: [PATCH] Add free camera impl for TR8 --- src/cdc/math/Math.cpp | 14 +++++ src/cdc/math/Math.h | 9 ++++ src/cdc/math/Matrix.cpp | 10 ++++ src/cdc/math/Matrix.h | 10 ++-- src/game/Camera.cpp | 13 ++++- src/game/Camera.h | 16 +++++- src/input/Input.h | 63 ++++++++++++++++++++++ src/modules/camera/FreeCamera.cpp | 31 +++++++---- src/modules/camera/FreeCamera.h | 31 ++++++++++- src/modules/camera/Legend.cpp | 6 ++- src/modules/camera/Underworld.cpp | 90 +++++++++++++++++++++++++++++++ 11 files changed, 275 insertions(+), 18 deletions(-) create mode 100644 src/cdc/math/Math.cpp create mode 100644 src/cdc/math/Math.h create mode 100644 src/cdc/math/Matrix.cpp create mode 100644 src/modules/camera/Underworld.cpp diff --git a/src/cdc/math/Math.cpp b/src/cdc/math/Math.cpp new file mode 100644 index 0000000..2a73205 --- /dev/null +++ b/src/cdc/math/Math.cpp @@ -0,0 +1,14 @@ +#include "Math.h" + +cdc::Vector3 cdc::Mul3x3(Matrix* matA, Vector3* vecB) +{ + cdc::Vector3 result; + + result.vec128 = _mm_add_ps( + _mm_mul_ps(matA->col0.vec128, _mm_shuffle_ps(vecB->vec128, vecB->vec128, 0)), + _mm_add_ps( + _mm_mul_ps(matA->col1.vec128, _mm_shuffle_ps(vecB->vec128, vecB->vec128, 85)), + _mm_mul_ps(matA->col2.vec128, _mm_shuffle_ps(vecB->vec128, vecB->vec128, 170)))); + + return result; +} \ No newline at end of file diff --git a/src/cdc/math/Math.h b/src/cdc/math/Math.h new file mode 100644 index 0000000..ae34dc4 --- /dev/null +++ b/src/cdc/math/Math.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Vector.h" +#include "Matrix.h" + +namespace cdc +{ + Vector3 Mul3x3(Matrix* matA, Vector3* vecB); +} \ No newline at end of file diff --git a/src/cdc/math/Matrix.cpp b/src/cdc/math/Matrix.cpp new file mode 100644 index 0000000..3dfa8fe --- /dev/null +++ b/src/cdc/math/Matrix.cpp @@ -0,0 +1,10 @@ +#include "Matrix.h" +#include "util/Hooking.h" + +void cdc::Matrix::Build(Euler* euler) +{ + // Too lazy to implement myself + auto addr = GET_ADDRESS(0x000000, 0x000000, 0x49DD70); + + Hooking::ThisCall(addr, this, euler); +} \ No newline at end of file diff --git a/src/cdc/math/Matrix.h b/src/cdc/math/Matrix.h index 91eef5c..9bc7fe3 100644 --- a/src/cdc/math/Matrix.h +++ b/src/cdc/math/Matrix.h @@ -7,9 +7,11 @@ namespace cdc class Matrix { public: - cdc::Vector col0; - cdc::Vector col1; - cdc::Vector col2; - cdc::Vector col3; + Vector col0; + Vector col1; + Vector col2; + Vector col3; + + void Build(Euler* euler); }; } \ No newline at end of file diff --git a/src/game/Camera.cpp b/src/game/Camera.cpp index 9141a89..48893e1 100644 --- a/src/game/Camera.cpp +++ b/src/game/Camera.cpp @@ -3,7 +3,11 @@ Camera* CAMERA_GetCamera() { +#ifndef TR8 return (Camera*)GET_ADDRESS(0x000000, 0x850670, 0x000000); +#else + return *(Camera**)0xE80534; +#endif } void CAMERA_CalcPosition(cdc::Vector3* position, cdc::Vector3* base, cdc::Euler* rotation, float distance) @@ -11,4 +15,11 @@ void CAMERA_CalcPosition(cdc::Vector3* position, cdc::Vector3* base, cdc::Euler* auto addr = GET_ADDRESS(0x48D8B0, 0x491320, 0x000000); Hooking::Call(addr, position, base, rotation, distance); -} \ No newline at end of file +} + +#ifdef TR8 +void CAMERA_SetMode(int mode) +{ + Hooking::Call(0x5F39F0, mode); +} +#endif \ No newline at end of file diff --git a/src/game/Camera.h b/src/game/Camera.h index 1fcc862..5cb34c0 100644 --- a/src/game/Camera.h +++ b/src/game/Camera.h @@ -1,7 +1,9 @@ #pragma once #include "cdc/math/Vector.h" +#include "cdc/math/Matrix.h" +#ifndef TR8 struct CameraCore { cdc::Vector3 position; @@ -18,6 +20,18 @@ struct Camera : CameraCore int lock; __int16 mode; }; +#else +struct Camera +{ + char pad1[16]; + + cdc::Matrix transform; +}; +#endif Camera* CAMERA_GetCamera(); -void CAMERA_CalcPosition(cdc::Vector3* position, cdc::Vector3* base, cdc::Euler* rotation, float distance); \ No newline at end of file +void CAMERA_CalcPosition(cdc::Vector3* position, cdc::Vector3* base, cdc::Euler* rotation, float distance); + +#ifdef TR8 +void CAMERA_SetMode(int mode); +#endif \ No newline at end of file diff --git a/src/input/Input.h b/src/input/Input.h index 4c637d0..398468d 100644 --- a/src/input/Input.h +++ b/src/input/Input.h @@ -1,5 +1,64 @@ #pragma once +enum INPUTACTION +{ + INPUTACTION_NONE, + + INPUTACTION_UP, + INPUTACTION_DOWN, + INPUTACTION_LEFT, + INPUTACTION_RIGHT, + INPUTACTION_DPAD_UP, + INPUTACTION_DPAD_DOWN, + INPUTACTION_DPAD_LEFT, + INPUTACTION_DPAD_RIGHT, + INPUTACTION_START, + INPUTACTION_SELECT, + +#ifndef TR8 + INPUTACTION_TRIANGLE = 16, + INPUTACTION_SQUARE = 17, + INPUTACTION_CIRCLE = 18, + INPUTACTION_CROSS = 19, + INPUTACTION_L1 = 20, + INPUTACTION_R1 = 21, + INPUTACTION_L2 = 22, + INPUTACTION_R2 = 23, + + // Kinda hack, instead we should probably see how to register an input action + // which would also allow rebinding of them, but this will work for now + INPUTACTION_CAMERA_UP = INPUTACTION_TRIANGLE, + INPUTACTION_CAMERA_DOWN = INPUTACTION_SQUARE, + INPUTACTION_CAMERA_FAST = INPUTACTION_CIRCLE, + INPUTACTION_CAMERA_SLOW = INPUTACTION_R2, +#else + INPUTACTION_TRIANGLE = 11, + INPUTACTION_SQUARE = 12, + INPUTACTION_CIRCLE = 13, + INPUTACTION_CROSS = 14, + INPUTACTION_L1 = 15, + INPUTACTION_R1 = 16, + INPUTACTION_L2 = 17, + INPUTACTION_R2 = 18, + + INPUTACTION_CAMERA_UP = INPUTACTION_TRIANGLE, + INPUTACTION_CAMERA_DOWN = INPUTACTION_SQUARE, + INPUTACTION_CAMERA_FAST = INPUTACTION_L2, + INPUTACTION_CAMERA_SLOW = INPUTACTION_CIRCLE, +#endif +}; + +enum INPUTAXIS +{ + INPUTAXIS_LANALOGUEX, + INPUTAXIS_LANALOGUEY, + INPUTAXIS_RANALOGUEX, + INPUTAXIS_RANALOGUEY, + + INPUTAXIS_MOUSEX = 16, + INPUTAXIS_MOUSEY = 17, +}; + class InputActionMapper { public: @@ -7,7 +66,11 @@ class InputActionMapper { unsigned int state; +#ifndef TR8 char pad1[20]; +#else + char pad1[44]; +#endif }; ActionResult* m_pActionResults; diff --git a/src/modules/camera/FreeCamera.cpp b/src/modules/camera/FreeCamera.cpp index 9f2146e..2788151 100644 --- a/src/modules/camera/FreeCamera.cpp +++ b/src/modules/camera/FreeCamera.cpp @@ -42,8 +42,8 @@ void FreeCameraBase::OnControl() auto gameTracker = Game::GetGameTracker(); // Camera rotation based on mouse/controller axis - auto rotX = input->GetAxisValue(17) * gameTracker->timeMult; - auto rotZ = input->GetAxisValue(16) * gameTracker->timeMult; + auto rotX = input->GetAxisValue(INPUTAXIS_MOUSEY) * gameTracker->timeMult; + auto rotZ = input->GetAxisValue(INPUTAXIS_MOUSEX) * gameTracker->timeMult; Rotate(rotX, rotZ); @@ -57,40 +57,51 @@ void FreeCameraBase::OnControl() } // Change the speed depending on if shift/alt is pressed - auto shift = Input::IsInputActionPressed(18); - auto control = Input::IsInputActionPressed(23); + auto shift = Input::IsInputActionPressed(INPUTACTION_CAMERA_FAST); + auto control = Input::IsInputActionPressed(INPUTACTION_CAMERA_SLOW); auto speed = shift ? 200.f : control ? 20.f : 80.f; // Camera forward/backward - if (Input::IsInputActionPressed(1) || Input::IsInputActionPressed(2)) + if (Input::IsInputActionPressed(INPUTACTION_UP) || Input::IsInputActionPressed(INPUTACTION_DOWN)) { - auto distance = Input::IsInputActionPressed(1) ? -speed : speed; + auto distance = Input::IsInputActionPressed(INPUTACTION_UP) ? -speed : speed; MoveForward(distance * gameTracker->timeMult); } // Camera left/right - if (Input::IsInputActionPressed(3) || Input::IsInputActionPressed(4)) + if (Input::IsInputActionPressed(INPUTACTION_LEFT) || Input::IsInputActionPressed(INPUTACTION_RIGHT)) { - auto distance = Input::IsInputActionPressed(3) ? -speed : speed; + auto distance = Input::IsInputActionPressed(INPUTACTION_LEFT) ? -speed : speed; MoveLeft(distance * gameTracker->timeMult); } // Camera up/down - if (Input::IsInputActionPressed(16) || Input::IsInputActionPressed(17)) + if (Input::IsInputActionPressed(INPUTACTION_CAMERA_UP) || Input::IsInputActionPressed(INPUTACTION_CAMERA_DOWN)) { - auto distance = Input::IsInputActionPressed(16) ? -speed : speed; + auto distance = Input::IsInputActionPressed(INPUTACTION_CAMERA_UP) ? -speed : speed; MoveUp(distance * gameTracker->timeMult); } } +#include "Hook.h" +#include "modules/Log.h" + void FreeCameraBase::OnLoop() { if (m_mode == Enabled) { OnControl(); } + + for (int i = 0; i < 100; i++) + { + if (Input::IsInputActionPressed(i)) + { + Hook::GetInstance().GetModule()->WriteLine("%d", i); + } + } } \ No newline at end of file diff --git a/src/modules/camera/FreeCamera.h b/src/modules/camera/FreeCamera.h index 341f0aa..300426c 100644 --- a/src/modules/camera/FreeCamera.h +++ b/src/modules/camera/FreeCamera.h @@ -1,6 +1,7 @@ #pragma once #include "modules/Module.h" +#include "cdc/math/Vector.h" // Base class for both free camera implementations class FreeCameraBase : public Module @@ -36,6 +37,8 @@ class FreeCameraBase : public Module void OnLoop(); }; +#ifndef TR8 + // Free camera implementation for Legend and Anniversary class LegendCamera : public FreeCameraBase { @@ -49,4 +52,30 @@ class LegendCamera : public FreeCameraBase void MoveUp(float distance); }; -using FreeCamera = LegendCamera; \ No newline at end of file +#else + +// Free camera implementation for Underworld +class UnderworldCamera : public FreeCameraBase +{ +private: + cdc::Vector m_position = { }; + cdc::Euler m_rotation = { }; + +protected: + void ToggleMode(); + void OnControl(); + + void Rotate(float x, float z); + void Rotate(float y); + void MoveForward(float distance); + void MoveLeft(float distance); + void MoveUp(float distance); +}; + +#endif + +#ifndef TR8 +using FreeCamera = LegendCamera; +#else +using FreeCamera = UnderworldCamera; +#endif \ No newline at end of file diff --git a/src/modules/camera/Legend.cpp b/src/modules/camera/Legend.cpp index 9521c9a..57fd927 100644 --- a/src/modules/camera/Legend.cpp +++ b/src/modules/camera/Legend.cpp @@ -1,3 +1,5 @@ +#ifndef TR8 + #define _USE_MATH_DEFINES #include @@ -61,4 +63,6 @@ void LegendCamera::MoveUp(float distance) auto camera = CAMERA_GetCamera(); camera->position.z += distance; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/modules/camera/Underworld.cpp b/src/modules/camera/Underworld.cpp new file mode 100644 index 0000000..bd8b7df --- /dev/null +++ b/src/modules/camera/Underworld.cpp @@ -0,0 +1,90 @@ +#if TR8 + +#define _USE_MATH_DEFINES +#include + +#include "FreeCamera.h" +#include "game/Camera.h" +#include "game/Game.h" +#include "util/Hooking.h" +#include "cdc/math/Math.h" + +static cdc::Vector3 RotationToDirection(cdc::Euler* rotation, float distance) +{ + cdc::Matrix m; + m.Build(rotation); + + cdc::Vector3 v = { 0.f, -distance, 0.f }; + + // TODO fixme + return cdc::Mul3x3(&m, &v); +} + +void UnderworldCamera::ToggleMode() +{ + FreeCameraBase::ToggleMode(); + + if (m_mode == Enabled) + { + CAMERA_SetMode(11); + + // Set the camera position to the player position + auto camera = CAMERA_GetCamera(); + camera->transform.col3 = Game::GetPlayerInstance()->position; + } + + if (m_mode == Disabled) + { + // Restore the gameplay camera + Hooking::ThisCall(0x5EDF50, 0xE804F0 /* CameraManager */); + } +} + +void UnderworldCamera::OnControl() +{ + auto camera = CAMERA_GetCamera(); + m_position = camera->transform.col3; + + FreeCameraBase::OnControl(); + + // Apply the rotation and position + camera->transform.Build(&m_rotation); + camera->transform.col3 = m_position; +} + +void UnderworldCamera::Rotate(float x, float z) +{ + m_rotation.x -= x; + m_rotation.z -= z; +} + +void UnderworldCamera::Rotate(float y) +{ + m_rotation.y += y; +} + +void UnderworldCamera::MoveForward(float distance) +{ + auto forward = RotationToDirection(&m_rotation, distance); + + m_position += &forward; +} + +void UnderworldCamera::MoveLeft(float distance) +{ + auto rotation = m_rotation; + rotation.x = 0.f; + rotation.y = 0.f; + rotation.z += static_cast(M_PI) / 2.f; + + auto forward = RotationToDirection(&rotation, distance); + + m_position += &forward; +} + +void UnderworldCamera::MoveUp(float distance) +{ + m_position.z += distance; +} + +#endif \ No newline at end of file