summaryrefslogtreecommitdiff
path: root/src/code/z_camera.c
diff options
context:
space:
mode:
authorengineer124 <47598039+engineer124@users.noreply.github.com>2022-08-15 14:36:33 -0400
committerGitHub <noreply@github.com>2022-08-15 14:36:33 -0400
commit0082c299c62ca5debfbaee1ce21d67df7fb0b441 (patch)
tree28ae5ce6384d7d75eabb89861c9ecc821c213310 /src/code/z_camera.c
parent24ba04d70c7e8af692ddaadbe4f356b5c91212c4 (diff)
Decompile Camera Helper Functions (#1023)
* helper functions * more pr suggestions
Diffstat (limited to 'src/code/z_camera.c')
-rw-r--r--src/code/z_camera.c418
1 files changed, 386 insertions, 32 deletions
diff --git a/src/code/z_camera.c b/src/code/z_camera.c
index 20420d6ef..027b78a4a 100644
--- a/src/code/z_camera.c
+++ b/src/code/z_camera.c
@@ -1,42 +1,243 @@
#include "global.h"
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/Camera_fabsf.s")
+/**
+ * Returns the absolute value for floats
+ */
+f32 Camera_fabsf(f32 f) {
+ return ABS(f);
+}
+
+/**
+ * Returns the magnitude for 3D float vectors
+ */
+f32 Camera_Vec3fMagnitude(Vec3f* vec) {
+ return sqrtf(SQ(vec->x) + SQ(vec->y) + SQ(vec->z));
+}
+
+/**
+ * Interpolates along the curve shown below
+ * returns value y ranging from 0.0f to 1.0f for -xMax <= x <= xMax
+ * returns 1.0f otherwise
+ *
+ * y = 1.0f ________ _________
+ * __ __
+ * _ _
+ * y axis _ _
+ * ___ ___
+ * _____
+ * y = 0.0f | | |
+ * -xMax 0 xMax
+ *
+ * x axis
+ */
+f32 Camera_QuadraticAttenuation(f32 xRange, f32 x) {
+ f32 y;
+ f32 absX;
+ f32 percent40 = 0.4f;
+ f32 percent60;
+ f32 xQuadratic;
+ f32 xMaxQuadratic; // Normalizing constant
+
+ absX = Camera_fabsf(x);
+
+ if (absX > xRange) {
+ // fixed value outside xMax range
+ y = 1.0f;
+ } else {
+ // inside xMax range
+ percent60 = 1.0f - percent40;
+
+ if (absX < (xRange * percent60)) {
+ // quadratic curve in the inner 60% of xMax range: +concavity (upward curve)
+ xQuadratic = SQ(x) * (1.0f - percent40);
+ xMaxQuadratic = SQ(xRange * percent60);
+
+ y = xQuadratic / xMaxQuadratic;
+ } else {
+ // quadratic curve in the outer 40% of xMax range: -concavity (flattening curve)
+ xQuadratic = SQ(xRange - absX) * percent40;
+ xMaxQuadratic = SQ(0.4f * xRange);
+
+ y = 1.0f - (xQuadratic / xMaxQuadratic);
+ }
+ }
+ return y;
+}
+
+/*
+ * Performs linear interpoloation between `cur` and `target`. If `cur` is within
+ * `minDiff` units, the result is rounded up to `target`
+ */
+f32 Camera_LerpCeilF(f32 target, f32 cur, f32 stepScale, f32 minDiff) {
+ f32 diff = target - cur;
+ f32 step = diff * stepScale;
+
+ return (Camera_fabsf(diff) >= minDiff) ? cur + step : target;
+}
+
+/*
+ * Performs linear interpoloation between `cur` and `target`. If `cur` is within
+ * `minDiff` units, the result is rounded up to `target`
+ */
+s16 Camera_LerpCeilS(s16 target, s16 cur, f32 stepScale, s16 minDiff) {
+ s16 diff = target - cur;
+ s16 step = diff * stepScale + 0.5f;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/Camera_LengthVec3f.s")
+ return (ABS(diff) >= minDiff) ? cur + step : target;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB270.s")
+/*
+ * Performs linear interpoloation between `cur` and `target`. If `cur` is within
+ * `minDiff` units, the result is rounded down to `cur`
+ */
+s16 Camera_LerpFloorS(s16 target, s16 cur, f32 stepScale, s16 minDiff) {
+ s16 diff = target - cur;
+ s16 step = diff * stepScale + 0.5f;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/Camera_Lerpf.s")
+ return (ABS(diff) >= minDiff) ? cur + step : cur;
+}
+
+/*
+ * Performs linear interpoloation between `cur` and `target`. If `cur` is within
+ * `minDiff` units, the result is rounded up to `target`. Output is written to `cur`
+ */
+void Camera_LerpCeilVec3f(Vec3f* target, Vec3f* cur, f32 xzStepScale, f32 yStepScale, f32 minDiff) {
+ cur->x = Camera_LerpCeilF(target->x, cur->x, xzStepScale, minDiff);
+ cur->y = Camera_LerpCeilF(target->y, cur->y, yStepScale, minDiff);
+ cur->z = Camera_LerpCeilF(target->z, cur->z, xzStepScale, minDiff);
+}
+
+void Camera_SetUpdateRatesFastPitch(Camera* camera) {
+ camera->yawUpdateRateInv = 100.0f;
+ camera->pitchUpdateRateInv = 16.0f;
+ camera->rUpdateRateInv = 20.0f;
+ camera->yOffsetUpdateRate = 0.05f;
+ camera->xzOffsetUpdateRate = 0.05f;
+ camera->fovUpdateRate = 0.05f;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/Camera_Lerps.s")
+void Camera_SetUpdateRatesFastYaw(Camera* camera) {
+ camera->rUpdateRateInv = 50.0f;
+ camera->pitchUpdateRateInv = 100.0f;
+ camera->yawUpdateRateInv = 50.0f;
+ camera->yOffsetUpdateRate = 0.01f;
+ camera->xzOffsetUpdateRate = 0.1f;
+ camera->fovUpdateRate = 0.01f;
+ if (camera->speedRatio > 1.0f) {
+ camera->speedRatio = 1.0f;
+ }
+}
+
+void Camera_SetUpdateRatesSlow(Camera* camera) {
+ camera->rUpdateRateInv = 1800.0f;
+ camera->yawUpdateRateInv = 1800.0f;
+ camera->pitchUpdateRateInv = 1800.0f;
+ camera->yOffsetUpdateRate = 0.01;
+ camera->xzOffsetUpdateRate = 0.01;
+ camera->fovUpdateRate = 0.01;
+}
+
+/**
+ * Converts a 3D s16 vector into a 3D f32 vector
+ */
+Vec3f* Camera_Vec3sToVec3f(Vec3f* dest, Vec3s* src) {
+ Vec3f copy;
+
+ copy.x = src->x;
+ copy.y = src->y;
+ copy.z = src->z;
+
+ *dest = copy;
+ return dest;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB42C.s")
+/**
+ * Returns the difference between two angles and scales the difference up
+ */
+s16 Camera_AngleDiffAndScale(s16 angle1, s16 angle2, f32 scale) {
+ return BINANG_SUB(angle1, angle2) * scale;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/Camera_LerpVec3f.s")
+/**
+ * Calculates the current offset between the camera's at-coordinates and the centered actor's coordinates
+ */
+void Camera_UpdateAtActorOffset(Camera* camera, Vec3f* actorOffset) {
+ camera->atActorOffset.x = camera->at.x - actorOffset->x;
+ camera->atActorOffset.y = camera->at.y - actorOffset->y;
+ camera->atActorOffset.z = camera->at.z - actorOffset->z;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB544.s")
+f32 Camera_GetFocalActorHeight(Camera* camera) {
+ PosRot actorFocus;
+ Actor* focalActor = camera->focalActor;
+ f32 focalHeight;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB584.s")
+ if (focalActor == &GET_PLAYER(camera->play)->actor) {
+ focalHeight = Player_GetHeight((Player*)focalActor);
+ } else {
+ Actor_GetFocus(&actorFocus, focalActor);
+ focalHeight = actorFocus.pos.y - camera->focalActorPosRot.pos.y;
+ if (focalHeight == 0.0f) {
+ focalHeight = 10.0f;
+ }
+ }
+ return focalHeight;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB5DC.s")
+f32 Camera_GetRunSpeedLimit(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
+ f32 runSpeedLimit;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB60C.s")
+ if (focalActor == &GET_PLAYER(camera->play)->actor) {
+ runSpeedLimit = Player_GetRunSpeedLimit((Player*)focalActor);
+ } else {
+ runSpeedLimit = 10.0f;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB674.s")
+ return runSpeedLimit;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB6C8.s")
+s32 func_800CB7CC(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB700.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags3 & PLAYER_STATE3_10;
+ } else {
+ return 0;
+ }
+}
+s32 Camera_IsMountedOnHorse(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB780.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags1 & PLAYER_STATE1_800000;
+ } else {
+ return 0;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB7CC.s")
+s32 Camera_IsDekuHovering(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB7F8.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags3 & PLAYER_STATE3_2000;
+ } else {
+ return 0;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB828.s")
+/**
+ * When walking in a cutscene? Used during Postman's minigame.
+ */
+s32 func_800CB854(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB854.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags1 & PLAYER_STATE1_20;
+ } else {
+ return 0;
+ }
+}
s32 Camera_IsSwimming(Camera* camera) {
Actor* focalActor = camera->focalActor;
@@ -55,31 +256,184 @@ s32 Camera_IsSwimming(Camera* camera) {
}
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB8C8.s")
+s32 Camera_IsDiving(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
+
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags2 & PLAYER_STATE2_800;
+ } else {
+ return 0;
+ }
+}
+
+s32 Camera_IsPlayerFormZora(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
+
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->transformation == PLAYER_FORM_ZORA;
+ } else {
+ return false;
+ }
+}
+
+s32 func_800CB924(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
+
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags3 & PLAYER_STATE3_1000;
+ } else {
+ return 0;
+ }
+}
+
+s32 func_800CB950(Camera* camera) {
+ Player* player;
+ s32 phi_v0;
+ s32 ret;
+ f32 yDiff;
+
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ yDiff = Camera_fabsf(camera->focalActorPosRot.pos.y - camera->playerFloorHeight);
+
+ phi_v0 = false;
+ if (yDiff < 11.0f) {
+ phi_v0 = true;
+ }
+
+ ret = phi_v0;
+
+ if (!ret) {
+
+ ret = false;
+
+ if (camera->focalActor->gravity > -0.1f) {
+ ret = true;
+ }
+
+ player = (Player*)camera->focalActor;
+ if (!ret) {
+ // Using zora fins
+ ret = player->stateFlags1 & PLAYER_STATE1_200000;
+ ret = !!ret;
+ }
+ }
+ return ret;
+ } else {
+ return true;
+ }
+}
+
+s32 Camera_IsClimbingLedge(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
+
+ if (focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags1 & PLAYER_STATE1_4;
+ } else {
+ return 0;
+ }
+}
+
+s32 Camera_IsChargingSwordOrDekuFlowerDive(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
+ s32 ret;
+
+ if (focalActor == &GET_PLAYER(camera->play)->actor) {
+ // Charging Sword
+ ret = !!(((Player*)focalActor)->stateFlags1 & PLAYER_STATE1_1000);
+ if (!ret) {
+ // Deku Flower Dive
+ ret = !!(((Player*)focalActor)->stateFlags3 & PLAYER_STATE3_100);
+ }
+ return ret;
+ } else {
+ return false;
+ }
+}
+
+s32 func_800CBA7C(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
+
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags2 & PLAYER_STATE2_800000;
+ } else {
+ return 0;
+ }
+}
+
+s32 func_800CBAAC(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB8F4.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->meleeWeaponState;
+ } else {
+ return 0;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB924.s")
+s32 Camera_GetFocalActorPos(Vec3f* dst, Camera* camera) {
+ PosRot focalPosRot;
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CB950.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ *dst = ((Player*)focalActor)->bodyPartsPos[0];
+ return dst;
+ } else {
+ Actor_GetWorldPosShapeRot(&focalPosRot, camera->focalActor);
+ *dst = focalPosRot.pos;
+ return dst;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBA08.s")
+s32 Camera_IsUnderwaterAsZora(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBA34.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->currentBoots == PLAYER_BOOTS_ZORA_UNDERWATER;
+ } else {
+ return 0;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBA7C.s")
+/**
+ * Evaluate if player is in one of two sword animations
+ */
+s32 func_800CBB88(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBAAC.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ if ((((Player*)focalActor)->meleeWeaponState != 0) &&
+ (((Player*)focalActor)->meleeWeaponAnimation == PLAYER_MWA_GORON_PUNCH_BUTT)) {
+ return 3;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBAD4.s")
+ if ((((Player*)focalActor)->stateFlags2 & PLAYER_STATE2_20000) ||
+ ((((Player*)focalActor)->meleeWeaponState != 0) &&
+ (((Player*)focalActor)->meleeWeaponAnimation == PLAYER_MWA_ZORA_PUNCH_KICK))) {
+ return 1;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBB58.s")
+ return 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBB88.s")
+s32 Camera_IsUsingZoraFins(Camera* camera) {
+ Actor* focalActor = camera->focalActor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBC00.s")
+ if (camera->focalActor == &GET_PLAYER(camera->play)->actor) {
+ return ((Player*)focalActor)->stateFlags1 & PLAYER_STATE1_200000;
+ } else {
+ return 0;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBC30.s")
+s32 func_800CBC30(Camera* camera, f32 waterYMax, f32 waterYMin) {
+ if ((camera->playerFloorHeight != camera->waterYPos) && (camera->waterYPos < waterYMax) &&
+ (camera->waterYPos > waterYMin)) {
+ return true;
+ } else {
+ return false;
+ }
+}
#pragma GLOBAL_ASM("asm/non_matchings/code/z_camera/func_800CBC84.s")