diff --git a/assets/models/player/chell.blend b/assets/models/player/chell.blend index 610b0d4..68b54a3 100644 Binary files a/assets/models/player/chell.blend and b/assets/models/player/chell.blend differ diff --git a/src/math/quaternion.c b/src/math/quaternion.c index cf33ac5..1a449b7 100644 --- a/src/math/quaternion.c +++ b/src/math/quaternion.c @@ -5,6 +5,8 @@ #include "mathf.h" #include +struct Quaternion gQuaternionZero = {0.0f, 0.0f, 0.0f, 0.0f}; + void quatIdent(struct Quaternion* q) { q->x = 0.0f; q->y = 0.0f; diff --git a/src/math/quaternion.h b/src/math/quaternion.h index fbcc2ff..78fb31d 100644 --- a/src/math/quaternion.h +++ b/src/math/quaternion.h @@ -9,6 +9,8 @@ struct Quaternion { float x, y, z, w; }; +extern struct Quaternion gQuaternionZero; + void quatIdent(struct Quaternion* q); void quatAxisAngle(struct Vector3* axis, float angle, struct Quaternion* out); void quatAxisComplex(struct Vector3* axis, struct Vector2* complex, struct Quaternion* out); diff --git a/src/player/player.c b/src/player/player.c index c4a33a4..7eb066f 100644 --- a/src/player/player.c +++ b/src/player/player.c @@ -98,9 +98,10 @@ void playerInit(struct Player* player, struct Location* startLocation, struct Ve collisionSceneAddDynamicObject(&player->collisionObject); skArmatureInit(&player->armature, &player_chell_armature); - skAnimatorV2Init(&player->animator, player_chell_armature.numberOfBones); + skBlenderInit(&player->animator, player_chell_armature.numberOfBones); - skAnimatorV2RunClip(&player->animator, &player_chell_Armature_runn_clip, 0.0f, SKAnimatorV2FlagsLoop); + skAnimatorRunClip(&player->animator.from, &player_chell_Armature_runn_clip, 0.0f, SKAnimatorFlagsLoop); + skAnimatorRunClip(&player->animator.to, &player_chell_Armature_runc_clip, 0.0f, SKAnimatorFlagsLoop); player->body.velocity = *velocity; player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING; @@ -294,11 +295,53 @@ void playerGetMoveBasis(struct Transform* transform, struct Vector3* forward, st vector3Normalize(right, right); } +struct SKAnimationClip* playerDetermineNextClip(struct Player* player, float* blendLerp, float* startTime, struct Vector3* forwardDir, struct Vector3* rightDir) { + float horzSpeed = player->body.velocity.x * player->body.velocity.x + player->body.velocity.z * player->body.velocity.z; + + if (horzSpeed < 0.0001f) { + *blendLerp = 0.0f; + *startTime = 0.0f; + return &player_chell_Armature_idle_clip; + } + + horzSpeed = sqrtf(horzSpeed); + + *blendLerp = 1.0f - horzSpeed * (1.0f / PLAYER_SPEED); + + if (*blendLerp < 0.0f) { + *blendLerp = 0.0f; + } + + if (*blendLerp > 1.0f) { + *blendLerp = 1.0f; + } + + *startTime = player->animator.from.currentTime; + + float forward = forwardDir->x * player->body.velocity.x + forwardDir->z * player->body.velocity.z; + float right = rightDir->x * player->body.velocity.x + rightDir->z * player->body.velocity.z; + + if (fabsf(forward) > fabsf(right)) { + if (forward > 0.0f) { + return &player_chell_Armature_runs_clip; + } else { + return &player_chell_Armature_runn_clip; + } + } else { + if (right > 0.0f) { + return &player_chell_Armature_rune_clip; + } else { + return &player_chell_Armature_runw_clip; + } + } + +} + void playerUpdate(struct Player* player, struct Transform* cameraTransform) { struct Vector3 forward; struct Vector3 right; - skAnimatorV2Update(&player->animator, player->armature.boneTransforms, FIXED_DELTA_TIME); + skBlenderUpdate(&player->animator, player->armature.boneTransforms, FIXED_DELTA_TIME); int doorwayMask = worldCheckDoorwaySides(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom); playerGetMoveBasis(&player->lookTransform, &forward, &right); @@ -448,4 +491,11 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) { player->body.currentRoom = worldCheckDoorwayCrossings(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom, doorwayMask); dynamicSceneSetRoomFlags(player->dynamicId, ROOM_FLAG_FROM_INDEX(player->body.currentRoom)); + + float startTime = 0.0f; + struct SKAnimationClip* clip = playerDetermineNextClip(player, &player->animator.blendLerp, &startTime, &forward, &right); + + if (clip != player->animator.from.currentClip) { + skAnimatorRunClip(&player->animator.from, clip, startTime, SKAnimatorFlagsLoop); + } } diff --git a/src/player/player.h b/src/player/player.h index 90365ba..1274003 100644 --- a/src/player/player.h +++ b/src/player/player.h @@ -23,7 +23,7 @@ struct Player { struct RigidBody body; struct Transform lookTransform; struct SKArmature armature; - struct SKAnimatorV2 animator; + struct SKAnimatorBlender animator; short grabbingThroughPortal; short dynamicId; struct CollisionObject* grabbing; diff --git a/src/scene/box_dropper.c b/src/scene/box_dropper.c index 66536e8..5d72210 100644 --- a/src/scene/box_dropper.c +++ b/src/scene/box_dropper.c @@ -100,7 +100,7 @@ void boxDropperInit(struct BoxDropper* dropper, struct BoxDropperDefinition* def skArmatureInit(&dropper->armature, &props_box_dropper_armature); - skAnimatorV2Init(&dropper->animator, PROPS_BOX_DROPPER_DEFAULT_BONES_COUNT); + skAnimatorInit(&dropper->animator, PROPS_BOX_DROPPER_DEFAULT_BONES_COUNT); dropper->flags = 0; dropper->reloadTimer = DROOPER_RELOAD_TIME; @@ -109,7 +109,7 @@ void boxDropperInit(struct BoxDropper* dropper, struct BoxDropperDefinition* def } void boxDropperUpdate(struct BoxDropper* dropper) { - skAnimatorV2Update(&dropper->animator, dropper->armature.boneTransforms, FIXED_DELTA_TIME); + skAnimatorUpdate(&dropper->animator, dropper->armature.boneTransforms, FIXED_DELTA_TIME); if (dropper->reloadTimer > 0.0f) { dropper->reloadTimer -= FIXED_DELTA_TIME; @@ -143,7 +143,7 @@ void boxDropperUpdate(struct BoxDropper* dropper) { boxDropperFakePos(dropper, &pendingCubePos); decorObjectInit(&dropper->activeCube, decorObjectDefinitionForId(DECOR_TYPE_CUBE), &pendingCubePos, dropper->roomIndex); - skAnimatorV2RunClip(&dropper->animator, &props_box_dropper_Armature_DropCube_clip, 0.0f, 0); + skAnimatorRunClip(&dropper->animator, &props_box_dropper_Armature_DropCube_clip, 0.0f, 0); dropper->flags &= ~BoxDropperFlagsCubeRequested; dropper->flags |= BoxDropperFlagsCubeIsActive; diff --git a/src/scene/box_dropper.h b/src/scene/box_dropper.h index cf29384..98a7ba3 100644 --- a/src/scene/box_dropper.h +++ b/src/scene/box_dropper.h @@ -17,7 +17,7 @@ enum BoxDropperFlags { struct BoxDropper { struct Transform transform; struct SKArmature armature; - struct SKAnimatorV2 animator; + struct SKAnimator animator; struct DecorObject activeCube; float reloadTimer; diff --git a/src/scene/pedestal.c b/src/scene/pedestal.c index edd9eba..ff43508 100644 --- a/src/scene/pedestal.c +++ b/src/scene/pedestal.c @@ -60,7 +60,7 @@ void pedestalInit(struct Pedestal* pedestal, struct PedestalDefinition* definiti skArmatureInit(&pedestal->armature, &pedestal_armature); - skAnimatorV2Init(&pedestal->animator, PEDESTAL_DEFAULT_BONES_COUNT); + skAnimatorInit(&pedestal->animator, PEDESTAL_DEFAULT_BONES_COUNT); pedestal->dynamicId = dynamicSceneAdd(pedestal, pedestalRender, &pedestal->transform, 0.8f); @@ -82,7 +82,7 @@ void pedestalDetermineHolderAngle(struct Pedestal* pedestal, struct Vector2* out } void pedestalUpdate(struct Pedestal* pedestal) { - skAnimatorV2Update(&pedestal->animator, pedestal->armature.boneTransforms, FIXED_DELTA_TIME); + skAnimatorUpdate(&pedestal->animator, pedestal->armature.boneTransforms, FIXED_DELTA_TIME); if (pedestal->flags & PedestalFlagsIsPointing) { struct Vector2 target; @@ -99,7 +99,7 @@ void pedestalUpdate(struct Pedestal* pedestal) { void pedestalHide(struct Pedestal* pedestal) { pedestal->flags |= PedestalFlagsDown; - skAnimatorV2RunClip(&pedestal->animator, &pedestal_Armature_Hide_clip, 0.0f, 0); + skAnimatorRunClip(&pedestal->animator, &pedestal_Armature_Hide_clip, 0.0f, 0); } void pedestalPointAt(struct Pedestal* pedestal, struct Vector3* target) { diff --git a/src/scene/pedestal.h b/src/scene/pedestal.h index 7bc4a6d..2f2fa1d 100644 --- a/src/scene/pedestal.h +++ b/src/scene/pedestal.h @@ -13,7 +13,7 @@ enum PedestalFlags { struct Pedestal { struct Transform transform; struct SKArmature armature; - struct SKAnimatorV2 animator; + struct SKAnimator animator; short dynamicId; short roomIndex; diff --git a/src/sk64/skelatool_animator.c b/src/sk64/skelatool_animator.c index 8b26d22..a01f57f 100644 --- a/src/sk64/skelatool_animator.c +++ b/src/sk64/skelatool_animator.c @@ -31,7 +31,7 @@ void skAnimatorCopy(u32 romAddress, void* target, u32 size) { osEPiStartDma(gAnimationPiHandle, ioMesg, OS_READ); } -void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones) { +void skAnimatorInit(struct SKAnimator* animator, int nBones) { animator->currentClip = NULL; animator->currentTime = 0.0f; animator->blendLerp = 0.0f; @@ -43,7 +43,7 @@ void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones) { animator->nBones = nBones; } -void skAnimatorV2Cleanup(struct SKAnimatorV2* animator) { +void skAnimatorCleanup(struct SKAnimator* animator) { free(animator->boneState[0]); free(animator->boneState[1]); @@ -51,7 +51,7 @@ void skAnimatorV2Cleanup(struct SKAnimatorV2* animator) { animator->boneState[1] = NULL; } -void skAnimatorV2RequestNext(struct SKAnimatorV2* animator) { +void skAnimatorRequestNext(struct SKAnimator* animator) { struct SKAnimationClip* currentClip = animator->currentClip; if (!currentClip) { @@ -77,63 +77,88 @@ void skAnimatorV2RequestNext(struct SKAnimatorV2* animator) { skAnimatorCopy((u32)currentClip->frames + frameSize * nextFrame, (void*)animator->boneState[animator->latestBoneState], sizeof(struct SKAnimationBoneFrame) * boneCount); } -void skAnimatorV2Extractstate(struct SKAnimationBoneFrame* frames, int boneCount, struct Transform* result) { - for (int i = 0; i < boneCount; ++i) { - result[i].position.x = (float)frames[i].position.x; - result[i].position.y = (float)frames[i].position.y; - result[i].position.z = (float)frames[i].position.z; +void skAnimatorExtractBone(struct SKAnimationBoneFrame* bone, struct Transform* result) { + result->position.x = (float)bone->position.x; + result->position.y = (float)bone->position.y; + result->position.z = (float)bone->position.z; - result[i].rotation.x = frames[i].rotation.x * (1.0f / 32767.0f); - result[i].rotation.y = frames[i].rotation.y * (1.0f / 32767.0f); - result[i].rotation.z = frames[i].rotation.z * (1.0f / 32767.0f); - float wSqrd = 1.0f - (result[i].rotation.x * result[i].rotation.x + result[i].rotation.y * result[i].rotation.y + result[i].rotation.z * result[i].rotation.z); - if (wSqrd <= 0.0f) { - result[i].rotation.w = 0.0f; - } else { - result[i].rotation.w = sqrtf(wSqrd); - } - - result[i].scale = gOneVec; + result->rotation.x = bone->rotation.x * (1.0f / 32767.0f); + result->rotation.y = bone->rotation.y * (1.0f / 32767.0f); + result->rotation.z = bone->rotation.z * (1.0f / 32767.0f); + float wSqrd = 1.0f - (result->rotation.x * result->rotation.x + result->rotation.y * result->rotation.y + result->rotation.z * result->rotation.z); + if (wSqrd <= 0.0f) { + result->rotation.w = 0.0f; + } else { + result->rotation.w = sqrtf(wSqrd); } } -void skAnimatorV2ReadTransform(struct SKAnimatorV2* animator, struct Transform* transforms) { +void skAnimatorInitZeroTransform(struct SKAnimator* animator, struct Transform* transforms) { if (animator->latestBoneState == -1) { return; } - if (animator->blendLerp >= 1.0f) { - skAnimatorV2Extractstate(animator->boneState[animator->latestBoneState], animator->nBones, transforms); - return; - } - - struct Transform fromState[animator->nBones]; - struct Transform toState[animator->nBones]; - - skAnimatorV2Extractstate(animator->boneState[animator->latestBoneState], animator->nBones, toState); - skAnimatorV2Extractstate(animator->boneState[animator->latestBoneState ^ 1], animator->nBones, fromState); - for (int i = 0; i < animator->nBones; ++i) { - transformLerp(&fromState[i], &toState[i], animator->blendLerp, &transforms[i]); + transforms[i].position = gZeroVec; + transforms[i].rotation = gQuaternionZero; + transforms[i].scale = gOneVec; } } -void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transforms, float deltaTime) { +void skAnimatorNormalize(struct SKAnimator* animator, struct Transform* transforms) { + for (int i = 0; i < animator->nBones; ++i) { + quatNormalize(&transforms[i].rotation, &transforms[i].rotation); + } +} + +void skAnimatorBlendTransform(struct SKAnimationBoneFrame* frame, struct Transform* transforms, int nBones, float weight) { + for (int i = 0; i < nBones; ++i) { + struct Transform boneTransform; + skAnimatorExtractBone(&frame[i], &boneTransform); + + vector3AddScaled(&transforms[i].position, &boneTransform.position, weight, &transforms[i].position); + + transforms[i].rotation.x += boneTransform.rotation.x * weight; + transforms[i].rotation.y += boneTransform.rotation.y * weight; + transforms[i].rotation.z += boneTransform.rotation.z * weight; + transforms[i].rotation.w += boneTransform.rotation.w * weight; + } +} + +void skAnimatorReadTransformWithWeight(struct SKAnimator* animator, struct Transform* transforms, float weight) { + if (animator->blendLerp >= 1.0f) { + skAnimatorBlendTransform(animator->boneState[animator->latestBoneState], transforms, animator->nBones, weight); + return; + } + + skAnimatorBlendTransform(animator->boneState[animator->latestBoneState], transforms, animator->nBones, animator->blendLerp * weight); + skAnimatorBlendTransform(animator->boneState[animator->latestBoneState ^ 1], transforms, animator->nBones, (1.0f - animator->blendLerp) * weight); +} + +void skAnimatorReadTransform(struct SKAnimator* animator, struct Transform* transforms) { + if (animator->latestBoneState == -1) { + return; + } + + skAnimatorInitZeroTransform(animator, transforms); + skAnimatorReadTransformWithWeight(animator, transforms, 1.0f); + skAnimatorNormalize(animator, transforms); +} + +void skAnimatorStep(struct SKAnimator* animator, float deltaTime) { struct SKAnimationClip* currentClip = animator->currentClip; if (!currentClip) { return; } - skAnimatorV2ReadTransform(animator, transforms); - animator->currentTime += deltaTime; float currentFrameFractional = animator->currentTime * currentClip->fps; int currentFrame = (int)ceilf(currentFrameFractional); while (currentFrame >= currentClip->nFrames) { - if (!(animator->flags & SKAnimatorV2FlagsLoop)) { + if (!(animator->flags & SKAnimatorFlagsLoop)) { animator->blendLerp = 1.0f; return; } @@ -162,10 +187,22 @@ void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transfo animator->blendLerp = 1.0f; } - skAnimatorV2RequestNext(animator); + skAnimatorRequestNext(animator); } -void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip* clip, float startTime, int flags) { +void skAnimatorUpdate(struct SKAnimator* animator, struct Transform* transforms, float deltaTime) { + struct SKAnimationClip* currentClip = animator->currentClip; + + if (!currentClip) { + return; + } + + skAnimatorReadTransform(animator, transforms); + + skAnimatorStep(animator, deltaTime); +} + +void skAnimatorRunClip(struct SKAnimator* animator, struct SKAnimationClip* clip, float startTime, int flags) { animator->currentClip = clip; if (!clip) { @@ -184,7 +221,7 @@ void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip* animator->currentTime = startTime; animator->flags = flags; - skAnimatorV2RequestNext(animator); + skAnimatorRequestNext(animator); } static unsigned gSegmentLocations[SK_SEGMENT_COUNT]; @@ -196,4 +233,48 @@ void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocation) { u32 skTranslateSegment(unsigned address) { unsigned segment = (address >> 24) & 0xF; return (address & 0xFFFFFF) + gSegmentLocations[segment]; +} + +void skBlenderInit(struct SKAnimatorBlender* blender, int nBones) { + skAnimatorInit(&blender->from, nBones); + skAnimatorInit(&blender->to, nBones); + blender->blendLerp = 0.0f; +} + +void skBlenderApply(struct SKAnimatorBlender* blender, struct Transform* transforms) { + float lerp = blender->blendLerp; + + if (blender->from.latestBoneState == -1) { + if (blender->to.latestBoneState == -1) { + return; + } + + lerp = 1.0f; + } + + if (blender->to.latestBoneState == -1) { + lerp = 0.0f; + } + + skAnimatorInitZeroTransform(&blender->from, transforms); + + if (lerp == 1.0f) { + skAnimatorReadTransformWithWeight(&blender->to, transforms, 1.0f); + } else if (lerp == 0.0f) { + skAnimatorReadTransformWithWeight(&blender->from, transforms, 1.0f); + } else { + skAnimatorReadTransformWithWeight(&blender->to, transforms, lerp); + skAnimatorReadTransformWithWeight(&blender->from, transforms, 1.0f - lerp); + } +} + +void skBlenderCleanup(struct SKAnimatorBlender* blender) { + skAnimatorCleanup(&blender->from); + skAnimatorCleanup(&blender->to); +} + +void skBlenderUpdate(struct SKAnimatorBlender* blender, struct Transform* transforms, float deltaTime) { + skBlenderApply(blender, transforms); + skAnimatorStep(&blender->from, deltaTime); + skAnimatorStep(&blender->to, deltaTime); } \ No newline at end of file diff --git a/src/sk64/skelatool_animator.h b/src/sk64/skelatool_animator.h index 57a0bef..553dab1 100644 --- a/src/sk64/skelatool_animator.h +++ b/src/sk64/skelatool_animator.h @@ -4,11 +4,11 @@ #include "skelatool_clip.h" #include "../math/transform.h" -enum SKAnimatorV2Flags { - SKAnimatorV2FlagsLoop = (1 << 0), +enum SKAnimatorFlags { + SKAnimatorFlagsLoop = (1 << 0), }; -struct SKAnimatorV2 { +struct SKAnimator { struct SKAnimationClip* currentClip; float currentTime; float blendLerp; @@ -19,15 +19,26 @@ struct SKAnimatorV2 { short nBones; }; -void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones); -void skAnimatorV2Cleanup(struct SKAnimatorV2* animator); -void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transforms, float deltaTime); +void skAnimatorInit(struct SKAnimator* animator, int nBones); +void skAnimatorCleanup(struct SKAnimator* animator); +void skAnimatorUpdate(struct SKAnimator* animator, struct Transform* transforms, float deltaTime); -void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip* clip, float startTime, int flags); +void skAnimatorRunClip(struct SKAnimator* animator, struct SKAnimationClip* clip, float startTime, int flags); #define SK_SEGMENT_COUNT 16 void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocatoin); u32 skTranslateSegment(unsigned address); +struct SKAnimatorBlender { + struct SKAnimator from; + struct SKAnimator to; + + float blendLerp; +}; + +void skBlenderInit(struct SKAnimatorBlender* blender, int nBones); +void skBlenderCleanup(struct SKAnimatorBlender* animator); +void skBlenderUpdate(struct SKAnimatorBlender* blender, struct Transform* transforms, float deltaTime); + #endif