Quellcode durchsuchen

Okay, AnimationState is done, on to SkeletonJson and SkeletonBinary

Stephen Gowen vor 7 Jahren
Ursprung
Commit
3fc2f08ff6
42 geänderte Dateien mit 835 neuen und 571 gelöschten Zeilen
  1. 1 1
      spine-cpp/spine-cpp/include/spine/Animation.h
  2. 34 533
      spine-cpp/spine-cpp/include/spine/AnimationState.h
  3. 2 0
      spine-cpp/spine-cpp/include/spine/AnimationStateData.h
  4. 1 1
      spine-cpp/spine-cpp/include/spine/AttachmentTimeline.h
  5. 2 0
      spine-cpp/spine-cpp/include/spine/Bone.h
  6. 2 0
      spine-cpp/spine-cpp/include/spine/BoneData.h
  7. 1 1
      spine-cpp/spine-cpp/include/spine/ColorTimeline.h
  8. 1 1
      spine-cpp/spine-cpp/include/spine/CurveTimeline.h
  9. 1 1
      spine-cpp/spine-cpp/include/spine/DeformTimeline.h
  10. 1 1
      spine-cpp/spine-cpp/include/spine/DrawOrderTimeline.h
  11. 2 0
      spine-cpp/spine-cpp/include/spine/Event.h
  12. 1 1
      spine-cpp/spine-cpp/include/spine/EventTimeline.h
  13. 1 1
      spine-cpp/spine-cpp/include/spine/IkConstraintTimeline.h
  14. 6 0
      spine-cpp/spine-cpp/include/spine/MathUtil.h
  15. 1 1
      spine-cpp/spine-cpp/include/spine/PathConstraintMixTimeline.h
  16. 1 1
      spine-cpp/spine-cpp/include/spine/PathConstraintPositionTimeline.h
  17. 1 1
      spine-cpp/spine-cpp/include/spine/PathConstraintSpacingTimeline.h
  18. 3 1
      spine-cpp/spine-cpp/include/spine/RotateTimeline.h
  19. 1 1
      spine-cpp/spine-cpp/include/spine/ScaleTimeline.h
  20. 1 1
      spine-cpp/spine-cpp/include/spine/ShearTimeline.h
  21. 1 0
      spine-cpp/spine-cpp/include/spine/Skeleton.h
  22. 1 1
      spine-cpp/spine-cpp/include/spine/Timeline.h
  23. 1 1
      spine-cpp/spine-cpp/include/spine/TransformConstraintTimeline.h
  24. 1 1
      spine-cpp/spine-cpp/include/spine/TranslateTimeline.h
  25. 1 1
      spine-cpp/spine-cpp/include/spine/TwoColorTimeline.h
  26. 2 2
      spine-cpp/spine-cpp/src/spine/Animation.cpp
  27. 741 2
      spine-cpp/spine-cpp/src/spine/AnimationState.cpp
  28. 1 1
      spine-cpp/spine-cpp/src/spine/AttachmentTimeline.cpp
  29. 1 1
      spine-cpp/spine-cpp/src/spine/ColorTimeline.cpp
  30. 1 1
      spine-cpp/spine-cpp/src/spine/DeformTimeline.cpp
  31. 1 1
      spine-cpp/spine-cpp/src/spine/DrawOrderTimeline.cpp
  32. 9 2
      spine-cpp/spine-cpp/src/spine/EventTimeline.cpp
  33. 1 1
      spine-cpp/spine-cpp/src/spine/IkConstraintTimeline.cpp
  34. 1 1
      spine-cpp/spine-cpp/src/spine/PathConstraintMixTimeline.cpp
  35. 1 1
      spine-cpp/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp
  36. 1 1
      spine-cpp/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp
  37. 1 1
      spine-cpp/spine-cpp/src/spine/RotateTimeline.cpp
  38. 1 1
      spine-cpp/spine-cpp/src/spine/ScaleTimeline.cpp
  39. 1 1
      spine-cpp/spine-cpp/src/spine/ShearTimeline.cpp
  40. 1 1
      spine-cpp/spine-cpp/src/spine/TransformConstraintTimeline.cpp
  41. 1 1
      spine-cpp/spine-cpp/src/spine/TranslateTimeline.cpp
  42. 1 1
      spine-cpp/spine-cpp/src/spine/TwoColorTimeline.cpp

+ 1 - 1
spine-cpp/spine-cpp/include/spine/Animation.h

@@ -70,7 +70,7 @@ namespace Spine
         
         /// Applies all the animation's timelines to the specified skeleton.
         /// See also Timeline::apply(Skeleton&, float, float, Vector, float, MixPose, MixDirection)
-        void apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        void apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         std::string getName();
         

+ 34 - 533
spine-cpp/spine-cpp/include/spine/AnimationState.h

@@ -297,181 +297,30 @@ namespace Spine
         
         ~AnimationState();
         
-        void setOnAnimationEventFunc(OnAnimationEventFunc inValue);
-        
         ///
         /// Increments the track entry times, setting queued animations as current if needed
         /// @param delta delta time
-        void update(float delta)
-        {
-//            delta *= timeScale;
-//            var tracksItems = tracks.Items;
-//            for (int i = 0, n = tracks.Count; i < n; i++) {
-//                TrackEntry current = tracksItems[i];
-//                if (current == NULL) continue;
-//
-//                current.animationLast = current.nextAnimationLast;
-//                current.trackLast = current.nextTrackLast;
-//
-//                float currentDelta = delta * current.timeScale;
-//
-//                if (current.delay > 0) {
-//                    current.delay -= currentDelta;
-//                    if (current.delay > 0) continue;
-//                    currentDelta = -current.delay;
-//                    current.delay = 0;
-//                }
-//
-//                TrackEntry next = current.next;
-//                if (next != NULL) {
-//                    // When the next entry's delay is passed, change to the next entry, preserving leftover time.
-//                    float nextTime = current.trackLast - next.delay;
-//                    if (nextTime >= 0) {
-//                        next.delay = 0;
-//                        next.trackTime = nextTime + (delta * next.timeScale);
-//                        current.trackTime += currentDelta;
-//                        setCurrent(i, next, true);
-//                        while (next.mixingFrom != NULL) {
-//                            next.mixTime += currentDelta;
-//                            next = next.mixingFrom;
-//                        }
-//                        continue;
-//                    }
-//                } 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.
-//                    tracksItems[i] = NULL;
-//
-//                    queue.end(current);
-//                    disposeNext(current);
-//                    continue;
-//                }
-//                if (current.mixingFrom != NULL && updateMixingFrom(current, delta)) {
-//                    // End mixing from entries once all have completed.
-//                    var from = current.mixingFrom;
-//                    current.mixingFrom = NULL;
-//                    while (from != NULL) {
-//                        queue.end(from);
-//                        from = from.mixingFrom;
-//                    }
-//                }
-//
-//                current.trackTime += currentDelta;
-//            }
-//
-//            queue.drain();
-        }
+        void update(float delta);
         
         ///
         /// 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.
