Эх сурвалжийг харах

[cpp] Fix SkeletinBinary, fix memory leaks

Mario Zechner 1 жил өмнө
parent
commit
2dc7335b4e

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

@@ -37,6 +37,8 @@ namespace spine {
 	/// The interface for all constraints.
 	/// The interface for all constraints.
 	class SP_API ConstraintData : public SpineObject {
 	class SP_API ConstraintData : public SpineObject {
 
 
+        friend class SkeletonBinary;
+
 	RTTI_DECL
 	RTTI_DECL
 
 
 	public:
 	public:

+ 6 - 2
spine-cpp/spine-cpp/include/spine/LinkedMesh.h

@@ -42,12 +42,16 @@ namespace spine {
 		friend class SkeletonJson;
 		friend class SkeletonJson;
 
 
 	public:
 	public:
-		LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent,
+		LinkedMesh(MeshAttachment *mesh, const int skinIndex, size_t slotIndex, const String &parent,
 				   bool inheritTimeline);
 				   bool inheritTimeline);
 
 
+        LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent,
+                   bool inheritTimeline);
+
 	private:
 	private:
 		MeshAttachment *_mesh;
 		MeshAttachment *_mesh;
-		String _skin;
+		int _skinIndex;
+        String _skin;
 		size_t _slotIndex;
 		size_t _slotIndex;
 		String _parent;
 		String _parent;
 		bool _inheritTimeline;
 		bool _inheritTimeline;

+ 14 - 4
spine-cpp/spine-cpp/include/spine/SkeletonBinary.h

@@ -75,6 +75,7 @@ namespace spine {
 		static const int BONE_SHEAR = 7;
 		static const int BONE_SHEAR = 7;
 		static const int BONE_SHEARX = 8;
 		static const int BONE_SHEARX = 8;
 		static const int BONE_SHEARY = 9;
 		static const int BONE_SHEARY = 9;
+        static const int BONE_INHERIT = 10;
 
 
 		static const int SLOT_ATTACHMENT = 0;
 		static const int SLOT_ATTACHMENT = 0;
 		static const int SLOT_RGBA = 1;
 		static const int SLOT_RGBA = 1;
@@ -90,6 +91,15 @@ namespace spine {
 		static const int PATH_SPACING = 1;
 		static const int PATH_SPACING = 1;
 		static const int PATH_MIX = 2;
 		static const int PATH_MIX = 2;
 
 
+        static const int PHYSICS_INERTIA = 0;
+        static const int PHYSICS_STRENGTH = 1;
+        static const int PHYSICS_DAMPING = 2;
+        static const int PHYSICS_MASS = 4;
+        static const int PHYSICS_WIND = 5;
+        static const int PHYSICS_GRAVITY = 6;
+        static const int PHYSICS_MIX = 7;
+        static const int PHYSICS_RESET = 8;
+
 		static const int CURVE_LINEAR = 0;
 		static const int CURVE_LINEAR = 0;
 		static const int CURVE_STEPPED = 1;
 		static const int CURVE_STEPPED = 1;
 		static const int CURVE_BEZIER = 2;
 		static const int CURVE_BEZIER = 2;
@@ -147,11 +157,11 @@ namespace spine {
 		Attachment *readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName,
 		Attachment *readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName,
 								   SkeletonData *skeletonData, bool nonessential);
 								   SkeletonData *skeletonData, bool nonessential);
 
 
-		void readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, int vertexCount);
+		int readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, bool weighted);
 
 
 		void readFloatArray(DataInput *input, int n, float scale, Vector<float> &array);
 		void readFloatArray(DataInput *input, int n, float scale, Vector<float> &array);
 
 
-		void readShortArray(DataInput *input, Vector<unsigned short> &array);
+		void readShortArray(DataInput *input, Vector<unsigned short> &array, int n);
 
 
 		Animation *readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData);
 		Animation *readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData);
 
 
@@ -159,9 +169,9 @@ namespace spine {
 		setBezier(DataInput *input, CurveTimeline *timeline, int bezier, int frame, int value, float time1, float time2,
 		setBezier(DataInput *input, CurveTimeline *timeline, int bezier, int frame, int value, float time1, float time2,
 				  float value1, float value2, float scale);
 				  float value1, float value2, float scale);
 
 
-		Timeline *readTimeline(DataInput *input, CurveTimeline1 *timeline, float scale);
+		void readTimeline(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline1 *timeline, float scale);
 
 
-		Timeline *readTimeline2(DataInput *input, CurveTimeline2 *timeline, float scale);
+		void readTimeline2(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline2 *timeline, float scale);
 	};
 	};
 }
 }
 
 

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

@@ -195,7 +195,7 @@ namespace spine {
         }
         }
 
 
         String substring(int startIndex, int length) const {
         String substring(int startIndex, int length) const {
-            if (startIndex < 0 || startIndex >= _length || length < 0 || startIndex + length > _length) {
+            if (startIndex < 0 || startIndex >= (int)_length || length < 0 || startIndex + length > (int)_length) {
                 return String();
                 return String();
             }
             }
             char* subStr = SpineExtension::calloc<char>(length + 1, __FILE__, __LINE__);
             char* subStr = SpineExtension::calloc<char>(length + 1, __FILE__, __LINE__);
@@ -205,7 +205,7 @@ namespace spine {
         }
         }
 
 
         String substring(int startIndex) const {
         String substring(int startIndex) const {
-            if (startIndex < 0 || startIndex >= _length) {
+            if (startIndex < 0 || startIndex >= (int)_length) {
                 return String();
                 return String();
             }
             }
             int length = _length - startIndex;
             int length = _length - startIndex;

+ 4 - 3
spine-cpp/spine-cpp/src/spine/IkConstraint.cpp

@@ -45,7 +45,7 @@ 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.getInherit()) {
+	switch (bone._inherit) {
 		case Inherit_OnlyTranslation:
 		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());
@@ -77,7 +77,7 @@ 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.getInherit()) {
+		switch (bone._inherit) {
 			case Inherit_NoScale:
 			case Inherit_NoScale:
 			case Inherit_NoScaleOrReflection:
 			case Inherit_NoScaleOrReflection:
 				tx = targetX - bone._worldX;
 				tx = targetX - bone._worldX;
@@ -109,7 +109,8 @@ void IkConstraint::apply(Bone &parent, Bone &child, float targetX, float targetY
 	Bone *pp = parent.getParent();
 	Bone *pp = parent.getParent();
 	float tx, ty, dx, dy, dd, l1, l2, a1, a2, r, td, sd, p;
 	float tx, ty, dx, dy, dd, l1, l2, a1, a2, r, td, sd, p;
 	float id, x, y;
 	float id, x, y;
-	px = parent._ax;
+    if (parent._inherit != Inherit_Normal || child._inherit != Inherit_Normal) return;
+    px = parent._ax;
 	py = parent._ay;
 	py = parent._ay;
 	psx = parent._ascaleX;
 	psx = parent._ascaleX;
 	psy = parent._ascaleY;
 	psy = parent._ascaleY;

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

@@ -37,11 +37,11 @@ RTTI_IMPL(IkConstraintData, ConstraintData)
 
 
 IkConstraintData::IkConstraintData(const String &name) : ConstraintData(name),
 IkConstraintData::IkConstraintData(const String &name) : ConstraintData(name),
 														 _target(NULL),
 														 _target(NULL),
-														 _bendDirection(1),
+														 _bendDirection(0),
 														 _compress(false),
 														 _compress(false),
 														 _stretch(false),
 														 _stretch(false),
 														 _uniform(false),
 														 _uniform(false),
-														 _mix(1),
+														 _mix(0),
 														 _softness(0) {
 														 _softness(0) {
 }
 }
 
 

+ 15 - 5
spine-cpp/spine-cpp/src/spine/LinkedMesh.cpp

@@ -33,10 +33,20 @@
 
 
 using namespace spine;
 using namespace spine;
 
 
+LinkedMesh::LinkedMesh(MeshAttachment *mesh, const int skinIndex, size_t slotIndex, const String &parent,
+                       bool inheritTimeline) : _mesh(mesh),
+                                               _skinIndex(skinIndex),
+                                               _skin(""),
+                                               _slotIndex(slotIndex),
+                                               _parent(parent),
+                                               _inheritTimeline(inheritTimeline) {
+}
+
 LinkedMesh::LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent,
 LinkedMesh::LinkedMesh(MeshAttachment *mesh, const String &skin, size_t slotIndex, const String &parent,
-					   bool inheritTimeline) : _mesh(mesh),
-											   _skin(skin),
-											   _slotIndex(slotIndex),
-											   _parent(parent),
-											   _inheritTimeline(inheritTimeline) {
+                       bool inheritTimeline) : _mesh(mesh),
+                                               _skinIndex(-1),
+                                               _skin(skin),
+                                               _slotIndex(slotIndex),
+                                               _parent(parent),
+                                               _inheritTimeline(inheritTimeline) {
 }
 }

+ 5 - 2
spine-cpp/spine-cpp/src/spine/Skeleton.cpp

@@ -136,6 +136,7 @@ Skeleton::~Skeleton() {
 	ContainerUtil::cleanUpVectorOfPointers(_ikConstraints);
 	ContainerUtil::cleanUpVectorOfPointers(_ikConstraints);
 	ContainerUtil::cleanUpVectorOfPointers(_transformConstraints);
 	ContainerUtil::cleanUpVectorOfPointers(_transformConstraints);
 	ContainerUtil::cleanUpVectorOfPointers(_pathConstraints);
 	ContainerUtil::cleanUpVectorOfPointers(_pathConstraints);
+    ContainerUtil::cleanUpVectorOfPointers(_physicsConstraints);
 }
 }
 
 
 void Skeleton::updateCache() {
 void Skeleton::updateCache() {
@@ -195,7 +196,7 @@ continue_outer:
 			}
 			}
 		}
 		}
 
 
-		for (size_t ii = 0; ii < pathCount; ++ii) {
+		for (size_t ii = 0; ii < physicsCount; ++ii) {
 			PhysicsConstraint *constraint = _physicsConstraints[ii];
 			PhysicsConstraint *constraint = _physicsConstraints[ii];
 			if (constraint->getData().getOrder() == i) {
 			if (constraint->getData().getOrder() == i) {
 				sortPhysicsConstraint(constraint);
 				sortPhysicsConstraint(constraint);
@@ -222,7 +223,9 @@ void Skeleton::printUpdateCache() {
 			printf("ik constraint %s\n", ((IkConstraint *) updatable)->getData().getName().buffer());
 			printf("ik constraint %s\n", ((IkConstraint *) updatable)->getData().getName().buffer());
 		} else if (updatable->getRTTI().isExactly(PathConstraint::rtti)) {
 		} else if (updatable->getRTTI().isExactly(PathConstraint::rtti)) {
 			printf("path constraint %s\n", ((PathConstraint *) updatable)->getData().getName().buffer());
 			printf("path constraint %s\n", ((PathConstraint *) updatable)->getData().getName().buffer());
-		}
+		} else if (updatable->getRTTI().isExactly(PhysicsConstraint::rtti)) {
+            printf("physics constraint %s\n", ((PhysicsConstraint *) updatable)->getData().getName().buffer());
+        }
 	}
 	}
 }
 }
 
 

