Selaa lähdekoodia

[cpp] Inherit timeline, latest ports from reference implementation, excluding loaders

Mario Zechner 1 vuosi sitten
vanhempi
commit
8210d25e2e
27 muutettua tiedostoa jossa 439 lisäystä ja 197 poistoa
  1. 5 0
      spine-cpp/spine-cpp/include/spine/AnimationState.h
  2. 12 0
      spine-cpp/spine-cpp/include/spine/Bone.h
  3. 4 4
      spine-cpp/spine-cpp/include/spine/BoneData.h
  4. 6 6
      spine-cpp/spine-cpp/include/spine/Inherit.h
  5. 68 0
      spine-cpp/spine-cpp/include/spine/InheritTimeline.h
  6. 5 1
      spine-cpp/spine-cpp/include/spine/PhysicsConstraintData.h
  7. 22 21
      spine-cpp/spine-cpp/include/spine/Property.h
  8. 1 1
      spine-cpp/spine-cpp/include/spine/SkeletonBinary.h
  9. 5 0
      spine-cpp/spine-cpp/include/spine/SkeletonData.h
  10. 4 0
      spine-cpp/spine-cpp/include/spine/Skin.h
  11. 5 0
      spine-cpp/spine-cpp/include/spine/SlotData.h
  12. 2 1
      spine-cpp/spine-cpp/include/spine/spine.h
  13. 18 6
      spine-cpp/spine-cpp/src/spine/AnimationState.cpp
  14. 54 37
      spine-cpp/spine-cpp/src/spine/Bone.cpp
  15. 19 19
      spine-cpp/spine-cpp/src/spine/BoneData.cpp
  16. 8 8
      spine-cpp/spine-cpp/src/spine/IkConstraint.cpp
  17. 80 0
      spine-cpp/spine-cpp/src/spine/InheritTimeline.cpp
  18. 86 79
      spine-cpp/spine-cpp/src/spine/PhysicsConstraint.cpp
  19. 9 1
      spine-cpp/spine-cpp/src/spine/PhysicsConstraintData.cpp
  20. 1 1
      spine-cpp/spine-cpp/src/spine/SequenceTimeline.cpp
  21. 1 1
      spine-cpp/spine-cpp/src/spine/ShearTimeline.cpp
  22. 4 1
      spine-cpp/spine-cpp/src/spine/Skeleton.cpp
  23. 1 1
      spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp
  24. 9 0
      spine-cpp/spine-cpp/src/spine/SkeletonData.cpp
  25. 7 7
      spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp
  26. 1 1
      spine-cpp/spine-cpp/src/spine/Skin.cpp
  27. 2 1
      spine-sdl/src/spine-sdl-cpp.cpp

+ 5 - 0
spine-cpp/spine-cpp/include/spine/AnimationState.h

