diff --git a/soh/include/functions.h b/soh/include/functions.h index b975ff338..b4bdc9463 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -944,6 +944,8 @@ void Environment_StopStormNatureAmbience(PlayState* play); void Environment_WarpSongLeave(PlayState* play); f32 Math_CosS(s16 angle); f32 Math_SinS(s16 angle); +f32 Math_AccurateCosS(s16 angle); +f32 Math_AccurateSinS(s16 angle); s32 Math_ScaledStepToS(s16* pValue, s16 target, s16 step); s32 Math_StepToS(s16* pValue, s16 target, s16 step); s32 Math_StepToF(f32* pValue, f32 target, f32 step); diff --git a/soh/soh/GameMenuBar.cpp b/soh/soh/GameMenuBar.cpp index f52c9bfee..8977c9030 100644 --- a/soh/soh/GameMenuBar.cpp +++ b/soh/soh/GameMenuBar.cpp @@ -1201,6 +1201,8 @@ namespace GameMenuBar { UIWidgets::Tooltip("Extend certain credits scenes so the music lines up properly with the visuals"); UIWidgets::PaddedEnhancementCheckbox("Fix Gerudo Warrior's clothing colors", "gGerudoWarriorClothingFix", true, false); UIWidgets::Tooltip("Prevent the Gerudo Warrior's clothes changing color when changing Link's tunic or using bombs in front of her"); + UIWidgets::PaddedEnhancementCheckbox("Fix Camera Drift", "gFixCameraDrift", true, false); + UIWidgets::Tooltip("Fixes camera slightly drifting to the left when standing still due to a math error"); ImGui::EndMenu(); } @@ -1376,7 +1378,7 @@ namespace GameMenuBar { UIWidgets::Tooltip("Holding down B skips text"); UIWidgets::PaddedEnhancementCheckbox("Free Camera", "gFreeCamera", true, false); UIWidgets::Tooltip("Enables camera control\nNote: You must remap C buttons off of the right stick in the controller config menu, and map the camera stick to the right stick."); - + #ifdef __SWITCH__ UIWidgets::Spacer(0); int slot = CVar_GetS32("gSwitchPerfMode", (int)Ship::SwitchProfiles::STOCK); diff --git a/soh/src/code/z_camera.c b/soh/src/code/z_camera.c index 0d7df8bbf..af343d8fc 100644 --- a/soh/src/code/z_camera.c +++ b/soh/src/code/z_camera.c @@ -1238,7 +1238,8 @@ f32 Camera_LERPClampDist(Camera* camera, f32 dist, f32 min, f32 max) { } camera->rUpdateRateInv = Camera_LERPCeilF(rUpdateRateInvTarget, camera->rUpdateRateInv, PCT(OREG(25)), 0.1f); - return Camera_LERPCeilF(distTarget, camera->dist, 1.0f / camera->rUpdateRateInv, 0.2f); + return Camera_LERPCeilF(distTarget, camera->dist, 1.0f / camera->rUpdateRateInv, + CVar_GetS32("gFixCameraDrift", 0) ? 0.0f : 0.2f); } f32 Camera_ClampDist(Camera* camera, f32 dist, f32 minDist, f32 maxDist, s16 timer) { @@ -1260,7 +1261,8 @@ f32 Camera_ClampDist(Camera* camera, f32 dist, f32 minDist, f32 maxDist, s16 tim } camera->rUpdateRateInv = Camera_LERPCeilF(rUpdateRateInvTarget, camera->rUpdateRateInv, PCT(OREG(25)), 0.1f); - return Camera_LERPCeilF(distTarget, camera->dist, 1.0f / camera->rUpdateRateInv, 0.2f); + return Camera_LERPCeilF(distTarget, camera->dist, 1.0f / camera->rUpdateRateInv, + CVar_GetS32("gFixCameraDrift", 0) ? 0.0f : 0.2f); } s16 Camera_CalcDefaultPitch(Camera* camera, s16 arg1, s16 arg2, s16 arg3) { diff --git a/soh/src/code/z_lib.c b/soh/src/code/z_lib.c index 1da31eb45..3508fceb7 100644 --- a/soh/src/code/z_lib.c +++ b/soh/src/code/z_lib.c @@ -1,4 +1,5 @@ #include "global.h" +#include f32 Math_CosS(s16 angle) { return coss(angle) * SHT_MINV; @@ -8,6 +9,14 @@ f32 Math_SinS(s16 angle) { return sins(angle) * SHT_MINV; } +f32 Math_AccurateCosS(s16 angle) { + return cosf(DEG_TO_RAD((f32)(angle & 0xFFFC) / SHT_MAX) * 180.0f); +} + +f32 Math_AccurateSinS(s16 angle) { + return sinf(DEG_TO_RAD((f32)(angle & 0xFFFC) / SHT_MAX) * 180.0f); +} + /** * Changes pValue by step (scaled by the update rate) towards target, setting it equal when the target is reached. * Returns true when target is reached, false otherwise. diff --git a/soh/src/code/z_olib.c b/soh/src/code/z_olib.c index 72cd6694b..9446e1dc1 100644 --- a/soh/src/code/z_olib.c +++ b/soh/src/code/z_olib.c @@ -76,12 +76,22 @@ Vec3f* OLib_Vec3fDistNormalize(Vec3f* dest, Vec3f* a, Vec3f* b) { Vec3f* OLib_VecSphToVec3f(Vec3f* dest, VecSph* sph) { Vec3f v; f32 sinPitch; - f32 cosPitch = Math_CosS(sph->pitch); + f32 cosPitch; f32 sinYaw; - f32 cosYaw = Math_CosS(sph->yaw); + f32 cosYaw; - sinPitch = Math_SinS(sph->pitch); - sinYaw = Math_SinS(sph->yaw); + if (CVar_GetS32("gFixCameraDrift", 0)) { + cosPitch = Math_AccurateCosS(sph->pitch); + cosYaw = Math_AccurateCosS(sph->yaw); + sinPitch = Math_AccurateSinS(sph->pitch); + sinYaw = Math_AccurateSinS(sph->yaw); + } else { + cosPitch = Math_CosS(sph->pitch); + cosYaw = Math_CosS(sph->yaw); + sinPitch = Math_SinS(sph->pitch); + sinYaw = Math_SinS(sph->yaw); + } + v.x = sph->r * sinPitch * sinYaw; v.y = sph->r * cosPitch;