+ 242 - 152
spine-cpp/spine-cpp/src/spine/SkeletonBinary.cpp

@@ -53,12 +53,15 @@
 #include <spine/EventTimeline.h>
 #include <spine/EventTimeline.h>
 #include <spine/IkConstraintData.h>
 #include <spine/IkConstraintData.h>
 #include <spine/IkConstraintTimeline.h>
 #include <spine/IkConstraintTimeline.h>
+#include <spine/InheritTimeline.h>
 #include <spine/MeshAttachment.h>
 #include <spine/MeshAttachment.h>
 #include <spine/PathAttachment.h>
 #include <spine/PathAttachment.h>
 #include <spine/PathConstraintData.h>
 #include <spine/PathConstraintData.h>
 #include <spine/PathConstraintMixTimeline.h>
 #include <spine/PathConstraintMixTimeline.h>
 #include <spine/PathConstraintPositionTimeline.h>
 #include <spine/PathConstraintPositionTimeline.h>
 #include <spine/PathConstraintSpacingTimeline.h>
 #include <spine/PathConstraintSpacingTimeline.h>
+#include <spine/PhysicsConstraintData.h>
+#include <spine/PhysicsConstraintTimeline.h>
 #include <spine/PointAttachment.h>
 #include <spine/PointAttachment.h>
 #include <spine/RegionAttachment.h>
 #include <spine/RegionAttachment.h>
 #include <spine/RotateTimeline.h>
 #include <spine/RotateTimeline.h>
@@ -129,6 +132,7 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 	skeletonData->_y = readFloat(input);
 	skeletonData->_y = readFloat(input);
 	skeletonData->_width = readFloat(input);
 	skeletonData->_width = readFloat(input);
 	skeletonData->_height = readFloat(input);
 	skeletonData->_height = readFloat(input);
+    skeletonData->_referenceScale = readFloat(input) * this->_scale;
 
 
 	nonessential = readBoolean(input);
 	nonessential = readBoolean(input);
 
 
@@ -161,6 +165,8 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 		data->_skinRequired = readBoolean(input);
 		data->_skinRequired = readBoolean(input);
 		if (nonessential) {
 		if (nonessential) {
 			readColor(input, data->getColor());
 			readColor(input, data->getColor());
+            data->_icon.own(readString(input));
+            data->_visible = readBoolean(input);
 		}
 		}
 		skeletonData->_bones[i] = data;
 		skeletonData->_bones[i] = data;
 	}
 	}
@@ -169,9 +175,17 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 	int slotsCount = readVarint(input, true);
 	int slotsCount = readVarint(input, true);
 	skeletonData->_slots.setSize(slotsCount, 0);
 	skeletonData->_slots.setSize(slotsCount, 0);
 	for (int i = 0; i < slotsCount; ++i) {
 	for (int i = 0; i < slotsCount; ++i) {
-		const char *slotName = readString(input);
+		String slotName = String(readString(input), true);
+        String pathName = "";
+        if (nonessential) {
+            int slash = slotName.lastIndexOf('/');
+            if (slash != -1) {
+                pathName = slotName.substring(0, slash);
+                slotName = slotName.substring(slash + 1);
+            }
+        }
 		BoneData *boneData = skeletonData->_bones[readVarint(input, true)];
 		BoneData *boneData = skeletonData->_bones[readVarint(input, true)];
-		SlotData *slotData = new (__FILE__, __LINE__) SlotData(i, String(slotName, true), *boneData);
+		SlotData *slotData = new (__FILE__, __LINE__) SlotData(i, slotName, *boneData);
 
 
 		readColor(input, slotData->getColor());
 		readColor(input, slotData->getColor());
 		unsigned char a = readByte(input);
 		unsigned char a = readByte(input);
@@ -184,6 +198,10 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 		}
 		}
 		slotData->_attachmentName = readStringRef(input, skeletonData);
 		slotData->_attachmentName = readStringRef(input, skeletonData);
 		slotData->_blendMode = static_cast<BlendMode>(readVarint(input, true));
 		slotData->_blendMode = static_cast<BlendMode>(readVarint(input, true));
+        if (nonessential) {
+            slotData->_visible = readBoolean(input);
+            slotData->_path = pathName;
+        }
 		skeletonData->_slots[i] = slotData;
 		skeletonData->_slots[i] = slotData;
 	}
 	}
 
 
@@ -194,18 +212,20 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 		const char *name = readString(input);
 		const char *name = readString(input);
 		IkConstraintData *data = new (__FILE__, __LINE__) IkConstraintData(String(name, true));
 		IkConstraintData *data = new (__FILE__, __LINE__) IkConstraintData(String(name, true));
 		data->setOrder(readVarint(input, true));
 		data->setOrder(readVarint(input, true));
-		data->setSkinRequired(readBoolean(input));
 		int bonesCount = readVarint(input, true);
 		int bonesCount = readVarint(input, true);
 		data->_bones.setSize(bonesCount, 0);
 		data->_bones.setSize(bonesCount, 0);
 		for (int ii = 0; ii < bonesCount; ++ii)
 		for (int ii = 0; ii < bonesCount; ++ii)
 			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
 			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
 		data->_target = skeletonData->_bones[readVarint(input, true)];
 		data->_target = skeletonData->_bones[readVarint(input, true)];