-        bool apply(Skeleton& skeleton)
-        {
-//            if (animationsChanged) animationsChanged();
-//
-//            var events = _events;
-//
-            bool applied = false;
-//            var tracksItems = tracks.Items;
-//            for (int i = 0, m = tracks.Count; i < m; i++) {
-//                TrackEntry current = tracksItems[i];
-//                if (current == NULL || current.delay > 0) continue;
-//                applied = true;
-//                MixPose currentPose = i == 0 ? MixPose.Current : MixPose.CurrentLayered;
-//
-//                // apply mixing from entries first.
-//                float mix = current.alpha;
-//                if (current.mixingFrom != NULL)
-//                    mix *= applyMixingFrom(current, skeleton, currentPose);
-//                else if (current.trackTime >= current.trackEnd && current.next == NULL) //
-//                    mix = 0; // Set to setup pose the last time the entry will be applied.
-//
-//                // apply current entry.
-//                float animationLast = current.animationLast, animationTime = current.AnimationTime;
-//                int timelineCount = current.animation.timelines.Count;
-//                var timelines = current.animation.timelines;
-//                var timelinesItems = timelines.Items;
-//                if (mix == 1) {
-//                    for (int ii = 0; ii < timelineCount; ii++)
-//                        timelinesItems[ii].apply(skeleton, animationLast, animationTime, events, 1, MixPose.Setup, MixDirection.In);
-//                } else {
-//                    var timelineData = current.timelineData.Items;
-//
-//                    bool firstFrame = current.timelinesRotation.Count == 0;
-//                    if (firstFrame) current.timelinesRotation.EnsureCapacity(timelines.Count << 1);
-//                    var timelinesRotation = current.timelinesRotation.Items;
-//
-//                    for (int ii = 0; ii < timelineCount; ii++) {
-//                        Timeline timeline = timelinesItems[ii];
-//                        MixPose pose = timelineData[ii] >= AnimationState.First ? MixPose.Setup : currentPose;
-//                        var rotateTimeline = timeline as RotateTimeline;
-//                        if (rotateTimeline != NULL)
-//                            applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
-//                        else
-//                            timeline.apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection.In);
-//                    }
-//                }
-//                queueEvents(current, animationTime);
-//                events.clear(false);
-//                current.nextAnimationLast = animationTime;
-//                current.nextTrackLast = current.trackTime;
-//            }
-//
-//            queue.drain();
-            return applied;
-        }
+        bool apply(Skeleton& skeleton);
         
         ///
         /// Removes all animations from all tracks, leaving skeletons in their previous pose.
         /// It may be desired to use AnimationState.setEmptyAnimations(float) to mix the skeletons back to the setup pose,
         /// rather than leaving them in their previous pose.
-        void clearTracks()
-        {
-//            bool olddrainDisabled = queue.drainDisabled;
-//            queue.drainDisabled = true;
-//            for (int i = 0, n = tracks.Count; i < n; i++) {
-//                clearTrack(i);
-//            }
-//            tracks.clear();
-//            queue.drainDisabled = olddrainDisabled;
-//            queue.drain();
-        }
+        void clearTracks();
         
         ///
         /// Removes all animations from the tracks, leaving skeletons in their previous pose.
         /// It may be desired to use AnimationState.setEmptyAnimations(float) to mix the skeletons back to the setup pose,
         /// rather than leaving them in their previous pose.
-        void clearTrack(int trackIndex)
-        {
-//            if (trackIndex >= tracks.Count) return;
-//            TrackEntry current = tracks.Items[trackIndex];
-//            if (current == NULL) return;
-//
-//            queue.end(current);
-//
-//            disposeNext(current);
-//
-//            TrackEntry entry = current;
-//            while (true) {
-//                TrackEntry from = entry.mixingFrom;
-//                if (from == NULL) break;
-//                queue.end(from);
-//                entry.mixingFrom = NULL;
-//                entry = from;
-//            }
-//
-//            tracks.Items[current.trackIndex] = NULL;
-//
-//            queue.drain();
-        }
+        void clearTrack(int trackIndex);
         
         /// Sets an animation by name. setAnimation(int, Animation, bool)
-        TrackEntry* setAnimation(int trackIndex, std::string animationName, bool loop)
-        {
-//            Animation animation = data.skeletonData.FindAnimation(animationName);
-//            if (animation == NULL) throw new ArgumentException("Animation not found: " + animationName, "animationName");
-//            return setAnimation(trackIndex, animation, loop);
-            return NULL;
-        }
+        TrackEntry* setAnimation(int trackIndex, std::string animationName, bool loop);
         
         /// Sets the current animation for a track, discarding any queued animations.
         /// @param loop If true, the animation will repeat.
@@ -480,39 +329,11 @@ namespace Spine
         /// @return
         /// A track entry to allow further customization of animation playback. References to the track entry must not be kept
         /// after AnimationState.Dispose.
-        TrackEntry* setAnimation(int trackIndex, Animation& animation, bool loop)
-        {
-//            bool interrupt = true;
-//            TrackEntry current = expandToIndex(trackIndex);
-//            if (current != NULL) {
-//                if (current.nextTrackLast == -1) {
-//                    // Don't mix from an entry that was never applied.
-//                    tracks.Items[trackIndex] = current.mixingFrom;
-//                    queue.interrupt(current);
-//                    queue.end(current);
-//                    disposeNext(current);
-//                    current = current.mixingFrom;
-//                    interrupt = false;
-//                } else {
-//                    disposeNext(current);
-//                }
-//            }
-//            TrackEntry entry = newTrackEntry(trackIndex, animation, loop, current);
-//            setCurrent(trackIndex, entry, interrupt);
-//            queue.drain();
-//            return entry;
-            return NULL;
-        }
+        TrackEntry* setAnimation(int trackIndex, Animation* animation, bool loop);
         
         /// Queues an animation by name.
         /// addAnimation(int, Animation, bool, float)
-        TrackEntry* addAnimation(int trackIndex, std::string animationName, bool loop, float delay)
-        {
-//            Animation animation = data.skeletonData.FindAnimation(animationName);
-//            if (animation == NULL) throw new ArgumentException("Animation not found: " + animationName, "animationName");
-//            return addAnimation(trackIndex, animation, loop, delay);
-            return NULL;
-        }
+        TrackEntry* addAnimation(int trackIndex, std::string animationName, bool loop, float delay);
         
         /// Adds an animation to be played delay seconds after the current or last queued animation
         /// for a track. If the track is empty, it is equivalent to calling setAnimation.
@@ -522,44 +343,11 @@ namespace Spine
         ///
         /// @return A track entry to allow further customization of animation playback. References to the track entry must not be kept
         /// after AnimationState.Dispose
-        TrackEntry* addAnimation(int trackIndex, Animation& animation, bool loop, float delay)
-        {
-//            TrackEntry last = expandToIndex(trackIndex);
-//            if (last != NULL) {
-//                while (last.next != NULL)
-//                    last = last.next;
-//            }
-//
-//            TrackEntry entry = newTrackEntry(trackIndex, animation, loop, last);
-//
-//            if (last == NULL) {
-//                setCurrent(trackIndex, entry, true);
-//                queue.drain();
-//            } else {
-//                last.next = entry;
-//                if (delay <= 0) {
-//                    float duration = last.animationEnd - last.animationStart;
-//                    if (duration != 0)
-//                        delay += duration * (1 + (int)(last.trackTime / duration)) - data.GetMix(last.animation, animation);
-//                    else
-//                        delay = 0;
-//                }
-//            }
-//
-//            entry.delay = delay;
-//            return entry;
-            return NULL;
-        }
+        TrackEntry* addAnimation(int trackIndex, Animation* animation, bool loop, float delay);
         
         ///
         /// Sets an empty animation for a track, discarding any queued animations, and mixes to it over the specified mix duration.
-        TrackEntry* setEmptyAnimation(int trackIndex, float mixDuration)
-        {
-            TrackEntry* entry = setAnimation(trackIndex, AnimationState::getEmptyAnimation(), false);
-            entry->_mixDuration = mixDuration;
-            entry->_trackEnd = mixDuration;
-            return entry;
-        }
+        TrackEntry* setEmptyAnimation(int trackIndex, float mixDuration);
         
         ///
         /// Adds an empty animation to be played after the current or last queued animation for a track, and mixes to it over the
@@ -571,44 +359,22 @@ namespace Spine
         /// @param mixDuration Mix duration.
         /// @param delay Seconds to begin this animation after the start of the previous animation. May be &lt;= 0 to use the animation
         /// duration of the previous track minus any mix duration plus the negative delay.
-        TrackEntry* addEmptyAnimation(int trackIndex, float mixDuration, float delay)
-        {
-            if (delay <= 0)
-            {
-                delay -= mixDuration;
-            }
-            
-            TrackEntry* entry = addAnimation(trackIndex, AnimationState::getEmptyAnimation(), false, delay);
-            entry->_mixDuration = mixDuration;
-            entry->_trackEnd = mixDuration;
-            return entry;
-        }
+        TrackEntry* addEmptyAnimation(int trackIndex, float mixDuration, float delay);
         
         ///
         /// Sets an empty animation for every track, discarding any queued animations, and mixes to it over the specified mix duration.
