1
0
mirror of https://github.com/zeldaret/oot.git synced 2024-09-21 04:24:43 +00:00

Document SkelCurve system (#1192)

* Rename and document SkelCurve

* AVOID_UB in DemoTreLgt_OverrideLimbDraw

* Rename code_8006C510

* Objdump flags in the makefile

* Move CC_CHECK above compilation

* Review 1

* Review 2

* Review 3

* Review
Add doxygen comments to file head
use angle macro,
improve bug comment,
make arguments of SkelCurve_Draw more consistent,
Change this temp to pad in MagicWind
This commit is contained in:
EllipticEllipsis 2022-05-20 07:27:54 +01:00 committed by GitHub
parent 0584b3d288
commit 0e51a51fb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 342 additions and 213 deletions

View File

@ -142,6 +142,8 @@ else
CC_CHECK = @:
endif
OBJDUMP_FLAGS := -d -r -z -Mreg-names=32
#### Files ####
# ROM image
@ -320,21 +322,21 @@ build/src/boot/z_std_dma.o: build/dmadata_table_spec.h
build/src/dmadata/dmadata.o: build/dmadata_table_spec.h
build/src/%.o: src/%.c
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
$(CC_CHECK) $<
@$(OBJDUMP) -d $@ > $(@:.o=.s)
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
@$(OBJDUMP) $(OBJDUMP_FLAGS) $@ > $(@:.o=.s)
build/src/libultra/libc/ll.o: src/libultra/libc/ll.c
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
$(CC_CHECK) $<
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
python3 tools/set_o32abi_bit.py $@
@$(OBJDUMP) -d $@ > $(@:.o=.s)
@$(OBJDUMP) $(OBJDUMP_FLAGS) $@ > $(@:.o=.s)
build/src/libultra/libc/llcvt.o: src/libultra/libc/llcvt.c
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
$(CC_CHECK) $<
$(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $<
python3 tools/set_o32abi_bit.py $@
@$(OBJDUMP) -d $@ > $(@:.o=.s)
@$(OBJDUMP) $(OBJDUMP_FLAGS) $@ > $(@:.o=.s)
build/src/overlays/%_reloc.o: build/$(SPEC)
$(FADO) $$(tools/reloc_prereq $< $(notdir $*)) -n $(notdir $*) -o $(@:.o=.s) -M $(@:.o=.d)

View File

@ -840,16 +840,6 @@ void Flags_UnsetAllEnv(GlobalContext* globalCtx);
void Flags_SetEnv(GlobalContext* globalCtx, s16 flag);
void Flags_UnsetEnv(GlobalContext* globalCtx, s16 flag);
s32 Flags_GetEnv(GlobalContext* globalCtx, s16 flag);
f32 func_8006C5A8(f32 target, TransformData* transData, s32 refIdx);
void SkelCurve_Clear(SkelAnimeCurve* skelCurve);
s32 SkelCurve_Init(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, SkelCurveLimbList* limbListSeg,
TransformUpdateIndex* transUpdIdx);
void SkelCurve_Destroy(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve);
void SkelCurve_SetAnim(SkelAnimeCurve* skelCurve, TransformUpdateIndex* transUpdIdx, f32 arg2, f32 animFinalFrame,
f32 animCurFrame, f32 animSpeed);
s32 SkelCurve_Update(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve);
void SkelCurve_Draw(Actor* actor, GlobalContext* globalCtx, SkelAnimeCurve* skelCurve,
OverrideCurveLimbDraw overrideLimbDraw, PostCurveLimbDraw postLimbDraw, s32 lod, void* data);
s32 func_8006CFC0(s32 scene);
void func_8006D074(GlobalContext* globalCtx);
void func_8006D0AC(GlobalContext* globalCtx);

View File

@ -15,6 +15,7 @@
#include "z64environment.h"
#include "z64cutscene.h"
#include "z64collision_check.h"
#include "z64curve.h"
#include "z64scene.h"
#include "z64effect.h"
#include "z64item.h"

View File

@ -189,54 +189,6 @@ typedef struct AnimationContext {
typedef void (*AnimationEntryCallback)(struct GlobalContext* globalCtx, AnimationEntryData* data);
// fcurve_skelanime structs
typedef struct {
/* 0x0000 */ u16 unk_00; // appears to be flags
/* 0x0002 */ s16 unk_02;
/* 0x0004 */ s16 unk_04;
/* 0x0006 */ s16 unk_06;
/* 0x0008 */ f32 unk_08;
} TransformData; // size = 0xC
typedef struct {
/* 0x0000 */ u8* refIndex;
/* 0x0004 */ TransformData* transformData;
/* 0x0008 */ s16* copyValues;
/* 0x000C */ s16 unk_0C;
/* 0x000E */ s16 unk_0E;
} TransformUpdateIndex; // size = 0x10
typedef struct {
/* 0x0000 */ u8 firstChildIdx;
/* 0x0001 */ u8 nextLimbIdx;
/* 0x0004 */ Gfx* dList[2];
} SkelCurveLimb; // size = 0xC
typedef struct {
/* 0x0000 */ SkelCurveLimb** limbs;
/* 0x0004 */ u8 limbCount;
} SkelCurveLimbList; // size = 0x8
typedef struct {
/* 0x0000 */ Vec3s scale;
/* 0x0006 */ Vec3s rot;
/* 0x000C */ Vec3s pos;
} LimbTransform; // size = 0x12
typedef struct {
/* 0x0000 */ u8 limbCount;
/* 0x0004 */ SkelCurveLimb** limbList;
/* 0x0008 */ TransformUpdateIndex* transUpdIdx;
/* 0x000C */ f32 unk_0C; // seems to be unused
/* 0x0010 */ f32 animFinalFrame;
/* 0x0014 */ f32 animSpeed;
/* 0x0018 */ f32 animCurFrame;
/* 0x001C */ LimbTransform* transforms;
} SkelAnimeCurve; // size = 0x20
typedef s32 (*OverrideCurveLimbDraw)(struct GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, s32 limbIndex, void*);
typedef void (*PostCurveLimbDraw)(struct GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, s32 limbIndex, void*);
typedef s32 (*AnimUpdateFunc)();
typedef struct SkelAnime {

68
include/z64curve.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef Z64_CURVE_H
#define Z64_CURVE_H
#include "ultra64/types.h"
#include "z64math.h"
struct GlobalContext;
typedef struct {
/* 0x0 */ u16 flags; // Only the bottom two bits are used, although others are set in objects
/* 0x2 */ s16 abscissa; // knot input value
/* 0x4 */ s16 leftGradient; // left derivative at the point
/* 0x6 */ s16 rightGradient; // right derivative at the point
/* 0x8 */ f32 ordinate; // output value
} CurveInterpKnot; // size = 0xC
typedef struct {
/* 0x0 */ u8* knotCounts;
/* 0x4 */ CurveInterpKnot* interpolationData;
/* 0x8 */ s16* constantData;
/* 0xC */ s16 unk_0C; // Set but not used, always 1 in objects
/* 0xE */ s16 frameCount; // Not used, inferred from use in objects
} CurveAnimationHeader; // size = 0x10
typedef struct {
/* 0x0 */ u8 child;
/* 0x1 */ u8 sibling;
/* 0x4 */ Gfx* dList[2];
} SkelCurveLimb; // size = 0xC
typedef struct {
/* 0x0 */ SkelCurveLimb** limbs;
/* 0x4 */ u8 limbCount;
} CurveSkeletonHeader; // size = 0x8
typedef struct {
/* 0x00 */ u8 limbCount;
/* 0x04 */ SkelCurveLimb** skeleton;
/* 0x08 */ CurveAnimationHeader* animation;
/* 0x0C */ f32 unk_0C; // set but not used
/* 0x10 */ f32 endFrame;
/* 0x14 */ f32 playSpeed;
/* 0x18 */ f32 curFrame;
/* 0x1C */ s16 (*jointTable)[9];
} SkelCurve; // size = 0x20
typedef s32 (*OverrideCurveLimbDraw)(struct GlobalContext* globalCtx, SkelCurve* skelCuve, s32 limbIndex, void* thisx);
typedef void (*PostCurveLimbDraw)(struct GlobalContext* globalCtx, SkelCurve* skelCuve, s32 limbIndex, void* thisx);
f32 Curve_Interpolate(f32 x, CurveInterpKnot* transData, s32 refIdx);
void SkelCurve_Clear(SkelCurve* skelCurve);
s32 SkelCurve_Init(struct GlobalContext* globalCtx, SkelCurve* skelCurve, CurveSkeletonHeader* limbListSeg, CurveAnimationHeader* transUpdIdx);
void SkelCurve_Destroy(struct GlobalContext* globalCtx, SkelCurve* skelCurve);
void SkelCurve_SetAnim(SkelCurve* skelCurve, CurveAnimationHeader* transUpdIdx, f32 arg2, f32 endFrame, f32 curFrame, f32 playSpeed);
s32 SkelCurve_Update(struct GlobalContext* globalCtx, SkelCurve* skelCurve);
void SkelCurve_Draw(Actor* actor, struct GlobalContext* globalCtx, SkelCurve* skelCurve, OverrideCurveLimbDraw overrideLimbDraw, PostCurveLimbDraw postLimbDraw, s32 lod, void* thisx);
// ZAPD compatibility typedefs
// TODO: Remove when ZAPD adds support for them
typedef CurveInterpKnot TransformData;
typedef CurveAnimationHeader TransformUpdateIndex;
typedef CurveSkeletonHeader SkelCurveLimbList;
#endif

2
spec
View File

@ -322,7 +322,7 @@ beginseg
include "build/src/code/z_elf_message.o"
include "build/src/code/z_face_reaction.o"
include "build/src/code/code_8006C3A0.o"
include "build/src/code/code_8006C510.o"
include "build/src/code/z_fcurve_data.o"
include "build/src/code/z_fcurve_data_skelanime.o"
include "build/src/code/z_game_dlftbls.o"
include "build/src/code/z_horse.o"

View File

@ -1,40 +0,0 @@
#include "global.h"
f32 func_8006C510(f32 arg0, f32 arg1, f32 arg2, f32 arg3, f32 arg4, f32 arg5) {
char pad[0x1C];
f32 sq = SQ(arg0);
f32 cube = sq * arg0;
return (((cube + cube) - sq * 3.0f) + 1.0f) * arg2 + (sq * 3.0f - (cube + cube)) * arg3 +
((cube - (sq + sq)) + arg0) * arg4 * arg1 + (cube - sq) * arg5 * arg1;
}
f32 func_8006C5A8(f32 target, TransformData* transData, s32 refIdx) {
s32 i;
s32 j;
if (target <= transData->unk_02) {
return transData->unk_08;
}
if (target >= transData[refIdx - 1].unk_02) {
return transData[refIdx - 1].unk_08;
}
for (i = 0;; i++) {
j = i + 1;
if (transData[j].unk_02 > target) {
if (transData[i].unk_00 & 1) {
return transData[i].unk_08;
} else if (transData[i].unk_00 & 2) {
return transData[i].unk_08 +
((target - (f32)transData[i].unk_02) / ((f32)transData[j].unk_02 - (f32)transData[i].unk_02)) *
(transData[j].unk_08 - transData[i].unk_08);
} else {
f32 diff = (f32)transData[j].unk_02 - (f32)transData[i].unk_02;
return func_8006C510((target - transData[i].unk_02) / ((f32)transData[j].unk_02 - transData[i].unk_02),
diff * (1.0f / 30.0f), transData[i].unk_08, transData[j].unk_08,
transData[i].unk_06, transData[j].unk_04);
}
}
}
}

85
src/code/z_fcurve_data.c Normal file
View File

@ -0,0 +1,85 @@
/**
* File: z_fcurve_data.c
* Description: Interpolation functions for use with Curve SkelAnime
*/
#include "global.h"
#include "z64curve.h"
#define FCURVE_INTERP_CUBIC 0 // Interpolate using a Hermite cubic spline
#define FCURVE_INTERP_NONE 1 // Return the value at the left endpoint instead of interpolating
#define FCURVE_INTERP_LINEAR 2 // Interpolate linearly
/**
* Hermite cubic spline interpolation between two endpoints, a,b. More information available at
* https://en.wikipedia.org/wiki/Cubic_Hermite_spline
*
* @param t interpolation parameter rescaled to lie in [0,1], (x-a)/(b-a)
* @param interval distance (b-a) between the endpoints
* @param y0 p(a)
* @param y1 p(b)
* @param m0 p'(a)
* @param m1 p'(b)
* @return f32 p(t), value of the cubic interpolating polynomial
*/
f32 Curve_CubicHermiteSpline(f32 t, f32 interval, f32 y0, f32 y1, f32 m0, f32 m1) {
f32 t2 = t * t;
f32 t3 = t2 * t;
f32 t3x2 = t3 * 2.0f;
f32 t2x3 = t2 * 3.0f;
// Hermite basis cubics h_{ij} satisfy h_{ij}^{(j)}(i) = 1, the other three values being 0
f32 h00 = t3x2 - t2x3 + 1.0f; // h_{00}(t) = 2t^3 - 3t^2 + 1
f32 h01 = t2x3 - t3x2; // h_{01}(t) = 3t^2 - 2t^3
f32 h10 = t3 - t2 * 2.0f + t; // h_{10}(t) = t^3 - 2t^2 + t
f32 h11 = t3 - t2; // h_{11}(t) = t^3 - t^2
f32 ret = h00 * y0;
ret += h01 * y1;
ret += h10 * m0 * interval;
ret += h11 * m1 * interval;
return ret;
}
/**
* Interpolates based on an array of CurveInterpKnot.
*
* @param x point at which to interpolate.
* @param knots Beginning of CurveInterpKnot array to use.
* @param knotCount number of knots to read from the array.
* @return f32 interpolated value
*/
f32 Curve_Interpolate(f32 x, CurveInterpKnot* knots, s32 knotCount) {
// If outside the entire interpolation interval, return the value at the near endpoint.
if (x <= knots[0].abscissa) {
return knots[0].ordinate;
} else if (x >= knots[knotCount - 1].abscissa) {
return knots[knotCount - 1].ordinate;
} else {
s32 cur;
for (cur = 0;; cur++) {
s32 next = cur + 1;
// Find the subinterval in which x lies
if (x < knots[next].abscissa) {
if (knots[cur].flags & FCURVE_INTERP_NONE) {
// No interpolation
return knots[cur].ordinate;
} else if (knots[cur].flags & FCURVE_INTERP_LINEAR) {
// Linear interpolation
return knots[cur].ordinate +
((x - (f32)knots[cur].abscissa) / ((f32)knots[next].abscissa - (f32)knots[cur].abscissa)) *
(knots[next].ordinate - knots[cur].ordinate);
} else {
// Cubic interpolation
f32 diff = (f32)knots[next].abscissa - (f32)knots[cur].abscissa;
f32 t = (x - (f32)knots[cur].abscissa) / ((f32)knots[next].abscissa - (f32)knots[cur].abscissa);
return Curve_CubicHermiteSpline(t, diff * (1.0f / 30.0f), knots[cur].ordinate, knots[next].ordinate,
knots[cur].rightGradient, knots[next].leftGradient);
}
}
}
}
}

View File

@ -1,90 +1,151 @@
/**
* @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(SkelAnimeCurve* skelCurve) {
void SkelCurve_Clear(SkelCurve* skelCurve) {
skelCurve->limbCount = 0;
skelCurve->limbList = NULL;
skelCurve->transUpdIdx = NULL;
skelCurve->animCurFrame = 0.0f;
skelCurve->animSpeed = 0.0f;
skelCurve->animFinalFrame = 0.0f;
skelCurve->transforms = NULL;
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;
}
s32 SkelCurve_Init(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, SkelCurveLimbList* limbListSeg,
TransformUpdateIndex* transUpdIdx) {
/**
* Initialises the SkelCurve struct and mallocs the joint table.
*
* @return bool always true
*/
s32 SkelCurve_Init(GlobalContext* globalCtx, SkelCurve* skelCurve, CurveSkeletonHeader* skeletonHeaderSeg,
CurveAnimationHeader* animation) {
SkelCurveLimb** limbs;
SkelCurveLimbList* limbList = SEGMENTED_TO_VIRTUAL(limbListSeg);
CurveSkeletonHeader* skeletonHeader = SEGMENTED_TO_VIRTUAL(skeletonHeaderSeg);
skelCurve->limbCount = limbList->limbCount;
skelCurve->limbList = SEGMENTED_TO_VIRTUAL(limbList->limbs);
skelCurve->limbCount = skeletonHeader->limbCount;
skelCurve->skeleton = SEGMENTED_TO_VIRTUAL(skeletonHeader->limbs);
skelCurve->transforms = ZeldaArena_MallocDebug(sizeof(*skelCurve->transforms) * skelCurve->limbCount,
skelCurve->jointTable = ZeldaArena_MallocDebug(sizeof(*skelCurve->jointTable) * skelCurve->limbCount,
"../z_fcurve_data_skelanime.c", 125);
ASSERT(skelCurve->transforms != NULL, "this->now_joint != NULL", "../z_fcurve_data_skelanime.c", 127);
skelCurve->animCurFrame = 0.0f;
return 1;
ASSERT(skelCurve->jointTable != NULL, "this->now_joint != NULL", "../z_fcurve_data_skelanime.c", 127);
skelCurve->curFrame = 0.0f;
return true;
}
void SkelCurve_Destroy(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve) {
if (skelCurve->transforms != NULL) {
ZeldaArena_FreeDebug(skelCurve->transforms, "../z_fcurve_data_skelanime.c", 146);
/**
* Frees the joint table.
*/
void SkelCurve_Destroy(GlobalContext* globalCtx, SkelCurve* skelCurve) {
if (skelCurve->jointTable != NULL) {
ZeldaArena_FreeDebug(skelCurve->jointTable, "../z_fcurve_data_skelanime.c", 146);
}
}
void SkelCurve_SetAnim(SkelAnimeCurve* skelCurve, TransformUpdateIndex* transUpdIdx, f32 arg2, f32 animFinalFrame,
f32 animCurFrame, f32 animSpeed) {
skelCurve->unk_0C = arg2 - skelCurve->animSpeed;
skelCurve->animFinalFrame = animFinalFrame;
skelCurve->animCurFrame = animCurFrame;
skelCurve->animSpeed = animSpeed;
skelCurve->transUpdIdx = transUpdIdx;
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;
}
s32 SkelCurve_Update(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve) {
s16* transforms;
u8* transformRefIdx;
TransformUpdateIndex* transformIndex;
u16* transformCopyValues;
s32 i;
s32 ret = 0;
s32 k;
TransformData* transData;
f32 transformValue;
s32 j;
typedef enum {
/* 0 */ SKELCURVE_VEC_TYPE_SCALE,
/* 1 */ SKELCURVE_VEC_TYPE_ROTATION,
/* 2 */ SKELCURVE_VEC_TYPE_POSIITON,
/* 3 */ SKELCURVE_VEC_TYPE_MAX
} SkelCurveVecType;
transformIndex = SEGMENTED_TO_VIRTUAL(skelCurve->transUpdIdx);
transformRefIdx = SEGMENTED_TO_VIRTUAL(transformIndex->refIndex);
transData = SEGMENTED_TO_VIRTUAL(transformIndex->transformData);
transformCopyValues = SEGMENTED_TO_VIRTUAL(transformIndex->copyValues);
transforms = (s16*)skelCurve->transforms;
#define SKELCURVE_SCALE_SCALE 1024.0f
#define SKELCURVE_SCALE_POSITION 100
skelCurve->animCurFrame += skelCurve->animSpeed * R_UPDATE_RATE * 0.5f;
/**
* The only animation updating function.
*
* @return bool true when the animation has finished.
*/
s32 SkelCurve_Update(GlobalContext* globalCtx, SkelCurve* skelCurve) {
s16* jointData;
u8* knotCounts;
CurveAnimationHeader* animation;
u16* constantData;
s32 curLimb;
s32 ret = false;
s32 coord;
CurveInterpKnot* startKnot;
s32 vecType;
if ((skelCurve->animSpeed >= 0.0f && skelCurve->animCurFrame > skelCurve->animFinalFrame) ||
(skelCurve->animSpeed < 0.0f && skelCurve->animCurFrame < skelCurve->animFinalFrame)) {
skelCurve->animCurFrame = skelCurve->animFinalFrame;
ret = 1;
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 (i = 0; i < skelCurve->limbCount; i++) {
for (j = 0; j < 3; j++) {
for (k = 0; k < 3; k++, transformRefIdx++, transforms++) {
if (*transformRefIdx == 0) {
transformValue = *transformCopyValues;
*transforms = transformValue;
transformCopyValues++;
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 = func_8006C5A8(skelCurve->animCurFrame, transData, *transformRefIdx);
transData += *transformRefIdx;
if (j == 0) {
*transforms = transformValue * 1024.0f;
} else if (j == 1) {
*transforms = transformValue * (32768.0f / 180.0f);
} else {
*transforms = transformValue * 100.0f;
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++;
}
}
}
@ -92,33 +153,36 @@ s32 SkelCurve_Update(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve) {
return ret;
}
void SkelCurve_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, SkelAnimeCurve* skelCurve,
/**
* Recursively draws limbs with appropriate properties.
*/
void SkelCurve_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, SkelCurve* skelCurve,
OverrideCurveLimbDraw overrideLimbDraw, PostCurveLimbDraw postLimbDraw, s32 lod, void* data) {
SkelCurveLimb* limb = SEGMENTED_TO_VIRTUAL(skelCurve->limbList[limbIndex]);
SkelCurveLimb* limb = SEGMENTED_TO_VIRTUAL(skelCurve->skeleton[limbIndex]);
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_fcurve_data_skelanime.c", 279);
Matrix_Push();
if (overrideLimbDraw == NULL ||
(overrideLimbDraw != NULL && overrideLimbDraw(globalCtx, skelCurve, limbIndex, data))) {
if ((overrideLimbDraw == NULL) ||
((overrideLimbDraw != NULL) && overrideLimbDraw(globalCtx, skelCurve, limbIndex, data))) {
Vec3f scale;
Vec3s rot;
Vec3f pos;
Gfx* dList;
Vec3s* transform = (Vec3s*)&skelCurve->transforms[limbIndex];
s16* jointData = skelCurve->jointTable[limbIndex];
scale.x = transform->x / 1024.0f;
scale.y = transform->y / 1024.0f;
scale.z = transform->z / 1024.0f;
transform++;
rot.x = transform->x;
rot.y = transform->y;
rot.z = transform->z;
transform++;
pos.x = transform->x;
pos.y = transform->y;
pos.z = transform->z;
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);
@ -157,22 +221,22 @@ void SkelCurve_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, SkelAnimeCurve*
postLimbDraw(globalCtx, skelCurve, limbIndex, data);
}
if (limb->firstChildIdx != LIMB_DONE) {
SkelCurve_DrawLimb(globalCtx, limb->firstChildIdx, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
if (limb->child != LIMB_DONE) {
SkelCurve_DrawLimb(globalCtx, limb->child, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
}
Matrix_Pop();
if (limb->nextLimbIdx != LIMB_DONE) {
SkelCurve_DrawLimb(globalCtx, limb->nextLimbIdx, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
if (limb->sibling != LIMB_DONE) {
SkelCurve_DrawLimb(globalCtx, limb->sibling, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_fcurve_data_skelanime.c", 371);
}
void SkelCurve_Draw(Actor* actor, GlobalContext* globalCtx, SkelAnimeCurve* skelCurve,
void SkelCurve_Draw(Actor* actor, GlobalContext* globalCtx, SkelCurve* skelCurve,
OverrideCurveLimbDraw overrideLimbDraw, PostCurveLimbDraw postLimbDraw, s32 lod, void* data) {
if (skelCurve->transforms != NULL) {
if (skelCurve->jointTable != NULL) {
SkelCurve_DrawLimb(globalCtx, 0, skelCurve, overrideLimbDraw, postLimbDraw, lod, data);
}
}

View File

@ -2043,7 +2043,7 @@ void DemoEffect_DrawGetItem(Actor* thisx, GlobalContext* globalCtx) {
/**
* Callback for the SkelCurve system to draw the animated limbs.
*/
s32 DemoEffect_DrawTimewarpLimbs(GlobalContext* globalCtx, SkelAnimeCurve* skelCuve, s32 limbIndex, void* thisx) {
s32 DemoEffect_OverrideLimbDrawTimeWarp(GlobalContext* globalCtx, SkelCurve* skelCurve, s32 limbIndex, void* thisx) {
s32 pad;
DemoEffect* this = (DemoEffect*)thisx;
u32 frames = globalCtx->gameplayFrames;
@ -2058,13 +2058,13 @@ s32 DemoEffect_DrawTimewarpLimbs(GlobalContext* globalCtx, SkelAnimeCurve* skelC
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_demo_effect.c", 3172);
if (limbIndex == 0) {
LimbTransform* transform = &skelCuve->transforms[0];
s16* transform = skelCurve->jointTable[0];
transform->scale.y = 1024;
transform->scale.z = transform->scale.x = 1024;
transform[2] = transform[0] = 1024;
transform[1] = 1024;
}
return 1;
return true;
}
/**
@ -2079,9 +2079,11 @@ void DemoEffect_DrawTimeWarp(Actor* thisx, GlobalContext* globalCtx) {
Flags_GetEnv(globalCtx, 1) || gSaveContext.sceneSetupIndex >= 4 ||
gSaveContext.entranceIndex == ENTR_TOKINOMA_4) {
OPEN_DISPS(gfxCtx, "../z_demo_effect.c", 3201);
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 25);
Matrix_Scale(2.0f, 2.0f, 2.0f, MTXMODE_APPLY);
SkelCurve_Draw(thisx, globalCtx, &this->skelCurve, DemoEffect_DrawTimewarpLimbs, NULL, 1, this);
SkelCurve_Draw(&this->actor, globalCtx, &this->skelCurve, DemoEffect_OverrideLimbDrawTimeWarp, NULL, 1, &this->actor);
CLOSE_DISPS(gfxCtx, "../z_demo_effect.c", 3216);
}
}

View File

@ -78,7 +78,7 @@ typedef struct {
typedef struct DemoEffect {
/* 0x0000 */ Actor actor;
/* 0x014C */ SkelAnimeCurve skelCurve;
/* 0x014C */ SkelCurve skelCurve;
/* 0x016C */ u8 initObjectBankIndex;
/* 0x0170 */ Gfx* jewelDisplayList;
/* 0x0174 */ Gfx* jewelHolderDisplayList;

View File

@ -38,7 +38,7 @@ const ActorInit Demo_Tre_Lgt_InitVars = {
(ActorFunc)DemoTreLgt_Draw,
};
static TransformUpdateIndex* sTransformUpdIdx[] = { &gTreasureChestCurveAnim_4B60, &gTreasureChestCurveAnim_4F70 };
static CurveAnimationHeader* sAnimations[] = { &gTreasureChestCurveAnim_4B60, &gTreasureChestCurveAnim_4F70 };
static DemoTreLgtActionFunc sActionFuncs[] = {
func_8099375C,
@ -48,7 +48,7 @@ static DemoTreLgtActionFunc sActionFuncs[] = {
void DemoTreLgt_Init(Actor* thisx, GlobalContext* globalCtx) {
DemoTreLgt* this = (DemoTreLgt*)thisx;
if (!SkelCurve_Init(globalCtx, &this->skelCurve, &gTreasureChestCurveSkel, sTransformUpdIdx[0])) {
if (!SkelCurve_Init(globalCtx, &this->skelCurve, &gTreasureChestCurveSkel, sAnimations[0])) {
// "Demo_Tre_Lgt_Actor_ct (); Construct failed"
osSyncPrintf("Demo_Tre_Lgt_Actor_ct();コンストラクト失敗\n");
}
@ -74,25 +74,25 @@ void func_80993754(DemoTreLgt* this) {
void func_8099375C(DemoTreLgt* this, GlobalContext* globalCtx) {
EnBox* treasureChest = (EnBox*)this->actor.parent;
if (treasureChest != NULL && Animation_OnFrame(&treasureChest->skelanime, 10.0f)) {
if ((treasureChest != NULL) && Animation_OnFrame(&treasureChest->skelanime, 10.0f)) {
func_809937B4(this, globalCtx, treasureChest->skelanime.curFrame);
}
}
void func_809937B4(DemoTreLgt* this, GlobalContext* globalCtx, f32 currentFrame) {
SkelAnimeCurve* skelCurve = &this->skelCurve;
SkelCurve* skelCurve = &this->skelCurve;
s32 pad[2];
this->action = DEMO_TRE_LGT_ACTION_ANIMATE;
SkelCurve_SetAnim(skelCurve, sTransformUpdIdx[gSaveContext.linkAge], 1.0f,
SkelCurve_SetAnim(skelCurve, sAnimations[gSaveContext.linkAge], 1.0f,
sDemoTreLgtInfo[gSaveContext.linkAge].endFrame + sDemoTreLgtInfo[gSaveContext.linkAge].unk_08,
currentFrame, 1.0f);
SkelCurve_Update(globalCtx, skelCurve);
}
void func_80993848(DemoTreLgt* this, GlobalContext* globalCtx) {
f32 currentFrame = this->skelCurve.animCurFrame;
f32 currentFrame = this->skelCurve.curFrame;
if (currentFrame < sDemoTreLgtInfo[((void)0, gSaveContext.linkAge)].endFrame) {
this->unk_170 = 255;
@ -131,7 +131,7 @@ void DemoTreLgt_Update(Actor* thisx, GlobalContext* globalCtx) {
sActionFuncs[this->action](this, globalCtx);
}
s32 DemoTreLgt_OverrideLimbDraw(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, s32 limbIndex, void* thisx) {
s32 DemoTreLgt_OverrideLimbDraw(GlobalContext* globalCtx, SkelCurve* skelCurve, s32 limbIndex, void* thisx) {
s32 pad;
DemoTreLgt* this = (DemoTreLgt*)thisx;
@ -149,9 +149,14 @@ s32 DemoTreLgt_OverrideLimbDraw(GlobalContext* globalCtx, SkelAnimeCurve* skelCu
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_demo_tre_lgt.c", 448);
//! @bug missing return
// If the return value ends up being false (0), the limb won't draw (meaning no limb at all will draw).
// In MQ Debug, `Graph_CloseDisps` has the last instruction writing to v0 before this function ends.
// That instruction sets v0 to a non-NULL pointer, which is "true", so the limbs get drawn.
//! If the returned value (i.e. the contents of v0) ends up being false (0), the limb won't draw. Therefore what
//! matters is what was last written to v0 before the end of the function.
//! - In debug versions, the last instruction that does this is in `Graph_CloseDisps`.
//! - In retail versions, `gDPSetPrimColor` writes to it last.
//! In both cases, that instruction sets v0 to a non-NULL pointer, which is "true", so the limb happens to be drawn.
#ifdef AVOID_UB
return true;
#endif
}
void DemoTreLgt_Draw(Actor* thisx, GlobalContext* globalCtx) {
@ -166,7 +171,7 @@ void DemoTreLgt_Draw(Actor* thisx, GlobalContext* globalCtx) {
func_80093D84(gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 200, 255, 0, 0);
SkelCurve_Draw(&this->actor, globalCtx, &this->skelCurve, DemoTreLgt_OverrideLimbDraw, NULL, 1, thisx);
SkelCurve_Draw(&this->actor, globalCtx, &this->skelCurve, DemoTreLgt_OverrideLimbDraw, NULL, 1, &this->actor);
CLOSE_DISPS(gfxCtx, "../z_demo_tre_lgt.c", 476);
}

View File

@ -10,7 +10,7 @@ typedef void (*DemoTreLgtActionFunc)(struct DemoTreLgt*, GlobalContext*);
typedef struct DemoTreLgt {
/* 0x0000 */ Actor actor;
/* 0x014C */ SkelAnimeCurve skelCurve;
/* 0x014C */ SkelCurve skelCurve;
/* 0x016C */ s32 action;
/* 0x0170 */ u32 unk_170; // some sort of alpha
/* 0x0174 */ u32 unk_174; // another sort of alpha

View File

@ -45,7 +45,7 @@ void MagicWind_Init(Actor* thisx, GlobalContext* globalCtx) {
MagicWind* this = (MagicWind*)thisx;
Player* player = GET_PLAYER(globalCtx);
if (SkelCurve_Init(globalCtx, &this->skelCurve, &sSkel, &sAnim) == 0) {
if (!SkelCurve_Init(globalCtx, &this->skelCurve, &sSkel, &sAnim)) {
// "Magic_Wind_Actor_ct (): Construct failed"
osSyncPrintf("Magic_Wind_Actor_ct():コンストラクト失敗\n");
}
@ -140,8 +140,8 @@ void MagicWind_Update(Actor* thisx, GlobalContext* globalCtx) {
this->actionFunc(this, globalCtx);
}
s32 MagicWind_OverrideLimbDraw(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, s32 limbIndex, void* thisx) {
MagicWind* this = (MagicWind*)thisx;
s32 MagicWind_OverrideLimbDraw(GlobalContext* globalCtx, SkelCurve* skelCurve, s32 limbIndex, void* thisx) {
s32 pad;
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_magic_wind.c", 615);
@ -173,7 +173,7 @@ void MagicWind_Draw(Actor* thisx, GlobalContext* globalCtx) {
if (this->actionFunc != MagicWind_WaitForTimer) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 25);
SkelCurve_Draw(thisx, globalCtx, &this->skelCurve, MagicWind_OverrideLimbDraw, NULL, 1, NULL);
SkelCurve_Draw(&this->actor, globalCtx, &this->skelCurve, MagicWind_OverrideLimbDraw, NULL, 1, NULL);
}
CLOSE_DISPS(gfxCtx, "../z_magic_wind.c", 673);

View File

@ -10,7 +10,7 @@ typedef void (*MagicWindFunc)(struct MagicWind* this, GlobalContext* globalCtx);
typedef struct MagicWind {
/* 0x0000 */ Actor actor;
/* 0x014C */ SkelAnimeCurve skelCurve;
/* 0x014C */ SkelCurve skelCurve;
/* 0x016C */ s16 timer;
/* 0x0170 */ MagicWindFunc actionFunc;
} MagicWind; // size = 0x0174