-		data->_mix = readFloat(input);
-		data->_softness = readFloat(input) * _scale;
-		data->_bendDirection = readSByte(input);
-		data->_compress = readBoolean(input);
-		data->_stretch = readBoolean(input);
-		data->_uniform = readBoolean(input);
+        int flags = readByte(input);
+        data->_skinRequired = (flags & 1) != 0;
+        data->_bendDirection = (flags & 2) != 0 ? 1 : -1;
+        data->_compress = (flags & 4) != 0;
+        data->_stretch = (flags & 8) != 0;
+        data->_uniform = (flags & 16) != 0;
+        if ((flags & 32) != 0) data->_mix = (flags & 64) != 0 ? readFloat(input) : 1;
+        if ((flags & 128) != 0) data->_softness = readFloat(input) * _scale;
+
 		skeletonData->_ikConstraints[i] = data;
 		skeletonData->_ikConstraints[i] = data;
 	}
 	}
 
 
@@ -216,27 +236,30 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 		const char *name = readString(input);
 		const char *name = readString(input);
 		TransformConstraintData *data = new (__FILE__, __LINE__) TransformConstraintData(String(name, true));
 		TransformConstraintData *data = new (__FILE__, __LINE__) TransformConstraintData(String(name, true));
 		data->setOrder(readVarint(input, true));
 		data->setOrder(readVarint(input, true));
-		data->setSkinRequired(readBoolean(input));
 		int bonesCount = readVarint(input, true);
 		int bonesCount = readVarint(input, true);
 		data->_bones.setSize(bonesCount, 0);
 		data->_bones.setSize(bonesCount, 0);
 		for (int ii = 0; ii < bonesCount; ++ii)
 		for (int ii = 0; ii < bonesCount; ++ii)
 			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
 			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
 		data->_target = skeletonData->_bones[readVarint(input, true)];
 		data->_target = skeletonData->_bones[readVarint(input, true)];
-		data->_local = readBoolean(input);
-		data->_relative = readBoolean(input);
-		data->_offsetRotation = readFloat(input);
-		data->_offsetX = readFloat(input) * _scale;
-		data->_offsetY = readFloat(input) * _scale;
-		data->_offsetScaleX = readFloat(input);
-		data->_offsetScaleY = readFloat(input);
-		data->_offsetShearY = readFloat(input);
-		data->_mixRotate = readFloat(input);
-		data->_mixX = readFloat(input);
-		data->_mixY = readFloat(input);
-		data->_mixScaleX = readFloat(input);
-		data->_mixScaleY = readFloat(input);
-		data->_mixShearY = readFloat(input);
-		skeletonData->_transformConstraints[i] = data;
+        int flags = readByte(input);
+        data->_skinRequired = (flags & 1) != 0;
+        data->_local = (flags & 2) != 0;
+        data->_relative = (flags & 4) != 0;
+        if ((flags & 8) != 0) data->_offsetRotation = readFloat(input);
+        if ((flags & 16) != 0) data->_offsetX =readFloat(input) * _scale;
+        if ((flags & 32) != 0) data->_offsetY = readFloat(input) * _scale;
+        if ((flags & 64) != 0) data->_offsetScaleX = readFloat(input);
+        if ((flags & 128) != 0) data->_offsetScaleY = readFloat(input);
+        flags = readByte(input);
+        if ((flags & 1) != 0) data->_offsetShearY = readFloat(input);
+        if ((flags & 2) != 0) data->_mixRotate = readFloat(input);
+        if ((flags & 4) != 0) data->_mixX = readFloat(input);
+        if ((flags & 8) != 0) data->_mixY = readFloat(input);
+        if ((flags & 16) != 0) data->_mixScaleX = readFloat(input);
+        if ((flags & 32) != 0) data->_mixScaleY = readFloat(input);
+        if ((flags & 64) != 0) data->_mixShearY = readFloat(input);
+
+        skeletonData->_transformConstraints[i] = data;
 	}
 	}
 
 
 	/* Path constraints */
 	/* Path constraints */
@@ -252,10 +275,11 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 		for (int ii = 0; ii < bonesCount; ++ii)
 		for (int ii = 0; ii < bonesCount; ++ii)
 			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
 			data->_bones[ii] = skeletonData->_bones[readVarint(input, true)];
 		data->_target = skeletonData->_slots[readVarint(input, true)];
 		data->_target = skeletonData->_slots[readVarint(input, true)];
-		data->_positionMode = static_cast<PositionMode>(readVarint(input, true));
-		data->_spacingMode = static_cast<SpacingMode>(readVarint(input, true));
-		data->_rotateMode = static_cast<RotateMode>(readVarint(input, true));
-		data->_offsetRotation = readFloat(input);
+        int flags = readByte(input);
+        data->_positionMode = (PositionMode)(flags & 1);
+        data->_spacingMode = (SpacingMode)((flags >> 1) & 3);
+        data->_rotateMode = (RotateMode)((flags >> 3) & 3);
+        if ((flags & 128) != 0) data->_offsetRotation = readFloat(input);
 		data->_position = readFloat(input);
 		data->_position = readFloat(input);
 		if (data->_positionMode == PositionMode_Fixed) data->_position *= _scale;
 		if (data->_positionMode == PositionMode_Fixed) data->_position *= _scale;
 		data->_spacing = readFloat(input);
 		data->_spacing = readFloat(input);
@@ -267,6 +291,41 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 		skeletonData->_pathConstraints[i] = data;
 		skeletonData->_pathConstraints[i] = data;
 	}
 	}
 
 
