浏览代码

Ported first batch of last changes to runtimes.

badlogic 7 年之前
父节点
当前提交
0bbcd971e9
共有 39 个文件被更改,包括 452 次插入375 次删除
  1. 2 2
      spine-cpp/spine-cpp/include/spine/Animation.h
  2. 8 3
      spine-cpp/spine-cpp/include/spine/AnimationState.h
  3. 2 2
      spine-cpp/spine-cpp/include/spine/AttachmentTimeline.h
  4. 1 1
      spine-cpp/spine-cpp/include/spine/ColorTimeline.h
  5. 1 1
      spine-cpp/spine-cpp/include/spine/CurveTimeline.h
  6. 1 1
      spine-cpp/spine-cpp/include/spine/DeformTimeline.h
  7. 1 1
      spine-cpp/spine-cpp/include/spine/DrawOrderTimeline.h
  8. 1 1
      spine-cpp/spine-cpp/include/spine/EventTimeline.h
  9. 1 1
      spine-cpp/spine-cpp/include/spine/IkConstraintTimeline.h
  10. 6 9
      spine-cpp/spine-cpp/include/spine/MixBlend.h
  11. 1 1
      spine-cpp/spine-cpp/include/spine/PathConstraintMixTimeline.h
  12. 1 1
      spine-cpp/spine-cpp/include/spine/PathConstraintPositionTimeline.h
  13. 1 1
      spine-cpp/spine-cpp/include/spine/PathConstraintSpacingTimeline.h
  14. 1 1
      spine-cpp/spine-cpp/include/spine/RotateTimeline.h
  15. 1 1
      spine-cpp/spine-cpp/include/spine/ScaleTimeline.h
  16. 1 1
      spine-cpp/spine-cpp/include/spine/ShearTimeline.h
  17. 3 3
      spine-cpp/spine-cpp/include/spine/Timeline.h
  18. 1 1
      spine-cpp/spine-cpp/include/spine/TransformConstraintTimeline.h
  19. 1 1
      spine-cpp/spine-cpp/include/spine/TranslateTimeline.h
  20. 1 1
      spine-cpp/spine-cpp/include/spine/TwoColorTimeline.h
  21. 1 1
      spine-cpp/spine-cpp/include/spine/spine.h
  22. 2 2
      spine-cpp/spine-cpp/src/spine/Animation.cpp
  23. 69 67
      spine-cpp/spine-cpp/src/spine/AnimationState.cpp
  24. 3 3
      spine-cpp/spine-cpp/src/spine/AttachmentTimeline.cpp
  25. 10 14
      spine-cpp/spine-cpp/src/spine/ColorTimeline.cpp
  26. 150 84
      spine-cpp/spine-cpp/src/spine/DeformTimeline.cpp
  27. 3 3
      spine-cpp/spine-cpp/src/spine/DrawOrderTimeline.cpp
  28. 2 2
      spine-cpp/spine-cpp/src/spine/EventTimeline.cpp
  29. 6 7
      spine-cpp/spine-cpp/src/spine/IkConstraintTimeline.cpp
  30. 5 6
      spine-cpp/spine-cpp/src/spine/PathConstraintMixTimeline.cpp
  31. 5 6
      spine-cpp/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp
  32. 5 6
      spine-cpp/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp
  33. 30 27
      spine-cpp/spine-cpp/src/spine/RotateTimeline.cpp
  34. 53 23
      spine-cpp/spine-cpp/src/spine/ScaleTimeline.cpp
  35. 19 14
      spine-cpp/spine-cpp/src/spine/ShearTimeline.cpp
  36. 5 6
      spine-cpp/spine-cpp/src/spine/TransformConstraintTimeline.cpp
  37. 19 14
      spine-cpp/spine-cpp/src/spine/TranslateTimeline.cpp
  38. 13 43
      spine-cpp/spine-cpp/src/spine/TwoColorTimeline.cpp
  39. 16 13
      spine-sfml/cpp/example/main.cpp

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

@@ -32,7 +32,7 @@
 #define Spine_Animation_h
 
 #include <spine/Vector.h>
-#include <spine/MixPose.h>
+#include <spine/MixBlend.h>
 #include <spine/MixDirection.h>
 #include <spine/SpineObject.h>
 #include <spine/String.h>
@@ -89,7 +89,7 @@ public:
 	/// 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 *> *pEvents, float alpha,
-			   MixPose pose, MixDirection direction);
+			   MixBlend blend, MixDirection direction);
 
 	const String &getName();
 

+ 8 - 3
spine-cpp/spine-cpp/include/spine/AnimationState.h

@@ -33,7 +33,7 @@
 
 #include <spine/Vector.h>
 #include <spine/Pool.h>
-#include <spine/MixPose.h>
+#include <spine/MixBlend.h>
 #include <spine/SpineObject.h>
 #include <spine/String.h>
 
@@ -196,6 +196,10 @@ namespace Spine {
         ///
         float getMixDuration();
         void setMixDuration(float inValue);
+
+
+        float getMixBlend();
+        void setMixBlend(MixBlend blend);
         
         ///
         /// The track entry for the previous animation when mixing from the previous animation to this animation, or NULL if no
@@ -227,6 +231,7 @@ namespace Spine {
         float _animationStart, _animationEnd, _animationLast, _nextAnimationLast;
         float _delay, _trackTime, _trackLast, _nextTrackLast, _trackEnd, _timeScale;
         float _alpha, _mixTime, _mixDuration, _interruptAlpha, _totalAlpha;
+        MixBlend _mixBlend;
         Vector<int> _timelineData;
         Vector<TrackEntry*> _timelineDipMix;
         Vector<float> _timelinesRotation;
@@ -400,12 +405,12 @@ namespace Spine {
 
         static Animation* getEmptyAnimation();
         
-        static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixPose pose, Vector<float>& timelinesRotation, int i, bool firstFrame);
+        static void applyRotateTimeline(RotateTimeline* rotateTimeline, Skeleton& skeleton, float time, float alpha, MixBlend pose, Vector<float>& timelinesRotation, int i, bool firstFrame);
         
         /// Returns true when all mixing from entries are complete.
         bool updateMixingFrom(TrackEntry* to, float delta);
         
-        float applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixPose currentPose);
+        float applyMixingFrom(TrackEntry* to, Skeleton& skeleton, MixBlend currentPose);
         
         void queueEvents(TrackEntry* entry, float animationTime);
         

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

@@ -34,7 +34,7 @@
 #include <spine/Timeline.h>
 #include <spine/SpineObject.h>
 #include <spine/Vector.h>
-#include <spine/MixPose.h>
+#include <spine/MixBlend.h>
 #include <spine/MixDirection.h>
 #include <spine/String.h>
 
@@ -51,7 +51,7 @@ namespace Spine {
     public:
         explicit AttachmentTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixBlend blend, MixDirection direction);
         
         virtual int getPropertyId();
         

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

@@ -47,7 +47,7 @@ public:
 	explicit ColorTimeline(int frameCount);
 
 	virtual void
-	apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixPose pose,
+	apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
 		  MixDirection direction);
 
 	virtual int getPropertyId();

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

@@ -44,7 +44,7 @@ namespace Spine {
 
         virtual ~CurveTimeline();
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction) = 0;
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixBlend blend, MixDirection direction) = 0;
         
         virtual int getPropertyId() = 0;
         

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

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

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

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

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

@@ -45,7 +45,7 @@ namespace Spine {
         
         ~EventTimeline();
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixBlend blend, MixDirection direction);
         
         virtual int getPropertyId();
         

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

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

+ 6 - 9
spine-cpp/spine-cpp/include/spine/MixPose.h → spine-cpp/spine-cpp/include/spine/MixBlend.h

