This commit is contained in:
Stephen Gowen 2017-11-28 19:30:27 -05:00
parent 1449af5864
commit d5c47a709a
3 changed files with 351 additions and 267 deletions

View File

@ -45,8 +45,8 @@ namespace Spine
class Animation class Animation
{ {
friend class RotateTimeline; friend class AnimationState;
friend class TranslateTimeline; friend class TrackEntry;
friend class AnimationStateData; friend class AnimationStateData;
friend class AttachmentTimeline; friend class AttachmentTimeline;
@ -58,6 +58,7 @@ namespace Spine
friend class PathConstraintMixTimeline; friend class PathConstraintMixTimeline;
friend class PathConstraintPositionTimeline; friend class PathConstraintPositionTimeline;
friend class PathConstraintSpacingTimeline; friend class PathConstraintSpacingTimeline;
friend class RotateTimeline;
friend class ScaleTimeline; friend class ScaleTimeline;
friend class ShearTimeline; friend class ShearTimeline;
friend class TransformConstraintTimeline; friend class TransformConstraintTimeline;

View File

@ -32,10 +32,27 @@
#define Spine_AnimationState_h #define Spine_AnimationState_h
#include <spine/Vector.h> #include <spine/Vector.h>
#include <spine/Pool.h>
namespace Spine namespace Spine
{ {
enum EventType
{
EventType_Start,
EventType_Interrupt,
EventType_End,
EventType_Complete,
EventType_Dispose,
EventType_Event
};
class AnimationState;
class TrackEntry;
class Animation; class Animation;
class Event;
typedef void (*OnAnimationEventFunc) (AnimationState* state, EventType type, TrackEntry* entry, Event* event);
/// State for the playback of an animation /// State for the playback of an animation
class TrackEntry class TrackEntry
@ -146,7 +163,7 @@ namespace Spine
void setDrawOrderThreshold(float inValue); void setDrawOrderThreshold(float inValue);
/// ///
/// The animation queued to start after this animation, or null. /// The animation queued to start after this animation, or NULL.
TrackEntry* getNext(); TrackEntry* getNext();
/// ///
@ -175,7 +192,7 @@ namespace Spine
void setMixDuration(float inValue); void setMixDuration(float inValue);
/// ///
/// The track entry for the previous animation when mixing from the previous animation to this animation, or null if no /// The track entry for the previous animation when mixing from the previous animation to this animation, or NULL if no
/// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a linked list. /// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a linked list.
TrackEntry* getMixingFrom(); TrackEntry* getMixingFrom();
@ -189,215 +206,94 @@ namespace Spine
/// TrackEntry chooses the short way the first time it is applied and remembers that direction. /// TrackEntry chooses the short way the first time it is applied and remembers that direction.
void resetRotationDirections(); void resetRotationDirections();
void setOnAnimationEventFunc(OnAnimationEventFunc inValue);
private: private:
Animation* _animation; Animation* _animation;
TrackEntry* _next; TrackEntry* _next;
TrackEntry* _mixingFrom; TrackEntry* _mixingFrom;
int _trackIndex; int _trackIndex;
//
bool _loop; bool _loop;
float _eventThreshold, _attachmentThreshold, _drawOrderThreshold; float _eventThreshold, _attachmentThreshold, _drawOrderThreshold;
float _animationStart, _animationEnd, _animationLast, _nextAnimationLast; float _animationStart, _animationEnd, _animationLast, _nextAnimationLast;
float _delay, _trackTime, _trackLast, _nextTrackLast, _trackEnd, _timeScale = 1.0f; float _delay, _trackTime, _trackLast, _nextTrackLast, _trackEnd, _timeScale = 1.0f;
float _alpha, _mixTime, _mixDuration, _interruptAlpha, _totalAlpha; float _alpha, _mixTime, _mixDuration, _interruptAlpha, _totalAlpha;
Vector<int> _timelineData; Vector<int> _timelineData;
Vector<TrackEntry> _timelineDipMix; Vector<TrackEntry*> _timelineDipMix;
Vector<float> _timelinesRotation; Vector<float> _timelinesRotation;
// event AnimationState.TrackEntryDelegate Start, Interrupt, End, Dispose, Complete; OnAnimationEventFunc _onAnimationEventFunc;
// event AnimationState.TrackEntryEventDelegate Event;
/// Sets the timeline data. /// Sets the timeline data.
/// @param to May be null. /// @param to May be NULL.
// TrackEntry setTimelineData(TrackEntry* to, Vector<TrackEntry> mixingToArray, HashSet<int> propertyIDs) TrackEntry* setTimelineData(TrackEntry* to, Vector<TrackEntry*>& mixingToArray, Vector<int>& propertyIDs);
// {
// if (to != null) mixingToArray.Add(to);
// var lastEntry = mixingFrom != null ? mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
// if (to != null) mixingToArray.Pop();
//
// var mixingTo = mixingToArray.Items;
// int mixingToLast = mixingToArray.Count - 1;
// var timelines = animation.timelines.Items;
// int timelinesCount = animation.timelines.Count;
// var timelineDataItems = timelineData.Resize(timelinesCount).Items; // timelineData.setSize(timelinesCount);
// timelineDipMix.clear();
// var timelineDipMixItems = timelineDipMix.Resize(timelinesCount).Items; //timelineDipMix.setSize(timelinesCount);
//
// // outer:
// for (int i = 0; i < timelinesCount; i++) {
// int id = timelines[i].PropertyId;
// if (!propertyIDs.Add(id)) {
// timelineDataItems[i] = AnimationState.Subsequent;
// } else if (to == null || !to.hasTimeline(id)) {
// timelineDataItems[i] = AnimationState.First;
// } else {
// for (int ii = mixingToLast; ii >= 0; ii--) {
// var entry = mixingTo[ii];
// if (!entry.hasTimeline(id)) {
// if (entry.mixDuration > 0) {
// timelineDataItems[i] = AnimationState.DipMix;
// timelineDipMixItems[i] = entry;
// goto continue_outer; // continue outer;
// }
// break;
// }
// }
// timelineDataItems[i] = AnimationState.Dip;
// }
// continue_outer: {}
// }
// return lastEntry;
// }
bool hasTimeline(int inId) bool hasTimeline(int inId);
void reset();
};
class EventQueueEntry
{
friend class EventQueue;
public:
EventType _type;
TrackEntry* _entry;
Event* _event;
EventQueueEntry(EventType eventType, TrackEntry* trackEntry, Event* event = NULL)
{ {
// var timelines = animation.timelines.Items; _type = eventType;
// for (int i = 0, n = animation.timelines.Count; i < n; ++i) _entry = trackEntry;
// { _event = event;
// if (timelines[i].PropertyId == inId)
// {
// return true;
// }
// }
return false;
} }
// void onStart() { if (Start != null) Start(this); }
// void onInterrupt() { if (Interrupt != null) Interrupt(this); }
// void onEnd() { if (End != null) End(this); }
// void onDispose() { if (Dispose != null) Dispose(this); }
// void onComplete() { if (Complete != null) Complete(this); }
// void onEvent(Event& e) { if (Event != null) Event(this, e); }
//
// void reset()
// {
// next = null;
// mixingFrom = null;
// animation = null;
// timelineData.clear();
// timelineDipMix.clear();
// timelinesRotation.clear();
//
// Start = null;
// Interrupt = null;
// End = null;
// Dispose = null;
// Complete = null;
// Event = null;
// }
}; };
class EventQueue class EventQueue
{ {
// private readonly List<EventQueueEntry> eventQueueEntries = new List<EventQueueEntry>(); friend class AnimationState;
// internal bool drainDisabled;
// private:
// private readonly AnimationState state; Vector<EventQueueEntry*> _eventQueueEntries;
// private readonly Pool<TrackEntry> trackEntryPool; bool _drainDisabled;
// internal event Action animationsChanged;
// AnimationState& _state;
// internal EventQueue(AnimationState state, Action HandleanimationsChanged, Pool<TrackEntry> trackEntryPool) { Pool<TrackEntry>& _trackEntryPool;
// this.state = state;
// this.animationsChanged += HandleanimationsChanged; EventQueue(AnimationState& state, Pool<TrackEntry>& trackEntryPool);
// this.trackEntryPool = trackEntryPool;
// } void start(TrackEntry* entry);
//
// struct EventQueueEntry { void interrupt(TrackEntry* entry);
// public EventType type;
// public TrackEntry entry; void end(TrackEntry* entry);
// public Event e;
// void dispose(TrackEntry* entry);
// public EventQueueEntry(EventType eventType, TrackEntry trackEntry, Event e = null) {
// this.type = eventType; void complete(TrackEntry* entry);
// this.entry = trackEntry;
// this.e = e; void event(TrackEntry* entry, Event* e);
// }
// } /// Raises all events in the queue and drains the queue.
// void drain();
// enum EventType {
// Start, Interrupt, End, Dispose, Complete, Event void clear();
// }
//
// internal void Start(TrackEntry entry) {
// eventQueueEntries.Add(new EventQueueEntry(EventType.Start, entry));
// if (animationsChanged != null) animationsChanged();
// }
//
// internal void Interrupt(TrackEntry entry) {
// eventQueueEntries.Add(new EventQueueEntry(EventType.Interrupt, entry));
// }
//
// internal void End(TrackEntry entry) {
// eventQueueEntries.Add(new EventQueueEntry(EventType.End, entry));
// if (animationsChanged != null) animationsChanged();
// }
//
// internal void Dispose(TrackEntry entry) {
// eventQueueEntries.Add(new EventQueueEntry(EventType.Dispose, entry));
// }
//
// internal void Complete(TrackEntry entry) {
// eventQueueEntries.Add(new EventQueueEntry(EventType.Complete, entry));
// }
//
// internal void Event(TrackEntry entry, Event e) {
// eventQueueEntries.Add(new EventQueueEntry(EventType.Event, entry, e));
// }
//
// /// Raises all events in the queue and drains the queue.
// internal void drain() {
// if (drainDisabled) return;
// drainDisabled = true;
//
// var entries = this.eventQueueEntries;
// AnimationState state = this.state;
//
// // Don't cache entries.Count so callbacks can queue their own events (eg, call setAnimation in AnimationState_Complete).
// for (int i = 0; i < entries.Count; i++) {
// var queueEntry = entries[i];
// TrackEntry trackEntry = queueEntry.entry;
//
// switch (queueEntry.type) {
// case EventType.Start:
// trackEntry.onStart();
// state.onStart(trackEntry);
// break;
// case EventType.Interrupt:
// trackEntry.onInterrupt();
// state.onInterrupt(trackEntry);
// break;
// case EventType.End:
// trackEntry.onEnd();
// state.onEnd(trackEntry);
// case EventType.Dispose:
// trackEntry.onDispose();
// state.onDispose(trackEntry);
// trackEntryPool.Free(trackEntry); // Pooling
// break;
// case EventType.Complete:
// trackEntry.onComplete();
// state.onComplete(trackEntry);
// break;
// case EventType.Event:
// trackEntry.onEvent(queueEntry.e);
// state.onEvent(trackEntry, queueEntry.e);
// break;
// }
// }
// eventQueueEntries.clear();
//
// drainDisabled = false;
// }
//
// internal void clear() {
// eventQueueEntries.clear();
// }
}; };
class AnimationState class AnimationState
{ {
friend class TrackEntry;
friend class EventQueue;
public:
void setOnAnimationEventFunc(OnAnimationEventFunc inValue);
private:
static const int Subsequent, First, Dip, DipMix;
// static readonly Animation EmptyAnimation = new Animation("<empty>", new Vector<Timeline>(), 0); // static readonly Animation EmptyAnimation = new Animation("<empty>", new Vector<Timeline>(), 0);
// internal const int Subsequent = 0, First = 1, Dip = 2, DipMix = 3;
// //
// private AnimationStateData data; // private AnimationStateData data;
// //
@ -408,27 +304,23 @@ namespace Spine
// //
// private readonly HashSet<int> propertyIDs = new HashSet<int>(); // private readonly HashSet<int> propertyIDs = new HashSet<int>();
// private readonly Vector<TrackEntry> mixingTo = new Vector<TrackEntry>(); // private readonly Vector<TrackEntry> mixingTo = new Vector<TrackEntry>();
// private bool animationsChanged; bool _animationsChanged;
// //
// private float timeScale = 1; // private float timeScale = 1;
// //
// public AnimationStateData Data { get { return data; } } // public AnimationStateData Data { get { return data; } }
// /// A list of tracks that have animations, which may contain nulls. // /// A list of tracks that have animations, which may contain NULLs.
// public Vector<TrackEntry> Tracks { get { return tracks; } } // public Vector<TrackEntry> Tracks { get { return tracks; } }
// public float TimeScale { get { return timeScale; } set { timeScale = value; } } // public float TimeScale { get { return timeScale; } set { timeScale = value; } }
// //
// public delegate void TrackEntryDelegate(TrackEntry trackEntry); OnAnimationEventFunc _onAnimationEventFunc;
// public event TrackEntryDelegate Start, Interrupt, End, Dispose, Complete;
//
// public delegate void TrackEntryEventDelegate(TrackEntry trackEntry, Event e);
// public event TrackEntryEventDelegate Event;
// //
// public AnimationState(AnimationStateData data) { // public AnimationState(AnimationStateData data) {
// if (data == null) throw new ArgumentNullException("data", "data cannot be null."); // if (data == NULL) throw new ArgumentNULLException("data", "data cannot be NULL.");
// this.data = data; // _data = data;
// this.queue = new EventQueue( // _queue = new EventQueue(
// this, // this,
// delegate { this.animationsChanged = true; }, // delegate { _animationsChanged = true; },
// trackEntryPool // trackEntryPool
// ); // );
// } // }
@ -441,7 +333,7 @@ namespace Spine
// var tracksItems = tracks.Items; // var tracksItems = tracks.Items;
// for (int i = 0, n = tracks.Count; i < n; i++) { // for (int i = 0, n = tracks.Count; i < n; i++) {
// TrackEntry current = tracksItems[i]; // TrackEntry current = tracksItems[i];
// if (current == null) continue; // if (current == NULL) continue;
// //
// current.animationLast = current.nextAnimationLast; // current.animationLast = current.nextAnimationLast;
// current.trackLast = current.nextTrackLast; // current.trackLast = current.nextTrackLast;
@ -456,7 +348,7 @@ namespace Spine
// } // }
// //
// TrackEntry next = current.next; // TrackEntry next = current.next;
// if (next != null) { // if (next != NULL) {
// // When the next entry's delay is passed, change to the next entry, preserving leftover time. // // When the next entry's delay is passed, change to the next entry, preserving leftover time.
// float nextTime = current.trackLast - next.delay; // float nextTime = current.trackLast - next.delay;
// if (nextTime >= 0) { // if (nextTime >= 0) {
@ -464,26 +356,26 @@ namespace Spine
// next.trackTime = nextTime + (delta * next.timeScale); // next.trackTime = nextTime + (delta * next.timeScale);
// current.trackTime += currentDelta; // current.trackTime += currentDelta;
// setCurrent(i, next, true); // setCurrent(i, next, true);
// while (next.mixingFrom != null) { // while (next.mixingFrom != NULL) {
// next.mixTime += currentDelta; // next.mixTime += currentDelta;
// next = next.mixingFrom; // next = next.mixingFrom;
// } // }
// continue; // continue;
// } // }
// } else if (current.trackLast >= current.trackEnd && current.mixingFrom == null) { // } else if (current.trackLast >= current.trackEnd && current.mixingFrom == NULL) {
// // clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom. // // clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom.
// tracksItems[i] = null; // tracksItems[i] = NULL;
// //
// queue.End(current); // queue.end(current);
// disposeNext(current); // disposeNext(current);
// continue; // continue;
// } // }
// if (current.mixingFrom != null && updateMixingFrom(current, delta)) { // if (current.mixingFrom != NULL && updateMixingFrom(current, delta)) {
// // End mixing from entries once all have completed. // // End mixing from entries once all have completed.
// var from = current.mixingFrom; // var from = current.mixingFrom;
// current.mixingFrom = null; // current.mixingFrom = NULL;
// while (from != null) { // while (from != NULL) {
// queue.End(from); // queue.end(from);
// from = from.mixingFrom; // from = from.mixingFrom;
// } // }
// } // }
@ -497,7 +389,7 @@ namespace Spine
// /// Returns true when all mixing from entries are complete. // /// Returns true when all mixing from entries are complete.
// private bool updateMixingFrom(TrackEntry to, float delta) { // private bool updateMixingFrom(TrackEntry to, float delta) {
// TrackEntry from = to.mixingFrom; // TrackEntry from = to.mixingFrom;
// if (from == null) return true; // if (from == NULL) return true;
// //
// bool finished = updateMixingFrom(from, delta); // bool finished = updateMixingFrom(from, delta);
// //
@ -507,7 +399,7 @@ namespace Spine
// if (from.totalAlpha == 0 || to.mixDuration == 0) { // if (from.totalAlpha == 0 || to.mixDuration == 0) {
// to.mixingFrom = from.mixingFrom; // to.mixingFrom = from.mixingFrom;
// to.interruptAlpha = from.interruptAlpha; // to.interruptAlpha = from.interruptAlpha;
// queue.End(from); // queue.end(from);
// } // }
// return finished; // return finished;
// } // }
@ -523,24 +415,24 @@ namespace Spine
// /// Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the // /// Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the
// /// animation state can be applied to multiple skeletons to pose them identically. // /// animation state can be applied to multiple skeletons to pose them identically.
// public bool apply(Skeleton skeleton) { // public bool apply(Skeleton skeleton) {
// if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); // if (skeleton == NULL) throw new ArgumentNULLException("skeleton", "skeleton cannot be NULL.");
// if (animationsChanged) animationsChanged(); // if (animationsChanged) animationsChanged();
// //
// var events = this.events; // var events = _events;
// //
// bool applied = false; // bool applied = false;
// var tracksItems = tracks.Items; // var tracksItems = tracks.Items;
// for (int i = 0, m = tracks.Count; i < m; i++) { // for (int i = 0, m = tracks.Count; i < m; i++) {
// TrackEntry current = tracksItems[i]; // TrackEntry current = tracksItems[i];
// if (current == null || current.delay > 0) continue; // if (current == NULL || current.delay > 0) continue;
// applied = true; // applied = true;
// MixPose currentPose = i == 0 ? MixPose.Current : MixPose.CurrentLayered; // MixPose currentPose = i == 0 ? MixPose.Current : MixPose.CurrentLayered;
// //
// // apply mixing from entries first. // // apply mixing from entries first.
// float mix = current.alpha; // float mix = current.alpha;
// if (current.mixingFrom != null) // if (current.mixingFrom != NULL)
// mix *= applyMixingFrom(current, skeleton, currentPose); // mix *= applyMixingFrom(current, skeleton, currentPose);
// else if (current.trackTime >= current.trackEnd && current.next == null) // // else if (current.trackTime >= current.trackEnd && current.next == NULL) //
// mix = 0; // Set to setup pose the last time the entry will be applied. // mix = 0; // Set to setup pose the last time the entry will be applied.
// //
// // apply current entry. // // apply current entry.
@ -562,7 +454,7 @@ namespace Spine
// Timeline timeline = timelinesItems[ii]; // Timeline timeline = timelinesItems[ii];
// MixPose pose = timelineData[ii] >= AnimationState.First ? MixPose.Setup : currentPose; // MixPose pose = timelineData[ii] >= AnimationState.First ? MixPose.Setup : currentPose;
// var rotateTimeline = timeline as RotateTimeline; // var rotateTimeline = timeline as RotateTimeline;
// if (rotateTimeline != null) // if (rotateTimeline != NULL)
// applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame); // applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
// else // else
// timeline.apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection.In); // timeline.apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection.In);
@ -580,7 +472,7 @@ namespace Spine
// //
// private float applyMixingFrom(TrackEntry to, Skeleton skeleton, MixPose currentPose) { // private float applyMixingFrom(TrackEntry to, Skeleton skeleton, MixPose currentPose) {
// TrackEntry from = to.mixingFrom; // TrackEntry from = to.mixingFrom;
// if (from.mixingFrom != null) applyMixingFrom(from, skeleton, currentPose); // if (from.mixingFrom != NULL) applyMixingFrom(from, skeleton, currentPose);
// //
// float mix; // float mix;
// if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes. // if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
@ -591,7 +483,7 @@ namespace Spine
// if (mix > 1) mix = 1; // if (mix > 1) mix = 1;
// } // }
// //
// var eventBuffer = mix < from.eventThreshold ? this.events : null; // var eventBuffer = mix < from.eventThreshold ? _events : NULL;
// bool attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold; // bool attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold;
// float animationLast = from.animationLast, animationTime = from.AnimationTime; // float animationLast = from.animationLast, animationTime = from.AnimationTime;
// var timelines = from.animation.timelines; // var timelines = from.animation.timelines;
@ -632,7 +524,7 @@ namespace Spine
// } // }
// from.totalAlpha += alpha; // from.totalAlpha += alpha;
// var rotateTimeline = timeline as RotateTimeline; // var rotateTimeline = timeline as RotateTimeline;
// if (rotateTimeline != null) { // if (rotateTimeline != NULL) {
// applyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame); // applyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame);
// } else { // } else {
// timeline.apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection.Out); // timeline.apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection.Out);
@ -640,7 +532,7 @@ namespace Spine
// } // }
// //
// if (to.mixDuration > 0) queueEvents(from, animationTime); // if (to.mixDuration > 0) queueEvents(from, animationTime);
// this.events.clear(false); // _events.clear(false);
// from.nextAnimationLast = animationTime; // from.nextAnimationLast = animationTime;
// from.nextTrackLast = from.trackTime; // from.nextTrackLast = from.trackTime;
// //
@ -653,7 +545,7 @@ namespace Spine
// if (firstFrame) timelinesRotation[i] = 0; // if (firstFrame) timelinesRotation[i] = 0;
// //
// if (alpha == 1) { // if (alpha == 1) {
// rotateTimeline.apply(skeleton, 0, time, null, 1, pose, MixDirection.In); // rotateTimeline.apply(skeleton, 0, time, NULL, 1, pose, MixDirection.In);
// return; // return;
// } // }
// //
@ -718,27 +610,27 @@ namespace Spine
// float trackLastWrapped = entry.trackLast % duration; // float trackLastWrapped = entry.trackLast % duration;
// //
// // Queue events before complete. // // Queue events before complete.
// var events = this.events; // var events = _events;
// var eventsItems = events.Items; // var eventsItems = events.Items;
// int i = 0, n = events.Count; // int i = 0, n = events.Count;
// for (; i < n; i++) { // for (; i < n; i++) {
// var e = eventsItems[i]; // var e = eventsItems[i];
// if (e.time < trackLastWrapped) break; // if (e.time < trackLastWrapped) break;
// if (e.time > animationEnd) continue; // Discard events outside animation start/end. // if (e.time > animationEnd) continue; // Discard events outside animation start/end.
// queue.Event(entry, e); // queue.event(entry, e);
// } // }
// //
// // Queue complete if completed a loop iteration or the animation. // // Queue complete if completed a loop iteration or the animation.
// if (entry.loop ? (trackLastWrapped > entry.trackTime % duration) // if (entry.loop ? (trackLastWrapped > entry.trackTime % duration)
// : (animationTime >= animationEnd && entry.animationLast < animationEnd)) { // : (animationTime >= animationEnd && entry.animationLast < animationEnd)) {
// queue.Complete(entry); // queue.complete(entry);
// } // }
// //
// // Queue events after complete. // // Queue events after complete.
// for (; i < n; i++) { // for (; i < n; i++) {
// Event e = eventsItems[i]; // Event e = eventsItems[i];
// if (e.time < animationStart) continue; // Discard events outside animation start/end. // if (e.time < animationStart) continue; // Discard events outside animation start/end.
// queue.Event(entry, eventsItems[i]); // queue.event(entry, eventsItems[i]);
// } // }
// } // }
// //
@ -764,22 +656,22 @@ namespace Spine
// public void clearTrack(int trackIndex) { // public void clearTrack(int trackIndex) {
// if (trackIndex >= tracks.Count) return; // if (trackIndex >= tracks.Count) return;
// TrackEntry current = tracks.Items[trackIndex]; // TrackEntry current = tracks.Items[trackIndex];
// if (current == null) return; // if (current == NULL) return;
// //
// queue.End(current); // queue.end(current);
// //
// disposeNext(current); // disposeNext(current);
// //
// TrackEntry entry = current; // TrackEntry entry = current;
// while (true) { // while (true) {
// TrackEntry from = entry.mixingFrom; // TrackEntry from = entry.mixingFrom;
// if (from == null) break; // if (from == NULL) break;
// queue.End(from); // queue.end(from);
// entry.mixingFrom = null; // entry.mixingFrom = NULL;
// entry = from; // entry = from;
// } // }
// //
// tracks.Items[current.trackIndex] = null; // tracks.Items[current.trackIndex] = NULL;
// //
// queue.drain(); // queue.drain();
// } // }
@ -789,26 +681,26 @@ namespace Spine
// TrackEntry from = expandToIndex(index); // TrackEntry from = expandToIndex(index);
// tracks.Items[index] = current; // tracks.Items[index] = current;
// //
// if (from != null) { // if (from != NULL) {
// if (interrupt) queue.Interrupt(from); // if (interrupt) queue.interrupt(from);
// current.mixingFrom = from; // current.mixingFrom = from;
// current.mixTime = 0; // current.mixTime = 0;
// //
// // Store interrupted mix percentage. // // Store interrupted mix percentage.
// if (from.mixingFrom != null && from.mixDuration > 0) // if (from.mixingFrom != NULL && from.mixDuration > 0)
// current.interruptAlpha *= Math.Min(1, from.mixTime / from.mixDuration); // current.interruptAlpha *= Math.Min(1, from.mixTime / from.mixDuration);
// //
// from.timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in. // from.timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in.
// } // }
// //
// queue.Start(current); // triggers animationsChanged // queue.start(current); // triggers animationsChanged
// } // }
// //
// //
// /// Sets an animation by name. setAnimation(int, Animation, bool) // /// Sets an animation by name. setAnimation(int, Animation, bool)
// public TrackEntry setAnimation(int trackIndex, string animationName, bool loop) { // public TrackEntry setAnimation(int trackIndex, string animationName, bool loop) {
// Animation animation = data.skeletonData.FindAnimation(animationName); // Animation animation = data.skeletonData.FindAnimation(animationName);
// if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); // if (animation == NULL) throw new ArgumentException("Animation not found: " + animationName, "animationName");
// return setAnimation(trackIndex, animation, loop); // return setAnimation(trackIndex, animation, loop);
// } // }
// //
@ -820,15 +712,15 @@ namespace Spine
// /// A track entry to allow further customization of animation playback. References to the track entry must not be kept // /// A track entry to allow further customization of animation playback. References to the track entry must not be kept
// /// after AnimationState.Dispose. // /// after AnimationState.Dispose.
// public TrackEntry setAnimation(int trackIndex, Animation animation, bool loop) { // public TrackEntry setAnimation(int trackIndex, Animation animation, bool loop) {
// if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); // if (animation == NULL) throw new ArgumentNULLException("animation", "animation cannot be NULL.");
// bool interrupt = true; // bool interrupt = true;
// TrackEntry current = expandToIndex(trackIndex); // TrackEntry current = expandToIndex(trackIndex);
// if (current != null) { // if (current != NULL) {
// if (current.nextTrackLast == -1) { // if (current.nextTrackLast == -1) {
// // Don't mix from an entry that was never applied. // // Don't mix from an entry that was never applied.
// tracks.Items[trackIndex] = current.mixingFrom; // tracks.Items[trackIndex] = current.mixingFrom;
// queue.Interrupt(current); // queue.interrupt(current);
// queue.End(current); // queue.end(current);
// disposeNext(current); // disposeNext(current);
// current = current.mixingFrom; // current = current.mixingFrom;
// interrupt = false; // interrupt = false;
@ -846,7 +738,7 @@ namespace Spine
// /// addAnimation(int, Animation, bool, float) // /// addAnimation(int, Animation, bool, float)
// public TrackEntry addAnimation(int trackIndex, string animationName, bool loop, float delay) { // public TrackEntry addAnimation(int trackIndex, string animationName, bool loop, float delay) {
// Animation animation = data.skeletonData.FindAnimation(animationName); // Animation animation = data.skeletonData.FindAnimation(animationName);
// if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); // if (animation == NULL) throw new ArgumentException("Animation not found: " + animationName, "animationName");
// return addAnimation(trackIndex, animation, loop, delay); // return addAnimation(trackIndex, animation, loop, delay);
// } // }
// //
@ -859,17 +751,17 @@ namespace Spine
// /// @return A track entry to allow further customization of animation playback. References to the track entry must not be kept // /// @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
// /// after AnimationState.Dispose // /// after AnimationState.Dispose
// public TrackEntry addAnimation(int trackIndex, Animation animation, bool loop, float delay) { // public TrackEntry addAnimation(int trackIndex, Animation animation, bool loop, float delay) {
// if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); // if (animation == NULL) throw new ArgumentNULLException("animation", "animation cannot be NULL.");
// //
// TrackEntry last = expandToIndex(trackIndex); // TrackEntry last = expandToIndex(trackIndex);
// if (last != null) { // if (last != NULL) {
// while (last.next != null) // while (last.next != NULL)
// last = last.next; // last = last.next;
// } // }
// //
// TrackEntry entry = newTrackEntry(trackIndex, animation, loop, last); // TrackEntry entry = newTrackEntry(trackIndex, animation, loop, last);
// //
// if (last == null) { // if (last == NULL) {
// setCurrent(trackIndex, entry, true); // setCurrent(trackIndex, entry, true);
// queue.drain(); // queue.drain();
// } else { // } else {
@ -921,7 +813,7 @@ namespace Spine
// queue.drainDisabled = true; // queue.drainDisabled = true;
// for (int i = 0, n = tracks.Count; i < n; i++) { // for (int i = 0, n = tracks.Count; i < n; i++) {
// TrackEntry current = tracks.Items[i]; // TrackEntry current = tracks.Items[i];
// if (current != null) setEmptyAnimation(i, mixDuration); // if (current != NULL) setEmptyAnimation(i, mixDuration);
// } // }
// queue.drainDisabled = olddrainDisabled; // queue.drainDisabled = olddrainDisabled;
// queue.drain(); // queue.drain();
@ -930,12 +822,12 @@ namespace Spine
// private TrackEntry expandToIndex(int index) { // private TrackEntry expandToIndex(int index) {
// if (index < tracks.Count) return tracks.Items[index]; // if (index < tracks.Count) return tracks.Items[index];
// while (index >= tracks.Count) // while (index >= tracks.Count)
// tracks.Add(null); // tracks.Add(NULL);
// return null; // return NULL;
// } // }
// //
// /// Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values. // /// Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values.
// /// @param last May be null. // /// @param last May be NULL.
// private TrackEntry newTrackEntry(int trackIndex, Animation animation, bool loop, TrackEntry last) { // private TrackEntry newTrackEntry(int trackIndex, Animation animation, bool loop, TrackEntry last) {
// TrackEntry entry = trackEntryPool.Obtain(); // Pooling // TrackEntry entry = trackEntryPool.Obtain(); // Pooling
// entry.trackIndex = trackIndex; // entry.trackIndex = trackIndex;
@ -961,45 +853,45 @@ namespace Spine
// entry.alpha = 1; // entry.alpha = 1;
// entry.interruptAlpha = 1; // entry.interruptAlpha = 1;
// entry.mixTime = 0; // entry.mixTime = 0;
// entry.mixDuration = (last == null) ? 0 : data.GetMix(last.animation, animation); // entry.mixDuration = (last == NULL) ? 0 : data.GetMix(last.animation, animation);
// return entry; // return entry;
// } // }
// //
// /// Dispose all track entries queued after the given TrackEntry. // /// Dispose all track entries queued after the given TrackEntry.
// private void disposeNext(TrackEntry entry) { // private void disposeNext(TrackEntry entry) {
// TrackEntry next = entry.next; // TrackEntry next = entry.next;
// while (next != null) { // while (next != NULL) {
// queue.Dispose(next); // queue.dispose(next);
// next = next.next; // next = next.next;
// } // }
// entry.next = null; // entry.next = NULL;
// } // }
// //
// private void animationsChanged() { // private void animationsChanged() {
// animationsChanged = false; // animationsChanged = false;
// //
// var propertyIDs = this.propertyIDs; // var propertyIDs = _propertyIDs;
// propertyIDs.clear(); // propertyIDs.clear();
// var mixingTo = this.mixingTo; // var mixingTo = _mixingTo;
// //
// var tracksItems = tracks.Items; // var tracksItems = tracks.Items;
// for (int i = 0, n = tracks.Count; i < n; i++) { // for (int i = 0, n = tracks.Count; i < n; i++) {
// var entry = tracksItems[i]; // var entry = tracksItems[i];
// if (entry != null) entry.setTimelineData(null, mixingTo, propertyIDs); // if (entry != NULL) entry.setTimelineData(NULL, mixingTo, propertyIDs);
// } // }
// } // }
// //
// /// @return The track entry for the animation currently playing on the track, or null if no animation is currently playing. // /// @return The track entry for the animation currently playing on the track, or NULL if no animation is currently playing.
// public TrackEntry getCurrent(int trackIndex) { // public TrackEntry getCurrent(int trackIndex) {
// return (trackIndex >= tracks.Count) ? null : tracks.Items[trackIndex]; // return (trackIndex >= tracks.Count) ? NULL : tracks.Items[trackIndex];
// } // }
// //
// internal void onStart(TrackEntry entry) { if (Start != null) Start(entry); } // internal void onStart(TrackEntry entry) { if (Start != NULL) Start(entry); }
// internal void onInterrupt(TrackEntry entry) { if (Interrupt != null) Interrupt(entry); } // internal void onInterrupt(TrackEntry entry) { if (Interrupt != NULL) Interrupt(entry); }
// internal void onEnd(TrackEntry entry) { if (End != null) End(entry); } // internal void onEnd(TrackEntry entry) { if (End != NULL) End(entry); }
// internal void onDispose(TrackEntry entry) { if (Dispose != null) Dispose(entry); } // internal void onDispose(TrackEntry entry) { if (Dispose != NULL) Dispose(entry); }
// internal void onComplete(TrackEntry entry) { if (Complete != null) Complete(entry); } // internal void onComplete(TrackEntry entry) { if (Complete != NULL) Complete(entry); }
// internal void onEvent(TrackEntry entry, Event e) { if (Event != null) Event(entry, e); } // internal void onEvent(TrackEntry entry, Event e) { if (Event != NULL) Event(entry, e); }
}; };
} }