+    // Physics constraints.
+    int physicsConstraintsCount = readVarint(input, true);
+    skeletonData->_physicsConstraints.setSize(physicsConstraintsCount, 0);
+    for (int i = 0; i < physicsConstraintsCount; i++) {
+        const char *name = readString(input);
+        PhysicsConstraintData *data = new (__FILE__, __LINE__) PhysicsConstraintData(String(name, true));
+        data->_order = readVarint(input, true);
+        data->_bone = skeletonData->_bones[readVarint(input, true)];
+        int flags = readByte(input);
+        data->_skinRequired = (flags & 1) != 0;
+        if ((flags & 2) != 0) data->_x = readFloat(input);
+        if ((flags & 4) != 0) data->_y = readFloat(input);
+        if ((flags & 8) != 0) data->_rotate = readFloat(input);
+        if ((flags & 16) != 0) data->_scaleX = readFloat(input);
+        if ((flags & 32) != 0) data->_shearX = readFloat(input);
+        data->_limit = ((flags & 64) != 0 ? readFloat(input) : 5000) * _scale;
+        data->_step = 1.f / readByte(input);
+        data->_inertia = readFloat(input);
+        data->_strength = readFloat(input);
+        data->_damping = readFloat(input);
+        data->_massInverse = (flags & 128) != 0 ? readFloat(input) : 1;
+        data->_wind = readFloat(input);
+        data->_gravity = readFloat(input);
+        flags = readByte(input);
+        if ((flags & 1) != 0) data->_inertiaGlobal = true;
+        if ((flags & 2) != 0) data->_strengthGlobal = true;
+        if ((flags & 4) != 0) data->_dampingGlobal = true;
+        if ((flags & 8) != 0) data->_massGlobal = true;
+        if ((flags & 16) != 0) data->_windGlobal = true;
+        if ((flags & 32) != 0) data->_gravityGlobal = true;
+        if ((flags & 64) != 0) data->_mixGlobal = true;
+        data->_mix = (flags & 128) != 0 ? readFloat(input) : 1;
+        skeletonData->_physicsConstraints[i] = data;
+    }
+
 	/* Default skin. */
 	/* Default skin. */
 	Skin *defaultSkin = readSkin(input, true, skeletonData, nonessential);
 	Skin *defaultSkin = readSkin(input, true, skeletonData, nonessential);
 	if (defaultSkin) {
 	if (defaultSkin) {
@@ -289,13 +348,7 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 	/* Linked meshes. */
 	/* Linked meshes. */
 	for (int i = 0, n = (int) _linkedMeshes.size(); i < n; ++i) {
 	for (int i = 0, n = (int) _linkedMeshes.size(); i < n; ++i) {
 		LinkedMesh *linkedMesh = _linkedMeshes[i];
 		LinkedMesh *linkedMesh = _linkedMeshes[i];
-		Skin *skin = linkedMesh->_skin.length() == 0 ? skeletonData->getDefaultSkin() : skeletonData->findSkin(linkedMesh->_skin);
-		if (skin == NULL) {
-			delete input;
-			delete skeletonData;
-			setError("Skin not found: ", linkedMesh->_skin.buffer());
-			return NULL;
-		}
+		Skin *skin = skeletonData->_skins[linkedMesh->_skinIndex];
 		Attachment *parent = skin->getAttachment(linkedMesh->_slotIndex, linkedMesh->_parent);
 		Attachment *parent = skin->getAttachment(linkedMesh->_slotIndex, linkedMesh->_parent);
 		if (parent == NULL) {
 		if (parent == NULL) {
 			delete input;
 			delete input;
@@ -316,8 +369,8 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
 	int eventsCount = readVarint(input, true);
 	int eventsCount = readVarint(input, true);
 	skeletonData->_events.setSize(eventsCount, 0);
 	skeletonData->_events.setSize(eventsCount, 0);
 	for (int i = 0; i < eventsCount; ++i) {
 	for (int i = 0; i < eventsCount; ++i) {
-		const char *name = readStringRef(input, skeletonData);
-		EventData *eventData = new (__FILE__, __LINE__) EventData(String(name));
+		const char *name = readString(input);
+		EventData *eventData = new (__FILE__, __LINE__) EventData(String(name, true));
 		eventData->_intValue = readVarint(input, false);
 		eventData->_intValue = readVarint(input, false);
 		eventData->_floatValue = readFloat(input);
 		eventData->_floatValue = readFloat(input);
 		eventData->_stringValue.own(readString(input));
 		eventData->_stringValue.own(readString(input));
@@ -452,7 +505,10 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
 		if (slotCount == 0) return NULL;
 		if (slotCount == 0) return NULL;
 		skin = new (__FILE__, __LINE__) Skin("default");
 		skin = new (__FILE__, __LINE__) Skin("default");
 	} else {
 	} else {
-		skin = new (__FILE__, __LINE__) Skin(readStringRef(input, skeletonData));
+		skin = new (__FILE__, __LINE__) Skin(String(readString(input), true));
+
+        if (nonessential) readColor(input, skin->getColor());
+
 		for (int i = 0, n = readVarint(input, true); i < n; i++) {
 		for (int i = 0, n = readVarint(input, true); i < n; i++) {
 			int boneIndex = readVarint(input, true);
 			int boneIndex = readVarint(input, true);
 			if (boneIndex >= (int) skeletonData->_bones.size()) return NULL;
 			if (boneIndex >= (int) skeletonData->_bones.size()) return NULL;
@@ -476,6 +532,12 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
 			if (pathIndex >= (int) skeletonData->_pathConstraints.size()) return NULL;
 			if (pathIndex >= (int) skeletonData->_pathConstraints.size()) return NULL;
 			skin->getConstraints().add(skeletonData->_pathConstraints[pathIndex]);
 			skin->getConstraints().add(skeletonData->_pathConstraints[pathIndex]);
 		}
 		}
+
+        for (int i = 0, n = readVarint(input, true); i < n; i++) {
+            int physicsIndex = readVarint(input, true);
+            if (physicsIndex >= (int) skeletonData->_physicsConstraints.size()) return NULL;
+            skin->getConstraints().add(skeletonData->_physicsConstraints[physicsIndex]);
+        }
 		slotCount = readVarint(input, true);
 		slotCount = readVarint(input, true);
 	}
 	}
 
 
@@ -496,7 +558,6 @@ Skin *SkeletonBinary::readSkin(DataInput *input, bool defaultSkin, SkeletonData
 }
 }
 
 
 Sequence *SkeletonBinary::readSequence(DataInput *input) {
 Sequence *SkeletonBinary::readSequence(DataInput *input) {
-	if (!readBoolean(input)) return NULL;
 	Sequence *sequence = new (__FILE__, __LINE__) Sequence(readVarint(input, true));
 	Sequence *sequence = new (__FILE__, __LINE__) Sequence(readVarint(input, true));
 	sequence->_start = readVarint(input, true);
 	sequence->_start = readVarint(input, true);
 	sequence->_digits = readVarint(input, true);
 	sequence->_digits = readVarint(input, true);
@@ -506,24 +567,23 @@ Sequence *SkeletonBinary::readSequence(DataInput *input) {
 
 
 Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName,
 Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slotIndex, const String &attachmentName,
 										   SkeletonData *skeletonData, bool nonessential) {
 										   SkeletonData *skeletonData, bool nonessential) {
-	String name(readStringRef(input, skeletonData));
-	if (name.isEmpty()) name = attachmentName;
 
 
-	AttachmentType type = static_cast<AttachmentType>(readByte(input));
+    int flags = readByte(input);
+    String name = (flags & 8) != 0 ? readStringRef(input, skeletonData) : attachmentName;
+	AttachmentType type = static_cast<AttachmentType>(flags & 0x7);
 	switch (type) {
 	switch (type) {
 		case AttachmentType_Region: {
 		case AttachmentType_Region: {
-			String path(readStringRef(input, skeletonData));
-			if (path.isEmpty()) path = name;
-			float rotation = readFloat(input);
+            String path = (flags & 16) != 0 ? readStringRef(input, skeletonData) : name;
+            Color color(1, 1, 1, 1);
+            if ((flags & 32) != 0) readColor(input, color);
+            Sequence *sequence = (flags & 64) != 0 ? readSequence(input) : nullptr;
+            float rotation = (flags & 128) != 0 ? readFloat(input) : 0;
 			float x = readFloat(input) * _scale;
 			float x = readFloat(input) * _scale;
 			float y = readFloat(input) * _scale;
 			float y = readFloat(input) * _scale;
 			float scaleX = readFloat(input);
 			float scaleX = readFloat(input);
 			float scaleY = readFloat(input);
 			float scaleY = readFloat(input);
 			float width = readFloat(input) * _scale;
 			float width = readFloat(input) * _scale;
 			float height = readFloat(input) * _scale;
 			float height = readFloat(input) * _scale;
-			Color color;
-			readColor(input, color);
-			Sequence *sequence = readSequence(input);
 			RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path), sequence);
 			RegionAttachment *region = _attachmentLoader->newRegionAttachment(*skin, String(name), String(path), sequence);
 			if (!region) {
 			if (!region) {
 				setError("Error reading attachment: ", name.buffer());
 				setError("Error reading attachment: ", name.buffer());
@@ -544,14 +604,13 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			return region;
 			return region;
 		}
 		}
 		case AttachmentType_Boundingbox: {
 		case AttachmentType_Boundingbox: {
-			int vertexCount = readVarint(input, true);
 			BoundingBoxAttachment *box = _attachmentLoader->newBoundingBoxAttachment(*skin, String(name));
 			BoundingBoxAttachment *box = _attachmentLoader->newBoundingBoxAttachment(*skin, String(name));
 			if (!box) {
 			if (!box) {
 				setError("Error reading attachment: ", name.buffer());
 				setError("Error reading attachment: ", name.buffer());
 				return NULL;
 				return NULL;
 			}
 			}
-			readVertices(input, box->getVertices(), box->getBones(), vertexCount);
-			box->setWorldVerticesLength(vertexCount << 1);
+			readVertices(input, box->getVertices(), box->getBones(), (flags & 16) != 0);
+			box->setWorldVerticesLength(box->getVertices().size());
 			if (nonessential) {
 			if (nonessential) {
 				readColor(input, box->getColor());
 				readColor(input, box->getColor());
 			}
 			}
@@ -559,31 +618,28 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			return box;
 			return box;
 		}
 		}
 		case AttachmentType_Mesh: {
 		case AttachmentType_Mesh: {
-			Color color;
-			int vertexCount;
 			Vector<float> uvs;
 			Vector<float> uvs;
 			Vector<unsigned short> triangles;
 			Vector<unsigned short> triangles;
 			Vector<float> vertices;
 			Vector<float> vertices;
 			Vector<int> bones;
 			Vector<int> bones;
 			int hullLength;
 			int hullLength;
-			Sequence *sequence;
 			float width = 0;
 			float width = 0;
 			float height = 0;
 			float height = 0;
 			Vector<unsigned short> edges;
 			Vector<unsigned short> edges;
 
 
-			String path(readStringRef(input, skeletonData));
-			if (path.isEmpty()) path = name;
-			readColor(input, color);
-			vertexCount = readVarint(input, true);
-			readFloatArray(input, vertexCount << 1, 1, uvs);
-			readShortArray(input, triangles);
-			readVertices(input, vertices, bones, vertexCount);
-			hullLength = readVarint(input, true) << 1;
-			sequence = readSequence(input);
+            String path = (flags & 16) != 0 ? readStringRef(input, skeletonData) : name;
+            Color color(1, 1, 1, 1);
+            if ((flags & 32) != 0) readColor(input, color);
+            Sequence *sequence = (flags & 64) != 0 ? readSequence(input) : nullptr;
+			hullLength = readVarint(input, true);
+            int verticesLength = readVertices(input, vertices, bones, (flags & 128) != 0);
+            readFloatArray(input, verticesLength, 1, uvs);
+            readShortArray(input, triangles, (verticesLength - hullLength - 2) * 3);
+
 			if (nonessential) {
 			if (nonessential) {
-				readShortArray(input, edges);
-				width = readFloat(input) * _scale;
-				height = readFloat(input) * _scale;
+				readShortArray(input, edges, readVarint(input, true));
+				width = readFloat(input);
+				height = readFloat(input);
 			}
 			}
 
 
 			MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence);
 			MeshAttachment *mesh = _attachmentLoader->newMeshAttachment(*skin, String(name), String(path), sequence);
@@ -595,7 +651,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			mesh->_color.set(color);
 			mesh->_color.set(color);
 			mesh->_bones.addAll(bones);
 			mesh->_bones.addAll(bones);
 			mesh->_vertices.addAll(vertices);
 			mesh->_vertices.addAll(vertices);
-			mesh->setWorldVerticesLength(vertexCount << 1);
+			mesh->setWorldVerticesLength(verticesLength);
 			mesh->_triangles.addAll(triangles);
 			mesh->_triangles.addAll(triangles);
 			mesh->_regionUVs.addAll(uvs);
 			mesh->_regionUVs.addAll(uvs);
 			if (sequence == NULL) mesh->updateRegion();
 			if (sequence == NULL) mesh->updateRegion();
@@ -610,16 +666,14 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 			return mesh;
 			return mesh;
 		}
 		}
 		case AttachmentType_Linkedmesh: {
 		case AttachmentType_Linkedmesh: {
-			String path(readStringRef(input, skeletonData));
-			if (path.isEmpty()) path = name;
-
-			Color color;
-			float width = 0, height = 0;
-			readColor(input, color);
-			String skinName(readStringRef(input, skeletonData));
+            String path = (flags & 16) != 0 ? readStringRef(input, skeletonData) : name;
+            Color color(1, 1, 1, 1);
+            if ((flags & 32) != 0) readColor(input, color);
+            Sequence *sequence = (flags & 64) != 0 ? readSequence(input) : nullptr;
+            bool inheritTimelines = (flags & 128) != 0;
+            int skinIndex = readVarint(input, true);
 			String parent(readStringRef(input, skeletonData));
 			String parent(readStringRef(input, skeletonData));
-			bool inheritTimelines = readBoolean(input);
-			Sequence *sequence = readSequence(input);
+            float width = 0, height = 0;
 			if (nonessential) {
 			if (nonessential) {
 				width = readFloat(input) * _scale;
 				width = readFloat(input) * _scale;
 				height = readFloat(input) * _scale;
 				height = readFloat(input) * _scale;
@@ -638,7 +692,7 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 				mesh->_height = height;
 				mesh->_height = height;
 			}
 			}
 
 
-			LinkedMesh *linkedMesh = new (__FILE__, __LINE__) LinkedMesh(mesh, String(skinName), slotIndex,
+			LinkedMesh *linkedMesh = new (__FILE__, __LINE__) LinkedMesh(mesh, skinIndex, slotIndex,
 																		 String(parent), inheritTimelines);
 																		 String(parent), inheritTimelines);
 			_linkedMeshes.add(linkedMesh);
 			_linkedMeshes.add(linkedMesh);
 			return mesh;
 			return mesh;
@@ -649,12 +703,11 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 				setError("Error reading attachment: ", name.buffer());
 				setError("Error reading attachment: ", name.buffer());
 				return NULL;
 				return NULL;
 			}
 			}
-			path->_closed = readBoolean(input);
-			path->_constantSpeed = readBoolean(input);
-			int vertexCount = readVarint(input, true);
-			readVertices(input, path->getVertices(), path->getBones(), vertexCount);
-			path->setWorldVerticesLength(vertexCount << 1);
-			int lengthsLength = vertexCount / 3;
+			path->_closed = (flags & 16) != 0;
+			path->_constantSpeed = (flags & 32) != 0;
+			int verticesLength = readVertices(input, path->getVertices(), path->getBones(), (flags & 64) != 0);
+			path->setWorldVerticesLength(verticesLength);
+			int lengthsLength = verticesLength / 6;
 			path->_lengths.setSize(lengthsLength, 0);
 			path->_lengths.setSize(lengthsLength, 0);
 			for (int i = 0; i < lengthsLength; ++i) {
 			for (int i = 0; i < lengthsLength; ++i) {
 				path->_lengths[i] = readFloat(input) * _scale;
 				path->_lengths[i] = readFloat(input) * _scale;
@@ -683,14 +736,13 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 		}
 		}
 		case AttachmentType_Clipping: {
 		case AttachmentType_Clipping: {
 			int endSlotIndex = readVarint(input, true);
 			int endSlotIndex = readVarint(input, true);
-			int vertexCount = readVarint(input, true);
 			ClippingAttachment *clip = _attachmentLoader->newClippingAttachment(*skin, name);
 			ClippingAttachment *clip = _attachmentLoader->newClippingAttachment(*skin, name);
 			if (!clip) {
 			if (!clip) {
 				setError("Error reading attachment: ", name.buffer());
 				setError("Error reading attachment: ", name.buffer());
 				return NULL;
 				return NULL;
 			}
 			}
-			readVertices(input, clip->getVertices(), clip->getBones(), vertexCount);
-			clip->setWorldVerticesLength(vertexCount << 1);
+			int verticesLength = readVertices(input, clip->getVertices(), clip->getBones(), (flags & 16) != 0);
+			clip->setWorldVerticesLength(verticesLength);
 			clip->_endSlot = skeletonData->_slots[endSlotIndex];
 			clip->_endSlot = skeletonData->_slots[endSlotIndex];
 			if (nonessential) {
 			if (nonessential) {
 				readColor(input, clip->getColor());
 				readColor(input, clip->getColor());
@@ -702,18 +754,16 @@ Attachment *SkeletonBinary::readAttachment(DataInput *input, Skin *skin, int slo
 	return NULL;
 	return NULL;
 }
 }
 
 
-void SkeletonBinary::readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, int vertexCount) {
+int SkeletonBinary::readVertices(DataInput *input, Vector<float> &vertices, Vector<int> &bones, bool weighted) {
 	float scale = _scale;
 	float scale = _scale;
+    int vertexCount = readVarint(input, true);
 	int verticesLength = vertexCount << 1;
 	int verticesLength = vertexCount << 1;
-
-	if (!readBoolean(input)) {
-		readFloatArray(input, verticesLength, scale, vertices);
-		return;
-	}
-
-	vertices.ensureCapacity(verticesLength * 3 * 3);
-	bones.ensureCapacity(verticesLength * 3);
-
+    if (!weighted) {
+        readFloatArray(input, verticesLength, scale, vertices);
+        return verticesLength;
+    }
+    vertices.ensureCapacity(verticesLength * 3 * 3);
+    bones.ensureCapacity(verticesLength * 3);
 	for (int i = 0; i < vertexCount; ++i) {
 	for (int i = 0; i < vertexCount; ++i) {
 		int boneCount = readVarint(input, true);
 		int boneCount = readVarint(input, true);
 		bones.add(boneCount);
 		bones.add(boneCount);
@@ -724,6 +774,7 @@ void SkeletonBinary::readVertices(DataInput *input, Vector<float> &vertices, Vec
 			vertices.add(readFloat(input));
 			vertices.add(readFloat(input));
 		}
 		}
 	}
 	}
+    return verticesLength;
 }
 }
 
 
 void SkeletonBinary::readFloatArray(DataInput *input, int n, float scale, Vector<float> &array) {
 void SkeletonBinary::readFloatArray(DataInput *input, int n, float scale, Vector<float> &array) {
@@ -741,14 +792,10 @@ void SkeletonBinary::readFloatArray(DataInput *input, int n, float scale, Vector
 	}
 	}
 }
 }
 
 
-void SkeletonBinary::readShortArray(DataInput *input, Vector<unsigned short> &array) {
-	int n = readVarint(input, true);
+void SkeletonBinary::readShortArray(DataInput *input, Vector<unsigned short> &array, int n) {
 	array.setSize(n, 0);
 	array.setSize(n, 0);
-
-	int i;
-	for (i = 0; i < n; ++i) {
-		array[i] = readByte(input) << 8;
-		array[i] |= readByte(input);
+	for (int i = 0; i < n; ++i) {
+		array[i] = (short)readVarint(input, true);
 	}
 	}
 }
 }
 
 
@@ -762,7 +809,7 @@ void SkeletonBinary::setBezier(DataInput *input, CurveTimeline *timeline, int be
 	timeline->setBezier(bezier, frame, value, time1, value1, cx1, cy1 * scale, cx2, cy2 * scale, time2, value2);
 	timeline->setBezier(bezier, frame, value, time1, value1, cx1, cy1 * scale, cx2, cy2 * scale, time2, value2);
 }
 }
 
 
-Timeline *SkeletonBinary::readTimeline(DataInput *input, CurveTimeline1 *timeline, float scale) {
+void SkeletonBinary::readTimeline(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline1 *timeline, float scale) {
 	float time = readFloat(input);
 	float time = readFloat(input);
 	float value = readFloat(input) * scale;
 	float value = readFloat(input) * scale;
 	for (int frame = 0, bezier = 0, frameLast = (int) timeline->getFrameCount() - 1;; frame++) {
 	for (int frame = 0, bezier = 0, frameLast = (int) timeline->getFrameCount() - 1;; frame++) {
@@ -780,10 +827,10 @@ Timeline *SkeletonBinary::readTimeline(DataInput *input, CurveTimeline1 *timelin
 		time = time2;
 		time = time2;
 		value = value2;
 		value = value2;
 	}
 	}
-	return timeline;
+    timelines.add(timeline);
 }
 }
 
 
-Timeline *SkeletonBinary::readTimeline2(DataInput *input, CurveTimeline2 *timeline, float scale) {
+void SkeletonBinary::readTimeline2(DataInput *input, Vector<Timeline*> &timelines, CurveTimeline2 *timeline, float scale) {
 	float time = readFloat(input);
 	float time = readFloat(input);
 	float value1 = readFloat(input) * scale;
 	float value1 = readFloat(input) * scale;
 	float value2 = readFloat(input) * scale;
 	float value2 = readFloat(input) * scale;
@@ -805,7 +852,7 @@ Timeline *SkeletonBinary::readTimeline2(DataInput *input, CurveTimeline2 *timeli
 		value1 = nvalue1;
 		value1 = nvalue1;
 		value2 = nvalue2;
 		value2 = nvalue2;
 	}
 	}
-	return timeline;
+	timelines.add(timeline);
 }
 }
 
 
 Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData) {
 Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, SkeletonData *skeletonData) {
@@ -1039,50 +1086,59 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
 		for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) {
 		for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) {
 			unsigned char timelineType = readByte(input);
 			unsigned char timelineType = readByte(input);
 			int frameCount = readVarint(input, true);
 			int frameCount = readVarint(input, true);
-			int bezierCount = readVarint(input, true);
-			Timeline *timeline = NULL;
+            if (timelineType == BONE_INHERIT) {
+                InheritTimeline *timeline = new (__FILE__, __LINE__) InheritTimeline(frameCount, boneIndex);
+                for (int frame = 0; frame < frameCount; frame++) {
+                    float time = readFloat(input);
+                    Inherit inherit = (Inherit)readByte(input);
+                    timeline->setFrame(frame, time, inherit);
+                }
+                timelines.add(timeline);
+                continue;
+            }
+            int bezierCount = readVarint(input, true);
 			switch (timelineType) {
 			switch (timelineType) {
 				case BONE_ROTATE:
 				case BONE_ROTATE:
-					timeline = readTimeline(input,
+					readTimeline(input, timelines,
 											new (__FILE__, __LINE__) RotateTimeline(frameCount, bezierCount, boneIndex),
 											new (__FILE__, __LINE__) RotateTimeline(frameCount, bezierCount, boneIndex),
 											1);
 											1);
 					break;
 					break;
 				case BONE_TRANSLATE:
 				case BONE_TRANSLATE:
-					timeline = readTimeline2(input, new (__FILE__, __LINE__) TranslateTimeline(frameCount, bezierCount, boneIndex), scale);
+					readTimeline2(input, timelines,new (__FILE__, __LINE__) TranslateTimeline(frameCount, bezierCount, boneIndex), scale);
 					break;
 					break;
 				case BONE_TRANSLATEX:
 				case BONE_TRANSLATEX:
-					timeline = readTimeline(input, new (__FILE__, __LINE__) TranslateXTimeline(frameCount, bezierCount, boneIndex), scale);
+					readTimeline(input, timelines, new (__FILE__, __LINE__) TranslateXTimeline(frameCount, bezierCount, boneIndex), scale);
 					break;
 					break;
 				case BONE_TRANSLATEY:
 				case BONE_TRANSLATEY:
-					timeline = readTimeline(input, new (__FILE__, __LINE__) TranslateYTimeline(frameCount, bezierCount, boneIndex), scale);
+                    readTimeline(input, timelines, new (__FILE__, __LINE__) TranslateYTimeline(frameCount, bezierCount, boneIndex), scale);
 					break;
 					break;
 				case BONE_SCALE:
 				case BONE_SCALE:
-					timeline = readTimeline2(input,
+					readTimeline2(input, timelines,
 											 new (__FILE__, __LINE__) ScaleTimeline(frameCount, bezierCount, boneIndex),
 											 new (__FILE__, __LINE__) ScaleTimeline(frameCount, bezierCount, boneIndex),
 											 1);
 											 1);
 					break;
 					break;
 				case BONE_SCALEX:
 				case BONE_SCALEX:
-					timeline = readTimeline(input,
+					readTimeline(input, timelines,
 											new (__FILE__, __LINE__) ScaleXTimeline(frameCount, bezierCount, boneIndex),
 											new (__FILE__, __LINE__) ScaleXTimeline(frameCount, bezierCount, boneIndex),
 											1);
 											1);
 					break;
 					break;
 				case BONE_SCALEY:
 				case BONE_SCALEY:
-					timeline = readTimeline(input,
+					readTimeline(input, timelines,
 											new (__FILE__, __LINE__) ScaleYTimeline(frameCount, bezierCount, boneIndex),
 											new (__FILE__, __LINE__) ScaleYTimeline(frameCount, bezierCount, boneIndex),
 											1);
 											1);
 					break;
 					break;
 				case BONE_SHEAR:
 				case BONE_SHEAR:
-					timeline = readTimeline2(input,
+					readTimeline2(input, timelines,
 											 new (__FILE__, __LINE__) ShearTimeline(frameCount, bezierCount, boneIndex),
 											 new (__FILE__, __LINE__) ShearTimeline(frameCount, bezierCount, boneIndex),
 											 1);
 											 1);
 					break;
 					break;
 				case BONE_SHEARX:
 				case BONE_SHEARX:
-					timeline = readTimeline(input,
+					readTimeline(input, timelines,
 											new (__FILE__, __LINE__) ShearXTimeline(frameCount, bezierCount, boneIndex),
 											new (__FILE__, __LINE__) ShearXTimeline(frameCount, bezierCount, boneIndex),
 											1);
 											1);
 					break;
 					break;
 				case BONE_SHEARY:
 				case BONE_SHEARY:
-					timeline = readTimeline(input,
+					readTimeline(input, timelines,
 											new (__FILE__, __LINE__) ShearYTimeline(frameCount, bezierCount, boneIndex),
 											new (__FILE__, __LINE__) ShearYTimeline(frameCount, bezierCount, boneIndex),
 											1);
 											1);
 					break;
 					break;
@@ -1092,7 +1148,6 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
 					return NULL;
 					return NULL;
 				}
 				}
 			}
 			}
-			timelines.add(timeline);
 		}
 		}
 	}
 	}
 
 
@@ -1103,25 +1158,20 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
 		int frameLast = frameCount - 1;
 		int frameLast = frameCount - 1;
 		int bezierCount = readVarint(input, true);
 		int bezierCount = readVarint(input, true);
 		IkConstraintTimeline *timeline = new (__FILE__, __LINE__) IkConstraintTimeline(frameCount, bezierCount, index);
 		IkConstraintTimeline *timeline = new (__FILE__, __LINE__) IkConstraintTimeline(frameCount, bezierCount, index);
-		float time = readFloat(input);
-		float mix = readFloat(input);
-		float softness = readFloat(input) * scale;
-		for (int frame = 0, bezier = 0;; frame++) {
-			int bendDirection = readSByte(input);
-			bool compress = readBoolean(input);
-			bool stretch = readBoolean(input);
-			timeline->setFrame(frame, time, mix, softness, bendDirection, compress, stretch);
+        int flags = readByte(input);
+        float time = readFloat(input), mix = (flags & 1) != 0 ? ((flags & 2) != 0 ? readFloat(input) : 1) : 0;
+        float softness = (flags & 4) != 0 ? readFloat(input) * scale : 0;
+        for (int frame = 0, bezier = 0;; frame++) {
+			timeline->setFrame(frame, time, mix, softness, (flags & 8) != 0 ? 1 : -1, (flags & 16) != 0, (flags & 32) != 0);
 			if (frame == frameLast) break;
 			if (frame == frameLast) break;
-			float time2 = readFloat(input);
-			float mix2 = readFloat(input);
-			float softness2 = readFloat(input) * scale;
-			switch (readSByte(input)) {
-				case CURVE_STEPPED:
-					timeline->setStepped(frame);
-					break;
-				case CURVE_BEZIER:
-					setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1);
-					setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale);
+            flags = readByte(input);
+            float time2 = readFloat(input), mix2 = (flags & 1) != 0 ? ((flags & 2) != 0 ? readFloat(input) : 1) : 0;
+            float softness2 = (flags & 4) != 0 ? readFloat(input) * scale : 0;
+            if ((flags & 64) != 0)
+                timeline->setStepped(frame);
+            else if ((flags & 128) != 0) {
+			    setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1);
+				setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale);
 			}
 			}
 			time = time2;
 			time = time2;
 			mix = mix2;
 			mix = mix2;
