Work on animations playable from cutscenes

Allow animator to run backwards or at any speed
This commit is contained in:
James Lambert 2023-01-01 16:53:08 -07:00
parent 44c9974afb
commit 058ad8fd98
8 changed files with 210 additions and 49 deletions

View file

@ -124,6 +124,10 @@ void cutsceneQueueSound(int soundId, float volume, int channel) {
}
}
float cutsceneRunnerConvertPlaybackSpeed(s8 asInt) {
return asInt * (1.0f / 127.0f);
}
void cutsceneRunnerStartStep(struct CutsceneRunner* runner) {
struct CutsceneStep* step = &runner->currentCutscene->steps[runner->currentStep];
switch (step->type) {
@ -192,6 +196,21 @@ void cutsceneRunnerStartStep(struct CutsceneRunner* runner) {
pedestalPointAt(&gScene.pedestals[i], &gCurrentLevel->locations[step->pointPedestal.atLocation].transform.position);
}
break;
case CutsceneStepPlayAnimation:
sceneAnimatorPlay(
&gScene.animator,
step->playAnimation.armatureIndex,
step->playAnimation.animationIndex,
cutsceneRunnerConvertPlaybackSpeed(step->playAnimation.playbackSpeed)
);
break;
case CutsceneStepSetAnimationSpeed:
sceneAnimatorSetSpeed(
&gScene.animator,
step->playAnimation.armatureIndex,
cutsceneRunnerConvertPlaybackSpeed(step->playAnimation.playbackSpeed)
);
break;
default:
}
}
@ -213,6 +232,8 @@ int cutsceneRunnerUpdateCurrentStep(struct CutsceneRunner* runner) {
return signalsRead(step->waitForSignal.signalIndex);
case CutsceneStepTypeWaitForCutscene:
return !cutsceneIsRunning(&gCurrentLevel->cutscenes[step->cutscene.cutsceneIndex]);
case CutsceneStepWaitForAnimation:
return !sceneAnimatorIsRunning(&gScene.animator, step->waitForAnimation.armatureIndex);
default:
return 1;
}

View file

@ -41,6 +41,9 @@ enum CutsceneStepType {
CutsceneStepTypeWaitForCutscene,
CutsceneStepTypeHidePedestal,
CutsceneStepTypePointPedestal,
CutsceneStepPlayAnimation,
CutsceneStepSetAnimationSpeed,
CutsceneStepWaitForAnimation,
};
#define CH_NONE 0xFF
@ -95,6 +98,18 @@ struct CutsceneStep {
struct {
u16 atLocation;
} pointPedestal;
struct {
u8 armatureIndex;
u8 animationIndex;
s8 playbackSpeed;
} playAnimation;
struct {
u8 armatureIndex;
s8 playbackSpeed;
} setAnimationSpeed;
struct {
u8 armatureIndex;
} waitForAnimation;
int noop;
};
};

View file

