1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2024-12-04 00:36:09 +00:00
oot/src/code/z_fcurve_data_skelanime.c
fig02 2e6279bc8e
PlayState Rename (#1231)
* global context -> play

* fix PlayState* PlayState
2022-05-21 14:23:43 -04:00

242 lines
8.9 KiB
C

/**
* @file z_fcurve_data_skelanime.c
* @brief Curve skeleton animation system
*
* A curve skeleton has a fixed number of limbs, each of which has 9 properties that may be changed by the animation:
* - 3 scales,
* - 3 rotations,
* - 3 positions
* (note the position is stored in the animations instead of being stored in the limbs like SkelAnime would). Otherwise
* the structure is similar to an ordinary SkelAnime-compatible skeleton.
*
* The animations are significantly more complex than SkelAnime. A curve animation consists of 4 parts:
* - a header (CurveAnimationHeader)
* - a list of counts, one for each of the 9 properties of each limb (u8)
* - a list of interpolation data (CurveInterpKnot). The length is the sum of the counts.
* - a list of constant data (s16[9]). The length is the number of 0s in counts.
*
* If the interpolation count for a property is 0, the value of the property is copied from the next number in the
* constant data; there are no gaps for nonzero interpolation count.
* If the interpolation count N for a property is larger than 0, the next N elements of the interpolation data array
* are used to interpolate the value of the property, using Curve_Interpolate.
*
* Curve limbs may use LOD:
* - lower detail draws only the first displaylist
* - higher detail draws both.
*/
#include "global.h"
#include "z64curve.h"
void SkelCurve_Clear(SkelCurve* skelCurve) {
skelCurve->limbCount = 0;
skelCurve->skeleton = NULL;
skelCurve->animation = NULL;
skelCurve->curFrame = 0.0f;
skelCurve->playSpeed = 0.0f;
skelCurve->endFrame = 0.0f;
skelCurve->unk_0C = 0.0f;
skelCurve->jointTable = NULL;
}
/**
* Initialises the SkelCurve struct and mallocs the joint table.
*
* @return bool always true
*/
s32 SkelCurve_Init(PlayState* play, SkelCurve* skelCurve, CurveSkeletonHeader* skeletonHeaderSeg,
CurveAnimationHeader* animation) {
SkelCurveLimb** limbs;
CurveSkeletonHeader* skeletonHeader = SEGMENTED_TO_VIRTUAL(skeletonHeaderSeg);
skelCurve->limbCount = skeletonHeader->limbCount;
skelCurve->skeleton = SEGMENTED_TO_VIRTUAL(skeletonHeader->limbs);
skelCurve->jointTable = ZeldaArena_MallocDebug(sizeof(*skelCurve->jointTable) * skelCurve->limbCount,
"../z_fcurve_data_skelanime.c", 125);
ASSERT(skelCurve->jointTable != NULL, "this->now_joint != NULL", "../z_fcurve_data_skelanime.c", 127);
skelCurve->curFrame = 0.0f;
return true;
}
/**
* Frees the joint table.
*/
void SkelCurve_Destroy(PlayState* play, SkelCurve* skelCurve) {
if (skelCurve->jointTable != NULL) {
ZeldaArena_FreeDebug(skelCurve->jointTable, "../z_fcurve_data_skelanime.c", 146);
}
}
void SkelCurve_SetAnim(SkelCurve* skelCurve, CurveAnimationHeader* animation, f32 arg2, f32 endFrame, f32 curFrame,
f32 playSpeed) {
skelCurve->unk_0C = arg2 - skelCurve->playSpeed;
skelCurve->endFrame = endFrame;
skelCurve->curFrame = curFrame;
skelCurve->playSpeed = playSpeed;
skelCurve->animation = animation;
}
typedef enum {
/* 0 */ SKELCURVE_VEC_TYPE_SCALE,
/* 1 */ SKELCURVE_VEC_TYPE_ROTATION,
/* 2 */ SKELCURVE_VEC_TYPE_POSIITON,
/* 3 */ SKELCURVE_VEC_TYPE_MAX
} SkelCurveVecType;
#define SKELCURVE_SCALE_SCALE 1024.0f
#define SKELCURVE_SCALE_POSITION 100
/**
* The only animation updating function.
*
* @return bool true when the animation has finished.
*/
s32 SkelCurve_Update(PlayState* play, SkelCurve* skelCurve) {
s16* jointData;
u8* knotCounts;
CurveAnimationHeader* animation;
u16* constantData;
s32 curLimb;
s32 ret = false;
s32 coord;
CurveInterpKnot* startKnot;
s32 vecType;
animation = SEGMENTED_TO_VIRTUAL(skelCurve->animation);
knotCounts = SEGMENTED_TO_VIRTUAL(animation->knotCounts);
startKnot = SEGMENTED_TO_VIRTUAL(animation->interpolationData);
constantData = SEGMENTED_TO_VIRTUAL(animation->constantData);
jointData = *skelCurve->jointTable;
skelCurve->curFrame += skelCurve->playSpeed * R_UPDATE_RATE * 0.5f;
if (((skelCurve->playSpeed >= 0.0f) && (skelCurve->curFrame > skelCurve->endFrame)) ||
((skelCurve->playSpeed < 0.0f) && (skelCurve->curFrame < skelCurve->endFrame))) {
skelCurve->curFrame = skelCurve->endFrame;
ret = true;
}
for (curLimb = 0; curLimb < skelCurve->limbCount; curLimb++) {
// scale/rotation/position
for (vecType = SKELCURVE_VEC_TYPE_SCALE; vecType < SKELCURVE_VEC_TYPE_MAX; vecType++) {
// x/y/z
for (coord = 0; coord < 3; coord++) {
f32 transformValue;
if (*knotCounts == 0) {
transformValue = *constantData;
*jointData = transformValue;
constantData++;
} else {
transformValue = Curve_Interpolate(skelCurve->curFrame, startKnot, *knotCounts);
startKnot += *knotCounts;
if (vecType == SKELCURVE_VEC_TYPE_SCALE) {
// Rescaling allows for more refined scaling using an s16
*jointData = transformValue * SKELCURVE_SCALE_SCALE;
} else if (vecType == SKELCURVE_VEC_TYPE_ROTATION) {
// Convert value from degrees to a binary angle
*jointData = DEG_TO_BINANG(transformValue);
} else { // SKELCURVE_VEC_TYPE_POSIITON
// Model to world scale conversion
*jointData = transformValue * SKELCURVE_SCALE_POSITION;
}
}
knotCounts++;
jointData++;
}
}
}
return ret;
}
/**
* Recursively draws limbs with appropriate properties.
*/
void SkelCurve_DrawLimb(PlayState* play, s32 limbIndex, SkelCurve* skelCurve, OverrideCurveLimbDraw overrideLimbDraw,
PostCurveLimbDraw postLimbDraw, s32 lod, void* data) {
SkelCurveLimb* limb = SEGMENTED_TO_VIRTUAL(skelCurve->skeleton[limbIndex]);
OPEN_DISPS(play->state.gfxCtx, "../z_fcurve_data_skelanime.c", 279);
Matrix_Push();
if ((overrideLimbDraw == NULL) ||
((overrideLimbDraw != NULL) && overrideLimbDraw(play, skelCurve, limbIndex, data))) {
Vec3f scale;
Vec3s rot;
Vec3f pos;
Gfx* dList;
s16* jointData = skelCurve->jointTable[limbIndex];
scale.x = jointData[0] / SKELCURVE_SCALE_SCALE;
scale.y = jointData[1] / SKELCURVE_SCALE_SCALE;
scale.z = jointData[2] / SKELCURVE_SCALE_SCALE;
jointData += 3;
rot.x = jointData[0];
rot.y = jointData[1];
rot.z = jointData[2];
jointData += 3;
pos.x = jointData[0];
pos.y = jointData[1];
pos.z = jointData[2];
Matrix_TranslateRotateZYX(&pos, &rot);
Matrix_Scale(scale.x, scale.y, scale.z, MTXMODE_APPLY);
if (lod == 0) {
s32 pad1;
dList = limb->dList[0];
if (dList != NULL) {
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, "../z_fcurve_data_skelanime.c", 321),
G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, dList);
}
} else if (lod == 1) {
s32 pad2;
dList = limb->dList[0];
if (dList != NULL) {
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, "../z_fcurve_data_skelanime.c", 332),
G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, dList);
}
dList = limb->dList[1];
if (dList != NULL) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, "../z_fcurve_data_skelanime.c", 338),
G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, dList);
}
} else {
// "FcSkeletonInfo_draw_child (): Not supported"
osSyncPrintf("FcSkeletonInfo_draw_child():未対応\n");
}
}
if (postLimbDraw != NULL) {
postLimbDraw(play, skelCurve, limbIndex, data);
}
if (limb->child != LIMB_DONE) {
SkelCurve_DrawLimb(play, limb->child, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
}
Matrix_Pop();
if (limb->sibling != LIMB_DONE) {
SkelCurve_DrawLimb(play, limb->sibling, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
}
CLOSE_DISPS(play->state.gfxCtx, "../z_fcurve_data_skelanime.c", 371);
}
void SkelCurve_Draw(Actor* actor, PlayState* play, SkelCurve* skelCurve, OverrideCurveLimbDraw overrideLimbDraw,
PostCurveLimbDraw postLimbDraw, s32 lod, void* data) {
if (skelCurve->jointTable != NULL) {
SkelCurve_DrawLimb(play, 0, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
}
}