diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index 7e077742a..f2c0f84d9 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -30,11 +30,10 @@ using System; using System.Collections.Generic; -using System.Text; namespace Spine { public class AnimationState { - private static Animation EmptyAnimation = new Animation("", new ExposedList(), 0); + static readonly Animation EmptyAnimation = new Animation("", new ExposedList(), 0); private AnimationStateData data; private readonly ExposedList tracks = new ExposedList(); @@ -44,6 +43,8 @@ namespace Spine { private bool animationsChanged; private float timeScale = 1; + Pool trackEntryPool = new Pool(); + public AnimationStateData Data { get { return data; } } /// A list of tracks that have animations, which may contain nulls. public ExposedList Tracks { get { return tracks; } } @@ -58,7 +59,7 @@ namespace Spine { public AnimationState (AnimationStateData data) { if (data == null) throw new ArgumentNullException("data", "data cannot be null."); this.data = data; - this.queue = new EventQueue(this, HandleAnimationsChanged); + this.queue = new EventQueue(this, HandleAnimationsChanged, trackEntryPool); } void HandleAnimationsChanged () { @@ -526,32 +527,32 @@ namespace Spine { /// May be null. private TrackEntry NewTrackEntry (int trackIndex, Animation animation, bool loop, TrackEntry last) { - return new TrackEntry { - trackIndex = trackIndex, - animation = animation, - loop = loop, + TrackEntry entry = trackEntryPool.Obtain(); // Pooling + entry.trackIndex = trackIndex; + entry.animation = animation; + entry.loop = loop; - eventThreshold = 0, - attachmentThreshold = 0, - drawOrderThreshold = 0, + entry.eventThreshold = 0; + entry.attachmentThreshold = 0; + entry.drawOrderThreshold = 0; - animationStart = 0, - animationEnd = animation.duration, - animationLast = -1, - nextAnimationLast = -1, + entry.animationStart = 0; + entry.animationEnd = animation.Duration; + entry.animationLast = -1; + entry.nextAnimationLast = -1; - delay = 0, - trackTime = 0, - trackLast = -1, - nextTrackLast = -1, - trackEnd = loop ? int.MaxValue : animation.duration, - timeScale = 1, + entry.delay = 0; + entry.trackTime = 0; + entry.trackLast = -1; + entry.nextTrackLast = -1; + entry.trackEnd = float.MaxValue; // loop ? float.MaxValue : animation.Duration; + entry.timeScale = 1; - alpha = 1, - mixAlpha = 1, - mixTime = 0, - mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation), - }; + entry.alpha = 1; + entry.mixAlpha = 1; + entry.mixTime = 0; + entry.mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation); + return entry; } private void DisposeNext (TrackEntry entry) { @@ -627,7 +628,7 @@ namespace Spine { } override public String ToString () { - var buffer = new StringBuilder(); + var buffer = new System.Text.StringBuilder(); for (int i = 0, n = tracks.Count; i < n; i++) { TrackEntry entry = tracks.Items[i]; if (entry == null) continue; @@ -646,7 +647,7 @@ namespace Spine { } /// State for the playback of an animation. - public class TrackEntry { + public class TrackEntry : Pool.IPoolable { internal Animation animation; internal TrackEntry next, mixingFrom; @@ -657,9 +658,25 @@ namespace Spine { internal float animationStart, animationEnd, animationLast, nextAnimationLast; internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f; internal float alpha, mixTime, mixDuration, mixAlpha; - internal readonly ExposedList timelinesFirst = new ExposedList(), timelinesLast = new ExposedList(); + internal readonly ExposedList timelinesFirst = new ExposedList(); internal readonly ExposedList timelinesRotation = new ExposedList(); + // IPoolable.Reset() + public void Reset () { + next = null; + mixingFrom = null; + animation = null; + timelinesFirst.Clear(); + timelinesRotation.Clear(); + + Start = null; + Interrupt = null; + End = null; + Dispose = null; + Complete = null; + Event = null; + } + /// The index of the track where this entry is either current or queued. public int TrackIndex { get { return trackIndex; } } @@ -824,11 +841,13 @@ namespace Spine { public bool drainDisabled; private readonly AnimationState state; + private readonly Pool trackEntryPool; public event Action AnimationsChanged; - public EventQueue (AnimationState state, Action HandleAnimationsChanged) { + public EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool trackEntryPool) { this.state = state; this.AnimationsChanged += HandleAnimationsChanged; + this.trackEntryPool = trackEntryPool; } struct EventQueueEntry { @@ -901,6 +920,7 @@ namespace Spine { case EventType.Dispose: trackEntry.OnDispose(); state.OnDispose(trackEntry); + trackEntryPool.Free(trackEntry); // Pooling break; case EventType.Complete: trackEntry.OnComplete(); @@ -921,4 +941,57 @@ namespace Spine { eventQueueEntries.Clear(); } } + + public class Pool where T : class, new() { + public readonly int max; + readonly Stack freeObjects; + + public int Count { get { return freeObjects.Count; } } + public int Peak { get; private set; } + + public Pool (int initialCapacity = 16, int max = int.MaxValue) { + freeObjects = new Stack(initialCapacity); + this.max = max; + } + + public T Obtain () { + return freeObjects.Count == 0 ? new T() : freeObjects.Pop(); + } + + public void Free (T obj) { + if (obj == null) throw new ArgumentNullException("obj", "obj cannot be null"); + if (freeObjects.Count < max) { + freeObjects.Push(obj); + Peak = Math.Max(Peak, freeObjects.Count); + } + Reset(obj); + } + +// protected void FreeAll (List objects) { +// if (objects == null) throw new ArgumentNullException("objects", "objects cannot be null."); +// var freeObjects = this.freeObjects; +// int max = this.max; +// for (int i = 0; i < objects.Count; i++) { +// T obj = objects[i]; +// if (obj == null) continue; +// if (freeObjects.Count < max) freeObjects.Push(obj); +// Reset(obj); +// } +// Peak = Math.Max(Peak, freeObjects.Count); +// } + + public void Clear () { + freeObjects.Clear(); + } + + protected void Reset (T obj) { + var poolable = obj as IPoolable; + if (poolable != null) poolable.Reset(); + } + + public interface IPoolable { + void Reset (); + } + } + }