@ -7,6 +7,7 @@
void sceneAnimatorInit(struct SceneAnimator* sceneAnimator, struct AnimationInfo* animationInfo, int animatorCount) {
sceneAnimator->armatures = malloc(sizeof(struct SKArmature) * animatorCount);
sceneAnimator->animators = malloc(sizeof(struct SKAnimator) * animatorCount);
sceneAnimator->playbackSpeeds = malloc(sizeof(float) * animatorCount);
sceneAnimator->animationInfo = animationInfo;
sceneAnimator->animatorCount = animatorCount;
@ -16,6 +17,7 @@ void sceneAnimatorInit(struct SceneAnimator* sceneAnimator, struct AnimationInfo
for (int i = 0; i < animatorCount; ++i) {
skArmatureInit(&sceneAnimator->armatures[i], &animationInfo[i].armature);
skAnimatorInit(&sceneAnimator->animators[i], animationInfo[i].armature.numberOfBones);
sceneAnimator->playbackSpeeds[i] = 1.0f;
sceneAnimator->boneCount += animationInfo[i].armature.numberOfBones;
}
@ -23,7 +25,7 @@ void sceneAnimatorInit(struct SceneAnimator* sceneAnimator, struct AnimationInfo
void sceneAnimatorUpdate(struct SceneAnimator* sceneAnimator) {
for (int i = 0; i < sceneAnimator->animatorCount; ++i) {
skAnimatorUpdate(&sceneAnimator->animators[i], sceneAnimator->armatures[i].pose, FIXED_DELTA_TIME);
skAnimatorUpdate(&sceneAnimator->animators[i], sceneAnimator->armatures[i].pose, FIXED_DELTA_TIME * sceneAnimator->playbackSpeeds[i]);
}
}
@ -39,4 +41,42 @@ Mtx* sceneAnimatorBuildTransforms(struct SceneAnimator* sceneAnimator, struct Re
}
return result;
}
void sceneAnimatorPlay(struct SceneAnimator* sceneAnimator, int animatorIndex, int animationIndex, float speed) {
if (animatorIndex < 0 || animatorIndex >= sceneAnimator->animatorCount) {
return;
}
struct AnimationInfo* info = &sceneAnimator->animationInfo[animatorIndex];
if (animationIndex < 0 || animationIndex >= info->clipCount) {
return;
}
struct SKAnimationClip* clip = &info->clips[animationIndex];
sceneAnimator->playbackSpeeds[animatorIndex] = speed;
if (sceneAnimator->animators[animatorIndex].currentClip == clip) {
return;
}
skAnimatorRunClip(&sceneAnimator->animators[animatorIndex], clip, speed >= 0.0f ? 0.0f : clip->nFrames / clip->fps, 0);
}
void sceneAnimatorSetSpeed(struct SceneAnimator* sceneAnimator, int animatorIndex, float speed) {
if (animatorIndex < 0 || animatorIndex >= sceneAnimator->animatorCount) {
return;
}
sceneAnimator->playbackSpeeds[animatorIndex] = speed;
}
int sceneAnimatorIsRunning(struct SceneAnimator* sceneAnimator, int animatorIndex) {
if (animatorIndex < 0 || animatorIndex >= sceneAnimator->animatorCount) {
return 0;
}
return skAnimatorIsRunning(&sceneAnimator->animators[animatorIndex]);
}

View file

@ -12,6 +12,7 @@ struct SceneAnimator {
struct SKArmature* armatures;
struct SKAnimator* animators;
struct AnimationInfo* animationInfo;
float* playbackSpeeds;
short animatorCount;
short boneCount;
};
@ -22,4 +23,9 @@ void sceneAnimatorUpdate(struct SceneAnimator* sceneAnimator);
Mtx* sceneAnimatorBuildTransforms(struct SceneAnimator* sceneAnimator, struct RenderState* renderState);
void sceneAnimatorPlay(struct SceneAnimator* sceneAnimator, int animatorIndex, int animationIndex, float speed);
void sceneAnimatorSetSpeed(struct SceneAnimator* sceneAnimator, int animatorIndex, float speed);
int sceneAnimatorIsRunning(struct SceneAnimator* sceneAnimator, int animatorIndex);
#endif

View file

@ -39,7 +39,7 @@ void skAnimatorInit(struct SKAnimator* animator, int nBones) {
animator->boneState[1] = malloc(sizeof(struct SKAnimationBoneFrame) * nBones);
animator->boneStateFrames[0] = -1;
animator->boneStateFrames[1] = -1;
animator->latestBoneState = -1;
animator->nextFrameStateIndex = -1;
animator->nBones = nBones;
}
@ -51,30 +51,28 @@ void skAnimatorCleanup(struct SKAnimator* animator) {
animator->boneState[1] = NULL;
}
void skAnimatorRequestNext(struct SKAnimator* animator) {
void skAnimatorRequestFrame(struct SKAnimator* animator, int nextFrame) {
struct SKAnimationClip* currentClip = animator->currentClip;
if (!currentClip) {
return;
}
int nextFrame = (int)ceilf(animator->currentTime * currentClip->fps);
if (animator->latestBoneState == -1) {
animator->latestBoneState = 0;
if (animator->nextFrameStateIndex == -1) {
animator->nextFrameStateIndex = 0;
}
if (animator->boneStateFrames[animator->latestBoneState] == nextFrame) {
if (animator->boneStateFrames[animator->nextFrameStateIndex] == nextFrame) {
return;
}
animator->boneStateFrames[animator->latestBoneState] = nextFrame;
animator->boneStateFrames[animator->nextFrameStateIndex] = nextFrame;
int boneCount = MIN(animator->nBones, currentClip->nBones);
int frameSize = currentClip->nBones * sizeof(struct SKAnimationBoneFrame);
skAnimatorCopy((u32)currentClip->frames + frameSize * nextFrame, (void*)animator->boneState[animator->latestBoneState], sizeof(struct SKAnimationBoneFrame) * boneCount);
skAnimatorCopy((u32)currentClip->frames + frameSize * nextFrame, (void*)animator->boneState[animator->nextFrameStateIndex], sizeof(struct SKAnimationBoneFrame) * boneCount);
}
void skAnimatorExtractBone(struct SKAnimationBoneFrame* bone, struct Transform* result) {
@ -94,7 +92,7 @@ void skAnimatorExtractBone(struct SKAnimationBoneFrame* bone, struct Transform*
}
void skAnimatorInitZeroTransform(struct SKAnimator* animator, struct Transform* transforms) {
if (animator->latestBoneState == -1) {
if (animator->nextFrameStateIndex == -1) {
return;
}
@ -135,16 +133,16 @@ void skAnimatorBlendTransform(struct SKAnimationBoneFrame* frame, struct Transfo
void skAnimatorReadTransformWithWeight(struct SKAnimator* animator, struct Transform* transforms, float weight) {
if (animator->blendLerp >= 1.0f) {
skAnimatorBlendTransform(animator->boneState[animator->latestBoneState], transforms, animator->nBones, weight);
skAnimatorBlendTransform(animator->boneState[animator->nextFrameStateIndex], 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);
skAnimatorBlendTransform(animator->boneState[animator->nextFrameStateIndex], transforms, animator->nBones, animator->blendLerp * weight);
skAnimatorBlendTransform(animator->boneState[animator->nextFrameStateIndex ^ 1], transforms, animator->nBones, (1.0f - animator->blendLerp) * weight);
}
void skAnimatorReadTransform(struct SKAnimator* animator, struct Transform* transforms) {
if (animator->latestBoneState == -1) {
if (animator->nextFrameStateIndex == -1) {
return;
}
@ -153,6 +151,18 @@ void skAnimatorReadTransform(struct SKAnimator* animator, struct Transform* tran
skAnimatorNormalize(animator, transforms);
}
int skAnimatorBoneStateIndexOfFrame(struct SKAnimator* animator, int frame) {
if (animator->boneStateFrames[0] == frame) {
return 0;
}
if (animator->boneStateFrames[1] == frame) {
return 1;
}
return 0;
}
void skAnimatorStep(struct SKAnimator* animator, float deltaTime) {
struct SKAnimationClip* currentClip = animator->currentClip;
@ -162,41 +172,59 @@ void skAnimatorStep(struct SKAnimator* animator, float deltaTime) {
animator->currentTime += deltaTime;
float currentFrameFractional = animator->currentTime * currentClip->fps;
int currentFrame = (int)ceilf(currentFrameFractional);
float duration = currentClip->nFrames / currentClip->fps;
while (currentFrame >= currentClip->nFrames) {
if (!(animator->flags & SKAnimatorFlagsLoop)) {
animator->blendLerp = 1.0f;
animator->currentClip = NULL;
return;
}
animator->currentTime -= currentClip->nFrames / currentClip->fps;
if (animator->currentTime < 0.0f) {
animator->currentTime = 0.0f;
}
currentFrameFractional = animator->currentTime * currentClip->fps;
currentFrame = (int)ceilf(currentFrameFractional);
if (animator->currentTime >= duration || animator->currentTime < 0.0f) {
animator->currentTime = mathfMod(animator->currentTime, duration);
}
int existingFrame = animator->boneStateFrames[animator->latestBoneState];
animator->blendLerp = 1.0f - (currentFrame - currentFrameFractional);
float currentFrameFractional = animator->currentTime * currentClip->fps;
int prevFrame = (int)floorf(currentFrameFractional);
int nextFrame = (int)ceilf(currentFrameFractional);
float lerpValue = currentFrameFractional - prevFrame;
// no need to request the next frame
if (existingFrame == (int)currentFrame) {
int existingPrevFrame = skAnimatorBoneStateIndexOfFrame(animator, prevFrame);
int existingNextFrame = skAnimatorBoneStateIndexOfFrame(animator, nextFrame);
if (existingPrevFrame == -1 && existingNextFrame == -1) {
// both frames need to be requested
animator->blendLerp = lerpValue;
if (prevFrame != nextFrame) {
animator->nextFrameStateIndex = 0;
skAnimatorRequestFrame(animator, prevFrame);
}
animator->nextFrameStateIndex = 1;
skAnimatorRequestFrame(animator, nextFrame);
return;
}
animator->latestBoneState ^= 1;
if ((int)currentFrame > existingFrame + 1) {
animator->blendLerp = 1.0f;
if (existingNextFrame == -1) {
// only the next frame needs to be requested
animator->blendLerp = lerpValue;
animator->nextFrameStateIndex = existingPrevFrame ^ 1;
skAnimatorRequestFrame(animator, nextFrame);
return;
}
skAnimatorRequestNext(animator);
if (existingPrevFrame == -1) {
// only the previous frame needs to be requested
animator->blendLerp = 1.0f - lerpValue;
animator->nextFrameStateIndex = existingNextFrame ^ 1;
skAnimatorRequestFrame(animator, prevFrame);
return;
}
if (existingNextFrame == existingPrevFrame) {
// only one frame is needed and is already present
animator->blendLerp = 1.0f;
animator->nextFrameStateIndex = existingNextFrame;
}
if (existingNextFrame == 1) {
animator->blendLerp = lerpValue;
} else {
animator->blendLerp = 1.0f - lerpValue;
}
}
void skAnimatorUpdate(struct SKAnimator* animator, struct Transform* transforms, float deltaTime) {
@ -218,8 +246,8 @@ void skAnimatorRunClip(struct SKAnimator* animator, struct SKAnimationClip* clip
return;
}
if (animator->latestBoneState != -1) {
animator->latestBoneState ^= 1;
if (animator->nextFrameStateIndex != -1) {
animator->nextFrameStateIndex ^= 1;
}
animator->boneStateFrames[0] = -1;
@ -230,7 +258,7 @@ void skAnimatorRunClip(struct SKAnimator* animator, struct SKAnimationClip* clip
animator->currentTime = startTime;
animator->flags = flags;
skAnimatorRequestNext(animator);
skAnimatorStep(animator, 0.0f);
}
int skAnimatorIsRunning(struct SKAnimator* animator) {
@ -257,15 +285,15 @@ void skBlenderInit(struct SKAnimatorBlender* blender, int nBones) {
void skBlenderApply(struct SKAnimatorBlender* blender, struct Transform* transforms) {
float lerp = blender->blendLerp;
if (blender->from.latestBoneState == -1) {
if (blender->to.latestBoneState == -1) {
if (blender->from.nextFrameStateIndex == -1) {
if (blender->to.nextFrameStateIndex == -1) {
return;
}
lerp = 1.0f;
}
if (blender->to.latestBoneState == -1) {
if (blender->to.nextFrameStateIndex == -1) {
lerp = 0.0f;
}

View file

@ -14,7 +14,7 @@ struct SKAnimator {
float blendLerp;
struct SKAnimationBoneFrame* boneState[2];
short boneStateFrames[2];
short latestBoneState;
short nextFrameStateIndex;
short flags;
short nBones;
};

View file

@ -18,6 +18,9 @@ end
local armatures = {}
local armature_indices_by_name = {}
local animation_indices_by_name = {}
local node_to_bone_index = {}
local node_to_armature_index = {}
local bones_as_array = {}
@ -48,10 +51,14 @@ for index, armature in pairs(armatures) do
local armature_data = sk_animation.build_armature_data(armature.armature, nil, armature.name, '_geo')
local animation_clips = {}
for _, animation in pairs(sk_animation.filter_animations_for_armature(armature.armature, sk_scene.scene.animations)) do
local animation_names = {}
for animation_index, animation in pairs(sk_animation.filter_animations_for_armature(armature.armature, sk_scene.scene.animations)) do
local clip = sk_animation.build_animation_clip(animation, armature.armature, '_anim')
sk_definition_writer.add_macro(armature.name .. '_' .. animation.name, tostring(#animation_clips))
table.insert(animation_clips, clip)
animation_names[animation.name] = sk_definition_writer.raw(sk_definition_writer.add_macro(armature.name .. '_ANIMATION_' .. animation.name, animation_index - 1))
end
sk_definition_writer.add_definition(armature.name .. '_clips', 'struct SKAnimationClip[]', '_geo', animation_clips)
@ -61,6 +68,9 @@ for index, armature in pairs(armatures) do
clips = sk_definition_writer.reference_to(animation_clips, 1),
clipCount = #animation_clips
})
armature_indices_by_name[armature.name] = sk_definition_writer.raw(sk_definition_writer.add_macro('ARMATURE_' .. armature.name, tostring(index - 1)))
animation_indices_by_name[armature.name] = animation_names
end
local function get_bone_index_for_node(node)
@ -71,10 +81,26 @@ local function get_bone_for_index(index)
return bones_as_array[index]
end
local function get_armature_index_with_name(name)
return armature_indices_by_name[name]
end
local function get_animation_with_name(armature_name, animation_name)
local armature = animation_indices_by_name[armature_name]
if not armature then
return nil
end
return armature[animation_name]
end
sk_definition_writer.add_definition('anim', 'struct AnimationInfo[]', '_geo', animated_nodes)
return {
animated_nodes = animated_nodes,
get_bone_index_for_node = get_bone_index_for_node,
get_bone_for_index = get_bone_for_index,
get_armature_index_with_name = get_armature_index_with_name,
get_animation_with_name = get_animation_with_name,
}

View file

@ -3,6 +3,7 @@ local sk_definition_writer = require('sk_definition_writer')
local sk_scene = require('sk_scene')
local room_export = require('tools.level_scripts.room_export')
local signals = require('tools.level_scripts.signals')
local animation = require('tools.level_scripts.animation')
sk_definition_writer.add_header('"../build/src/audio/clips.h"')
@ -182,6 +183,30 @@ local function generate_cutscene_step(step, step_index, label_locations, cutscen
result.pointPedestal = {
find_location_index(step.args[1]),
}
elseif step.command == "play_animation" then
result.type = sk_definition_writer.raw('CutsceneStepPlayAnimation')
result.playAnimation = {
animation.get_armature_index_with_name(step.args[1]) or 0,
animation.get_animation_with_name(step.args[1], step.args[2]) or 0,
step.args[3] and (tonumber(step.args[3]) * 127) or 127,
}
elseif step.command == "pause_animation" then
result.type = sk_definition_writer.raw('CutsceneStepSetAnimationSpeed')
result.setAnimationSpeed = {
animation.get_armature_index_with_name(step.args[1]) or 0,
0,
}
elseif step.command == "resume_animation" then
result.type = sk_definition_writer.raw('CutsceneStepSetAnimationSpeed')
result.setAnimationSpeed = {
animation.get_armature_index_with_name(step.args[1]) or 0,
step.args[2] and (tonumber(step.args[2]) * 127) or 127,
}
elseif step.command == "wait_for_animation" then
result.type = sk_definition_writer.raw('CutsceneStepWaitForAnimation')
result.waitForAnimation = {
animation.get_armature_index_with_name(step.args[1]) or 0,
}
else
result.type = sk_definition_writer.raw('CutsceneStepTypeNoop')
table.noop = 0;