-        void setEmptyAnimations(float mixDuration)
-        {
-//            bool olddrainDisabled = queue.drainDisabled;
-//            queue.drainDisabled = true;
-//            for (int i = 0, n = tracks.Count; i < n; i++)
-//            {
-//                TrackEntry current = tracks.Items[i];
-//                if (current != NULL) setEmptyAnimation(i, mixDuration);
-//            }
-//            queue.drainDisabled = olddrainDisabled;
-//            queue.drain();
-        }
+        void setEmptyAnimations(float mixDuration);
         
         /// @return The track entry for the animation currently playing on the track, or NULL if no animation is currently playing.
-        TrackEntry* getCurrent(int trackIndex)
-        {
-            return trackIndex >= _tracks.size() ? NULL : _tracks[trackIndex];
-        }
+        TrackEntry* getCurrent(int trackIndex);
         
-//        AnimationStateData Data { get { return data; } }
-//        /// A list of tracks that have animations, which may contain NULLs.
-//        Vector<TrackEntry> Tracks { get { return tracks; } }
-//        float TimeScale { get { return timeScale; } set { timeScale = value; } }
+        AnimationStateData& getData();
+        
+        /// A list of tracks that have animations, which may contain NULLs.
+        Vector<TrackEntry*> getTracks();
+        float getTimeScale();
+        void setTimeScale(float inValue);
+        void setOnAnimationEventFunc(OnAnimationEventFunc inValue);
         
     private:
         static const int Subsequent, First, Dip, DipMix;
@@ -617,306 +383,41 @@ namespace Spine
 
         Pool<TrackEntry> _trackEntryPool;
         Vector<TrackEntry*> _tracks;
-        Vector<Event> _events;
+        Vector<Event*> _events;
         EventQueue* _queue;
 
         Vector<int> _propertyIDs;
-        Vector<TrackEntry> _mixingTo;
+        Vector<TrackEntry*> _mixingTo;
         bool _animationsChanged;
 
         OnAnimationEventFunc _onAnimationEventFunc;
         
         float _timeScale;
 
-        static Animation& getEmptyAnimation();
-        
-        static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixPose pose,
-                                        Vector<float>& timelinesRotation, int i, bool firstFrame)
-        {
-//            if (firstFrame) timelinesRotation[i] = 0;
-//            
-//            if (alpha == 1) {
-//                rotateTimeline.apply(skeleton, 0, time, NULL, 1, pose, MixDirection.In);
-//                return;
-//            }
-//            
-//            Bone bone = skeleton.bones.Items[rotateTimeline.boneIndex];
-//            float[] frames = rotateTimeline.frames;
-//            if (time < frames[0]) {
-//                if (pose == MixPose.Setup) bone.rotation = bone.data.rotation;
-//                return;
-//            }
-//            
-//            float r2;
-//            if (time >= frames[frames.Length - RotateTimeline.ENTRIES]) // Time is after last frame.
-//                r2 = bone.data.rotation + frames[frames.Length + RotateTimeline.PREV_ROTATION];
-//            else {
-//                // Interpolate between the previous frame and the current frame.
-//                int frame = Animation.BinarySearch(frames, time, RotateTimeline.ENTRIES);
-//                float prevRotation = frames[frame + RotateTimeline.PREV_ROTATION];
-//                float frameTime = frames[frame];
-//                float percent = rotateTimeline.GetCurvePercent((frame >> 1) - 1,
-//                                                               1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime));
-//                
-//                r2 = frames[frame + RotateTimeline.ROTATION] - prevRotation;
-//                r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
-//                r2 = prevRotation + r2 * percent + bone.data.rotation;
-//                r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
-//            }
-//            
-//            // Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
-//            float r1 = pose == MixPose.Setup ? bone.data.rotation : bone.rotation;
-//            float total, diff = r2 - r1;
-//            if (diff == 0) {
-//                total = timelinesRotation[i];
-//            } else {
-//                diff -= (16384 - (int)(16384.499999999996 - diff / 360)) * 360;
-//                float lastTotal, lastDiff;
-//                if (firstFrame) {
-//                    lastTotal = 0;
-//                    lastDiff = diff;
-//                } else {
-//                    lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops.
-//                    lastDiff = timelinesRotation[i + 1]; // Difference between bones.
-//                }
-//                bool current = diff > 0, dir = lastTotal >= 0;
-//                // Detect cross at 0 (not 180).
-//                if (Math.Sign(lastDiff) != Math.Sign(diff) && Math.Abs(lastDiff) <= 90) {
-//                    // A cross after a 360 rotation is a loop.
-//                    if (Math.Abs(lastTotal) > 180) lastTotal += 360 * Math.Sign(lastTotal);
-//                    dir = current;
-//                }
-//                total = diff + lastTotal - lastTotal % 360; // Store loops as part of lastTotal.
-//                if (dir != current) total += 360 * Math.Sign(lastTotal);
-//                timelinesRotation[i] = total;
-//            }
-//            timelinesRotation[i + 1] = diff;
-//            r1 += total * alpha;
-//            bone.rotation = r1 - (16384 - (int)(16384.499999999996 - r1 / 360)) * 360;
-        }
+        static Animation* getEmptyAnimation();
+        
+        static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixPose pose, Vector<float>& timelinesRotation, int i, bool firstFrame);
         
         /// Returns true when all mixing from entries are complete.
-        bool updateMixingFrom(TrackEntry to, float delta)
-        {
-//            TrackEntry from = to.mixingFrom;
-//            if (from == NULL) return true;
-//
-//            bool finished = updateMixingFrom(from, delta);
-//
-//            // Require mixTime > 0 to ensure the mixing from entry was applied at least once.
-//            if (to.mixTime > 0 && (to.mixTime >= to.mixDuration || to.timeScale == 0)) {
-//                // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).
-//                if (from.totalAlpha == 0 || to.mixDuration == 0) {
-//                    to.mixingFrom = from.mixingFrom;
-//                    to.interruptAlpha = from.interruptAlpha;
-//                    queue.end(from);
-//                }
-//                return finished;
-//            }
-//
-//            from.animationLast = from.nextAnimationLast;
-//            from.trackLast = from.nextTrackLast;
-//            from.trackTime += delta * from.timeScale;
-//            to.mixTime += delta * to.timeScale;
-            return false;
-        }
-        
-        float applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixPose currentPose)
-        {
-//            TrackEntry from = to.mixingFrom;
-//            if (from.mixingFrom != NULL) applyMixingFrom(from, skeleton, currentPose);
-//
-//            float mix;
-//            if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
-//                mix = 1;
-//                currentPose = MixPose.Setup;
-//            } else {
-//                mix = to.mixTime / to.mixDuration;
-//                if (mix > 1) mix = 1;
-//            }
-//
-//            var eventBuffer = mix < from.eventThreshold ? _events : NULL;
-//            bool attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold;
-//            float animationLast = from.animationLast, animationTime = from.AnimationTime;
-//            var timelines = from.animation.timelines;
-//            int timelineCount = timelines.Count;
-//            var timelinesItems = timelines.Items;
-//            var timelineData = from.timelineData.Items;
-//            var timelineDipMix = from.timelineDipMix.Items;
-//
-//            bool firstFrame = from.timelinesRotation.Count == 0;
-//            if (firstFrame) from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize
-//            var timelinesRotation = from.timelinesRotation.Items;
-//
-//            MixPose pose;
-//            float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
-//            from.totalAlpha = 0;
-//            for (int i = 0; i < timelineCount; i++) {
-//                Timeline timeline = timelinesItems[i];
-//                switch (timelineData[i]) {
-//                    case Subsequent:
-//                        if (!attachments && timeline is AttachmentTimeline) continue;
-//                        if (!drawOrder && timeline is DrawOrderTimeline) continue;
-//                        pose = currentPose;
-//                        alpha = alphaMix;
-//                        break;
-//                    case First:
-//                        pose = MixPose.Setup;
-//                        alpha = alphaMix;
-//                        break;
-//                    case Dip:
-//                        pose = MixPose.Setup;
-//                        alpha = alphaDip;
-//                        break;
-//                    default:
-//                        pose = MixPose.Setup;
-//                        TrackEntry dipMix = timelineDipMix[i];
-//                        alpha = alphaDip * Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
-//                        break;
-//                }
-//                from.totalAlpha += alpha;
-//                var rotateTimeline = timeline as RotateTimeline;
-//                if (rotateTimeline != NULL) {
-//                    applyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame);
-//                } else {
-//                    timeline.apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection.Out);
-//                }
-//            }
-//
-//            if (to.mixDuration > 0) queueEvents(from, animationTime);
-//            _events.clear(false);
-//            from.nextAnimationLast = animationTime;
-//            from.nextTrackLast = from.trackTime;
-//
-//            return mix;
-            return 0;
-        }
-        
-        void queueEvents(TrackEntry* entry, float animationTime)
-        {
-//            float animationStart = entry.animationStart, animationEnd = entry.animationEnd;
-//            float duration = animationEnd - animationStart;
-//            float trackLastWrapped = entry.trackLast % duration;
-//
-//            // Queue events before complete.
-//            var events = _events;
-//            var eventsItems = events.Items;
-//            int i = 0, n = events.Count;
-//            for (; i < n; i++) {
-//                var e = eventsItems[i];
-//                if (e.time < trackLastWrapped) break;
-//                if (e.time > animationEnd) continue; // Discard events outside animation start/end.
-//                queue.event(entry, e);
-//            }
-//
-//            // Queue complete if completed a loop iteration or the animation.
-//            if (entry.loop ? (trackLastWrapped > entry.trackTime % duration)
-//                : (animationTime >= animationEnd && entry.animationLast < animationEnd)) {
-//                queue.complete(entry);
-//            }
-//
-//            // Queue events after complete.
-//            for (; i < n; i++) {
-//                Event e = eventsItems[i];
-//                if (e.time < animationStart) continue; // Discard events outside animation start/end.
-//                queue.event(entry, eventsItems[i]);
-//            }
-        }
+        bool updateMixingFrom(TrackEntry* to, float delta);
+        
+        float applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixPose currentPose);
+        
+        void queueEvents(TrackEntry* entry, float animationTime);
         
         /// Sets the active TrackEntry for a given track number.
