// Get the Vector3 value for the given time public Vector3 GetValue(TimeSpan time) { // Check sizes if (m_nextFreeIndex == 0) { throw new Exception("Attempted to get value from TinyAnim but no keyframes had been added to the array yet!"); } else if (m_nextFreeIndex == 1) { return(m_keyframes[0].vec); } else if (m_nextFreeIndex > 1) { int index = Array.BinarySearch(m_keyframes, 0, m_nextFreeIndex, new TinyKeyframe(new Vector3(0, 0, 0), time)); if (index < 0) { // Not an exact match so fetch the closest index using bitwise complement index = ~index; if (index == 0) { // Time < first keyframe time - Return first keyframe's value return(m_keyframes[0].vec); } else if (index >= m_nextFreeIndex) { // Time > last keyframe time - Return last keyframe's value return(m_keyframes[m_nextFreeIndex - 1].vec); } else { // Index will be the end boundary keyframe TinyKeyframe startBound = m_keyframes[index - 1]; TinyKeyframe endBound = m_keyframes[index]; if (startBound != null && endBound != null) { // We have found the correct two keyframes that we need to interpolate between bool smooth = startBound.smooth && endBound.smooth; return(TinyLerp(startBound, endBound, time, smooth)); } } } else { // Exact match - return that keyframe's value return(m_keyframes[index].vec); } } // This should never happen but it is here to catch anomolies and satisfy the compiler throw new Exception("Attempted to get value from TinyAnim but no Vector was returned!"); }
// Interpolate between two TinyKeyframes private Vector3 TinyLerp(TinyKeyframe start, TinyKeyframe end, TimeSpan time, bool smoothStep) { // Calculate blend value depending on what is chosen (percentage or smooth step) float percent = 0f; if (smoothStep) { percent = SmoothStep(time, start.time, end.time); } else { percent = Percent(time, start.time, end.time); } return(new Vector3(start.vec.x + (percent * (end.vec.x - start.vec.x)), start.vec.y + (percent * (end.vec.y - start.vec.y)), start.vec.z + (percent * (end.vec.z - start.vec.z)))); }
// Comparison for Array.Sort public int CompareTo(object other) { // Send all null keyframes to the back of the array if (other == null) { return(-1); } // Sort actual keyframes TinyKeyframe otherKf = other as TinyKeyframe; if (otherKf != null) { return(time.CompareTo(otherKf.time)); } else { throw new ArgumentException("Comparison object is not a TinyKeyframe!"); } }
// Add (or update) a keyframe to the array. This also sorts the array so that the keyframes remain in ascending time order. // If a keyframe already exists at the given time, update that keyframe instead. public void AddKeyframe(TinyKeyframe kf) { // Ensure keyframe array is not full if (m_nextFreeIndex < m_maxKeyframes) { // Does a keyframe already exists at the given time? TinyKeyframe existing = Array.Find(m_keyframes, o => o != null ? o.time.Equals(kf.time) : false); if (existing != null) { // Update the existing keyframe existing.vec = kf.vec; } else { // Add new keyframe m_keyframes[m_nextFreeIndex] = kf; m_nextFreeIndex++; } } else { throw new OverflowException("The keyframe array is full."); } }