From 95dcc2061137634c579659664146297bbe11c4cb Mon Sep 17 00:00:00 2001 From: praydog Date: Fri, 27 Mar 2020 12:46:05 -0700 Subject: [PATCH] FirstPerson: Fixes to some jankiness FirstPerson: More jank fixes, lock FOV upon entering cutscene (fixes #44) Add Rotate Body, make leaving cutscenes less buggy --- src/CMakeLists.txt | 1 + src/FirstPerson.cpp | 296 ++++++++++++++++++++++++++++++++++-------- src/FirstPerson.hpp | 20 +++ src/PositionHooks.cpp | 13 ++ src/sdk/REMath.hpp | 53 ++++++++ 5 files changed, 330 insertions(+), 53 deletions(-) create mode 100644 src/sdk/REMath.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f870d4a95..478d7826a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,7 @@ set(SDK_SRC sdk/REGlobals.hpp sdk/REGlobals.cpp sdk/REManagedObject.hpp + sdk/REMath.hpp sdk/REString.hpp sdk/RETransform.hpp sdk/RETypes.hpp diff --git a/src/FirstPerson.cpp b/src/FirstPerson.cpp index 833b494d6..b763c5323 100644 --- a/src/FirstPerson.cpp +++ b/src/FirstPerson.cpp @@ -5,6 +5,7 @@ #include "utility/Scan.hpp" #include "REFramework.hpp" +#include "sdk/REMath.hpp" #include "FirstPerson.hpp" @@ -100,6 +101,7 @@ void FirstPerson::on_draw_ui() { ImGui::SameLine(); m_rotate_mesh->draw("Force Rotate Joint"); + m_rotate_body->draw("Rotate Body"); if (m_disable_vignette->draw("Disable Vignette") && m_disable_vignette->value() == false) { set_vignette(via::render::ToneMapping::Vignetting::KerarePlus); @@ -126,6 +128,8 @@ void FirstPerson::on_draw_ui() { m_current_fov->draw("CurrentFOV"); } + m_body_rotate_speed->draw("BodyRotateSpeed"); + if (ImGui::InputText("Joint", m_attach_bone_imgui.data(), 256)) { m_attach_bone = std::wstring{ std::begin(m_attach_bone_imgui), std::end(m_attach_bone_imgui) }; } @@ -161,6 +165,7 @@ void FirstPerson::on_config_save(utility::Config& cfg) { thread_local bool g_in_player_transform = false; thread_local bool g_first_time = true; +thread_local glm::quat g_old_rotation{}; void FirstPerson::on_pre_update_transform(RETransform* transform) { if (!m_enabled->value() || m_camera == nullptr || m_camera->ownerGameObject == nullptr) { @@ -171,22 +176,36 @@ void FirstPerson::on_pre_update_transform(RETransform* transform) { return; } - // can change to action camera - if (!m_show_in_cutscenes->value() && m_camera_system->cameraController != m_player_camera_controller) { - return; - } - // We need to lock a mutex because these UpdateTransform functions // are called from multiple threads if (transform == m_player_transform) { + if (!is_first_person_allowed()) { + return; + } + g_in_player_transform = true; g_first_time = true; m_matrix_mutex.lock(); + + // Update this beforehand so we don't see the player's head disappear when using the inventory + m_last_camera_type = utility::re_managed_object::get_field(m_camera_system, "BusyCameraType"); + m_cached_bone_matrix = nullptr; + + update_player_transform(m_player_transform); } // This is because UpdateTransform recursively calls UpdateTransform on its children, // and the player transform (topmost) is the one that actually updates the bone matrix, // and all the child transforms operate on the bones that it updated else if (g_in_player_transform) { + if (!is_first_person_allowed()) { + return; + } + + /*if (g_first_time) { + g_old_rotation = *(glm::quat*)&m_player_transform->angles; + }*/ + + //update_player_transform(m_player_transform); update_player_bones(m_player_transform); } } @@ -194,7 +213,17 @@ void FirstPerson::on_pre_update_transform(RETransform* transform) { void FirstPerson::on_update_transform(RETransform* transform) { // Do this first before anything else. if (g_in_player_transform && transform == m_player_transform) { + // By also updating this in here, it fixes the out of sync issue sometimes seen for one frame + // where the player body appears slightly ahead of the camera + // This should especially help with frametime fluctuations + if (m_camera_system != nullptr && m_camera_system->mainCamera != nullptr && m_camera_system->mainCamera->ownerGameObject != nullptr) { + update_camera_transform(m_camera_system->mainCamera->ownerGameObject->transform); + } + update_joint_names(); + //update_player_transform(transform); + + //transform->angles = *(Vector4f*)&g_old_rotation; g_in_player_transform = false; m_matrix_mutex.unlock(); @@ -236,11 +265,6 @@ void FirstPerson::on_update_transform(RETransform* transform) { } if (transform == m_camera_system->mainCamera->ownerGameObject->transform) { - // Don't mess with the camera if we're in a cutscene - if (!m_show_in_cutscenes->value() && m_camera_system->cameraController != m_player_camera_controller) { - return; - } - update_camera_transform(transform); update_fov(m_camera_system->cameraController); } @@ -251,23 +275,13 @@ void FirstPerson::on_update_camera_controller(RopewayPlayerCameraController* con return; } - if (!m_show_in_cutscenes->value() && m_camera_system->cameraController != m_player_camera_controller) { + if (!is_first_person_allowed()) { return; } -#ifdef RE3 - // Just update the FOV in here. Whatever. - update_fov(controller); - - // Save the original position and rotation before our modifications. - // If we don't, the camera rotation will freeze up, because it keeps getting overwritten. - m_last_controller_pos = controller->worldPosition; - m_last_controller_rotation = *(glm::quat*)&controller->worldRotation; -#endif - // The following code fixes inaccuracies between the rotation set by the game and what's set in updateCameraTransform controller->worldPosition = m_last_camera_matrix[3]; - *(glm::quat*)&controller->worldRotation = glm::quat{ m_last_camera_matrix }; + *(glm::quat*)&controller->worldRotation = glm::quat{ m_last_camera_matrix }; m_camera->ownerGameObject->transform->worldTransform = m_last_camera_matrix; m_camera->ownerGameObject->transform->angles = *(Vector4f*)&controller->worldRotation; @@ -281,10 +295,26 @@ void FirstPerson::on_update_camera_controller2(RopewayPlayerCameraController* co // Just update the FOV in here. Whatever. update_fov(controller); - // Save the original position and rotation before our modifications. - // If we don't, the camera rotation will freeze up, because it keeps getting overwritten. + if (m_camera_system->cameraController == m_player_camera_controller) { + if (m_ignore_next_player_angles) { + // keep ignoring player input until no longer switching cameras + if (m_ignore_next_player_angles && !utility::re_managed_object::get_field(m_camera_system->mainCameraController, "SwitchingCamera")) { + m_ignore_next_player_angles = false; + } + + *(glm::quat*)&controller->worldRotation = m_last_controller_rotation; + controller->pitch = m_last_controller_angles.x; + controller->yaw = m_last_controller_angles.y; + } + else { + m_ignore_next_player_angles = false; + } + + m_last_controller_angles = Vector3f{ controller->pitch, controller->yaw, 0.0f }; + } + m_last_controller_pos = controller->worldPosition; - m_last_controller_rotation = *(glm::quat*)&controller->worldRotation; + m_last_controller_rotation = *(glm::quat*) & controller->worldRotation; } void FirstPerson::reset() { @@ -294,6 +324,7 @@ void FirstPerson::reset() { m_last_bone_matrix = glm::identity(); m_last_controller_pos = Vector4f{}; m_last_controller_rotation = glm::quat{}; + m_cached_bone_matrix = nullptr; std::lock_guard _{ m_frame_mutex }; m_attach_names.clear(); @@ -384,9 +415,70 @@ bool FirstPerson::update_pointers_from_camera_system(RopewayCameraSystem* camera return true; } +void FirstPerson::update_player_transform(RETransform* transform) { + if (!m_enabled->value() || m_camera_system == nullptr) { + return; + } + + // so we don't go spinning everywhere in cutscenes + if (m_last_camera_type != app::ropeway::camera::CameraControlType::PLAYER) { + return; + } + + if (!m_rotate_body->value()) { + return; + } + + auto& player_matrix = glm::mat4{ *(glm::quat*) & transform->angles }; + + auto player_right = *(Vector3f*)&player_matrix[0] * -1.0f; + player_right[1] = 0.0f; + player_right = glm::normalize(player_right); + auto player_forward = *(Vector3f*)&player_matrix[2] * -1.0f; + player_forward[1] = 0.0f; + player_forward = glm::normalize(player_forward); + + auto camera_matrix = m_last_camera_matrix; + + auto cam_forward3 = *(Vector3f*)&camera_matrix[2]; + + // Remove the upwards facing component of the forward vector + cam_forward3[1] = 0.0f; + cam_forward3 = glm::normalize(cam_forward3); + + auto angle_between = glm::degrees(glm::orientedAngle(player_forward, cam_forward3, Vector3f{ 0.0f, 1.0f, 0.0f })); + + if (std::abs(angle_between) == 0.0f) { + return; + } + + if (angle_between > 0) { + player_right *= -1.0f; + } + + auto angle_diff = std::abs(angle_between) / 720.0f; + auto diff = (player_forward - player_right) * angle_diff * update_delta_time(transform) * m_body_rotate_speed->value(); + + // Create a two-dimensional representation of the forward vector as a rotation matrix + auto rot = glm::lookAtRH(Vector3f{}, glm::normalize(player_forward + diff), Vector3f{ 0.0f, 1.0f, 0.0f }); + camera_matrix = glm::extractMatrixRotation(glm::rowMajor4(rot)); + + auto camera_quat = glm::quat{ camera_matrix }; + + // Finally rotate the player transform to match the camera in a two-dimensional fashion + transform->angles = *(Vector4f*)&camera_quat; +} + void FirstPerson::update_camera_transform(RETransform* transform) { std::lock_guard _{ m_matrix_mutex }; + m_last_camera_type = utility::re_managed_object::get_field(m_camera_system, "BusyCameraType"); + + // Don't mess with the camera if we're in a cutscene + if (!is_first_person_allowed()) { + return; + } + auto delta_time = update_delta_time(transform); auto& mtx = transform->worldTransform; @@ -401,11 +493,45 @@ void FirstPerson::update_camera_transform(RETransform* transform) { 0, 0, 0, 1 }; - auto is_player_camera = m_camera_system->cameraController == m_player_camera_controller; - auto bone_scale = is_player_camera ? (m_bone_scale->value() * 0.01f) : 1.0f; + const auto is_player_camera = m_last_camera_type == app::ropeway::camera::CameraControlType::PLAYER; + const auto is_switching_camera = utility::re_managed_object::get_field(m_camera_system->mainCameraController, "SwitchingCamera"); + const auto is_player_in_control = (is_player_camera && !is_switching_camera); + const auto is_switching_to_player_camera = is_player_camera && is_switching_camera; + //is_player_camera = is_player_camera && !is_switching_camera; + + m_interp_bone_scale = glm::lerp(m_interp_bone_scale, m_bone_scale->value(), std::clamp(delta_time * 0.05f, 0.0f, 1.0f)); + m_interp_camera_speed = glm::lerp(m_interp_camera_speed, m_camera_scale->value(), std::clamp(delta_time * 0.05f, 0.0f, 1.0f)); + + if (is_switching_camera || !is_player_camera) { + if (is_switching_camera) { + m_interp_camera_speed = 100.0f; + + auto c = m_camera_system->mainCameraController; + + if (is_player_camera) { + auto len = c->switchInterpolationTime; + + if (len == 0.0f) { + len = 1.0f; + } + + m_interp_bone_scale = (5.0f / len); + //m_interp_bone_scale = 10.0f; + } + else { + m_interp_bone_scale = 100.0f; + } + } + else { + m_interp_camera_speed = 100.0f; + m_interp_bone_scale = 50.0f; + } + } + + auto bone_scale = (is_player_in_control || is_switching_to_player_camera) ? (m_interp_bone_scale * 0.01f) : 1.0f; // Lets camera modification work in cutscenes/action camera etc - if (!is_player_camera) { + if (!is_player_camera && !is_switching_camera) { m_camera_system->mainCameraController->updateCamera = false; } else { @@ -434,19 +560,29 @@ void FirstPerson::update_camera_transform(RETransform* transform) { + glm::distance(m_interpolated_bone[2], head_rot_mat[2])) / 3.0f; // interpolate the bone rotation (it's snappy otherwise) - m_interpolated_bone = glm::interpolate(m_interpolated_bone, head_rot_mat, delta_time * bone_scale * dist); + if (is_player_in_control || is_switching_to_player_camera) { + m_interpolated_bone = glm::interpolate(m_interpolated_bone, head_rot_mat, delta_time * bone_scale * dist); + } + else { + m_interpolated_bone = head_rot_mat; + } // Look at where the camera is pointing from the head position - cam_rot_mat = glm::extractMatrixRotation(glm::rowMajor4(glm::lookAtLH(final_pos, cam_pos3 + (cam_forward3 * 8192.0f), { 0.0f, 1.0f, 0.0f }))); + cam_rot_mat = glm::extractMatrixRotation(glm::rowMajor4(glm::lookAtLH(final_pos, cam_pos3 + (cam_forward3 * 8192.0f), Vector3f{ 0.0f, 1.0f, 0.0f }))); // Follow the bone rotation, but rotate towards where the camera is looking. auto wanted_mat = glm::inverse(m_interpolated_bone) * cam_rot_mat; - // Average the distance to the wanted rotation - dist = (glm::distance(m_rotation_offset[0], wanted_mat[0]) - + glm::distance(m_rotation_offset[1], wanted_mat[1]) - + glm::distance(m_rotation_offset[2], wanted_mat[2])) / 3.0f; + if (is_player_in_control || is_switching_to_player_camera) { + // Average the distance to the wanted rotation + dist = (glm::distance(m_rotation_offset[0], wanted_mat[0]) + + glm::distance(m_rotation_offset[1], wanted_mat[1]) + + glm::distance(m_rotation_offset[2], wanted_mat[2])) / 3.0f; - m_rotation_offset = glm::interpolate(m_rotation_offset, wanted_mat, delta_time * (m_camera_scale->value() * 0.01f) * dist); + m_rotation_offset = glm::interpolate(m_rotation_offset, wanted_mat, delta_time * (m_interp_camera_speed * 0.01f) * dist); + } + else { + m_rotation_offset = wanted_mat; + } auto final_mat = is_player_camera ? (m_interpolated_bone * m_rotation_offset) : m_interpolated_bone; auto final_quat = glm::quat{ final_mat }; @@ -460,20 +596,46 @@ void FirstPerson::update_camera_transform(RETransform* transform) { // Apply the new matrix *(Matrix3x4f*)&mtx = final_mat; - m_last_camera_matrix = mtx; + + //if (is_player_in_control || !is_player_camera) { + m_last_camera_matrix = mtx; + //} // Fixes snappiness after camera switching - if (!is_player_camera) { + if (!is_player_in_control) { m_last_controller_pos = m_camera_system->cameraController->worldPosition; m_last_controller_rotation = final_quat; m_camera_system->mainCameraController->cameraPosition = m_last_controller_pos; m_camera_system->mainCameraController->cameraRotation = *(Vector4f*)&final_quat; - /*m_playerCameraController->ownerGameObject->transform->position = m_lastControllerPos; - m_playerCameraController->ownerGameObject->transform->angles = *(Vector4f*)&finalQuat; - m_playerCameraController->worldPosition = m_lastControllerPos; - m_playerCameraController->worldRotation = *(Vector4f*)&finalQuat;*/ + //if (!is_switching_to_player_camera) { + m_last_controller_angles = utility::math::euler_angles(final_mat); + //} + + // These are what control the real rotation, so only set it in a cutscene or something + // If we did it all the time, the view would drift constantly + //m_camera_system->cameraController->pitch = m_last_controller_angles.x; + //m_camera_system->cameraController->yaw = m_last_controller_angles.y; + + if (m_player_camera_controller != nullptr) { + m_player_camera_controller->worldPosition = m_camera_system->cameraController->worldPosition; + m_player_camera_controller->worldRotation = m_camera_system->cameraController->worldRotation; + + /*if (m_last_camera_type == app::ropeway::camera::CameraControlType::PLAYER) { + m_last_controller_angles.z = 0.0f; + + m_last_controller_angles += (prev_angles - m_last_controller_angles) * delta_time; + }*/ + + // Forces the game to keep the previous angles/rotation we set after exiting a cutscene + //if (!is_switching_to_player_camera) { + m_player_camera_controller->pitch = m_last_controller_angles.x; + m_player_camera_controller->yaw = m_last_controller_angles.y; + //} + + m_ignore_next_player_angles = !is_switching_to_player_camera; + } } if (transform->joints.size >= 1 && transform->joints.matrices != nullptr) { @@ -494,13 +656,20 @@ void FirstPerson::update_sweet_light_context(RopewaySweetLightManagerContext* ct } void FirstPerson::update_player_bones(RETransform* transform) { - auto& bone_matrix = utility::re_transform::get_joint_matrix(*m_player_transform, m_attach_bone); - if (g_first_time) { + auto& bone_matrix = utility::re_transform::get_joint_matrix(*m_player_transform, m_attach_bone); + + m_cached_bone_matrix = &bone_matrix; m_last_bone_matrix = bone_matrix; g_first_time = false; } + if (m_cached_bone_matrix == nullptr) { + return; + } + + auto& bone_matrix = *m_cached_bone_matrix; + // Forcefully rotate the bone to match the camera direction if (m_camera_system->cameraController == m_player_camera_controller && m_rotate_mesh->value()) { auto wanted_mat = m_last_camera_matrix * Matrix4x4f{ @@ -537,24 +706,36 @@ void FirstPerson::update_fov(RopewayPlayerCameraController* controller) { return; } - if (!m_show_in_cutscenes->value() && m_camera_system->cameraController != m_player_camera_controller) { + if (!is_first_person_allowed()) { return; } if (auto param = controller->cameraParam; param != nullptr) { auto new_value = (param->fov * m_fov_mult->value()) + m_fov_offset->value(); - if (m_fov_mult->value() != m_last_fov_mult) { - auto prev_value = (param->fov * m_last_fov_mult) + m_fov_offset->value(); - auto delta = prev_value - new_value; - - m_fov_offset->value() += delta; - m_camera_system->mainCameraController->mainCamera->fov = (param->fov * m_fov_mult->value()) + m_fov_offset->value(); - controller->activeCamera->fov = m_camera_system->mainCameraController->mainCamera->fov; + if (m_last_camera_type == app::ropeway::camera::CameraControlType::PLAYER) { + if (m_fov_mult->value() != m_last_fov_mult) { + auto prev_value = (param->fov * m_last_fov_mult) + m_fov_offset->value(); + auto delta = prev_value - new_value; + + m_fov_offset->value() += delta; + m_camera_system->mainCameraController->mainCamera->fov = (param->fov * m_fov_mult->value()) + m_fov_offset->value(); + controller->activeCamera->fov = m_camera_system->mainCameraController->mainCamera->fov; + } + else { + m_camera_system->mainCameraController->mainCamera->fov = new_value; + controller->activeCamera->fov = m_camera_system->mainCameraController->mainCamera->fov; + } + + m_last_player_fov = controller->activeCamera->fov; } else { - m_camera_system->mainCameraController->mainCamera->fov = new_value; - controller->activeCamera->fov = m_camera_system->mainCameraController->mainCamera->fov; + if (m_last_player_fov == 0.0f) { + m_last_player_fov = 90.0f; + } + + m_camera_system->mainCameraController->mainCamera->fov = m_last_player_fov; + controller->activeCamera->fov = m_last_player_fov; } // Causes the camera to ignore the FOV inside the param @@ -585,6 +766,15 @@ float FirstPerson::update_delta_time(REComponent* component) { return utility::re_component::get_delta_time(component); } +bool FirstPerson::is_first_person_allowed() const { + // Don't mess with the camera if we're in a cutscene + if (m_show_in_cutscenes->value()) { + return m_allowed_camera_types.count(m_last_camera_type) > 0; + } + + return m_last_camera_type == app::ropeway::camera::CameraControlType::PLAYER; +} + void FirstPerson::on_disabled() { // Disable fov and camera light changes if (m_camera_system != nullptr && m_sweet_light_manager != nullptr) { diff --git a/src/FirstPerson.hpp b/src/FirstPerson.hpp index b4ea67990..c547dc2dc 100644 --- a/src/FirstPerson.hpp +++ b/src/FirstPerson.hpp @@ -35,12 +35,14 @@ class FirstPerson : public Mod { void reset(); void set_vignette(via::render::ToneMapping::Vignetting value); bool update_pointers_from_camera_system(RopewayCameraSystem* camera_system); + void update_player_transform(RETransform* transform); void update_camera_transform(RETransform* transform); void update_sweet_light_context(RopewaySweetLightManagerContext* ctx); void update_player_bones(RETransform* transform); void update_fov(RopewayPlayerCameraController* controller); void update_joint_names(); float update_delta_time(REComponent* component); + bool is_first_person_allowed() const; // Needs to be recursive for some reason. Otherwise freeze. std::recursive_mutex m_matrix_mutex{}; @@ -57,10 +59,25 @@ class FirstPerson : public Mod { Matrix4x4f m_interpolated_bone{ glm::identity() }; Matrix4x4f m_last_bone_matrix{ glm::identity() }; Matrix4x4f m_last_camera_matrix{ glm::identity() }; + Matrix4x4f* m_cached_bone_matrix{ nullptr }; Vector4f m_last_controller_pos{}; glm::quat m_last_controller_rotation{}; + Vector3f m_last_controller_angles{}; + bool m_ignore_next_player_angles{ false }; + app::ropeway::camera::CameraControlType m_last_camera_type{}; + + // Don't show first person when the camera is not one of these + std::unordered_set m_allowed_camera_types{ + app::ropeway::camera::CameraControlType::PLAYER, // normal gameplay + app::ropeway::camera::CameraControlType::EVENT, // cutscene + app::ropeway::camera::CameraControlType::ACTION, // grabbed by zombie or something similar + app::ropeway::camera::CameraControlType::GIMMICK_MOTION, // traversal cutscene + }; + float m_last_player_fov{ 0.0f }; float m_last_fov_mult{ 0.0f }; + float m_interp_camera_speed{ 100.0f }; + float m_interp_bone_scale{ 1.0f }; RETransform* m_player_transform{ nullptr }; RECamera* m_camera{ nullptr }; @@ -84,6 +101,8 @@ class FirstPerson : public Mod { const ModToggle::Ptr m_rotate_mesh{ ModToggle::create(generate_name("ForceRotateMesh"), true) }; const ModToggle::Ptr m_disable_light_source{ ModToggle::create(generate_name("DisableLightSource"), true) }; const ModToggle::Ptr m_show_in_cutscenes{ ModToggle::create(generate_name("ShowInCutscenes"), false) }; + const ModToggle::Ptr m_rotate_body{ ModToggle::create(generate_name("RotateBody"), false) }; + const ModSlider::Ptr m_body_rotate_speed{ ModSlider::create(generate_name("BodyRotateSpeed"), 0.01f, 5.0f, 0.3f) }; const ModSlider::Ptr m_fov_offset{ ModSlider::create(generate_name("FOVOffset"), -100.0f, 100.0f, 10.0f) }; const ModSlider::Ptr m_fov_mult{ ModSlider::create(generate_name("FOVMultiplier"), 0.0f, 2.0f, 1.0f) }; @@ -100,6 +119,7 @@ class FirstPerson : public Mod { *m_disable_vignette, *m_hide_mesh, *m_rotate_mesh, + *m_rotate_body, *m_disable_light_source, *m_show_in_cutscenes, *m_fov_offset, diff --git a/src/PositionHooks.cpp b/src/PositionHooks.cpp index b407c573c..e84e15c3a 100644 --- a/src/PositionHooks.cpp +++ b/src/PositionHooks.cpp @@ -1,6 +1,7 @@ #include "Mods.hpp" #include "REFramework.hpp" #include "utility/Scan.hpp" +#include "utility/Module.hpp" #include "PositionHooks.hpp" @@ -65,6 +66,18 @@ std::optional PositionHooks::on_initialize() { // Version 2 Dec 17th, 2019 game.exe+0x6CD9C0 (works on old version too) auto update_camera_controller2 = utility::scan(game, "40 53 57 48 81 EC ? ? ? ? 48 ? ? ? 48 ? ? 48 ? ? ? ? 00 00"); +#ifdef RE3 + while (update_camera_controller2) { + if (utility::scan(*update_camera_controller2, 0x100, "0F B6 4F 51")) { + break; + } + + update_camera_controller2 = utility::scan(*update_camera_controller2 + 1, + (uint32_t)(*utility::get_module_size(game) - ((*update_camera_controller2 + 1) - (uintptr_t)game)), + "40 53 57 48 81 EC ? ? ? ? 48 ? ? ? 48 ? ? 48 ? ? ? ? 00 00"); + } +#endif + if (!update_camera_controller2) { return "Unable to find UpdateCameraController2 pattern."; } diff --git a/src/sdk/REMath.hpp b/src/sdk/REMath.hpp new file mode 100644 index 000000000..cc6d1851f --- /dev/null +++ b/src/sdk/REMath.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include + +#define GLM_ENABLE_EXPERIMENTAL +#include +#include + +#include "ReClass.hpp" + +namespace utility::math { + using namespace glm; + + static vec3 euler_angles(const glm::mat4& rot); + static float fix_angle(float ang); + static void fix_angles(const glm::vec3& angles); + static float clamp_pitch(float ang); + + // RE engine's way of storing euler angles or I'm just an idiot. + static vec3 euler_angles(const glm::mat4& rot) { + float pitch = 0.0f; + float yaw = 0.0f; + float roll = 0.0f; + glm::extractEulerAngleYZX(rot, yaw, roll, pitch); + + return { pitch, yaw, roll }; + } + + static float fix_angle(float ang) { + auto angDeg = glm::degrees(ang); + + while (angDeg > 180.0f) { + angDeg -= 360.0f; + } + + while (angDeg < -180.0f) { + angDeg += 360.0f; + } + + return glm::radians(angDeg); + } + + static void fix_angles(glm::vec3& angles) { + angles[0] = fix_angle(angles[0]); + angles[1] = fix_angle(angles[1]); + angles[2] = fix_angle(angles[2]); + } + + float clamp_pitch(float ang) { + return std::clamp(ang, glm::radians(-89.0f), glm::radians(89.0f)); + } + +} \ No newline at end of file