#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;
}
}
}