@@ -34,15 +34,12 @@
 namespace Spine {
 ///
 /// Controls how a timeline is mixed with the setup or current pose.
-/// See also Timeline::apply(Skeleton&, float, float, Vector&, float, MixPose, MixDirection)
-enum MixPose {
-	///  The timeline value is mixed with the setup pose (the current pose is not used).
-			MixPose_Setup = 0,
-	///  The timeline value is mixed with the current pose. The setup pose is used as the timeline value before the first key,
-	/// except for timelines which perform instant transitions, such as DrawOrderTimeline or AttachmentTimeline.
-			MixPose_Current,
-	///  The timeline value is mixed with the current pose. No change is made before the first key (the current pose is kept until the first key).
-			MixPose_CurrentLayered
+/// See also Timeline::apply(Skeleton&, float, float, Vector&, float, Blend, MixDirection)
+enum MixBlend {
+	MixBlend_Setup = 0,
+	MixBlend_First,
+	MixBlend_Replace,
+	MixBlend_Add
 };
 }
 

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

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

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

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

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

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

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

@@ -46,7 +46,7 @@ namespace Spine {
 
         explicit RotateTimeline(int frameCount);
         
-        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixPose pose, MixDirection direction);
+        virtual void apply(Skeleton& skeleton, float lastTime, float time, Vector<Event*>* pEvents, float alpha, MixBlend blend, MixDirection direction);
         
         virtual int getPropertyId();
         

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

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

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

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

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

@@ -33,7 +33,7 @@
 
 #include <spine/RTTI.h>
 #include <spine/Vector.h>
-#include <spine/MixPose.h>
+#include <spine/MixBlend.h>
 #include <spine/MixDirection.h>
 #include <spine/SpineObject.h>
 
@@ -59,10 +59,10 @@ public:
 	///     value. Between 0 and 1 applies a value between the current or setup pose and the timeline value. By adjusting
 	///     alpha over time, an animation can be mixed in or out. alpha can also be useful to
 	///      apply animations on top of each other (layered).
-	/// @param pose Controls how mixing is applied when alpha is than 1.
+	/// @param blend 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 *> *pEvents, float alpha, MixPose pose,
+	apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
 		  MixDirection direction) = 0;
 
 	virtual int getPropertyId() = 0;

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

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

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

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

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

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

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

@@ -65,7 +65,7 @@
 #include <spine/MathUtil.h>
 #include <spine/MeshAttachment.h>
 #include <spine/MixDirection.h>
-#include <spine/MixPose.h>
+#include <spine/MixBlend.h>
 #include <spine/PathAttachment.h>
 #include <spine/PathConstraint.h>
 #include <spine/PathConstraintData.h>

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

