summaryrefslogtreecommitdiff
path: root/src/code
diff options
context:
space:
mode:
authorfullgrowngaming <42490167+fullgrowngaming@users.noreply.github.com>2020-10-11 10:31:06 -0700
committerGitHub <noreply@github.com>2020-10-11 13:31:06 -0400
commit1c4a3047dea5649ad703779cdc07854fc623260d (patch)
tree91ab4ca90c73aa3cb25c1b6ec6ff600201b9f952 /src/code
parent96d05d4e7d97dccf7fef335b708307c204e0725a (diff)
z_skelanime OK (#34)
* initial skelanime commit * Skelanime OK * Forgot to add z64animation.h and skelanime.c
Diffstat (limited to 'src/code')
-rw-r--r--src/code/z_skelanime.c1735
1 files changed, 1735 insertions, 0 deletions
diff --git a/src/code/z_skelanime.c b/src/code/z_skelanime.c
new file mode 100644
index 000000000..d7fca3c48
--- /dev/null
+++ b/src/code/z_skelanime.c
@@ -0,0 +1,1735 @@
+#include <ultra64.h>
+#include <global.h>
+
+s32 func_80136288(GlobalContext* globalCtx, SkelAnime* skelAnime);
+s32 func_8013631C(GlobalContext* globalCtx, SkelAnime* skelAnime);
+s32 func_8013702C(SkelAnime* skelAnime);
+s32 func_801370B0(SkelAnime* skelAnime);
+s32 func_8013713C(SkelAnime* skelAnime);
+void SkelAnime_ChangeAnimDefaultRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg);
+void func_80137748(SkelAnime* skelAnime, Vec3f* pos, s16 angle);
+void SkelAnime_ChangeLinkAnim(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimetionEntry* linkAnimetionEntrySeg,
+ f32 playbackSpeed, f32 frame, f32 frameCount, u8 animationMode, f32 transitionRate);
+void SkelAnime_CopyVec3s(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src);
+void SkelAnime_LinkAnimetionLoaded(GlobalContext* globalCtx, AnimationEntryType0* entry);
+void SkelAnime_AnimationType1Loaded(GlobalContext* globalCtx, AnimationEntryType1* entry);
+void SkelAnime_AnimationType2Loaded(GlobalContext* globalCtx, AnimationEntryType2* entry);
+void SkelAnime_AnimationType3Loaded(GlobalContext* globalCtx, AnimationEntryType3* entry);
+void SkelAnime_AnimationType4Loaded(GlobalContext* globalCtx, AnimationEntryType4* entry);
+void SkelAnime_AnimationType5Loaded(GlobalContext* globalCtx, AnimationEntryType5* entry);
+
+static AnimationEntryCallback sAnimationLoadDone[] = {
+ SkelAnime_LinkAnimetionLoaded, SkelAnime_AnimationType1Loaded, SkelAnime_AnimationType2Loaded,
+ SkelAnime_AnimationType3Loaded, SkelAnime_AnimationType4Loaded, SkelAnime_AnimationType5Loaded,
+};
+
+s32 D_801F5AB0;
+s32 D_801F5AB4;
+
+/*
+ * Draws the limb at `limbIndex` with a level of detail display lists index by `dListIndex`
+ */
+void SkelAnime_LodDrawLimb(GlobalContext* globalCtx, s32 limbIndex, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, s32 dListIndex) {
+ SkelLimbEntry* limbEntry;
+ Gfx* dList;
+ Vec3f pos;
+ Vec3s rot;
+ GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
+ s32 pad;
+
+ SysMatrix_StatePush();
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[limbIndex]);
+ limbIndex++;
+ rot = limbDrawTable[limbIndex];
+
+ pos.x = limbEntry->translation.x;
+ pos.y = limbEntry->translation.y;
+ pos.z = limbEntry->translation.z;
+
+ dList = limbEntry->displayLists[dListIndex];
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_AppendStateToPolyOpaDisp(globalCtx->state.gfxCtx), G_MTX_LOAD);
+
+ gSPDisplayList(polyTemp + 1, dList);
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, limbIndex, &dList, &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ SkelAnime_LodDrawLimb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, dListIndex);
+ }
+
+ SysMatrix_StatePop();
+
+ if (limbEntry->nextLimbIndex != LIMB_DONE) {
+ SkelAnime_LodDrawLimb(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, dListIndex);
+ }
+}
+
+/*
+ * Draws the Skeleton described by `skeleton` with a level of detail display list indexed by `dListIndex`
+ */
+void SkelAnime_LodDraw(GlobalContext* globalCtx, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, s32 dListIndex) {
+ SkelLimbEntry* limbEntry;
+ s32 pad;
+ Gfx* dList;
+ Vec3f pos;
+ Vec3s rot;
+ GraphicsContext* gfxCtx;
+ s32 pad2;
+
+ if (skeleton == NULL) {
+ return;
+ }
+
+ gfxCtx = globalCtx->state.gfxCtx;
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[0]);
+ pos.x = limbDrawTable[0].x;
+ pos.y = limbDrawTable[0].y;
+ pos.z = limbDrawTable[0].z;
+
+ rot = limbDrawTable[1];
+ dList = limbEntry->displayLists[dListIndex];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_AppendStateToPolyOpaDisp(globalCtx->state.gfxCtx), G_MTX_LOAD);
+
+ gSPDisplayList(polyTemp + 1, dList);
+
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, 1, &dList, &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != 0xFF) {
+ SkelAnime_LodDrawLimb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, dListIndex);
+ }
+
+ SysMatrix_StatePop();
+}
+
+/*
+ * Draws the limb at `limbIndex` with a level of detail display lists index by `dListIndex`, Limb matrices come
+ * from a dynamic allocation from the graph arena.
+ */
+void SkelAnime_LodDrawLimbSV(GlobalContext* globalCtx, s32 limbIndex, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDrawSV overrideLimbDraw, PostLimbDrawSV postLimbDraw, Actor* actor,
+ s32 dListIndex, RSPMatrix** mtx) {
+ SkelLimbEntry* limbEntry;
+ Gfx* dList[2];
+ Vec3f pos;
+ Vec3s rot;
+ GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
+ s32 pad;
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[limbIndex]);
+ limbIndex++;
+
+ rot = limbDrawTable[limbIndex];
+
+ pos.x = limbEntry->translation.x;
+ pos.y = limbEntry->translation.y;
+ pos.z = limbEntry->translation.z;
+ // Double assignment here would not work.
+ dList[0] = limbEntry->displayLists[dListIndex];
+ dList[1] = dList[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList[1], &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList[1] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(*mtx);
+ gSPMatrix(gfxCtx->polyOpa.p++, *mtx, G_MTX_LOAD);
+ gSPDisplayList(gfxCtx->polyOpa.p++, dList[1]);
+ (*mtx)++;
+ } else if (dList[0] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(*mtx);
+ (*mtx)++;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, limbIndex, &dList[1], &dList[0], &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ SkelAnime_LodDrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, dListIndex, mtx);
+ }
+
+ SysMatrix_StatePop();
+
+ if (limbEntry->nextLimbIndex != LIMB_DONE) {
+ SkelAnime_LodDrawLimbSV(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, dListIndex, mtx);
+ }
+}
+
+/*
+ * Draws the Skeleton described by `skeleton` with a level of detail display list indexed by `dListIndex`
+ * Matricies for the limbs are dynamically allocted from the graph arena. The dynamic allocation occurs
+ * because the Skeleton is too large to be supported by the normal matrix stack.
+ */
+void SkelAnime_LodDrawSV(GlobalContext* globalCtx, Skeleton* skeleton, Vec3s* limbDrawTable, s32 dListCount,
+ OverrideLimbDrawSV overrideLimbDraw, PostLimbDrawSV postLimbDraw, Actor* actor,
+ s32 dListIndex) {
+ SkelLimbEntry* limbEntry;
+ s32 pad;
+ Gfx* dList[2];
+ Vec3f pos;
+ Vec3s rot;
+ RSPMatrix* mtx;
+ GraphicsContext* gfxCtx;
+ s32 pad2;
+
+ mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount));
+
+ if (skeleton == NULL) {
+ return;
+ }
+
+ gfxCtx = globalCtx->state.gfxCtx;
+
+ gSPSegment(gfxCtx->polyOpa.p++, 0xD, mtx);
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[0]);
+ pos.x = limbDrawTable[0].x;
+ pos.y = limbDrawTable[0].y;
+ pos.z = limbDrawTable[0].z;
+
+ rot = limbDrawTable[1];
+
+ dList[0] = limbEntry->displayLists[dListIndex];
+ dList[1] = dList[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList[1], &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList[1] != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD);
+ gSPDisplayList(polyTemp + 1, dList[1]);
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ mtx++;
+ } else if (dList[0] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(mtx);
+ mtx++;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, 1, &dList[1], &dList[0], &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ SkelAnime_LodDrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, dListIndex, &mtx);
+ }
+
+ SysMatrix_StatePop();
+}
+
+/*
+ * Draws the limb of the Skeleton `skeleton` at `limbIndex`
+ */
+void SkelAnime_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor) {
+ SkelLimbEntry* limbEntry;
+ Gfx* dList;
+ Vec3f pos;
+ Vec3s rot;
+ GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
+ s32 pad;
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[limbIndex]);
+ limbIndex++;
+ rot = limbDrawTable[limbIndex];
+ pos.x = limbEntry->translation.x;
+ pos.y = limbEntry->translation.y;
+ pos.z = limbEntry->translation.z;
+ dList = limbEntry->displayLists[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_AppendStateToPolyOpaDisp(globalCtx->state.gfxCtx), G_MTX_LOAD);
+ gSPDisplayList(polyTemp + 1, dList);
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, limbIndex, &dList, &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ SkelAnime_DrawLimb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor);
+ }
+
+ SysMatrix_StatePop();
+
+ if (limbEntry->nextLimbIndex != LIMB_DONE) {
+ SkelAnime_DrawLimb(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw,
+ actor);
+ }
+}
+
+void SkelAnime_Draw(GlobalContext* globalCtx, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor) {
+ SkelLimbEntry* rootLimb;
+ s32 pad;
+ Gfx* dList;
+ Vec3f pos;
+ Vec3s rot;
+ GraphicsContext* gfxCtx;
+ s32 pad2;
+
+ if (skeleton == NULL) {
+ return;
+ }
+
+ gfxCtx = globalCtx->state.gfxCtx;
+
+ SysMatrix_StatePush();
+ rootLimb = Lib_PtrSegToVirt(skeleton->limbs[0]);
+
+ pos.x = limbDrawTable[0].x;
+ pos.y = limbDrawTable[0].y;
+ pos.z = limbDrawTable[0].z;
+
+ rot = limbDrawTable[1];
+ dList = rootLimb->displayLists[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_AppendStateToPolyOpaDisp(globalCtx->state.gfxCtx), G_MTX_LOAD);
+ gSPDisplayList(polyTemp + 1, dList);
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, 1, &dList, &rot, actor);
+ }
+
+ if (rootLimb->firstChildIndex != LIMB_DONE) {
+ SkelAnime_DrawLimb(globalCtx, rootLimb->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor);
+ }
+
+ SysMatrix_StatePop();
+}
+
+void SkelAnime_DrawLimbSV(GlobalContext* globalCtx, s32 limbIndex, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor,
+ RSPMatrix** limbMatricies) {
+ SkelLimbEntry* limbEntry;
+ Gfx* dList[2];
+ Vec3f pos;
+ Vec3s rot;
+ GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
+ s32 pad;
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[limbIndex]);
+ limbIndex++;
+ rot = limbDrawTable[limbIndex];
+
+ pos.x = limbEntry->translation.x;
+ pos.y = limbEntry->translation.y;
+ pos.z = limbEntry->translation.z;
+
+ dList[0] = limbEntry->displayLists[0];
+ dList[1] = dList[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList[1], &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList[1] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(*limbMatricies);
+ gSPMatrix(gfxCtx->polyOpa.p++, *limbMatricies, G_MTX_LOAD);
+ gSPDisplayList(gfxCtx->polyOpa.p++, dList[1]);
+ (*limbMatricies)++;
+ } else if (dList[0] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(*limbMatricies);
+ (*limbMatricies)++;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, limbIndex, &dList[0], &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ SkelAnime_DrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, limbMatricies);
+ }
+
+ SysMatrix_StatePop();
+
+ if (limbEntry->nextLimbIndex != LIMB_DONE) {
+ SkelAnime_DrawLimbSV(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, limbMatricies);
+ }
+}
+
+void SkelAnime_DrawSV(GlobalContext* globalCtx, Skeleton* skeleton, Vec3s* limbDrawTable, s32 dListCount,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor) {
+ SkelLimbEntry* limbEntry;
+ s32 pad;
+ Gfx* dList[2];
+ Vec3f pos;
+ Vec3s rot;
+ RSPMatrix* mtx;
+ GraphicsContext* gfxCtx;
+ s32 pad2;
+
+ mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount));
+
+ if (skeleton == NULL) {
+ return;
+ }
+
+ gfxCtx = globalCtx->state.gfxCtx;
+
+ gSPSegment(gfxCtx->polyOpa.p++, 0xD, mtx);
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[0]);
+
+ pos.x = limbDrawTable[0].x;
+ pos.y = limbDrawTable[0].y;
+ pos.z = limbDrawTable[0].z;
+ rot = limbDrawTable[1];
+
+ dList[0] = limbEntry->displayLists[0];
+ dList[1] = dList[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList[1], &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList[1] != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD);
+ gSPDisplayList(polyTemp + 1, dList[1]);
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ mtx++;
+ } else {
+ if (dList[0] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(mtx);
+ mtx++;
+ }
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, 1, &dList[0], &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ SkelAnime_DrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, &mtx);
+ }
+
+ SysMatrix_StatePop();
+}
+
+void func_80134148(GlobalContext* globalCtx, s32 limbIndex, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, UnkActorDraw unkDraw, Actor* actor,
+ RSPMatrix** mtx) {
+ SkelLimbEntry* limbEntry;
+ Gfx* dList[2];
+ Vec3f pos;
+ Vec3s rot;
+ GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
+ s32 pad2;
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[limbIndex]);
+ limbIndex++;
+
+ rot = limbDrawTable[limbIndex];
+ pos.x = limbEntry->translation.x;
+ pos.y = limbEntry->translation.y;
+ pos.z = limbEntry->translation.z;
+
+ dList[0] = limbEntry->displayLists[0];
+ dList[1] = dList[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList[1], &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ SysMatrix_StatePush();
+ unkDraw(globalCtx, limbIndex, actor);
+ if (dList[1] != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(*mtx), G_MTX_LOAD);
+ gSPDisplayList(polyTemp + 1, dList[1]);
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ (*mtx)++;
+ } else {
+ if (dList[0] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(*mtx);
+ (*mtx)++;
+ }
+ }
+ SysMatrix_StatePop();
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, limbIndex, &dList[0], &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ func_80134148(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw,
+ unkDraw, actor, mtx);
+ }
+
+ SysMatrix_StatePop();
+
+ if (limbEntry->nextLimbIndex != LIMB_DONE) {
+ func_80134148(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw,
+ unkDraw, actor, mtx);
+ }
+}
+
+void func_801343C0(GlobalContext* globalCtx, Skeleton* skeleton, Vec3s* limbDrawTable, s32 dListCount,
+ OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, UnkActorDraw unkDraw, Actor* actor) {
+ SkelLimbEntry* limbEntry;
+ s32 pad;
+ Gfx* dList[2];
+ Vec3f pos;
+ Vec3s rot;
+ RSPMatrix* mtx;
+ GraphicsContext* gfxCtx;
+ s32 pad2;
+
+ if (skeleton == NULL) {
+ return;
+ }
+
+ gfxCtx = globalCtx->state.gfxCtx;
+
+ mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount));
+
+ gSPSegment(gfxCtx->polyOpa.p++, 0xD, mtx);
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[0]);
+
+ pos.x = limbDrawTable[0].x;
+ pos.y = limbDrawTable[0].y;
+ pos.z = limbDrawTable[0].z;
+ rot = limbDrawTable[1];
+
+ dList[0] = limbEntry->displayLists[0];
+ dList[1] = dList[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList[1], &pos, &rot, actor) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ SysMatrix_StatePush();
+ unkDraw(globalCtx, 1, actor);
+ if (dList[1] != NULL) {
+ Gfx* polyTemp = gfxCtx->polyOpa.p;
+
+ gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD);
+ gSPDisplayList(polyTemp + 1, dList[1]);
+ gfxCtx->polyOpa.p = polyTemp + 2;
+ mtx++;
+ } else {
+ if (dList[0] != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(mtx++);
+ }
+ }
+ SysMatrix_StatePop();
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, 1, &dList[0], &rot, actor);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ func_80134148(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw,
+ unkDraw, actor, &mtx);
+ }
+
+ SysMatrix_StatePop();
+}
+
+/*
+ * Copies the rotation values from the rotation value table, indexed by the rotation index table
+ * When a rotation index is >= the animation limit, the output rotation value is copied from the frame's
+ * rotation value list, otherwise it is copied from the initial rotation value list
+ */
+void SkelAnime_AnimateFrame(AnimationHeader* animationSeg, s32 currentFrame, s32 limbCount, Vec3s* dst) {
+ AnimationHeader* animationHeader = Lib_PtrSegToVirt(animationSeg);
+ AnimationRotationIndex* index = Lib_PtrSegToVirt(animationHeader->rotationIndexSeg);
+ AnimationRotationValue* rotationValueTable = Lib_PtrSegToVirt(animationHeader->rotationValueSeg);
+ AnimationRotationValue* frameRotationValueTable = &rotationValueTable[currentFrame];
+ s32 i;
+ u16 limit = animationHeader->limit;
+
+ for (i = 0; i < limbCount; i++) {
+ // Debug prints here, this is needed to prevent loop unrolling
+ if (0) {
+ if (0) {};
+ }
+ dst->x = index->x >= limit ? frameRotationValueTable[index->x] : rotationValueTable[index->x];
+ dst->y = index->y >= limit ? frameRotationValueTable[index->y] : rotationValueTable[index->y];
+ dst->z = index->z >= limit ? frameRotationValueTable[index->z] : rotationValueTable[index->z];
+ index++, dst++;
+ }
+}
+
+s16 SkelAnime_GetTotalFrames(GenericAnimationHeader* animationSeg) {
+ GenericAnimationHeader* animation = Lib_PtrSegToVirt(animationSeg);
+ return animation->frameCount;
+}
+
+s16 SkelAnime_GetFrameCount(GenericAnimationHeader* animationSeg) {
+ GenericAnimationHeader* animation = Lib_PtrSegToVirt(animationSeg);
+
+ return (u16)animation->frameCount - 1;
+}
+
+/*
+ * Draws the Skeleton `skeleton`'s limb at index `limbIndex`. Appends all generated graphics commands to
+ * `gfx`. Returns a pointer to the next gfx to be appended to.
+ */
+Gfx* SkelAnime_Draw2Limb(GlobalContext* globalCtx, s32 limbIndex, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor, Gfx* gfx) {
+ SkelLimbEntry* limbEntry;
+ Gfx* dList;
+ Vec3f pos;
+ Vec3s rot;
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[limbIndex]);
+ limbIndex++;
+
+ rot = limbDrawTable[limbIndex];
+ pos.x = limbEntry->translation.x;
+ pos.y = limbEntry->translation.y;
+ pos.z = limbEntry->translation.z;
+
+ dList = limbEntry->displayLists[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor, &gfx) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList != NULL) {
+ gSPMatrix(gfx, SysMatrix_AppendStateToPolyOpaDisp(globalCtx->state.gfxCtx), G_MTX_LOAD);
+ gSPDisplayList(gfx + 1, dList);
+ gfx = gfx + 2;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, limbIndex, &dList, &rot, actor, &gfx);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ gfx = SkelAnime_Draw2Limb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, gfx);
+ }
+
+ SysMatrix_StatePop();
+
+ if (limbEntry->nextLimbIndex != LIMB_DONE) {
+ gfx = SkelAnime_Draw2Limb(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, gfx);
+ }
+
+ return gfx;
+}
+
+/*
+ * Draws the Skeleton `skeleton` Appends all generated graphics to `gfx`, and returns a pointer to the
+ * next gfx to be appended to.
+ */
+Gfx* SkelAnime_Draw2(GlobalContext* globalCtx, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor, Gfx* gfx) {
+ SkelLimbEntry* limbEntry;
+ s32 pad;
+ Gfx* dList;
+ Vec3f pos;
+ Vec3s rot;
+
+ if (skeleton == NULL) {
+ return NULL;
+ }
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[0]);
+
+ pos.x = limbDrawTable[0].x;
+ pos.y = limbDrawTable[0].y;
+ pos.z = limbDrawTable[0].z;
+ rot = limbDrawTable[1];
+
+ dList = limbEntry->displayLists[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor, &gfx) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList != NULL) {
+ gSPMatrix(gfx, SysMatrix_AppendStateToPolyOpaDisp(globalCtx->state.gfxCtx), G_MTX_LOAD);
+ gSPDisplayList(gfx + 1, dList);
+ gfx = gfx + 2;
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, 1, &dList, &rot, actor, &gfx);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ gfx = SkelAnime_Draw2Limb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, gfx);
+ }
+
+ SysMatrix_StatePop();
+
+ return gfx;
+}
+
+/*
+ * Draws the Skeleton `skeleton` Appends all generated graphics to `gfx`, and returns a pointer to the
+ * next gfx to be appended to. Allocates matricies for display lists on the graph heap.
+ */
+Gfx* SkelAnime_DrawLimbSV2(GlobalContext* globalCtx, s32 limbIndex, Skeleton* skeleton, Vec3s* limbDrawTable,
+ OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor,
+ RSPMatrix** mtx, Gfx* gfx) {
+ SkelLimbEntry* limbEntry;
+ Gfx* dList1;
+ Gfx* dList2;
+ Vec3f pos;
+ Vec3s rot;
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[limbIndex]);
+ limbIndex++;
+ rot = limbDrawTable[limbIndex];
+
+ pos.x = limbEntry->translation.x;
+ pos.y = limbEntry->translation.y;
+ pos.z = limbEntry->translation.z;
+
+ dList1 = dList2 = limbEntry->displayLists[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList1, &pos, &rot, actor, &gfx) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList1 != NULL) {
+ gSPMatrix(gfx, SysMatrix_GetStateAsRSPMatrix(*mtx), G_MTX_LOAD);
+ gSPDisplayList(gfx + 1, dList1);
+ gfx = gfx + 2;
+ (*mtx)++;
+ } else {
+ if (dList2 != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(*mtx);
+ (*mtx)++;
+ }
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, limbIndex, &dList2, &rot, actor, &gfx);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ gfx = SkelAnime_DrawLimbSV2(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, mtx, gfx);
+ }
+
+ SysMatrix_StatePop();
+
+ if (limbEntry->nextLimbIndex != LIMB_DONE) {
+ gfx = SkelAnime_DrawLimbSV2(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, mtx, gfx);
+ }
+
+ return gfx;
+}
+
+Gfx* SkelAnime_DrawSV2(GlobalContext* globalCtx, Skeleton* skeleton, Vec3s* limbDrawTable, s32 dListCount,
+ OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor, Gfx* gfx) {
+ SkelLimbEntry* limbEntry;
+ s32 pad;
+ Gfx* dList1;
+ Gfx* dList2;
+ Vec3f pos;
+ Vec3s rot;
+ RSPMatrix* mtx;
+
+ if (skeleton == NULL) {
+ return NULL;
+ }
+
+ mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount));
+
+ gSPSegment(gfx++, 0xD, mtx);
+
+ SysMatrix_StatePush();
+
+ limbEntry = Lib_PtrSegToVirt(skeleton->limbs[0]);
+
+ pos.x = limbDrawTable[0].x;
+ pos.y = limbDrawTable[0].y;
+ pos.z = limbDrawTable[0].z;
+
+ rot = limbDrawTable[1];
+
+ dList1 = dList2 = limbEntry->displayLists[0];
+
+ if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList1, &pos, &rot, actor, &gfx) == 0)) {
+ SysMatrix_RotateAndTranslateState(&pos, &rot);
+ if (dList1 != NULL) {
+ gSPMatrix(gfx, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD);
+ gSPDisplayList(gfx + 1, dList1);
+ gfx = gfx + 2;
+ mtx++;
+ } else {
+ if (dList2 != NULL) {
+ SysMatrix_GetStateAsRSPMatrix(mtx);
+ mtx++;
+ }
+ }
+ }
+
+ if (postLimbDraw != NULL) {
+ postLimbDraw(globalCtx, 1, &dList2, &rot, actor, &gfx);
+ }
+
+ if (limbEntry->firstChildIndex != LIMB_DONE) {
+ gfx = SkelAnime_DrawLimbSV2(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw,
+ postLimbDraw, actor, &mtx, gfx);
+ }
+
+ SysMatrix_StatePop();
+
+ return gfx;
+}
+
+//Function is unused.
+GLOBAL_ASM("asm/non_matchings/z_skelanime/func_80134FFC.asm")
+
+s16 func_801353D4(GenericAnimationHeader* animationSeg) {
+ GenericAnimationHeader* animation = Lib_PtrSegToVirt(animationSeg);
+
+ return animation->unk02;
+}
+
+/*
+ * Appears to be unused anywhere in the game. Appears to be a clone of
+ * SkelAnime_GetTotalFrames
+ */
+s16 SkelAnime_GetTotalFrames2(GenericAnimationHeader* animationSeg) {
+ GenericAnimationHeader* animation = Lib_PtrSegToVirt(animationSeg);
+
+ return animation->frameCount;
+}
+
+/*
+ * Appears to be unused anywhere in the game. Appears to be a clone of
+ * SkelAnime_GetFrameCount
+ */
+s16 SkelAnime_GetFrameCount2(GenericAnimationHeader* animationSeg) {
+ GenericAnimationHeader* animation = Lib_PtrSegToVirt(animationSeg);
+
+ return animation->frameCount - 1;
+}
+
+void SkelAnime_InterpolateVec3s(s32 limbCount, Vec3s* dst, Vec3s* vec2, Vec3s* vec3, f32 unkf) {
+ s32 i;
+ s16 dist;
+ s16 temp2;
+
+ if (unkf < 1.0f) {
+ for (i = 0; i < limbCount; i++, dst++, vec2++, vec3++) {
+ temp2 = vec2->x;
+ dist = vec3->x - temp2;
+ dst->x = (s16)(dist * unkf) + temp2;
+ temp2 = vec2->y;
+ dist = vec3->y - temp2;
+ dst->y = (s16)(dist * unkf) + temp2;
+ temp2 = vec2->z;
+ dist = vec3->z - temp2;
+ dst->z = (s16)(dist * unkf) + temp2;
+ }
+ } else {
+ for (i = 0; i < limbCount; i++, dst++, vec3++) {
+ dst->x = vec3->x;
+ dst->y = vec3->y;
+ dst->z = vec3->z;
+ }
+ }
+}
+
+void SkelAnime_AnimationCtxReset(AnimationContext* animationCtx) {
+ animationCtx->animationCount = 0;
+}
+
+void func_801358D4(GlobalContext* globalCtx) {
+ D_801F5AB0 *= 2;
+}
+
+void func_801358F4(GlobalContext* globalCtx) {
+ D_801F5AB4 |= D_801F5AB0;
+}
+
+AnimationEntry* SkelAnime_NextEntry(AnimationContext* animationCtx, AnimationType type) {
+ AnimationEntry* entry;
+ s16 index = animationCtx->animationCount;
+
+ if (index >= ANIMATION_ENTRY_MAX) {
+ return NULL;
+ }
+
+ animationCtx->animationCount = index + 1;
+ entry = &animationCtx->entries[index];
+ entry->type = type;
+ return entry;
+}
+
+/*
+ * The next 6 functions are coordinate with the AnimationType enum
+ */
+
+void SkelAnime_LoadLinkAnimetion(GlobalContext* globalCtx, LinkAnimetionEntry* linkAnimetionSeg, s32 frame,
+ s32 limbCount, void* ram) {
+ AnimationEntry* entry;
+ LinkAnimetionEntry* linkAnimetionEntry;
+ s32 pad;
+
+ entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_LINKANIMETION);
+
+ if (entry != NULL) {
+ linkAnimetionEntry = Lib_PtrSegToVirt(linkAnimetionSeg);
+ osCreateMesgQueue(&entry->types.type0.msgQueue, &entry->types.type0.msg, 1);
+ DmaMgr_SendRequestImpl(
+ &entry->types.type0.req, ram,
+ LINK_ANIMETION_OFFSET(linkAnimetionEntry->animationSegAddress, (sizeof(Vec3s) * limbCount + 2) * frame),
+ sizeof(Vec3s) * limbCount + 2, 0, &entry->types.type0.msgQueue, NULL);
+ }
+}
+
+void SkelAnime_LoadAnimationType1(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src) {
+ AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE1);
+
+ if (entry != NULL) {
+ entry->types.type1.unk00 = D_801F5AB0;
+ entry->types.type1.vecCount = vecCount;
+ entry->types.type1.dst = dst;
+ entry->types.type1.src = src;
+ }
+}
+
+void SkelAnime_LoadAnimationType2(GlobalContext* globalCtx, s32 limbCount, Vec3s* arg2, Vec3s* arg3, f32 arg4) {
+ AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE2);
+
+ if (entry != NULL) {
+ entry->types.type2.unk00 = D_801F5AB0;
+ entry->types.type2.limbCount = limbCount;
+ entry->types.type2.unk04 = arg2;
+ entry->types.type2.unk08 = arg3;
+ entry->types.type2.unk0C = arg4;
+ }
+}
+
+void SkelAnime_LoadAnimationType3(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src, u8* index) {
+ AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE3);
+
+ if (entry != NULL) {
+ entry->types.type3.unk00 = D_801F5AB0;
+ entry->types.type3.vecCount = vecCount;
+ entry->types.type3.dst = dst;
+ entry->types.type3.src = src;
+ entry->types.type3.index = index;
+ }
+}
+
+void SkelAnime_LoadAnimationType4(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src, u8* index) {
+ AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE4);
+
+ if (entry != NULL) {
+ entry->types.type4.unk00 = D_801F5AB0;
+ entry->types.type4.vecCount = vecCount;
+ entry->types.type4.dst = dst;
+ entry->types.type4.src = src;
+ entry->types.type4.index = index;
+ }
+}
+
+void SkelAnime_LoadAnimationType5(GlobalContext* globalCtx, Actor* actor, SkelAnime* skelAnime, f32 arg3) {
+ AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE5);
+
+ if (entry != NULL) {
+ entry->types.type5.actor = actor;
+ entry->types.type5.skelAnime = skelAnime;
+ entry->types.type5.unk08 = arg3;
+ }
+}
+
+/* The next functions are callbacks to loading animations */
+
+void SkelAnime_LinkAnimetionLoaded(GlobalContext* globalCtx, AnimationEntryType0* entry) {
+ osRecvMesg(&entry->msgQueue, NULL, OS_MESG_BLOCK);
+}
+
+void SkelAnime_AnimationType1Loaded(GlobalContext* globalCtx, AnimationEntryType1* entry) {
+ s32 i;
+ Vec3s* dst;
+ Vec3s* src;
+ AnimationEntryRaw* genericEntry = (AnimationEntryRaw*)entry;
+
+ if ((genericEntry->raw[0] & D_801F5AB4) != 0) {
+ return;
+ }
+
+ for (dst = entry->dst, src = entry->src, i = 0; i < genericEntry->raw[1]; i++) {
+ *dst++ = *src++;
+ }
+}
+
+void SkelAnime_AnimationType2Loaded(GlobalContext* globalCtx, AnimationEntryType2* entry) {
+ if ((entry->unk00 & D_801F5AB4) == 0) {
+ SkelAnime_InterpolateVec3s(entry->limbCount, entry->unk04, entry->unk04, entry->unk08, entry->unk0C);
+ }
+}
+
+void SkelAnime_AnimationType3Loaded(GlobalContext* globalCtx, AnimationEntryType3* entry) {
+ s32 i;
+ Vec3s* dst;
+ Vec3s* src;
+ u8* index;
+ AnimationEntryRaw* rawEntry = (AnimationEntryRaw*)entry;
+
+ if ((rawEntry->raw[0] & D_801F5AB4) == 0) {
+ for (dst = entry->dst, src = entry->src, index = entry->index, i = 0; i < rawEntry->raw[1]; i++, dst++, src++) {
+ if (*index++) {
+ *dst = *src;
+ }
+ }
+ }
+}
+
+void SkelAnime_AnimationType4Loaded(GlobalContext* globalCtx, AnimationEntryType4* entry) {
+ s32 i;
+ Vec3s* dst;
+ Vec3s* src;
+ u8* index;
+ AnimationEntryRaw* rawEntry = (AnimationEntryRaw*)entry;
+
+ if ((rawEntry->raw[0] & D_801F5AB4) == 0) {
+ for (dst = entry->dst, src = entry->src, index = entry->index, i = 0; i < rawEntry->raw[1]; i++, dst++, src++) {
+ if (*index++ < 1U) {
+ *dst = *src;
+ }
+ }
+ }
+}
+
+void SkelAnime_AnimationType5Loaded(GlobalContext* globalCtx, AnimationEntryType5* entry) {
+ s32 pad;
+ Actor* actor = entry->actor;
+ Vec3f pos;
+
+ func_80137748(entry->skelAnime, &pos, actor->shape.rot.y);
+ actor->currPosRot.pos.x += (pos.x * actor->scale.x) * entry->unk08;
+ actor->currPosRot.pos.y += (pos.y * actor->scale.y) * entry->unk08;
+ actor->currPosRot.pos.z += (pos.z * actor->scale.z) * entry->unk08;
+}
+
+void func_80135EE8(GlobalContext* globalCtx, AnimationContext* animationCtx) {
+ AnimationEntry* entry = animationCtx->entries;
+
+ for (; animationCtx->animationCount != 0; entry++, animationCtx->animationCount--) {
+ sAnimationLoadDone[entry->type](globalCtx, &entry->types);
+ }
+
+ D_801F5AB0 = 1;
+ D_801F5AB4 = 0;
+}
+
+void SkelAnime_InitLinkAnimetion(GlobalContext* globalCtx, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg,
+ LinkAnimetionEntry* linkAnimetionEntrySeg, s32 flags, Vec3s* limbDrawTbl,
+ Vec3s* transitionDrawTbl, s32 limbBufCount) {
+ SkeletonHeader* skeletonHeader;
+ s32 headerCount;
+ s32 limbCount;
+ u32 allocSize;
+
+ skeletonHeader = Lib_PtrSegToVirt(skeletonHeaderSeg);
+ headerCount = skeletonHeader->limbCount;
+ skelAnime->initFlags = flags;
+ limbCount = (flags & 2) ? headerCount : 1;
+
+ if (flags & 1) {
+ limbCount += headerCount;
+ }
+
+ if (flags & 4) {
+ limbCount += headerCount;
+ }
+
+ skelAnime->limbCount = limbCount;
+ skelAnime->dListCount = skeletonHeader->dListCount;
+ skelAnime->skeleton = Lib_PtrSegToVirt(skeletonHeader->skeletonSeg);
+ allocSize = sizeof(Vec3s) * limbCount;
+
+ if (flags & 8) {
+ allocSize += 2;
+ }
+
+ if (limbDrawTbl == NULL) {
+ skelAnime->limbDrawTbl = zelda_malloc(allocSize);
+ skelAnime->transitionDrawTbl = zelda_malloc(allocSize);
+ } else {
+ skelAnime->limbDrawTbl = (Vec3s*)ALIGN16((u32)limbDrawTbl);
+ skelAnime->transitionDrawTbl = (Vec3s*)ALIGN16((u32)transitionDrawTbl);
+ }
+
+ SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimetionEntrySeg, 1.0f, 0.0f, 0.0f, 0, 0.0f);
+}
+
+void func_801360A8(SkelAnime* skelAnime) {
+ if (skelAnime->mode < 2) {
+ skelAnime->animUpdate = func_80136288;
+ } else {
+ skelAnime->animUpdate = func_8013631C;
+ }
+ skelAnime->transCurrentFrame = 0.0f;
+}
+
+s32 func_801360E0(GlobalContext* globalCtx, SkelAnime* skelAnime) {
+ return skelAnime->animUpdate(globalCtx, skelAnime);
+}
+
+s32 func_80136104(GlobalContext* globalCtx, SkelAnime* skelAnime) {
+ f32 prevUnk28 = skelAnime->transCurrentFrame;
+ f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f;
+
+ skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate;
+ if (skelAnime->transCurrentFrame <= 0.0f) {
+ func_801360A8(skelAnime);
+ }
+
+ SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->transitionDrawTbl,
+ 1.0f - (skelAnime->transCurrentFrame / prevUnk28));
+ return 0;
+}
+
+void func_801361BC(GlobalContext* globalCtx, SkelAnime* skelAnime) {
+ SkelAnime_LoadLinkAnimetion(globalCtx, skelAnime->linkAnimetionSeg, skelAnime->animCurrentFrame,
+ skelAnime->limbCount, skelAnime->limbDrawTbl);
+ if (skelAnime->transCurrentFrame != 0) {
+ f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f;
+ skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate;
+ if (skelAnime->transCurrentFrame <= 0.0f) {
+ skelAnime->transCurrentFrame = 0.0f;
+ } else {
+ SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl,
+ skelAnime->transitionDrawTbl, skelAnime->transCurrentFrame);
+ }
+ }
+}
+
+s32 func_80136288(GlobalContext* globalCtx, SkelAnime* skelAnime) {
+ f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f;
+
+ skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate;
+ if (skelAnime->animCurrentFrame < 0.0f) {
+ skelAnime->animCurrentFrame += skelAnime->totalFrames;
+ } else if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) {
+ skelAnime->animCurrentFrame -= skelAnime->totalFrames;
+ }
+ func_801361BC(globalCtx, skelAnime);
+ return 0;
+}
+
+s32 func_8013631C(GlobalContext* globalCtx, SkelAnime* skelAnime) {
+ f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f;
+
+ if (skelAnime->animCurrentFrame == skelAnime->animFrameCount) {
+ func_801361BC(globalCtx, skelAnime);
+ return 1;
+ }
+
+ skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate;
+
+ if (((skelAnime->animCurrentFrame - skelAnime->animFrameCount) * skelAnime->animPlaybackSpeed) > 0.0f) {
+ skelAnime->animCurrentFrame = skelAnime->animFrameCount;
+ } else {
+ if (skelAnime->animCurrentFrame < 0.0f) {
+ skelAnime->animCurrentFrame += skelAnime->totalFrames;
+ } else if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) {
+ skelAnime->animCurrentFrame -= skelAnime->totalFrames;
+ }
+ }
+ func_801361BC(globalCtx, skelAnime);
+ return 0;
+}
+
+void SkelAnime_SetTransition(GlobalContext* globalCtx, SkelAnime* skelAnime, f32 transitionRate) {
+ skelAnime->transCurrentFrame = 1.0f;
+ skelAnime->transitionStep = 1.0f / transitionRate;
+}
+
+void SkelAnime_ChangeLinkAnim(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimetionEntry* linkAnimetionEntrySeg,
+ f32 playbackSpeed, f32 frame, f32 frameCount, u8 animationMode, f32 transitionRate) {
+ skelAnime->mode = animationMode;
+ if ((transitionRate != 0.0f) &&
+ ((linkAnimetionEntrySeg != skelAnime->linkAnimetionSeg) || (frame != skelAnime->animCurrentFrame))) {
+ if (transitionRate < 0) {
+ func_801360A8(skelAnime);
+ SkelAnime_CopyVec3s(skelAnime, skelAnime->transitionDrawTbl, skelAnime->limbDrawTbl);
+ transitionRate = -transitionRate;
+ } else {
+ skelAnime->animUpdate = func_80136104;
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg, (s32)frame, skelAnime->limbCount,
+ skelAnime->transitionDrawTbl);
+ }
+ skelAnime->transCurrentFrame = 1.0f;
+ skelAnime->transitionStep = 1.0f / transitionRate;
+ } else {
+ func_801360A8(skelAnime);
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg, (s32)frame, skelAnime->limbCount,
+ skelAnime->limbDrawTbl);
+ skelAnime->transCurrentFrame = 0.0f;
+ }
+
+ skelAnime->linkAnimetionSeg = linkAnimetionEntrySeg;
+ skelAnime->animCurrentFrame = 0.0f;
+ skelAnime->initialFrame = frame;
+ skelAnime->animCurrentFrame = frame;
+ skelAnime->animFrameCount = frameCount;
+ skelAnime->totalFrames = SkelAnime_GetTotalFrames(linkAnimetionEntrySeg);
+ skelAnime->animPlaybackSpeed = playbackSpeed;
+}
+
+void SkelAnime_ChangeLinkAnimDefaultStop(GlobalContext* globalCtx, SkelAnime* skelAnime,
+ LinkAnimetionEntry* linkAnimetionEntrySeg) {
+ SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimetionEntrySeg, 1.0f, 0.0f,
+ SkelAnime_GetFrameCount(&linkAnimetionEntrySeg->genericHeader), 2, 0.0f);
+}
+
+void SkelAnime_ChangeLinkAnimPlaybackStop(GlobalContext* globalCtx, SkelAnime* skelAnime,
+ LinkAnimetionEntry* linkAnimetionEntrySeg, f32 playbackSpeed) {
+ SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimetionEntrySeg, playbackSpeed, 0.0f,
+ SkelAnime_GetFrameCount(&linkAnimetionEntrySeg->genericHeader), 2, 0.0f);
+}
+
+void SkelAnime_ChangeLinkAnimDefaultRepeat(GlobalContext* globalCtx, SkelAnime* skelAnime,
+ LinkAnimetionEntry* linkAnimetionEntrySeg) {
+ SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimetionEntrySeg, 1.0f, 0.0f,
+ SkelAnime_GetFrameCount(&linkAnimetionEntrySeg->genericHeader), 0, 0.0f);
+}
+
+void SkelAnime_ChangeLinkAnimPlaybackRepeat(GlobalContext* globalCtx, SkelAnime* skelAnime,
+ LinkAnimetionEntry* linkAnimetionEntrySeg, f32 playbackSpeed) {
+ SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimetionEntrySeg, playbackSpeed, 0.0f,
+ SkelAnime_GetFrameCount(&linkAnimetionEntrySeg->genericHeader), 0, 0.0f);
+}
+
+void func_8013670C(GlobalContext* globalCtx, SkelAnime* skelAnime) {
+ SkelAnime_LoadAnimationType1(globalCtx, skelAnime->limbCount, skelAnime->transitionDrawTbl, skelAnime->limbDrawTbl);
+}
+
+void func_8013673C(GlobalContext* globalCtx, SkelAnime* skelAnime) {
+ SkelAnime_LoadAnimationType1(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->transitionDrawTbl);
+}
+
+void func_8013676C(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimetionEntry* linkAnimetionEntrySeg,
+ f32 frame) {
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg, (s32)frame, skelAnime->limbCount,
+ skelAnime->transitionDrawTbl);
+}
+
+void func_801367B0(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimetionEntry* linkAnimetionEntrySeg,
+ f32 frame) {
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg, (s32)frame, skelAnime->limbCount,
+ skelAnime->limbDrawTbl);
+}
+
+void func_801367F4(GlobalContext* globalCtx, SkelAnime* skelAnime, f32 frame) {
+ SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->transitionDrawTbl,
+ frame);
+}
+
+void func_8013682C(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimetionEntry* linkAnimetionEntrySeg,
+ f32 transitionFrame, LinkAnimetionEntry* linkAnimetionEntrySeg2, f32 frame, f32 transitionRate,
+ Vec3s* limbDrawTbl) {
+ Vec3s* alignedLimbDrawTbl;
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg, (s32)transitionFrame, skelAnime->limbCount,
+ skelAnime->limbDrawTbl);
+
+ alignedLimbDrawTbl = (Vec3s*)ALIGN16((u32)limbDrawTbl);
+
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg2, (s32)frame, skelAnime->limbCount,
+ alignedLimbDrawTbl);
+ SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, alignedLimbDrawTbl,
+ transitionRate);
+}
+
+void func_801368CC(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimetionEntry* linkAnimetionEntrySeg,
+ f32 transitionFrame, LinkAnimetionEntry* linkAnimetionEntrySeg2, f32 frame, f32 transitionRate,
+ Vec3s* limbDrawTbl) {
+ Vec3s* alignedLimbDrawTbl;
+
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg, (s32)transitionFrame, skelAnime->limbCount,
+ skelAnime->transitionDrawTbl);
+
+ alignedLimbDrawTbl = (Vec3s*)ALIGN16((u32)limbDrawTbl);
+
+ SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimetionEntrySeg2, (s32)frame, skelAnime->limbCount,
+ alignedLimbDrawTbl);
+ SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->transitionDrawTbl, alignedLimbDrawTbl,
+ transitionRate);
+}
+
+void SkelAnime_SetModeStop(SkelAnime* skelAnime) {
+ skelAnime->mode = 2;
+ func_801360A8(skelAnime);
+}
+
+s32 func_80136990(SkelAnime* skelAnime, f32 arg1, f32 updateRate) {
+ f32 updateSpeed;
+ f32 temp_f12;
+ f32 nextFrame;
+
+ updateSpeed = skelAnime->animPlaybackSpeed * updateRate;
+ nextFrame = skelAnime->animCurrentFrame - updateSpeed;
+ if (nextFrame < 0.0f) {
+ nextFrame += skelAnime->totalFrames;
+ } else if (skelAnime->totalFrames <= nextFrame) {
+ nextFrame -= skelAnime->totalFrames;
+ }
+
+ if ((arg1 == 0.0f) && (updateSpeed > 0.0f)) {
+ arg1 = skelAnime->totalFrames;
+ }
+
+ temp_f12 = (nextFrame + updateSpeed) - arg1;
+ if ((0.0f <= (temp_f12 * updateSpeed)) && (((temp_f12 - updateSpeed) * updateSpeed) < 0.0f)) {
+ return 1;
+ }
+ return 0;
+}
+
+s32 func_80136A48(SkelAnime* skelAnime, f32 arg1) {
+ f32 updateRate = gFramerateDivisorHalf;
+
+ return func_80136990(skelAnime, arg1, updateRate);
+}
+
+void SkelAnime_Init(GlobalContext* globalCtx, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg,
+ AnimationHeader* animationSeg, Vec3s* limbDrawTbl, Vec3s* transitionDrawTable, s32 limbCount) {
+ SkeletonHeader* skeletonHeader;
+
+ skeletonHeader = Lib_PtrSegToVirt(skeletonHeaderSeg);
+ skelAnime->limbCount = skeletonHeader->limbCount + 1;
+ skelAnime->skeleton = Lib_PtrSegToVirt(skeletonHeader->skeletonSeg);
+ if (limbDrawTbl == NULL) {
+ skelAnime->limbDrawTbl = zelda_malloc(sizeof(*skelAnime->limbDrawTbl) * skelAnime->limbCount);
+ skelAnime->transitionDrawTbl = zelda_malloc(sizeof(*skelAnime->transitionDrawTbl) * skelAnime->limbCount);
+ } else {
+ skelAnime->limbDrawTbl = limbDrawTbl;
+ skelAnime->transitionDrawTbl = transitionDrawTable;
+ }
+
+ if (animationSeg != NULL) {
+ SkelAnime_ChangeAnimDefaultRepeat(skelAnime, animationSeg);
+ }
+}
+
+void SkelAnime_InitSV(GlobalContext* globalCtx, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg,
+ AnimationHeader* animationSeg, Vec3s* limbDrawTbl, Vec3s* transitionDrawTable, s32 limbCount) {
+ SkeletonHeader* skeletonHeader;
+
+ skeletonHeader = Lib_PtrSegToVirt(skeletonHeaderSeg);
+ skelAnime->limbCount = skeletonHeader->limbCount + 1;
+ skelAnime->dListCount = skeletonHeader->dListCount;
+ skelAnime->skeleton = Lib_PtrSegToVirt(skeletonHeader->skeletonSeg);
+
+ if (limbDrawTbl == NULL) {
+ skelAnime->limbDrawTbl = zelda_malloc(sizeof(*skelAnime->limbDrawTbl) * skelAnime->limbCount);
+
+ skelAnime->transitionDrawTbl = zelda_malloc(sizeof(*skelAnime->transitionDrawTbl) * skelAnime->limbCount);
+ } else {
+ skelAnime->limbDrawTbl = limbDrawTbl;
+ skelAnime->transitionDrawTbl = transitionDrawTable;
+ }
+
+ if (animationSeg != NULL) {
+ SkelAnime_ChangeAnimDefaultRepeat(skelAnime, animationSeg);
+ }
+}
+
+void SkelAnime_InitSkin(GlobalContext* globalCtx, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg,
+ AnimationHeader* animationSeg) {
+ SkeletonHeader* skeletonHeader;
+
+ skeletonHeader = Lib_PtrSegToVirt(skeletonHeaderSeg);
+ skelAnime->limbCount = skeletonHeader->limbCount + 1;
+ skelAnime->skeleton = Lib_PtrSegToVirt(skeletonHeader->skeletonSeg);
+ skelAnime->limbDrawTbl = zelda_malloc(sizeof(*skelAnime->limbDrawTbl) * skelAnime->limbCount);
+ skelAnime->transitionDrawTbl = zelda_malloc(sizeof(*skelAnime->transitionDrawTbl) * skelAnime->limbCount);
+
+ // Debug prints here, required to match.
+ if (1) {};
+
+ if (animationSeg != NULL) {
+ SkelAnime_ChangeAnimDefaultRepeat(skelAnime, animationSeg);
+ }
+}
+
+void func_80136C84(SkelAnime* skelAnime) {
+ if (skelAnime->mode < 2) {
+ skelAnime->animUpdate = func_8013702C;
+ } else if (skelAnime->mode < 4) {
+ skelAnime->animUpdate = func_8013713C;
+ } else {
+ skelAnime->animUpdate = func_801370B0;
+ }
+}
+
+s32 SkelAnime_FrameUpdateMatrix(SkelAnime* skelAnime) {
+ return skelAnime->animUpdate(skelAnime);
+}
+
+s32 func_80136CF4(SkelAnime* skelAnime) {
+ f32 prevUnk28 = skelAnime->transCurrentFrame;
+ f32 updateRate = gFramerateDivisorThird;
+
+ skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate;
+ if (skelAnime->transCurrentFrame <= 0.0f) {
+ func_80136C84(skelAnime);
+ skelAnime->transCurrentFrame = 0.0f;
+ }
+ SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl,
+ skelAnime->transitionDrawTbl, 1.0f - (skelAnime->transCurrentFrame / prevUnk28));
+ return 0;
+}
+
+s32 func_80136D98(SkelAnime* skelAnime) {
+ s16 temp_a2 = (s16)(skelAnime->transCurrentFrame * 16384.0f);
+ s16 temp_a1;
+ f32 sp28;
+ f32 phi_f2;
+ f32 updateRate = gFramerateDivisorThird;
+
+ skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate;
+ if (skelAnime->transCurrentFrame <= 0.0f) {
+ func_80136C84(skelAnime);
+ skelAnime->transCurrentFrame = 0.0f;
+ }
+ temp_a1 = (s16)(skelAnime->transCurrentFrame * 16384.0f);
+ if (skelAnime->unk03 < 0) {
+ sp28 = 1.0f - Math_Coss(temp_a2);
+ phi_f2 = 1.0f - Math_Coss(temp_a1);
+ } else {
+ sp28 = Math_Sins(temp_a2);
+ phi_f2 = Math_Sins(temp_a1);
+ }
+ if (phi_f2 != 0.0f) {
+ phi_f2 /= sp28;
+ } else {
+ phi_f2 = 0.0f;
+ }
+ SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl,
+ skelAnime->transitionDrawTbl, 1.0f - phi_f2);
+ return 0;
+}
+
+void func_80136F04(SkelAnime* skelAnime) {
+ s32 t;
+ s32 pad[2];
+ Vec3s sp38[98];
+ f32 temp_f10;
+ f32 temp_f2;
+
+ SkelAnime_AnimateFrame(skelAnime->animCurrentSeg, skelAnime->animCurrentFrame, skelAnime->limbCount,
+ skelAnime->limbDrawTbl);
+ if (skelAnime->mode & 0x1) {
+ t = (s32)skelAnime->animCurrentFrame;
+ temp_f10 = t;
+ temp_f2 = skelAnime->animCurrentFrame - temp_f10;
+ t++;
+ if (t >= (s32)skelAnime->totalFrames) {
+ t = 0;
+ }
+ SkelAnime_AnimateFrame(skelAnime->animCurrentSeg, t, skelAnime->limbCount, sp38);
+ SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl, sp38, temp_f2);
+ }
+ if (skelAnime->transCurrentFrame != 0) {
+ f32 updateRate = gFramerateDivisorThird;
+ skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate;
+ if (skelAnime->transCurrentFrame <= 0.0f) {
+ skelAnime->transCurrentFrame = 0.0f;
+ return;
+ }
+ SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl,
+ skelAnime->transitionDrawTbl, skelAnime->transCurrentFrame);
+ }
+}
+
+s32 func_8013702C(SkelAnime* skelAnime) {
+ f32 updateRate = gFramerateDivisorThird;
+
+ skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate;
+ if (skelAnime->animCurrentFrame < 0.0f) {
+ skelAnime->animCurrentFrame += skelAnime->totalFrames;
+ } else if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) {
+ skelAnime->animCurrentFrame -= skelAnime->totalFrames;
+ }
+
+ func_80136F04(skelAnime);
+ return 0;
+}
+
+s32 func_801370B0(SkelAnime* skelAnime) {
+ f32 updateRate = gFramerateDivisorThird;
+
+ skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate;
+ if (skelAnime->animCurrentFrame < skelAnime->initialFrame) {
+ skelAnime->animCurrentFrame =
+ (skelAnime->animCurrentFrame - skelAnime->initialFrame) + skelAnime->animFrameCount;
+ } else if (skelAnime->animFrameCount <= skelAnime->animCurrentFrame) {
+ skelAnime->animCurrentFrame =
+ (skelAnime->animCurrentFrame - skelAnime->animFrameCount) + skelAnime->initialFrame;
+ }
+
+ func_80136F04(skelAnime);
+ return 0;
+}
+
+s32 func_8013713C(SkelAnime* skelAnime) {
+ f32 updateRate = gFramerateDivisorThird;
+
+ if (skelAnime->animCurrentFrame == skelAnime->animFrameCount) {
+ SkelAnime_AnimateFrame(skelAnime->animCurrentSeg, (s32)skelAnime->animCurrentFrame, skelAnime->limbCount,
+ skelAnime->limbDrawTbl);
+ func_80136F04(skelAnime);
+ return 1;
+ }
+
+ skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate;
+ if (((skelAnime->animCurrentFrame - skelAnime->animFrameCount) * skelAnime->animPlaybackSpeed) > 0.0f) {
+ skelAnime->animCurrentFrame = skelAnime->animFrameCount;
+ } else {
+ if (skelAnime->animCurrentFrame < 0.0f) {
+ skelAnime->animCurrentFrame += skelAnime->totalFrames;
+ } else {
+ if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) {
+ skelAnime->animCurrentFrame -= skelAnime->totalFrames;
+ }
+ }
+ }
+ func_80136F04(skelAnime);
+ return 0;
+}
+
+void SkelAnime_ChangeAnimImpl(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed, f32 frame,
+ f32 frameCount, u8 animationType, f32 transitionRate, s8 unk2) {
+ skelAnime->mode = animationType;
+ if ((transitionRate != 0.0f) &&
+ ((animationSeg != skelAnime->animCurrentSeg) || (frame != skelAnime->animCurrentFrame))) {
+ if (transitionRate < 0) {
+ func_80136C84(skelAnime);
+ SkelAnime_CopyVec3s(skelAnime, skelAnime->transitionDrawTbl, skelAnime->limbDrawTbl);
+ transitionRate = -transitionRate;
+ } else {
+ if (unk2 != 0) {
+ skelAnime->animUpdate = func_80136D98;
+ skelAnime->unk03 = unk2;
+ } else {
+ skelAnime->animUpdate = func_80136CF4;
+ }
+ SkelAnime_AnimateFrame(animationSeg, frame, skelAnime->limbCount, skelAnime->transitionDrawTbl);
+ }
+ skelAnime->transCurrentFrame = 1.0f;
+ skelAnime->transitionStep = 1.0f / transitionRate;
+ } else {
+ func_80136C84(skelAnime);
+ SkelAnime_AnimateFrame(animationSeg, frame, skelAnime->limbCount, skelAnime->limbDrawTbl);
+ skelAnime->transCurrentFrame = 0.0f;
+ }
+
+ skelAnime->animCurrentSeg = animationSeg;
+ skelAnime->initialFrame = frame;
+ skelAnime->animFrameCount = frameCount;
+ skelAnime->totalFrames = SkelAnime_GetTotalFrames(&animationSeg->genericHeader);
+ if (skelAnime->mode >= 4) {
+ skelAnime->animCurrentFrame = 0.0f;
+ } else {
+ skelAnime->animCurrentFrame = frame;
+ if (skelAnime->mode < 2) {
+ skelAnime->animFrameCount = skelAnime->totalFrames - 1.0f;
+ }
+ }
+ skelAnime->animPlaybackSpeed = playbackSpeed;
+}
+
+void SkelAnime_ChangeAnim(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed, f32 frame,
+ f32 frameCount, u8 mode, f32 transitionRate) {
+ SkelAnime_ChangeAnimImpl(skelAnime, animationSeg, playbackSpeed, frame, frameCount, mode, transitionRate, 0);
+}
+
+void SkelAnime_ChangeAnimDefaultStop(SkelAnime* skelAnime, AnimationHeader* animationSeg) {
+ SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0.0f, SkelAnime_GetFrameCount(&animationSeg->genericHeader), 2,
+ 0.0f);
+}
+
+void SkelAnime_ChangeAnimTransitionStop(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 transitionRate) {
+ SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0, SkelAnime_GetFrameCount(&animationSeg->genericHeader), 2,
+ transitionRate);
+}
+
+void SkelAnime_ChangeAnimPlaybackStop(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed) {
+ SkelAnime_ChangeAnim(skelAnime, animationSeg, playbackSpeed, 0.0f,
+ SkelAnime_GetFrameCount(&animationSeg->genericHeader), 2, 0.0f);
+}
+
+void SkelAnime_ChangeAnimDefaultRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg) {
+ SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0.0f, SkelAnime_GetFrameCount(&animationSeg->genericHeader), 0,
+ 0.0f);
+}
+
+void SkelAnime_ChangeAnimTransitionRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 transitionRate) {
+ SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0.0f, 0.0f, 0, transitionRate);
+}
+
+void SkelAnime_ChangeAnimPlaybackRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed) {
+ SkelAnime_ChangeAnim(skelAnime, animationSeg, playbackSpeed, 0.0f,
+ SkelAnime_GetFrameCount(&animationSeg->genericHeader), 0, 0.0f);
+}
+
+void SkelAnime_AnimSetStop(SkelAnime* skelAnime) {
+ skelAnime->mode = 2;
+ skelAnime->animFrameCount = skelAnime->totalFrames;
+ func_80136C84(skelAnime);
+}
+
+void SkelAnime_AnimReverse(SkelAnime* skelAnime) {
+ f32 initialFrame = skelAnime->initialFrame;
+
+ skelAnime->initialFrame = skelAnime->animFrameCount;
+ skelAnime->animPlaybackSpeed = -skelAnime->animPlaybackSpeed;
+ skelAnime->animFrameCount = initialFrame;
+}
+
+void func_80137674(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src, u8* index) {
+ s32 i;
+
+ for (i = 0; i < skelAnime->limbCount; i++, dst++, src++) {
+ if (*index++) {
+ *dst = *src;
+ }
+ }
+}
+
+void func_801376DC(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src, u8* arg3) {
+ s32 i;
+
+ for (i = 0; i < skelAnime->limbCount; i++, dst++, src++) {
+ if (*arg3++ < 1U) {
+ *dst = *src;
+ }
+ }
+}
+
+/*
+ * Moves `pos` backwards on the xz plane from `angle`
+ */
+void func_80137748(SkelAnime* skelAnime, Vec3f* pos, s16 angle) {
+ f32 x;
+ f32 z;
+ f32 sin;
+ f32 cos;
+
+ if (skelAnime->flags & 0x10) {
+ pos->z = 0.0f;
+ pos->x = 0.0f;
+ } else {
+ // `angle` rotation around y axis.
+ x = skelAnime->limbDrawTbl->x - skelAnime->prevFramePos.x;
+ z = skelAnime->limbDrawTbl->z - skelAnime->prevFramePos.z;
+ sin = Math_Sins(angle);
+ cos = Math_Coss(angle);
+ pos->x = x * cos + z * sin;
+ pos->z = z * cos - x * sin;
+ }
+
+ skelAnime->prevFramePos.x = skelAnime->limbDrawTbl->x;
+ skelAnime->limbDrawTbl->x = skelAnime->unk3E.x;
+ skelAnime->prevFramePos.z = skelAnime->limbDrawTbl->z;
+ skelAnime->limbDrawTbl->z = skelAnime->unk3E.z;
+ if (skelAnime->flags & ANIM_FLAG_UPDATEXZ) {
+ if (skelAnime->flags & ANIM_FLAG_UPDATEY) {
+ pos->y = 0.0f;
+ } else {
+ pos->y = skelAnime->limbDrawTbl->y - skelAnime->prevFramePos.y;
+ }
+ skelAnime->prevFramePos.y = skelAnime->limbDrawTbl->y;
+ skelAnime->limbDrawTbl->y = skelAnime->unk3E.y;
+ } else {
+ pos->y = 0.0f;
+ skelAnime->prevFramePos.y = skelAnime->limbDrawTbl->y;
+ }
+ skelAnime->flags &= ~ANIM_FLAG_UPDATEY;
+}
+
+s32 func_801378B8(SkelAnime* skelAnime, f32 arg1) {
+ return func_80136990(skelAnime, arg1, 1.0f);
+}
+
+void SkelAnime_Free(SkelAnime* skelAnime, GlobalContext* globalCtx) {
+ if (skelAnime->limbDrawTbl != NULL) {
+ zelda_free(skelAnime->limbDrawTbl);
+ }
+
+ if (skelAnime->transitionDrawTbl != NULL) {
+ zelda_free(skelAnime->transitionDrawTbl);
+ }
+}
+
+void SkelAnime_CopyVec3s(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src) {
+ _bcopy(src, dst, sizeof(Vec3s) * skelAnime->limbCount);
+}