-        void setCurrent(int index, TrackEntry* current, bool interrupt)
-        {
-//            TrackEntry from = expandToIndex(index);
-//            tracks.Items[index] = current;
-//
-//            if (from != NULL) {
-//                if (interrupt) queue.interrupt(from);
-//                current.mixingFrom = from;
-//                current.mixTime = 0;
-//
-//                // Store interrupted mix percentage.
-//                if (from.mixingFrom != NULL && from.mixDuration > 0)
-//                    current.interruptAlpha *= Math.Min(1, from.mixTime / from.mixDuration);
-//
-//                from.timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in.
-//            }
-//
-//            queue.start(current); // triggers animationsChanged
-        }
+        void setCurrent(int index, TrackEntry* current, bool interrupt);
 
-        TrackEntry* expandToIndex(int index)
-        {
-//            if (index < tracks.Count) return tracks.Items[index];
-//            while (index >= tracks.Count)
-//            {
-//                tracks.Add(NULL);
-//            }
-            return NULL;
-        }
+        TrackEntry* expandToIndex(int index);
 
         /// Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values.
         /// @param last May be NULL.
-        TrackEntry* newTrackEntry(int trackIndex, Animation* animation, bool loop, TrackEntry* last)
-        {
-//            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; // nextTrackLast == -1 signifies a TrackEntry that wasn't applied yet.
-//            entry.trackEnd = float.MaxValue; // loop ? float.MaxValue : animation.Duration;
-//            entry.timeScale = 1;
-//
-//            entry.alpha = 1;
-//            entry.interruptAlpha = 1;
-//            entry.mixTime = 0;
-//            entry.mixDuration = (last == NULL) ? 0 : data.GetMix(last.animation, animation);
-//            return entry;
-            return NULL;
-        }
+        TrackEntry* newTrackEntry(int trackIndex, Animation* animation, bool loop, TrackEntry* last);
 
         /// Dispose all track entries queued after the given TrackEntry.
-        void disposeNext(TrackEntry* entry)
-        {
-//            TrackEntry next = entry.next;
-//            while (next != NULL)
-//            {
-//                queue.dispose(next);
-//                next = next.next;
-//            }
-//            entry.next = NULL;
-        }
+        void disposeNext(TrackEntry* entry);
 
-        void animationsChanged()
-        {
-//            animationsChanged = false;
-//
-//            var propertyIDs = _propertyIDs;
-//            propertyIDs.clear();
-//            var mixingTo = _mixingTo;
-//
-//            var tracksItems = tracks.Items;
-//            for (int i = 0, n = tracks.Count; i < n; i++)
-//            {
-//                var entry = tracksItems[i];
-//                if (entry != NULL)
-//                {
-//                    entry.setTimelineData(NULL, mixingTo, propertyIDs);
-//                }
-//            }
-        }
+        void animationsChanged();
     };
 }
 

+ 2 - 0
spine-cpp/spine-cpp/include/spine/AnimationStateData.h