@@ -1182,26 +1232,24 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
 		int index = readVarint(input, true);
 		int index = readVarint(input, true);
 		PathConstraintData *data = skeletonData->_pathConstraints[index];
 		PathConstraintData *data = skeletonData->_pathConstraints[index];
 		for (int ii = 0, nn = readVarint(input, true); ii < nn; ii++) {
 		for (int ii = 0, nn = readVarint(input, true); ii < nn; ii++) {
-			int type = readSByte(input);
+			int type = readByte(input);
 			int frameCount = readVarint(input, true);
 			int frameCount = readVarint(input, true);
 			int bezierCount = readVarint(input, true);
 			int bezierCount = readVarint(input, true);
-			switch (type) {
+            switch (type) {
 				case PATH_POSITION: {
 				case PATH_POSITION: {
-					timelines
-							.add(readTimeline(input, new PathConstraintPositionTimeline(frameCount, bezierCount, index),
-											  data->_positionMode == PositionMode_Fixed ? scale : 1));
+					readTimeline(input, timelines, new PathConstraintPositionTimeline(frameCount, bezierCount, index),
+											  data->_positionMode == PositionMode_Fixed ? scale : 1);
 					break;
 					break;
 				}
 				}
 				case PATH_SPACING: {
 				case PATH_SPACING: {
-					timelines
-							.add(readTimeline(input,
+					readTimeline(input, timelines,
 											  new PathConstraintSpacingTimeline(frameCount,
 											  new PathConstraintSpacingTimeline(frameCount,
 																				bezierCount,
 																				bezierCount,
 																				index),
 																				index),
 											  data->_spacingMode == SpacingMode_Length ||
 											  data->_spacingMode == SpacingMode_Length ||
 															  data->_spacingMode == SpacingMode_Fixed
 															  data->_spacingMode == SpacingMode_Fixed
 													  ? scale
 													  ? scale
-													  : 1));
+													  : 1);
 					break;
 					break;
 				}
 				}
 				case PATH_MIX:
 				case PATH_MIX:
@@ -1236,7 +1284,46 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
 		}
 		}
 	}
 	}
 
 
