/* Copyright (c) 2018 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __ArmatureAnimation_H__ #define __ArmatureAnimation_H__ #ifdef __cplusplus extern "C" { #endif typedef struct ArmatureAnimation ArmatureAnimation; #define ArmatureAnimation_superclass StemObject #include "gamemath/ArmaturePose.h" #include "stemobject/StemObject.h" typedef uint32_t ArmatureAnimationMarkerID; #define ANIMATION_CURVE_SAMPLES_DEFAULT 8 // Bezier handles exist in a coordinate space where {0, 0} is the left keyframe, and {1, 1} is the right keyframe. // The input linear weight value is taken as the x coordinate, and the y value at that location is the output curved weight. // Curves that go outside the range of 0-1 on the x axis are clipped. Curves that have control points passing each other // will have their control points clipped to ensure that the curve cannot overlap itself on the time (x) axis. typedef struct ArmatureAnimationBoneKeyframe { ArmatureBoneID boneID; Vector3f offset; Vector2f incomingOffsetBezierHandle; Vector2f outgoingOffsetBezierHandle; Vector3f scale; Vector2f incomingScaleBezierHandle; Vector2f outgoingScaleBezierHandle; Quaternionf rotation; Vector2f incomingRotationBezierHandle; Vector2f outgoingRotationBezierHandle; } ArmatureAnimationBoneKeyframe; typedef struct ArmatureAnimationKeyframe { double interval; // Relative time until next keyframe unsigned int boneCount; ArmatureAnimationBoneKeyframe * bones; } ArmatureAnimationKeyframe; typedef struct ArmatureAnimationMarker { ArmatureAnimationMarkerID identifier; double time; // Absolute time from beginning of animation } ArmatureAnimationMarker; #define ArmatureAnimation_ivars \ StemObject_ivars \ \ bool loop; \ unsigned int keyframeCount; \ ArmatureAnimationKeyframe * keyframes; \ unsigned int markerCount; \ ArmatureAnimationMarker * markers; #define ArmatureAnimation_vtable(self_type) \ StemObject_vtable(self_type) stemobject_declare(ArmatureAnimation) // keyframes and markers are copied ArmatureAnimation * ArmatureAnimation_create(bool loop, unsigned int keyframeCount, ArmatureAnimationKeyframe * keyframes, unsigned int markerCount, ArmatureAnimationMarker * markers); bool ArmatureAnimation_init(ArmatureAnimation * self, bool loop, unsigned int keyframeCount, ArmatureAnimationKeyframe * keyframes, unsigned int markerCount, ArmatureAnimationMarker * markers); void ArmatureAnimation_dispose(ArmatureAnimation * self); // Returns the total time it takes to complete one loop of animation. The sum of all keyframe intervals. double ArmatureAnimation_getLength(ArmatureAnimation * self); // Returns the most recent marker at the specified time, or NULL if no markers exist. If loop is true, search will wrap around // in both directions. ArmatureAnimationMarker * ArmatureAnimation_getMarkerAtTime(ArmatureAnimation * self, double time); // Computes a pose at the specified time and writes the offset, scale, and rotation of each bone to pose. // Poses are applied additively. You should call ArmaturePose_resetAllPoseBones() before calling this function to start from the identity transformation. // This function does not call ArmaturePose_computePoseBoneTransforms(). The caller is responsible for calling it before rendering. // weight specifies the portion of this animation to apply to pose, where 1.0 applies it completely, and 0.0 doesn't apply at all. // curveSamples defines the sampling resolution of bezier curves. If unsure, pass ANIMATION_CURVE_SAMPLES_DEFAULT. void ArmatureAnimation_applyPoseAtTime(ArmatureAnimation * self, ArmaturePose * pose, double animationTime, float weight, unsigned int curveSamples); #ifdef __cplusplus } #endif #endif