Refactor animation system

This commit is contained in:
James Lambert 2022-12-02 21:33:49 -07:00
parent 9f61fde4a9
commit 95ab27db2f
20 changed files with 444 additions and 21 deletions

View file

@ -182,7 +182,7 @@ MODEL_LIST = assets/models/cube/cube.blend \
assets/models/portal/portal_orange_face.blend \
assets/models/pedestal.blend
ANIM_LIST = build/assets/models/pedestal_anim.o build/assets/models/props/box_dropper_anim.o
ANIM_LIST = build/assets/models/pedestal_anim.o build/assets/models/props/box_dropper_anim.o build/assets/models/player/chell_anim.o
MODEL_HEADERS = $(MODEL_LIST:%.blend=build/%.h)
MODEL_OBJECTS = $(MODEL_LIST:%.blend=build/%_geo.o)

View file

@ -113,6 +113,7 @@ int main(int argc, char *argv[]) {
settings.mBonesAsVertexGroups = args.mBonesAsVertexGroups;
settings.mForcePallete = args.mForcePallete;
settings.mTargetCIBuffer = args.mTargetCIBuffer;
settings.mTicksPerSecond = args.mFPS;
bool hasError = false;

View file

@ -28,6 +28,7 @@ bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArgumen
output.mDefaultMaterial = "default";
output.mForceMaterialName = "";
output.mProcessAsModel = false;
output.mFPS = 30.0f;
std::string lastParameter = "";
bool hasError = false;
@ -61,6 +62,8 @@ bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArgumen
output.mForcePallete = curr;
} else if (lastParameter == "script") {
output.mScriptFiles.push_back(curr);
} else if (lastParameter == "fps") {
output.mFPS = (float)atof(curr);
}
lastParameter = "";
@ -111,6 +114,8 @@ bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArgumen
output.mTargetCIBuffer = true;
} else if (strcmp(curr, "--model") == 0) {
output.mProcessAsModel = true;
} else if (strcmp(curr, "--fps") == 0) {
lastParameter = "fps";
} else {
if (curr[0] == '-') {
hasError = true;

View file

@ -27,6 +27,7 @@ struct CommandLineArguments {
std::string mForcePallete;
float mFixedPointScale;
float mModelScale;
float mFPS;
bool mExportAnimation;
bool mExportGeometry;
bool mBonesAsVertexGroups;

View file

@ -11,7 +11,7 @@ DisplayListSettings::DisplayListSettings():
mMaxMatrixDepth(10),
mMaxOptimizationIterations(DEFAULT_MAX_OPTIMIZATION_ITERATIONS),
mCanPopMultipleMatrices(true),
mTicksPerSecond(30),
mTicksPerSecond(30.0f),
mExportAnimation(true),
mExportGeometry(true),
mIncludeCulling(true),

View file

@ -8,7 +8,7 @@
#include "./materials/Material.h"
#include "./materials/MaterialState.h"
#define DEFAULT_MAX_OPTIMIZATION_ITERATIONS 1000000
#define DEFAULT_MAX_OPTIMIZATION_ITERATIONS 1000
struct DisplayListSettings {
DisplayListSettings();
@ -20,7 +20,7 @@ struct DisplayListSettings {
int mMaxMatrixDepth;
int mMaxOptimizationIterations;
bool mCanPopMultipleMatrices;
unsigned short mTicksPerSecond;
float mTicksPerSecond;
std::map<std::string, std::shared_ptr<Material>> mMaterials;
std::string mDefaultMaterialName;
std::string mForceMaterialName;

View file

@ -225,6 +225,10 @@ void orderRenderBnB(struct RenderChunkDistanceGraph& graph, int maxIterations) {
orderRenderPopulateNext(graph, *current);
iteration += 1;
if ((iteration % 10000) == 0) {
std::cout << iteration << "/" << maxIterations << " searching for better solution. current improvement:" << (graph.currentBest->currentLength / greedyLength) << std::endl;
}
}
if (graph.currentBest->currentLength == greedyLength) {

View file

@ -95,6 +95,173 @@ std::vector<SKAnimationHeader> generateAnimationData(const aiScene* scene, BoneH
return animations;
}
struct FrameData {
aiVector3D position;
aiQuaternion rotation;
};
template <typename T>
void findStartValue(const T* keys, unsigned keyCount, double at, unsigned& startValue, double& lerp) {
for (startValue = 0; startValue < keyCount; ++startValue) {
if (keys[startValue].mTime >= at) {
if (startValue == 0) {
lerp = 0.0f;
} else {
--startValue;
double deltaTime = keys[startValue + 1].mTime - keys[startValue].mTime;
if (deltaTime == 1.0) {
lerp = 0.0f;
} else {
lerp = (at - keys[startValue].mTime) / deltaTime;
}
}
break;
}
}
}
aiVector3D evaluateVectorAt(const aiVectorKey* keys, unsigned keyCount, double at) {
if (keyCount == 0) {
return aiVector3D();
}
if (keyCount == 1) {
return keys[0].mValue;
}
unsigned startValue;
double lerp = 0.0f;
findStartValue(keys, keyCount, at, startValue, lerp);
if (startValue == keyCount) {
return keys[keyCount - 1].mValue;
}
aiVector3D from = keys[startValue].mValue;
aiVector3D to = keys[startValue + 1].mValue;
return (to - from) * (float)lerp + from;
}
aiQuaternion evaluateQuaternionAt(const aiQuatKey* keys, unsigned keyCount, double at) {
if (keyCount == 0) {
return aiQuaternion();
}
if (keyCount == 1) {
return keys[0].mValue;
}
unsigned startValue;
double lerp = 0.0f;
findStartValue(keys, keyCount, at, startValue, lerp);
if (startValue == keyCount) {
return keys[keyCount - 1].mValue;
}
aiQuaternion from = keys[startValue].mValue;
aiQuaternion to = keys[startValue + 1].mValue;
aiQuaternion output;
aiQuaternion::Interpolate(output, from, to, lerp);
return output;
}
void generateanimationV2(const aiAnimation& animation, BoneHierarchy& bones, CFileDefinition& fileDef, const DisplayListSettings& settings) {
int nFrames = ceil(animation.mDuration * settings.mTicksPerSecond / animation.mTicksPerSecond);
std::vector<std::vector<FrameData>> allFrameData(nFrames);
for (int i = 0; i < nFrames; ++i) {
allFrameData[i].resize(bones.GetBoneCount());
}
for (unsigned boneIndex = 0; boneIndex < bones.GetBoneCount(); ++boneIndex) {
Bone* bone = bones.BoneByIndex(boneIndex);
aiNodeAnim* nodeAnim = nullptr;
// find the animation channel for the given frame
for (unsigned channelIndex = 0; channelIndex < animation.mNumChannels; ++channelIndex) {
if (bone->GetName() == animation.mChannels[channelIndex]->mNodeName.C_Str()) {
nodeAnim = animation.mChannels[channelIndex];
break;
}
}
if (!nodeAnim) {
continue;
}
// populate the frame data for the given channel
for (int frame = 0; frame < nFrames; ++frame) {
double at = frame * animation.mTicksPerSecond / settings.mTicksPerSecond;
aiVector3D origin = evaluateVectorAt(nodeAnim->mPositionKeys, nodeAnim->mNumPositionKeys, at);
aiQuaternion rotation = evaluateQuaternionAt(nodeAnim->mRotationKeys, nodeAnim->mNumRotationKeys, at);
if (!bone->GetParent()) {
aiQuaternion constRot = settings.mRotateModel;
origin = constRot.Rotate(origin) * settings.mModelScale;
rotation = constRot * rotation;
}
allFrameData[frame][boneIndex].position = origin * settings.mFixedPointScale;
allFrameData[frame][boneIndex].rotation = rotation;
}
}
std::unique_ptr<StructureDataChunk> frames(new StructureDataChunk());
for (int frame = 0; frame < nFrames; ++frame) {
for (auto& frameBone : allFrameData[frame]) {
std::unique_ptr<StructureDataChunk> posData(new StructureDataChunk());
std::unique_ptr<StructureDataChunk> rotData(new StructureDataChunk());
posData->AddPrimitive((short)(frameBone.position.x));
posData->AddPrimitive((short)(frameBone.position.y));
posData->AddPrimitive((short)(frameBone.position.z));
if (frameBone.rotation.w < 0.0f) {
rotData->AddPrimitive((short)(-frameBone.rotation.x * std::numeric_limits<short>::max()));
rotData->AddPrimitive((short)(-frameBone.rotation.y * std::numeric_limits<short>::max()));
rotData->AddPrimitive((short)(-frameBone.rotation.z * std::numeric_limits<short>::max()));
} else {
rotData->AddPrimitive((short)(frameBone.rotation.x * std::numeric_limits<short>::max()));
rotData->AddPrimitive((short)(frameBone.rotation.y * std::numeric_limits<short>::max()));
rotData->AddPrimitive((short)(frameBone.rotation.z * std::numeric_limits<short>::max()));
}
std::unique_ptr<StructureDataChunk> frameData(new StructureDataChunk());
frameData->Add(std::move(posData));
frameData->Add(std::move(rotData));
frames->Add(std::move(frameData));
}
}
std::string framesName = fileDef.AddDataDefinition(std::string(animation.mName.C_Str()) + "_data", "struct SKAnimationBoneFrame", true, "_anim", std::move(frames));
std::unique_ptr<StructureDataChunk> clip(new StructureDataChunk());
clip->AddPrimitive(nFrames);
clip->AddPrimitive(bones.GetBoneCount());
clip->AddPrimitive(framesName);
clip->AddPrimitive(settings.mTicksPerSecond);
fileDef.AddDataDefinition(std::string(animation.mName.C_Str()) + "_clip", "struct SKAnimationClip", false, "_geo", std::move(clip));
}
void generateAnimationDataV2(const aiScene* scene, BoneHierarchy& bones, CFileDefinition& fileDef, const DisplayListSettings& settings) {
for (unsigned animationIndex = 0; animationIndex < scene->mNumAnimations; ++animationIndex) {
generateanimationV2(*scene->mAnimations[animationIndex], bones, fileDef, settings);
}
}
AnimationResults generateAnimationForScene(const aiScene* scene, CFileDefinition &fileDefinition, DisplayListSettings& settings) {
AnimationResults result;
@ -173,5 +340,7 @@ AnimationResults generateAnimationForScene(const aiScene* scene, CFileDefinition
fileDefinition.AddMacro(result.numberOfAttachmentMacros, std::to_string(attachmentCount));
generateAnimationDataV2(scene, bones, fileDefinition, settings);
return result;
}

View file

@ -159,9 +159,9 @@ static void gameProc(void* arg) {
controllersInit();
initAudio();
soundPlayerInit();
sceneInit(&gScene);
skInitDataPool(gPiHandle);
skSetSegmentLocation(CHARACTER_ANIMATION_SEGMENT, (unsigned)_animation_segmentSegmentRomStart);
sceneInit(&gScene);
while (1) {
OSScMsg *msg = NULL;

View file

@ -90,4 +90,10 @@ void transformConcat(struct Transform* left, struct Transform* right, struct Tra
output->position.x = left->position.x + rotatedOffset.x * left->scale.x;
output->position.y = left->position.y + rotatedOffset.y * left->scale.y;
output->position.z = left->position.z + rotatedOffset.z * left->scale.z;
}
void transformLerp(struct Transform* a, struct Transform* b, float t, struct Transform* output) {
vector3Lerp(&a->position, &b->position, t, &output->position);
quatLerp(&a->rotation, &b->rotation, t, &output->rotation);
vector3Lerp(&a->scale, &b->scale, t, &output->scale);
}

View file

@ -20,4 +20,6 @@ void transformPointInverse(struct Transform* transform, struct Vector3* in, stru
void transformPointInverseNoScale(struct Transform* transform, struct Vector3* in, struct Vector3* out);
void transformConcat(struct Transform* left, struct Transform* right, struct Transform* output);
void transformLerp(struct Transform* a, struct Transform* b, float t, struct Transform* output);
#endif

View file

@ -98,6 +98,9 @@ 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);
skAnimatorV2RunClip(&player->animator, &player_chell_Armature_WalkForward_clip, 0.0f, SKAnimatorV2FlagsLoop);
player->body.velocity = *velocity;
player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING;
@ -295,6 +298,8 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
struct Vector3 forward;
struct Vector3 right;
skAnimatorV2Update(&player->animator, player->armature.boneTransforms, FIXED_DELTA_TIME);
int doorwayMask = worldCheckDoorwaySides(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom);
playerGetMoveBasis(&player->lookTransform, &forward, &right);

View file

@ -7,7 +7,7 @@
#include "../physics/collision_object.h"
#include "../levels/level_definition.h"
#include "../scene/dynamic_scene.h"
#include "../sk64/skelatool_animator.h"
#include "../sk64/skelatool_animator_v2.h"
#include "../sk64/skelatool_armature.h"
#define PLAYER_GRABBING_THROUGH_NOTHING -1
@ -23,6 +23,7 @@ struct Player {
struct RigidBody body;
struct Transform lookTransform;
struct SKArmature armature;
struct SKAnimatorV2 animator;
short grabbingThroughPortal;
short dynamicId;
struct CollisionObject* grabbing;

View file

@ -100,7 +100,7 @@ void boxDropperInit(struct BoxDropper* dropper, struct BoxDropperDefinition* def
skArmatureInit(&dropper->armature, &props_box_dropper_armature);
skAnimatorInit(&dropper->animator, PROPS_BOX_DROPPER_DEFAULT_BONES_COUNT, NULL, NULL);
skAnimatorV2Init(&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) {
skAnimatorUpdate(&dropper->animator, dropper->armature.boneTransforms, 1.0f);
skAnimatorV2Update(&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);
skAnimatorRunClip(&dropper->animator, &props_box_dropper_animations[PROPS_BOX_DROPPER_PROPS_BOX_DROPPER_ARMATURE_DROPCUBE_INDEX], 0);
skAnimatorV2RunClip(&dropper->animator, &props_box_dropper_Armature_DropCube_clip, 0.0f, 0);
dropper->flags &= ~BoxDropperFlagsCubeRequested;
dropper->flags |= BoxDropperFlagsCubeIsActive;

View file

@ -3,7 +3,7 @@
#include "../math/transform.h"
#include "../sk64/skelatool_armature.h"
#include "../sk64/skelatool_animator.h"
#include "../sk64/skelatool_animator_v2.h"
#include "../levels/level_definition.h"
#include "../decor/decor_object.h"
@ -17,7 +17,7 @@ enum BoxDropperFlags {
struct BoxDropper {
struct Transform transform;
struct SKArmature armature;
struct SKAnimator animator;
struct SKAnimatorV2 animator;
struct DecorObject activeCube;
float reloadTimer;

View file

@ -8,6 +8,7 @@
#define TICK_UNDEFINED ~((u16)(0))
static struct SKAnimationDataPool gSKAnimationPool;
static unsigned gSegmentLocations[SK_SEGMENT_COUNT];
void skWaitForNextMessage();
@ -177,7 +178,7 @@ void skProcess(OSIoMesg* message) {
void skInitDataPool(OSPiHandle* handle) {
gSKAnimationPool.handle = handle;
osCreateMesgQueue(&gSKAnimationPool.mesgQueue, gSKAnimationPool.mesgBuffer, SK_POOL_QUEUE_SIZE);
zeroMemory(gSKAnimationPool.segmentLocations, sizeof(gSKAnimationPool.segmentLocations));
zeroMemory(gSegmentLocations, sizeof(gSegmentLocations));
skResetDataPool();
}
@ -203,12 +204,12 @@ int skHasPendingMessages() {
}
void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocation) {
gSKAnimationPool.segmentLocations[segmentNumber] = segmentLocation;
gSegmentLocations[segmentNumber] = segmentLocation;
}
u32 skTranslateSegment(unsigned address) {
unsigned segment = (address >> 24) & 0xF;
return (address & 0xFFFFFF) + gSKAnimationPool.segmentLocations[segment];
return (address & 0xFFFFFF) + gSegmentLocations[segment];
}
void skWaitForNextMessage() {

View file

@ -6,12 +6,6 @@
#include "math/transform.h"
#include "skelatool_clip.h"
struct SKU16Vector3 {
short x;
short y;
short z;
};
struct SKBoneState {
unsigned short positionTick;
unsigned short rotationTick;
@ -75,7 +69,6 @@ struct SKAnimationDataPool {
struct SKAnimator* animatorsForMessages[SK_POOL_QUEUE_SIZE];
int nextMessage;
struct SKRingMemory memoryPool;
unsigned segmentLocations[SK_SEGMENT_COUNT];
};
void skInitDataPool(OSPiHandle* handle);
@ -83,6 +76,7 @@ void skResetDataPool();
void skReadMessages();
int skHasPendingMessages();
void skSetSegmentLocation(unsigned segmentNumber, unsigned segmentLocatoin);
u32 skTranslateSegment(unsigned address);
void skAnimatorInit(struct SKAnimator* animator, unsigned boneCount, SKAnimationEventCallback animtionCallback, void* callbackData);
void skAnimatorCleanup(struct SKAnimator* animator);

View file

@ -0,0 +1,188 @@
#include "skelatool_animator_v2.h"
#include "../util/memory.h"
#include "../math/mathf.h"
#include "skelatool_animator.h"
#define MAX_ANIMATION_QUEUE_ENTRIES 20
OSPiHandle* gAnimationPiHandle;
OSMesgQueue gAnimationQueue;
OSMesg gAnimationQueueEntries[MAX_ANIMATION_QUEUE_ENTRIES];
OSIoMesg gAnimationIOMesg[MAX_ANIMATION_QUEUE_ENTRIES];
int gAnimationNextMessage;
void skAnimatorCopy(u32 romAddress, void* target, u32 size) {
if (!gAnimationPiHandle) {
gAnimationPiHandle = osCartRomInit();
osCreateMesgQueue(&gAnimationQueue, gAnimationQueueEntries, MAX_ANIMATION_QUEUE_ENTRIES);
}
// request new chunk
OSIoMesg* ioMesg = &gAnimationIOMesg[gAnimationNextMessage];
gAnimationNextMessage = (gAnimationNextMessage + 1) % MAX_ANIMATION_QUEUE_ENTRIES;
ioMesg->hdr.pri = OS_MESG_PRI_NORMAL;
ioMesg->hdr.retQueue = &gAnimationQueue;
ioMesg->dramAddr = target;
ioMesg->devAddr = skTranslateSegment(romAddress);
ioMesg->size = size;
osEPiStartDma(gAnimationPiHandle, ioMesg, OS_READ);
}
void skAnimatorV2Init(struct SKAnimatorV2* animator, int nBones) {
animator->currentClip = NULL;
animator->currentTime = 0.0f;
animator->blendLerp = 0.0f;
animator->boneState[0] = malloc(sizeof(struct SKAnimationBoneFrame) * nBones);
animator->boneState[1] = malloc(sizeof(struct SKAnimationBoneFrame) * nBones);
animator->boneStateFrames[0] = -1;
animator->boneStateFrames[1] = -1;
animator->latestBoneState = -1;
animator->nBones = nBones;
}
void skAnimatorV2Cleanup(struct SKAnimatorV2* animator) {
free(animator->boneState[0]);
free(animator->boneState[1]);
animator->boneState[0] = NULL;
animator->boneState[1] = NULL;
}
void skAnimatorV2RequestNext(struct SKAnimatorV2* animator) {
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->boneStateFrames[animator->latestBoneState] == nextFrame) {
return;
}
animator->boneStateFrames[animator->latestBoneState] = 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);
}
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;
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;
}
}
void skAnimatorV2ReadTransform(struct SKAnimatorV2* 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]);
}
}
void skAnimatorV2Update(struct SKAnimatorV2* animator, struct Transform* transforms, 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)) {
animator->blendLerp = 1.0f;
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);
}
int existingFrame = animator->boneStateFrames[animator->latestBoneState];
animator->blendLerp = 1.0f - (currentFrame - currentFrameFractional);
// no need to request the next frame
if (existingFrame == (int)currentFrame) {
return;
}
animator->latestBoneState ^= 1;
if ((int)currentFrame > existingFrame + 1) {
animator->blendLerp = 1.0f;
}
skAnimatorV2RequestNext(animator);
}
void skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip* clip, float startTime, int flags) {
animator->currentClip = clip;
if (!clip) {
return;
}
if (animator->latestBoneState != -1) {
animator->latestBoneState ^= 1;
}
animator->boneStateFrames[0] = -1;
animator->boneStateFrames[1] = -1;
animator->blendLerp = 1.0f;
animator->currentTime = startTime;
animator->flags = flags;
skAnimatorV2RequestNext(animator);
}

View file

@ -0,0 +1,28 @@
#ifndef _SKELATOOL_ANIMATOR_H
#define _SKELATOOL_ANIMATOR_H
#include "skelatool_clip.h"
#include "../math/transform.h"
enum SKAnimatorV2Flags {
SKAnimatorV2FlagsLoop = (1 << 0),
};
struct SKAnimatorV2 {
struct SKAnimationClip* currentClip;
float currentTime;
float blendLerp;
struct SKAnimationBoneFrame* boneState[2];
short boneStateFrames[2];
short latestBoneState;
short flags;
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 skAnimatorV2RunClip(struct SKAnimatorV2* animator, struct SKAnimationClip* clip, float startTime, int flags);
#endif

View file

@ -4,6 +4,12 @@
#define SK_ANIMATION_EVENT_END 0xFFFF
#define SK_ANIMATION_EVENT_START 0xFFFE
struct SKU16Vector3 {
short x;
short y;
short z;
};
enum SKBoneAttrMask {
SKBoneAttrMaskPosition = (1 << 0),
SKBoneAttrMaskRotation = (1 << 1),
@ -48,4 +54,16 @@ struct SKAnimationHeader {
struct SKAnimationEvent* animationEvents;
};
struct SKAnimationBoneFrame {
struct SKU16Vector3 position;
struct SKU16Vector3 rotation;
};
struct SKAnimationClip {
short nFrames;
short nBones;
struct SKAnimationBoneFrame* frames;
float fps;
};
#endif