@@ -44,6 +44,8 @@ namespace Spine
     /// Stores mix (crossfade) durations to be applied when AnimationState animations are changed.
     class AnimationStateData
     {
+        friend class AnimationState;
+        
     public:
         /// The SkeletonData to look up animations when they are specified by name.
         SkeletonData& getSkeletonData();

+ 1 - 1
spine-cpp/spine-cpp/include/spine/AttachmentTimeline.h

@@ -51,7 +51,7 @@ namespace Spine
     public:
         AttachmentTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 2 - 0
spine-cpp/spine-cpp/include/spine/Bone.h

@@ -49,6 +49,8 @@ namespace Spine
     {
         RTTI_DECL;
         
+        friend class AnimationState;
+        
         friend class RotateTimeline;
         friend class IkConstraint;
         friend class TransformConstraint;

+ 2 - 0
spine-cpp/spine-cpp/include/spine/BoneData.h

@@ -39,6 +39,8 @@ namespace Spine
 {
     class BoneData
     {
+        friend class AnimationState;
+        
         friend class RotateTimeline;
         friend class ScaleTimeline;
         friend class ShearTimeline;

+ 1 - 1
spine-cpp/spine-cpp/include/spine/ColorTimeline.h

@@ -44,7 +44,7 @@ namespace Spine
         
         ColorTimeline (int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/CurveTimeline.h

@@ -46,7 +46,7 @@ namespace Spine
     public:
         CurveTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction) = 0;
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction) = 0;
         
         virtual int getPropertyId() = 0;
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/DeformTimeline.h

@@ -44,7 +44,7 @@ namespace Spine
     public:
         DeformTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/DrawOrderTimeline.h

@@ -42,7 +42,7 @@ namespace Spine
     public:
         DrawOrderTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 2 - 0
spine-cpp/spine-cpp/include/spine/Event.h

@@ -40,6 +40,8 @@ namespace Spine
     /// Stores the current pose values for an Event.
     class Event
     {
+        friend class AnimationState;
+        
     public:
         Event(float time, const EventData& data);
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/EventTimeline.h

@@ -42,7 +42,7 @@ namespace Spine
     public:
         EventTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/IkConstraintTimeline.h

@@ -44,7 +44,7 @@ namespace Spine
         
         IkConstraintTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 6 - 0
spine-cpp/spine-cpp/include/spine/MathUtil.h

@@ -50,6 +50,12 @@
 
 namespace Spine
 {
+    template <typename T>
+    int sign(T val)
+    {
+        return (T(0) < val) - (val < T(0));
+    }
+    
     inline bool areFloatsPracticallyEqual(float A, float B, float maxDiff = 0.0000000000000001f, float maxRelDiff = FLT_EPSILON)
     {
         // Check if the numbers are really close -- needed

+ 1 - 1
spine-cpp/spine-cpp/include/spine/PathConstraintMixTimeline.h

@@ -44,7 +44,7 @@ namespace Spine
         
         PathConstraintMixTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/PathConstraintPositionTimeline.h

@@ -44,7 +44,7 @@ namespace Spine
         
         PathConstraintPositionTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/PathConstraintSpacingTimeline.h

@@ -42,7 +42,7 @@ namespace Spine
     public:
         PathConstraintSpacingTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
     };

+ 3 - 1
spine-cpp/spine-cpp/include/spine/RotateTimeline.h

@@ -37,6 +37,8 @@ namespace Spine
 {
     class RotateTimeline : public CurveTimeline
     {
+        friend class AnimationState;
+        
         RTTI_DECL;
         
     public:
@@ -44,7 +46,7 @@ namespace Spine
         
         RotateTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/ScaleTimeline.h

@@ -42,7 +42,7 @@ namespace Spine
     public:
         ScaleTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
     };

+ 1 - 1
spine-cpp/spine-cpp/include/spine/ShearTimeline.h

@@ -42,7 +42,7 @@ namespace Spine
     public:
         ShearTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
     };

+ 1 - 0
spine-cpp/spine-cpp/include/spine/Skeleton.h

@@ -51,6 +51,7 @@ namespace Spine
     
     class Skeleton
     {
+        friend class AnimationState;
         friend class SkeletonBounds;
         friend class SkeletonClipping;
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/Timeline.h

@@ -61,7 +61,7 @@ namespace Spine
         ///      apply animations on top of each other (layered).
         /// @param pose Controls how mixing is applied when alpha is than 1.
         /// @param direction Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions such as DrawOrderTimeline and AttachmentTimeline.
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction) = 0;
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction) = 0;
         
         virtual int getPropertyId() = 0;
     };

+ 1 - 1
spine-cpp/spine-cpp/include/spine/TransformConstraintTimeline.h

@@ -44,7 +44,7 @@ namespace Spine
         
         TransformConstraintTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/TranslateTimeline.h

@@ -47,7 +47,7 @@ namespace Spine
         
         TranslateTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 1 - 1
spine-cpp/spine-cpp/include/spine/TwoColorTimeline.h

@@ -44,7 +44,7 @@ namespace Spine
         
         TwoColorTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
         
         virtual int getPropertyId();
         

+ 2 - 2
spine-cpp/spine-cpp/src/spine/Animation.cpp

@@ -47,7 +47,7 @@ namespace Spine
         assert(_name.length() > 0);
     }
     
-    void Animation::apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void Animation::apply(Skeleton& skeleton, float lastTime, float time, bool loop, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         if (loop && _duration != 0)
         {
@@ -60,7 +60,7 @@ namespace Spine
         
         for (int i = 0, n = static_cast<int>(_timelines.size()); i < n; ++i)
         {
-            _timelines[i]->apply(skeleton, lastTime, time, events, alpha, pose, direction);
+            _timelines[i]->apply(skeleton, lastTime, time, pEvents, alpha, pose, direction);
         }
     }
     

+ 741 - 2
spine-cpp/spine-cpp/src/spine/AnimationState.cpp

@@ -37,6 +37,11 @@
 #include <spine/RotateTimeline.h>
 
 #include <spine/Timeline.h>
+#include <spine/SkeletonData.h>
+#include <spine/Bone.h>
+#include <spine/BoneData.h>
+#include <spine/AttachmentTimeline.h>
+#include <spine/DrawOrderTimeline.h>
 
 #include <spine/MathUtil.h>
 #include <spine/ContainerUtil.h>
@@ -325,6 +330,7 @@ namespace Spine
                 case EventType_Dispose:
                     trackEntry->_onAnimationEventFunc(state, EventType_Dispose, trackEntry, NULL);
                     state._onAnimationEventFunc(state, EventType_Dispose, trackEntry, NULL);
+                    trackEntry->reset();
                     _trackEntryPool.free(trackEntry);
                     break;
                 case EventType_Event:
@@ -357,15 +363,748 @@ namespace Spine
         DESTROY(EventQueue, _queue);
     }
     
+    void AnimationState::update(float delta)
+    {
+        delta *= _timeScale;
+        for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
+        {
+            TrackEntry* currentP = _tracks[i];
+            if (currentP == NULL)
+            {
+                continue;
+            }
+            
+            TrackEntry& current = *currentP;
+            
+            current._animationLast = current._nextAnimationLast;
+            current._trackLast = current._nextTrackLast;
+            
+            float currentDelta = delta * current._timeScale;
+            
+            if (current._delay > 0)
+            {
+                current._delay -= currentDelta;
+                if (current._delay > 0)
+                {
+                    continue;
+                }
+                currentDelta = -current._delay;
+                current._delay = 0;
+            }
+            
+            TrackEntry* next = current._next;
+            if (next != NULL)
+            {
+                // When the next entry's delay is passed, change to the next entry, preserving leftover time.
+                float nextTime = current._trackLast - next->_delay;
+                if (nextTime >= 0)
+                {
+                    next->_delay = 0;
+                    next->_trackTime = nextTime + (delta * next->_timeScale);
+                    current._trackTime += currentDelta;
+                    setCurrent(i, next, true);
+                    while (next->_mixingFrom != NULL)
+                    {
+                        next->_mixTime += currentDelta;
+                        next = next->_mixingFrom;
+                    }
+                    continue;
+                }
+            }
+            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.
+                _tracks[i] = NULL;
+                
+                _queue->end(currentP);
+                disposeNext(currentP);
+                continue;
+            }
+            
+            if (current._mixingFrom != NULL && updateMixingFrom(currentP, delta))
+            {
+                // End mixing from entries once all have completed.
+                TrackEntry* from = current._mixingFrom;
+                current._mixingFrom = NULL;
+                while (from != NULL)
+                {
+                    _queue->end(from);
+                    from = from->_mixingFrom;
+                }
+            }
+            
+            current._trackTime += currentDelta;
+        }
+        
+        _queue->drain();
+    }
+    
+    bool AnimationState::apply(Skeleton& skeleton)
+    {
+        if (_animationsChanged)
+        {
+            animationsChanged();
+        }
+        
+        bool applied = false;
+        for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
+        {
+            TrackEntry* currentP = _tracks[i];
+            if (currentP == NULL || currentP->_delay > 0)
+            {
+                continue;
+            }
+            
+            TrackEntry& current = *currentP;
+            
+            applied = true;
+            MixPose currentPose = i == 0 ? MixPose_Current : MixPose_CurrentLayered;
+            
+            // apply mixing from entries first.
+            float mix = current._alpha;
+            if (current._mixingFrom != NULL)
+            {
+                mix *= applyMixingFrom(currentP, skeleton, currentPose);
+            }
+            else if (current._trackTime >= current._trackEnd && current._next == NULL) //
+            {
+                mix = 0; // Set to setup pose the last time the entry will be applied.
+            }
+            
+            // apply current entry.
+            float animationLast = current._animationLast, animationTime = current.getAnimationTime();
+            int timelineCount = static_cast<int>(current._animation->_timelines.size());
+            Vector<Timeline*>& timelines = current._animation->_timelines;
+            if (mix == 1)
+            {
+                for (int ii = 0; ii < timelineCount; ++ii)
+                {
+                    timelines[ii]->apply(skeleton, animationLast, animationTime, &_events, 1, MixPose_Setup, MixDirection_In);
+                }
+            }
+            else
+            {
+                Vector<int>& timelineData = current._timelineData;
+                
+                bool firstFrame = current._timelinesRotation.size() == 0;
+                if (firstFrame)
+                {
+                    current._timelinesRotation.reserve(timelines.size() << 1);
+                }
+                Vector<float>& timelinesRotation = current._timelinesRotation;
+                
+                for (int ii = 0; ii < timelineCount; ++ii)
+                {
+                    Timeline* timeline = timelines[ii];
+                    assert(timeline);
+                    
+                    MixPose pose = timelineData[ii] >= AnimationState::First ? MixPose_Setup : currentPose;
+                    
+                    RotateTimeline* rotateTimeline = NULL;
+                    if (timeline->getRTTI().derivesFrom(RotateTimeline::rtti))
+                    {
+                        rotateTimeline = static_cast<RotateTimeline*>(timeline);
+                    }
+                    
+                    if (rotateTimeline != NULL)
+                    {
+                        applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
+                    }
+                    else
+                    {
+                        timeline->apply(skeleton, animationLast, animationTime, &_events, mix, pose, MixDirection_In);
+                    }
+                }
+            }
+            
+            queueEvents(currentP, animationTime);
+            _events.clear();
+            current._nextAnimationLast = animationTime;
+            current._nextTrackLast = current._trackTime;
+        }
+        
+        _queue->drain();
+        return applied;
+    }
+    
+    void AnimationState::clearTracks()
+    {
+        bool oldDrainDisabled = _queue->_drainDisabled;
+        _queue->_drainDisabled = true;
+        for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
+        {
+            clearTrack(i);
+        }
+        _tracks.clear();
+        _queue->_drainDisabled = oldDrainDisabled;
+        _queue->drain();
+    }
+    
+    void AnimationState::clearTrack(int trackIndex)
+    {
+        if (trackIndex >= _tracks.size())
+        {
+            return;
+        }
+        
+        TrackEntry* current = _tracks[trackIndex];
+        if (current == NULL)
+        {
+            return;
+        }
+        
+        _queue->end(current);
+        
+        disposeNext(current);
+        
+        TrackEntry* entry = current;
+        while (true)
+        {
+            TrackEntry* from = entry->_mixingFrom;
+            if (from == NULL)
+            {
+                break;
+            }
+            
+            _queue->end(from);
+            entry->_mixingFrom = NULL;
+            entry = from;
+        }
+        
+        _tracks[current->_trackIndex] = NULL;
+        
+        _queue->drain();
+    }
+    
+    TrackEntry* AnimationState::setAnimation(int trackIndex, std::string animationName, bool loop)
+    {
+        Animation* animation = _data._skeletonData.findAnimation(animationName);
+        assert(animation != NULL);
+        
+        return setAnimation(trackIndex, animation, loop);
+    }
+    
+    TrackEntry* AnimationState::setAnimation(int trackIndex, Animation* animation, bool loop)
+    {
+        assert(animation != NULL);
+        
+        bool interrupt = true;
+        TrackEntry* current = expandToIndex(trackIndex);
+        if (current != NULL)
+        {
+            if (current->_nextTrackLast == -1)
+            {
+                // Don't mix from an entry that was never applied.
+                _tracks[trackIndex] = current->_mixingFrom;
+                _queue->interrupt(current);
+                _queue->end(current);
+                disposeNext(current);
+                current = current->_mixingFrom;
+                interrupt = false;
+            }
+            else
+            {
+                disposeNext(current);
+            }
+        }
+        
+        TrackEntry* entry = newTrackEntry(trackIndex, animation, loop, current);
+        setCurrent(trackIndex, entry, interrupt);
+        _queue->drain();
+        
+        return entry;
+    }
+    
+    TrackEntry* AnimationState::addAnimation(int trackIndex, std::string animationName, bool loop, float delay)
+    {
+        Animation* animation = _data._skeletonData.findAnimation(animationName);
+        assert(animation != NULL);
+        
+        return addAnimation(trackIndex, animation, loop, delay);
+    }
+    
+    TrackEntry* AnimationState::addAnimation(int trackIndex, Animation* animation, bool loop, float delay)
+    {
+        assert(animation != NULL);
+        
+        TrackEntry* last = expandToIndex(trackIndex);
+        if (last != NULL)
+        {
+            while (last->_next != NULL)
+            {
+                last = last->_next;
+            }
+        }
+        
+        TrackEntry* entry = newTrackEntry(trackIndex, animation, loop, last);
+        
+        if (last == NULL)
+        {
+            setCurrent(trackIndex, entry, true);
+            _queue->drain();
+        }
+        else
+        {
+            last->_next = entry;
+            if (delay <= 0)
+            {
+                float duration = last->_animationEnd - last->_animationStart;
+                if (duration != 0)
+                {
+                    delay += duration * (1 + (int)(last->_trackTime / duration)) - _data.getMix(last->_animation, animation);
+                }
+                else
+                {
+                    delay = 0;
+                }
+            }
+        }
+        
+        entry->_delay = delay;
+        return entry;
+    }
+    
+    TrackEntry* AnimationState::setEmptyAnimation(int trackIndex, float mixDuration)
+    {
+        TrackEntry* entry = setAnimation(trackIndex, AnimationState::getEmptyAnimation(), false);
+        entry->_mixDuration = mixDuration;
+        entry->_trackEnd = mixDuration;
+        return entry;
+    }
+    
+    TrackEntry* AnimationState::addEmptyAnimation(int trackIndex, float mixDuration, float delay)
+    {
+        if (delay <= 0)
+        {
+            delay -= mixDuration;
+        }
+        
+        TrackEntry* entry = addAnimation(trackIndex, AnimationState::getEmptyAnimation(), false, delay);
+        entry->_mixDuration = mixDuration;
+        entry->_trackEnd = mixDuration;
+        return entry;
+    }
+    
+    void AnimationState::setEmptyAnimations(float mixDuration)
+    {
+        bool oldDrainDisabled = _queue->_drainDisabled;
+        _queue->_drainDisabled = true;
+        for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
+        {
+            TrackEntry* current = _tracks[i];
+            if (current != NULL)
+            {
+                setEmptyAnimation(i, mixDuration);
+            }
+        }
+        _queue->_drainDisabled = oldDrainDisabled;
+        _queue->drain();
+    }
+    
+    TrackEntry* AnimationState::getCurrent(int trackIndex)
+    {
+        return trackIndex >= _tracks.size() ? NULL : _tracks[trackIndex];
+    }
+    
+    AnimationStateData& AnimationState::getData()
+    {
+        return _data;
+    }
+    
+    Vector<TrackEntry*> AnimationState::getTracks()
+    {
+        return _tracks;
+    }
+    
+    float AnimationState::getTimeScale()
+    {
+        return _timeScale;
+    }
+    
+    void AnimationState::setTimeScale(float inValue)
+    {
+        _timeScale = inValue;
+    }
+    
     void AnimationState::setOnAnimationEventFunc(OnAnimationEventFunc inValue)
     {
         _onAnimationEventFunc = inValue;
     }
     
-    Animation& AnimationState::getEmptyAnimation()
+    Animation* AnimationState::getEmptyAnimation()
     {
         static Vector<Timeline*> timelines;
         static Animation ret(std::string("<empty>"), timelines, 0);
-        return ret;
+        return &ret;
+    }
+    
+    void AnimationState::applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixPose pose, Vector<float>& timelinesRotation, int i, bool firstFrame)
+    {
+        if (firstFrame)
+        {
+            timelinesRotation[i] = 0;
+        }
+        
+        if (alpha == 1)
+        {
+            rotateTimeline->apply(skeleton, 0, time, NULL, 1, pose, MixDirection_In);
+            return;
+        }
+        
+        Bone* bone = skeleton._bones[rotateTimeline->_boneIndex];
+        Vector<float> frames = rotateTimeline->_frames;
+        if (time < frames[0])
+        {
+            if (pose == MixPose_Setup)
+            {
+                bone->_rotation = bone->_data._rotation;
+            }
+            return;
+        }
+        
+        float r2;
+        if (time >= frames[frames.size() - RotateTimeline::ENTRIES]) // Time is after last frame.
+        {
+            r2 = bone->_data._rotation + frames[frames.size() + RotateTimeline::PREV_ROTATION];
+        }
+        else
+        {
+            // Interpolate between the previous frame and the current frame.
+            int frame = Animation::binarySearch(frames, time, RotateTimeline::ENTRIES);
+            float prevRotation = frames[frame + RotateTimeline::PREV_ROTATION];
+            float frameTime = frames[frame];
+            float percent = rotateTimeline->getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline::PREV_TIME] - frameTime));
+            
+            r2 = frames[frame + RotateTimeline::ROTATION] - prevRotation;
+            r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
+            r2 = prevRotation + r2 * percent + bone->_data._rotation;
+            r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
+        }
+        
+        // Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
+        float r1 = pose == MixPose_Setup ? bone->_data._rotation : bone->_rotation;
+        float total, diff = r2 - r1;
+        if (diff == 0)
+        {
+            total = timelinesRotation[i];
+        }
+        else
+        {
+            diff -= (16384 - (int)(16384.499999999996 - diff / 360)) * 360;
+            float lastTotal, lastDiff;
+            if (firstFrame)
+            {
+                lastTotal = 0;
+                lastDiff = diff;
+            }
+            else
+            {
+                lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops.
+                lastDiff = timelinesRotation[i + 1]; // Difference between bones.
+            }
+            
+            bool current = diff > 0, dir = lastTotal >= 0;
+            // Detect cross at 0 (not 180).
+            if (sign(lastDiff) != sign(diff) && abs(lastDiff) <= 90)
+            {
+                // A cross after a 360 rotation is a loop.
+                if (abs(lastTotal) > 180)
+                {
+                    lastTotal += 360 * sign(lastTotal);
+                }
+                dir = current;
+            }
+            
+            total = diff + lastTotal - fmod(lastTotal, 360); // Store loops as part of lastTotal.
+            if (dir != current)
+            {
+                total += 360 * sign(lastTotal);
+            }
+            timelinesRotation[i] = total;
+        }
+        timelinesRotation[i + 1] = diff;
+        r1 += total * alpha;
+        bone->_rotation = r1 - (16384 - (int)(16384.499999999996 - r1 / 360)) * 360;
+    }
+    
+    bool AnimationState::updateMixingFrom(TrackEntry* to, float delta)
+    {
+        TrackEntry* from = to->_mixingFrom;
+        if (from == NULL)
+        {
+            return true;
+        }
+        
+        bool finished = updateMixingFrom(from, delta);
+        
+        // Require mixTime > 0 to ensure the mixing from entry was applied at least once.
+        if (to->_mixTime > 0 && (to->_mixTime >= to->_mixDuration || to->_timeScale == 0))
+        {
+            // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).
+            if (from->_totalAlpha == 0 || to->_mixDuration == 0)
+            {
+                to->_mixingFrom = from->_mixingFrom;
+                to->_interruptAlpha = from->_interruptAlpha;
+                _queue->end(from);
+            }
+            return finished;
+        }
+        
+        from->_animationLast = from->_nextAnimationLast;
+        from->_trackLast = from->_nextTrackLast;
+        from->_trackTime += delta * from->_timeScale;
+        to->_mixTime += delta * to->_timeScale;
+        
+        return false;
+    }
+    
+    float AnimationState::applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixPose currentPose)
+    {
+        TrackEntry* from = to->_mixingFrom;
+        if (from->_mixingFrom != NULL)
+        {
+            applyMixingFrom(from, skeleton, currentPose);
+        }
+        
+        float mix;
+        if (to->_mixDuration == 0)
+        {
+            // Single frame mix to undo mixingFrom changes.
+            mix = 1;
+            currentPose = MixPose_Setup;
+        }
+        else
+        {
+            mix = to->_mixTime / to->_mixDuration;
+            if (mix > 1)
+            {
+                mix = 1;
+            }
+        }
+        
+        Vector<Event*>* eventBuffer = mix < from->_eventThreshold ? &_events : NULL;
+        bool attachments = mix < from->_attachmentThreshold, drawOrder = mix < from->_drawOrderThreshold;
+        float animationLast = from->_animationLast, animationTime = from->getAnimationTime();
+        Vector<Timeline*>& timelines = from->_animation->_timelines;
+        int timelineCount = static_cast<int>(timelines.size());
+        Vector<int>& timelineData = from->_timelineData;
+        Vector<TrackEntry*>& timelineDipMix = from->_timelineDipMix;
+        
+        bool firstFrame = from->_timelinesRotation.size() == 0;
+        if (firstFrame)
+        {
+            // from.timelinesRotation.setSize
+            from->_timelinesRotation.reserve(timelines.size() << 1);
+        }
+        
+        Vector<float>& timelinesRotation = from->_timelinesRotation;
+        
+        MixPose pose;
+        float alphaDip = from->_alpha * to->_interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
+        from->_totalAlpha = 0;
+        for (int i = 0; i < timelineCount; ++i)
+        {
+            Timeline* timeline = timelines[i];
+            switch (timelineData[i])
+            {
+                case Subsequent:
+                    if (!attachments && timeline->getRTTI().derivesFrom(AttachmentTimeline::rtti))
+                    {
+                        continue;
+                    }
+                    if (!drawOrder && timeline->getRTTI().derivesFrom(DrawOrderTimeline::rtti))
+                    {
+                        continue;
+                    }
+                    
+                    pose = currentPose;
+                    alpha = alphaMix;
+                    break;
+                case First:
+                    pose = MixPose_Setup;
+                    alpha = alphaMix;
+                    break;
+                case Dip:
+                    pose = MixPose_Setup;
+                    alpha = alphaDip;
+                    break;
+                default:
+                    pose = MixPose_Setup;
+                    TrackEntry* dipMix = timelineDipMix[i];
+                    alpha = alphaDip * MAX(0, 1 - dipMix->_mixTime / dipMix->_mixDuration);
+                    break;
+            }
+            from->_totalAlpha += alpha;
+            
+            RotateTimeline* rotateTimeline = NULL;
+            if (timeline->getRTTI().derivesFrom(RotateTimeline::rtti))
+            {
+                rotateTimeline = static_cast<RotateTimeline*>(timeline);
+            }
+            
+            if (rotateTimeline != NULL)
+            {
+                applyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame);
+            }
+            else
+            {
+                timeline->apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection_Out);
+            }
+        }
+        
+        if (to->_mixDuration > 0)
+        {
+            queueEvents(from, animationTime);
+        }
+        
+        _events.clear();
+        from->_nextAnimationLast = animationTime;
+        from->_nextTrackLast = from->_trackTime;
+        
+        return mix;
+    }
+    
+    void AnimationState::queueEvents(TrackEntry* entry, float animationTime)
+    {
+        float animationStart = entry->_animationStart, animationEnd = entry->_animationEnd;
+        float duration = animationEnd - animationStart;
+        float trackLastWrapped = fmodf(entry->_trackLast, duration);
+        
+        // Queue events before complete.
+        int i = 0, n = static_cast<int>(_events.size());
+        for (; i < n; ++i)
+        {
+            Event* e = _events[i];
+            if (e->_time < trackLastWrapped)
+            {
+                break;
+            }
+            if (e->_time > animationEnd)
+            {
+                // Discard events outside animation start/end.
+                continue;
+            }
+            _queue->event(entry, e);
+        }
+        
+        // Queue complete if completed a loop iteration or the animation.
+        if (entry->_loop ? (trackLastWrapped > fmod(entry->_trackTime, duration)) : (animationTime >= animationEnd && entry->_animationLast < animationEnd))
+        {
+            _queue->complete(entry);
+        }
+        
+        // Queue events after complete.
+        for (; i < n; ++i)
+        {
+            Event* e = _events[i];
+            if (e->_time < animationStart)
+            {
+                // Discard events outside animation start/end.
+                continue;
+            }
+            _queue->event(entry, _events[i]);
+        }
+    }
+    
+    void AnimationState::setCurrent(int index, TrackEntry* current, bool interrupt)
+    {
+        TrackEntry* from = expandToIndex(index);
+        _tracks[index] = current;
+        
+        if (from != NULL)
+        {
+            if (interrupt)
+            {
+                _queue->interrupt(from);
+            }
+            
+            current->_mixingFrom = from;
+            current->_mixTime = 0;
+            
+            // Store interrupted mix percentage.
+            if (from->_mixingFrom != NULL && from->_mixDuration > 0)
+            {
+                current->_interruptAlpha *= MIN(1, from->_mixTime / from->_mixDuration);
+            }
+            
+            from->_timelinesRotation.clear(); // Reset rotation for mixing out, in case entry was mixed in.
+        }
+        
+        _queue->start(current); // triggers animationsChanged
+    }
+    
+    TrackEntry* AnimationState::expandToIndex(int index)
+    {
+        if (index < _tracks.size())
+        {
+            return _tracks[index];
+        }
+        
+        while (index >= _tracks.size())
+        {
+            _tracks.push_back(NULL);
+        }
+        
+        return NULL;
+    }
+    
+    TrackEntry* AnimationState::newTrackEntry(int trackIndex, Animation* animation, bool loop, TrackEntry* last)
+    {
+        TrackEntry* entryP = _trackEntryPool.obtain(); // Pooling
+        TrackEntry& entry = *entryP;
+        
+        entry._trackIndex = trackIndex;
+        entry._animation = animation;
+        entry._loop = loop;
+        
+        entry._eventThreshold = 0;
+        entry._attachmentThreshold = 0;
+        entry._drawOrderThreshold = 0;
+        
+        entry._animationStart = 0;
+        entry._animationEnd = animation->getDuration();
+        entry._animationLast = -1;
+        entry._nextAnimationLast = -1;
+        
+        entry._delay = 0;
+        entry._trackTime = 0;
+        entry._trackLast = -1;
+        entry._nextTrackLast = -1; // nextTrackLast == -1 signifies a TrackEntry that wasn't applied yet.
+        entry._trackEnd = std::numeric_limits<float>::max(); // loop ? float.MaxValue : animation.Duration;
+        entry._timeScale = 1;
+        
+        entry._alpha = 1;
+        entry._interruptAlpha = 1;
+        entry._mixTime = 0;
+        entry._mixDuration = (last == NULL) ? 0 : _data.getMix(last->_animation, animation);
+        
+        return entryP;
+    }
+    
+    void AnimationState::disposeNext(TrackEntry* entry)
+    {
+        TrackEntry* next = entry->_next;
+        while (next != NULL)
+        {
+            _queue->dispose(next);
+            next = next->_next;
+        }
+        entry->_next = NULL;
+    }
+    
+    void AnimationState::animationsChanged()
+    {
+        _animationsChanged = false;
+        
+        _propertyIDs.clear();
+        
+        for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i)
+        {
+            TrackEntry* entry = _tracks[i];
+            if (entry != NULL)
+            {
+                entry->setTimelineData(NULL, _mixingTo, _propertyIDs);
+            }
+        }
     }
 }

