#include "bones/BoneAnimationStateController.h" #include #include #include #include "3dmath/Quaternion.h" #include "bones/BoneAnimationList.h" #include "bones/BoneAnimationSequence.h" #include "bones/BoneAnimationState.h" #include "bones/Skeleton.h" BoneAnimationStateController * BoneAnimationStateController_create(BoneAnimationState * animationState, BoneAnimationList * animationList) { BoneAnimationStateController * self; self = malloc(sizeof(BoneAnimationStateController)); BoneAnimationStateController_init(self, animationState, animationList); return self; } void BoneAnimationStateController_init(BoneAnimationStateController * self, BoneAnimationState * animationState, BoneAnimationList * animationList) { self->animationState = animationState; self->animationList = animationList; self->sequenceName = NULL; self->sequencePlaybackTime = 0.0f; self->lastAnimationState = NULL; self->sequenceTransitionDuration = 1.0f; self->dispose = BoneAnimationStateController_dispose; self->update = BoneAnimationStateController_update; self->setSequence = BoneAnimationStateController_setSequence; } void BoneAnimationStateController_dispose(void * selfPtr) { BoneAnimationStateController * self = selfPtr; if (self->lastAnimationState != NULL) { self->lastAnimationState->dispose(self->lastAnimationState); } free(self); } void BoneAnimationStateController_update(void * selfPtr, double timestep) { BoneAnimationStateController * self = selfPtr; BoneAnimationSequence * animationSequence; unsigned int boneIndex, boneTransformIndex; unsigned int keyframeIndex; struct BoneAnimationSequence_keyframe * keyframeLeft, * keyframeRight; Quaternion orientationLeft, orientationRight; Vector3 offsetLeft, offsetRight; float normalizedKeyframeTime; animationSequence = self->animationList->getSequence(self->animationList, self->sequenceName); if (animationSequence == NULL || animationSequence->numberOfKeyframes == 0) { return; } self->sequencePlaybackTime += timestep; if (self->lastAnimationState != NULL && self->sequencePlaybackTime > self->sequenceTransitionDuration) { self->lastAnimationState->dispose(self->lastAnimationState); self->lastAnimationState = NULL; self->sequencePlaybackTime = 0.0f; } if (self->lastAnimationState != NULL) { keyframeRight = &animationSequence->keyframes[0]; normalizedKeyframeTime = self->sequencePlaybackTime / self->sequenceTransitionDuration; for (boneIndex = 0; boneIndex < self->animationState->skeleton->numberOfBones; boneIndex++) { orientationLeft = self->lastAnimationState->boneOrientations[boneIndex]; orientationRight = Quaternion_identity(); offsetLeft = self->lastAnimationState->boneOffsets[boneIndex]; offsetRight = Vector3_zero(); for (boneTransformIndex = 0; boneTransformIndex < keyframeRight->numberOfBones; boneTransformIndex++) { if (keyframeRight->boneTransforms[boneTransformIndex].boneID == self->animationState->skeleton->bones[boneIndex].boneID) { orientationRight = keyframeRight->boneTransforms[boneTransformIndex].orientation; offsetRight = keyframeRight->boneTransforms[boneTransformIndex].offset; } } self->animationState->boneOrientations[boneIndex] = Quaternion_slerp(orientationLeft, orientationRight, normalizedKeyframeTime); self->animationState->boneOffsets[boneIndex] = Vector3_interpolate(offsetLeft, offsetRight, normalizedKeyframeTime); } } else { self->sequencePlaybackTime = fmod(self->sequencePlaybackTime, animationSequence->getDuration(animationSequence)); keyframeIndex = animationSequence->keyframeIndexForTime(animationSequence, self->sequencePlaybackTime); keyframeLeft = &animationSequence->keyframes[keyframeIndex]; keyframeRight = &animationSequence->keyframes[(keyframeIndex + 1) % animationSequence->numberOfKeyframes]; normalizedKeyframeTime = (self->sequencePlaybackTime - animationSequence->timeForKeyframeIndex(animationSequence, keyframeIndex)) / keyframeLeft->duration; for (boneIndex = 0; boneIndex < self->animationState->skeleton->numberOfBones; boneIndex++) { orientationLeft = orientationRight = Quaternion_identity(); offsetLeft = offsetRight = Vector3_zero(); for (boneTransformIndex = 0; boneTransformIndex < keyframeLeft->numberOfBones; boneTransformIndex++) { if (keyframeLeft->boneTransforms[boneTransformIndex].boneID == self->animationState->skeleton->bones[boneIndex].boneID) { orientationLeft = keyframeLeft->boneTransforms[boneTransformIndex].orientation; offsetLeft = keyframeLeft->boneTransforms[boneTransformIndex].offset; } } for (boneTransformIndex = 0; boneTransformIndex < keyframeRight->numberOfBones; boneTransformIndex++) { if (keyframeRight->boneTransforms[boneTransformIndex].boneID == self->animationState->skeleton->bones[boneIndex].boneID) { orientationRight = keyframeRight->boneTransforms[boneTransformIndex].orientation; offsetRight = keyframeRight->boneTransforms[boneTransformIndex].offset; } } self->animationState->boneOrientations[boneIndex] = Quaternion_slerp(orientationLeft, orientationRight, normalizedKeyframeTime); self->animationState->boneOffsets[boneIndex] = Vector3_interpolate(offsetLeft, offsetRight, normalizedKeyframeTime); } } self->animationState->updateBoneMatrices(self->animationState); } void BoneAnimationStateController_setSequence(void * selfPtr, Atom sequenceName) { BoneAnimationStateController * self = selfPtr; BoneAnimationSequence * animationSequence; if (sequenceName != self->sequenceName) { self->lastAnimationState = self->animationState->createCopy(self->animationState); animationSequence = self->animationList->getSequence(self->animationList, self->sequenceName); if (animationSequence != NULL) { struct BoneAnimationSequence_keyframe * keyframe; keyframe = &animationSequence->keyframes[animationSequence->keyframeIndexForTime(animationSequence, self->sequencePlaybackTime)]; self->sequenceTransitionDuration = keyframe->duration; animationSequence = self->animationList->getSequence(self->animationList, sequenceName); if (animationSequence != NULL) { keyframe = &animationSequence->keyframes[0]; if (keyframe->duration < self->sequenceTransitionDuration) { self->sequenceTransitionDuration = keyframe->duration; } } } self->sequenceName = sequenceName; self->sequencePlaybackTime = 0.0f; } }