浏览代码

[csharp] AnimationState TrackEntry pooling.

John 8 年之前
父节点
当前提交
3884422543
共有 1 个文件被更改,包括 106 次插入33 次删除
  1. 106 33
      spine-csharp/src/AnimationState.cs

+ 106 - 33
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("<empty>", new ExposedList<Timeline>(), 0);
+		static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
 
 		private AnimationStateData data;
 		private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
@@ -44,6 +43,8 @@ namespace Spine {
 		private bool animationsChanged;
 		private float timeScale = 1;
 
+		Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
+
 		public AnimationStateData Data { get { return data; } }
 		/// <summary>A list of tracks that have animations, which may contain nulls.</summary>
 		public ExposedList<TrackEntry> 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 {
 
 		/// <param name="last">May be null.</param>
 		private TrackEntry NewTrackEntry (int trackIndex, Animation animation, bool loop, TrackEntry last) {
-			return new TrackEntry {
-				trackIndex = trackIndex,
-				animation = animation,
-				loop = loop,
-
-				eventThreshold = 0,
-				attachmentThreshold = 0,
-				drawOrderThreshold = 0,
-
-				animationStart = 0,
-				animationEnd = animation.duration,
-				animationLast = -1,
-				nextAnimationLast = -1,
-
-				delay = 0,
-				trackTime = 0,
-				trackLast = -1,
-				nextTrackLast = -1,
-				trackEnd = loop ? int.MaxValue : animation.duration,
-				timeScale = 1,
-
-				alpha = 1,
-				mixAlpha = 1,
-				mixTime = 0,
-				mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation),
-			};
+			TrackEntry entry = trackEntryPool.Obtain(); // Pooling
+			entry.trackIndex = trackIndex;
+			entry.animation = animation;
+			entry.loop = loop;
+
+			entry.eventThreshold = 0;
+			entry.attachmentThreshold = 0;
+			entry.drawOrderThreshold = 0;
+
+			entry.animationStart = 0;
+			entry.animationEnd = animation.Duration;
+			entry.animationLast = -1;
+			entry.nextAnimationLast = -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;
+
+			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 {
 	}
 
 	/// <summary>State for the playback of an animation.</summary>
-	public class TrackEntry {
+	public class TrackEntry : Pool<TrackEntry>.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<bool> timelinesFirst = new ExposedList<bool>(), timelinesLast = new ExposedList<bool>();
+		internal readonly ExposedList<bool> timelinesFirst = new ExposedList<bool>();
 		internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>();
 
+		// 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;
+		}
+
 		/// <summary>The index of the track where this entry is either current or queued.</summary>
 		public int TrackIndex { get { return trackIndex; } }
 
@@ -824,11 +841,13 @@ namespace Spine {
 		public bool drainDisabled;
 
 		private readonly AnimationState state;
+		private readonly Pool<TrackEntry> trackEntryPool;
 		public event Action AnimationsChanged;
 
-		public EventQueue (AnimationState state, Action HandleAnimationsChanged) {
+		public EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool<TrackEntry> 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<T> where T : class, new() {
+		public readonly int max;
+		readonly Stack<T> 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<T>(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<T> 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 ();
+		}
+	}
+
 }