+ 1 - 1
spine-cpp/spine-cpp/src/spine/AttachmentTimeline.cpp

@@ -48,7 +48,7 @@ namespace Spine
         _attachmentNames.reserve(frameCount);
     }
     
-    void AttachmentTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void AttachmentTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         assert(_slotIndex < skeleton._slots.size());
         

+ 1 - 1
spine-cpp/spine-cpp/src/spine/ColorTimeline.cpp

@@ -58,7 +58,7 @@ namespace Spine
         _frames.reserve(frameCount * ENTRIES);
     }
     
-    void ColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void ColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Slot* slotP = skeleton._slots[_slotIndex];
         Slot& slot = *slotP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/DeformTimeline.cpp

@@ -50,7 +50,7 @@ namespace Spine
         _frameVertices.reserve(frameCount);
     }
     
-    void DeformTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void DeformTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Slot* slotP = skeleton._slots[_slotIndex];
         Slot& slot = *slotP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/DrawOrderTimeline.cpp

@@ -48,7 +48,7 @@ namespace Spine
         _drawOrders.reserve(frameCount);
     }
     
-    void DrawOrderTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void DrawOrderTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Vector<Slot*>& drawOrder = skeleton._drawOrder;
         Vector<Slot*>& slots = skeleton._slots;

+ 9 - 2
spine-cpp/spine-cpp/src/spine/EventTimeline.cpp

