Browse Source

[cpp] Initial pass at physics, incomplete

Mario Zechner 1 year ago
parent
commit
5ffdcdb1e6

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

@@ -209,16 +209,22 @@ namespace spine {
 		/// When the mix percentage (mix time / mix duration) is less than the attachment threshold, attachment timelines for the
 		/// animation being mixed out will be applied. Defaults to 0, so attachment timelines are not applied for an animation being
 		/// mixed out.
-		float getAttachmentThreshold();
+		float getMixAttachmentThreshold();
 
-		void setAttachmentThreshold(float inValue);
+		void setMixAttachmentThreshold(float inValue);
+
+        /// When getAlpha() is greater than alphaAttachmentThreshold, attachment timelines are applied.
+	    /// Defaults to 0, so attachment timelines are always applied. */
+        float getAlphaAttachmentThreshold();
+
+        void setAlphaAttachmentThreshold(float inValue);
 
 		/// When the mix percentage (mix time / mix duration) is less than the draw order threshold, draw order timelines for the
 		/// animation being mixed out will be applied. Defaults to 0, so draw order timelines are not applied for an animation being
 		/// mixed out.
-		float getDrawOrderThreshold();
+		float getMixDrawOrderThreshold();
 
-		void setDrawOrderThreshold(float inValue);
+		void setMixDrawOrderThreshold(float inValue);
 
 		/// The animation queued to start after this animation, or NULL.
 		TrackEntry *getNext();
@@ -271,6 +277,8 @@ namespace spine {
 
 		void setListener(AnimationStateListenerObject *listener);
 
+        bool wasApplied();
+
 	private:
 		Animation *_animation;
 		TrackEntry *_previous;
@@ -280,7 +288,7 @@ namespace spine {
 		int _trackIndex;
 
 		bool _loop, _holdPrevious, _reverse, _shortestRotation;
-		float _eventThreshold, _attachmentThreshold, _drawOrderThreshold;
+		float _eventThreshold, _mixAttachmentThreshold, _alphaAttachmentThreshold, _mixDrawOrderThreshold;
 		float _animationStart, _animationEnd, _animationLast, _nextAnimationLast;
 		float _delay, _trackTime, _trackLast, _nextTrackLast, _trackEnd, _timeScale;
 		float _alpha, _mixTime, _mixDuration, _interruptAlpha, _totalAlpha;

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

@@ -57,6 +57,8 @@ namespace spine {
 
 		friend class PathConstraint;
 
+        friend class PhysicsConstraint;
+
 		friend class Skeleton;
 
 		friend class RegionAttachment;
@@ -104,7 +106,7 @@ namespace spine {
 		Bone(BoneData &data, Skeleton &skeleton, Bone *parent = NULL);
 
 		/// Same as updateWorldTransform. This method exists for Bone to implement Spine::Updatable.
-		virtual void update();
+		virtual void update(Physics physics);
 
 		/// Computes the world transform using the parent bone and this bone's local transform.
 		void updateWorldTransform();

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

@@ -125,6 +125,14 @@ namespace spine {
 
 		Color &getColor();
 
+        const String &getIcon();
+
+        void setIcon(const String &icon);
+
+        bool isVisible();
+
+        void setVisible(bool inValue);
+
 	private:
 		const int _index;
 		const String _name;
@@ -134,6 +142,8 @@ namespace spine {
 		TransformMode _transformMode;
 		bool _skinRequired;
 		Color _color;
+        String _icon;
+        bool _visible;
 	};
 }
 

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

@@ -64,7 +64,7 @@ namespace spine {
 
 		IkConstraint(IkConstraintData &data, Skeleton &skeleton);
 
-		virtual void update();
+		virtual void update(Physics physics);
 
 		virtual int getOrder();
 
@@ -100,6 +100,8 @@ namespace spine {
 
 		void setActive(bool inValue);
 
+        void setToSetupPose();
+
 	private:
 		IkConstraintData &_data;
 		Vector<Bone *> _bones;

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

@@ -46,6 +46,7 @@ namespace spine {
 	public:
 		static const float Pi;
 		static const float Pi_2;
+        static const float InvPi_2;
 		static const float Deg_Rad;
 		static const float Rad_Deg;
 
@@ -77,6 +78,8 @@ namespace spine {
 		/// degrees), largest error of 0.00488 radians (0.2796 degrees).
 		static float atan2(float y, float x);
 
+        static float atan2Deg(float x, float y);
+
 		static float acos(float v);
 
 		static float sqrt(float v);
@@ -92,6 +95,8 @@ namespace spine {
 		static float randomTriangular(float min, float max, float mode);
 
 		static float pow(float a, float b);
+
+        static float ceil(float v);
 	};
 
 	struct SP_API Interpolation {

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

@@ -59,7 +59,7 @@ namespace spine {
 	public:
 		PathConstraint(PathConstraintData &data, Skeleton &skeleton);
 
-		virtual void update();
+		virtual void update(Physics physics);
 
 		virtual int getOrder();
 
@@ -95,6 +95,8 @@ namespace spine {
 
 		void setActive(bool inValue);
 
+        void setToSetupPose();
+
 	private:
 		static const float EPSILON;
 		static const int NONE;

+ 49 - 0
spine-cpp/spine-cpp/include/spine/Physics.h

@@ -0,0 +1,49 @@
+/******************************************************************************
+ * 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_Physics_h
+#define Spine_Physics_h
+
+/** Determines how physics and other non-deterministic updates are applied. */
+namespace spine {
+    enum Physics {
+        /** Physics are not updated or applied. */
+        none,
+
+        /** Physics are reset to the current pose. */
+        reset,
+
+        /** Physics are updated and the pose from physics is applied. */
+        update,
+
+        /** Physics are not updated but the pose from physics is applied. */
+        pose
+    };
+}
+
+#endif

+ 170 - 0
spine-cpp/spine-cpp/include/spine/PhysicsConstraint.h

@@ -0,0 +1,170 @@
+/******************************************************************************
+ * 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_PhysicsConstraint_h
+#define Spine_PhysicsConstraint_h
+
+#include <spine/ConstraintData.h>
+
+#include <spine/Vector.h>
+
+namespace spine {
+	class PhysicsConstraintData;
+
+	class Skeleton;
+
+	class Bone;
+
+    class SP_API PhysicsConstraint : public Updatable {
+
+    RTTI_DECL
+    public:
+        explicit PhysicsConstraint(PhysicsConstraintData& data, Skeleton& skeleton);
+
+        void setBone(Bone* bone);
+        Bone* getBone() const;
+
+        void setInertia(float value);
+        float getInertia() const;
+
+        void setStrength(float value);
+        float getStrength() const;
+
+        void setDamping(float value);
+        float getDamping() const;
+
+        void setMassInverse(float value);
+        float getMassInverse() const;
+
+        void setWind(float value);
+        float getWind() const;
+
+        void setGravity(float value);
+        float getGravity() const;
+
+        void setMix(float value);
+        float getMix() const;
+
+        void setReset(bool value);
+        bool getReset() const;
+
+        void setUx(float value);
+        float getUx() const;
+
+        void setUy(float value);
+        float getUy() const;
+
+        void setCx(float value);
+        float getCx() const;
+
+        void setCy(float value);
+        float getCy() const;
+
+        void setTx(float value);
+        float getTx() const;
+
+        void setTy(float value);
+        float getTy() const;
+
+        void setXOffset(float value);
+        float getXOffset() const;
+
+        void setXVelocity(float value);
+        float getXVelocity() const;
+
+        void setYOffset(float value);
+        float getYOffset() const;
+
+        void setYVelocity(float value);
+        float getYVelocity() const;
+
+        void setRotateOffset(float value);
+        float getRotateOffset() const;
+
+        void setRotateVelocity(float value);
+        float getRotateVelocity() const;
+
+        void setScaleOffset(float value);
+        float getScaleOffset() const;
+
+        void setScaleVelocity(float value);
+        float getScaleVelocity() const;
+
+        void setActive(bool value);
+        bool isActive() const;
+
+        void setRemaining(float value);
+        float getRemaining() const;
+
+        void setLastTime(float value);
+        float getLastTime() const;
+
+        void reset();
+
+        void setToSetupPose();
+
+        void update(Physics physics) override;
+
+    private:
+        const PhysicsConstraintData& _data;
+        Bone* _bone;
+
+        float _inertia;
+        float _strength;
+        float _damping;
+        float _massInverse;
+        float _wind;
+        float _gravity;
+        float _mix;
+
+        bool _reset;
+        float _ux;
+        float _uy;
+        float _cx;
+        float _cy;
+        float _tx;
+        float _ty;
+        float _xOffset;
+        float _xVelocity;
+        float _yOffset;
+        float _yVelocity;
+        float _rotateOffset;
+        float _rotateVelocity;
+        float _scaleOffset;
+        float _scaleVelocity;
+
+        bool _active;
+
+        Skeleton& _skeleton;
+        float _remaining;
+        float _lastTime;
+    };
+}
+
+#endif /* Spine_PhysicsConstraint_h */

+ 147 - 0
spine-cpp/spine-cpp/include/spine/PhysicsConstraintData.h

@@ -0,0 +1,147 @@
+/******************************************************************************
+ * 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_PhysicsConstraintData_h
+#define Spine_PhysicsConstraintData_h
+
+#include <spine/Vector.h>
+#include <spine/SpineObject.h>
+#include <spine/SpineString.h>
+#include <spine/ConstraintData.h>
+
+namespace spine {
+	class BoneData;
+
+	class SP_API PhysicsConstraintData : public ConstraintData {
+		friend class SkeletonBinary;
+
+		friend class SkeletonJson;
+
+		friend class Skeleton;
+
+        friend class PhysicsConstraint;
+
+	public:
+		RTTI_DECL
+
+		explicit PhysicsConstraintData(const String &name);
+
+        void setBone(BoneData* bone);
+
+        BoneData* getBone() const;
+
+        void setX(float x);
+
+        float getX() const;
+
+        void setY(float y);
+
+        float getY() const;
+
+        void setRotate(float rotate);
+
+        float getRotate() const;
+
+        void setScaleX(float scaleX);
+
+        float getScaleX() const;
+
+        void setShearX(float shearX);
+
+        float getShearX() const;
+
+        void setStep(float step);
+
+        float getStep() const;
+
+        void setInertia(float inertia);
+
+        float getInertia() const;
+
+        void setStrength(float strength);
+
+        float getStrength() const;
+
+        void setDamping(float damping);
+
+        float getDamping() const;
+
+        void setMassInverse(float massInverse);
+
+        float getMassInverse() const;
+
+        void setWind(float wind);
+
+        float getWind() const;
+
+        void setGravity(float gravity);
+
+        float getGravity() const;
+
+        void setMix(float mix);
+
+        float getMix() const;
+
+        void setInertiaGlobal(bool inertiaGlobal);
+
+        bool isInertiaGlobal() const;
+
+        void setStrengthGlobal(bool strengthGlobal);
+
+        bool isStrengthGlobal() const;
+
+        void setDampingGlobal(bool dampingGlobal);
+
+        bool isDampingGlobal() const;
+
+        void setMassGlobal(bool massGlobal);
+
+        bool isMassGlobal() const;
+
+        void setWindGlobal(bool windGlobal);
+
+        bool isWindGlobal() const;
+
+        void setGravityGlobal(bool gravityGlobal);
+
+        bool isGravityGlobal() const;
+
+        void setMixGlobal(bool mixGlobal);
+
+        bool isMixGlobal() const;
+
+	private:
+		BoneData *_bone;
+        float _x, _y, _rotate, _scaleX, _shearX;
+        float _step, _inertia, _strength, _damping, _massInverse, _wind, _gravity, _mix;
+        bool _inertiaGlobal, _strengthGlobal, _dampingGlobal, _massGlobal, _windGlobal, _gravityGlobal, _mixGlobal;
+	};
+}
+
+#endif /* Spine_PhysicsConstraintData_h */

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

@@ -49,6 +49,8 @@ namespace spine {
 
 	class PathConstraint;
 
+    class PhysicsConstraint;
+
 	class TransformConstraint;
 
 	class Skin;
@@ -220,6 +222,12 @@ namespace spine {
 
 		void setScaleY(float inValue);
 
+        float getTime();
+
+        float setTime(float time);
+
+        void update(float delta);
+
 	private:
 		SkeletonData *_data;
 		Vector<Bone *> _bones;
@@ -233,11 +241,14 @@ namespace spine {
 		Color _color;
 		float _scaleX, _scaleY;
 		float _x, _y;
+        float _time;
 
 		void sortIkConstraint(IkConstraint *constraint);
 
 		void sortPathConstraint(PathConstraint *constraint);
 
+        void sortPhysicsConstraint(PhysicsConstraint *constraint);
+
 		void sortTransformConstraint(TransformConstraint *constraint);
 
 		void sortPathConstraintAttachment(Skin *skin, size_t slotIndex, Bone &slotBone);

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

@@ -105,6 +105,10 @@ namespace spine {
 
 		void setBlendMode(BlendMode inValue);
 
+        bool isVisible();
+
+        void setVisible(bool inValue);
+
 	private:
 		const int _index;
 		String _name;
@@ -115,6 +119,7 @@ namespace spine {
 		bool _hasDarkColor;
 		String _attachmentName;
 		BlendMode _blendMode;
+        bool _visible;
 	};
 }
 

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

@@ -51,7 +51,7 @@ namespace spine {
 	public:
 		TransformConstraint(TransformConstraintData &data, Skeleton &skeleton);
 
-		virtual void update();
+		virtual void update(Physics physics);
 
 		virtual int getOrder();
 
@@ -91,6 +91,8 @@ namespace spine {
 
 		void setActive(bool inValue);
 
+        void setToSetupPose();
+
 	private:
 		TransformConstraintData &_data;
 		Vector<Bone *> _bones;

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

@@ -32,6 +32,7 @@
 
 #include <spine/RTTI.h>
 #include <spine/SpineObject.h>
+#include <spine/Physics.h>
 
 namespace spine {
 	class SP_API Updatable : public SpineObject {
@@ -42,7 +43,7 @@ namespace spine {
 
 		virtual ~Updatable();
 
-		virtual void update() = 0;
+		virtual void update(Physics physics) = 0;
 
 		virtual bool isActive() = 0;
 

+ 35 - 23
spine-cpp/spine-cpp/src/spine/AnimationState.cpp

@@ -56,7 +56,7 @@ void dummyOnAnimationEventFunc(AnimationState *state, spine::EventType type, Tra
 TrackEntry::TrackEntry() : _animation(NULL), _previous(NULL), _next(NULL), _mixingFrom(NULL), _mixingTo(0),
 						   _trackIndex(0), _loop(false), _holdPrevious(false), _reverse(false),
 						   _shortestRotation(false),
-						   _eventThreshold(0), _attachmentThreshold(0), _drawOrderThreshold(0), _animationStart(0),
+						   _eventThreshold(0), _mixAttachmentThreshold(0), _alphaAttachmentThreshold(0), _mixDrawOrderThreshold(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), _mixBlend(MixBlend_Replace),
@@ -136,13 +136,17 @@ float TrackEntry::getEventThreshold() { return _eventThreshold; }
 
 void TrackEntry::setEventThreshold(float inValue) { _eventThreshold = inValue; }
 
-float TrackEntry::getAttachmentThreshold() { return _attachmentThreshold; }
+float TrackEntry::getMixAttachmentThreshold() { return _mixAttachmentThreshold; }
 
-void TrackEntry::setAttachmentThreshold(float inValue) { _attachmentThreshold = inValue; }
+void TrackEntry::setMixAttachmentThreshold(float inValue) { _mixAttachmentThreshold = inValue; }
 
-float TrackEntry::getDrawOrderThreshold() { return _drawOrderThreshold; }
+float TrackEntry::getAlphaAttachmentThreshold() { return _alphaAttachmentThreshold; }
 
-void TrackEntry::setDrawOrderThreshold(float inValue) { _drawOrderThreshold = inValue; }
+void TrackEntry::setAlphaAttachmentThreshold(float inValue) { _alphaAttachmentThreshold = inValue; }
+
+float TrackEntry::getMixDrawOrderThreshold() { return _mixDrawOrderThreshold; }
+
+void TrackEntry::setMixDrawOrderThreshold(float inValue) { _mixDrawOrderThreshold = inValue; }
 
 TrackEntry *TrackEntry::getNext() { return _next; }
 
@@ -206,6 +210,10 @@ float TrackEntry::getTrackComplete() {
 	return _trackTime;// Next update.
 }
 
+bool TrackEntry::wasApplied() {
+    return _nextTrackLast != -1;
+}
+
 EventQueueEntry::EventQueueEntry(EventType eventType, TrackEntry *trackEntry, Event *event) : _type(eventType),
 																							  _entry(trackEntry),
 																							  _event(event) {
@@ -428,14 +436,16 @@ bool AnimationState::apply(Skeleton &skeleton) {
 		MixBlend blend = i == 0 ? MixBlend_First : current._mixBlend;
 
 		// apply mixing from entries first.
-		float mix = current._alpha;
+		float alpha = current._alpha;
 		if (current._mixingFrom != NULL) {
-			mix *= applyMixingFrom(currentP, skeleton, blend);
+            alpha *= 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.
+            alpha = 0;// Set to setup pose the last time the entry will be applied.
 		}
+        bool attachments = alpha >= current._alphaAttachmentThreshold;
+
 
-		// apply current entry.
+        // apply current entry.
 		float animationLast = current._animationLast, animationTime = current.getAnimationTime();
 		float applyTime = animationTime;
 		Vector<Event *> *applyEvents = &_events;
@@ -445,14 +455,15 @@ bool AnimationState::apply(Skeleton &skeleton) {
 		}
 		size_t timelineCount = current._animation->_timelines.size();
 		Vector<Timeline *> &timelines = current._animation->_timelines;
-		if ((i == 0 && mix == 1) || blend == MixBlend_Add) {
-			for (size_t ii = 0; ii < timelineCount; ++ii) {
+		if ((i == 0 && alpha == 1) || blend == MixBlend_Add) {
+            if (i == 0) attachments = true;
+            for (size_t ii = 0; ii < timelineCount; ++ii) {
 				Timeline *timeline = timelines[ii];
 				if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))
 					applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, applyTime, blend,
-											true);
+											attachments);
 				else
-					timeline->apply(skeleton, animationLast, applyTime, applyEvents, mix, blend, MixDirection_In);
+					timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, MixDirection_In);
 			}
 		} else {
 			Vector<int> &timelineMode = current._timelineMode;
@@ -469,14 +480,14 @@ bool AnimationState::apply(Skeleton &skeleton) {
 				MixBlend timelineBlend = timelineMode[ii] == Subsequent ? blend : MixBlend_Setup;
 
 				if (!shortestRotation && timeline->getRTTI().isExactly(RotateTimeline::rtti))
-					applyRotateTimeline(static_cast<RotateTimeline *>(timeline), skeleton, applyTime, mix,
-										timelineBlend, timelinesRotation, ii << 1, firstFrame);
+					applyRotateTimeline(static_cast<RotateTimeline *>(timeline), skeleton, applyTime, alpha,
+                                        timelineBlend, timelinesRotation, ii << 1, firstFrame);
 				else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti))
 					applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, applyTime,
 											timelineBlend, true);
 				else
-					timeline->apply(skeleton, animationLast, applyTime, applyEvents, mix, timelineBlend,
-									MixDirection_In);
+					timeline->apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend,
+                                    MixDirection_In);
 			}
 		}
 
@@ -733,8 +744,8 @@ void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleto
 
 	// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
 	float total, diff = r2 - r1;
-	diff -= (16384 - (int) (16384.499999999996 - diff / 360)) * 360;
-	if (diff == 0) {
+    diff -= MathUtil::ceil(diff / 360 - 0.5) * 360;
+    if (diff == 0) {
 		total = timelinesRotation[i];
 	} else {
 		float lastTotal, lastDiff;
@@ -812,7 +823,7 @@ float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixBle
 		if (blend != MixBlend_First) blend = from->_mixBlend;
 	}
 
-	bool attachments = mix < from->_attachmentThreshold, drawOrder = mix < from->_drawOrderThreshold;
+	bool attachments = mix < from->_mixAttachmentThreshold, drawOrder = mix < from->_mixDrawOrderThreshold;
 	Vector<Timeline *> &timelines = from->_animation->_timelines;
 	size_t timelineCount = timelines.size();
 	float alphaHold = from->_alpha * to->_interruptAlpha, alphaMix = alphaHold * (1 - mix);
@@ -874,7 +885,7 @@ float AnimationState::applyMixingFrom(TrackEntry *to, Skeleton &skeleton, MixBle
 									timelinesRotation, i << 1, firstFrame);
 			} else if (timeline->getRTTI().isExactly(AttachmentTimeline::rtti)) {
 				applyAttachmentTimeline(static_cast<AttachmentTimeline *>(timeline), skeleton, applyTime, timelineBlend,
-										attachments);
+                                        attachments && alpha >= from->_alphaAttachmentThreshold);
 			} else {
 				if (drawOrder && timeline->getRTTI().isExactly(DrawOrderTimeline::rtti) &&
 					timelineBlend == MixBlend_Setup)
@@ -974,8 +985,9 @@ TrackEntry *AnimationState::newTrackEntry(size_t trackIndex, Animation *animatio
 	entry._shortestRotation = false;
 
 	entry._eventThreshold = 0;
-	entry._attachmentThreshold = 0;
-	entry._drawOrderThreshold = 0;
+	entry._mixAttachmentThreshold = 0;
+    entry._alphaAttachmentThreshold = 0;
+	entry._mixDrawOrderThreshold = 0;
 
 	entry._animationStart = 0;
 	entry._animationEnd = animation->getDuration();

+ 102 - 106
spine-cpp/spine-cpp/src/spine/Bone.cpp

@@ -75,7 +75,7 @@ Bone::Bone(BoneData &data, Skeleton &skeleton, Bone *parent) : Updatable(),
 	setToSetupPose();
 }
 
-void Bone::update() {
+void Bone::update(Physics physics) {
 	updateWorldTransform(_ax, _ay, _arotation, _ascaleX, _ascaleY, _ashearX, _ashearY);
 }
 
@@ -84,7 +84,6 @@ void Bone::updateWorldTransform() {
 }
 
 void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) {
-	float cosine, sine;
 	float pa, pb, pc, pd;
 	Bone *parent = _parent;
 
@@ -97,13 +96,15 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 	_ashearY = shearY;
 
 	if (!parent) { /* Root bone. */
-		float rotationY = rotation + 90 + shearY;
-		float sx = _skeleton.getScaleX();
-		float sy = _skeleton.getScaleY();
-		_a = MathUtil::cosDeg(rotation + shearX) * scaleX * sx;
-		_b = MathUtil::cosDeg(rotationY) * scaleY * sx;
-		_c = MathUtil::sinDeg(rotation + shearX) * scaleX * sy;
-		_d = MathUtil::sinDeg(rotationY) * scaleY * sy;
+        auto skeleton = this->_skeleton;
+        float sx = skeleton.getScaleX();
+        float sy = skeleton.getScaleY();
+        float rx = (rotation + shearX) * MathUtil::Deg_Rad;
+        float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
+        _a = MathUtil::cos(rx) * scaleX * sx;
+        _b = MathUtil::cos(ry) * scaleY * sx;
+        _c = MathUtil::sin(rx) * scaleX * sy;
+        _d = MathUtil::sin(ry) * scaleY * sy;
 		_worldX = x * sx + _skeleton.getX();
 		_worldY = y * sy + _skeleton.getY();
 		return;
@@ -119,11 +120,12 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 
 	switch (_data.getTransformMode()) {
 		case TransformMode_Normal: {
-			float rotationY = rotation + 90 + shearY;
-			float la = MathUtil::cosDeg(rotation + shearX) * scaleX;
-			float lb = MathUtil::cosDeg(rotationY) * scaleY;
-			float lc = MathUtil::sinDeg(rotation + shearX) * scaleX;
-			float ld = MathUtil::sinDeg(rotationY) * scaleY;
+            float rx = (rotation + shearX) * MathUtil::Deg_Rad;
+            float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
+            float la = MathUtil::cos(rx) * scaleX;
+            float lb = MathUtil::cos(ry) * scaleY;
+            float lc = MathUtil::sin(rx) * scaleX;
+            float ld = MathUtil::sin(ry) * scaleY;
 			_a = pa * la + pb * lc;
 			_b = pa * lb + pb * ld;
 			_c = pc * la + pd * lc;
@@ -131,16 +133,17 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 			return;
 		}
 		case TransformMode_OnlyTranslation: {
-			float rotationY = rotation + 90 + shearY;
-			_a = MathUtil::cosDeg(rotation + shearX) * scaleX;
-			_b = MathUtil::cosDeg(rotationY) * scaleY;
-			_c = MathUtil::sinDeg(rotation + shearX) * scaleX;
-			_d = MathUtil::sinDeg(rotationY) * scaleY;
+            float rx = (rotation + shearX) * MathUtil::Deg_Rad;
+            float ry = (rotation + 90 + shearY) * MathUtil::Deg_Rad;
+            _a = MathUtil::cos(rx) * scaleX;
+            _b = MathUtil::cos(ry) * scaleY;
+            _c = MathUtil::sin(rx) * scaleX;
+            _d = MathUtil::sin(ry) * scaleY;
 			break;
 		}
 		case TransformMode_NoRotationOrReflection: {
 			float s = pa * pa + pc * pc;
-			float prx, rx, ry, la, lb, lc, ld;
+			float prx;
 			if (s > 0.0001f) {
 				s = MathUtil::abs(pa * pd - pb * pc) / s;
 				pa /= _skeleton.getScaleX();
@@ -153,12 +156,12 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 				pc = 0;
 				prx = 90 - MathUtil::atan2(pd, pb) * MathUtil::Rad_Deg;
 			}
-			rx = rotation + shearX - prx;
-			ry = rotation + shearY - prx + 90;
-			la = MathUtil::cosDeg(rx) * scaleX;
-			lb = MathUtil::cosDeg(ry) * scaleY;
-			lc = MathUtil::sinDeg(rx) * scaleX;
-			ld = MathUtil::sinDeg(ry) * scaleY;
+            float rx = (rotation + shearX - prx) * MathUtil::Deg_Rad;
+            float ry = (rotation + shearY - prx + 90) * MathUtil::Deg_Rad;
+            float la = MathUtil::cos(rx) * scaleX;
+            float lb = MathUtil::cos(ry) * scaleY;
+            float lc = MathUtil::sin(rx) * scaleX;
+            float ld = MathUtil::sin(ry) * scaleY;
 			_a = pa * la - pb * lc;
 			_b = pa * lb - pb * ld;
 			_c = pc * la + pd * lc;
@@ -167,13 +170,12 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 		}
 		case TransformMode_NoScale:
 		case TransformMode_NoScaleOrReflection: {
-			float za, zc, s;
-			float r, zb, zd, la, lb, lc, ld;
-			cosine = MathUtil::cosDeg(rotation);
-			sine = MathUtil::sinDeg(rotation);
-			za = (pa * cosine + pb * sine) / _skeleton.getScaleX();
-			zc = (pc * cosine + pd * sine) / _skeleton.getScaleY();
-			s = MathUtil::sqrt(za * za + zc * zc);
+            rotation *= MathUtil::Deg_Rad;
+            float cosine = MathUtil::cos(rotation);
+            float sine = MathUtil::sin(rotation);
+			float za = (pa * cosine + pb * sine) / _skeleton.getScaleX();
+			float zc = (pc * cosine + pd * sine) / _skeleton.getScaleY();
+			float s = MathUtil::sqrt(za * za + zc * zc);
 			if (s > 0.00001f) s = 1 / s;
 			za *= s;
 			zc *= s;
@@ -181,13 +183,15 @@ void Bone::updateWorldTransform(float x, float y, float rotation, float scaleX,
 			if (_data.getTransformMode() == TransformMode_NoScale &&
 				(pa * pd - pb * pc < 0) != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0))
 				s = -s;
-			r = MathUtil::Pi / 2 + MathUtil::atan2(zc, za);
-			zb = MathUtil::cos(r) * s;
-			zd = MathUtil::sin(r) * s;
-			la = MathUtil::cosDeg(shearX) * scaleX;
-			lb = MathUtil::cosDeg(90 + shearY) * scaleY;
-			lc = MathUtil::sinDeg(shearX) * scaleX;
-			ld = MathUtil::sinDeg(90 + shearY) * scaleY;
+            rotation = MathUtil::Pi / 2 + MathUtil::atan2(zc, za);
+            float zb = MathUtil::cos(rotation) * s;
+            float zd = MathUtil::sin(rotation) * s;
+            shearX *= MathUtil::Deg_Rad;
+            shearY = (90 + shearY) * MathUtil::Deg_Rad;
+            float la = MathUtil::cos(shearX) * scaleX;
+            float lb = MathUtil::cos(shearY) * scaleY;
+            float lc = MathUtil::sin(shearX) * scaleX;
+            float ld = MathUtil::sin(shearY) * scaleY;
 			_a = za * la + zb * lc;
 			_b = za * lb + zb * ld;
 			_c = zc * la + zd * lc;
@@ -247,18 +251,13 @@ float Bone::localToWorldRotation(float localRotation) {
 }
 
 void Bone::rotateWorld(float degrees) {
-	float a = _a;
-	float b = _b;
-	float c = _c;
-	float d = _d;
-
-	float cos = MathUtil::cosDeg(degrees);
-	float sin = MathUtil::sinDeg(degrees);
-
-	_a = cos * a - sin * c;
-	_b = cos * b - sin * d;
-	_c = sin * a + cos * c;
-	_d = sin * b + cos * d;
+    degrees *= MathUtil::Deg_Rad;
+    float sine = MathUtil::sin(degrees), cosine = MathUtil::cos(degrees);
+    float ra = _a, rb = _b;
+    _a = cosine * ra - sine * _c;
+    _b = cosine * rb - sine * _d;
+    _c = sine * ra + cosine * _c;
+    _d = sine * rb + cosine * _d;
 }
 
 float Bone::getWorldToLocalRotationX() {
@@ -498,67 +497,64 @@ void Bone::updateAppliedTransform() {
 	}
 	float pa = parent->_a, pb = parent->_b, pc = parent->_c, pd = parent->_d;
 	float pid = 1 / (pa * pd - pb * pc);
-	float ia = pd * pid, ib = pb * pid, ic = pc * pid, id = pa * pid;
-	float dx = _worldX - parent->_worldX, dy = _worldY - parent->_worldY;
+    float ia = pd * pid, ib = pb * pid, ic = pc * pid, id = pa * pid;
+    float dx = _worldX - parent->_worldX, dy = _worldY - parent->_worldY;
 	_ax = (dx * ia - dy * ib);
 	_ay = (dy * id - dx * ic);
 
-	float ra, rb, rc, rd;
-	if (_data.getTransformMode() == TransformMode_OnlyTranslation) {
-		ra = _a;
-		rb = _b;
-		rc = _c;
-		rd = _d;
-	} else {
-		switch (_data.getTransformMode()) {
-			case TransformMode_NoRotationOrReflection: {
-				float s = MathUtil::abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
-				float sa = pa / _skeleton.getScaleX();
-				float sc = pc / _skeleton.getScaleY();
-				pb = -sc * s * _skeleton.getScaleX();
-				pd = sa * s * _skeleton.getScaleY();
-				pid = 1 / (pa * pd - pb * pc);
-				ia = pd * pid;
-				ib = pb * pid;
-				break;
-			}
-			case TransformMode_NoScale:
-			case TransformMode_NoScaleOrReflection: {
-				float cos = MathUtil::cosDeg(_rotation), sin = MathUtil::sinDeg(_rotation);
-				pa = (pa * cos + pb * sin) / _skeleton.getScaleX();
-				pc = (pc * cos + pd * sin) / _skeleton.getScaleY();
-				float s = MathUtil::sqrt(pa * pa + pc * pc);
-				if (s > 0.00001f) s = 1 / s;
-				pa *= s;
-				pc *= s;
-				s = MathUtil::sqrt(pa * pa + pc * pc);
-				if (_data.getTransformMode() == TransformMode_NoScale && pid < 0 != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0)) s = -s;
-				float r = MathUtil::Pi / 2 + MathUtil::atan2(pc, pa);
-				pb = MathUtil::cos(r) * s;
-				pd = MathUtil::sin(r) * s;
-				pid = 1 / (pa * pd - pb * pc);
-				ia = pd * pid;
-				ib = pb * pid;
-				ic = pc * pid;
-				id = pa * pid;
-				break;
-			}
-			default:
-				break;
-		}
-		ra = ia * _a - ib * _c;
-		rb = ia * _b - ib * _d;
-		rc = id * _c - ic * _a;
-		rd = id * _d - ic * _b;
-	}
-
-	_ashearX = 0;
+    float ra, rb, rc, rd;
+    if (_data.getTransformMode() == TransformMode_OnlyTranslation) {
+        ra = _a;
+        rb = _b;
+        rc = _c;
+        rd = _d;
+    } else {
+        switch (_data.getTransformMode()) {
+            case TransformMode_NoRotationOrReflection: {
+                float s = MathUtil::abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
+                float sa = pa / _skeleton.getScaleX();
+                float sc = pc / _skeleton.getScaleY();
+                pb = -sc * s * _skeleton.getScaleX();
+                pd = sa * s * _skeleton.getScaleY();
+                pid = 1 / (pa * pd - pb * pc);
+                ia = pd * pid;
+                ib = pb * pid;
+                break;
+            }
+            case TransformMode_NoScale:
+            case TransformMode_NoScaleOrReflection:
+                float cos = MathUtil::cosDeg(_rotation), sin = MathUtil::sinDeg(_rotation);
+                pa = (pa * cos + pb * sin) / _skeleton.getScaleX();
+                pc = (pc * cos + pd * sin) / _skeleton.getScaleY();
+                float s = MathUtil::sqrt(pa * pa + pc * pc);
+                if (s > 0.00001) s = 1 / s;
+                pa *= s;
+                pc *= s;
+                s = MathUtil::sqrt(pa * pa + pc * pc);
+                if (_data.getTransformMode() == TransformMode_NoScale && pid < 0 != (_skeleton.getScaleX() < 0 != _skeleton.getScaleY() < 0)) s = -s;
+                float r = MathUtil::Pi / 2 + MathUtil::atan2(pc, pa);
+                pb = MathUtil::cos(r) * s;
+                pd = MathUtil::sin(r) * s;
+                pid = 1 / (pa * pd - pb * pc);
+                ia = pd * pid;
+                ib = pb * pid;
+                ic = pc * pid;
+                id = pa * pid;
+                break;
+        }
+        ra = ia * _a - ib * _c;
+        rb = ia * _b - ib * _d;
+        rc = id * _c - ic * _a;
+        rd = id * _d - ic * _b;
+    }
+
+    _ashearX = 0;
 	_ascaleX = MathUtil::sqrt(ra * ra + rc * rc);
 	if (_ascaleX > 0.0001f) {
 		float det = ra * rd - rb * rc;
 		_ascaleY = det / _ascaleX;
-		_ashearY = -MathUtil::atan2(ra * rb + rc * rd, det) * MathUtil::Rad_Deg;
-		_arotation = MathUtil::atan2(rc, ra) * MathUtil::Rad_Deg;
+        _ashearY = -MathUtil::atan2(ra * rb + rc * rd, det) * MathUtil::Rad_Deg;
+        _arotation = MathUtil::atan2(rc, ra) * MathUtil::Rad_Deg;
 	} else {
 		_ascaleX = 0;
 		_ascaleY = MathUtil::sqrt(rb * rb + rd * rd);

+ 20 - 1
spine-cpp/spine-cpp/src/spine/BoneData.cpp

@@ -46,7 +46,9 @@ BoneData::BoneData(int index, const String &name, BoneData *parent) : _index(ind
 																	  _shearY(0),
 																	  _transformMode(TransformMode_Normal),
 																	  _skinRequired(false),
-																	  _color() {
+																	  _color(),
+                                                                      _icon(),
+                                                                      _visible(true){
 	assert(index >= 0);
 	assert(_name.length() > 0);
 }
@@ -146,3 +148,20 @@ void BoneData::setSkinRequired(bool inValue) {
 Color &BoneData::getColor() {
 	return _color;
 }
+
+const String &BoneData::getIcon() {
+    return _icon;
+}
+
+void BoneData::setIcon(const String &icon) {
+    this->_icon = icon;
+}
+
+bool BoneData::isVisible() {
+    return _visible;
+}
+
+void BoneData::setVisible(bool inValue) {
+    this->_visible = inValue;
+}
+

+ 20 - 7
spine-cpp/spine-cpp/src/spine/IkConstraint.cpp

@@ -84,12 +84,16 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress
 				ty = targetY - bone._worldY;
 			default:;
 		}
-		float b = bone._data.getLength() * sx, dd = MathUtil::sqrt(tx * tx + ty * ty);
-		if (((compress && dd < b) || (stretch && dd > b)) && (b > 0.0001f)) {
-			float s = (dd / b - 1) * alpha + 1;
-			sx *= s;
-			if (uniform) sy *= s;
-		}
+
+        float b = bone._data.getLength() * sx;
+        if (b > 0.0001) {
+            float dd = tx * tx + ty * ty;
+            if ((compress && dd < b * b) || (stretch && dd > b * b)) {
+                float s = (MathUtil::sqrt(dd) / b - 1) * alpha + 1;
+                sx *= s;
+                if (uniform) sy *= s;
+            }
+        }
 	}
 	bone.updateWorldTransform(bone._ax, bone._ay, bone._arotation + rotationIK * alpha, sx, sy, bone._ashearX,
 							  bone._ashearY);
@@ -279,7 +283,7 @@ IkConstraint::IkConstraint(IkConstraintData &data, Skeleton &skeleton) : Updatab
 	}
 }
 
-void IkConstraint::update() {
+void IkConstraint::update(Physics physics) {
 	if (_mix == 0) return;
 	switch (_bones.size()) {
 		case 1: {
@@ -363,3 +367,12 @@ float IkConstraint::getSoftness() {
 void IkConstraint::setSoftness(float inValue) {
 	_softness = inValue;
 }
+
+void IkConstraint::setToSetupPose() {
+    auto data = this->_data;
+    this->_mix = data._mix;
+    this->_softness = data._softness;
+    this->_bendDirection = data._bendDirection;
+    this->_compress = data._compress;
+    this->_stretch = data._stretch;
+}

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

@@ -40,6 +40,7 @@ using namespace spine;
 
 const float MathUtil::Pi = 3.1415926535897932385f;
 const float MathUtil::Pi_2 = 3.1415926535897932385f * 2;
+const float MathUtil::InvPi_2 = 1 / MathUtil::Pi_2;
 const float MathUtil::Deg_Rad = (3.1415926535897932385f / 180.0f);
 const float MathUtil::Rad_Deg = (180.0f / 3.1415926535897932385f);
 
@@ -66,6 +67,10 @@ float MathUtil::atan2(float y, float x) {
 	return (float) ::atan2(y, x);
 }
 
+float MathUtil::atan2Deg(float x, float y) {
+    return MathUtil::atan2(x, y) * MathUtil::Deg_Rad;
+}
+
 /// Returns the cosine in radians from a lookup table.
 float MathUtil::cos(float radians) {
 	return (float) ::cos(radians);
@@ -122,3 +127,7 @@ float MathUtil::randomTriangular(float min, float max, float mode) {
 float MathUtil::pow(float a, float b) {
 	return (float) ::pow(a, b);
 }
+
+float MathUtil::ceil(float v) {
+    return ::ceil(v);
+}

+ 15 - 8
spine-cpp/spine-cpp/src/spine/PathConstraint.cpp

@@ -66,7 +66,7 @@ PathConstraint::PathConstraint(PathConstraintData &data, Skeleton &skeleton) : U
 	_segments.setSize(10, 0);
 }
 
-void PathConstraint::update() {
+void PathConstraint::update(Physics physics) {
 	Attachment *baseAttachment = _target->getAttachment();
 	if (baseAttachment == NULL || !baseAttachment->getRTTI().instanceOf(PathAttachment::rtti)) {
 		return;
@@ -91,13 +91,11 @@ void PathConstraint::update() {
 					Bone *boneP = _bones[i];
 					Bone &bone = *boneP;
 					float setupLength = bone._data.getLength();
-					if (setupLength < PathConstraint::EPSILON) {
-						_lengths[i] = 0;
-					} else {
-						float x = setupLength * bone._a, y = setupLength * bone._c;
-						_lengths[i] = MathUtil::sqrt(x * x + y * y);
-					}
-				}
+                    float x = setupLength * bone._a;
+                    float y = setupLength * bone._c;
+                    _lengths[i] = MathUtil::sqrt(x * x + y * y);
+
+                }
 			}
 			for (size_t i = 1; i < spacesCount; ++i) {
 				_spaces[i] = spacing;
@@ -580,3 +578,12 @@ bool PathConstraint::isActive() {
 void PathConstraint::setActive(bool inValue) {
 	_active = inValue;
 }
+
+void PathConstraint::setToSetupPose() {
+    auto data = this->_data;
+    this->_position = data._position;
+    this->_spacing = data._spacing;
+    this->_mixRotate = data._mixRotate;
+    this->_mixX = data._mixX;
+    this->_mixY = data._mixY;
+}

+ 464 - 0
spine-cpp/spine-cpp/src/spine/PhysicsConstraint.cpp

@@ -0,0 +1,464 @@
+/******************************************************************************
+ * 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/PhysicsConstraint.h>
+#include <spine/PhysicsConstraintData.h>
+
+#include <spine/Bone.h>
+#include <spine/Skeleton.h>
+#include <spine/BoneData.h>
+
+using namespace spine;
+
+RTTI_IMPL(PhysicsConstraint, Updatable)
+
+PhysicsConstraint::PhysicsConstraint(PhysicsConstraintData& data, Skeleton& skeleton)
+        : _data(data), _skeleton(skeleton) {
+    // Assuming 'bones' is a vector or similar container in 'Skeleton'
+    // and 'index' is an accessible member of 'BoneData' in 'PhysicsConstraintData'
+    _bone = skeleton.getBones()[data.getBone()->getIndex()];  // Adjust based on actual data structure
+
+    _inertia = data.getInertia();
+    _strength = data.getStrength();
+    _damping = data.getDamping();
+    _massInverse = data.getMassInverse();
+    _wind = data.getWind();
+    _gravity = data.getGravity();
+    _mix = data.getMix();
+
+    _reset = true;
+    _ux = 0;
+    _uy = 0;
+    _cx = 0;
+    _cy = 0;
+    _tx = 0;
+    _ty = 0;
+    _xOffset = 0;
+    _xVelocity = 0;
+    _yOffset = 0;
+    _yVelocity = 0;
+    _rotateOffset = 0;
+    _rotateVelocity = 0;
+    _scaleOffset = 0;
+    _scaleVelocity = 0;
+    _active = false;
+    _remaining = 0;
+    _lastTime = 0;
+}
+
+void PhysicsConstraint::setBone(Bone* bone) {
+    _bone = bone;
+}
+
+Bone* PhysicsConstraint::getBone() const {
+    return _bone;
+}
+
+void PhysicsConstraint::setInertia(float value) {
+    _inertia = value;
+}
+
+float PhysicsConstraint::getInertia() const {
+    return _inertia;
+}
+
+void PhysicsConstraint::setStrength(float value) {
+    _strength = value;
+}
+
+float PhysicsConstraint::getStrength() const {
+    return _strength;
+}
+
+void PhysicsConstraint::setDamping(float value) {
+    _damping = value;
+}
+
+float PhysicsConstraint::getDamping() const {
+    return _damping;
+}
+
+void PhysicsConstraint::setMassInverse(float value) {
+    _massInverse = value;
+}
+
+float PhysicsConstraint::getMassInverse() const {
+    return _massInverse;
+}
+
+void PhysicsConstraint::setWind(float value) {
+    _wind = value;
+}
+
+float PhysicsConstraint::getWind() const {
+    return _wind;
+}
+
+void PhysicsConstraint::setGravity(float value) {
+    _gravity = value;
+}
+
+float PhysicsConstraint::getGravity() const {
+    return _gravity;
+}
+
+void PhysicsConstraint::setMix(float value) {
+    _mix = value;
+}
+
+float PhysicsConstraint::getMix() const {
+    return _mix;
+}
+
+void PhysicsConstraint::setReset(bool value) {
+    _reset = value;
+}
+
+bool PhysicsConstraint::getReset() const {
+    return _reset;
+}
+
+void PhysicsConstraint::setUx(float value) {
+    _ux = value;
+}
+
+float PhysicsConstraint::getUx() const {
+    return _ux;
+}
+
+void PhysicsConstraint::setUy(float value) {
+    _uy = value;
+}
+
+float PhysicsConstraint::getUy() const {
+    return _uy;
+}
+
+void PhysicsConstraint::setCx(float value) {
+    _cx = value;
+}
+
+float PhysicsConstraint::getCx() const {
+    return _cx;
+}
+
+void PhysicsConstraint::setCy(float value) {
+    _cy = value;
+}
+
+float PhysicsConstraint::getCy() const {
+    return _cy;
+}
+
+void PhysicsConstraint::setTx(float value) {
+    _tx = value;
+}
+
+float PhysicsConstraint::getTx() const {
+    return _tx;
+}
+
+void PhysicsConstraint::setTy(float value) {
+    _ty = value;
+}
+
+float PhysicsConstraint::getTy() const {
+    return _ty;
+}
+
+void PhysicsConstraint::setXOffset(float value) {
+    _xOffset = value;
+}
+
+float PhysicsConstraint::getXOffset() const {
+    return _xOffset;
+}
+
+void PhysicsConstraint::setXVelocity(float value) {
+    _xVelocity = value;
+}
+
+float PhysicsConstraint::getXVelocity() const {
+    return _xVelocity;
+}
+
+void PhysicsConstraint::setYOffset(float value) {
+    _yOffset = value;
+}
+
+float PhysicsConstraint::getYOffset() const {
+    return _yOffset;
+}
+
+void PhysicsConstraint::setYVelocity(float value) {
+    _yVelocity = value;
+}
+
+float PhysicsConstraint::getYVelocity() const {
+    return _yVelocity;
+}
+
+void PhysicsConstraint::setRotateOffset(float value) {
+    _rotateOffset = value;
+}
+
+float PhysicsConstraint::getRotateOffset() const {
+    return _rotateOffset;
+}
+
+void PhysicsConstraint::setRotateVelocity(float value) {
+    _rotateVelocity = value;
+}
+
+float PhysicsConstraint::getRotateVelocity() const {
+    return _rotateVelocity;
+}
+
+void PhysicsConstraint::setScaleOffset(float value) {
+    _scaleOffset = value;
+}
+
+float PhysicsConstraint::getScaleOffset() const {
+    return _scaleOffset;
+}
+
+void PhysicsConstraint::setScaleVelocity(float value) {
+    _scaleVelocity = value;
+}
+
+float PhysicsConstraint::getScaleVelocity() const {
+    return _scaleVelocity;
+}
+
+void PhysicsConstraint::setActive(bool value) {
+    _active = value;
+}
+
+bool PhysicsConstraint::isActive() const {
+    return _active;
+}
+
+void PhysicsConstraint::setRemaining(float value) {
+    _remaining = value;
+}
+
+float PhysicsConstraint::getRemaining() const {
+    return _remaining;
+}
+
+void PhysicsConstraint::setLastTime(float value) {
+    _lastTime = value;
+}
+
+float PhysicsConstraint::getLastTime() const {
+    return _lastTime;
+}
+
+void PhysicsConstraint::reset() {
+    _remaining = 0;
+    _lastTime = _skeleton.getTime();  // Assuming Skeleton has a method getTime()
+    _reset = true;
+    _xOffset = 0;
+    _xVelocity = 0;
+    _yOffset = 0;
+    _yVelocity = 0;
+    _rotateOffset = 0;
+    _rotateVelocity = 0;
+    _scaleOffset = 0;
+    _scaleVelocity = 0;
+}
+
+void PhysicsConstraint::setToSetupPose() {
+    _inertia = _data.getInertia();
+    _strength = _data.getStrength();
+    _damping = _data.getDamping();
+    _massInverse = _data.getMassInverse();
+    _wind = _data.getWind();
+    _gravity = _data.getGravity();
+    _mix = _data.getMix();
+}
+void PhysicsConstraint::update(Physics physics) {
+    float mix = _mix;
+    if (mix == 0) return;
+
+    bool x = _data._x > 0;
+    bool y = _data._y > 0;
+    bool rotateOrShearX = _data._rotate > 0 || _data._shearX > 0;
+    bool scaleX = _data._scaleX > 0;
+
+    Bone* bone = _bone;
+    float l = bone->_data.getLength();  // Direct access to Bone's length
+
+    switch (physics) {
+        case Physics::none:
+            return;
+        case Physics::reset:
+            reset();
+            // Fall through.
+        case Physics::update: {
+            _remaining += MathUtil::max(_skeleton.getTime() - _lastTime, 0.0f);
+            _lastTime = _skeleton.getTime();
+
+            float bx = bone->_worldX, by = bone->_worldY;
+            if (_reset) {
+                _reset = false;
+                _ux = bx;
+                _uy = by;
+            } else {
+                float remaining = _remaining, i = _inertia, step = _data._step;
+                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) bone->_worldX += _xOffset * mix * _data._x;
+                    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;
+            }
+
+            _cx = bone->_worldX;
+            _cy = bone->_worldY;
+            break;
+        }
+        case Physics::pose: {
+            if (x) bone->_worldX += _xOffset * mix * _data._x;
+            if (y) bone->_worldY += _yOffset * mix * _data._y;
+            break;
+        }
+    }
+
+    if (rotateOrShearX) {
+        float o = _rotateOffset * mix, s = 0, c = 0, a = 0;
+        if (_data._shearX > 0) {
+            float r = 0;
+            if (_data._rotate > 0) {
+                r = o * _data._rotate;
+                s = MathUtil::sin(r);
+                c = MathUtil::cos(r);
+                a = bone->_b;
+                bone->_b = c * a - s * bone->_d;
+                bone->_d = s * a + c * bone->_d;
+            }
+            r += o * _data._shearX;
+            s = MathUtil::sin(r);
+            c = MathUtil::cos(r);
+            a = bone->_a;
+            bone->_a = c * a - s * bone->_c;
+            bone->_c = s * a + c * bone->_c;
+        } else {
+            o *= _data._rotate;
+            s = MathUtil::sin(o);
+            c = MathUtil::cos(o);
+            a = bone->_a;
+            bone->_a = c * a - s * bone->_c;
+            bone->_c = s * a + c * bone->_c;
+            a = bone->_b;
+            bone->_b = c * a - s * bone->_d;
+            bone->_d = s * a + c * bone->_d;
+        }
+    }
+    if (scaleX) {
+        float s = 1 + _scaleOffset * mix * _data._scaleX;
+        bone->_a *= s;
+        bone->_c *= s;
+    }
+    if (physics != Physics::pose) {
+        _tx = l * bone->_a;
+        _ty = l * bone->_c;
+    }
+    bone->updateAppliedTransform();
+}

+ 216 - 0
spine-cpp/spine-cpp/src/spine/PhysicsConstraintData.cpp

@@ -0,0 +1,216 @@
+/******************************************************************************
+ * 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/PhysicsConstraintData.h>
+
+#include <spine/BoneData.h>
+
+#include <assert.h>
+
+using namespace spine;
+
+RTTI_IMPL(PhysicsConstraintData, ConstraintData)
+
+PhysicsConstraintData::PhysicsConstraintData(const String &name) : ConstraintData(name),
+                                                                   _bone(nullptr),
+                                                                   _x(0), _y(0), _rotate(0), _scaleX(0), _shearX(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),
+                                                                   _windGlobal(false), _gravityGlobal(false), _mixGlobal(false)
+{
+}
+
+
+void PhysicsConstraintData::setBone(BoneData* bone) {
+    _bone = bone;
+}
+
+BoneData* PhysicsConstraintData::getBone() const {
+    return _bone;
+}
+
+void PhysicsConstraintData::setX(float x) {
+    _x = x;
+}
+
+float PhysicsConstraintData::getX() const {
+    return _x;
+}
+
+void PhysicsConstraintData::setY(float y) {
+    _y = y;
+}
+
+float PhysicsConstraintData::getY() const {
+    return _y;
+}
+
+void PhysicsConstraintData::setRotate(float rotate) {
+    _rotate = rotate;
+}
+
+float PhysicsConstraintData::getRotate() const {
+    return _rotate;
+}
+
+void PhysicsConstraintData::setScaleX(float scaleX) {
+    _scaleX = scaleX;
+}
+
+float PhysicsConstraintData::getScaleX() const {
+    return _scaleX;
+}
+
+void PhysicsConstraintData::setShearX(float shearX) {
+    _shearX = shearX;
+}
+
+float PhysicsConstraintData::getShearX() const {
+    return _shearX;
+}
+
+void PhysicsConstraintData::setStep(float step) {
+    _step = step;
+}
+
+float PhysicsConstraintData::getStep() const {
+    return _step;
+}
+
+void PhysicsConstraintData::setInertia(float inertia) {
+    _inertia = inertia;
+}
+
+float PhysicsConstraintData::getInertia() const {
+    return _inertia;
+}
+
+void PhysicsConstraintData::setStrength(float strength) {
+    _strength = strength;
+}
+
+float PhysicsConstraintData::getStrength() const {
+    return _strength;
+}
+
+void PhysicsConstraintData::setDamping(float damping) {
+    _damping = damping;
+}
+
+float PhysicsConstraintData::getDamping() const {
+    return _damping;
+}
+
+void PhysicsConstraintData::setMassInverse(float massInverse) {
+    _massInverse = massInverse;
+}
+
+float PhysicsConstraintData::getMassInverse() const {
+    return _massInverse;
+}
+
+void PhysicsConstraintData::setWind(float wind) {
+    _wind = wind;
+}
+
+float PhysicsConstraintData::getWind() const {
+    return _wind;
+}
+
+void PhysicsConstraintData::setGravity(float gravity) {
+    _gravity = gravity;
+}
+
+float PhysicsConstraintData::getGravity() const {
+    return _gravity;
+}
+
+void PhysicsConstraintData::setMix(float mix) {
+    _mix = mix;
+}
+
+float PhysicsConstraintData::getMix() const {
+    return _mix;
+}
+
+void PhysicsConstraintData::setInertiaGlobal(bool inertiaGlobal) {
+    _inertiaGlobal = inertiaGlobal;
+}
+
+bool PhysicsConstraintData::isInertiaGlobal() const {
+    return _inertiaGlobal;
+}
+
+void PhysicsConstraintData::setStrengthGlobal(bool strengthGlobal) {
+    _strengthGlobal = strengthGlobal;
+}
+
+bool PhysicsConstraintData::isStrengthGlobal() const {
+    return _strengthGlobal;
+}
+
+void PhysicsConstraintData::setDampingGlobal(bool dampingGlobal) {
+    _dampingGlobal = dampingGlobal;
+}
+
+bool PhysicsConstraintData::isDampingGlobal() const {
+    return _dampingGlobal;
+}
+
+void PhysicsConstraintData::setMassGlobal(bool massGlobal) {
+    _massGlobal = massGlobal;
+}
+
+bool PhysicsConstraintData::isMassGlobal() const {
+    return _massGlobal;
+}
+
+void PhysicsConstraintData::setWindGlobal(bool windGlobal) {
+    _windGlobal = windGlobal;
+}
+
+bool PhysicsConstraintData::isWindGlobal() const {
+    return _windGlobal;
+}
+
+void PhysicsConstraintData::setGravityGlobal(bool gravityGlobal) {
+    _gravityGlobal = gravityGlobal;
+}
+
+bool PhysicsConstraintData::isGravityGlobal() const {
+    return _gravityGlobal;
+}
+
+void PhysicsConstraintData::setMixGlobal(bool mixGlobal) {
+    _mixGlobal = mixGlobal;
+}
+
+bool PhysicsConstraintData::isMixGlobal() const {
+    return _mixGlobal;
+}

+ 4 - 6
spine-cpp/spine-cpp/src/spine/PointAttachment.cpp

@@ -45,12 +45,10 @@ void PointAttachment::computeWorldPosition(Bone &bone, float &ox, float &oy) {
 }
 
 float PointAttachment::computeWorldRotation(Bone &bone) {
-	float cos = MathUtil::cosDeg(_rotation);
-	float sin = MathUtil::sinDeg(_rotation);
-	float ix = cos * bone._a + sin * bone._b;
-	float iy = cos * bone._c + sin * bone._d;
-
-	return MathUtil::atan2(iy, ix) * MathUtil::Rad_Deg;
+    float r = _rotation * MathUtil::Deg_Rad, cosine = MathUtil::cos(r), sine = MathUtil::sin(r);
+    float x = cosine * bone._a + sine * bone._b;
+    float y = cosine * bone._c + sine * bone._d;
+    return MathUtil::atan2Deg(y, x);
 }
 
 float PointAttachment::getX() {

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

@@ -59,7 +59,8 @@ Skeleton::Skeleton(SkeletonData *skeletonData) : _data(skeletonData),
 												 _scaleX(1),
 												 _scaleY(1),
 												 _x(0),
-												 _y(0) {
+												 _y(0),
+                                                 _time(0){
 	_bones.ensureCapacity(_data->getBones().size());
 	for (size_t i = 0; i < _data->getBones().size(); ++i) {
 		BoneData *data = _data->getBones()[i];
@@ -683,3 +684,15 @@ void Skeleton::sortReset(Vector<Bone *> &bones) {
 		bone->_sorted = false;
 	}
 }
+
+float Skeleton::getTime() {
+    return _time;
+}
+
+float Skeleton::setTime(float time) {
+    _time = time;
+}
+
+void Skeleton::update(float delta) {
+    _time += delta;
+}

+ 10 - 1
spine-cpp/spine-cpp/src/spine/SlotData.cpp

@@ -40,7 +40,8 @@ SlotData::SlotData(int index, const String &name, BoneData &boneData) : _index(i
 																		_darkColor(0, 0, 0, 0),
 																		_hasDarkColor(false),
 																		_attachmentName(),
-																		_blendMode(BlendMode_Normal) {
+																		_blendMode(BlendMode_Normal),
+                                                                        _visible(true) {
 	assert(_index >= 0);
 	assert(_name.length() > 0);
 }
@@ -88,3 +89,11 @@ BlendMode SlotData::getBlendMode() {
 void SlotData::setBlendMode(BlendMode inValue) {
 	_blendMode = inValue;
 }
+
+bool SlotData::isVisible() {
+    return _visible;
+}
+
+void SlotData::setVisible(bool inValue) {
+    this->_visible = inValue;
+}

+ 13 - 3
spine-cpp/spine-cpp/src/spine/TransformConstraint.cpp

@@ -61,7 +61,7 @@ TransformConstraint::TransformConstraint(TransformConstraintData &data, Skeleton
 	}
 }
 
-void TransformConstraint::update() {
+void TransformConstraint::update(Physics physics) {
 	if (_mixRotate == 0 && _mixX == 0 && _mixY == 0 && _mixScaleX == 0 && _mixScaleY == 0 && _mixShearY == 0) return;
 
 	if (_data.isLocal()) {
@@ -287,7 +287,7 @@ void TransformConstraint::applyAbsoluteLocal() {
 		float rotation = bone._arotation;
 		if (mixRotate != 0) {
 			float r = target._arotation - rotation + _data._offsetRotation;
-			r -= (16384 - (int) (16384.499999999996 - r / 360)) * 360;
+			r -= MathUtil::ceil(r / 360 - 0.5) * 360;
 			rotation += r * mixRotate;
 		}
 
@@ -304,7 +304,7 @@ void TransformConstraint::applyAbsoluteLocal() {
 		float shearY = bone._ashearY;
 		if (mixShearY != 0) {
 			float r = target._ashearY - shearY + _data._offsetShearY;
-			r -= (16384 - (int) (16384.499999999996 - r / 360)) * 360;
+			r -= MathUtil::ceil(r / 360 - 0.5) * 360;
 			bone._shearY += r * mixShearY;
 		}
 
@@ -338,3 +338,13 @@ bool TransformConstraint::isActive() {
 void TransformConstraint::setActive(bool inValue) {
 	_active = inValue;
 }
+
+void TransformConstraint::setToSetupPose() {
+	auto data = this->_data;
+	this->_mixRotate = data._mixRotate;
+	this->_mixX = data._mixX;
+	this->_mixY = data._mixY;
+	this->_mixScaleX = data._mixScaleX;
+	this->_mixScaleY = data._mixScaleY;
+	this->_mixShearY = data._mixShearY;
+}