-	// Deform timelines.
+    // Physics timelines.
+    for (int i = 0, n = readVarint(input, true); i < n; i++) {
+        int index = readVarint(input, true) - 1;
+        for (int ii = 0, nn = readVarint(input, true); ii < nn; ii++) {
+            int type = readByte(input);
+            int frameCount = readVarint(input, true);
+            if (type == PHYSICS_RESET) {
+                PhysicsConstraintResetTimeline *timeline = new (__FILE__, __LINE__) PhysicsConstraintResetTimeline(frameCount, index);
+                for (int frame = 0; frame < frameCount; frame++)
+                    timeline->setFrame(frame, readFloat(input));
+                timelines.add(timeline);
+                continue;
+            }
+            int bezierCount = readVarint(input, true);
+            switch (type) {
+                case PHYSICS_INERTIA:
+                    readTimeline(input, timelines, new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, index), 1);
+                    break;
+                case PHYSICS_STRENGTH:
+                    readTimeline(input, timelines, new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, index), 1);
+                    break;
+                case PHYSICS_DAMPING:
+                    readTimeline(input, timelines, new PhysicsConstraintDampingTimeline(frameCount, bezierCount, index), 1);
+                    break;
+                case PHYSICS_MASS:
+                    readTimeline(input, timelines, new PhysicsConstraintMassTimeline(frameCount, bezierCount, index), 1);
+                    break;
+                case PHYSICS_WIND:
+                    readTimeline(input, timelines, new PhysicsConstraintWindTimeline(frameCount, bezierCount, index), 1);
+                    break;
+                case PHYSICS_GRAVITY:
+                    readTimeline(input, timelines, new PhysicsConstraintGravityTimeline(frameCount, bezierCount, index), 1);
+                    break;
+                case PHYSICS_MIX:
+                    readTimeline(input, timelines, new PhysicsConstraintMixTimeline(frameCount, bezierCount, index), 1);
+            }
+        }
+    }
+
+	// Attachment timelines.
 	for (int i = 0, n = readVarint(input, true); i < n; ++i) {
 	for (int i = 0, n = readVarint(input, true); i < n; ++i) {
 		Skin *skin = skeletonData->_skins[readVarint(input, true)];
 		Skin *skin = skeletonData->_skins[readVarint(input, true)];
 		for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) {
 		for (int ii = 0, nn = readVarint(input, true); ii < nn; ++ii) {
@@ -1379,10 +1466,13 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
 
 
 			event->_intValue = readVarint(input, false);
 			event->_intValue = readVarint(input, false);
 			event->_floatValue = readFloat(input);
 			event->_floatValue = readFloat(input);
-			bool freeString = readBoolean(input);
-			const char *event_stringValue = freeString ? readString(input) : eventData->_stringValue.buffer();
-			event->_stringValue = String(event_stringValue);
-			if (freeString) SpineExtension::free(event_stringValue, __FILE__, __LINE__);
+			const char *event_stringValue = readString(input);
+            if (event_stringValue == nullptr) {
+                event->_stringValue = eventData->_stringValue;
+            } else {
+                event->_stringValue = String(event_stringValue);
+                SpineExtension::free(event_stringValue, __FILE__, __LINE__);
+            }
 
 
 			if (!eventData->_audioPath.isEmpty()) {
 			if (!eventData->_audioPath.isEmpty()) {
 				event->_volume = readFloat(input);
 				event->_volume = readFloat(input);

+ 63 - 1
spine-cpp/spine-cpp/src/spine/SkeletonJson.cpp

@@ -58,6 +58,7 @@
 #include <spine/PathConstraintMixTimeline.h>
 #include <spine/PathConstraintMixTimeline.h>
 #include <spine/PathConstraintPositionTimeline.h>
 #include <spine/PathConstraintPositionTimeline.h>
 #include <spine/PathConstraintSpacingTimeline.h>
 #include <spine/PathConstraintSpacingTimeline.h>
+#include <spine/PhysicsConstraintData.h>
 #include <spine/PointAttachment.h>
 #include <spine/PointAttachment.h>
 #include <spine/RegionAttachment.h>
 #include <spine/RegionAttachment.h>
 #include <spine/RotateTimeline.h>
 #include <spine/RotateTimeline.h>
@@ -133,7 +134,7 @@ SkeletonData *SkeletonJson::readSkeletonDataFile(const String &path) {
 SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
 SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
 	int i, ii;
 	int i, ii;
 	SkeletonData *skeletonData;
 	SkeletonData *skeletonData;
-	Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *slots, *skins, *animations, *events;
+	Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *physics, *slots, *skins, *animations, *events;
 
 
 	_error = "";
 	_error = "";
 	_linkedMeshes.clear();
 	_linkedMeshes.clear();
@@ -455,6 +456,54 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
 		}
 		}
 	}
 	}
 
 
+    /* Physics constraints */
+    physics = Json::getItem(root, "physics");
+    if (physics) {
+        Json *constraintMap;
+        skeletonData->_physicsConstraints.ensureCapacity(physics->_size);
+        skeletonData->_physicsConstraints.setSize(physics->_size, 0);
+        for (constraintMap = physics->_child, i = 0; constraintMap; constraintMap = constraintMap->_next, ++i) {
+            const char *name;
+
+            PhysicsConstraintData *data = new (__FILE__, __LINE__) PhysicsConstraintData(
+                    Json::getString(constraintMap, "name", 0));
+            data->setOrder(Json::getInt(constraintMap, "order", 0));
+            data->setSkinRequired(Json::getBoolean(constraintMap, "skin", false));
+
+            name = Json::getString(constraintMap, "bone", 0);
+            data->_bone = skeletonData->findBone(name);
+            if (!data->_bone) {
+                delete skeletonData;
+                setError(root, "Physics bone not found: ", name);
+                return NULL;
+            }
+
+            data->_x = Json::getFloat(constraintMap, "x", 0);
+            data->_y = Json::getFloat(constraintMap, "y", 0);
+            data->_rotate = Json::getFloat(constraintMap, "rotate", 0);
+            data->_scaleX = Json::getFloat(constraintMap, "scaleX", 0);
+            data->_shearX = Json::getFloat(constraintMap, "shearX", 0);
+            data->_limit = Json::getFloat(constraintMap, "limit", 5000) * _scale;
+            data->_step = 1.0f / Json::getInt(constraintMap, "fps", 60);
+            data->_inertia = Json::getFloat(constraintMap, "inertia", 1);
+            data->_strength = Json::getFloat(constraintMap, "strength", 100);
+            data->_damping = Json::getFloat(constraintMap, "damping", 1);
+            data->_massInverse = 1 / Json::getFloat(constraintMap, "mass", 1);
+            data->_wind = Json::getFloat(constraintMap, "wind", 0);
+            data->_gravity = Json::getFloat(constraintMap, "gravity", 0);
+            data->_mix = Json::getFloat(constraintMap, "mix", 1);
+            data->_inertiaGlobal = Json::getBoolean(constraintMap, "inertiaGlobal", false);
+            data->_strengthGlobal = Json::getBoolean(constraintMap, "strengthGlobal", false);
+            data->_dampingGlobal = Json::getBoolean(constraintMap, "dampingGlobal", false);
+            data->_massGlobal = Json::getBoolean(constraintMap, "massGlobal", false);
+            data->_windGlobal = Json::getBoolean(constraintMap, "windGlobal", false);
+            data->_gravityGlobal = Json::getBoolean(constraintMap, "gravityGlobal", false);
+            data->_mixGlobal = Json::getBoolean(constraintMap, "mixGlobal", false);
+
+            skeletonData->_physicsConstraints[i] = data;
+        }
+    }
+
 	/* Skins. */
 	/* Skins. */
 	skins = Json::getItem(root, "skins");
 	skins = Json::getItem(root, "skins");
 	if (skins) {
 	if (skins) {
@@ -520,6 +569,19 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
 				}
 				}
 			}
 			}
 
 