@@ -49,8 +49,15 @@ namespace Spine
         _events.reserve(frameCount);
     }
     
-    void EventTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void EventTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
+        if (pEvents == NULL)
+        {
+            return;
+        }
+        
+        Vector<Event*>& events = *pEvents;
+        
         if (events.size() == 0)
         {
             return;
@@ -61,7 +68,7 @@ namespace Spine
         if (lastTime > time)
         {
             // Fire events after last time for looped animations.
-            apply(skeleton, lastTime, std::numeric_limits<int>::max(), events, alpha, pose, direction);
+            apply(skeleton, lastTime, std::numeric_limits<int>::max(), pEvents, alpha, pose, direction);
             lastTime = -1.0f;
         }
         else if (lastTime >= _frames[frameCount - 1]) // Last time is after last frame.

+ 1 - 1
spine-cpp/spine-cpp/src/spine/IkConstraintTimeline.cpp

@@ -56,7 +56,7 @@ namespace Spine
         _frames.reserve(frameCount * ENTRIES);
     }
     
-    void IkConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void IkConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         IkConstraint* constraintP = skeleton._ikConstraints[_ikConstraintIndex];
         IkConstraint& constraint = *constraintP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/PathConstraintMixTimeline.cpp

@@ -56,7 +56,7 @@ namespace Spine
         _frames.reserve(frameCount * ENTRIES);
     }
     
