mirror of
https://github.com/mwpenny/portal64-still-alive.git
synced 2024-10-19 22:27:36 -04:00
Refactor animation system
This commit is contained in:
parent
9f61fde4a9
commit
95ab27db2f
2
Makefile
2
Makefile
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct CommandLineArguments {
|
|||
std::string mForcePallete;
|
||||
float mFixedPointScale;
|
||||
float mModelScale;
|
||||
float mFPS;
|
||||
bool mExportAnimation;
|
||||
bool mExportGeometry;
|
||||
bool mBonesAsVertexGroups;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
188
src/sk64/skelatool_animator_v2.c
Normal file
188
src/sk64/skelatool_animator_v2.c
Normal 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);
|
||||
}
|
28
src/sk64/skelatool_animator_v2.h
Normal file
28
src/sk64/skelatool_animator_v2.h
Normal 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
|
|
@ -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
|
Loading…
Reference in a new issue