@@ -250,6 +250,8 @@ namespace spine {
 
 
 		void setMixDuration(float inValue);
 		void setMixDuration(float inValue);
 
 
+        void setMixDuration(float mixDuration, float delay);
+
 		MixBlend getMixBlend();
 		MixBlend getMixBlend();
 
 
 		void setMixBlend(MixBlend blend);
 		void setMixBlend(MixBlend blend);
@@ -277,6 +279,9 @@ namespace spine {
 
 
 		void setListener(AnimationStateListenerObject *listener);
 		void setListener(AnimationStateListenerObject *listener);
 
 
+        /// Returns true if this track entry has been applied at least once.
+        ///
+        /// See AnimationState::apply(Skeleton).
         bool wasApplied();
         bool wasApplied();
 
 
 	private:
 	private:

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

@@ -33,6 +33,7 @@
 #include <spine/Updatable.h>
 #include <spine/Updatable.h>
 #include <spine/SpineObject.h>
 #include <spine/SpineObject.h>
 #include <spine/Vector.h>
 #include <spine/Vector.h>
+#include <spine/Inherit.h>
 
 
 namespace spine {
 namespace spine {
 	class BoneData;
 	class BoneData;
@@ -95,6 +96,8 @@ namespace spine {
 
 
 		friend class TranslateYTimeline;
 		friend class TranslateYTimeline;
 
 
+        friend class InheritTimeline;
+
 	RTTI_DECL
 	RTTI_DECL
 
 
 	public:
 	public:
@@ -125,8 +128,12 @@ namespace spine {
 
 
 		void worldToLocal(float worldX, float worldY, float &outLocalX, float &outLocalY);
 		void worldToLocal(float worldX, float worldY, float &outLocalX, float &outLocalY);
 
 
+        void worldToParent(float worldX, float worldY, float &outParentX, float &outParentY);
+
 		void localToWorld(float localX, float localY, float &outWorldX, float &outWorldY);
 		void localToWorld(float localX, float localY, float &outWorldX, float &outWorldY);
 
 
+        void parentToWorld(float worldX, float worldY, float &outX, float &outY);
+
 		float worldToLocalRotation(float worldRotation);
 		float worldToLocalRotation(float worldRotation);
 
 
 		float localToWorldRotation(float localRotation);
 		float localToWorldRotation(float localRotation);
@@ -255,6 +262,10 @@ namespace spine {
 
 
 		void setActive(bool inValue);
 		void setActive(bool inValue);
 
 
+        Inherit getInherit() { return _inherit; }
+
+        void setInherit(Inherit inValue) { _inherit = inValue; }
+
 	private:
 	private:
 		static bool yDown;
 		static bool yDown;
 
 
@@ -268,6 +279,7 @@ namespace spine {
 		float _c, _d, _worldY;
 		float _c, _d, _worldY;
 		bool _sorted;
 		bool _sorted;
 		bool _active;
 		bool _active;
+        Inherit _inherit;
 	};
 	};
 }
 }
 
 

+ 4 - 4
spine-cpp/spine-cpp/include/spine/BoneData.h

@@ -30,7 +30,7 @@
 #ifndef Spine_BoneData_h
 #ifndef Spine_BoneData_h
 #define Spine_BoneData_h
 #define Spine_BoneData_h
 
 
-#include <spine/TransformMode.h>
+#include <spine/Inherit.h>
 #include <spine/SpineObject.h>
 #include <spine/SpineObject.h>
 #include <spine/SpineString.h>
 #include <spine/SpineString.h>
 #include <spine/Color.h>
 #include <spine/Color.h>
@@ -115,9 +115,9 @@ namespace spine {
 		void setShearY(float inValue);
 		void setShearY(float inValue);
 
 
 		/// The transform mode for how parent world transforms affect this bone.
 		/// The transform mode for how parent world transforms affect this bone.
-		TransformMode getTransformMode();
+		Inherit getInherit();
 
 
-		void setTransformMode(TransformMode inValue);
+		void setInherit(Inherit inValue);
 
 
 		bool isSkinRequired();
 		bool isSkinRequired();
 
 
@@ -139,7 +139,7 @@ namespace spine {
 		BoneData *_parent;
 		BoneData *_parent;
 		float _length;
 		float _length;
 		float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
 		float _x, _y, _rotation, _scaleX, _scaleY, _shearX, _shearY;
-		TransformMode _transformMode;
+		Inherit _inherit;
 		bool _skinRequired;
 		bool _skinRequired;
 		Color _color;
 		Color _color;
         String _icon;
         String _icon;

+ 6 - 6
spine-cpp/spine-cpp/include/spine/TransformMode.h → spine-cpp/spine-cpp/include/spine/Inherit.h

@@ -31,12 +31,12 @@
 #define Spine_TransformMode_h
 #define Spine_TransformMode_h
 
 
 namespace spine {
 namespace spine {
-	enum TransformMode {
-		TransformMode_Normal = 0,
-		TransformMode_OnlyTranslation,
-		TransformMode_NoRotationOrReflection,
-		TransformMode_NoScale,
-		TransformMode_NoScaleOrReflection
+	enum Inherit {
+		Inherit_Normal = 0,
+		Inherit_OnlyTranslation,
+		Inherit_NoRotationOrReflection,
+		Inherit_NoScale,
+		Inherit_NoScaleOrReflection
 	};
 	};
 }
 }
 
 

+ 68 - 0
spine-cpp/spine-cpp/include/spine/InheritTimeline.h

@@ -0,0 +1,68 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef Spine_InheritTimeline_h
+#define Spine_InheritTimeline_h
+
+#include <spine/Timeline.h>
+
+#include <spine/Animation.h>
+#include <spine/Property.h>
+#include <spine/Inherit.h>
+
+namespace spine {
+
+	class SP_API InheritTimeline : public Timeline {
+		friend class SkeletonBinary;
+
+		friend class SkeletonJson;
+
+	RTTI_DECL
+
+	public:
+		explicit InheritTimeline(size_t frameCount, int boneIndex);
+
+		virtual ~InheritTimeline();
+
+        void setFrame(int frame, float time, Inherit inherit);
+
+		virtual void
+		apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha, MixBlend blend,
+			  MixDirection direction);
+
+		int getBoneIndex() { return _boneIndex; }
+
+		void setBoneIndex(int inValue) { _boneIndex = inValue; }
+
+	private:
+		int _boneIndex;
+	};
+}
+
+#endif /* Spine_InheritTimeline_h */

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

@@ -76,6 +76,10 @@ namespace spine {
 
 
         float getShearX() const;
         float getShearX() const;
 
 
+        void setLimit(float limit);
+
+        float getLimit() const;
+
         void setStep(float step);
         void setStep(float step);
 
 
         float getStep() const;
         float getStep() const;
@@ -138,7 +142,7 @@ namespace spine {
 
 
 	private:
 	private:
 		BoneData *_bone;
 		BoneData *_bone;
-        float _x, _y, _rotate, _scaleX, _shearX;
+        float _x, _y, _rotate, _scaleX, _shearX, _limit;
         float _step, _inertia, _strength, _damping, _massInverse, _wind, _gravity, _mix;
         float _step, _inertia, _strength, _damping, _massInverse, _wind, _gravity, _mix;
         bool _inertiaGlobal, _strengthGlobal, _dampingGlobal, _massGlobal, _windGlobal, _gravityGlobal, _mixGlobal;
         bool _inertiaGlobal, _strengthGlobal, _dampingGlobal, _massGlobal, _windGlobal, _gravityGlobal, _mixGlobal;
 	};
 	};

+ 22 - 21
spine-cpp/spine-cpp/include/spine/Property.h

@@ -40,27 +40,28 @@ namespace spine {
 		Property_ScaleY = 1 << 4,
 		Property_ScaleY = 1 << 4,
 		Property_ShearX = 1 << 5,
 		Property_ShearX = 1 << 5,
 		Property_ShearY = 1 << 6,
 		Property_ShearY = 1 << 6,
-		Property_Rgb = 1 << 7,
-		Property_Alpha = 1 << 8,
-		Property_Rgb2 = 1 << 9,
-		Property_Attachment = 1 << 10,
-		Property_Deform = 1 << 11,
-		Property_Event = 1 << 12,
-		Property_DrawOrder = 1 << 13,
-		Property_IkConstraint = 1 << 14,
-		Property_TransformConstraint = 1 << 15,
-		Property_PathConstraintPosition = 1 << 16,
-		Property_PathConstraintSpacing = 1 << 17,
-		Property_PathConstraintMix = 1 << 18,
-        Property_PhysicsConstraintInertia = 1 << 19,
-        Property_PhysicsConstraintStrength = 1 << 20,
-        Property_PhysicsConstraintDamping = 1 << 21,
-        Property_PhysicsConstraintMass = 1 << 22,
-        Property_PhysicsConstraintWind = 1 << 23,
-        Property_PhysicsConstraintGravity = 1 << 24,
-        Property_PhysicsConstraintMix = 1 << 25,
-        Property_PhysicsConstraintReset = 1 << 26,
-		Property_Sequence = 1 << 27
+        Property_Inherit = 1 << 7,
+		Property_Rgb = 1 << 8,
+		Property_Alpha = 1 << 9,
+		Property_Rgb2 = 1 << 10,
+		Property_Attachment = 1 << 11,
+		Property_Deform = 1 << 12,
+		Property_Event = 1 << 13,
+		Property_DrawOrder = 1 << 14,
+		Property_IkConstraint = 1 << 15,
+		Property_TransformConstraint = 1 << 16,
+		Property_PathConstraintPosition = 1 << 17,
+		Property_PathConstraintSpacing = 1 << 18,
+		Property_PathConstraintMix = 1 << 19,
+        Property_PhysicsConstraintInertia = 1 << 20,
+        Property_PhysicsConstraintStrength = 1 << 21,
+        Property_PhysicsConstraintDamping = 1 << 22,
+        Property_PhysicsConstraintMass = 1 << 23,
+        Property_PhysicsConstraintWind = 1 << 24,
+        Property_PhysicsConstraintGravity = 1 << 25,
+        Property_PhysicsConstraintMix = 1 << 26,
+        Property_PhysicsConstraintReset = 1 << 27,
+		Property_Sequence = 1 << 28
 	};
 	};
 }
 }
 
 

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

@@ -30,7 +30,7 @@
 #ifndef Spine_SkeletonBinary_h
 #ifndef Spine_SkeletonBinary_h
 #define Spine_SkeletonBinary_h
 #define Spine_SkeletonBinary_h
 
 
-#include <spine/TransformMode.h>
+#include <spine/Inherit.h>
 #include <spine/Vector.h>
 #include <spine/Vector.h>
 #include <spine/SpineObject.h>
 #include <spine/SpineObject.h>
 #include <spine/SpineString.h>
 #include <spine/SpineString.h>

+ 5 - 0
spine-cpp/spine-cpp/include/spine/SkeletonData.h

@@ -141,6 +141,10 @@ namespace spine {
 
 
 		void setHeight(float inValue);
 		void setHeight(float inValue);
 
 
+        float getReferenceScale();
+
+        void setReferenceScale(float inValue);
+
 		/// The Spine version used to export this data, or NULL.
 		/// The Spine version used to export this data, or NULL.
 		const String &getVersion();
 		const String &getVersion();
 
 
@@ -176,6 +180,7 @@ namespace spine {
 		Vector<PathConstraintData *> _pathConstraints;
 		Vector<PathConstraintData *> _pathConstraints;
         Vector<PhysicsConstraintData *> _physicsConstraints;
         Vector<PhysicsConstraintData *> _physicsConstraints;
 		float _x, _y, _width, _height;
 		float _x, _y, _width, _height;
+        float _referenceScale;
 		String _version;
 		String _version;
 		String _hash;
 		String _hash;
 		Vector<char *> _strings;
 		Vector<char *> _strings;

+ 4 - 0
spine-cpp/spine-cpp/include/spine/Skin.h

@@ -32,6 +32,7 @@
 
 
 #include <spine/Vector.h>
 #include <spine/Vector.h>
 #include <spine/SpineString.h>
 #include <spine/SpineString.h>
+#include <spine/Color.h>
 
 
 namespace spine {
 namespace spine {
 	class Attachment;
 	class Attachment;
@@ -153,11 +154,14 @@ namespace spine {
 
 
 		Vector<ConstraintData *> &getConstraints();
 		Vector<ConstraintData *> &getConstraints();
 
 
+        Color &getColor() { return _color; }
+
 	private:
 	private:
 		const String _name;
 		const String _name;
 		AttachmentMap _attachments;
 		AttachmentMap _attachments;
 		Vector<BoneData *> _bones;
 		Vector<BoneData *> _bones;
 		Vector<ConstraintData *> _constraints;
 		Vector<ConstraintData *> _constraints;
+        Color _color;
 
 
 		/// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached.
 		/// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached.
 		void attachAll(Skeleton &skeleton, Skin &oldSkin);
 		void attachAll(Skeleton &skeleton, Skin &oldSkin);

+ 5 - 0
spine-cpp/spine-cpp/include/spine/SlotData.h

@@ -109,6 +109,10 @@ namespace spine {
 
 
         void setVisible(bool inValue);
         void setVisible(bool inValue);
 
 
+        String &getPath() { return _path; }
+
+        void setPath(const String &inValue) { _path = inValue; }
+
 	private:
 	private:
 		const int _index;
 		const int _index;
 		String _name;
 		String _name;
@@ -120,6 +124,7 @@ namespace spine {
 		String _attachmentName;
 		String _attachmentName;
 		BlendMode _blendMode;
 		BlendMode _blendMode;
         bool _visible;
         bool _visible;
+        String _path;
 	};
 	};
 }
 }
 
 

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

@@ -60,6 +60,7 @@
 #include <spine/IkConstraint.h>
 #include <spine/IkConstraint.h>
 #include <spine/IkConstraintData.h>
 #include <spine/IkConstraintData.h>
 #include <spine/IkConstraintTimeline.h>
 #include <spine/IkConstraintTimeline.h>
+#include <spine/InheritTimeline.h>
 #include <spine/Json.h>
 #include <spine/Json.h>
 #include <spine/LinkedMesh.h>
 #include <spine/LinkedMesh.h>
 #include <spine/MathUtil.h>
 #include <spine/MathUtil.h>
@@ -101,7 +102,7 @@
 #include <spine/TransformConstraint.h>
 #include <spine/TransformConstraint.h>
 #include <spine/TransformConstraintData.h>
 #include <spine/TransformConstraintData.h>
 #include <spine/TransformConstraintTimeline.h>
 #include <spine/TransformConstraintTimeline.h>
-#include <spine/TransformMode.h>
+#include <spine/Inherit.h>
 #include <spine/TranslateTimeline.h>
 #include <spine/TranslateTimeline.h>
 #include <spine/Triangulator.h>
 #include <spine/Triangulator.h>
 #include <spine/Updatable.h>
 #include <spine/Updatable.h>

+ 18 - 6
spine-cpp/spine-cpp/src/spine/AnimationState.cpp

@@ -162,6 +162,12 @@ float TrackEntry::getMixDuration() { return _mixDuration; }
 
 
 void TrackEntry::setMixDuration(float inValue) { _mixDuration = inValue; }
 void TrackEntry::setMixDuration(float inValue) { _mixDuration = inValue; }
 
 
+void TrackEntry::setMixDuration(float mixDuration, float delay) {
+    _mixDuration = mixDuration;
+    if (_previous && delay <= 0) delay += _previous->getTrackComplete() - mixDuration;
+    this->_delay = delay;
+}
+
 TrackEntry *TrackEntry::getMixingFrom() { return _mixingFrom; }
 TrackEntry *TrackEntry::getMixingFrom() { return _mixingFrom; }
 
 
 TrackEntry *TrackEntry::getMixingTo() { return _mixingTo; }
 TrackEntry *TrackEntry::getMixingTo() { return _mixingTo; }
@@ -484,7 +490,7 @@ bool AnimationState::apply(Skeleton &skeleton) {
 										timelineBlend, timelinesRotation, ii << 1, firstFrame);
 										timelineBlend, timelinesRotation, ii << 1, firstFrame);
 				else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))
 				else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))
 					applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, applyTime,
 					applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, applyTime,