-    void PathConstraintMixTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void PathConstraintMixTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         PathConstraint* constraintP = skeleton._pathConstraints[_pathConstraintIndex];
         PathConstraint& constraint = *constraintP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp

@@ -54,7 +54,7 @@ namespace Spine
         _frames.reserve(frameCount * ENTRIES);
     }
     
-    void PathConstraintPositionTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void PathConstraintPositionTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         PathConstraint* constraintP = skeleton._pathConstraints[_pathConstraintIndex];
         PathConstraint& constraint = *constraintP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp

@@ -49,7 +49,7 @@ namespace Spine
         // Empty
     }
     
-    void PathConstraintSpacingTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void PathConstraintSpacingTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         PathConstraint* constraintP = skeleton._pathConstraints[_pathConstraintIndex];
         PathConstraint& constraint = *constraintP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/RotateTimeline.cpp

@@ -47,7 +47,7 @@ namespace Spine
         _frames.reserve(frameCount << 1);
     }
     
-    void RotateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void RotateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Bone* bone = skeleton.getBones()[_boneIndex];
         

+ 1 - 1
spine-cpp/spine-cpp/src/spine/ScaleTimeline.cpp

@@ -49,7 +49,7 @@ namespace Spine
         // Empty
     }
     
-    void ScaleTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void ScaleTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Bone* boneP = skeleton._bones[_boneIndex];
         Bone& bone = *boneP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/ShearTimeline.cpp

@@ -49,7 +49,7 @@ namespace Spine
         // Empty
     }
     
-    void ShearTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void ShearTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Bone* boneP = skeleton._bones[_boneIndex];
         Bone& bone = *boneP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/TransformConstraintTimeline.cpp

@@ -60,7 +60,7 @@ namespace Spine
         _frames.reserve(frameCount * ENTRIES);
     }
     
-    void TransformConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void TransformConstraintTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         TransformConstraint* constraintP = skeleton._transformConstraints[_transformConstraintIndex];
         TransformConstraint& constraint = *constraintP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/TranslateTimeline.cpp

@@ -56,7 +56,7 @@ namespace Spine
         _frames.reserve(frameCount * ENTRIES);
     }
     
-    void TranslateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void TranslateTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Bone* boneP = skeleton._bones[_boneIndex];
         Bone& bone = *boneP;

+ 1 - 1
spine-cpp/spine-cpp/src/spine/TwoColorTimeline.cpp

@@ -64,7 +64,7 @@ namespace Spine
         _frames.reserve(frameCount * ENTRIES);
     }
     
-    void TwoColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>& events, float alpha, MixPose pose, MixDirection direction)
+    void TwoColorTimeline::apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction)
     {
         Slot* slotP = skeleton._slots[_slotIndex];
         Slot& slot = *slotP;