summaryrefslogtreecommitdiff
path: root/src/code
diff options
context:
space:
mode:
authorAnghelo Carvajal <angheloalf95@gmail.com>2022-03-23 18:30:34 -0300
committerGitHub <noreply@github.com>2022-03-23 17:30:34 -0400
commit92c4d42f446cc12c79de9b441b9afa341cf294e8 (patch)
tree68e412217a3961905efa586d85b5cb1c92c5725d /src/code
parentf1560614d6671ecee1ea067349a06ea088536edf (diff)
`z_skin` and `z_skin_awb` OK and documented a bit (#415)
* oot copypaste * func_8013859C non matching and func_80138700 * protos * the other functions * func_80138300 * progress * func_80137F58 * func_80137EBC * func_80137B34 NON_MATCHING * func_80137970 * func_8013835C * z64skin * some docs * some bits * Match func_80137B34 * Match Skin_DrawImpl * Match Skin_Init tahnks to Anon * Some docs? * AnimatedLimb * SkinVtx * more names * fix merge issue * format * another clean * trailing comma * cleanup * format * add some descriptions * Import bss * last cleanup * Update ZAPD symbol map * Reanme gIdentityMtx and gIdentityMtxF * fix merge issues * bss * review * Update include/z64skin.h Co-authored-by: Derek Hensley <hensley.derek58@gmail.com> * bss * Port @fig02 skin docs * format and a few changes * format * Port over OoT review * fixes * Engineer's review * format * address pr * Fix bss * fix bss * Update src/code/z_skin_awb.c Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com> * bss * bss * undo * pr * Skin_Setup Co-authored-by: Derek Hensley <hensley.derek58@gmail.com> Co-authored-by: engineer124 <47598039+engineer124@users.noreply.github.com>
Diffstat (limited to 'src/code')
-rw-r--r--src/code/z_bgcheck.c1
-rw-r--r--src/code/z_demo.c1
-rw-r--r--src/code/z_lifemeter.c17
-rw-r--r--src/code/z_skelanime.c2
-rw-r--r--src/code/z_skin.c272
-rw-r--r--src/code/z_skin_awb.c203
6 files changed, 470 insertions, 26 deletions
diff --git a/src/code/z_bgcheck.c b/src/code/z_bgcheck.c
index 3f5583f79..910458b77 100644
--- a/src/code/z_bgcheck.c
+++ b/src/code/z_bgcheck.c
@@ -1,3 +1,4 @@
+#include "prevent_bss_reordering.h"
#include "global.h"
#include "vt.h"
diff --git a/src/code/z_demo.c b/src/code/z_demo.c
index fb6f8687c..785f86856 100644
--- a/src/code/z_demo.c
+++ b/src/code/z_demo.c
@@ -1,3 +1,4 @@
+#include "prevent_bss_reordering.h"
#include "global.h"
#include "overlays/gamestates/ovl_daytelop/z_daytelop.h"
diff --git a/src/code/z_lifemeter.c b/src/code/z_lifemeter.c
index 17e73dc34..703b966de 100644
--- a/src/code/z_lifemeter.c
+++ b/src/code/z_lifemeter.c
@@ -1,15 +1,16 @@
+#include "prevent_bss_reordering.h"
#include "global.h"
#include "interface/parameter_static/parameter_static.h"
#include "prevent_bss_reordering.h"
-static s16 sHeartsPrimColors[3][3] = { { 255, 70, 50 }, { 255, 190, 0 }, { 100, 100, 255 } };
-static s16 sHeartsEnvColors[3][3] = { { 50, 40, 60 }, { 255, 0, 0 }, { 0, 0, 255 } };
-static s16 sHeartsPrimFactors[3][3] = { { 0, 0, 0 }, { 0, 120, -50 }, { -155, 30, 205 } };
-static s16 sHeartsEnvFactors[3][3] = { { 0, 0, 0 }, { 205, -40, -60 }, { -50, -40, 195 } };
-static s16 sHeartsDDPrimColors[3][3] = { { 255, 255, 255 }, { 255, 190, 0 }, { 100, 100, 255 } };
-static s16 sHeartsDDEnvColors[3][3] = { { 200, 0, 0 }, { 255, 0, 0 }, { 0, 0, 255 } };
-static s16 sHeartsDDPrimFactors[3][3] = { { 0, 0, 0 }, { 0, -65, -255 }, { -155, -155, 0 } };
-static s16 sHeartsDDEnvFactors[3][3] = { { 0, 0, 0 }, { 55, 0, 0 }, { -200, 0, 255 } };
+s16 sHeartsPrimColors[3][3] = { { 255, 70, 50 }, { 255, 190, 0 }, { 100, 100, 255 } };
+s16 sHeartsEnvColors[3][3] = { { 50, 40, 60 }, { 255, 0, 0 }, { 0, 0, 255 } };
+s16 sHeartsPrimFactors[3][3] = { { 0, 0, 0 }, { 0, 120, -50 }, { -155, 30, 205 } };
+s16 sHeartsEnvFactors[3][3] = { { 0, 0, 0 }, { 205, -40, -60 }, { -50, -40, 195 } };
+s16 sHeartsDDPrimColors[3][3] = { { 255, 255, 255 }, { 255, 190, 0 }, { 100, 100, 255 } };
+s16 sHeartsDDEnvColors[3][3] = { { 200, 0, 0 }, { 255, 0, 0 }, { 0, 0, 255 } };
+s16 sHeartsDDPrimFactors[3][3] = { { 0, 0, 0 }, { 0, -65, -255 }, { -155, -155, 0 } };
+s16 sHeartsDDEnvFactors[3][3] = { { 0, 0, 0 }, { 55, 0, 0 }, { -200, 0, 255 } };
s16 sBeatingHeartsDDPrim[3];
s16 sBeatingHeartsDDEnv[3];
diff --git a/src/code/z_skelanime.c b/src/code/z_skelanime.c
index 9fc5467e0..f0ed1f516 100644
--- a/src/code/z_skelanime.c
+++ b/src/code/z_skelanime.c
@@ -1577,7 +1577,7 @@ void SkelAnime_InitFlex(GlobalContext* globalCtx, SkelAnime* skelAnime, FlexSkel
/**
* Initializes a skeleton with SkinLimbs to a looping animation, dynamically allocating the frame tables.
*/
-void SkelAnime_InitSkin(GlobalContext* globalCtx, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg,
+void SkelAnime_InitSkin(GameState* gameState, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg,
AnimationHeader* animation) {
SkeletonHeader* skeletonHeader;
diff --git a/src/code/z_skin.c b/src/code/z_skin.c
index f031b007f..808a00da0 100644
--- a/src/code/z_skin.c
+++ b/src/code/z_skin.c
@@ -1,23 +1,273 @@
#include "global.h"
+#include "z64skin.h"
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80137970.s")
+// 60 is an arbitrary number which specifies the max amount of limbs per skeleton this system supports
+MtxF gSkinLimbMatrices[60];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80137B34.s")
+static s32 sUnused;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80137EBC.s")
+void Skin_UpdateVertices(MtxF* mtx, SkinVertex* skinVertices, SkinLimbModif* modifEntry, Vtx* vtxBuf, Vec3f* pos) {
+ SkinVertex* vertexEntry;
+ Vtx* vtx;
+ Vec3f wTemp;
+ Vec3f normal;
+ Vec3f sp44;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80137F58.s")
+ wTemp.x = mtx->wx;
+ wTemp.y = mtx->wy;
+ wTemp.z = mtx->wz;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80138050.s")
+ mtx->wx = 0.0f;
+ mtx->wy = 0.0f;
+ mtx->wz = 0.0f;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80138228.s")
+ for (vertexEntry = skinVertices; vertexEntry < &skinVertices[modifEntry->vtxCount]; vertexEntry++) {
+ vtx = &vtxBuf[vertexEntry->index];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80138258.s")
+ vtx->n.ob[0] = pos->x;
+ vtx->n.ob[1] = pos->y;
+ vtx->n.ob[2] = pos->z;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_8013828C.s")
+ sp44.x = vertexEntry->normX;
+ sp44.y = vertexEntry->normY;
+ sp44.z = vertexEntry->normZ;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_801382C4.s")
+ SkinMatrix_Vec3fMtxFMultXYZ(mtx, &sp44, &normal);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_80138300.s")
+ vtx->n.n[0] = normal.x;
+ vtx->n.n[1] = normal.y;
+ vtx->n.n[2] = normal.z;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin/func_8013835C.s")
+ mtx->wx = wTemp.x;
+ mtx->wy = wTemp.y;
+ mtx->wz = wTemp.z;
+}
+
+void Skin_ApplyLimbModifications(GraphicsContext* gfxCtx, Skin* skin, s32 limbIndex, s32 arg3) {
+ s32 modifCount;
+ SkinLimb** skeleton;
+ s32 pad;
+ SkinAnimatedLimbData* data;
+ s32 pad2[5];
+ SkinLimbModif* modif;
+ SkinLimbVtx* vtxEntry;
+ s32 pad3;
+ s32 transformCount;
+ f32 scale;
+ SkinVertex* skinVertices;
+ Vec3f sp88;
+ Vtx* vtxBuf;
+ SkinTransformation* limbTransformations;
+ Vec3f spDC;
+ Vec3f spD0;
+ SkinTransformation* transformationEntry;
+ SkinLimb* limb;
+ SkinLimbModif* modifications;
+
+ OPEN_DISPS(gfxCtx);
+
+ skeleton = (SkinLimb**)Lib_SegmentedToVirtual(skin->skeletonHeader->segment);
+ limb = (SkinLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]);
+ data = Lib_SegmentedToVirtual(limb->segment);
+ modifications = (SkinLimbModif*)Lib_SegmentedToVirtual(data->limbModifications);
+
+ vtxEntry = &skin->vtxTable[limbIndex];
+
+ vtxBuf = vtxEntry->buf[vtxEntry->index];
+ modifCount = data->limbModifCount;
+
+ for (modif = modifications; modif < &modifications[modifCount]; modif++) {
+ Vec3f spAC;
+ Vec3f spA0;
+
+ skinVertices = (SkinVertex*)Lib_SegmentedToVirtual(modif->skinVertices);
+ limbTransformations = (SkinTransformation*)Lib_SegmentedToVirtual(modif->limbTransformations);
+ transformCount = modif->transformCount;
+
+ if (transformCount == 1) {
+ spAC.x = limbTransformations[0].x;
+ spAC.y = limbTransformations[0].y;
+ spAC.z = limbTransformations[0].z;
+
+ SkinMatrix_Vec3fMtxFMultXYZ(&gSkinLimbMatrices[limbTransformations[0].limbIndex], &spAC, &spDC);
+ } else if (arg3) {
+ transformationEntry = &limbTransformations[modif->unk_04];
+
+ spA0.x = transformationEntry->x;
+ spA0.y = transformationEntry->y;
+ spA0.z = transformationEntry->z;
+ SkinMatrix_Vec3fMtxFMultXYZ(&gSkinLimbMatrices[transformationEntry->limbIndex], &spA0, &spDC);
+ } else {
+ spDC.x = 0.0f;
+ spDC.y = 0.0f;
+ spDC.z = 0.0f;
+
+ for (transformationEntry = limbTransformations; transformationEntry < &limbTransformations[transformCount];
+ transformationEntry++) {
+ scale = transformationEntry->scale * 0.01f;
+
+ sp88.x = transformationEntry->x;
+ sp88.y = transformationEntry->y;
+ sp88.z = transformationEntry->z;
+
+ SkinMatrix_Vec3fMtxFMultXYZ(&gSkinLimbMatrices[transformationEntry->limbIndex], &sp88, &spD0);
+
+ spDC.x += spD0.x * scale;
+ spDC.y += spD0.y * scale;
+ spDC.z += spD0.z * scale;
+ }
+ }
+
+ Skin_UpdateVertices(&gSkinLimbMatrices[limbTransformations[modif->unk_04].limbIndex], skinVertices, modif,
+ vtxBuf, &spDC);
+ }
+
+ gSPSegment(POLY_OPA_DISP++, 0x08, vtxEntry->buf[vtxEntry->index]);
+
+ vtxEntry->index = (vtxEntry->index == 0);
+
+ CLOSE_DISPS(gfxCtx);
+}
+
+/**
+ * Draw a limb of type SKIN_LIMB_TYPE_ANIMATED, of the skeleton `skin` at index `limbIndex`
+ * The vertices of this limb are modified dynamically
+ */
+void Skin_DrawAnimatedLimb(GraphicsContext* gfxCtx, Skin* skin, s32 limbIndex, s32 arg3, s32 drawFlags) {
+ SkinLimb** skeleton;
+ s32 pad[3];
+ SkinAnimatedLimbData* data;
+
+ OPEN_DISPS(gfxCtx);
+
+ skeleton = Lib_SegmentedToVirtual(skin->skeletonHeader->segment);
+ data = Lib_SegmentedToVirtual(((SkinLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]))->segment);
+
+ if (!(drawFlags & SKIN_DRAW_FLAG_CUSTOM_TRANSFORMS)) {
+ Skin_ApplyLimbModifications(gfxCtx, skin, limbIndex, arg3);
+ }
+
+ gSPDisplayList(POLY_OPA_DISP++, data->dlist);
+
+ CLOSE_DISPS(gfxCtx);
+}
+
+/**
+ * Draw a limb of type SKIN_LIMB_TYPE_NORMAL, of the skeleton `skin` at index `limbIndex`
+ */
+void Skin_DrawLimb(GraphicsContext* gfxCtx, Skin* skin, s32 limbIndex, Gfx* dListOverride, s32 drawFlags) {
+ Gfx* gfx = dListOverride;
+ SkinLimb** skeleton;
+
+ OPEN_DISPS(gfxCtx);
+
+ skeleton = Lib_SegmentedToVirtual(skin->skeletonHeader->segment);
+
+ if (dListOverride == NULL) {
+ gfx = ((SkinLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]))->segment;
+ }
+
+ if (gfx != NULL) {
+ Mtx* mtx = SkinMatrix_MtxFToNewMtx(gfxCtx, &gSkinLimbMatrices[limbIndex]);
+
+ if (mtx != NULL) {
+ gSPMatrix(POLY_OPA_DISP++, mtx, G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
+ gSPDisplayList(POLY_OPA_DISP++, gfx);
+ gSPPopMatrix(POLY_OPA_DISP++, G_MTX_MODELVIEW);
+ gDPPipeSync(POLY_OPA_DISP++);
+ }
+ }
+
+ CLOSE_DISPS(gfxCtx);
+}
+
+void Skin_DrawImpl(Actor* actor, GlobalContext* globalCtx, Skin* skin, SkinPostDraw postDraw,
+ SkinOverrideLimbDraw overrideLimbDraw, s32 setTranslation, s32 arg6, s32 drawFlags) {
+ s32 i;
+ SkinLimb** skeleton;
+ GraphicsContext* gfxCtx = globalCtx->state.gfxCtx;
+
+ OPEN_DISPS(gfxCtx);
+
+ if (!(drawFlags & SKIN_DRAW_FLAG_CUSTOM_TRANSFORMS)) {
+ Skin_ApplyAnimTransformations(skin, gSkinLimbMatrices, actor, setTranslation);
+ }
+
+ skeleton = Lib_SegmentedToVirtual(skin->skeletonHeader->segment);
+
+ if (!(drawFlags & SKIN_DRAW_FLAG_CUSTOM_MATRIX)) {
+ Mtx* mtx;
+
+ gSPMatrix(POLY_OPA_DISP++, &gIdentityMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ mtx = SkinMatrix_MtxFToNewMtx(gfxCtx, &skin->mtx);
+ if (mtx == NULL) {
+ goto close_disps;
+ }
+ gSPMatrix(POLY_OPA_DISP++, mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+ }
+
+ for (i = 0; i < skin->skeletonHeader->limbCount; i++) {
+ s32 shouldDraw = true;
+ s32 segmentType;
+
+ if (overrideLimbDraw != NULL) {
+ shouldDraw = overrideLimbDraw(actor, globalCtx, i, skin);
+ }
+
+ segmentType = ((SkinLimb*)Lib_SegmentedToVirtual(skeleton[i]))->segmentType;
+
+ if (segmentType == SKIN_LIMB_TYPE_ANIMATED && shouldDraw) {
+ Skin_DrawAnimatedLimb(gfxCtx, skin, i, arg6, drawFlags);
+ } else if (segmentType == SKIN_LIMB_TYPE_NORMAL && shouldDraw) {
+ Skin_DrawLimb(gfxCtx, skin, i, NULL, drawFlags);
+ }
+ }
+
+ if (postDraw != NULL) {
+ postDraw(actor, globalCtx, skin);
+ }
+
+close_disps:;
+ CLOSE_DISPS(gfxCtx);
+}
+
+// allows specifying postDraw and setTranslation
+void func_80138228(Actor* actor, GlobalContext* globalCtx, Skin* skin, SkinPostDraw postDraw, s32 setTranslation) {
+ Skin_DrawImpl(actor, globalCtx, skin, postDraw, NULL, setTranslation, false, 0);
+}
+
+// allows specifying OverrideLimbDraw, postDraw and setTranslation
+void func_80138258(Actor* actor, GlobalContext* globalCtx, Skin* skin, SkinPostDraw postDraw,
+ SkinOverrideLimbDraw overrideLimbDraw, s32 setTranslation) {
+ Skin_DrawImpl(actor, globalCtx, skin, postDraw, overrideLimbDraw, setTranslation, false, 0);
+}
+
+// allows specifying OverrideLimbDraw, postDraw, setTranslation, and arg6
+void func_8013828C(Actor* actor, GlobalContext* globalCtx, Skin* skin, SkinPostDraw postDraw,
+ SkinOverrideLimbDraw overrideLimbDraw, s32 setTranslation, s32 arg6) {
+ Skin_DrawImpl(actor, globalCtx, skin, postDraw, overrideLimbDraw, setTranslation, arg6, 0);
+}
+
+// allows specifying all variables
+void func_801382C4(Actor* actor, GlobalContext* globalCtx, Skin* skin, SkinPostDraw postDraw,
+ SkinOverrideLimbDraw overrideLimbDraw, s32 setTranslation, s32 arg6, s32 drawFlags) {
+ Skin_DrawImpl(actor, globalCtx, skin, postDraw, overrideLimbDraw, setTranslation, arg6, drawFlags);
+}
+
+void Skin_GetLimbPos(Skin* skin, s32 limbIndex, Vec3f* offset, Vec3f* dst) {
+ MtxF mtxf;
+
+ SkinMatrix_MtxFMtxFMult(&skin->mtx, &gSkinLimbMatrices[limbIndex], &mtxf);
+ SkinMatrix_Vec3fMtxFMultXYZ(&mtxf, offset, dst);
+}
+
+void Skin_GetVertexPos(Skin* skin, s32 limbIndex, s32 vtxIndex, Vec3f* dst) {
+ Vec3f pos;
+ Vtx* vtx = &skin->vtxTable[limbIndex].buf[skin->vtxTable[0].index][vtxIndex];
+
+ pos.x = vtx->n.ob[0];
+ pos.y = vtx->n.ob[1];
+ pos.z = vtx->n.ob[2];
+ SkinMatrix_Vec3fMtxFMultXYZ(&skin->mtx, &pos, dst);
+}
diff --git a/src/code/z_skin_awb.c b/src/code/z_skin_awb.c
index 22a1c637f..d45b9bc25 100644
--- a/src/code/z_skin_awb.c
+++ b/src/code/z_skin_awb.c
@@ -1,13 +1,204 @@
#include "global.h"
+#include "z64skin.h"
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin_awb/func_80138410.s")
+void Skin_Setup(Skin* skin) {
+ skin->skeletonHeader = NULL;
+ skin->limbCount = 0;
+ skin->vtxTable = NULL;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin_awb/func_80138424.s")
+/**
+ * Initialises the Vtx buffers used for limb at index `limbIndex`
+ */
+void Skin_InitAnimatedLimb(GameState* gameState, Skin* skin, s32 limbIndex) {
+ s32 i;
+ SkinLimb** skeleton = Lib_SegmentedToVirtual(skin->skeletonHeader->segment);
+ SkinAnimatedLimbData* animatedLimbData =
+ Lib_SegmentedToVirtual(((SkinLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]))->segment);
+ SkinLimbModif* limbModifications = Lib_SegmentedToVirtual(animatedLimbData->limbModifications);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin_awb/func_8013859C.s")
+ for (i = 0; i < ARRAY_COUNT(skin->vtxTable->buf); i++) {
+ Vtx* vertices = skin->vtxTable[limbIndex].buf[i];
+ SkinLimbModif* modifEntry;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin_awb/func_80138700.s")
+ for (modifEntry = limbModifications; modifEntry < &limbModifications[animatedLimbData->limbModifCount];
+ modifEntry++) {
+ SkinVertex* skinVertices = Lib_SegmentedToVirtual(modifEntry->skinVertices);
+ SkinVertex* skinVtxEntry;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin_awb/func_801387D4.s")
+ for (skinVtxEntry = skinVertices; skinVtxEntry < &skinVertices[modifEntry->vtxCount];) {
+ Vtx* vtx = &vertices[skinVtxEntry->index];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_skin_awb/func_801388E4.s")
+ skinVtxEntry++;
+
+ vtx->n.flag = 0;
+ vtx->n.tc[0] = skinVtxEntry[-1].s;
+ vtx->n.tc[1] = skinVtxEntry[-1].t;
+ vtx->n.a = skinVtxEntry[-1].alpha;
+ }
+ }
+ }
+}
+
+/**
+ * Initializes a skin skeleton to looping animation, dynamically allocating the frame tables,
+ * and dynamically allocating and initialising the Vtx and SkinLimbVtx buffers for its animated limbs
+ */
+void Skin_Init(GameState* gameState, Skin* skin, SkeletonHeader* skeletonHeader, AnimationHeader* animationHeader) {
+ s32 limbCount;
+ s32 i;
+ SkinLimb** skeleton;
+ SkeletonHeader* virtSkelHeader = Lib_SegmentedToVirtual(skeletonHeader);
+
+ skin->limbCount = virtSkelHeader->limbCount;
+ skin->skeletonHeader = virtSkelHeader;
+ limbCount = skin->skeletonHeader->limbCount;
+
+ skeleton = Lib_SegmentedToVirtual(skin->skeletonHeader->segment);
+ skin->vtxTable = ZeldaArena_Malloc(limbCount * sizeof(SkinLimbVtx));
+
+ for (i = 0; i < limbCount; i++) {
+ SkinLimbVtx* vtxEntry = &skin->vtxTable[i];
+
+ if ((((SkinLimb*)Lib_SegmentedToVirtual(skeleton[i]))->segmentType != SKIN_LIMB_TYPE_ANIMATED) ||
+ (((SkinLimb*)Lib_SegmentedToVirtual(skeleton[i]))->segment == NULL)) {
+ vtxEntry->index = 0;
+
+ vtxEntry->buf[0] = NULL;
+ vtxEntry->buf[1] = NULL;
+ } else {
+ SkinAnimatedLimbData* animatedLimbData =
+ Lib_SegmentedToVirtual((((SkinLimb*)Lib_SegmentedToVirtual(skeleton[i]))->segment));
+
+ { s32 tmp; }
+
+ vtxEntry->index = 0;
+ vtxEntry->buf[0] = ZeldaArena_Malloc(animatedLimbData->totalVtxCount * sizeof(Vtx));
+ vtxEntry->buf[1] = ZeldaArena_Malloc(animatedLimbData->totalVtxCount * sizeof(Vtx));
+
+ Skin_InitAnimatedLimb(gameState, skin, i);
+ }
+ }
+
+ SkelAnime_InitSkin(gameState, &skin->skelAnime, skeletonHeader, animationHeader);
+}
+
+/**
+ * Frees the dynamically allocated Vtx and SkinLimbVtx buffers and tables
+ */
+void Skin_Free(GameState* gameState, Skin* skin) {
+ if (skin->vtxTable != NULL) {
+ s32 i;
+
+ for (i = 0; i < skin->limbCount; i++) {
+ if (skin->vtxTable[i].buf[0] != NULL) {
+ ZeldaArena_Free(skin->vtxTable[i].buf[0]);
+ skin->vtxTable[i].buf[0] = NULL;
+ }
+ if (skin->vtxTable[i].buf[1] != NULL) {
+ ZeldaArena_Free(skin->vtxTable[i].buf[1]);
+ skin->vtxTable[i].buf[1] = NULL;
+ }
+ }
+
+ if (skin->vtxTable != NULL) {
+ ZeldaArena_Free(skin->vtxTable);
+ }
+
+ SkelAnime_Free(&skin->skelAnime, (GlobalContext*)gameState);
+ }
+}
+
+s32 func_801387D4(Skin* skin, SkinLimb** skeleton, MtxF* limbMatrices, u8 parentIndex, u8 limbIndex) {
+ s32 pad;
+ SkinLimb* limb = Lib_SegmentedToVirtual(skeleton[limbIndex]);
+ MtxF* mtx;
+ s32 ret;
+ MtxF sp28;
+
+ if (parentIndex == LIMB_DONE) {
+ SkinMatrix_GetClear(&mtx);
+ } else {
+ mtx = &limbMatrices[(s32)parentIndex];
+ }
+
+ SkinMatrix_MtxFMtxFMult(mtx, &limbMatrices[limbIndex], &sp28);
+ SkinMatrix_MtxFCopy(&sp28, &limbMatrices[limbIndex]);
+
+ if (limb->child != LIMB_DONE) {
+ ret = func_801387D4(skin, skeleton, limbMatrices, limbIndex, limb->child);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ if (limb->sibling != LIMB_DONE) {
+ ret = func_801387D4(skin, skeleton, limbMatrices, parentIndex, limb->sibling);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Recursively applies matrix tranformations to each limb
+ */
+s32 Skin_ApplyAnimTransformations(Skin* skin, MtxF* limbMatrices, Actor* actor, s32 setTranslation) {
+ s32 i;
+ s32 pad;
+ f32 yRot;
+ f32 xRot;
+ f32 zRot;
+ s32 ret;
+ f32 yTransl;
+ f32 xTransl;
+ f32 zTransl;
+ SkinLimb** skeleton = Lib_SegmentedToVirtual(skin->skeletonHeader->segment);
+ Vec3s* jointRot = skin->skelAnime.jointTable;
+
+ jointRot++;
+ xRot = jointRot->x;
+ yRot = jointRot->y;
+ zRot = jointRot->z;
+
+ if (setTranslation) {
+ jointRot--;
+ xTransl = jointRot->x;
+ yTransl = jointRot->y;
+ zTransl = jointRot->z;
+ jointRot++;
+
+ SkinMatrix_SetRotateRPYTranslate(limbMatrices, xRot, yRot, zRot, xTransl, yTransl, zTransl);
+ } else {
+ SkinMatrix_SetRotateRPYTranslate(limbMatrices, xRot, yRot, zRot, 0.0f, 0.0f, 0.0f);
+ }
+
+ jointRot++;
+
+ for (i = 1; i < skin->skeletonHeader->limbCount; i++) {
+ SkinLimb* limb = Lib_SegmentedToVirtual(skeleton[i]);
+
+ xTransl = limb->jointPos.x;
+ yTransl = limb->jointPos.y;
+ zTransl = limb->jointPos.z;
+ xRot = jointRot->x;
+ yRot = jointRot->y;
+ zRot = jointRot->z;
+ jointRot++;
+ SkinMatrix_SetRotateRPYTranslate(&limbMatrices[i], xRot, yRot, zRot, xTransl, yTransl, zTransl);
+ }
+
+ SkinMatrix_SetScaleRotateYRPTranslate(
+ &skin->mtx, actor->scale.x, actor->scale.y, actor->scale.z, actor->shape.rot.x, actor->shape.rot.y,
+ actor->shape.rot.z, actor->world.pos.x, actor->world.pos.y + (actor->shape.yOffset * actor->scale.y),
+ actor->world.pos.z);
+
+ ret = func_801387D4(skin, Lib_SegmentedToVirtual(skin->skeletonHeader->segment), limbMatrices, LIMB_DONE, 0);
+ if (!ret) {
+ return ret;
+ }
+
+ return false;
+}