+            item = Json::getItem(skinMap, "physics");
+            if (item) {
+                for (item = item->_child; item; item = item->_next) {
+                    PhysicsConstraintData *data = skeletonData->findPhysicsConstraint(item->_valueString);
+                    if (!data) {
+                        delete skeletonData;
+                        setError(root, String("Skin physics constraint not found: "), item->_valueString);
+                        return NULL;
+                    }
+                    skin->getConstraints().add(data);
+                }
+            }
+
 			skeletonData->_skins[skinsIndex++] = skin;
 			skeletonData->_skins[skinsIndex++] = skin;
 			if (strcmp(Json::getString(skinMap, "name", ""), "default") == 0) {
 			if (strcmp(Json::getString(skinMap, "name", ""), "default") == 0) {
 				skeletonData->_defaultSkin = skin;
 				skeletonData->_defaultSkin = skin;

+ 36 - 2
spine-sfml/cpp/example/main.cpp

@@ -611,6 +611,40 @@ void mixAndMatch(SkeletonData *skeletonData, Atlas *atlas) {
 	}
 	}
 }
 }
 
 
+void celestialCircus(SkeletonData *skeletonData, Atlas *atlas) {
+    SP_UNUSED(atlas);
+
+    SkeletonDrawable drawable(skeletonData);
+    drawable.timeScale = 1;
+    drawable.setUsePremultipliedAlpha(true);
+
+    Skeleton *skeleton = drawable.skeleton;
+    skeleton->setPosition(320, 480);
+    skeleton->updateWorldTransform(Physics_Update);
+
+    drawable.state->setAnimation(0, "swing", true);
+
+    sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - celestial circus");
+    window.setFramerateLimit(60);
+    sf::Event event;
+    sf::Clock deltaClock;
+
+    while (window.isOpen()) {
+        while (window.pollEvent(event)) {
+            if (event.type == sf::Event::Closed) window.close();
+        }
+
+        float delta = deltaClock.getElapsedTime().asSeconds();
+        deltaClock.restart();
+
+        drawable.update(delta);
+
+        window.clear();
+        window.draw(drawable);
+        window.display();
+    }
+}
+
 /**
 /**
  * Used for debugging purposes during runtime development
  * Used for debugging purposes during runtime development
  */
  */
