[csharp] AnimationState TrackEntry pooling.

This commit is contained in:
John 2016-12-02 18:48:39 +08:00 committed by GitHub
parent 932467e3ac
commit 3884422543

View File

@ -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,
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 {
}
/// <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 ();
}
}
}