diff options
| author | emilybrooks <emilybrooksemilybrooks@gmail.com> | 2023-08-05 18:51:56 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-08-05 21:51:56 -0400 |
| commit | 44f0a79323a08c107df4217c76e0563f55872a81 (patch) | |
| tree | d933700160eb7e5a76118203dc6bd99569d481e0 /src/code/c_keyframe.c | |
| parent | 94b300b0d0e228dc38dcb08ca160334fa2ba128f (diff) | |
c_keyframe OK (#25)
* matched a few functions
* found some function names from the dnm+ map
* floating point hell and struct hell
* investigating skeletoninfo
* structs
* g3
* matching progress
* cKF_SkeletonInfo_R_AnimationMove_base
* lots of matched functions
* matched 2 functions
* keycalc
* rodata problem fixed
* cKF_SkeletonInfo_R_morphJoint matched
* cKF_Si3_draw_R_SV fake match
* cKF_SkeletonInfo_R_combine_translation matched
* cKF_SkeletonInfo_R_combine_rotation matched
* func_80053384_jp matched
* cKF_SkeletonInfo_R_AnimationMove_ct_base matched
* started documenting
* naming some stuff
* wrong struct size
* moved stuff to header files
* documenting
* more documenting
* comments for FrameControl done
* cKF_Si3_draw_SV_R_child fake match
* cleaning up draw functions
* imported bss
* matched cKF_SkeletonInfo_R_combine_play
* matched cKF_SkeletonInfo_R_T_combine_play
* matched cKF_SkeletonInfo_R_play
* everything matching
* cleaning up cKF_SkeletonInfo_R_play
* started on morph stuff
* cleaning up draw functions
* cleaning up structs
* trying to make pr ready
* changed wording
* review feedback
* forgot some animation pointer temps
* reverted cKF_SkeletonInfo_R_init_reverse_setspeedandmorphandmode
* review2
* fixed draw function fake matches
Diffstat (limited to 'src/code/c_keyframe.c')
| -rw-r--r-- | src/code/c_keyframe.c | 1227 |
1 files changed, 1227 insertions, 0 deletions
diff --git a/src/code/c_keyframe.c b/src/code/c_keyframe.c new file mode 100644 index 0000000..31a698f --- /dev/null +++ b/src/code/c_keyframe.c @@ -0,0 +1,1227 @@ +/** + * @file c_keyframe.c + * + * Skeletal animation with keyframes. + * + * This system was used in Majora's Mask, however Doubutsu no Mori uses the "R" variants of structs, which differ + * slightly. + * + * Animation is broken down into multiple parts that work together. + * + * FrameControl: A struct responsible for keeping track of the time component of animations. Animations use frames + * (one thirtieth of a second) as a unit of time. + * + * Joint: A display list that represents a small section of the overall model. Joints have a hierarchal structure, where + * joints can specify child joints, and each joint inherits it's parent's transformation. Joints are represented in two + * places. A JointElemR struct stores the joint's display list. There's also a jointTable gets passed in from an actor. + * This is a Vec3s array, with the first vector storing the root translation, the second vector is the root rotation, + * and each vector after that is a joint's rotation. + * + * Morph: Normally switching from the previous animation to a new animation produces jarring motion as the joints jump + * to the first frame of the new animation in a single frame. Morph allows the joints to interpolate between their old + * position and the current animation's position over multiple frames (specified by morphCounter) to avoid this. If an + * animation is using morph an array separate from jointTable, morphTable stores the the animation's joint rotations for + * the current frame. + * + * BaseSkeletonR: A collection of JointElemR structs that make up the skeleton that will be animated. + * + * BaseAnimationR: Stores keyframes used to animate the skeleton. Skeletons are animated by rotating joints. They can't + * be translated or scaled, and the distance between two joints will always be the same. The only joint that has + * translation data is the root joint. + * + * SkeletonInfoR: The large struct containing a FrameControl, BaseSkeletonR, BaseAnimationR, jointTable, morphTable, and + * more. + */ + +#include "global.h" +#include "c_keyframe.h" +#include "z64math.h" +#include "m_lib.h" +#include "gfx.h" +#include "m_play.h" +#include "fp.h" +#include "sys_matrix.h" +#include "sys_math3d.h" + +UNK_PTR* B_801458A0_jp[4]; + +void cKF_FrameControl_zeroClear(FrameControl* frameControl) { + bzero(frameControl, sizeof(FrameControl)); + frameControl->mode = ANIMATION_STOP; + frameControl->duration = 1.0f; + frameControl->currentFrame = 1.0f; + frameControl->speed = 1.0f; + frameControl->end = 1.0f; + frameControl->start = 1.0f; +} + +void cKF_FrameControl_ct(FrameControl* frameControl) { + cKF_FrameControl_zeroClear(frameControl); +} + +void cKF_FrameControl_setFrame(FrameControl* frameControl, f32 start, f32 end, f32 duration, f32 currentFrame, + f32 speed, AnimationMode mode) { + frameControl->start = start; + frameControl->end = (end < 1.0f) ? duration : end; + frameControl->duration = duration; + frameControl->speed = speed; + frameControl->currentFrame = currentFrame; + frameControl->mode = mode; +} + +/** + * Check if the next frame will pass the specified frame number. + * + * @param[in] frameControl The FrameControl struct to check. + * @param[in] compareFrame The frame number to compare against. + * @param[out] remainder The amount of frames past compareFrame. + * @return Boolean. True if the next frame passes compareFrame. + */ +s32 cKF_FrameControl_passCheck(FrameControl* frameControl, f32 compareFrame, f32* remainder) { + f32 speed; + + *remainder = 0.0f; + + if (compareFrame == frameControl->currentFrame) { + return false; + } + + speed = (frameControl->start < frameControl->end) ? frameControl->speed : -frameControl->speed; + + if ((speed >= 0.0f && frameControl->currentFrame < compareFrame && + frameControl->currentFrame + speed >= compareFrame) || + (speed < 0.0f && compareFrame < frameControl->currentFrame && + frameControl->currentFrame + speed <= compareFrame)) { + *remainder = frameControl->currentFrame + speed - compareFrame; + return true; + } + + return false; +} + +/** + * Check if the current frame is past the specified frame number. + * + * @return Boolean. True if the current frame is past compareFrame. + */ +s32 cKF_FrameControl_passCheck_now(FrameControl* frameControl, f32 compareFrame) { + s32 ret = false; + + if (compareFrame != frameControl->currentFrame) { + f32 speed = (frameControl->start < frameControl->end) ? frameControl->speed : -frameControl->speed; + + if ((speed >= 0.0f && compareFrame <= frameControl->currentFrame && + frameControl->currentFrame - speed < compareFrame) || + (speed < 0.0f && frameControl->currentFrame <= compareFrame && + frameControl->currentFrame - speed > compareFrame)) { + ret = true; + } + } else { + ret = true; + } + + return ret; +} + +/** + * Check if an animation that plays once has completed. + * + * @return 0 if the animation is still playing. 1 if the animation mode is ANIMATION_STOP and has completed. + */ +s32 cKF_FrameControl_stop_proc(FrameControl* frameControl) { + f32 remainder; + + if (frameControl->currentFrame == frameControl->end) { + return 1; + } + if (cKF_FrameControl_passCheck(frameControl, frameControl->end, &remainder)) { + frameControl->currentFrame = frameControl->end; + return 1; + } + if (cKF_FrameControl_passCheck(frameControl, frameControl->start, &remainder)) { + frameControl->currentFrame = frameControl->end; + return 1; + } + + return 0; +} + +/** + * Check if an animation that repeats has completed one loop. + * + * @return 0 if the animation is still playing. 2 if the animation mode is ANIMATION_REPEAT and a loop has completed. + */ +s32 cKF_FrameControl_repeat_proc(FrameControl* frameControl) { + f32 remainder; + + if (cKF_FrameControl_passCheck(frameControl, frameControl->end, &remainder)) { + frameControl->currentFrame = (f32)(frameControl->start + remainder); + return 2; + } + if (cKF_FrameControl_passCheck(frameControl, frameControl->start, &remainder)) { + frameControl->currentFrame = frameControl->end + remainder; + return 2; + } + + return 0; +} + +/** + * Advance a FrameControl struct by 1 frame. + * + * @return 0 if the animation is still playing. 1 if the animation mode is ANIMATION_STOP and has completed. 2 if the + * animation mode is ANIMATION_REPEAT and a loop has completed. + */ +s32 cKF_FrameControl_play(FrameControl* frameControl) { + f32 speed; + s32 ret; + + if (frameControl->mode == ANIMATION_STOP) { + ret = cKF_FrameControl_stop_proc(frameControl); + } else { + ret = cKF_FrameControl_repeat_proc(frameControl); + } + + // if the animation is still playing + if (ret == 0) { + speed = (frameControl->start < frameControl->end) ? frameControl->speed : -frameControl->speed; + frameControl->currentFrame += speed; + } + + // if the current frame is past the end, wrap the frame counter back to the start of the animation + if (frameControl->currentFrame < 1.0f) { + frameControl->currentFrame = (frameControl->currentFrame - 1.0f) + frameControl->duration; + } else if (frameControl->duration < frameControl->currentFrame) { + frameControl->currentFrame = (frameControl->currentFrame - frameControl->duration) + 1.0f; + } + + return ret; +} + +/** + * Interpolate between two values using a cubic Hermite curve. + * + * A Hermite curve is a parametric function p(t) where t is restricted to the domain [0, 1]. + * It's defined with a start point and an end point. The shape of the curve is controlled by the tangents of the end + * points. + * If keyframes aren't placed at fixed intervals in time, the animation will abruptly change speed and direction when + * passing through keyframes. To avoid this, the tangents are multiplied by the length of time between the two + * keyframes. + * + * @param t Represents the desired position between keyframe 1 and keyframe 2 to interpolate. + * @param duration The amount of time between keyframe 1 and keyframe 2, in seconds. + * @param p0 The start point. + * @param p1 The end point. + * @param v0 The velocity at p0. + * @param v1 The velocity at p1. + * @return Interpolated value. + */ +f32 cKF_HermitCalc(f32 t, f32 duration, f32 p0, f32 p1, f32 v0, f32 v1) { + // Hermite basis functions + f32 h3 = 3.0f * SQ(t) - 2.0f * CB(t); + f32 h2 = -SQ(t) + CB(t); + f32 h1 = CB(t) - 2.0f * SQ(t) + t; + f32 h0 = 1.0f - h3; + + return h0 * p0 + h3 * p1 + (h1 * v0 + h2 * v1) * duration; +} + +/** + * Given a sequence of keyframes, return the value from currentFrame of the animation. + * + * Animations are defined by a small sequence of keyframes, which record a value at a specific frame of the + * animation. Any value between two keyframes is calculated by interpolating between them. + * Keyframes are 1 dimensional. In the context of a joint the x, y, and z rotation each use a separate + * sequence of keyframes. + * + * @param startIndex Which keyframe in dataSource to start with. + * @param sequenceLength How many keyframes are in the sequence. + * @param dataSource Array where all the keyframes are stored. + * @return The value that corresponds to currentFrame. + */ +s16 cKF_KeyCalc(s16 startIndex, s16 sequenceLength, Keyframe* dataSource, f32 currentFrame) { + Keyframe* ds = &dataSource[startIndex]; + f32 frameDelta; + s32 kf2; + s32 kf1; + + // If currentFrame is before the first keyframe of the sequence. + if (currentFrame <= ds[0].frame) { + return ds[0].value; + } + // If currentFrame is after the last frame of the sequence. + if (ds[sequenceLength - 1].frame <= currentFrame) { + return ds[sequenceLength - 1].value; + } + // Iterate over each keyframe to find which keyframes are before and after currentFrame. + for (kf2 = 1, kf1 = 0; true; kf1++, kf2++) { + if (currentFrame < ds[kf2].frame) { + frameDelta = ds[kf2].frame - ds[kf1].frame; + if (!IS_ZERO(frameDelta)) { + return nearbyint(cKF_HermitCalc((currentFrame - ds[kf1].frame) / frameDelta, frameDelta * (1.0f / 30), + ds[kf1].value, ds[kf2].value, ds[kf1].velocity, ds[kf2].velocity)); + } else { + return ds[kf1].value; + } + } + } +} + +void cKF_SkeletonInfo_subRotInterpolation(f32 t, s16* out, s16 jointRotation, s16 morphRotation) { + u16 urot1 = jointRotation; + s32 pad; + u16 urot2 = morphRotation; + f32 f1 = jointRotation; + f32 signedDiff = morphRotation - f1; + f32 f2 = urot1; + f32 unsignedDiff = urot2 - f2; + + if (fabsf(signedDiff) < fabsf(unsignedDiff)) { + *out = f1 + signedDiff * t; + } else { + *out = f2 + unsignedDiff * t; + } +} + +/** + * When playing a morph animation, linearly interpolate the root joint between it's current position and it's position + * in the current frame of the animation. + * + * Linear interpolation uses a parametric function p(t) where t is restricted to the domain [0, 1]. + * + * @param t Represents the desired position between p0 and p1 to interpolate. + */ +void cKF_SkeletonInfo_morphST(s16* joint, s16* morph, f32 t) { + s32 i; + + for (i = 0; i < 3; i++) { + if (*joint != *morph) { + f32 p0 = *joint; + f32 p1 = *morph; + + *joint = p0 + (p1 - p0) * t; + } + joint++; + morph++; + } +} + +void cKF_SkeletonInfo_R_zeroClear(SkeletonInfoR* skeletonInfo) { + bzero(skeletonInfo, sizeof(SkeletonInfoR)); +} + +void cKF_SkeletonInfo_R_ct(SkeletonInfoR* skeletonInfo, BaseSkeletonR* skeleton, BaseAnimationR* animation, + Vec3s* jointTable, Vec3s* morphTable) { + cKF_SkeletonInfo_R_zeroClear(skeletonInfo); + cKF_FrameControl_ct(&skeletonInfo->frameControl); + skeletonInfo->skeleton = Lib_SegmentedToVirtual(skeleton); + skeletonInfo->animation = Lib_SegmentedToVirtual(animation); + skeletonInfo->jointTable = jointTable; + skeletonInfo->morphTable = morphTable; +} + +void cKF_SkeletonInfo_R_dt(SkeletonInfoR* skeletonInfo) { +} + +void cKF_SkeletonInfo_R_init_standard_stop(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, 1.0f, 1.0, + 0.0f, ANIMATION_STOP, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_standard_stop_speedset(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable, f32 speed) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, 1.0f, speed, + 0.0f, ANIMATION_STOP, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_standard_stop_morph(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable, f32 morphCounter) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, 1.0f, 1.0, + morphCounter, ANIMATION_STOP, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_standard_repeat(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, 1.0f, 1.0, + 0.0f, ANIMATION_REPEAT, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_standard_repeat_speedset(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable, f32 speed) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, 1.0f, speed, + 0.0f, ANIMATION_REPEAT, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_standard_repeat_morph(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable, f32 morphCounter) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, 1.0f, 1.0, + morphCounter, ANIMATION_REPEAT, diffRotTable); +} + +void cKF_SkeletonInfo_R_init(SkeletonInfoR* skeletonInfo, BaseSkeletonR* skeleton, BaseAnimationR* animation, + f32 startFrame, f32 endFrame, f32 currentFrame, f32 speed, f32 morphCounter, + AnimationMode mode, Vec3s* diffRotTable) { + skeletonInfo->morphCounter = morphCounter; + skeletonInfo->skeleton = Lib_SegmentedToVirtual(skeleton); + skeletonInfo->animation = Lib_SegmentedToVirtual(animation); + cKF_FrameControl_setFrame(&skeletonInfo->frameControl, startFrame, endFrame, skeletonInfo->animation->duration, + currentFrame, speed, mode); + skeletonInfo->diffRotTable = diffRotTable; +} + +void cKF_SkeletonInfo_R_setAnim(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + skeletonInfo->animation = animationPtr; + skeletonInfo->frameControl.duration = animationPtr->duration; +} + +void cKF_SkeletonInfo_R_morphJoint(SkeletonInfoR* skeletonInfo) { + // the current position of the joints + Vec3s* joint = skeletonInfo->jointTable; + // the animation's current position + Vec3s* morph = skeletonInfo->morphTable; + // Represents the position between joint 1 and joint 2 to interpolate. + f32 parameter = !IS_ZERO(skeletonInfo->morphCounter) ? 1.0f / fabsf(skeletonInfo->morphCounter) : 0.0f; + Vec3s jointTemp; + Vec3s morphTemp; + Vec3s temp_vec; + s32 i; + f32 new_var; + f32 new_var2; + + // the first Vec3s is the root joint's translation + cKF_SkeletonInfo_morphST((s16*)joint, (s16*)morph, parameter); + + joint++; + morph++; + + for (i = 0; i < skeletonInfo->skeleton->numberOfJoints; i++) { + jointTemp.x = joint->x; + jointTemp.y = joint->y; + jointTemp.z = joint->z; + + morphTemp.x = morph->x; + morphTemp.y = morph->y; + morphTemp.z = morph->z; + + if ((jointTemp.x != morphTemp.x) || (jointTemp.y != morphTemp.y) || (jointTemp.z != morphTemp.z)) { + temp_vec.x = 0x7FFF + jointTemp.x; + temp_vec.y = 0x7FFF - jointTemp.y; + temp_vec.z = 0x7FFF + jointTemp.z; + + new_var = (fabsf(((f32)morphTemp.x) - jointTemp.x) + fabsf(((f32)morphTemp.y) - jointTemp.y)) + + fabsf(((f32)morphTemp.z) - jointTemp.z); + new_var2 = (fabsf(((f32)morphTemp.x) - temp_vec.x) + fabsf(((f32)morphTemp.y) - temp_vec.y)) + + fabsf(((f32)morphTemp.z) - temp_vec.z); + + if (new_var < new_var2) { + cKF_SkeletonInfo_subRotInterpolation(parameter, &joint->x, jointTemp.x, morphTemp.x); + cKF_SkeletonInfo_subRotInterpolation(parameter, &joint->y, jointTemp.y, morphTemp.y); + cKF_SkeletonInfo_subRotInterpolation(parameter, &joint->z, jointTemp.z, morphTemp.z); + } else { + cKF_SkeletonInfo_subRotInterpolation(parameter, &joint->x, temp_vec.x, morphTemp.x); + cKF_SkeletonInfo_subRotInterpolation(parameter, &joint->y, temp_vec.y, morphTemp.y); + cKF_SkeletonInfo_subRotInterpolation(parameter, &joint->z, temp_vec.z, morphTemp.z); + } + } + morph++; + joint++; + } +} + +/** + * Advance the animation one frame and transform the joints accordingly. + * + * Joints can be animated in two ways, with keyframes or constant values. Which one a value uses is stored in + * constKeyCheckBitTable. In this table, there is a byte for every joint, which is a bitfield. 1 is keyframe, 0 is + * constant value. The 00111000 bits correspond to that joint's x, y, or z translation. the 00000111 bits correspond to + * that joint's x, y, or z rotation. Note that only the root joint can be translated. + * + * @return 0 if the animation is still playing. 1 if the animation has completed. 2 if the animation repeated. + */ +s32 cKF_SkeletonInfo_R_play(SkeletonInfoR* skeletonInfo) { + s32 jointIndex; + s32 componentIndex; + u8* ckcbTable; + s32 keyframeNumberIndex = 0; + s32 constValueIndex = 0; + s32 keyframeStartIndex = 0; + s16* jointComponent = + (!IS_ZERO(skeletonInfo->morphCounter)) ? (s16*)skeletonInfo->morphTable : (s16*)skeletonInfo->jointTable; + s16* constValueTable; + Keyframe* dataSource; + s16* keyframeNumberTable; + u32 ckcbIndex; + Vec3s* joint; + + constValueTable = Lib_SegmentedToVirtual(skeletonInfo->animation->constValueTable); + keyframeNumberTable = Lib_SegmentedToVirtual(skeletonInfo->animation->keyframeNumber); + dataSource = Lib_SegmentedToVirtual(skeletonInfo->animation->dataSource); + ckcbTable = Lib_SegmentedToVirtual(skeletonInfo->animation->constKeyCheckBitTable); + + // Translate the root joint. + for (ckcbIndex = 0x20, componentIndex = 0; componentIndex < 3; componentIndex++) { + + if (*ckcbTable & ckcbIndex) { + *jointComponent = cKF_KeyCalc(keyframeStartIndex, keyframeNumberTable[keyframeNumberIndex], dataSource, + skeletonInfo->frameControl.currentFrame); + keyframeStartIndex += keyframeNumberTable[keyframeNumberIndex]; + keyframeNumberIndex++; + + } else { + *jointComponent = constValueTable[constValueIndex]; + constValueIndex++; + } + + ckcbIndex >>= 1; + jointComponent++; + } + + // Rotate every joint. + for (jointIndex = 0; jointIndex < skeletonInfo->skeleton->numberOfJoints; jointIndex++) { + ckcbIndex = 4; + for (componentIndex = 0; componentIndex < 3; componentIndex++) { + + if (ckcbTable[jointIndex] & ckcbIndex) { + *jointComponent = cKF_KeyCalc(keyframeStartIndex, keyframeNumberTable[keyframeNumberIndex], dataSource, + skeletonInfo->frameControl.currentFrame); + keyframeStartIndex += keyframeNumberTable[keyframeNumberIndex]; + keyframeNumberIndex++; + + } else { + *jointComponent = constValueTable[constValueIndex]; + constValueIndex++; + } + + // Animations store angles in degrees * 10. These are converted to binary angles. + *jointComponent = DEG_TO_BINANG(FMOD(*jointComponent * 0.1f, 360.0f)); + + ckcbIndex >>= 1; + jointComponent++; + } + } + + if (skeletonInfo->diffRotTable) { + joint = (!IS_ZERO(skeletonInfo->morphCounter)) ? skeletonInfo->morphTable : skeletonInfo->jointTable; + joint++; + for (jointIndex = 0; jointIndex < skeletonInfo->skeleton->numberOfJoints; jointIndex++) { + joint->x = joint->x + skeletonInfo->diffRotTable[jointIndex].x; + joint->y = joint->y + skeletonInfo->diffRotTable[jointIndex].y; + joint->z = joint->z + skeletonInfo->diffRotTable[jointIndex].z; + joint++; + } + } + + // If the animation isn't using morph. + if (IS_ZERO(skeletonInfo->morphCounter)) { + return cKF_FrameControl_play(&skeletonInfo->frameControl); + + } else if (skeletonInfo->morphCounter > 0.0f) { + // A positive morphCounter will wait to play the animation until the morph has finished. + cKF_SkeletonInfo_R_morphJoint(skeletonInfo); + + skeletonInfo->morphCounter -= 1.0f; + if (skeletonInfo->morphCounter <= 0.0f) { + skeletonInfo->morphCounter = 0.0f; + } + return 0; + + } else { + // A negative morphCounter will play the animation and morph at the same time. + cKF_SkeletonInfo_R_morphJoint(skeletonInfo); + + skeletonInfo->morphCounter += 1.0f; + if (skeletonInfo->morphCounter >= 0.0f) { + skeletonInfo->morphCounter = 0.0f; + } + return cKF_FrameControl_play(&skeletonInfo->frameControl); + } +} + +/** + * Draw a specified joint in a SkeletonInfo struct. + * + * This is a recursive function, that will call itself again for each child this joint has. + * + * Joints inherit the transformation of their parent joint. This is accomplished with a matrix stack, where each joint + * pushes it's own transformation matrix onto the stack, and pops the matrix when there are no more children. + * + * Actors can override the drawing process with beforeCallback and afterCallback functions. One common example is to set + * a specific joint's display list to null in order to make it invisible. + * + * @param jointIndex The index of the jointElem to draw. + */ +void cKF_Si3_draw_SV_R_child(PlayState* play, SkeletonInfoR* skeletonInfo, s32* jointIndex, DrawCallback beforeCallback, + DrawCallback afterCallback, void* arg, Mtx** mtx) { + JointElemR* jointElem = *jointIndex + (JointElemR*)Lib_SegmentedToVirtual(skeletonInfo->skeleton->jointElemTable); + s32 i; + Gfx* newDlist; + Gfx* shape; + u8 displayBufferFlag; + Vec3s rotation; + Vec3s* joint = &skeletonInfo->jointTable[*jointIndex]; + Vec3f translation; + + // if this is not the root joint. + if (*jointIndex != 0) { + translation.x = jointElem->translation.x; + translation.y = jointElem->translation.y; + translation.z = jointElem->translation.z; + + } else { + s32 transformationFlag = skeletonInfo->animationMove.transformationFlag; + Vec3f* baseTranslation = &skeletonInfo->animationMove.baseShapeTranslation; + + // Translate the root joint. + // The AnimationMove struct can specify an override translation. + if (transformationFlag & 1) { + translation.x = baseTranslation->x; + translation.z = baseTranslation->z; + } else { + translation.x = joint->x; + translation.z = joint->z; + } + + if (transformationFlag & 2) { + translation.y = baseTranslation->y; + } else { + translation.y = joint->y; + } + } + + // jointIndex increases by 1 each recursive call, but because the root joint uses the first 2 Vec3s in jointTable, + // the index of the current joint is actually jointIndex + 1. + joint++; + rotation = *joint; + + if (*jointIndex == 0) { + s32 transformationFlag = skeletonInfo->animationMove.transformationFlag; + + if (transformationFlag & 4) { + rotation.x = skeletonInfo->animationMove.baseShapeRotation.x; + rotation.y = skeletonInfo->animationMove.updatedBaseShapeRotation.y; + rotation.z = skeletonInfo->animationMove.updatedBaseShapeRotation.z; + } + } + + OPEN_DISPS(play->state.gfxCtx); + Matrix_push(); + newDlist = shape = jointElem->shape; + displayBufferFlag = jointElem->displayBufferFlag; + + if ((beforeCallback == NULL) || + (beforeCallback != NULL && beforeCallback(play, skeletonInfo, *jointIndex, &newDlist, &displayBufferFlag, arg, + &rotation, &translation) != NULL)) { + Matrix_softcv3_mult(&translation, &rotation); + + if (newDlist != NULL) { + _Matrix_to_Mtx(*mtx); + + if (displayBufferFlag & 1) { + gSPMatrix(POLY_XLU_DISP++, *mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, newDlist); + } else { + gSPMatrix(POLY_OPA_DISP++, *mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, newDlist); + } + + (*mtx)++; + + } else if (shape != NULL) { + _Matrix_to_Mtx(*mtx); + gSPMatrix(POLY_OPA_DISP++, *mtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + (*mtx)++; + } + } + + if (afterCallback != NULL) { + afterCallback(play, skeletonInfo, *jointIndex, &newDlist, &displayBufferFlag, arg, &rotation, &translation); + } + + (*jointIndex)++; + + for (i = 0; i < jointElem->numberOfChildren; i++) { + cKF_Si3_draw_SV_R_child(play, skeletonInfo, jointIndex, beforeCallback, afterCallback, arg, mtx); + } + + Matrix_pull(); + CLOSE_DISPS(play->state.gfxCtx); +} + +/** + * Draw all the joints in in a SkeletonInfo struct. + * + * This function calls cKF_Si3_draw_SV_R_child() to recursively draw each joint. + */ +void cKF_Si3_draw_R_SV(PlayState* play, SkeletonInfoR* skeletonInfo, Mtx* mtx, DrawCallback beforeCallback, + DrawCallback afterCallback, void* arg) { + s32 jointIndex; + + if (mtx != NULL) { + OPEN_DISPS(play->state.gfxCtx); + gSPSegment(POLY_OPA_DISP++, 0x0D, mtx); + gSPSegment(POLY_XLU_DISP++, 0x0D, mtx); + jointIndex = 0; + cKF_Si3_draw_SV_R_child(play, skeletonInfo, &jointIndex, beforeCallback, afterCallback, arg, &mtx); + CLOSE_DISPS(play->state.gfxCtx); + } +} + +void cKF_SkeletonInfo_R_init_standard_repeat_speedsetandmorph(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable, f32 speed, f32 morphCounter) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, 1.0f, speed, + morphCounter, ANIMATION_REPEAT, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_standard_repeat_setframeandspeedandmorph(SkeletonInfoR* skeletonInfo, + BaseAnimationR* animation, Vec3s* diffRotTable, + f32 currentFrame, f32 speed, f32 morphCounter) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, currentFrame, + speed, morphCounter, ANIMATION_REPEAT, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_standard_setframeandspeedandmorphandmode(SkeletonInfoR* skeletonInfo, + BaseAnimationR* animation, Vec3s* diffRotTable, + f32 currentFrame, f32 speed, f32 morphCounter, + AnimationMode mode) { + BaseAnimationR* animationPtr = Lib_SegmentedToVirtual(animation); + + cKF_SkeletonInfo_R_init(skeletonInfo, skeletonInfo->skeleton, animation, 1.0f, animationPtr->duration, currentFrame, + speed, morphCounter, mode, diffRotTable); +} + +void cKF_SkeletonInfo_R_init_reverse_setspeedandmorphandmode(SkeletonInfoR* skeletonInfo, BaseAnimationR* animation, + Vec3s* diffRotTable, f32 currentFrame, f32 speed, + AnimationMode mode) { + cKF_SkeletonInfo_R_init( + skeletonInfo, skeletonInfo->skeleton, animation, ((BaseAnimationR*)Lib_SegmentedToVirtual(animation))->duration, + 1.0f, ((BaseAnimationR*)Lib_SegmentedToVirtual(animation))->duration, currentFrame, speed, mode, diffRotTable); +} + +void func_80053384_jp(s32 arg0, s32 arg1, s32 arg2, s32 arg3, s32 arg4, s32 arg5, UNK_PTR* arg6, UNK_PTR* arg7, + UNK_PTR* arg8) { + if (arg3 != 0) { + B_801458A0_jp[arg0] = OS_PHYSICAL_TO_K0(arg6); + } + if (arg4 != 0) { + B_801458A0_jp[arg1] = OS_PHYSICAL_TO_K0(arg7); + } + if (arg5 != 0) { + B_801458A0_jp[arg2] = OS_PHYSICAL_TO_K0(arg8); + } +} + +void cKF_SkeletonInfo_R_combine_work_set(SkeletonInfoRCombineWork* combineWork, SkeletonInfoR* skeletonInfo) { + combineWork->skeletonInfo = skeletonInfo; + combineWork->constValueTable = Lib_SegmentedToVirtual(skeletonInfo->animation->constValueTable); + combineWork->keyframeNumber = Lib_SegmentedToVirtual(skeletonInfo->animation->keyframeNumber); + combineWork->dataSource = Lib_SegmentedToVirtual(skeletonInfo->animation->dataSource); + combineWork->constKeyCheckBitTable = Lib_SegmentedToVirtual(skeletonInfo->animation->constKeyCheckBitTable); + combineWork->keyframeNumberIndex = 0; + combineWork->ckcbIndex = 0; + combineWork->keyframeStartIndex = 0; +} + +void cKF_SkeletonInfo_R_combine_translation(s16** joint, u32* flag, SkeletonInfoRCombineWork* combineWork, s8* arg3) { + SkeletonInfoRCombineWork* temp_s1; + SkeletonInfoRCombineWork* temp_s2; + s32 i; + + temp_s1 = &combineWork[1]; + temp_s2 = &combineWork[2]; + for (i = 0; i < 3; i++) { + switch (*arg3) { + case 0: + if (*combineWork[0].constKeyCheckBitTable & *flag) { + **joint = + cKF_KeyCalc(combineWork[0].keyframeStartIndex, + combineWork[0].keyframeNumber[combineWork->keyframeNumberIndex], + combineWork[0].dataSource, combineWork[0].skeletonInfo->frameControl.currentFrame); + } else { + **joint = combineWork->constValueTable[combineWork->ckcbIndex]; + } + break; + + case 1: + if (*temp_s1->constKeyCheckBitTable & *flag) { + **joint = + cKF_KeyCalc(temp_s1->keyframeStartIndex, temp_s1->keyframeNumber[temp_s1->keyframeNumberIndex], + temp_s1->dataSource, temp_s1->skeletonInfo->frameControl.currentFrame); + } else { + **joint = temp_s1->constValueTable[temp_s1->ckcbIndex]; + } + break; + + case 2: + if (*temp_s2->constKeyCheckBitTable & *flag) { + **joint = + cKF_KeyCalc(temp_s2->keyframeStartIndex, temp_s2->keyframeNumber[temp_s2->keyframeNumberIndex], + temp_s2->dataSource, temp_s2->skeletonInfo->frameControl.currentFrame); + } else { + **joint = temp_s2->constValueTable[temp_s2->ckcbIndex]; + } + break; + } + if (*combineWork[0].constKeyCheckBitTable & *flag) { + combineWork->keyframeStartIndex += combineWork[0].keyframeNumber[combineWork->keyframeNumberIndex++]; + } else { + combineWork->ckcbIndex += 1; + } + if (*temp_s1->constKeyCheckBitTable & *flag) { + temp_s1->keyframeStartIndex += temp_s1->keyframeNumber[temp_s1->keyframeNumberIndex++]; + } else { + temp_s1->ckcbIndex++; + } + if (*temp_s2->constKeyCheckBitTable & *flag) { + temp_s2->keyframeStartIndex += temp_s2->keyframeNumber[temp_s2->keyframeNumberIndex++]; + } else { + temp_s2->ckcbIndex += 1; + } + *flag >>= 1; + (*joint)++; + } +} + +void cKF_SkeletonInfo_R_combine_rotation(s16** joint, u32* flag, SkeletonInfoRCombineWork* combineWork, s8* arg3) { + SkeletonInfoRCombineWork* sp64; + SkeletonInfoRCombineWork* temp_s0; + SkeletonInfoRCombineWork* temp_s1; + s32 i; + s32 j; + + sp64 = combineWork; + temp_s0 = &combineWork[1]; + temp_s1 = &combineWork[2]; + for (i = 0; i < sp64->skeletonInfo->skeleton->numberOfJoints; i++) { + *flag = 4; + for (j = 0; j < 3; j++) { + switch (arg3[i + 1]) { + case 0: + if (combineWork->constKeyCheckBitTable[i] & *flag) { + **joint = + cKF_KeyCalc(combineWork[0].keyframeStartIndex, + combineWork->keyframeNumber[combineWork->keyframeNumberIndex], + combineWork->dataSource, combineWork->skeletonInfo->frameControl.currentFrame); + } else { + **joint = combineWork->constValueTable[combineWork->ckcbIndex]; + } + break; + + case 1: + if (temp_s0->constKeyCheckBitTable[i] & *flag) { + **joint = cKF_KeyCalc(temp_s0->keyframeStartIndex, + temp_s0->keyframeNumber[temp_s0->keyframeNumberIndex], + temp_s0->dataSource, temp_s0->skeletonInfo->frameControl.currentFrame); + } else { + **joint = temp_s0->constValueTable[temp_s0->ckcbIndex]; + } + break; + + case 2: + if (temp_s1->constKeyCheckBitTable[i] & *flag) { + **joint = cKF_KeyCalc(temp_s1->keyframeStartIndex, + temp_s1->keyframeNumber[temp_s1->keyframeNumberIndex], + temp_s1->dataSource, temp_s1->skeletonInfo->frameControl.currentFrame); + } else { + **joint = temp_s1->constValueTable[temp_s1->ckcbIndex]; + } + break; + } + if (combineWork->constKeyCheckBitTable[i] & *flag) { + combineWork->keyframeStartIndex += combineWork->keyframeNumber[combineWork->keyframeNumberIndex++]; + } else { + combineWork->ckcbIndex++; + } + if (temp_s0->constKeyCheckBitTable[i] & *flag) { + temp_s0->keyframeStartIndex += temp_s0->keyframeNumber[temp_s0->keyframeNumberIndex++]; + } else { + temp_s0->ckcbIndex++; + } + if (temp_s1->constKeyCheckBitTable[i] & *flag) { + temp_s1->keyframeStartIndex += temp_s1->keyframeNumber[temp_s1->keyframeNumberIndex++]; + } else { + temp_s1->ckcbIndex++; + } + **joint = DEG_TO_BINANG(FMOD(**joint * 0.1f, 360.0f)); + *flag >>= 1; + *joint += 1; + } + } +} + +s32 cKF_SkeletonInfo_R_combine_play(SkeletonInfoR* skeletonInfo1, SkeletonInfoR* skeletonInfo2, s32 arg2, s32 arg3, + s32 arg4, s32 arg5, s8* flag) { + Vec3s* var_v0; + u32 spB0; + s16* joint; + SkeletonInfoRCombineWork combine1; + SkeletonInfoRCombineWork combine2; + SkeletonInfoRCombineWork combine3; + s32 var_s0; + UNK_PTR* sp44 = NULL; + UNK_PTR* sp40 = NULL; + s32 var_v1; + + if ((skeletonInfo1 == NULL) || (skeletonInfo2 == NULL) || (arg2 < 0) || (arg2 >= 0x10) || (arg3 < 0) || + (arg3 >= 0x10) || (flag == NULL)) { + return 0; + } + + joint = (!IS_ZERO(skeletonInfo1->morphCounter)) ? (s16*)skeletonInfo1->morphTable : (s16*)skeletonInfo1->jointTable; + + if (arg4 != 0) { + sp44 = OS_PHYSICAL_TO_K0(B_801458A0_jp[arg2]); + B_801458A0_jp[arg2] = OS_PHYSICAL_TO_K0(arg4); + cKF_SkeletonInfo_R_combine_work_set(&combine3, skeletonInfo1); + } + + if (arg5 != 0) { + sp40 = OS_PHYSICAL_TO_K0(B_801458A0_jp[arg3]); + B_801458A0_jp[arg3] = OS_PHYSICAL_TO_K0(arg5); + cKF_SkeletonInfo_R_combine_work_set(&combine2, skeletonInfo2); + cKF_SkeletonInfo_R_combine_work_set(&combine1, skeletonInfo2); + } + + spB0 = 0x20; + cKF_SkeletonInfo_R_combine_translation(&joint, &spB0, &combine3, flag); + cKF_SkeletonInfo_R_combine_rotation(&joint, &spB0, &combine3, flag); + + if (skeletonInfo1->diffRotTable != NULL) { + var_v0 = (!IS_ZERO(skeletonInfo1->morphCounter)) ? skeletonInfo1->morphTable : skeletonInfo1->jointTable; + var_v0++; + + for (var_v1 = 0; var_v1 < skeletonInfo1->skeleton->numberOfJoints; var_v1++) { + var_v0->x = var_v0->x + skeletonInfo1->diffRotTable[var_v1].x; + var_v0->y = var_v0->y + skeletonInfo1->diffRotTable[var_v1].y; + var_v0->z = var_v0->z + skeletonInfo1->diffRotTable[var_v1].z; + var_v0++; + } + } + if (IS_ZERO(skeletonInfo1->morphCounter)) { + cKF_FrameControl_play(&skeletonInfo2->frameControl); + var_s0 = cKF_FrameControl_play(&skeletonInfo1->frameControl); + func_80053384_jp(arg2, arg3, 0, arg4, arg5, 0, sp44, sp40, 0); + } else { + if (skeletonInfo1->morphCounter > 0.0f) { + cKF_SkeletonInfo_R_morphJoint(skeletonInfo1); + skeletonInfo1->morphCounter -= 1.0f; + if (skeletonInfo1->morphCounter <= 0.0f) { + skeletonInfo1->morphCounter = 0.0f; + } + func_80053384_jp(arg2, arg3, 0, arg4, arg5, 0, sp44, sp40, 0); + return 0; + } + + cKF_SkeletonInfo_R_morphJoint(skeletonInfo1); + + skeletonInfo1->morphCounter += 1.0f; + if (skeletonInfo1->morphCounter >= 0.0f) { + skeletonInfo1->morphCounter = 0.0f; + } + + cKF_FrameControl_play(&skeletonInfo2->frameControl); + var_s0 = cKF_FrameControl_play(&skeletonInfo1->frameControl); + func_80053384_jp(arg2, arg3, 0, arg4, arg5, 0, sp44, sp40, 0); + } + return var_s0; +} + +void cKF_SkeletonInfo_R_T_combine_play(s32* arg0, s32* arg1, s32* arg2, SkeletonInfoR* skeletonInfo1, + SkeletonInfoR* skeletonInfo2, SkeletonInfoR* skeletonInfo3, s32 arg6, s32 arg7, + s32 arg8, s32 arg9, s32 argA, s32 argB, s8* flag) { + s32 i; + u32 spB0; + s16* spAC; + SkeletonInfoRCombineWork sp8C; + SkeletonInfoRCombineWork sp6C; + SkeletonInfoRCombineWork sp4C; + UNK_PTR* sp48 = NULL; + UNK_PTR* sp44 = NULL; + UNK_PTR* sp40 = NULL; + Vec3s* var_v0; + + if ((skeletonInfo1 == NULL) || (skeletonInfo2 == NULL) || (skeletonInfo3 == NULL) || (arg6 < 0) || (arg6 >= 0x10) || + (arg7 < 0) || (arg7 >= 0x10) || (arg8 < 0) || (arg8 >= 0x10) || (flag == NULL)) { + return; + } + + spAC = (!IS_ZERO(skeletonInfo1->morphCounter)) ? (s16*)skeletonInfo1->morphTable : (s16*)skeletonInfo1->jointTable; + + if (arg9 != 0) { + sp48 = OS_PHYSICAL_TO_K0(B_801458A0_jp[arg6]); + B_801458A0_jp[arg6] = OS_PHYSICAL_TO_K0(arg9); + cKF_SkeletonInfo_R_combine_work_set(&sp4C, skeletonInfo1); + } + if (argA != 0) { + sp44 = OS_PHYSICAL_TO_K0(B_801458A0_jp[arg7]); + B_801458A0_jp[arg7] = OS_PHYSICAL_TO_K0(argA); + cKF_SkeletonInfo_R_combine_work_set(&sp6C, skeletonInfo2); + } + if (argB != 0) { + sp40 = OS_PHYSICAL_TO_K0(B_801458A0_jp[arg8]); + B_801458A0_jp[arg8] = OS_PHYSICAL_TO_K0(argB); + cKF_SkeletonInfo_R_combine_work_set(&sp8C, skeletonInfo3); + } + + spB0 = 0x20; + cKF_SkeletonInfo_R_combine_translation(&spAC, &spB0, &sp4C, flag); + cKF_SkeletonInfo_R_combine_rotation(&spAC, &spB0, &sp4C, flag); + + if (skeletonInfo1->diffRotTable != NULL) { + var_v0 = (!IS_ZERO(skeletonInfo1->morphCounter)) ? skeletonInfo1->morphTable : skeletonInfo1->jointTable; + var_v0++; + + for (i = 0; i < skeletonInfo1->skeleton->numberOfJoints; i++) { + var_v0->x = var_v0->x + skeletonInfo1->diffRotTable[i].x; + var_v0->y = var_v0->y + skeletonInfo1->diffRotTable[i].y; + var_v0->z = var_v0->z + skeletonInfo1->diffRotTable[i].z; + var_v0++; + } + } + + if (IS_ZERO(skeletonInfo1->morphCounter)) { + *arg0 = cKF_FrameControl_play(&skeletonInfo1->frameControl); + *arg1 = cKF_FrameControl_play(&skeletonInfo2->frameControl); + *arg2 = cKF_FrameControl_play(&skeletonInfo3->frameControl); + } else if (skeletonInfo1->morphCounter > 0.0f) { + cKF_SkeletonInfo_R_morphJoint(skeletonInfo1); + skeletonInfo1->morphCounter -= 1.0f; + if (skeletonInfo1->morphCounter <= 0.0f) { + skeletonInfo1->morphCounter = 0.0f; + } + *arg0 = 0; + *arg1 = 0; + *arg2 = 0; + } else { + cKF_SkeletonInfo_R_morphJoint(skeletonInfo1); + skeletonInfo1->morphCounter += 1.0f; + if (skeletonInfo1->morphCounter >= 0.0f) { + skeletonInfo1->morphCounter = 0.0f; + } + *arg0 = cKF_FrameControl_play(&skeletonInfo1->frameControl); + *arg1 = cKF_FrameControl_play(&skeletonInfo2->frameControl); + *arg2 = cKF_FrameControl_play(&skeletonInfo3->frameControl); + } + func_80053384_jp(arg6, arg7, arg8, arg9, argA, argB, sp48, sp44, sp40); +} + +void cKF_SkeletonInfo_R_Animation_Set_base_shape_trs(SkeletonInfoR* skeletonInfo, f32 translationX, f32 translationY, + f32 translationZ, s16 rotX, s16 rotY, s16 rotZ) { + skeletonInfo->animationMove.baseShapeTranslation.x = translationX; + skeletonInfo->animationMove.baseShapeTranslation.y = translationY; + skeletonInfo->animationMove.baseShapeTranslation.z = translationZ; + skeletonInfo->animationMove.updatedBaseShapeRotation.x = skeletonInfo->animationMove.baseShapeRotation.x = rotX; + skeletonInfo->animationMove.updatedBaseShapeRotation.y = skeletonInfo->animationMove.baseShapeRotation.y = rotY; + skeletonInfo->animationMove.updatedBaseShapeRotation.z = skeletonInfo->animationMove.baseShapeRotation.z = rotZ; +} + +void cKF_SkeletonInfo_R_AnimationMove_ct_base(Vec3f* arg0, Vec3f* arg1, s16 arg2, s16 arg3, f32 arg4, + SkeletonInfoR* skeletonInfo, s32 transformationFlag) { + s32 var_v0; + + skeletonInfo->animationMove.transformationFlag = transformationFlag; + skeletonInfo->animationMove.counter = ABS(arg4); + skeletonInfo->animationMove.baseWorldPosition = ZeroVec; + skeletonInfo->animationMove.shapeWorldPositionCorrection = ZeroVec; + + if (arg0 != NULL) { + if (arg1 == NULL) { + arg1 = arg0; + } + if (transformationFlag & 1) { + skeletonInfo->animationMove.baseWorldPosition.x = arg1->x; + skeletonInfo->animationMove.baseWorldPosition.z = arg1->z; + skeletonInfo->animationMove.shapeWorldPositionCorrection.x = arg0->x - arg1->x; + skeletonInfo->animationMove.shapeWorldPositionCorrection.z = arg0->z - arg1->z; + } + if (transformationFlag & 2) { + skeletonInfo->animationMove.baseWorldPosition.y = arg1->y; + skeletonInfo->animationMove.shapeWorldPositionCorrection.y = (f32)(arg0->y - arg1->y); + } + } + skeletonInfo->animationMove.baseAngleY = arg3; + skeletonInfo->animationMove.shapeAngleCorrection = 0; + if (transformationFlag & 4) { + var_v0 = arg2 - arg3; + if (var_v0 > 0x8000) { + var_v0 = -(0x10000 - var_v0); + } else if (var_v0 < -0x8000) { + var_v0 = var_v0 + 0x10000; + } + skeletonInfo->animationMove.shapeAngleCorrection = var_v0; + } +} + +void cKF_SkeletonInfo_R_AnimationMove_dt(SkeletonInfoR* skeletonInfo) { + s32 transformationFlag = skeletonInfo->animationMove.transformationFlag; + Vec3s* rootJointTranslation = &skeletonInfo->jointTable[0]; + Vec3f* baseShapeTranslation = &skeletonInfo->animationMove.baseShapeTranslation; + + if (transformationFlag & 1) { + rootJointTranslation->x = baseShapeTranslation->x; + rootJointTranslation->z = baseShapeTranslation->z; + } + if (transformationFlag & 2) { + rootJointTranslation->y = baseShapeTranslation->y; + } + if (transformationFlag & 4) { + Vec3s* rootJointRotation = &skeletonInfo->jointTable[1]; + + rootJointRotation->x = skeletonInfo->animationMove.baseShapeRotation.x; + rootJointRotation->y = skeletonInfo->animationMove.baseShapeRotation.y; + rootJointRotation->z = skeletonInfo->animationMove.baseShapeRotation.z; + } + skeletonInfo->animationMove.transformationFlag = 0; +} + +void cKF_SkeletonInfo_R_AnimationMove_base(Vec3f* arg0, Vec3s* arg1, Vec3f* arg2, s16 arg3, + SkeletonInfoR* skeletonInfo) { + u32 transformationFlag = skeletonInfo->animationMove.transformationFlag; + f32 counter = skeletonInfo->animationMove.counter; + f32 count; + f32 var_ft4; + + count = counter + 1.0f; + if (count > 1.0f) { + var_ft4 = 1.0f / count; + } else { + var_ft4 = 0.0f; + } + + if (transformationFlag & 4) { + f32 temp6 = skeletonInfo->animationMove.shapeAngleCorrection; + + if (count > 1.0f) { + temp6 *= var_ft4; + skeletonInfo->animationMove.shapeAngleCorrection -= (s16)temp6; + } else { + skeletonInfo->animationMove.shapeAngleCorrection = 0; + } + } + if (count > 1.0f) { + if (transformationFlag & 1) { + f32 posXTemp; + f32 posZTemp; + + posXTemp = skeletonInfo->animationMove.shapeWorldPositionCorrection.x; + posXTemp *= var_ft4; + + posZTemp = skeletonInfo->animationMove.shapeWorldPositionCorrection.z; + posZTemp *= var_ft4; + + skeletonInfo->animationMove.shapeWorldPositionCorrection.x -= posXTemp; + skeletonInfo->animationMove.shapeWorldPositionCorrection.z -= posZTemp; + } + if (transformationFlag & 2) { + f32 posYTemp; + + posYTemp = skeletonInfo->animationMove.shapeWorldPositionCorrection.y; + posYTemp *= var_ft4; + + skeletonInfo->animationMove.shapeWorldPositionCorrection.y -= posYTemp; + } + } else { + skeletonInfo->animationMove.shapeWorldPositionCorrection.x = 0.0f; + skeletonInfo->animationMove.shapeWorldPositionCorrection.y = 0.0f; + skeletonInfo->animationMove.shapeWorldPositionCorrection.z = 0.0f; + } + + if ((arg1 != NULL) && (transformationFlag & 4)) { + s32 sp8C = skeletonInfo->animationMove.baseAngleY; + s32 sp88 = skeletonInfo->animationMove.shapeAngleCorrection; + Vec3s* sp28 = &skeletonInfo->animationMove.updatedBaseShapeRotation; + s32 sp80 = skeletonInfo->animationMove.baseShapeRotation.x; + s32 temp; + + Matrix_push(); + Matrix_rotateXYZ(skeletonInfo->jointTable[1].x, skeletonInfo->jointTable[1].y, skeletonInfo->jointTable[1].z, + 0); + Matrix_to_rotate2_new(get_Matrix_now(), sp28, 0); + Matrix_pull(); + temp = sp28->x - sp80; + arg1->x = (sp8C + sp88) + temp; + } + + if (arg0 != NULL) { + Vec3s* sp78 = skeletonInfo->jointTable; + s16 var_a0 = 0; + + if (arg1 != NULL) { + var_a0 = arg1->x - arg3; + } + + if (transformationFlag & 1) { + f32 baseTranslationXTemp = skeletonInfo->animationMove.baseShapeTranslation.x; + f32 baseTranslationZTemp = skeletonInfo->animationMove.baseShapeTranslation.z; + f32 sin1 = sin_s(var_a0); + f32 cos1 = cos_s(var_a0); + s32 pad[2]; + f32 move_x = arg2->x * (sp78->x - ((baseTranslationXTemp * cos1) + (baseTranslationZTemp * sin1))); + f32 move_z = arg2->z * (sp78->z - ((-baseTranslationXTemp * sin1) + (baseTranslationZTemp * cos1))); + f32 sin2 = sin_s(arg3); + f32 cos2 = cos_s(arg3); + f32 correctBaseWorldXTemp = skeletonInfo->animationMove.shapeWorldPositionCorrection.x; + f32 correctBaseWorldZTemp = skeletonInfo->animationMove.shapeWorldPositionCorrection.z; + s32 pad2[2]; + + arg0->x = (skeletonInfo->animationMove.baseWorldPosition.x + correctBaseWorldXTemp) + + ((move_x * cos2) + (move_z * sin2)); + arg0->z = (skeletonInfo->animationMove.baseWorldPosition.z + correctBaseWorldZTemp) + + ((-move_x * sin2) + (move_z * cos2)); + } + + if (transformationFlag & 2) { + f32 yTemp = skeletonInfo->animationMove.baseShapeTranslation.y; + f32 temp3 = (arg2->y * (sp78->y - yTemp)); + f32 new_var = skeletonInfo->animationMove.shapeWorldPositionCorrection.y; + + arg0->y = (skeletonInfo->animationMove.baseWorldPosition.y + new_var) + temp3; + } + } + counter -= 1.0f; + + if (counter < 0.0f) { + counter = 0.0f; + } + + skeletonInfo->animationMove.counter = counter; +} + +void cKF_SkeletonInfo_R_AnimationMove_CulcTransToWorld(Vec3f* arg0, Vec3f* arg1, f32 arg2, f32 arg3, f32 arg4, s16 arg5, + Vec3f* arg6, SkeletonInfoR* skeleton, s32 arg8) { + Vec3s* temp_v0 = &skeleton->jointTable[0]; + f32 sp20; + f32 sp1C; + f32 sp18; + f32 temp_fv0; + + if (arg8 & 1) { + sp20 = temp_v0->x - arg2; + sp1C = temp_v0->z - arg4; + sp18 = sin_s(arg5); + temp_fv0 = cos_s(arg5); + arg0->x = (arg1->x + (arg6->x * ((sp20 * temp_fv0) + (sp1C * sp18)))); + arg0->z = (arg1->z + (arg6->z * ((-sp20 * sp18) + (sp1C * temp_fv0)))); + } + if (arg8 & 2) { + arg0->y = arg1->y + (arg6->y * (temp_v0->y - arg3)); + } +} |
