+VG_STATIC void keyframe_copy_pose( mdl_keyframe *kfa, mdl_keyframe *kfb,
+ int num )
+{
+ for( int i=0; i<num; i++ )
+ kfb[i] = kfa[i];
+}
+
+/*
+ * Lerp between two sets of keyframes and store in dest. Rotations use Nlerp.
+ */
+VG_STATIC void keyframe_lerp_pose( mdl_keyframe *kfa, mdl_keyframe *kfb,
+ float t, mdl_keyframe *kfd, int count )
+{
+ if( t <= 0.01f )
+ {
+ keyframe_copy_pose( kfa, kfd, count );
+ return;
+ }
+ else if( t >= 0.99f )
+ {
+ keyframe_copy_pose( kfb, kfd, count );
+ return;
+ }
+
+ for( int i=0; i<count; i++ )
+ {
+ v3_lerp( kfa[i].co, kfb[i].co, t, kfd[i].co );
+ q_nlerp( kfa[i].q, kfb[i].q, t, kfd[i].q );
+ v3_lerp( kfa[i].s, kfb[i].s, t, kfd[i].s );
+ }
+}
+
+VG_STATIC void skeleton_lerp_pose( struct skeleton *skele,
+ mdl_keyframe *kfa, mdl_keyframe *kfb, float t,
+ mdl_keyframe *kfd )
+{
+ keyframe_lerp_pose( kfa, kfb, t, kfd, skele->bone_count-1 );
+}
+
+VG_STATIC void skeleton_copy_pose( struct skeleton *skele,
+ mdl_keyframe *kfa, mdl_keyframe *kfd )
+{
+ keyframe_copy_pose( kfa, kfd, skele->bone_count-1 );
+}
+
+/*
+ * Sample animation between 2 closest frames using time value. Output is a
+ * keyframe buffer that is allocated with an appropriate size
+ */
+VG_STATIC void skeleton_sample_anim( struct skeleton *skele,
+ struct skeleton_anim *anim,
+ float time,
+ mdl_keyframe *output )