// MonoGame - Copyright (C) The MonoGame Team // This file is subject to the terms and conditions defined in // file 'LICENSE.txt', which is part of this source code package. using System; using System.Collections; using System.Collections.Generic; namespace Microsoft.Xna.Framework.Content.Pipeline.Graphics { /// /// Provides methods and properties for maintaining an animation channel. An animation channel is a collection of keyframes describing the movement of a single bone or rigid object. /// public sealed class AnimationChannel : ICollection, IEnumerable, IEnumerable { List keyframes; /// /// Gets the number of keyframes in the collection. /// public int Count { get { return keyframes.Count; } } /// /// Gets the keyframe at the specified index position. /// public AnimationKeyframe this[int index] { get { return keyframes[index]; } } /// /// Returns a value indicating whether the object is read-only. /// bool ICollection.IsReadOnly { get { return false; } } /// /// Initializes a new instance of AnimationChannel. /// public AnimationChannel() { keyframes = new List(); } /// /// To satisfy ICollection /// /// void ICollection.Add(AnimationKeyframe item) { keyframes.Add(item); } /// /// Adds a new keyframe to the collection, automatically sorting the contents according to keyframe times. /// /// Keyframe to be added to the channel. /// Index of the new keyframe. public int Add(AnimationKeyframe item) { if (item == null) throw new ArgumentNullException("item"); // Find the correct place at which to insert it, so we can know the index to return. // The alternative is Add, Sort then return IndexOf, which would be horribly inefficient // and the order returned by Sort would change each time for keyframes with the same time. // BinarySearch returns the index of the first item found with the same time, or the bitwise // complement of the next largest item found. int index = keyframes.BinarySearch(item); if (index >= 0) { // If a match is found, we do not know if it is at the start, middle or end of a range of // keyframes with the same time value. So look for the end of the range and insert there // so we have deterministic behaviour. while (index < keyframes.Count) { if (item.CompareTo(keyframes[index]) != 0) break; ++index; } } else { // If BinarySearch returns a negative value, it is the bitwise complement of the next largest // item in the list. So we just do a bitwise complement and insert at that index. index = ~index; } keyframes.Insert(index, item); return index; } /// /// Removes all keyframes from the collection. /// public void Clear() { keyframes.Clear(); } /// /// Searches the collection for the specified keyframe. /// /// Keyframe being searched for. /// true if the keyframe exists; false otherwise. public bool Contains(AnimationKeyframe item) { return keyframes.Contains(item); } /// /// To satisfy ICollection /// /// /// void ICollection.CopyTo(AnimationKeyframe[] array, int arrayIndex) { keyframes.CopyTo(array, arrayIndex); } /// /// Determines the index for the specified keyframe. /// /// Identity of a keyframe. /// Index of the specified keyframe. public int IndexOf(AnimationKeyframe item) { return keyframes.IndexOf(item); } /// /// Removes the specified keyframe from the collection. /// /// Keyframe being removed. /// true if the keyframe was removed; false otherwise. public bool Remove(AnimationKeyframe item) { return keyframes.Remove(item); } /// /// Removes the keyframe at the specified index position. /// /// Index of the keyframe being removed. public void RemoveAt(int index) { keyframes.RemoveAt(index); } /// /// Returns an enumerator that iterates through the keyframes. /// /// Enumerator for the keyframe collection. public IEnumerator GetEnumerator() { return keyframes.GetEnumerator(); } /// /// To satisfy ICollection /// /// IEnumerator IEnumerable.GetEnumerator() { return keyframes.GetEnumerator(); } } }