@@ -50,7 +50,7 @@ Animation::~Animation() {
 }
 
 void Animation::apply(Skeleton &skeleton, float lastTime, float time, bool loop, Vector<Event *> *pEvents, float alpha,
-					  MixPose pose, MixDirection direction) {
+					  MixBlend blend, MixDirection direction) {
 	if (loop && _duration != 0) {
 		time = MathUtil::fmod(time, _duration);
 		if (lastTime > 0) {
@@ -59,7 +59,7 @@ void Animation::apply(Skeleton &skeleton, float lastTime, float time, bool loop,
 	}
 
 	for (int i = 0, n = static_cast<int>(_timelines.size()); i < n; ++i) {
-		_timelines[i]->apply(skeleton, lastTime, time, pEvents, alpha, pose, direction);
+		_timelines[i]->apply(skeleton, lastTime, time, pEvents, alpha, blend, direction);
 	}
 }
 

+ 69 - 67
spine-cpp/spine-cpp/src/spine/AnimationState.cpp

@@ -51,7 +51,7 @@ TrackEntry::TrackEntry() : _animation(NULL), _next(NULL), _mixingFrom(NULL), _tr
 						   _eventThreshold(0), _attachmentThreshold(0), _drawOrderThreshold(0), _animationStart(0),
 						   _animationEnd(0), _animationLast(0), _nextAnimationLast(0), _delay(0), _trackTime(0),
 						   _trackLast(0), _nextTrackLast(0), _trackEnd(0), _timeScale(1.0f), _alpha(0), _mixTime(0),
-						   _mixDuration(0), _interruptAlpha(0), _totalAlpha(0),
+						   _mixDuration(0), _mixBlend(MixBlend_Replace), _interruptAlpha(0), _totalAlpha(0),
 						   _onAnimationEventFunc(dummyOnAnimationEventFunc) {
 }
 
@@ -139,6 +139,10 @@ void TrackEntry::setMixDuration(float inValue) { _mixDuration = inValue; }
 
 TrackEntry *TrackEntry::getMixingFrom() { return _mixingFrom; }
 
+void TrackEntry::setMixBlend(MixBlend blend) { _mixBlend = blend; }
+
+float TrackEntry::getMixBlend() { return _mixBlend; }
+
 void TrackEntry::resetRotationDirections() {
 	_timelinesRotation.clear();
 }
@@ -419,12 +423,12 @@ bool AnimationState::apply(Skeleton &skeleton) {
 		TrackEntry &current = *currentP;
 
 		applied = true;
-		MixPose currentPose = i == 0 ? MixPose_Current : MixPose_CurrentLayered;
+		MixBlend blend = i == 0 ? MixBlend_First : current._mixBlend;
 
 		// apply mixing from entries first.
 		float mix = current._alpha;
 		if (current._mixingFrom != NULL) {
-			mix *= applyMixingFrom(currentP, skeleton, currentPose);
+			mix *= applyMixingFrom(currentP, skeleton, blend);
 		} else if (current._trackTime >= current._trackEnd && current._next == NULL) {
 			mix = 0; // Set to setup pose the last time the entry will be applied.
 		}
@@ -433,9 +437,9 @@ bool AnimationState::apply(Skeleton &skeleton) {
 		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) {
+		if (mix == 1 || blend == MixBlend_Add) {
 			for (int ii = 0; ii < timelineCount; ++ii) {
-				timelines[ii]->apply(skeleton, animationLast, animationTime, &_events, 1, MixPose_Setup,
+				timelines[ii]->apply(skeleton, animationLast, animationTime, &_events, mix, blend,
 									 MixDirection_In);
 			}
 		} else {
@@ -451,7 +455,7 @@ bool AnimationState::apply(Skeleton &skeleton) {
 				Timeline *timeline = timelines[ii];
 				assert(timeline);
 
-				MixPose pose = timelineData[ii] >= AnimationState::First ? MixPose_Setup : currentPose;
+				MixBlend timelineBlend = timelineData[ii] == AnimationState::Subsequent ? blend : MixBlend_Setup;
 
 				RotateTimeline *rotateTimeline = NULL;
 				if (timeline->getRTTI().isExactly(RotateTimeline::rtti)) {
@@ -459,10 +463,10 @@ bool AnimationState::apply(Skeleton &skeleton) {
 				}
 
 				if (rotateTimeline != NULL) {
-					applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1,
+					applyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1,
 										firstFrame);
 				} else {
-					timeline->apply(skeleton, animationLast, animationTime, &_events, mix, pose, MixDirection_In);
+					timeline->apply(skeleton, animationLast, animationTime, &_events, mix, timelineBlend, MixDirection_In);
 				}
 			}
 		}
@@ -665,20 +669,20 @@ Animation *AnimationState::getEmptyAnimation() {
 }
 
 void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleton &skeleton, float time, float alpha,
-										 MixPose pose, Vector<float> &timelinesRotation, int i, bool firstFrame) {
+										 MixBlend blend, 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);
+		rotateTimeline->apply(skeleton, 0, time, NULL, 1, blend, MixDirection_In);
 		return;
 	}
 
 	Bone *bone = skeleton._bones[rotateTimeline->_boneIndex];
 	Vector<float>& frames = rotateTimeline->_frames;
 	if (time < frames[0]) {
-		if (pose == MixPose_Setup) {
+		if (blend == MixBlend_Setup) {
 			bone->_rotation = bone->_data._rotation;
 		}
 		return;
@@ -704,7 +708,7 @@ void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleto
 	}
 
 	// 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 r1 = blend == MixBlend_Setup ? bone->_data._rotation : bone->_rotation;
 	float total, diff = r2 - r1;
 	if (diff == 0) {
 		total = timelinesRotation[i];
@@ -767,22 +771,23 @@ bool AnimationState::updateMixingFrom(TrackEntry *to, float delta) {
 	return false;
 }
 
-float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixPose currentPose) {
+float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixBlend blend) {
 	TrackEntry *from = to->_mixingFrom;
 	if (from->_mixingFrom != NULL) {
-		applyMixingFrom(from, skeleton, currentPose);
+		applyMixingFrom(from, skeleton, blend);
 	}
 
 	float mix;
 	if (to->_mixDuration == 0) {
 		// Single frame mix to undo mixingFrom changes.
 		mix = 1;
-		currentPose = MixPose_Setup;
+		if (blend == MixBlend_First) blend = MixBlend_Setup;
 	} else {
 		mix = to->_mixTime / to->_mixDuration;
 		if (mix > 1) {
 			mix = 1;
 		}
+		if (blend != MixBlend_First) blend = from->_mixBlend;
 	}
 
 	Vector<Event *> *eventBuffer = mix < from->_eventThreshold ? &_events : NULL;
@@ -790,59 +795,56 @@ float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixPos
 	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(timelines.size() << 1, 0);
-	}
-
-	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().isExactly(AttachmentTimeline::rtti)) {
-					continue;
-				}
-				if (!drawOrder && timeline->getRTTI().isExactly(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 * MathUtil::max(0.0f, 1 - dipMix->_mixTime / dipMix->_mixDuration);
-				break;
-		}
-		from->_totalAlpha += alpha;
+	float alphaDip = from->_alpha * to->_interruptAlpha, alphaMix = alphaDip * (1 - mix);
 
-		RotateTimeline *rotateTimeline = NULL;
-		if (timeline->getRTTI().isExactly(RotateTimeline::rtti)) {
-			rotateTimeline = static_cast<RotateTimeline *>(timeline);
-		}
+	if (blend == MixBlend_Add) {
+		for (int i = 0; i < timelineCount; i++)
+			timelines[i]->apply(skeleton, animationLast, animationTime, eventBuffer, alphaMix, blend, MixDirection_Out);
+	} else {
+		Vector<int> &timelineData = from->_timelineData;
+		Vector<TrackEntry *> &timelineDipMix = from->_timelineDipMix;
 
-		if (rotateTimeline != NULL) {
-			applyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1,
-								firstFrame);
-		} else {
-			timeline->apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection_Out);
+		bool firstFrame = from->_timelinesRotation.size() == 0;
+		if (firstFrame) {
+			from->_timelinesRotation.setSize(timelines.size() << 1, 0);
+		}
+
+		Vector<float> &timelinesRotation = from->_timelinesRotation;
+
+		from->_totalAlpha = 0;
+		for (int i = 0; i < timelineCount; i++) {
+			Timeline *timeline = timelines[i];
+			MixBlend timelineBlend;
+			float alpha;
+			switch (timelineData[i]) {
+				case AnimationState::Subsequent:
+					if (!attachments && (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))) continue;
+					if (!drawOrder && (timeline->getRTTI().isExactly(DrawOrderTimeline::rtti))) continue;
+					timelineBlend = blend;
+					alpha = alphaMix;
+					break;
+				case AnimationState::First:
+					timelineBlend = MixBlend_Setup;
+					alpha = alphaMix;
+					break;
+				case AnimationState::Dip:
+					timelineBlend = MixBlend_Setup;
+					alpha = alphaDip;
+					break;
+				default:
+					timelineBlend = MixBlend_Setup;
+					TrackEntry *dipMix = timelineDipMix[i];
+					alpha = alphaDip * MathUtil::max(0.0f, 1.0f - dipMix->_mixTime / dipMix->_mixDuration);
+					break;
+			}
+			from->_totalAlpha += alpha;
+			if ((timeline->getRTTI().isExactly(RotateTimeline::rtti))) {
+				applyRotateTimeline((RotateTimeline*)timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1,
+									firstFrame);
+			} else {
+				timeline->apply(skeleton, animationLast, animationTime, eventBuffer, alpha, timelineBlend,
+								MixDirection_Out);
+			}
 		}
 	}
 
@@ -976,7 +978,7 @@ void AnimationState::animationsChanged() {
 
 	for (int i = 0, n = static_cast<int>(_tracks.size()); i < n; ++i) {
 		TrackEntry *entry = _tracks[i];
-		if (entry != NULL) {
+		if (entry != NULL && entry->_mixBlend != MixBlend_Add) {
 			entry->setTimelineData(NULL, _mixingTo, _propertyIDs);
 		}
 	}

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

@@ -54,13 +54,13 @@ AttachmentTimeline::AttachmentTimeline(int frameCount) : Timeline(), _slotIndex(
 }
 
 void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-							   MixPose pose, MixDirection direction) {
+							   MixBlend blend, MixDirection direction) {
 	assert(_slotIndex < skeleton._slots.size());
 
 	String *attachmentName;
 	Slot *slotP = skeleton._slots[_slotIndex];
 	Slot &slot = *slotP;
-	if (direction == MixDirection_Out && pose == MixPose_Setup) {
+	if (direction == MixDirection_Out && blend == MixBlend_Setup) {
 		attachmentName = &slot._data._attachmentName;
 		slot._attachment = attachmentName->length() == 0 ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName);
 		return;
@@ -68,7 +68,7 @@ void AttachmentTimeline::apply(Skeleton &skeleton, float lastTime, float time, V
 
 	if (time < _frames[0]) {
 		// Time is before first frame.
-		if (pose == MixPose_Setup) {
+		if (blend == MixBlend_Setup || blend == MixBlend_First) {
 			attachmentName = &slot._data._attachmentName;
 			slot._attachment =
 					attachmentName->length() == 0 ? NULL : skeleton.getAttachment(_slotIndex, *attachmentName);

+ 10 - 14
spine-cpp/spine-cpp/src/spine/ColorTimeline.cpp

@@ -58,27 +58,23 @@ ColorTimeline::ColorTimeline(int frameCount) : CurveTimeline(frameCount), _slotI
 }
 
 void ColorTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-						  MixPose pose, MixDirection direction) {
+						  MixBlend blend, MixDirection direction) {
 	Slot *slotP = skeleton._slots[_slotIndex];
 	Slot &slot = *slotP;
 	if (time < _frames[0]) {
 		SlotData &slotData = slot._data;
-		switch (pose) {
-			case MixPose_Setup:
-				slot.getColor().set(slotData.getColor());
+		switch (blend) {
+			case MixBlend_Setup:
+				slot._color.set(slot._data._color);
 				return;
-			case MixPose_Current: {
-				Color &color = slot.getColor();
-				Color &setup = slot.getData().getColor();
-				color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha,
-						  (setup.b - color.b) * alpha,
+			case MixBlend_First: {
+				Color color = slot._color, setup = slot._data._color;
+				color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha,
 						  (setup.a - color.a) * alpha);
-				return;
 			}
-			case MixPose_CurrentLayered:
-			default:
-				return;
+			default: ;
 		}
+		return;
 	}
 
 	float r, g, b, a;
@@ -110,7 +106,7 @@ void ColorTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector
 		slot.getColor().set(r, g, b, a);
 	} else {
 		Color &color = slot.getColor();
-		if (pose == MixPose_Setup) color.set(slot.getData().getColor());
+		if (blend == MixBlend_Setup) color.set(slot.getData().getColor());
 		color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
 	}
 }

+ 150 - 84
spine-cpp/spine-cpp/src/spine/DeformTimeline.cpp

@@ -57,128 +57,194 @@ DeformTimeline::DeformTimeline(int frameCount) : CurveTimeline(frameCount), _slo
 }
 
 void DeformTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-						   MixPose pose, MixDirection direction) {
+						   MixBlend blend, MixDirection direction) {
 	Slot *slotP = skeleton._slots[_slotIndex];
 	Slot &slot = *slotP;
 
-	if (slot._attachment == NULL || !slot._attachment->getRTTI().instanceOf(VertexAttachment::rtti)) {
+	Attachment *slotAttachment = slot._attachment;
+	if (slotAttachment == NULL || !slotAttachment->getRTTI().instanceOf(VertexAttachment::rtti)) {
 		return;
 	}
 
-	VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slot._attachment);
+	VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slotAttachment);
 	if (!vertexAttachment->applyDeform(_attachment)) {
 		return;
 	}
 
-	Vector<float> &vertices = slot._attachmentVertices;
-	if (vertices.size() == 0) {
-		alpha = 1;
+	Vector<float> &verticesArray = slot._attachmentVertices;
+	if (verticesArray.size() == 0) {
+		blend = MixBlend_Setup;
 	}
 
-	int vertexCount = static_cast<int>(_frameVertices[0].size());
+	Vector< Vector<float> > &frameVertices = _frameVertices;
+	int vertexCount = static_cast<int>(frameVertices[0].size());
 
+	Vector<float> &frames = _frames;
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
-				vertices.clear();
-				return;
-			case MixPose_Current:
-				if (alpha == 1) {
-					vertices.clear();
-					return;
-				}
-
-				// Ensure size and preemptively set count.
-				vertices.setSize(vertexCount, 0);
-
-				if (vertexAttachment->_bones.size() == 0) {
-					// Unweighted vertex positions.
-					Vector<float> &setupVertices = vertexAttachment->_vertices;
-					for (int i = 0; i < vertexCount; ++i) {
-						vertices[i] += (setupVertices[i] - vertices[i]) * alpha;
-					}
-				} else {
-					// Weighted deform offsets.
-					alpha = 1 - alpha;
-					for (int i = 0; i < vertexCount; ++i) {
-						vertices[i] *= alpha;
-					}
-				}
-				return;
-			default:
+		switch (blend) {
+		case MixBlend_Setup:
+			verticesArray.clear();
+			return;
+		case MixBlend_First:
+			if (alpha == 1) {
+				verticesArray.clear();
 				return;
+			}
+			verticesArray.setSize(vertexCount, 0);
+			Vector<float> &vertices = verticesArray;
+			if (vertexAttachment->getBones().size() == 0) {
+				// Unweighted vertex positions.
+				Vector<float> &setupVertices = vertexAttachment->getVertices();
+				for (int i = 0; i < vertexCount; i++)
+					vertices[i] += (setupVertices[i] - vertices[i]) * alpha;
+			} else {
+				// Weighted deform offsets.
+				alpha = 1 - alpha;
+				for (int i = 0; i < vertexCount; i++)
+					vertices[i] *= alpha;
+			}
 		}
+		return;
 	}
 
-	// Ensure size and preemptively set count.
-	vertices.setSize(vertexCount, 0);
+	verticesArray.setSize(vertexCount, 0);
+	Vector<float> &vertices = verticesArray;
 
-	if (time >= _frames[_frames.size() - 1]) {
-		// Time is after last frame.
-		Vector<float> &lastVertices = _frameVertices[_frames.size() - 1];
+	if (time >= frames[frames.size() - 1]) { // Time is after last frame.
+		Vector<float> &lastVertices = frameVertices[frames.size() - 1];
 		if (alpha == 1) {
-			// Vertex positions or deform offsets, no alpha.
-			vertices.clear();
-			for (int i = 0; i < vertexCount; ++i) {
-				float vertex = lastVertices[i];
-				vertices.add(vertex);
-			}
-		} else if (pose == MixPose_Setup) {
-			if (vertexAttachment->_bones.size() == 0) {
-				// Unweighted vertex positions, with alpha.
-				Vector<float> &setupVertices = vertexAttachment->_vertices;
-				for (int i = 0; i < vertexCount; i++) {
-					float setup = setupVertices[i];
-					vertices[i] = setup + (lastVertices[i] - setup) * alpha;
+			if (blend == MixBlend_Add) {
+				VertexAttachment *vertexAttachment = static_cast<VertexAttachment*>(slotAttachment);
+				if (vertexAttachment->getBones().size() == 0) {
+					// Unweighted vertex positions, no alpha.
+					Vector<float> &setupVertices = vertexAttachment->getVertices();
+					for (int i = 0; i < vertexCount; i++)
+						vertices[i] += lastVertices[i] - setupVertices[i];
+				} else {
+					// Weighted deform offsets, no alpha.
+					for (int i = 0; i < vertexCount; i++)
+						vertices[i] += lastVertices[i];
 				}
 			} else {
-				// Weighted deform offsets, with alpha.
-				for (int i = 0; i < vertexCount; ++i) {
-					vertices[i] = lastVertices[i] * alpha;
-				}
+				// Vertex positions or deform offsets, no alpha.
+				memcpy(vertices.buffer(), lastVertices.buffer(), vertexCount * sizeof(float));
 			}
 		} else {
-			// Vertex positions or deform offsets, with alpha.
-			for (int i = 0; i < vertexCount; ++i) {
-				vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
+			switch (blend) {
+				case MixBlend_Setup: {
+					VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slotAttachment);
+					if (vertexAttachment->getBones().size() == 0) {
+						// Unweighted vertex positions, with alpha.
+						Vector<float> &setupVertices = vertexAttachment->getVertices();
+						for (int i = 0; i < vertexCount; i++) {
+							float setup = setupVertices[i];
+							vertices[i] = setup + (lastVertices[i] - setup) * alpha;
+						}
+					} else {
+						// Weighted deform offsets, with alpha.
+						for (int i = 0; i < vertexCount; i++)
+							vertices[i] = lastVertices[i] * alpha;
+					}
+					break;
+				}
+				case MixBlend_First:
+				case MixBlend_Replace:
+					// Vertex positions or deform offsets, with alpha.
+					for (int i = 0; i < vertexCount; i++)
+						vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
+					break;
+				case MixBlend_Add:
+					VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slotAttachment);
+					if (vertexAttachment->getBones().size() == 0) {
+						// Unweighted vertex positions, no alpha.
+						Vector<float> &setupVertices = vertexAttachment->getVertices();
+						for (int i = 0; i < vertexCount; i++)
+							vertices[i] += (lastVertices[i] - setupVertices[i]) * alpha;
+					} else {
+						// Weighted deform offsets, alpha.
+						for (int i = 0; i < vertexCount; i++)
+							vertices[i] += lastVertices[i] * alpha;
+					}
 			}
 		}
 		return;
 	}
 
 	// Interpolate between the previous frame and the current frame.
-	int frame = Animation::binarySearch(_frames, time);
-	Vector<float> &prevVertices = _frameVertices[frame - 1];
-	Vector<float> &nextVertices = _frameVertices[frame];
-	float frameTime = _frames[frame];
-	float percent = getCurvePercent(frame - 1, 1 - (time - frameTime) / (_frames[frame - 1] - frameTime));
+	int frame = Animation::binarySearch(frames, time);
+	Vector<float>  &prevVertices = frameVertices[frame - 1];
+	Vector<float>  &nextVertices = frameVertices[frame];
+	float frameTime = frames[frame];
+	float percent = getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime));
 
 	if (alpha == 1) {
-		// Vertex positions or deform offsets, no alpha.
-		for (int i = 0; i < vertexCount; ++i) {
-			float prev = prevVertices[i];
-			vertices[i] = prev + (nextVertices[i] - prev) * percent;
-		}
-	} else if (pose == MixPose_Setup) {
-		if (vertexAttachment->_bones.size() == 0) {
-			// Unweighted vertex positions, with alpha.
-			Vector<float> &setupVertices = vertexAttachment->_vertices;
-			for (int i = 0; i < vertexCount; ++i) {
-				float prev = prevVertices[i], setup = setupVertices[i];
-				vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
+		if (blend == MixBlend_Add) {
+			VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slotAttachment);
+			if (vertexAttachment->getBones().size() == 0) {
+				// Unweighted vertex positions, no alpha.
+				Vector<float> &setupVertices = vertexAttachment->getVertices();
+				for (int i = 0; i < vertexCount; i++) {
+					float prev = prevVertices[i];
+					vertices[i] += prev + (nextVertices[i] - prev) * percent - setupVertices[i];
+				}
+			} else {
+				// Weighted deform offsets, no alpha.
+				for (int i = 0; i < vertexCount; i++) {
+					float prev = prevVertices[i];
+					vertices[i] += prev + (nextVertices[i] - prev) * percent;
+				}
 			}
 		} else {
-			// Weighted deform offsets, with alpha.
-			for (int i = 0; i < vertexCount; ++i) {
+			// Vertex positions or deform offsets, no alpha.
+			for (int i = 0; i < vertexCount; i++) {
 				float prev = prevVertices[i];
-				vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
+				vertices[i] = prev + (nextVertices[i] - prev) * percent;
 			}
 		}
 	} else {
-		// Vertex positions or deform offsets, with alpha.
-		for (int i = 0; i < vertexCount; ++i) {
-			float prev = prevVertices[i];
-			vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
+		switch (blend) {
+			case MixBlend_Setup: {
+				VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slotAttachment);
+				if (vertexAttachment->getBones().size() == 0) {
+					// Unweighted vertex positions, with alpha.
+					Vector<float> &setupVertices = vertexAttachment->getVertices();
+					for (int i = 0; i < vertexCount; i++) {
+						float prev = prevVertices[i], setup = setupVertices[i];
+						vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
+					}
+				} else {
+					// Weighted deform offsets, with alpha.
+					for (int i = 0; i < vertexCount; i++) {
+						float prev = prevVertices[i];
+						vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
+					}
+				}
+				break;
+			}
+			case MixBlend_First:
+			case MixBlend_Replace:
+				// Vertex positions or deform offsets, with alpha.
+				for (int i = 0; i < vertexCount; i++) {
+					float prev = prevVertices[i];
+					vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
+				}
+				break;
+			case MixBlend_Add:
+				VertexAttachment *vertexAttachment = static_cast<VertexAttachment *>(slotAttachment);
+				if (vertexAttachment->getBones().size() == 0) {
+					// Unweighted vertex positions, with alpha.
+					Vector<float> &setupVertices = vertexAttachment->getVertices();
+					for (int i = 0; i < vertexCount; i++) {
+						float prev = prevVertices[i];
+						vertices[i] += (prev + (nextVertices[i] - prev) * percent - setupVertices[i]) * alpha;
+					}
+				} else {
+					// Weighted deform offsets, with alpha.
+					for (int i = 0; i < vertexCount; i++) {
+						float prev = prevVertices[i];
+						vertices[i] += (prev + (nextVertices[i] - prev) * percent) * alpha;
+					}
+				}
 		}
 	}
 }

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

@@ -55,10 +55,10 @@ DrawOrderTimeline::DrawOrderTimeline(int frameCount) : Timeline() {
 }
 
 void DrawOrderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-							  MixPose pose, MixDirection direction) {
+							  MixBlend blend, MixDirection direction) {
 	Vector<Slot *> &drawOrder = skeleton._drawOrder;
 	Vector<Slot *> &slots = skeleton._slots;
-	if (direction == MixDirection_Out && pose == MixPose_Setup) {
+	if (direction == MixDirection_Out && blend == MixBlend_Setup) {
 		drawOrder.clear();
 		drawOrder.ensureCapacity(slots.size());
 		for (int i = 0, n = static_cast<int>(slots.size()); i < n; ++i) {
@@ -68,7 +68,7 @@ void DrawOrderTimeline::apply(Skeleton &skeleton, float lastTime, float time, Ve
 	}
 
 	if (time < _frames[0]) {
-		if (pose == MixPose_Setup) {
+		if (blend == MixBlend_Setup) {
 			drawOrder.clear();
 			drawOrder.ensureCapacity(slots.size());
 			for (int i = 0, n = static_cast<int>(slots.size()); i < n; ++i) {

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

@@ -54,7 +54,7 @@ EventTimeline::~EventTimeline() {
 }
 
 void EventTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-						  MixPose pose, MixDirection direction) {
+						  MixBlend blend, MixDirection direction) {
 	if (pEvents == NULL) {
 		return;
 	}
@@ -69,7 +69,7 @@ void EventTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector
 
 	if (lastTime > time) {
 		// Fire events after last time for looped animations.
-		apply(skeleton, lastTime, std::numeric_limits<int>::max(), pEvents, alpha, pose, direction);
+		apply(skeleton, lastTime, std::numeric_limits<int>::max(), pEvents, alpha, blend, direction);
 		lastTime = -1.0f;
 	} else if (lastTime >= _frames[frameCount - 1]) {
 		// Last time is after last frame.

+ 6 - 7
spine-cpp/spine-cpp/src/spine/IkConstraintTimeline.cpp

@@ -56,20 +56,19 @@ IkConstraintTimeline::IkConstraintTimeline(int frameCount) : CurveTimeline(frame
 }
 
 void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-								 MixPose pose, MixDirection direction) {
+								 MixBlend blend, MixDirection direction) {
 	IkConstraint *constraintP = skeleton._ikConstraints[_ikConstraintIndex];
 	IkConstraint &constraint = *constraintP;
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				constraint._mix = constraint._data._mix;
 				constraint._bendDirection = constraint._data._bendDirection;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				constraint._mix += (constraint._data._mix - constraint._mix) * alpha;
 				constraint._bendDirection = constraint._data._bendDirection;
 				return;
-			case MixPose_CurrentLayered:
 			default:
 				return;
 		}
@@ -77,7 +76,7 @@ void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time,
 
 	if (time >= _frames[_frames.size() - ENTRIES]) {
 		// Time is after last frame.
-		if (pose == MixPose_Setup) {
+		if (blend == MixBlend_Setup) {
 			constraint._mix =
 					constraint._data._mix + (_frames[_frames.size() + PREV_MIX] - constraint._data._mix) * alpha;
 			constraint._bendDirection = direction == MixDirection_Out ? constraint._data._bendDirection
@@ -99,7 +98,7 @@ void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time,
 	float percent = getCurvePercent(frame / ENTRIES - 1,
 									1 - (time - frameTime) / (_frames[frame + PREV_TIME] - frameTime));
 
-	if (pose == MixPose_Setup) {
+	if (blend == MixBlend_Setup) {
 		constraint._mix =
 				constraint._data._mix + (mix + (_frames[frame + MIX] - mix) * percent - constraint._data._mix) * alpha;
 		constraint._bendDirection =

+ 5 - 6
spine-cpp/spine-cpp/src/spine/PathConstraintMixTimeline.cpp

@@ -58,20 +58,19 @@ PathConstraintMixTimeline::PathConstraintMixTimeline(int frameCount) : CurveTime
 
 void
 PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-								 MixPose pose, MixDirection direction) {
+								 MixBlend blend, MixDirection direction) {
 	PathConstraint *constraintP = skeleton._pathConstraints[_pathConstraintIndex];
 	PathConstraint &constraint = *constraintP;
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				constraint._rotateMix = constraint._data._rotateMix;
 				constraint._translateMix = constraint._data._translateMix;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				constraint._rotateMix += (constraint._data._rotateMix - constraint._rotateMix) * alpha;
 				constraint._translateMix += (constraint._data._translateMix - constraint._translateMix) * alpha;
 				return;
-			case MixPose_CurrentLayered:
 			default:
 				return;
 		}
@@ -95,7 +94,7 @@ PathConstraintMixTimeline::apply(Skeleton &skeleton, float lastTime, float time,
 		translate += (_frames[frame + TRANSLATE] - translate) * percent;
 	}
 
-	if (pose == MixPose_Setup) {
+	if (blend == MixBlend_Setup) {
 		constraint._rotateMix = constraint._data._rotateMix + (rotate - constraint._data._rotateMix) * alpha;
 		constraint._translateMix =
 				constraint._data._translateMix + (translate - constraint._data._translateMix) * alpha;

+ 5 - 6
spine-cpp/spine-cpp/src/spine/PathConstraintPositionTimeline.cpp

@@ -58,18 +58,17 @@ PathConstraintPositionTimeline::~PathConstraintPositionTimeline() {
 }
 
 void PathConstraintPositionTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
-										   float alpha, MixPose pose, MixDirection direction) {
+										   float alpha, MixBlend blend, MixDirection direction) {
 	PathConstraint *constraintP = skeleton._pathConstraints[_pathConstraintIndex];
 	PathConstraint &constraint = *constraintP;
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				constraint._position = constraint._data._position;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				constraint._position += (constraint._data._position - constraint._position) * alpha;
 				return;
-			case MixPose_CurrentLayered:
 			default:
 				return;
 		}
@@ -89,7 +88,7 @@ void PathConstraintPositionTimeline::apply(Skeleton &skeleton, float lastTime, f
 
 		position += (_frames[frame + VALUE] - position) * percent;
 	}
-	if (pose == MixPose_Setup) {
+	if (blend == MixBlend_Setup) {
 		constraint._position = constraint._data._position + (position - constraint._data._position) * alpha;
 	} else {
 		constraint._position += (position - constraint._position) * alpha;

+ 5 - 6
spine-cpp/spine-cpp/src/spine/PathConstraintSpacingTimeline.cpp

@@ -49,18 +49,17 @@ PathConstraintSpacingTimeline::PathConstraintSpacingTimeline(int frameCount) : P
 }
 
 void PathConstraintSpacingTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
-										  float alpha, MixPose pose, MixDirection direction) {
+										  float alpha, MixBlend blend, MixDirection direction) {
 	PathConstraint *constraintP = skeleton._pathConstraints[_pathConstraintIndex];
 	PathConstraint &constraint = *constraintP;
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				constraint._spacing = constraint._data._spacing;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				constraint._spacing += (constraint._data._spacing - constraint._spacing) * alpha;
 				return;
-			case MixPose_CurrentLayered:
 			default:
 				return;
 		}
@@ -81,7 +80,7 @@ void PathConstraintSpacingTimeline::apply(Skeleton &skeleton, float lastTime, fl
 		spacing += (_frames[frame + VALUE] - spacing) * percent;
 	}
 
-	if (pose == MixPose_Setup) {
+	if (blend == MixBlend_Setup) {
 		constraint._spacing = constraint._data._spacing + (spacing - constraint._data._spacing) * alpha;
 	} else {
 		constraint._spacing += (spacing - constraint._spacing) * alpha;

+ 30 - 27
spine-cpp/spine-cpp/src/spine/RotateTimeline.cpp

@@ -47,22 +47,21 @@ RotateTimeline::RotateTimeline(int frameCount) : CurveTimeline(frameCount), _bon
 }
 
 void RotateTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-						   MixPose pose, MixDirection direction) {
+						   MixBlend blend, MixDirection direction) {
 	Bone *bone = skeleton.getBones()[_boneIndex];
 
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup: {
+		switch (blend) {
+			case MixBlend_Setup: {
 				bone->_rotation = bone->_data._rotation;
 				break;
 			}
-			case MixPose_Current: {
-				float rr = bone->_data._rotation - bone->_rotation;
-				rr -= (16384 - (int) (16384.499999999996 - rr / 360)) * 360;
-				bone->_rotation += rr * alpha;
+			case MixBlend_First: {
+				float r = bone->_data._rotation - bone->_rotation;
+				bone->_rotation += (r - (16384 - (int) (16384.499999999996 - r / 360)) * 360) * alpha;
 				break;
 			}
-			case MixPose_CurrentLayered: {
+			default: {
 				// TODO?
 				break;
 			}
@@ -72,15 +71,19 @@ void RotateTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vecto
 	}
 
 	if (time >= _frames[_frames.size() - ENTRIES]) {
-		// Time is after last frame.
-		if (pose == MixPose_Setup) {
-			bone->_rotation = bone->_data._rotation + _frames[_frames.size() + PREV_ROTATION] * alpha;
-		} else {
-			float rr = bone->_data._rotation + _frames[_frames.size() + PREV_ROTATION] - bone->_rotation;
-			rr -= (16384 - (int) (16384.499999999996 - rr / 360)) * 360; // Wrap within -180 and 180.
-			bone->_rotation += rr * alpha;
+		float r = _frames[_frames.size() + PREV_ROTATION];
+		switch (blend) {
+			case MixBlend_Setup:
+				bone->_rotation = bone->_data._rotation + r * alpha;
+				break;
+			case MixBlend_First:
+			case MixBlend_Replace:
+				r += bone->_data._rotation - bone->_rotation;
+				r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
+				// Fall through.
+			case MixBlend_Add:
+				bone->_rotation += r * alpha;
 		}
-
 		return;
 	}
 
@@ -90,18 +93,18 @@ void RotateTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vecto
 	float frameTime = _frames[frame];
 	float percent = getCurvePercent((frame >> 1) - 1,
 									1 - (time - frameTime) / (_frames[frame + PREV_TIME] - frameTime));
-
 	float r = _frames[frame + ROTATION] - prevRotation;
-	r -= (16384 - (int) (16384.499999999996 - r / 360)) * 360;
-	r = prevRotation + r * percent;
-
-	if (pose == MixPose_Setup) {
-		r -= (16384 - (int) (16384.499999999996 - r / 360)) * 360;
-		bone->_rotation = bone->_data._rotation + r * alpha;
-	} else {
-		r = bone->_data._rotation + r - bone->_rotation;
-		r -= (16384 - (int) (16384.499999999996 - r / 360)) * 360;
-		bone->_rotation += r * alpha;
+	r = prevRotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * percent;
+	switch (blend) {
+		case MixBlend_Setup:
+			bone->_rotation = bone->_data._rotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
+			break;
+		case MixBlend_First:
+		case MixBlend_Replace:
+			r += bone->_data._rotation - bone->_rotation;
+			// Fall through.
+		case MixBlend_Add:
+			bone->_rotation += (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
 	}
 }
 

+ 53 - 23
spine-cpp/spine-cpp/src/spine/ScaleTimeline.cpp

@@ -46,24 +46,22 @@ ScaleTimeline::ScaleTimeline(int frameCount) : TranslateTimeline(frameCount) {
 }
 
 void ScaleTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-						  MixPose pose, MixDirection direction) {
+						  MixBlend blend, MixDirection direction) {
 	Bone *boneP = skeleton._bones[_boneIndex];
 	Bone &bone = *boneP;
 
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				bone._scaleX = bone._data._scaleX;
 				bone._scaleY = bone._data._scaleY;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				bone._scaleX += (bone._data._scaleX - bone._scaleX) * alpha;
 				bone._scaleY += (bone._data._scaleY - bone._scaleY) * alpha;
-				return;
-			case MixPose_CurrentLayered:
-			default:
-				return;
+			default: {}
 		}
+		return;
 	}
 
 	float x, y;
@@ -85,27 +83,59 @@ void ScaleTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector
 	}
 
 	if (alpha == 1) {
-		bone._scaleX = x;
-		bone._scaleY = y;
-	} else {
-		float bx, by;
-		if (pose == MixPose_Setup) {
-			bx = bone._data._scaleX;
-			by = bone._data._scaleY;
+		if (blend == MixBlend_Add) {
+			bone._scaleX += x - bone._data._scaleX;
+			bone._scaleY += y - bone._data._scaleY;
 		} else {
-			bx = bone._scaleX;
-			by = bone._scaleY;
+			bone._scaleX = x;
+			bone._scaleY = y;
 		}
+	} else {
 		// Mixing out uses sign of setup or current pose, else use sign of key.
+		float bx, by;
 		if (direction == MixDirection_Out) {
-			x = (x >= 0 ? x : -x) * (bx >= 0 ? 1 : -1);
-			y = (y >= 0 ? y : -y) * (by >= 0 ? 1 : -1);
+			switch (blend) {
+				case MixBlend_Setup:
+					bx = bone._data._scaleX;
+					by = bone._data._scaleY;
+					bone._scaleX = bx + (MathUtil::abs(x) * MathUtil::sign(bx) - bx) * alpha;
+					bone._scaleY = by + (MathUtil::abs(y) * MathUtil::sign(by) - by) * alpha;
+					break;
+				case MixBlend_First:
+				case MixBlend_Replace:
+					bx = bone._scaleX;
+					by = bone._scaleY;
+					bone._scaleX = bx + (MathUtil::abs(x) * MathUtil::sign(bx) - bx) * alpha;
+					bone._scaleY = by + (MathUtil::abs(y) * MathUtil::sign(by) - by) * alpha;
+					break;
+				case MixBlend_Add:
+					bx = bone._scaleX;
+					by = bone._scaleY;
+					bone._scaleX = bx + (MathUtil::abs(x) * MathUtil::sign(bx) - bone._data._scaleX) * alpha;
+					bone._scaleY = by + (MathUtil::abs(y) * MathUtil::sign(by) - bone._data._scaleY) * alpha;
+			}
 		} else {
-			bx = (bx >= 0 ? bx : -bx) * (x >= 0 ? 1 : -1);
-			by = (by >= 0 ? by : -by) * (y >= 0 ? 1 : -1);
+			switch (blend) {
+				case MixBlend_Setup:
+					bx = MathUtil::abs(bone._data._scaleX) * MathUtil::sign(x);
+					by = MathUtil::abs(bone._data._scaleY) * MathUtil::sign(y);
+					bone._scaleX = bx + (x - bx) * alpha;
+					bone._scaleY = by + (y - by) * alpha;
+					break;
+				case MixBlend_First:
+				case MixBlend_Replace:
+					bx = MathUtil::abs(bone._scaleX) * MathUtil::sign(x);
+					by = MathUtil::abs(bone._scaleY) * MathUtil::sign(y);
+					bone._scaleX = bx + (x - bx) * alpha;
+					bone._scaleY = by + (y - by) * alpha;
+					break;
+				case MixBlend_Add:
+					bx = MathUtil::sign(x);
+					by = MathUtil::sign(y);
+					bone._scaleX = MathUtil::abs(bone._scaleX) * bx + (x - MathUtil::abs(bone._data._scaleX) * bx) * alpha;
+					bone._scaleY = MathUtil::abs(bone._scaleY) * by + (y - MathUtil::abs(bone._data._scaleY) * by) * alpha;
+			}
 		}
-		bone._scaleX = bx + (x - bx) * alpha;
-		bone._scaleY = by + (y - by) * alpha;
 	}
 }
 

+ 19 - 14
spine-cpp/spine-cpp/src/spine/ShearTimeline.cpp

@@ -46,24 +46,22 @@ ShearTimeline::ShearTimeline(int frameCount) : TranslateTimeline(frameCount) {
 }
 
 void ShearTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-						  MixPose pose, MixDirection direction) {
+						  MixBlend blend, MixDirection direction) {
 	Bone *boneP = skeleton._bones[_boneIndex];
 	Bone &bone = *boneP;
 
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				bone._shearX = bone._data._shearX;
 				bone._shearY = bone._data._shearY;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				bone._shearX += (bone._data._shearX - bone._shearX) * alpha;
 				bone._shearY += (bone._data._shearY - bone._shearY) * alpha;
-				return;
-			case MixPose_CurrentLayered:
-			default:
-				return;
+			default: {}
 		}
+		return;
 	}
 
 	float x, y;
@@ -84,12 +82,19 @@ void ShearTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector
 		y = y + (_frames[frame + Y] - y) * percent;
 	}
 
-	if (pose == MixPose_Setup) {
-		bone._shearX = bone._data._shearX + x * alpha;
-		bone._shearY = bone._data._shearY + y * alpha;
-	} else {
-		bone._shearX += (bone._data._shearX + x - bone._shearX) * alpha;
-		bone._shearY += (bone._data._shearY + y - bone._shearY) * alpha;
+	switch (blend) {
+		case MixBlend_Setup:
+			bone._shearX = bone._data._shearX + x * alpha;
+			bone._shearY = bone._data._shearY + y * alpha;
+			break;
+		case MixBlend_First:
+		case MixBlend_Replace:
+			bone._shearX += (bone._data._shearX + x - bone._shearX) * alpha;
+			bone._shearY += (bone._data._shearY + y - bone._shearY) * alpha;
+			break;
+		case MixBlend_Add:
+			bone._shearX += x * alpha;
+			bone._shearY += y * alpha;
 	}
 }
 

+ 5 - 6
spine-cpp/spine-cpp/src/spine/TransformConstraintTimeline.cpp

@@ -61,25 +61,24 @@ TransformConstraintTimeline::TransformConstraintTimeline(int frameCount) : Curve
 }
 
 void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents,
-										float alpha, MixPose pose, MixDirection direction) {
+										float alpha, MixBlend blend, MixDirection direction) {
 	TransformConstraint *constraintP = skeleton._transformConstraints[_transformConstraintIndex];
 	TransformConstraint &constraint = *constraintP;
 
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				constraint._rotateMix = constraint._data._rotateMix;
 				constraint._translateMix = constraint._data._translateMix;
 				constraint._scaleMix = constraint._data._scaleMix;
 				constraint._shearMix = constraint._data._shearMix;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				constraint._rotateMix += (constraint._data._rotateMix - constraint._rotateMix) * alpha;
 				constraint._translateMix += (constraint._data._translateMix - constraint._translateMix) * alpha;
 				constraint._scaleMix += (constraint._data._scaleMix - constraint._scaleMix) * alpha;
 				constraint._shearMix += (constraint._data._shearMix - constraint._shearMix) * alpha;
 				return;
-			case MixPose_CurrentLayered:
 			default:
 				return;
 		}
@@ -110,7 +109,7 @@ void TransformConstraintTimeline::apply(Skeleton &skeleton, float lastTime, floa
 		shear += (_frames[frame + SHEAR] - shear) * percent;
 	}
 
-	if (pose == MixPose_Setup) {
+	if (blend == MixBlend_Setup) {
 		TransformConstraintData &data = constraint._data;
 		constraint._rotateMix = data._rotateMix + (rotate - data._rotateMix) * alpha;
 		constraint._translateMix = data._translateMix + (translate - data._translateMix) * alpha;

+ 19 - 14
spine-cpp/spine-cpp/src/spine/TranslateTimeline.cpp

@@ -58,24 +58,22 @@ TranslateTimeline::~TranslateTimeline() {
 }
 
 void TranslateTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-							  MixPose pose, MixDirection direction) {
+							  MixBlend blend, MixDirection direction) {
 	Bone *boneP = skeleton._bones[_boneIndex];
 	Bone &bone = *boneP;
 
 	if (time < _frames[0]) {
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				bone._x = bone._data._x;
 				bone._y = bone._data._y;
 				return;
-			case MixPose_Current:
+			case MixBlend_First:
 				bone._x += (bone._data._x - bone._x) * alpha;
 				bone._y += (bone._data._y - bone._y) * alpha;
-				return;
-			case MixPose_CurrentLayered:
-			default:
-				return;
+			default: {}
 		}
+		return;
 	}
 
 	float x, y;
@@ -96,12 +94,19 @@ void TranslateTimeline::apply(Skeleton &skeleton, float lastTime, float time, Ve
 		y += (_frames[frame + Y] - y) * percent;
 	}
 
-	if (pose == MixPose_Setup) {
-		bone._x = bone._data._x + x * alpha;
-		bone._y = bone._data._y + y * alpha;
-	} else {
-		bone._x += (bone._data._x + x - bone._x) * alpha;
-		bone._y += (bone._data._y + y - bone._y) * alpha;
+	switch (blend) {
+		case MixBlend_Setup:
+			bone._x = bone._data._x + x * alpha;
+			bone._y = bone._data._y + y * alpha;
+			break;
+		case MixBlend_First:
+		case MixBlend_Replace:
+			bone._x += (bone._data._x + x - bone._x) * alpha;
+			bone._y += (bone._data._y + y - bone._y) * alpha;
+			break;
+		case MixBlend_Add:
+			bone._x += x * alpha;
+			bone._y += y * alpha;
 	}
 }
 

+ 13 - 43
spine-cpp/spine-cpp/src/spine/TwoColorTimeline.cpp

@@ -65,18 +65,18 @@ TwoColorTimeline::TwoColorTimeline(int frameCount) : CurveTimeline(frameCount),
 }
 
 void TwoColorTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
-							 MixPose pose, MixDirection direction) {
+							 MixBlend blend, MixDirection direction) {
 	Slot *slotP = skeleton._slots[_slotIndex];
 	Slot &slot = *slotP;
 
 	if (time < _frames[0]) {
 		// Time is before first frame.
-		switch (pose) {
-			case MixPose_Setup:
+		switch (blend) {
+			case MixBlend_Setup:
 				slot.getColor().set(slot.getData().getColor());
 				slot.getDarkColor().set(slot.getData().getDarkColor());
 				return;
-			case MixPose_Current: {
+			case MixBlend_First: {
 				Color &color = slot.getColor();
 				color.r += (color.r - slot._data.getColor().r) * alpha;
 				color.g += (color.g - slot._data.getColor().g) * alpha;
@@ -89,7 +89,6 @@ void TwoColorTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vec
 				darkColor.b += (darkColor.b - slot._data.getDarkColor().b) * alpha;
 				return;
 			}
-			case MixPose_CurrentLayered:
 			default:
 				return;
 		}
@@ -131,48 +130,19 @@ void TwoColorTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vec
 
 	if (alpha == 1) {
 		Color &color = slot.getColor();
-		color.r = r;
-		color.g = g;
-		color.b = b;
-		color.a = a;
+		color.set(r, g, b, a);
 
 		Color &darkColor = slot.getDarkColor();
-		darkColor.r = r2;
-		darkColor.g = g2;
-		darkColor.b = b2;
+		darkColor.set(r2, g2, b2, 1);
 	} else {
-		float br, bg, bb, ba, br2, bg2, bb2;
-		if (pose == MixPose_Setup) {
-			br = slot._data.getColor().r;
-			bg = slot._data.getColor().g;
-			bb = slot._data.getColor().b;
-			ba = slot._data.getColor().a;
-			br2 = slot._data.getDarkColor().r;
-			bg2 = slot._data.getDarkColor().g;
-			bb2 = slot._data.getDarkColor().b;
-		} else {
-			Color &color = slot.getColor();
-			br = color.r;
-			bg = color.g;
-			bb = color.b;
-			ba = color.a;
-
-			Color &darkColor = slot.getDarkColor();
-			br2 = darkColor.r;
-			bg2 = darkColor.g;
-			bb2 = darkColor.b;
+		Color &light = slot._color;
+		Color &dark = slot._darkColor;
+		if (blend == MixBlend_Setup) {
+			light.set(slot._data._color);
+			dark.set(slot._data._darkColor);
 		}
-
-		Color &color = slot.getColor();
-		color.r = br + ((r - br) * alpha);
-		color.g = bg + ((g - bg) * alpha);
-		color.b = bb + ((b - bb) * alpha);
-		color.a = ba + ((a - ba) * alpha);
-
-		Color &darkColor = slot.getDarkColor();
-		darkColor.r = br2 + ((r2 - br2) * alpha);
-		darkColor.g = bg2 + ((g2 - bg2) * alpha);
-		darkColor.b = bb2 + ((b2 - bb2) * alpha);
+		light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
+		dark.add((r2 - dark.r) * alpha, (g2 - dark.g) * alpha, (b2 - dark.b) * alpha, 0);
 	}
 }
 

+ 16 - 13
spine-sfml/cpp/example/main.cpp

@@ -347,19 +347,22 @@ void coin (SkeletonData* skeletonData, Atlas* atlas) {
 	skeleton->updateWorldTransform();
 
 	drawable->state->setAnimation(0, "rotate", true);
-	drawable->update(0.1);
+	drawable->update(1);
 
-	sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - vine");
+	sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - coin");
 	window.setFramerateLimit(60);
 	sf::Event event;
 	sf::Clock deltaClock;
 	float swirlTime = 0;
 	while (window.isOpen()) {
-		while (window.pollEvent(event))
+		float delta = 0;
+		while (window.pollEvent(event)) {
 			if (event.type == sf::Event::Closed) window.close();
+			if (event.type == sf::Event::MouseButtonPressed) delta += 0.1f;
+		}
 
-		float delta = deltaClock.getElapsedTime().asSeconds();
-		deltaClock.restart();
+		// float delta = deltaClock.getElapsedTime().asSeconds();
+		// deltaClock.restart();
 
 		drawable->update(delta);
 
@@ -387,13 +390,13 @@ void owl (SkeletonData* skeletonData, Atlas* atlas) {
 	TrackEntry* down = drawable->state->setAnimation(5, "down", true);
 
 	left->setAlpha(0);
-	// BOZO left->setMixBlend(SP_MIX_BLEND_ADD);
+	left->setMixBlend(MixBlend_Add);
 	right->setAlpha(0);
-	// BOZO right->mixBlend = SP_MIX_BLEND_ADD;
+	right->setMixBlend(MixBlend_Add);
 	up->setAlpha(0);
-	// BOZO up->mixBlend = SP_MIX_BLEND_ADD;
+	up->setMixBlend(MixBlend_Add);
 	down->setAlpha(0);
-	// BOZO down->mixBlend = SP_MIX_BLEND_ADD;
+	down->setMixBlend(MixBlend_Add);
 
 	sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - owl");
 	window.setFramerateLimit(60);
@@ -452,10 +455,10 @@ int main () {
 	DebugExtension dbgExtension;
 	SpineExtension::setInstance(&dbgExtension);
 
-	testcase(raptor, "data/raptor-pro.json", "data/raptor-pro.skel", "data/raptor.atlas", 0.5f);
-	testcase(test, "data/tank-pro.json", "data/tank-pro.skel", "data/tank.atlas", 1.0f);
-	testcase(spineboy, "data/spineboy-ess.json", "data/spineboy-ess.skel", "data/spineboy.atlas", 0.6f);
-	testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl.atlas", 0.5f);
+	// testcase(raptor, "data/raptor-pro.json", "data/raptor-pro.skel", "data/raptor.atlas", 0.5f);
+	// testcase(test, "data/tank-pro.json", "data/tank-pro.skel", "data/tank.atlas", 1.0f);
+	// testcase(spineboy, "data/spineboy-ess.json", "data/spineboy-ess.skel", "data/spineboy.atlas", 0.6f);
+	// testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl.atlas", 0.5f);
 	testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin.atlas", 0.5f);
 	testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine.atlas", 0.5f);
 	testcase(tank, "data/tank-pro.json", "data/tank-pro.skel", "data/tank.atlas", 0.2f);