diff options
| author | fullgrowngaming <42490167+fullgrowngaming@users.noreply.github.com> | 2020-10-11 10:31:06 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-11 13:31:06 -0400 |
| commit | 1c4a3047dea5649ad703779cdc07854fc623260d (patch) | |
| tree | 91ab4ca90c73aa3cb25c1b6ec6ff600201b9f952 /src/code | |
| parent | 96d05d4e7d97dccf7fef335b708307c204e0725a (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.c | 1735 |
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); +} |
