#region File Description //----------------------------------------------------------------------------- // KeyFrameSequence.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion #region Using Statements using System; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using RobotGameData.Helper; #endregion namespace RobotGameData.GameObject { #region enum public enum AnimPlayMode { /// /// plays once. /// Once = 0, /// /// keeps repeating. /// Repeat, } #endregion #region key frame data /// /// key data of animation for one frame /// public struct KeyFrame { public bool HasTranslation; public bool HasRotation; public bool HasScale; public Vector3 Translation; public Quaternion Rotation; public Vector3 Scale; } #endregion /// /// this is the basic unit of animation which has single bone key frame. /// It calculates by interpolating two key frames. /// [Serializable] public class KeyFrameSequence { #region Fields public String BoneName = String.Empty; /// /// Key frame count /// public int KeyCount = 0; /// /// Animation playing time /// public float Duration = 0.0f; /// /// Gap of time for the each frame. /// public float KeyInterval = 0.0f; public bool HasTranslation = false; public bool HasRotation = false; public bool HasScale = false; public bool HasTime = false; /// /// If this flag is set to true, the first key frame’s translation value will be /// fixed during all key frame of the animation. /// public bool FixedTranslation = false; /// /// If this flag is set to true, the first key frame’s rotaion value will be /// fixed during all key frame of the animation. /// public bool FixedRotation = false; /// /// If this flag is set to true, the first key frame’s scale value will be /// fixed during all key frame of the animation. /// public bool FixedScale = false; /// /// The translation value in the list. /// public List Translation = null; /// /// The rotation value in the list. /// public List Rotation = null; /// /// The scale value in the list. /// public List Scale = null; /// /// The time value in the list. /// public List Time = null; #endregion /// /// Gets a key frame matrix by index /// /// key frame index /// public Matrix GetMatrix(int keyIndex) { Matrix mat = Matrix.Identity; if (HasRotation ) // Calculates rotation matrix using quaternion { if (FixedRotation ) mat = Matrix.CreateFromQuaternion(Rotation[0]); else mat = Matrix.CreateFromQuaternion(Rotation[keyIndex]); } if (HasTranslation ) // Calculates position { if (FixedRotation ) mat.Translation = Translation[0]; else mat.Translation = Translation[keyIndex]; } if (HasScale ) // Calculates scale { if (FixedRotation ) mat = mat * Matrix.CreateScale(Scale[0]); else mat = mat * Matrix.CreateScale(Scale[keyIndex]); } return mat; } /// /// calculates by interpolating two key frames. /// /// key frame index 1 /// key frame index 2 /// interpolate time (0.0 to 1.0) /// Interpolated key frame matrix public Matrix GetInterpolateMatrix(int keyIndex1, int keyIndex2, float t) { // Calculate KeyFrame interpolated matrix Matrix mat = Matrix.Identity; // Interpolate rotation value by Slerp if (HasRotation ) { Quaternion q = Quaternion.Identity; if (FixedRotation ) q = Rotation[0]; else q = Quaternion.Slerp(Rotation[keyIndex1], Rotation[keyIndex2], t); // Apply interpolate rotation to matrix mat = Matrix.CreateFromQuaternion(q); } // Interpolate translation value by Lerp if (HasTranslation ) { // Apply interpolate translation to matrix if (FixedTranslation ) mat.Translation = Translation[0]; else mat.Translation = Vector3.Lerp(Translation[keyIndex1], Translation[keyIndex2], t); } // Interpolate scale value by Lerp if (HasScale ) { Vector3 v = Vector3.Zero; if (FixedScale ) v = Scale[0]; else v = Vector3.Lerp(Scale[keyIndex1], Scale[keyIndex2], t); // Apply interpolate scale to matrix mat = mat * Matrix.CreateScale(v); } return mat; } /// /// calculates by interpolating two key frames. /// /// key frame index 1 /// key frame index 2 /// interpolate time (0.0 to 1.0) /// Interpolated key frame public KeyFrame GetInterpolateKeyFrame(int keyIndex1, int keyIndex2, float t) { // Calculate KeyFrame interpolated matrix KeyFrame keyFrame; // Interpolate rotation value by Slerp if (HasRotation ) { if (FixedRotation ) keyFrame.Rotation = Rotation[0]; else keyFrame.Rotation = Quaternion.Slerp( Rotation[keyIndex1], Rotation[keyIndex2], t); } else { keyFrame.Rotation = Quaternion.Identity; } keyFrame.HasRotation = HasRotation; // Interpolate translation value by Lerp if (HasTranslation ) { if (FixedTranslation ) keyFrame.Translation = Translation[0]; else keyFrame.Translation = Vector3.Lerp( Translation[keyIndex1], Translation[keyIndex2], t); } else { keyFrame.Translation = Vector3.Zero; } keyFrame.HasTranslation = HasTranslation; // Interpolate scale value by Lerp if (HasScale ) { if (FixedScale ) keyFrame.Scale = Scale[0]; else keyFrame.Scale = Vector3.Lerp(Scale[keyIndex1], Scale[keyIndex2], t); } else { keyFrame.Scale = Vector3.One; } keyFrame.HasScale = HasScale; return keyFrame; } public Matrix GetInterpolateMatrix(float localTime, AnimPlayMode mode) { int index1 = 0; // first key frame index int index2 = 0; // second key frame index float interpolateTime = 0.0f; CalculateKeyFrameIndex(localTime, mode, out index1, out index2, out interpolateTime); // Calcurate interpolate key frame matrix between KeyFrame1 and KeyFrame2 return GetInterpolateMatrix(index1, index2, interpolateTime); } public KeyFrame GetInterpolateKeyFrame(float localTime, AnimPlayMode mode) { int index1 = 0; // first key frame index int index2 = 0; // second key frame index float interpolateTime = 0.0f; CalculateKeyFrameIndex(localTime, mode, out index1, out index2, out interpolateTime); // Calcurate interpolate key frame matrix between KeyFrame1 and KeyFrame2 return GetInterpolateKeyFrame(index1, index2, interpolateTime); } /// /// returns two key frame index, which is included in the specified time. /// public void CalculateKeyFrameIndex(float localTime, AnimPlayMode mode, out int index1, out int index2, out float interpolateTime) { index1 = 0; // first key frame index index2 = 0; // second key frame index interpolateTime = 0.0f; // Calculate first key frame index if (HasTime ) index1 = GetKeyFrameIndex(localTime); else index1 = (int)(localTime / KeyInterval); // Calculate second key frame index by play mode switch (mode) { case AnimPlayMode.Once: // Just play once { // if index1 is last index index2 = (index1 >= KeyCount - 1 ? index1 : index1 + 1); } break; case AnimPlayMode.Repeat: // Play looping { // if index1 is last index, index2 must be begin (looping) index2 = (index1 >= KeyCount - 1 ? 0 : index1 + 1); } break; default: throw new NotSupportedException("Not supported play mode"); } if (index1 >= KeyCount - 1) { index1 = index2 = KeyCount - 1; interpolateTime = 1.0f; } else { if (HasTime ) { interpolateTime = (localTime - Time[index1]) / (Time[index2] - Time[index1]); } else { interpolateTime = HelperMath.CalculateModulo(localTime, KeyInterval) / KeyInterval; } } } /// /// returns two key frame index, which is included in the specified time. /// public int GetKeyFrameIndex(float localTime) { // Calculate index between two key frame on this time int startIndex, endIndex, middleIndex; startIndex = 0; endIndex = KeyCount - 1; if (localTime >= Time[endIndex]) { return endIndex; } do { middleIndex = (startIndex + endIndex) / 2; if ((endIndex - startIndex) <= 1) { break; } else if (Time[middleIndex] < localTime) { startIndex = middleIndex; } else if (Time[middleIndex] > localTime) { endIndex = middleIndex; } else { startIndex = middleIndex; break; } } while ((endIndex - startIndex) > 1); return startIndex; } } }