View File

@ -31,6 +31,9 @@
#include <spine/AnimationState.h> #include <spine/AnimationState.h>
#include <spine/Animation.h> #include <spine/Animation.h>
#include <spine/Event.h>
#include <spine/Timeline.h>
#include <spine/MathUtil.h> #include <spine/MathUtil.h>
@ -38,7 +41,7 @@ namespace Spine
{ {
TrackEntry::TrackEntry() TrackEntry::TrackEntry()
{ {
// Empty
} }
int TrackEntry::getTrackIndex() { return _trackIndex; } int TrackEntry::getTrackIndex() { return _trackIndex; }
@ -116,11 +119,199 @@ namespace Spine
TrackEntry* TrackEntry::getMixingFrom() { return _mixingFrom; } TrackEntry* TrackEntry::getMixingFrom() { return _mixingFrom; }
// event AnimationState.TrackEntryDelegate Start, Interrupt, End, Dispose, Complete;
// event AnimationState.TrackEntryEventDelegate Event;
void TrackEntry::resetRotationDirections() void TrackEntry::resetRotationDirections()
{ {
_timelinesRotation.clear(); _timelinesRotation.clear();
} }
void TrackEntry::setOnAnimationEventFunc(OnAnimationEventFunc inValue)
{
_onAnimationEventFunc = inValue;
}
TrackEntry* TrackEntry::setTimelineData(TrackEntry* to, Vector<TrackEntry*>& mixingToArray, Vector<int>& propertyIDs)
{
if (to != NULL)
{
mixingToArray.push_back(to);
}
TrackEntry* lastEntry = _mixingFrom != NULL ? _mixingFrom->setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != NULL)
{
mixingToArray.erase(mixingToArray.size() - 1);
}
int mixingToLast = static_cast<int>(mixingToArray.size()) - 1;
Vector<Timeline*>& timelines = _animation->_timelines;
int timelinesCount = static_cast<int>(timelines.size());
_timelineData.reserve(timelinesCount);
_timelineDipMix.clear();
_timelineDipMix.reserve(timelinesCount);
// outer:
for (int i = 0; i < timelinesCount; ++i)
{
int id = timelines[i]->getPropertyId();
if (propertyIDs.contains(id))
{
_timelineData[i] = AnimationState::Subsequent;
}
else if (to == NULL || !to->hasTimeline(id))
{
_timelineData[i] = AnimationState::First;
}
else
{
for (int ii = mixingToLast; ii >= 0; --ii)
{
TrackEntry* entry = mixingToArray[ii];
if (!entry->hasTimeline(id))
{
if (entry->_mixDuration > 0)
{
_timelineData[i] = AnimationState::DipMix;
_timelineDipMix[i] = entry;
goto continue_outer; // continue outer;
}
break;
}
}
_timelineData[i] = AnimationState::Dip;
}
continue_outer: {}
}
return lastEntry;
}
bool TrackEntry::hasTimeline(int inId)
{
Vector<Timeline*>& timelines = _animation->_timelines;
for (int i = 0, n = static_cast<int>(timelines.size()); i < n; ++i)
{
if (timelines[i]->getPropertyId() == inId)
{
return true;
}
}
return false;
}
void TrackEntry::reset()
{
_animation = NULL;
_next = NULL;
_mixingFrom = NULL;
_timelineData.clear();
_timelineDipMix.clear();
_timelinesRotation.clear();
_onAnimationEventFunc = NULL;
}
EventQueue::EventQueue(AnimationState& state, Pool<TrackEntry>& trackEntryPool) : _state(state), _trackEntryPool(trackEntryPool)
{
// Empty
}
void EventQueue::start(TrackEntry* entry)
{
_eventQueueEntries.push_back(new EventQueueEntry(EventType_Start, entry));
_state._animationsChanged = true;
}
void EventQueue::interrupt(TrackEntry* entry)
{
_eventQueueEntries.push_back(new EventQueueEntry(EventType_Interrupt, entry));
}
void EventQueue::end(TrackEntry* entry)
{
_eventQueueEntries.push_back(new EventQueueEntry(EventType_End, entry));
_state._animationsChanged = true;
}
void EventQueue::dispose(TrackEntry* entry)
{
_eventQueueEntries.push_back(new EventQueueEntry(EventType_Dispose, entry));
}
void EventQueue::complete(TrackEntry* entry)
{
_eventQueueEntries.push_back(new EventQueueEntry(EventType_Complete, entry));
}
void EventQueue::event(TrackEntry* entry, Event* e)
{
_eventQueueEntries.push_back(new EventQueueEntry(EventType_Event, entry, e));
}
/// Raises all events in the queue and drains the queue.
void EventQueue::drain()
{
if (_drainDisabled)
{
return;
}
_drainDisabled = true;
AnimationState& state = _state;
// Don't cache entries.size() so callbacks can queue their own events (eg, call setAnimation in AnimationState_Complete).
for (int i = 0; i < _eventQueueEntries.size(); ++i)
{
EventQueueEntry* queueEntry = _eventQueueEntries[i];
TrackEntry* trackEntry = queueEntry->_entry;
switch (queueEntry->_type)
{
// case EventType_Start:
// trackEntry.onStart();
// state.onStart(trackEntry);
// break;
// case EventType_Interrupt:
// trackEntry.onInterrupt();
// state.onInterrupt(trackEntry);
// break;
// case EventType_End:
// trackEntry.onEnd();
// state.onEnd(trackEntry);
// case EventType_Dispose:
// trackEntry.onDispose();
// state.onDispose(trackEntry);
// trackEntryPool.Free(trackEntry); // Pooling
// break;
// case EventType_Complete:
// trackEntry.onComplete();
// state.onComplete(trackEntry);
// break;
// case EventType_Event:
// trackEntry.onEvent(queueEntry.e);
// state.onEvent(trackEntry, queueEntry.e);
// break;
}
}
_eventQueueEntries.clear();
_drainDisabled = false;
}
void EventQueue::clear()
{
_eventQueueEntries.clear();
}
const int AnimationState::Subsequent = 0;
const int AnimationState::First = 1;
const int AnimationState::Dip = 2;
const int AnimationState::DipMix = 3;
void AnimationState::setOnAnimationEventFunc(OnAnimationEventFunc inValue)
{
_onAnimationEventFunc = inValue;
}
} }