@@ -636,11 +670,11 @@ DebugExtension dbgExtension(SpineExtension::getInstance());
 int main() {
 int main() {
 	SpineExtension::setInstance(&dbgExtension);
 	SpineExtension::setInstance(&dbgExtension);
 
 
+    testcase(ikDemo, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);
+    testcase(celestialCircus, "data/celestial-circus-pro.json", "data/celestial-circus-pro.skel", "data/celestial-circus-pma.atlas", 0.2f);
 	testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f);
 	testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f);
 	testcase(dragon, "data/dragon-ess.json", "data/dragon-ess.skel", "data/dragon-pma.atlas", 0.6f);
 	testcase(dragon, "data/dragon-ess.json", "data/dragon-ess.skel", "data/dragon-pma.atlas", 0.6f);
-	testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f);
 	testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl-pma.atlas", 0.5f);
 	testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl-pma.atlas", 0.5f);
-	testcase(ikDemo, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);
 	testcase(mixAndMatch, "data/mix-and-match-pro.json", "data/mix-and-match-pro.skel", "data/mix-and-match-pma.atlas", 0.5f);
 	testcase(mixAndMatch, "data/mix-and-match-pro.json", "data/mix-and-match-pro.skel", "data/mix-and-match-pma.atlas", 0.5f);
 	testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin-pma.atlas", 0.5f);
 	testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin-pma.atlas", 0.5f);
 	testcase(spineboy, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);
 	testcase(spineboy, "data/spineboy-pro.json", "data/spineboy-pro.skel", "data/spineboy-pma.atlas", 0.6f);

+ 1 - 0
spine-sfml/cpp/src/spine/spine-sfml.cpp

@@ -79,6 +79,7 @@ namespace spine {
 	void SkeletonDrawable::update(float deltaTime, Physics physics) {
 	void SkeletonDrawable::update(float deltaTime, Physics physics) {
 		state->update(deltaTime * timeScale);
 		state->update(deltaTime * timeScale);
 		state->apply(*skeleton);
 		state->apply(*skeleton);
+        skeleton->update(deltaTime * timeScale);
 		skeleton->updateWorldTransform(physics);
 		skeleton->updateWorldTransform(physics);
 	}
 	}