-											timelineBlend, true);
+											blend, attachments);
 				else
 				else
 					timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend,
 					timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend,
 									MixDirection_In);
 									MixDirection_In);
@@ -928,10 +934,16 @@ void AnimationState::queueEvents(TrackEntry *entry, float animationTime) {
 
 
 	// Queue complete if completed a loop iteration or the animation.
 	// Queue complete if completed a loop iteration or the animation.
 	bool complete = false;
 	bool complete = false;
-	if (entry->_loop)
-		complete = duration == 0 || (trackLastWrapped > MathUtil::fmod(entry->_trackTime, duration));
-	else
-		complete = animationTime >= animationEnd && entry->_animationLast < animationEnd;
+	if (entry->_loop) {
+        if (duration == 0)
+            complete = true;
+        else {
+            int cycles = (int) (entry->_trackTime / duration);
+            complete = cycles > 0 && cycles > (int) (entry->_trackLast / duration);
+        }
+    } else {
+        complete = animationTime >= animationEnd && entry->_animationLast < animationEnd;
+    }
 	if (complete) _queue->complete(entry);
 	if (complete) _queue->complete(entry);
 
 
 	// Queue events after complete.
 	// Queue events after complete.
@@ -985,8 +997,8 @@ TrackEntry *AnimationState::newTrackEntry(size_t trackIndex, Animation *animatio
 	entry._shortestRotation = false;
 	entry._shortestRotation = false;
 
 
 	entry._eventThreshold = 0;
 	entry._eventThreshold = 0;
-	entry._mixAttachmentThreshold = 0;
 	entry._alphaAttachmentThreshold = 0;
 	entry._alphaAttachmentThreshold = 0;
+    entry._mixAttachmentThreshold = 0;
 	entry._mixDrawOrderThreshold = 0;
 	entry._mixDrawOrderThreshold = 0;
 
 
 	entry._animationStart = 0;
 	entry._animationStart = 0;

+ 54 - 37
spine-cpp/spine-cpp/src/spine/Bone.cpp

@@ -71,7 +71,8 @@ Bone::Bone(BoneData &data, Skeleton &skeleton, Bone *parent) : Updatable(),
 															   _d(1),
 															   _d(1),
 															   _worldY(0),
 															   _worldY(0),
 															   _sorted(false),
 															   _sorted(false),
-															   _active(false) {
+															   _active(false),
+                                                               _inherit(Inherit_Normal){
 	setToSetupPose();
 	setToSetupPose();
 }
 }
 
 
@@ -118,8 +119,8 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 	_worldX = pa * x + pb * y + parent->_worldX;
 	_worldX = pa * x + pb * y + parent->_worldX;
 	_worldY = pc * x + pd * y + parent->_worldY;
 	_worldY = pc * x + pd * y + parent->_worldY;
 
 
-	switch (_data.getTransformMode()) {
-		case TransformMode_Normal: {
+	switch (_inherit) {
+		case Inherit_Normal: {
 			float rx = (rotation + shearX) * MathUtil::Deg_Rad;
 			float rx = (rotation + shearX) * MathUtil::Deg_Rad;
 			float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
 			float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
 			float la = MathUtil::cos(rx) * scaleX;
 			float la = MathUtil::cos(rx) * scaleX;
@@ -132,7 +133,7 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 			_d = pc * lb + pd * ld;
 			_d = pc * lb + pd * ld;
 			return;
 			return;
 		}
 		}
-		case TransformMode_OnlyTranslation: {
+		case Inherit_OnlyTranslation: {
 			float rx = (rotation + shearX) * MathUtil::Deg_Rad;
 			float rx = (rotation + shearX) * MathUtil::Deg_Rad;
 			float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
 			float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
 			_a = MathUtil::cos(rx) * scaleX;
 			_a = MathUtil::cos(rx) * scaleX;
@@ -141,7 +142,7 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 			_d = MathUtil::sin(ry) * scaleY;
 			_d = MathUtil::sin(ry) * scaleY;
 			break;
 			break;
 		}
 		}
-		case TransformMode_NoRotationOrReflection: {
+		case Inherit_NoRotationOrReflection: {
 			float s = pa * pa + pc * pc;
 			float s = pa * pa + pc * pc;
 			float prx;
 			float prx;
 			if (s > 0.0001f) {
 			if (s > 0.0001f) {
@@ -150,11 +151,11 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 				pc /= _skeleton.getScaleY();
 				pc /= _skeleton.getScaleY();
 				pb = pc * s;
 				pb = pc * s;
 				pd = pa * s;
 				pd = pa * s;
-				prx = MathUtil::atan2(pc, pa) * MathUtil::Rad_Deg;
+				prx = MathUtil::atan2Deg(pc, pa);
 			} else {
 			} else {
 				pa = 0;
 				pa = 0;
 				pc = 0;
 				pc = 0;
-				prx = 90 - MathUtil::atan2(pd, pb) * MathUtil::Rad_Deg;
+				prx = 90 - MathUtil::atan2Deg(pd, pb);
 			}
 			}
 			float rx = (rotation + shearX - prx) * MathUtil::Deg_Rad;
 			float rx = (rotation + shearX - prx) * MathUtil::Deg_Rad;
 			float ry = (rotation + shearY - prx + 90) * MathUtil::Deg_Rad;
 			float ry = (rotation + shearY - prx + 90) * MathUtil::Deg_Rad;
@@ -168,8 +169,8 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 			_d = pc * lb + pd * ld;
 			_d = pc * lb + pd * ld;
 			break;
 			break;
 		}
 		}
-		case TransformMode_NoScale:
-		case TransformMode_NoScaleOrReflection: {
+		case Inherit_NoScale:
+		case Inherit_NoScaleOrReflection: {
 			rotation *= MathUtil::Deg_Rad;
 			rotation *= MathUtil::Deg_Rad;
 			float cosine = MathUtil::cos(rotation);
 			float cosine = MathUtil::cos(rotation);
 			float sine = MathUtil::sin(rotation);
 			float sine = MathUtil::sin(rotation);
@@ -180,7 +181,7 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 			za *= s;
 			za *= s;
 			zc *= s;
 			zc *= s;
 			s = MathUtil::sqrt(za * za + zc * zc);
 			s = MathUtil::sqrt(za * za + zc * zc);
-			if (_data.getTransformMode() == TransformMode_NoScale &&
+			if (_inherit == Inherit_NoScale &&
 				(pa * pd - pb * pc < 0) != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
 				(pa * pd - pb * pc < 0) != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
 				s = -s;
 				s = -s;
 			rotation = MathUtil::Pi / 2 + MathUtil::atan2(zc, za);
 			rotation = MathUtil::Pi / 2 + MathUtil::atan2(zc, za);
@@ -213,6 +214,7 @@ void Bone::setToSetupPose() {
 	_scaleY = data.getScaleY();
 	_scaleY = data.getScaleY();
 	_shearX = data.getShearX();
 	_shearX = data.getShearX();
 	_shearY = data.getShearY();
 	_shearY = data.getShearY();
+    _inherit = data.getInherit();
 }
 }
 
 
 void Bone::worldToLocal(float worldX, float worldY, float &outLocalX, float &outLocalY) {
 void Bone::worldToLocal(float worldX, float worldY, float &outLocalX, float &outLocalY) {
@@ -229,25 +231,39 @@ void Bone::worldToLocal(float worldX, float worldY, float &outLocalX, float &out
 	outLocalY = (y * a * invDet - x * c * invDet);
 	outLocalY = (y * a * invDet - x * c * invDet);
 }
 }
 
 
+void Bone::worldToParent(float worldX, float worldY, float &outParentX, float &outParentY) {
+    if (!_parent) {
+        outParentX = worldX;
+        outParentY = worldY;
+    } else {
+        _parent->worldToLocal(worldX, worldY, outParentX, outParentY);
+    }
+}
+
 void Bone::localToWorld(float localX, float localY, float &outWorldX, float &outWorldY) {
 void Bone::localToWorld(float localX, float localY, float &outWorldX, float &outWorldY) {
 	outWorldX = localX * _a + localY * _b + _worldX;
 	outWorldX = localX * _a + localY * _b + _worldX;
 	outWorldY = localX * _c + localY * _d + _worldY;
 	outWorldY = localX * _c + localY * _d + _worldY;
 }
 }
 
 
-float Bone::worldToLocalRotation(float worldRotation) {
-	float sin = MathUtil::sinDeg(worldRotation);
-	float cos = MathUtil::cosDeg(worldRotation);
+void Bone::parentToWorld(float worldX, float worldY, float &outX, float &outY) {
+    if (!_parent) {
+        outX = worldX;
+        outY = worldY;
+    } else {
+        _parent->localToWorld(worldX, worldY, outX, outY);
+    }
+}
 
 
-	return MathUtil::atan2(_a * sin - _c * cos, _d * cos - _b * sin) * MathUtil::Rad_Deg + this->_rotation -
-		   this->_shearX;
+float Bone::worldToLocalRotation(float worldRotation) {
+    worldRotation *= MathUtil::Deg_Rad;
+    float sine = MathUtil::sin(worldRotation), cosine = MathUtil::cos(worldRotation);
+    return MathUtil::atan2Deg(_a * sine - _c * cosine, _d * cosine - _b * sine) + _rotation - _shearX;
 }
 }
 
 
 float Bone::localToWorldRotation(float localRotation) {
 float Bone::localToWorldRotation(float localRotation) {
-	localRotation -= this->_rotation - this->_shearX;
-	float sin = MathUtil::sinDeg(localRotation);
-	float cos = MathUtil::cosDeg(localRotation);
-
-	return MathUtil::atan2(cos * _c + sin * _d, cos * _a + sin * _b) * MathUtil::Rad_Deg;
+    localRotation = (localRotation - _rotation - _shearX) * MathUtil::Deg_Rad;
+    float sine = MathUtil::sin(localRotation), cosine = MathUtil::cos(localRotation);
+    return MathUtil::atan2Deg(cosine * _c + sine * _d, cosine * _a + sine * _b);
 }
 }
 
 
 void Bone::rotateWorld(float degrees) {
 void Bone::rotateWorld(float degrees) {
@@ -469,11 +485,11 @@ void Bone::setWorldY(float inValue) {
 }
 }
 
 
 float Bone::getWorldRotationX() {
 float Bone::getWorldRotationX() {
-	return MathUtil::atan2(_c, _a) * MathUtil::Rad_Deg;
+	return MathUtil::atan2Deg(_c, _a);
 }
 }
 
 
 float Bone::getWorldRotationY() {
 float Bone::getWorldRotationY() {
-	return MathUtil::atan2(_d, _b) * MathUtil::Rad_Deg;
+	return MathUtil::atan2Deg(_d, _b);
 }
 }
 
 
 float Bone::getWorldScaleX() {
 float Bone::getWorldScaleX() {
@@ -489,11 +505,11 @@ void Bone::updateAppliedTransform() {
 	if (!parent) {
 	if (!parent) {
 		_ax = _worldX - _skeleton.getX();
 		_ax = _worldX - _skeleton.getX();
 		_ay = _worldY - _skeleton.getY();
 		_ay = _worldY - _skeleton.getY();
-		_arotation = MathUtil::atan2(_c, _a) * MathUtil::Rad_Deg;
+		_arotation = MathUtil::atan2Deg(_c, _a);
 		_ascaleX = MathUtil::sqrt(_a * _a + _c * _c);
 		_ascaleX = MathUtil::sqrt(_a * _a + _c * _c);
 		_ascaleY = MathUtil::sqrt(_b * _b + _d * _d);
 		_ascaleY = MathUtil::sqrt(_b * _b + _d * _d);
 		_ashearX = 0;
 		_ashearX = 0;
-		_ashearY = MathUtil::atan2(_a * _b + _c * _d, _a * _d - _b * _c) * MathUtil::Rad_Deg;
+		_ashearY = MathUtil::atan2Deg(_a * _b + _c * _d, _a * _d - _b * _c);
 	}
 	}
 	float pa = parent->_a, pb = parent->_b, pc = parent->_c, pd = parent->_d;
 	float pa = parent->_a, pb = parent->_b, pc = parent->_c, pd = parent->_d;
 	float pid = 1 / (pa * pd - pb * pc);
 	float pid = 1 / (pa * pd - pb * pc);
@@ -503,14 +519,14 @@ void Bone::updateAppliedTransform() {
 	_ay = (dy * id - dx * ic);
 	_ay = (dy * id - dx * ic);
 
 
 	float ra, rb, rc, rd;
 	float ra, rb, rc, rd;
-	if (_data.getTransformMode() == TransformMode_OnlyTranslation) {
+	if (_inherit == Inherit_OnlyTranslation) {
 		ra = _a;
 		ra = _a;
 		rb = _b;
 		rb = _b;
 		rc = _c;
 		rc = _c;
 		rd = _d;
 		rd = _d;
 	} else {
 	} else {
-		switch (_data.getTransformMode()) {
-			case TransformMode_NoRotationOrReflection: {
+		switch (_inherit) {
+			case Inherit_NoRotationOrReflection: {
 				float s = MathUtil::abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
 				float s = MathUtil::abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
 				float sa = pa / _skeleton.getScaleX();
 				float sa = pa / _skeleton.getScaleX();
 				float sc = pc / _skeleton.getScaleY();
 				float sc = pc / _skeleton.getScaleY();
@@ -521,9 +537,10 @@ void Bone::updateAppliedTransform() {
 				ib = pb * pid;
 				ib = pb * pid;
 				break;
 				break;
 			}
 			}
-			case TransformMode_NoScale:
-			case TransformMode_NoScaleOrReflection: {
-				float cos = MathUtil::cosDeg(_rotation), sin = MathUtil::sinDeg(_rotation);
+			case Inherit_NoScale:
+			case Inherit_NoScaleOrReflection: {
+				float r = _rotation * MathUtil::Deg_Rad;
+                float cos = MathUtil::cos(r), sin = MathUtil::sin(r);
 				pa = (pa * cos + pb * sin) / _skeleton.getScaleX();
 				pa = (pa * cos + pb * sin) / _skeleton.getScaleX();
 				pc = (pc * cos + pd * sin) / _skeleton.getScaleY();
 				pc = (pc * cos + pd * sin) / _skeleton.getScaleY();
 				float s = MathUtil::sqrt(pa * pa + pc * pc);
 				float s = MathUtil::sqrt(pa * pa + pc * pc);
@@ -531,10 +548,10 @@ void Bone::updateAppliedTransform() {
 				pa *= s;
 				pa *= s;
 				pc *= s;
 				pc *= s;
 				s = MathUtil::sqrt(pa * pa + pc * pc);
 				s = MathUtil::sqrt(pa * pa + pc * pc);
-				if (_data.getTransformMode() == TransformMode_NoScale &&
+				if (_inherit == Inherit_NoScale &&
 					pid < 0 != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
 					pid < 0 != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
 					s = -s;
 					s = -s;
-				float r = MathUtil::Pi / 2 + MathUtil::atan2(pc, pa);
+				r = MathUtil::Pi / 2 + MathUtil::atan2(pc, pa);
 				pb = MathUtil::cos(r) * s;
 				pb = MathUtil::cos(r) * s;
 				pd = MathUtil::sin(r) * s;
 				pd = MathUtil::sin(r) * s;
 				pid = 1 / (pa * pd - pb * pc);
 				pid = 1 / (pa * pd - pb * pc);
@@ -544,8 +561,8 @@ void Bone::updateAppliedTransform() {
 				id = pa * pid;
 				id = pa * pid;
 				break;
 				break;
 			}
 			}
-			case TransformMode_Normal:
-			case TransformMode_OnlyTranslation:
+			case Inherit_Normal:
+			case Inherit_OnlyTranslation:
 				break;
 				break;
 		}
 		}
 		ra = ia * _a - ib * _c;
 		ra = ia * _a - ib * _c;
@@ -559,13 +576,13 @@ void Bone::updateAppliedTransform() {
 	if (_ascaleX > 0.0001f) {
 	if (_ascaleX > 0.0001f) {
 		float det = ra * rd - rb * rc;
 		float det = ra * rd - rb * rc;
 		_ascaleY = det / _ascaleX;
 		_ascaleY = det / _ascaleX;
-		_ashearY = -MathUtil::atan2(ra * rb + rc * rd, det) * MathUtil::Rad_Deg;
-		_arotation = MathUtil::atan2(rc, ra) * MathUtil::Rad_Deg;
+		_ashearY = -MathUtil::atan2Deg(ra * rb + rc * rd, det);
+		_arotation = MathUtil::atan2Deg(rc, ra);
 	} else {
 	} else {
 		_ascaleX = 0;
 		_ascaleX = 0;
 		_ascaleY = MathUtil::sqrt(rb * rb + rd * rd);
 		_ascaleY = MathUtil::sqrt(rb * rb + rd * rd);
 		_ashearY = 0;
 		_ashearY = 0;
-		_arotation = 90 - MathUtil::atan2(rd, rb) * MathUtil::Rad_Deg;
+		_arotation = 90 - MathUtil::atan2Deg(rd, rb);
 	}
 	}
 }
 }
 
 

+ 19 - 19
spine-cpp/spine-cpp/src/spine/BoneData.cpp

@@ -34,21 +34,21 @@
 using namespace spine;
 using namespace spine;
 
 
 BoneData::BoneData(int index, const String &name, BoneData *parent) : _index(index),
 BoneData::BoneData(int index, const String &name, BoneData *parent) : _index(index),
-																	  _name(name),
-																	  _parent(parent),
-																	  _length(0),
-																	  _x(0),
-																	  _y(0),
-																	  _rotation(0),
-																	  _scaleX(1),
-																	  _scaleY(1),
-																	  _shearX(0),
-																	  _shearY(0),
-																	  _transformMode(TransformMode_Normal),
-																	  _skinRequired(false),
-																	  _color(),
-																	  _icon(),
-																	  _visible(true) {
+                                                                      _name(name),
+                                                                      _parent(parent),
+                                                                      _length(0),
+                                                                      _x(0),
+                                                                      _y(0),
+                                                                      _rotation(0),
+                                                                      _scaleX(1),
+                                                                      _scaleY(1),
+                                                                      _shearX(0),
+                                                                      _shearY(0),
+                                                                      _inherit(Inherit_Normal),
+                                                                      _skinRequired(false),
+                                                                      _color(),
+                                                                      _icon(),
+                                                                      _visible(true) {
 	assert(index >= 0);
 	assert(index >= 0);
 	assert(_name.length() > 0);
 	assert(_name.length() > 0);
 }
 }
@@ -129,12 +129,12 @@ void BoneData::setShearY(float inValue) {
 	_shearY = inValue;
 	_shearY = inValue;
 }
 }
 
 
-TransformMode BoneData::getTransformMode() {
-	return _transformMode;
+Inherit BoneData::getInherit() {
+	return _inherit;
 }
 }
 
 
-void BoneData::setTransformMode(TransformMode inValue) {
-	_transformMode = inValue;
+void BoneData::setInherit(Inherit inValue) {
+    _inherit = inValue;
 }
 }
 
 
 bool BoneData::isSkinRequired() {
 bool BoneData::isSkinRequired() {

+ 8 - 8
spine-cpp/spine-cpp/src/spine/IkConstraint.cpp

@@ -45,18 +45,18 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
 	float rotationIK = -bone._ashearX - bone._arotation;
 	float rotationIK = -bone._ashearX - bone._arotation;
 	float tx = 0, ty = 0;
 	float tx = 0, ty = 0;
 
 
-	switch (bone._data.getTransformMode()) {
-		case TransformMode_OnlyTranslation:
+	switch (bone._data.getInherit()) {
+		case Inherit_OnlyTranslation:
 			tx = (targetX - bone._worldX) * MathUtil::sign(bone.getSkeleton().getScaleX());
 			tx = (targetX - bone._worldX) * MathUtil::sign(bone.getSkeleton().getScaleX());
 			ty = (targetY - bone._worldY) * MathUtil::sign(bone.getSkeleton().getScaleY());
 			ty = (targetY - bone._worldY) * MathUtil::sign(bone.getSkeleton().getScaleY());
 			break;
 			break;
-		case TransformMode_NoRotationOrReflection: {
+		case Inherit_NoRotationOrReflection: {
 			float s = MathUtil::abs(pa * pd - pb * pc) / MathUtil::max(0.0001f, pa * pa + pc * pc);
 			float s = MathUtil::abs(pa * pd - pb * pc) / MathUtil::max(0.0001f, pa * pa + pc * pc);
 			float sa = pa / bone._skeleton.getScaleX();
 			float sa = pa / bone._skeleton.getScaleX();
 			float sc = pc / bone._skeleton.getScaleY();
 			float sc = pc / bone._skeleton.getScaleY();
 			pb = -sc * s * bone._skeleton.getScaleX();
 			pb = -sc * s * bone._skeleton.getScaleX();
 			pd = sa * s * bone._skeleton.getScaleY();
 			pd = sa * s * bone._skeleton.getScaleY();
-			rotationIK += MathUtil::atan2(sc, sa) * MathUtil::Rad_Deg;
+			rotationIK += MathUtil::atan2Deg(sc, sa);
 		}
 		}
 		default:
 		default:
 			float x = targetX - p->_worldX, y = targetY - p->_worldY;
 			float x = targetX - p->_worldX, y = targetY - p->_worldY;
@@ -69,7 +69,7 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
 				ty = (y * pa - x * pc) / d - bone._ay;
 				ty = (y * pa - x * pc) / d - bone._ay;
 			}
 			}
 	}
 	}
-	rotationIK += MathUtil::atan2(ty, tx) * MathUtil::Rad_Deg;
+	rotationIK += MathUtil::atan2Deg(ty, tx);
 	if (bone._ascaleX < 0) rotationIK += 180;
 	if (bone._ascaleX < 0) rotationIK += 180;
 	if (rotationIK > 180) rotationIK -= 360;
 	if (rotationIK > 180) rotationIK -= 360;
 	else if (rotationIK < -180)
 	else if (rotationIK < -180)
@@ -77,9 +77,9 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
 	float sx = bone._ascaleX;
 	float sx = bone._ascaleX;
 	float sy = bone._ascaleY;
 	float sy = bone._ascaleY;
 	if (compress || stretch) {
 	if (compress || stretch) {
-		switch (bone._data.getTransformMode()) {
-			case TransformMode_NoScale:
-			case TransformMode_NoScaleOrReflection:
+		switch (bone._data.getInherit()) {
+			case Inherit_NoScale:
+			case Inherit_NoScaleOrReflection:
 				tx = targetX - bone._worldX;
 				tx = targetX - bone._worldX;
 				ty = targetY - bone._worldY;
 				ty = targetY - bone._worldY;
 			default:;
 			default:;

+ 80 - 0
spine-cpp/spine-cpp/src/spine/InheritTimeline.cpp

@@ -0,0 +1,80 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated July 28, 2023. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2023, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software or
+ * otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <spine/InheritTimeline.h>
+
+#include <spine/Event.h>
+#include <spine/Skeleton.h>
+
+#include <spine/Bone.h>
+#include <spine/BoneData.h>
+#include <spine/Slot.h>
+#include <spine/SlotData.h>
+
+using namespace spine;
+
+RTTI_IMPL(InheritTimeline, Timeline)
+
+#define ENTRIES 2
+#define INHERIT 1
+
+InheritTimeline::InheritTimeline(size_t frameCount, int boneIndex) : Timeline(frameCount, ENTRIES),
+                                                                     _boneIndex(boneIndex) {
+	PropertyId ids[] = {((PropertyId) Property_Inherit << 32) | boneIndex };
+	setPropertyIds(ids, 1);
+}
+
+InheritTimeline::~InheritTimeline() {
+}
+
+void InheritTimeline::setFrame(int frame, float time, Inherit inherit) {
+    frame *= ENTRIES;
+    _frames[frame] = time;
+    _frames[frame + INHERIT] = inherit;
+}
+
+
+void InheritTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vector<Event *> *pEvents, float alpha,
+                            MixBlend blend, MixDirection direction) {
+	SP_UNUSED(lastTime);
+	SP_UNUSED(pEvents);
+	SP_UNUSED(direction);
+    SP_UNUSED(alpha);
+
+    Bone *bone = skeleton.getBones()[_boneIndex];
+    if (!bone->isActive()) return;
+
+    if (time < _frames[0]) {
+        if (blend == MixBlend_Setup || blend == MixBlend_First) bone->_inherit = bone->_data.getInherit();
+        return;
+    }
+    int idx = Animation::search(_frames, time, ENTRIES) + INHERIT;
+    bone->_inherit = (Inherit)_frames[idx];
+}
+

+ 86 - 79
spine-cpp/spine-cpp/src/spine/PhysicsConstraint.cpp

@@ -32,6 +32,7 @@
 
 
 #include <spine/Bone.h>
 #include <spine/Bone.h>
 #include <spine/Skeleton.h>
 #include <spine/Skeleton.h>
+#include <spine/SkeletonData.h>
 #include <spine/BoneData.h>
 #include <spine/BoneData.h>
 
 
 using namespace spine;
 using namespace spine;
@@ -41,7 +42,6 @@ RTTI_IMPL(PhysicsConstraint, Updatable)
 PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData &data, Skeleton &skeleton)
 PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData &data, Skeleton &skeleton)
 	: _data(data), _skeleton(skeleton) {
 	: _data(data), _skeleton(skeleton) {
 	_bone = skeleton.getBones()[data.getBone()->getIndex()];
 	_bone = skeleton.getBones()[data.getBone()->getIndex()];
-
 	_inertia = data.getInertia();
 	_inertia = data.getInertia();
 	_strength = data.getStrength();
 	_strength = data.getStrength();
 	_damping = data.getDamping();
 	_damping = data.getDamping();
@@ -324,7 +324,8 @@ void PhysicsConstraint::update(Physics physics) {
 			reset();
 			reset();
 			// Fall through.
 			// Fall through.
 		case Physics::Physics_Update: {
 		case Physics::Physics_Update: {
-			_remaining += MathUtil::max(_skeleton.getTime() - _lastTime, 0.0f);
+            float delta = MathUtil::max(_skeleton.getTime() - _lastTime, 0.0f);
+			_remaining += delta;
 			_lastTime = _skeleton.getTime();
 			_lastTime = _skeleton.getTime();
 
 
 			float bx = bone->_worldX, by = bone->_worldY;
 			float bx = bone->_worldX, by = bone->_worldY;
@@ -333,83 +334,92 @@ void PhysicsConstraint::update(Physics physics) {
 				_ux = bx;
 				_ux = bx;
 				_uy = by;
 				_uy = by;
 			} else {
 			} else {
-				float remaining = _remaining, i = _inertia, step = _data._step;
+                float a = _remaining, i = _inertia, q = _data._limit * delta, t = _data._step, f = _skeleton.getData()->getReferenceScale(), d = -1;
 				if (x || y) {
 				if (x || y) {
-					if (x) {
-						_xOffset += (_ux - bx) * i;
-						_ux = bx;
-					}
-					if (y) {
-						_yOffset += (_uy - by) * i;
-						_uy = by;
-					}
-					if (remaining >= step) {
-						float m = _massInverse * step, e = _strength, w = _wind * 100, g = _gravity * -100;
-						float d = MathUtil::pow(_damping, 60 * step);
-						do {
-							if (x) {
-								_xVelocity += (w - _xOffset * e) * m;
-								_xOffset += _xVelocity * step;
-								_xVelocity *= d;
-							}
-							if (y) {
-								_yVelocity += (g - _yOffset * e) * m;
-								_yOffset += _yVelocity * step;
-								_yVelocity *= d;
-							}
-							remaining -= step;
-						} while (remaining >= step);
+                    if (x) {
+                        float u = (_ux - bx) * i;
+                        _xOffset += u > q ? q : u < -q ? -q : u;
+                        _ux = bx;
+                    }
+                    if (y) {
+                        float u = (_uy - by) * i;
+                        _yOffset += u > q ? q : u < -q ? -q : u;
+                        _uy = by;
+                    }
+					if (a >= t) {
+                        d = MathUtil::pow(_damping, 60 * t);
+                        float m = _massInverse * t, e = _strength, w = _wind * f, g = _gravity * f;
+                        do {
+                            if (x) {
+                                _xVelocity += (w - _xOffset * e) * m;
+                                _xOffset += _xVelocity * t;
+                                _xVelocity *= d;
+                            }
+                            if (y) {
+                                _yVelocity -= (g + _yOffset * e) * m;
+                                _yOffset += _yVelocity * t;
+                                _yVelocity *= d;
+                            }
+                            a -= t;
+                        } while (a >= t);
 					}
 					}
 					if (x) bone->_worldX += _xOffset * mix * _data._x;
 					if (x) bone->_worldX += _xOffset * mix * _data._x;
 					if (y) bone->_worldY += _yOffset * mix * _data._y;
 					if (y) bone->_worldY += _yOffset * mix * _data._y;
 				}
 				}
 
 
-				if (rotateOrShearX || scaleX) {
-					float ca = MathUtil::atan2(bone->_c, bone->_a), c = 0, s = 0, mr = 0;
-					if (rotateOrShearX) {
-						mr = (_data._rotate + _data._shearX) * mix;
-						float dx = _cx - bone->_worldX, dy = _cy - bone->_worldY;
-						float r = MathUtil::atan2(dy + _ty, dx + _tx) - ca - _rotateOffset * mr;
-						_rotateOffset += (r - MathUtil::ceil(r * MathUtil::InvPi_2 - 0.5) * MathUtil::Pi_2) * i;
-						r = _rotateOffset * mr + ca;
-						c = MathUtil::cos(r);
-						s = MathUtil::sin(r);
-						if (scaleX) {
-							r = l * bone->getWorldScaleX();
-							if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
-						}
-					} else {
-						c = MathUtil::cos(ca);
-						s = MathUtil::sin(ca);
-						float r = l * bone->getWorldScaleX();
-						if (r > 0) _scaleOffset += ((this->_cx - bone->_worldX) * c + (this->_cy - bone->_worldY) * s) * i / r;
-					}
-
-					remaining = _remaining;
-					if (remaining >= step) {
-						float m = _massInverse * step, e = _strength;
-						float d = MathUtil::pow(_damping, 60 * step);
-						while (true) {
-							remaining -= step;
-							if (scaleX) {
-								_scaleVelocity += (_wind * c - _gravity * s - _scaleOffset * e) * m;
-								_scaleOffset += _scaleVelocity * step;
-								_scaleVelocity *= d;
-							}
-							if (rotateOrShearX) {
-								_rotateVelocity += (-0.01f * l * (_wind * s + _gravity * c) - _rotateOffset * e) * m;
-								_rotateOffset += _rotateVelocity * step;
-								_rotateVelocity *= d;
-								if (remaining < step) break;
-								float r = _rotateOffset * mr + ca;
-								c = MathUtil::cos(r);
-								s = MathUtil::sin(r);
-							} else if (remaining < step)//
-								break;
-						}
-					}
-				}
-				_remaining = remaining;
+                if (rotateOrShearX || scaleX) {
+                    float ca = MathUtil::atan2(bone->_c, bone->_a), c, s, mr = 0;
+                    float dx = _cx - bone->_worldX, dy = _cy - bone->_worldY;
+                    if (dx > q)
+                        dx = q;
+                    else if (dx < -q) //
+                        dx = -q;
+                    if (dy > q)
+                        dy = q;
+                    else if (dy < -q) //
+                        dy = -q;
+                    if (rotateOrShearX) {
+                        mr = (_data._rotate + _data._shearX) * mix;
+                        float r = MathUtil::atan2(dy + _ty, dx + _tx) - ca - _rotateOffset * mr;
+                        _rotateOffset += (r - MathUtil::ceil(r * MathUtil::InvPi_2 - 0.5f) * MathUtil::Pi_2) * i;
+                        r = _rotateOffset * mr + ca;
+                        c = MathUtil::cos(r);
+                        s = MathUtil::sin(r);
+                        if (scaleX) {
+                            r = l * bone->getWorldScaleX();
+                            if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
+                        }
+                    } else {
+                        c = MathUtil::cos(ca);
+                        s = MathUtil::sin(ca);
+                        float r = l * bone->getWorldScaleX();
+                        if (r > 0) _scaleOffset += (dx * c + dy * s) * i / r;
+                    }
+                    a = _remaining;
+                    if (a >= t) {
+                        if (d == -1) d = MathUtil::pow(_damping, 60 * t);
+                        float m = _massInverse * t, e = _strength, w = _wind, g = _gravity, h = l / f;
+                        while (true) {
+                            a -= t;
+                            if (scaleX) {
+                                _scaleVelocity += (w * c - g * s - _scaleOffset * e) * m;
+                                _scaleOffset += _scaleVelocity * t;
+                                _scaleVelocity *= d;
+                            }
+                            if (rotateOrShearX) {
+                                _rotateVelocity -= ((w * s + g * c) * h + _rotateOffset * e) * m;
+                                _rotateOffset += _rotateVelocity * t;
+                                _rotateVelocity *= d;
+                                if (a < t) break;
+                                float r = _rotateOffset * mr + ca;
+                                c = MathUtil::cos(r);
+                                s = MathUtil::sin(r);
+                            } else if (a < t) //
+                                break;
+                        }
+                    }
+                }
+                _remaining = a;
 			}
 			}
 
 
 			_cx = bone->_worldX;
 			_cx = bone->_worldX;
@@ -466,12 +476,9 @@ void PhysicsConstraint::update(Physics physics) {
 }
 }
 
 
 void PhysicsConstraint::rotate(float x, float y, float degrees) {
 void PhysicsConstraint::rotate(float x, float y, float degrees) {
-	float r = degrees * MathUtil::Deg_Rad, cos = MathUtil::cos(r), sin = MathUtil::sin(r);
-	r = _tx * cos - _ty * sin;
-	_ty = _tx * sin + _ty * cos;
-	_tx = r;
-	float dx = _cx - x, dy = _cy - y;
-	translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy);
+    float r = degrees * MathUtil::Deg_Rad, cos = MathUtil::cos(r), sin = MathUtil::sin(r);
+    float dx = _cx - x, dy = _cy - y;
+    translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy);
 }
 }
 
 
 void PhysicsConstraint::translate(float x, float y) {
 void PhysicsConstraint::translate(float x, float y) {

+ 9 - 1
spine-cpp/spine-cpp/src/spine/PhysicsConstraintData.cpp

@@ -39,7 +39,7 @@ RTTI_IMPL(PhysicsConstraintData, ConstraintData)
 
 
 PhysicsConstraintData::PhysicsConstraintData(const String &name) : ConstraintData(name),
 PhysicsConstraintData::PhysicsConstraintData(const String &name) : ConstraintData(name),
 																   _bone(nullptr),
 																   _bone(nullptr),
-																   _x(0), _y(0), _rotate(0), _scaleX(0), _shearX(0),
+																   _x(0), _y(0), _rotate(0), _scaleX(0), _shearX(0), _limit(0),
 																   _step(0), _inertia(0), _strength(0), _damping(0), _massInverse(0), _wind(0), _gravity(0), _mix(0),
 																   _step(0), _inertia(0), _strength(0), _damping(0), _massInverse(0), _wind(0), _gravity(0), _mix(0),
 																   _inertiaGlobal(false), _strengthGlobal(false), _dampingGlobal(false), _massGlobal(false),
 																   _inertiaGlobal(false), _strengthGlobal(false), _dampingGlobal(false), _massGlobal(false),
 																   _windGlobal(false), _gravityGlobal(false), _mixGlobal(false) {
 																   _windGlobal(false), _gravityGlobal(false), _mixGlobal(false) {
@@ -94,6 +94,14 @@ float PhysicsConstraintData::getShearX() const {
 	return _shearX;
 	return _shearX;
 }
 }
 
 
+void PhysicsConstraintData::setLimit(float limit) {
+    _limit = limit;
+}
+
+float PhysicsConstraintData::getLimit() const {
+    return _limit;
+}
+
 void PhysicsConstraintData::setStep(float step) {
 void PhysicsConstraintData::setStep(float step) {
 	_step = step;
 	_step = step;
 }
 }

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

@@ -93,7 +93,7 @@ void SequenceTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vec
 	int index = modeAndIndex >> 4, count = (int) sequence->getRegions().size();
 	int index = modeAndIndex >> 4, count = (int) sequence->getRegions().size();
 	int mode = modeAndIndex & 0xf;
 	int mode = modeAndIndex & 0xf;
 	if (mode != SequenceMode::hold) {
 	if (mode != SequenceMode::hold) {
-		index += (int) (((time - before) / delay + 0.00001));
+		index += (int) (((time - before) / delay + 0.0001));
 		switch (mode) {
 		switch (mode) {
 			case SequenceMode::once:
 			case SequenceMode::once:
 				index = MathUtil::min(count - 1, index);
 				index = MathUtil::min(count - 1, index);

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

@@ -158,5 +158,5 @@ void ShearYTimeline::apply(Skeleton &skeleton, float lastTime, float time, Vecto
 	SP_UNUSED(direction);
 	SP_UNUSED(direction);
 
 
 	Bone *bone = skeleton._bones[_boneIndex];
 	Bone *bone = skeleton._bones[_boneIndex];
-	if (bone->_active) bone->_shearY = getRelativeValue(time, alpha, blend, bone->_shearX, bone->_data._shearY);
+	if (bone->_active) bone->_shearY = getRelativeValue(time, alpha, blend, bone->_shearY, bone->_data._shearY);
 }
 }

+ 4 - 1
spine-cpp/spine-cpp/src/spine/Skeleton.cpp

@@ -163,7 +163,6 @@ void Skeleton::updateCache() {
 	size_t transformCount = _transformConstraints.size();
 	size_t transformCount = _transformConstraints.size();
 	size_t pathCount = _pathConstraints.size();
 	size_t pathCount = _pathConstraints.size();
 	size_t physicsCount = _physicsConstraints.size();
 	size_t physicsCount = _physicsConstraints.size();
-
 	size_t constraintCount = ikCount + transformCount + pathCount + physicsCount;
 	size_t constraintCount = ikCount + transformCount + pathCount + physicsCount;
 
 
 	size_t i = 0;
 	size_t i = 0;
@@ -510,6 +509,10 @@ Vector<TransformConstraint *> &Skeleton::getTransformConstraints() {
 	return _transformConstraints;
 	return _transformConstraints;
 }
 }
 
 
+Vector<PhysicsConstraint *> &Skeleton::getPhysicsConstraints() {
+    return _physicsConstraints;
+}
+
 Skin *Skeleton::getSkin() {
 Skin *Skeleton::getSkin() {
 	return _skin;
 	return _skin;
 }
 }

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

@@ -157,7 +157,7 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 		data->_shearX = readFloat(input);
 		data->_shearX = readFloat(input);
 		data->_shearY = readFloat(input);
 		data->_shearY = readFloat(input);
 		data->_length = readFloat(input) * _scale;
 		data->_length = readFloat(input) * _scale;
-		data->_transformMode = static_cast<TransformMode>(readVarint(input, true));
+		data->_inherit = static_cast<Inherit>(readVarint(input, true));
 		data->_skinRequired = readBoolean(input);
 		data->_skinRequired = readBoolean(input);
 		if (nonessential) {
 		if (nonessential) {
 			readColor(input, data->getColor());
 			readColor(input, data->getColor());

+ 9 - 0
spine-cpp/spine-cpp/src/spine/SkeletonData.cpp

@@ -49,6 +49,7 @@ SkeletonData::SkeletonData() : _name(),
 							   _y(0),
 							   _y(0),
 							   _width(0),
 							   _width(0),
 							   _height(0),
 							   _height(0),
+							   _referenceScale(100),
 							   _version(),
 							   _version(),
 							   _hash(),
 							   _hash(),
 							   _fps(0),
 							   _fps(0),
@@ -193,6 +194,14 @@ void SkeletonData::setHeight(float inValue) {
 	_height = inValue;
 	_height = inValue;
 }
 }
 
 
+float SkeletonData::getReferenceScale() {
+	return _referenceScale;
+}
+
+void SkeletonData::setReferenceScale(float inValue) {
+	_referenceScale = inValue;
+}
+
 const String &SkeletonData::getVersion() {
 const String &SkeletonData::getVersion() {
 	return _version;
 	return _version;
 }
 }

+ 7 - 7
spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp

@@ -194,17 +194,17 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
 		data->_scaleY = Json::getFloat(boneMap, "scaleY", 1);
 		data->_scaleY = Json::getFloat(boneMap, "scaleY", 1);
 		data->_shearX = Json::getFloat(boneMap, "shearX", 0);
 		data->_shearX = Json::getFloat(boneMap, "shearX", 0);
 		data->_shearY = Json::getFloat(boneMap, "shearY", 0);
 		data->_shearY = Json::getFloat(boneMap, "shearY", 0);
-		transformMode = Json::getString(boneMap, "transform", "normal");
-		data->_transformMode = TransformMode_Normal;
-		if (strcmp(transformMode, "normal") == 0) data->_transformMode = TransformMode_Normal;
+		transformMode = Json::getString(boneMap, "inherit", "normal");
+		data->_inherit = Inherit_Normal;
+		if (strcmp(transformMode, "normal") == 0) data->_inherit = Inherit_Normal;
 		else if (strcmp(transformMode, "onlyTranslation") == 0)
 		else if (strcmp(transformMode, "onlyTranslation") == 0)
-			data->_transformMode = TransformMode_OnlyTranslation;
+			data->_inherit = Inherit_OnlyTranslation;
 		else if (strcmp(transformMode, "noRotationOrReflection") == 0)
 		else if (strcmp(transformMode, "noRotationOrReflection") == 0)
-			data->_transformMode = TransformMode_NoRotationOrReflection;
+			data->_inherit = Inherit_NoRotationOrReflection;
 		else if (strcmp(transformMode, "noScale") == 0)
 		else if (strcmp(transformMode, "noScale") == 0)
-			data->_transformMode = TransformMode_NoScale;
+			data->_inherit = Inherit_NoScale;
 		else if (strcmp(transformMode, "noScaleOrReflection") == 0)
 		else if (strcmp(transformMode, "noScaleOrReflection") == 0)
-			data->_transformMode = TransformMode_NoScaleOrReflection;
+			data->_inherit = Inherit_NoScaleOrReflection;
 		data->_skinRequired = Json::getBoolean(boneMap, "skin", false);
 		data->_skinRequired = Json::getBoolean(boneMap, "skin", false);
 
 
 		const char *color = Json::getString(boneMap, "color", NULL);
 		const char *color = Json::getString(boneMap, "color", NULL);

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

@@ -88,7 +88,7 @@ Skin::AttachmentMap::Entries Skin::AttachmentMap::getEntries() {
 	return Skin::AttachmentMap::Entries(_buckets);
 	return Skin::AttachmentMap::Entries(_buckets);
 }
 }
 
 
-Skin::Skin(const String &name) : _name(name), _attachments() {
+Skin::Skin(const String &name) : _name(name), _attachments(), _color(0.99607843f, 0.61960787f, 0.30980393f, 1) {
 	assert(_name.length() > 0);
 	assert(_name.length() > 0);
 }
 }
 
 

+ 2 - 1
spine-sdl/src/spine-sdl-cpp.cpp

@@ -54,7 +54,8 @@ SkeletonDrawable::~SkeletonDrawable() {
 void SkeletonDrawable::update(float delta) {
 void SkeletonDrawable::update(float delta) {
 	animationState->update(delta);
 	animationState->update(delta);
 	animationState->apply(*skeleton);
 	animationState->apply(*skeleton);
-	skeleton->updateWorldTransform();
+    skeleton->update(delta);
+	skeleton->updateWorldTransform(Physics_Update);
 }
 }
 
 
 void SkeletonDrawable::draw(SDL_Renderer *renderer) {
 void SkeletonDrawable::draw(SDL_Renderer *renderer) {