From 0283493db8e968be67d9e591ec4719fe9d0477f0 Mon Sep 17 00:00:00 2001 From: Dragorn421 Date: Sat, 15 Oct 2022 23:29:36 +0200 Subject: [PATCH] Lightweight trigonometry doc (#1356) * Doc units of trig functions * "Very simple" yet I made a mistake * sins returns in [-0x7FFF,0x7FFF] as the [-1,1] range * Also `sys_math_atan.c` * Remove `@param`s without descriptions * Add note on Math_Atan2S/F arguments being unlike atan2 * "from (1,0) to (x,y)" -> "from vector ..." * arg names -> `angle` * Improve `@return` comment on atans --- include/functions.h | 10 ++--- src/code/code_800FCE80.c | 24 +++++++++-- src/code/sys_math.c | 8 ++++ src/code/sys_math_atan.c | 40 +++++++++++++------ src/code/z_lib.c | 8 ++++ src/libultra/gu/cosf.c | 12 ++++-- src/libultra/gu/coss.c | 4 ++ src/libultra/gu/sinf.c | 16 +++++--- src/libultra/gu/sins.c | 16 +++++--- .../actors/ovl_Boss_Ganon/z_boss_ganon.c | 6 +-- 10 files changed, 104 insertions(+), 40 deletions(-) diff --git a/include/functions.h b/include/functions.h index 95fd407794..977cbc5159 100644 --- a/include/functions.h +++ b/include/functions.h @@ -1945,7 +1945,7 @@ s8 PadUtils_GetRelX(Input* input); s8 PadUtils_GetRelY(Input* input); void PadUtils_UpdateRelXY(Input* input); s32 PadSetup_Init(OSMesgQueue* mq, u8* outMask, OSContStatus* status); -f32 Math_FTanF(f32 x); +f32 Math_FTanF(f32 angle); f32 Math_FFloorF(f32 x); f32 Math_FCeilF(f32 x); f32 Math_FRoundF(f32 x); @@ -2043,8 +2043,8 @@ s32 JpegDecoder_ParseNextSymbol(JpegHuffmanTable* hTable, s16* outCoeff, s8* out u16 JpegDecoder_ReadBits(u8 len); s32 osPfsFreeBlocks(OSPfs* pfs, s32* leftoverBytes); void guScale(Mtx* m, f32 x, f32 y, f32 z); -f32 sinf(f32); -s16 sins(u16); +f32 sinf(f32 angle); +s16 sins(u16 angle); OSTask* _VirtualToPhysicalTask(OSTask* intp); void osSpTaskLoad(OSTask* intp); void osSpTaskStartGo(OSTask* tp); @@ -2108,8 +2108,8 @@ s32 osPfsDeleteFile(OSPfs* pfs, u16 companyCode, u32 gameCode, u8* gameName, u8* s32 __osPfsReleasePages(OSPfs* pfs, __OSInode* inode, u8 initialPage, u8 bank, __OSInodeUnit* finalPage); void guOrthoF(f32[4][4], f32, f32, f32, f32, f32, f32, f32); void guOrtho(Mtx*, f32, f32, f32, f32, f32, f32, f32); -f32 cosf(f32); -s16 coss(u16); +f32 cosf(f32 angle); +s16 coss(u16 angle); void osViSetEvent(OSMesgQueue* mq, OSMesg msg, u32 retraceCount); s32 osPfsIsPlug(OSMesgQueue* mq, u8* pattern); void __osPfsRequestData(u8 cmd); diff --git a/src/code/code_800FCE80.c b/src/code/code_800FCE80.c index 500e2c01d5..3d73123da0 100644 --- a/src/code/code_800FCE80.c +++ b/src/code/code_800FCE80.c @@ -3,9 +3,13 @@ s32 gUseAtanContFrac; -f32 Math_FTanF(f32 x) { - f32 sin = sinf(x); - f32 cos = cosf(x); +/** + * @param angle radians + * @return tan(angle) + */ +f32 Math_FTanF(f32 angle) { + f32 sin = sinf(angle); + f32 cos = cosf(angle); return sin / cos; } @@ -42,7 +46,7 @@ f32 Math_FAtanTaylorQF(f32 x) { const f32* c = coeffs; f32 term; - while (1) { + while (true) { term = *c++ * exp; if (poly + term == poly) { break; @@ -124,6 +128,9 @@ f32 Math_FAtanContFracF(f32 x) { } } +/** + * @return arctan(x) in radians, in (-pi/2,pi/2) range + */ f32 Math_FAtanF(f32 x) { if (!gUseAtanContFrac) { return Math_FAtanTaylorF(x); @@ -132,6 +139,9 @@ f32 Math_FAtanF(f32 x) { } } +/** + * @return angle to (x,y) from vector (1,0) around (0,0) in radians, in (-pi,pi] range + */ f32 Math_FAtan2F(f32 y, f32 x) { if (x == 0.0f) { if (y == 0.0f) { @@ -152,10 +162,16 @@ f32 Math_FAtan2F(f32 y, f32 x) { } } +/** + * @return arcsin(x) in radians, in [-pi/2,pi/2] range + */ f32 Math_FAsinF(f32 x) { return Math_FAtan2F(x, sqrtf(1.0f - SQ(x))); } +/** + * @return arccos(x) in radians, in [0,pi] range + */ f32 Math_FAcosF(f32 x) { return M_PI / 2 - Math_FAsinF(x); } diff --git a/src/code/sys_math.c b/src/code/sys_math.c index 0a85d5cf61..f19719bb95 100644 --- a/src/code/sys_math.c +++ b/src/code/sys_math.c @@ -38,10 +38,18 @@ f32 Math_PowF(f32 base, s32 exp) { return ret; } +/** + * @param angle radians + * @return sin(angle) + */ f32 Math_SinF(f32 angle) { return sins((s16)(angle * (0x7FFF / M_PI))) * SHT_MINV; } +/** + * @param angle radians + * @return cos(angle) + */ f32 Math_CosF(f32 angle) { return coss((s16)(angle * (0x7FFF / M_PI))) * SHT_MINV; } diff --git a/src/code/sys_math_atan.c b/src/code/sys_math_atan.c index 4e346da4ec..efbe8a2055 100644 --- a/src/code/sys_math_atan.c +++ b/src/code/sys_math_atan.c @@ -1,6 +1,6 @@ #include "global.h" -static u16 sATan2Tbl[] = { +static u16 sAtan2Tbl[] = { 0x0000, 0x000A, 0x0014, 0x001F, 0x0029, 0x0033, 0x003D, 0x0047, 0x0051, 0x005C, 0x0066, 0x0070, 0x007A, 0x0084, 0x008F, 0x0099, 0x00A3, 0x00AD, 0x00B7, 0x00C2, 0x00CC, 0x00D6, 0x00E0, 0x00EA, 0x00F4, 0x00FF, 0x0109, 0x0113, 0x011D, 0x0127, 0x0131, 0x013C, 0x0146, 0x0150, 0x015A, 0x0164, 0x016F, 0x0179, 0x0183, 0x018D, 0x0197, 0x01A1, @@ -77,24 +77,34 @@ static u16 sATan2Tbl[] = { 0x1FF6, 0x1FFB, 0x2000, }; -u16 Math_GetAtan2Tbl(f32 x, f32 y) { +/** + * @param y must be >= 0 and <= x + * @param x must be >= 0 + * @return arctan(y/x) as binang, in [0,0x2000] range + */ +u16 Math_GetAtan2Tbl(f32 y, f32 x) { u16 ret; - if (y == 0.0f) { - ret = sATan2Tbl[0]; + if (x == 0.0f) { + ret = sAtan2Tbl[0]; } else { - s32 tblIdx = ((x / y) * 1024.0f) + 0.5f; + s32 tblIdx = ((y / x) * 1024.0f) + 0.5f; - if (tblIdx >= ARRAY_COUNT(sATan2Tbl)) { - ret = sATan2Tbl[0]; + if (tblIdx >= ARRAY_COUNT(sAtan2Tbl)) { + ret = sAtan2Tbl[0]; } else { - ret = sATan2Tbl[tblIdx]; + ret = sAtan2Tbl[tblIdx]; } } return ret; } +/** + * @return angle to (x,y) from vector (1,0) around (0,0) as binang, in [-0x8000,0x7FFF] range + * + * @note The arguments are (x,y), which is different from atan2's (y,x) + */ s16 Math_Atan2S(f32 x, f32 y) { s32 ret; @@ -107,7 +117,7 @@ s16 Math_Atan2S(f32 x, f32 y) { } } else { if (-x < y) { - ret = Math_GetAtan2Tbl(-x, y) + 0x4000; + ret = 0x4000 + Math_GetAtan2Tbl(-x, y); } else { ret = 0x8000 - Math_GetAtan2Tbl(y, -x); } @@ -115,21 +125,27 @@ s16 Math_Atan2S(f32 x, f32 y) { } else { if (x < 0.0f) { if (-y <= -x) { - ret = Math_GetAtan2Tbl(-y, -x) + 0x8000; + ret = 0x8000 + Math_GetAtan2Tbl(-y, -x); } else { ret = 0xC000 - Math_GetAtan2Tbl(-x, -y); } } else { if (x < -y) { - ret = Math_GetAtan2Tbl(x, -y) + 0xC000; + ret = 0xC000 + Math_GetAtan2Tbl(x, -y); } else { ret = -Math_GetAtan2Tbl(-y, x); } } } - return ret; + + return (s16)ret; } +/** + * @return angle to (x,y) from vector (1,0) around (0,0) in radians, in [-pi,pi) range + * + * @note The arguments are (x,y), which is different from atan2's (y,x) + */ f32 Math_Atan2F(f32 x, f32 y) { return BINANG_TO_RAD(Math_Atan2S(x, y)); } diff --git a/src/code/z_lib.c b/src/code/z_lib.c index 3dd0030f07..ac5220ab0b 100644 --- a/src/code/z_lib.c +++ b/src/code/z_lib.c @@ -23,10 +23,18 @@ void Lib_MemSet(u8* dest, size_t len, u8 val) { // clang-format on } +/** + * @param angle binang + * @return cos(angle) + */ f32 Math_CosS(s16 angle) { return coss(angle) * SHT_MINV; } +/** + * @param angle binang + * @return sin(angle) + */ f32 Math_SinS(s16 angle) { return sins(angle) * SHT_MINV; } diff --git a/src/libultra/gu/cosf.c b/src/libultra/gu/cosf.c index cae7159ea8..639084093f 100644 --- a/src/libultra/gu/cosf.c +++ b/src/libultra/gu/cosf.c @@ -14,7 +14,11 @@ static const du pilo = { 0x3E6110B4, 0x611A6263 }; static const fu zero = { 0x00000000 }; -f32 cosf(f32 x) { +/** + * @param angle radians + * @return cos(angle) + */ +f32 cosf(f32 angle) { f32 absx; f64 dx; f64 xSq; @@ -22,13 +26,13 @@ f32 cosf(f32 x) { f64 dn; s32 n; f64 result; - s32 ix = *(s32*)&x; + s32 ix = *(s32*)∠ s32 xpt = (ix >> 22); xpt &= 0x1FF; if (xpt < 0x136) { - absx = (x > 0) ? x : -x; + absx = (angle > 0) ? angle : -angle; dx = absx; dn = dx * rpi.d + 0.5; @@ -51,7 +55,7 @@ f32 cosf(f32 x) { } return -(f32)result; } - if (x != x) { + if (angle != angle) { return __libm_qnan_f; } diff --git a/src/libultra/gu/coss.c b/src/libultra/gu/coss.c index 2dca0234b2..0eb8b5e65d 100644 --- a/src/libultra/gu/coss.c +++ b/src/libultra/gu/coss.c @@ -1,5 +1,9 @@ #include "global.h" +/** + * @param angle binang + * @return cos(angle)*0x7FFF + */ s16 coss(u16 angle) { return sins(angle + 0x4000); } diff --git a/src/libultra/gu/sinf.c b/src/libultra/gu/sinf.c index bb7f58e729..49929e8436 100644 --- a/src/libultra/gu/sinf.c +++ b/src/libultra/gu/sinf.c @@ -14,20 +14,24 @@ static const du pilo = { 0x3E6110B4, 0x611A6263 }; static const fu zero = { 0x00000000 }; -f32 sinf(f32 x) { +/** + * @param angle radians + * @return sin(angle) + */ +f32 sinf(f32 angle) { f64 dx; f64 xSq; f64 polyApprox; f64 dn; s32 n; f64 result; - s32 ix = *(s32*)&x; + s32 ix = *(s32*)∠ s32 xpt = (ix >> 22); xpt &= 0x1FF; if (xpt < 0xFF) { - dx = x; + dx = angle; if (xpt >= 0xE6) { xSq = SQ(dx); @@ -35,11 +39,11 @@ f32 sinf(f32 x) { result = dx + (dx * xSq) * polyApprox; return (f32)result; } - return x; + return angle; } if (xpt < 0x136) { - dx = x; + dx = angle; dn = dx * rpi.d; n = ROUND(dn); dn = n; @@ -57,7 +61,7 @@ f32 sinf(f32 x) { return -(f32)result; } - if (x != x) { + if (angle != angle) { return __libm_qnan_f; } return zero.f; diff --git a/src/libultra/gu/sins.c b/src/libultra/gu/sins.c index b6c2d229a9..636b76bd66 100644 --- a/src/libultra/gu/sins.c +++ b/src/libultra/gu/sins.c @@ -2,18 +2,22 @@ #include "sintable.inc.c" -s16 sins(u16 x) { +/** + * @param angle binang + * @return sin(angle)*0x7FFF + */ +s16 sins(u16 angle) { s16 value; - x >>= 4; + angle >>= 4; - if (x & 0x400) { - value = sintable[0x3FF - (x & 0x3FF)]; + if (angle & 0x400) { + value = sintable[0x3FF - (angle & 0x3FF)]; } else { - value = sintable[x & 0x3FF]; + value = sintable[angle & 0x3FF]; } - if (x & 0x800) { + if (angle & 0x800) { return -value; } else { return value; diff --git a/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c b/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c index 79e1999f3a..3fb7bc7c26 100644 --- a/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c +++ b/src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.c @@ -618,7 +618,7 @@ void BossGanon_IntroCutscene(BossGanon* this, PlayState* play) { this->csCamEye.z = 300.0f; this->csCamAt.x = 0.0f; - this->unk_704 = 1.2566371f; + this->unk_704 = 2 * M_PI / 5; FALLTHROUGH; case 3: this->envLightMode = 0; @@ -3178,8 +3178,8 @@ void BossGanon_Update(Actor* thisx, PlayState* play2) { this->unk_278.y = this->unk_2EC[0].y + 50.0f + 30.0f; this->unk_278.z = this->unk_2EC[0].z; - xOffset = (sinf(i * 1.2566371f) * 600.0f); - zOffset = (cosf(i * 1.2566371f) * 600.0f); + xOffset = (sinf(i * (2 * M_PI / 5)) * 600.0f); + zOffset = (cosf(i * (2 * M_PI / 5)) * 600.0f); // 5 or 6 light balls that go into the charge. not the same as the ones that he throws Actor_SpawnAsChild(&play->actorCtx, &this->actor, play, ACTOR_BOSS_GANON, this->unk_1FC.x + xOffset,