Bläddra i källkod

Merge branch 'spine-c-3.5' into spine-3.5

badlogic 9 år sedan
förälder
incheckning
7460418885

+ 6 - 6
spine-c/include/spine/Bone.h

@@ -47,11 +47,11 @@ struct spBone {
 	int childrenCount;
 	int childrenCount;
 	spBone** const children;
 	spBone** const children;
 	float x, y, rotation, scaleX, scaleY, shearX, shearY;
 	float x, y, rotation, scaleX, scaleY, shearX, shearY;
-	float appliedRotation;
+	float ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY;
+	int /*bool*/ appliedValid;
 
 
 	float const a, b, worldX;
 	float const a, b, worldX;
 	float const c, d, worldY;
 	float const c, d, worldY;
-	float const worldSignX, worldSignY;
 
 
 	int/*bool*/ sorted;
 	int/*bool*/ sorted;
 
 
@@ -62,11 +62,11 @@ struct spBone {
 		parent(0),
 		parent(0),
 		childrenCount(0), children(0),
 		childrenCount(0), children(0),
 		x(0), y(0), rotation(0), scaleX(0), scaleY(0),
 		x(0), y(0), rotation(0), scaleX(0), scaleY(0),
-		appliedRotation(0),
+		ax(0), ay(0), arotation(0), ascaleX(0), ascaleY(0), ashearX(0), ashearY(0),
+		appliedValid(0),
 
 
 		a(0), b(0), worldX(0),
 		a(0), b(0), worldX(0),
 		c(0), d(0), worldY(0),
 		c(0), d(0), worldY(0),
-		worldSignX(0), worldSignY(0),
 
 
 		sorted(0) {
 		sorted(0) {
 	}
 	}
@@ -93,7 +93,7 @@ float spBone_getWorldScaleY (spBone* self);
 float spBone_worldToLocalRotationX (spBone* self);
 float spBone_worldToLocalRotationX (spBone* self);
 float spBone_worldToLocalRotationY (spBone* self);
 float spBone_worldToLocalRotationY (spBone* self);
 void spBone_rotateWorld (spBone* self, float degrees);
 void spBone_rotateWorld (spBone* self, float degrees);
-void spBone_updateLocalTransform (spBone* self);
+void spBone_updateAppliedTransform (spBone* self);
 
 
 void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY);
 void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY);
 void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY);
 void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY);
@@ -114,7 +114,7 @@ typedef spBone Bone;
 #define Bone_worldToLocalRotationX(...) spBone_worldToLocalRotationX(__VA_ARGS__)
 #define Bone_worldToLocalRotationX(...) spBone_worldToLocalRotationX(__VA_ARGS__)
 #define Bone_worldToLocalRotationY(...) spBone_worldToLocalRotationY(__VA_ARGS__)
 #define Bone_worldToLocalRotationY(...) spBone_worldToLocalRotationY(__VA_ARGS__)
 #define Bone_rotateWorld(...) spBone_rotateWorld(__VA_ARGS__)
 #define Bone_rotateWorld(...) spBone_rotateWorld(__VA_ARGS__)
-#define Bone_updateLocalTransform(...) spBone_updateLocalTransform(__VA_ARGS__)
+#define Bone_updateAppliedTransform(...) spBone_updateAppliedTransform(__VA_ARGS__)
 #define Bone_worldToLocal(...) spBone_worldToLocal(__VA_ARGS__)
 #define Bone_worldToLocal(...) spBone_worldToLocal(__VA_ARGS__)
 #define Bone_localToWorld(...) spBone_localToWorld(__VA_ARGS__)
 #define Bone_localToWorld(...) spBone_localToWorld(__VA_ARGS__)
 #endif
 #endif

+ 10 - 2
spine-c/include/spine/BoneData.h

@@ -35,6 +35,14 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+typedef enum {
+	SP_TRANSFORMMODE_NORMAL,
+	SP_TRANSFORMMODE_ONLYTRANSLATION,
+	SP_TRANSFORMMODE_NOROTATIONORREFLECTION,
+	SP_TRANSFORMMODE_NOSCALE,
+	SP_TRANSFORMMODE_NOSCALEORREFLECTION
+} spTransformMode;
+
 typedef struct spBoneData spBoneData;
 typedef struct spBoneData spBoneData;
 struct spBoneData {
 struct spBoneData {
 	const int index;
 	const int index;
@@ -42,7 +50,7 @@ struct spBoneData {
 	spBoneData* const parent;
 	spBoneData* const parent;
 	float length;
 	float length;
 	float x, y, rotation, scaleX, scaleY, shearX, shearY;
 	float x, y, rotation, scaleX, scaleY, shearX, shearY;
-	int/*bool*/inheritRotation, inheritScale;
+	spTransformMode transformMode;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 	spBoneData() :
 	spBoneData() :
@@ -54,7 +62,7 @@ struct spBoneData {
 		rotation(0),
 		rotation(0),
 		scaleX(0), scaleY(0),
 		scaleX(0), scaleY(0),
 		shearX(0), shearY(0),
 		shearX(0), shearY(0),
-		inheritRotation(0), inheritScale(0) {
+		transformMode(SP_TRANSFORMMODE_NORMAL) {
 	}
 	}
 #endif
 #endif
 };
 };

+ 1 - 4
spine-c/include/spine/IkConstraint.h

@@ -50,8 +50,6 @@ typedef struct spIkConstraint {
 	int bendDirection;
 	int bendDirection;
 	float mix;
 	float mix;
 
 
-	int level;
-
 #ifdef __cplusplus
 #ifdef __cplusplus
 	spIkConstraint() :
 	spIkConstraint() :
 		data(0),
 		data(0),
@@ -59,8 +57,7 @@ typedef struct spIkConstraint {
 		bones(0),
 		bones(0),
 		target(0),
 		target(0),
 		bendDirection(0),
 		bendDirection(0),
-		mix(0),
-		level(0) {
+		mix(0) {
 	}
 	}
 #endif
 #endif
 } spIkConstraint;
 } spIkConstraint;

+ 1 - 1
spine-c/include/spine/IkConstraintData.h

@@ -39,7 +39,7 @@ extern "C" {
 
 
 typedef struct spIkConstraintData {
 typedef struct spIkConstraintData {
 	const char* const name;
 	const char* const name;
-
+	int order;
 	int bonesCount;
 	int bonesCount;
 	spBoneData** bones;
 	spBoneData** bones;
 
 

+ 1 - 0
spine-c/include/spine/PathConstraintData.h

@@ -52,6 +52,7 @@ typedef enum {
 
 
 typedef struct spPathConstraintData {
 typedef struct spPathConstraintData {
 	const char* const name;
 	const char* const name;
+	int order;
 	int bonesCount;
 	int bonesCount;
 	spBoneData** const bones;
 	spBoneData** const bones;
 	spSlotData* target;
 	spSlotData* target;

+ 0 - 2
spine-c/include/spine/Skeleton.h

@@ -55,7 +55,6 @@ typedef struct spSkeleton {
 
 
 	int ikConstraintsCount;
 	int ikConstraintsCount;
 	spIkConstraint** ikConstraints;
 	spIkConstraint** ikConstraints;
-	spIkConstraint** ikConstraintsSorted;
 
 
 	int transformConstraintsCount;
 	int transformConstraintsCount;
 	spTransformConstraint** transformConstraints;
 	spTransformConstraint** transformConstraints;
@@ -81,7 +80,6 @@ typedef struct spSkeleton {
 
 
 		ikConstraintsCount(0),
 		ikConstraintsCount(0),
 		ikConstraints(0),
 		ikConstraints(0),
-		ikConstraintsSorted(0),
 
 
 		transformConstraintsCount(0),
 		transformConstraintsCount(0),
 		transformConstraints(0),
 		transformConstraints(0),

+ 1 - 0
spine-c/include/spine/TransformConstraintData.h

@@ -39,6 +39,7 @@ extern "C" {
 
 
 typedef struct spTransformConstraintData {
 typedef struct spTransformConstraintData {
 	const char* const name;
 	const char* const name;
+	int order;
 	int bonesCount;
 	int bonesCount;
 	spBoneData** const bones;
 	spBoneData** const bones;
 	spBoneData* target;
 	spBoneData* target;

+ 121 - 107
spine-c/src/spine/Bone.c

@@ -61,15 +61,24 @@ void spBone_updateWorldTransform (spBone* self) {
 
 
 void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) {
 void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) {
 	float cosine, sine;
 	float cosine, sine;
-	float rotationY = rotation + 90 + shearY;
-	float la = COS_DEG(rotation + shearX) * scaleX, lb = COS_DEG(rotationY) * scaleY;
-	float lc = SIN_DEG(rotation + shearX) * scaleX, ld = SIN_DEG(rotationY) * scaleY;
-	float pa, pb, pc, pd, temp;
+	float pa, pb, pc, pd;
 	spBone* parent = self->parent;
 	spBone* parent = self->parent;
 
 
-	CONST_CAST(float, self->appliedRotation) = rotation;
+	self->ax = x;
+	self->ay = y;
+	self->arotation = rotation;
+	self->ascaleX = scaleX;
+	self->ascaleY = scaleY;
+	self->ashearX = shearX;
+	self->ashearY = shearY;
+	self->appliedValid = 1;
 
 
 	if (!parent) { /* Root bone. */
 	if (!parent) { /* Root bone. */
+		float rotationY = rotation + 90 + shearY;
+		float la = COS_DEG(rotation + shearX) * scaleX;
+		float lb = COS_DEG(rotationY) * scaleY;
+		float lc = SIN_DEG(rotation + shearX) * scaleX;
+		float ld = SIN_DEG(rotationY) * scaleY;
 		if (self->skeleton->flipX) {
 		if (self->skeleton->flipX) {
 			x = -x;
 			x = -x;
 			la = -la;
 			la = -la;
@@ -84,10 +93,8 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
 		CONST_CAST(float, self->b) = lb;
 		CONST_CAST(float, self->b) = lb;
 		CONST_CAST(float, self->c) = lc;
 		CONST_CAST(float, self->c) = lc;
 		CONST_CAST(float, self->d) = ld;
 		CONST_CAST(float, self->d) = ld;
-		CONST_CAST(float, self->worldX) = x;
-		CONST_CAST(float, self->worldY) = y;
-		CONST_CAST(float, self->worldSignX) = scaleX > 0 ? 1.0f : -1.0f;
-		CONST_CAST(float, self->worldSignY) = scaleY > 0 ? 1.0f : -1.0f;
+		CONST_CAST(float, self->worldX) = x + self->skeleton->x;
+		CONST_CAST(float, self->worldY) = y + self->skeleton->y;
 		return;
 		return;
 	}
 	}
 
 
@@ -98,84 +105,91 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
 
 
 	CONST_CAST(float, self->worldX) = pa * x + pb * y + parent->worldX;
 	CONST_CAST(float, self->worldX) = pa * x + pb * y + parent->worldX;
 	CONST_CAST(float, self->worldY) = pc * x + pd * y + parent->worldY;
 	CONST_CAST(float, self->worldY) = pc * x + pd * y + parent->worldY;
-	CONST_CAST(float, self->worldSignX) = parent->worldSignX * (scaleX > 0 ? 1 : -1);
-	CONST_CAST(float, self->worldSignY) = parent->worldSignY * (scaleY > 0 ? 1 : -1);
 
 
-	if (self->data->inheritRotation && self->data->inheritScale) {
-		CONST_CAST(float, self->a) = pa * la + pb * lc;
-		CONST_CAST(float, self->b) = pa * lb + pb * ld;
-		CONST_CAST(float, self->c) = pc * la + pd * lc;
-		CONST_CAST(float, self->d) = pc * lb + pd * ld;
-	} else {
-		if (self->data->inheritRotation) { /* No scale inheritance. */
-			pa = 1;
-			pb = 0;
-			pc = 0;
-			pd = 1;
-			do {
-				cosine = COS_DEG(parent->appliedRotation); sine = SIN_DEG(parent->appliedRotation);
-				temp = pa * cosine + pb * sine;
-				pb = pb * cosine - pa * sine;
-				pa = temp;
-				temp = pc * cosine + pd * sine;
-				pd = pd * cosine - pc * sine;
-				pc = temp;
-
-				if (!parent->data->inheritRotation) break;
-				parent = parent->parent;
-			} while (parent);
+	switch (self->data->transformMode) {
+		case SP_TRANSFORMMODE_NORMAL: {
+			float rotationY = rotation + 90 + shearY;
+			float la = COS_DEG(rotation + shearX) * scaleX;
+			float lb = COS_DEG(rotationY) * scaleY;
+			float lc = SIN_DEG(rotation + shearX) * scaleX;
+			float ld = SIN_DEG(rotationY) * scaleY;
 			CONST_CAST(float, self->a) = pa * la + pb * lc;
 			CONST_CAST(float, self->a) = pa * la + pb * lc;
 			CONST_CAST(float, self->b) = pa * lb + pb * ld;
 			CONST_CAST(float, self->b) = pa * lb + pb * ld;
 			CONST_CAST(float, self->c) = pc * la + pd * lc;
 			CONST_CAST(float, self->c) = pc * la + pd * lc;
 			CONST_CAST(float, self->d) = pc * lb + pd * ld;
 			CONST_CAST(float, self->d) = pc * lb + pd * ld;
-		} else if (self->data->inheritScale) { /* No rotation inheritance. */
-			pa = 1;
-			pb = 0;
-			pc = 0;
-			pd = 1;
-			do {
-				float za, zb, zc, zd;
-				float psx = parent->scaleX, psy = parent->scaleY;
-				cosine = COS_DEG(parent->appliedRotation);
-				sine = SIN_DEG(parent->appliedRotation);
-				za = cosine * psx; zb = sine * psy; zc = sine * psx; zd = cosine * psy;
-				temp = pa * za + pb * zc;
-				pb = pb * zd - pa * zb;
-				pa = temp;
-				temp = pc * za + pd * zc;
-				pd = pd * zd - pc * zb;
-				pc = temp;
-
-				if (psx >= 0) sine = -sine;
-				temp = pa * cosine + pb * sine;
-				pb = pb * cosine - pa * sine;
-				pa = temp;
-				temp = pc * cosine + pd * sine;
-				pd = pd * cosine - pc * sine;
-				pc = temp;
-
-				if (!parent->data->inheritScale) break;
-				parent = parent->parent;
-			} while (parent);
-			CONST_CAST(float, self->a) = pa * la + pb * lc;
-			CONST_CAST(float, self->b) = pa * lb + pb * ld;
+			return;
+		}
+		case SP_TRANSFORMMODE_ONLYTRANSLATION: {
+			float rotationY = rotation + 90 + shearY;
+			CONST_CAST(float, self->a) = COS_DEG(rotation + shearX) * scaleX;
+			CONST_CAST(float, self->b) = COS_DEG(rotationY) * scaleY;
+			CONST_CAST(float, self->c) = SIN_DEG(rotation + shearX) * scaleX;
+			CONST_CAST(float, self->d) = SIN_DEG(rotationY) * scaleY;
+			break;
+		}
+		case SP_TRANSFORMMODE_NOROTATIONORREFLECTION: {
+			float s = pa * pa + pc * pc;
+			float prx, rx, ry, la, lb, lc, ld;
+			if (s > 0.0001f) {
+				s = ABS(pa * pd - pb * pc) / s;
+				pb = pc * s;
+				pd = pa * s;
+				prx = ATAN2(pc, pa) * RAD_DEG;
+			} else {
+				pa = 0;
+				pc = 0;
+				prx = 90 - ATAN2(pd, pb) * RAD_DEG;
+			}
+			rx = rotation + shearX - prx;
+			ry = rotation + shearY - prx + 90;
+			la = COS_DEG(rx) * scaleX;
+			lb = COS_DEG(ry) * scaleY;
+			lc = SIN_DEG(rx) * scaleX;
+			ld = SIN_DEG(ry) * scaleY;
+			CONST_CAST(float, self->a) = pa * la - pb * lc;
+			CONST_CAST(float, self->b) = pa * lb - pb * ld;
 			CONST_CAST(float, self->c) = pc * la + pd * lc;
 			CONST_CAST(float, self->c) = pc * la + pd * lc;
 			CONST_CAST(float, self->d) = pc * lb + pd * ld;
 			CONST_CAST(float, self->d) = pc * lb + pd * ld;
-		} else {
-			CONST_CAST(float, self->a) = la;
-			CONST_CAST(float, self->b) = lb;
-			CONST_CAST(float, self->c) = lc;
-			CONST_CAST(float, self->d) = ld;
-		}
-		if (self->skeleton->flipX) {
-			CONST_CAST(float, self->a) = -self->a;
-			CONST_CAST(float, self->b) = -self->b;
+			break;
 		}
 		}
-		if (self->skeleton->flipY != yDown) {
-			CONST_CAST(float, self->c) = -self->c;
-			CONST_CAST(float, self->d) = -self->d;
+		case SP_TRANSFORMMODE_NOSCALE:
+		case SP_TRANSFORMMODE_NOSCALEORREFLECTION: {
+			float za, zc, s;
+			float r, zb, zd, la, lb, lc, ld;
+			cosine = COS_DEG(rotation); sine = SIN_DEG(rotation);
+			za = pa * cosine + pb * sine;
+			zc = pc * cosine + pd * sine;
+			s = SQRT(za * za + zc * zc);
+			if (s > 0.00001f) s = 1 / s;
+			za *= s;
+			zc *= s;
+			s = SQRT(za * za + zc * zc);
+			r = PI / 2 + atan2(zc, za);
+			zb = COS(r) * s;
+			zd = SIN(r) * s;
+			la = COS_DEG(shearX) * scaleX;
+			lb = COS_DEG(90 + shearY) * scaleY;
+			lc = SIN_DEG(shearX) * scaleX;
+			ld = SIN_DEG(90 + shearY) * scaleY;
+			CONST_CAST(float, self->a) = za * la + zb * lc;
+			CONST_CAST(float, self->b) = za * lb + zb * ld;
+			CONST_CAST(float, self->c) = zc * la + zd * lc;
+			CONST_CAST(float, self->d) = zc * lb + zd * ld;
+			if (self->data->transformMode != SP_TRANSFORMMODE_NOSCALEORREFLECTION ? pa * pd - pb * pc < 0 : self->skeleton->flipX != self->skeleton->flipY) {
+				CONST_CAST(float, self->b) = -self->b;
+				CONST_CAST(float, self->d) = -self->d;
+			}
+			return;
 		}
 		}
 	}
 	}
+	if (self->skeleton->flipX) {
+		CONST_CAST(float, self->a) = -self->a;
+		CONST_CAST(float, self->b) = -self->b;
+	}
+	if (self->skeleton->flipY != yDown) {
+		CONST_CAST(float, self->c) = -self->c;
+		CONST_CAST(float, self->d) = -self->d;
+	}
 }
 }
 
 
 void spBone_setToSetupPose (spBone* self) {
 void spBone_setToSetupPose (spBone* self) {
@@ -197,22 +211,22 @@ float spBone_getWorldRotationY (spBone* self) {
 }
 }
 
 
 float spBone_getWorldScaleX (spBone* self) {
 float spBone_getWorldScaleX (spBone* self) {
-	return SQRT(self->a * self->a + self->b * self->b) * self->worldSignX;
+	return SQRT(self->a * self->a + self->c * self->c);
 }
 }
 
 
 float spBone_getWorldScaleY (spBone* self) {
 float spBone_getWorldScaleY (spBone* self) {
-	return SQRT(self->c * self->c + self->d * self->d) * self->worldSignY;
+	return SQRT(self->b * self->b + self->d * self->d);
 }
 }
 
 
 float spBone_worldToLocalRotationX (spBone* self) {
 float spBone_worldToLocalRotationX (spBone* self) {
 	spBone* parent = self->parent;
 	spBone* parent = self->parent;
-	if (!parent) return self->rotation;
+	if (!parent) return self->arotation;
 	return ATAN2(parent->a * self->c - parent->c * self->a, parent->d * self->a - parent->b * self->c) * RAD_DEG;
 	return ATAN2(parent->a * self->c - parent->c * self->a, parent->d * self->a - parent->b * self->c) * RAD_DEG;
 }
 }
 
 
 float spBone_worldToLocalRotationY (spBone* self) {
 float spBone_worldToLocalRotationY (spBone* self) {
 	spBone* parent = self->parent;
 	spBone* parent = self->parent;
-	if (!parent) return self->rotation;
+	if (!parent) return self->arotation;
 	return ATAN2(parent->a * self->d - parent->c * self->b, parent->d * self->b - parent->b * self->d) * RAD_DEG;
 	return ATAN2(parent->a * self->d - parent->c * self->b, parent->d * self->b - parent->b * self->d) * RAD_DEG;
 }
 }
 
 
@@ -223,24 +237,25 @@ void spBone_rotateWorld (spBone* self, float degrees) {
 	CONST_CAST(float, self->b) = cosine * b - sine * d;
 	CONST_CAST(float, self->b) = cosine * b - sine * d;
 	CONST_CAST(float, self->c) = sine * a + cosine * c;
 	CONST_CAST(float, self->c) = sine * a + cosine * c;
 	CONST_CAST(float, self->d) = sine * b + cosine * d;
 	CONST_CAST(float, self->d) = sine * b + cosine * d;
+	CONST_CAST(int, self->appliedValid) = 1;
 }
 }
 
 
-/** Computes the local transform from the world transform. This can be useful to perform processing on the local transform
- * after the world transform has been modified directly (eg, by a constraint).
+
+/** Computes the individual applied transform values from the world transform. This can be useful to perform processing using
+ * the applied transform after the world transform has been modified directly (eg, by a constraint).
  * <p>
  * <p>
- * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local
- * transform values may differ from the original values but are functionally the same. */
-void spBone_updateLocalTransform (spBone* self) {
+ * Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */
+void spBone_updateAppliedTransform (spBone* self) {
 	spBone* parent = self->parent;
 	spBone* parent = self->parent;
+	self->appliedValid = 1;
 	if (!parent) {
 	if (!parent) {
-		float det = self->a * self->d - self->b * self->c;
-		self->x = self->worldX;
-		self->y = self->worldY;
-		self->rotation = ATAN2(self->c, self->a) * RAD_DEG;
-		self->scaleX = SQRT(self->a * self->a + self->c * self->c);
-		self->scaleY = SQRT(self->b * self->b + self->d * self->d);
-		self->shearX = 0;
-		self->shearY = ATAN2(self->a * self->b + self->c * self->d, det) * RAD_DEG;
+		self->ax = self->worldX;
+		self->ay = self->worldY;
+		self->arotation = ATAN2(self->c, self->a) * RAD_DEG;
+		self->ascaleX = SQRT(self->a * self->a + self->c * self->c);
+		self->ascaleY = SQRT(self->b * self->b + self->d * self->d);
+		self->ashearX = 0;
+		self->ashearY = ATAN2(self->a * self->b + self->c * self->d, self->a * self->d - self->b * self->c) * RAD_DEG;
 	} else {
 	} else {
 		float pa = parent->a, pb = parent->b, pc = parent->c, pd = parent->d;
 		float pa = parent->a, pb = parent->b, pc = parent->c, pd = parent->d;
 		float pid = 1 / (pa * pd - pb * pc);
 		float pid = 1 / (pa * pd - pb * pc);
@@ -253,22 +268,21 @@ void spBone_updateLocalTransform (spBone* self) {
 		float rb = ia * self->b - ib * self->d;
 		float rb = ia * self->b - ib * self->d;
 		float rc = id * self->c - ic * self->a;
 		float rc = id * self->c - ic * self->a;
 		float rd = id * self->d - ic * self->b;
 		float rd = id * self->d - ic * self->b;
-		self->x = (dx * pd * pid - dy * pb * pid);
-		self->y = (dy * pa * pid - dx * pc * pid);
-		self->shearX = 0;
-		self->scaleX = SQRT(ra * ra + rc * rc);
-		if (self->scaleX > 0.0001f) {
+		self->ax = (dx * pd * pid - dy * pb * pid);
+		self->ay = (dy * pa * pid - dx * pc * pid);
+		self->ashearX = 0;
+		self->ascaleX = SQRT(ra * ra + rc * rc);
+		if (self->ascaleX > 0.0001f) {
 			float det = ra * rd - rb * rc;
 			float det = ra * rd - rb * rc;
-			self->scaleY = det / self->scaleX;
-			self->shearY = ATAN2(ra * rb + rc * rd, det) * RAD_DEG;
-			self->rotation = ATAN2(rc, ra) * RAD_DEG;
+			self->ascaleY = det / self->ascaleX;
+			self->ashearY = ATAN2(ra * rb + rc * rd, det) * RAD_DEG;
+			self->arotation = ATAN2(rc, ra) * RAD_DEG;
 		} else {
 		} else {
-			self->scaleX = 0;
-			self->scaleY = SQRT(rb * rb + rd * rd);
-			self->shearY = 0;
-			self->rotation = 90 - ATAN2(rd, rb) * RAD_DEG;
+			self->ascaleX = 0;
+			self->ascaleY = SQRT(rb * rb + rd * rd);
+			self->ashearY = 0;
+			self->arotation = 90 - ATAN2(rd, rb) * RAD_DEG;
 		}
 		}
-		self->appliedRotation = self->rotation;
 	}
 	}
 }
 }
 
 

+ 1 - 2
spine-c/src/spine/BoneData.c

@@ -38,8 +38,7 @@ spBoneData* spBoneData_create (int index, const char* name, spBoneData* parent)
 	CONST_CAST(spBoneData*, self->parent) = parent;
 	CONST_CAST(spBoneData*, self->parent) = parent;
 	self->scaleX = 1;
 	self->scaleX = 1;
 	self->scaleY = 1;
 	self->scaleY = 1;
-	self->inheritRotation = 1;
-	self->inheritScale = 1;
+	self->transformMode = SP_TRANSFORMMODE_NORMAL;
 	return self;
 	return self;
 }
 }
 
 

+ 21 - 15
spine-c/src/spine/IkConstraint.c

@@ -67,21 +67,23 @@ void spIkConstraint_apply(spIkConstraint *self) {
 }
 }
 
 
 void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha) {
 void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha) {
-	spBone* pp = bone->parent;
-	float id = 1 / (pp->a * pp->d - pp->b * pp->c);
-	float x = targetX - pp->worldX, y = targetY - pp->worldY;
-	float tx = (x * pp->d - y * pp->b) * id - bone->x, ty = (y * pp->a - x * pp->c) * id - bone->y;
-	float rotationIK = ATAN2(ty, tx) * RAD_DEG - bone->shearX - bone->rotation;
-	if (bone->scaleX < 0) rotationIK += 180;
+	spBone* p = bone->parent;
+	float id, x, y, tx, ty, rotationIK;
+	if (!bone->appliedValid) spBone_updateAppliedTransform(bone);
+	id = 1 / (p->a * p->d - p->b * p->c);
+	x = targetX - p->worldX, y = targetY - p->worldY;
+	tx = (x * p->d - y * p->b) * id - bone->ax; ty = (y * p->a - x * p->c) * id - bone->ay;
+	rotationIK = ATAN2(ty, tx) * RAD_DEG - bone->ashearX - bone->arotation;
+	if (bone->ascaleX < 0) rotationIK += 180;
 	if (rotationIK > 180) rotationIK -= 360;
 	if (rotationIK > 180) rotationIK -= 360;
 	else if (rotationIK < -180) rotationIK += 360;
 	else if (rotationIK < -180) rotationIK += 360;
-	spBone_updateWorldTransformWith(bone, bone->x, bone->y, bone->rotation + rotationIK * alpha, bone->scaleX,
-		bone->scaleY, bone->shearX, bone->shearY);
+	spBone_updateWorldTransformWith(bone, bone->ax, bone->ay, bone->arotation + rotationIK * alpha, bone->ascaleX,
+		bone->ascaleY, bone->ashearX, bone->ashearY);
 }
 }
 
 
 void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, float alpha) {
 void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, float alpha) {
-	float px = parent->x, py = parent->y, psx = parent->scaleX, psy = parent->scaleY;
-	float cx = child->x, cy, csx = child->scaleX, cwx, cwy;
+	float px, py, psx, psy;
+	float cx, cy, csx, cwx, cwy;
 	int o1, o2, s2, u;
 	int o1, o2, s2, u;
 	spBone* pp = parent->parent;
 	spBone* pp = parent->parent;
 	float tx, ty, dx, dy, l1, l2, a1, a2, r;
 	float tx, ty, dx, dy, l1, l2, a1, a2, r;
@@ -90,6 +92,9 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
 		spBone_updateWorldTransform(child);
 		spBone_updateWorldTransform(child);
 		return;
 		return;
 	}
 	}
+	if (!parent->appliedValid) spBone_updateAppliedTransform(parent);
+	if (!child->appliedValid) spBone_updateAppliedTransform(child);
+	px = parent->ax; py = parent->ay; psx = parent->ascaleX; psy = parent->ascaleY; csx = child->ascaleX;
 	if (psx < 0) {
 	if (psx < 0) {
 		psx = -psx;
 		psx = -psx;
 		o1 = 180;
 		o1 = 180;
@@ -108,13 +113,14 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
 	} else
 	} else
 		o2 = 0;
 		o2 = 0;
 	r = psx - psy;
 	r = psx - psy;
+	cx = child->ax;
 	u = (r < 0 ? -r : r) <= 0.0001f;
 	u = (r < 0 ? -r : r) <= 0.0001f;
 	if (!u) {
 	if (!u) {
 		cy = 0;
 		cy = 0;
 		cwx = parent->a * cx + parent->worldX;
 		cwx = parent->a * cx + parent->worldX;
 		cwy = parent->c * cx + parent->worldY;
 		cwy = parent->c * cx + parent->worldY;
 	} else {
 	} else {
-		cy = child->y;
+		cy = child->ay;
 		cwx = parent->a * cx + parent->b * cy + parent->worldX;
 		cwx = parent->a * cx + parent->b * cy + parent->worldX;
 		cwy = parent->c * cx + parent->d * cy + parent->worldY;
 		cwy = parent->c * cx + parent->d * cy + parent->worldY;
 	}
 	}
@@ -198,13 +204,13 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
 	}
 	}
 	outer: {
 	outer: {
 		float os = ATAN2(cy, cx) * s2;
 		float os = ATAN2(cy, cx) * s2;
-		a1 = (a1 - os) * RAD_DEG + o1 - parent->rotation;
+		a1 = (a1 - os) * RAD_DEG + o1 - parent->arotation;
 		if (a1 > 180) a1 -= 360;
 		if (a1 > 180) a1 -= 360;
 		else if (a1 < -180) a1 += 360;
 		else if (a1 < -180) a1 += 360;
-		spBone_updateWorldTransformWith(parent, px, py, parent->rotation + a1 * alpha, parent->scaleX, parent->scaleY, 0, 0);
-		a2 = ((a2 + os) * RAD_DEG - child->shearX) * s2 + o2 - child->rotation;
+		spBone_updateWorldTransformWith(parent, px, py, parent->rotation + a1 * alpha, parent->ascaleX, parent->ascaleY, 0, 0);
+		a2 = ((a2 + os) * RAD_DEG - child->ashearX) * s2 + o2 - child->arotation;
 		if (a2 > 180) a2 -= 360;
 		if (a2 > 180) a2 -= 360;
 		else if (a2 < -180) a2 += 360;
 		else if (a2 < -180) a2 += 360;
-		spBone_updateWorldTransformWith(child, cx, cy, child->rotation + a2 * alpha, child->scaleX, child->scaleY, child->shearX, child->shearY);
+		spBone_updateWorldTransformWith(child, cx, cy, child->arotation + a2 * alpha, child->ascaleX, child->ascaleY, child->ashearX, child->ashearY);
 	}
 	}
 }
 }

+ 4 - 6
spine-c/src/spine/PathConstraint.c

@@ -77,8 +77,7 @@ void spPathConstraint_apply (spPathConstraint* self) {
 	float length, x, y, dx, dy, s;
 	float length, x, y, dx, dy, s;
 	float* spaces, *lengths, *positions;
 	float* spaces, *lengths, *positions;
 	float spacing;
 	float spacing;
-	spSkeleton* skeleton;
-	float skeletonX, skeletonY, boneX, boneY, offsetRotation;
+	float boneX, boneY, offsetRotation;
 	int/*bool*/tip;
 	int/*bool*/tip;
 	float rotateMix = self->rotateMix, translateMix = self->translateMix;
 	float rotateMix = self->rotateMix, translateMix = self->translateMix;
 	int/*bool*/ translate = translateMix > 0, rotate = rotateMix > 0;
 	int/*bool*/ translate = translateMix > 0, rotate = rotateMix > 0;
@@ -127,14 +126,12 @@ void spPathConstraint_apply (spPathConstraint* self) {
 
 
 	positions = spPathConstraint_computeWorldPositions(self, attachment, spacesCount, tangents,
 	positions = spPathConstraint_computeWorldPositions(self, attachment, spacesCount, tangents,
 		data->positionMode == SP_POSITION_MODE_PERCENT, spacingMode == SP_SPACING_MODE_PERCENT);
 		data->positionMode == SP_POSITION_MODE_PERCENT, spacingMode == SP_SPACING_MODE_PERCENT);
-	skeleton = self->target->bone->skeleton;
-	skeletonX = skeleton->x, skeletonY = skeleton->y;
 	boneX = positions[0], boneY = positions[1], offsetRotation = self->data->offsetRotation;
 	boneX = positions[0], boneY = positions[1], offsetRotation = self->data->offsetRotation;
 	tip = rotateMode == SP_ROTATE_MODE_CHAIN_SCALE && offsetRotation == 0;
 	tip = rotateMode == SP_ROTATE_MODE_CHAIN_SCALE && offsetRotation == 0;
 	for (i = 0, p = 3; i < boneCount; i++, p += 3) {
 	for (i = 0, p = 3; i < boneCount; i++, p += 3) {
 		spBone* bone = bones[i];
 		spBone* bone = bones[i];
-		CONST_CAST(float, bone->worldX) += (boneX - skeletonX - bone->worldX) * translateMix;
-		CONST_CAST(float, bone->worldY) += (boneY - skeletonY - bone->worldY) * translateMix;
+		CONST_CAST(float, bone->worldX) += (boneX - bone->worldX) * translateMix;
+		CONST_CAST(float, bone->worldY) += (boneY - bone->worldY) * translateMix;
 		x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
 		x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
 		if (scale) {
 		if (scale) {
 			length = lengths[i];
 			length = lengths[i];
@@ -174,6 +171,7 @@ void spPathConstraint_apply (spPathConstraint* self) {
 			CONST_CAST(float, bone->c) = sine * a + cosine * c;
 			CONST_CAST(float, bone->c) = sine * a + cosine * c;
 			CONST_CAST(float, bone->d) = sine * b + cosine * d;
 			CONST_CAST(float, bone->d) = sine * b + cosine * d;
 		}
 		}
+		CONST_CAST(int, bone->appliedValid) = -1;
 	}
 	}
 }
 }
 
 

+ 1 - 1
spine-c/src/spine/RegionAttachment.c

@@ -101,7 +101,7 @@ void spRegionAttachment_updateOffset (spRegionAttachment* self) {
 
 
 void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices) {
 void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices) {
 	const float* offset = self->offset;
 	const float* offset = self->offset;
-	float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY;
+	float x = bone->worldX, y = bone->worldY;
 	vertices[SP_VERTEX_X1] = offset[SP_VERTEX_X1] * bone->a + offset[SP_VERTEX_Y1] * bone->b + x;
 	vertices[SP_VERTEX_X1] = offset[SP_VERTEX_X1] * bone->a + offset[SP_VERTEX_Y1] * bone->b + x;
 	vertices[SP_VERTEX_Y1] = offset[SP_VERTEX_X1] * bone->c + offset[SP_VERTEX_Y1] * bone->d + y;
 	vertices[SP_VERTEX_Y1] = offset[SP_VERTEX_X1] * bone->c + offset[SP_VERTEX_Y1] * bone->d + y;
 	vertices[SP_VERTEX_X2] = offset[SP_VERTEX_X2] * bone->a + offset[SP_VERTEX_Y2] * bone->b + x;
 	vertices[SP_VERTEX_X2] = offset[SP_VERTEX_X2] * bone->a + offset[SP_VERTEX_Y2] * bone->b + x;

+ 150 - 95
spine-c/src/spine/Skeleton.c

@@ -32,7 +32,6 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include <spine/extension.h>
 #include <spine/extension.h>
-#include <spine/Skin.h>
 
 
 typedef enum {
 typedef enum {
 	SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_PATH_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT
 	SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_PATH_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT
@@ -49,6 +48,10 @@ typedef struct {
 	int updateCacheCount;
 	int updateCacheCount;
 	int updateCacheCapacity;
 	int updateCacheCapacity;
 	_spUpdate* updateCache;
 	_spUpdate* updateCache;
+
+	int updateCacheResetCount;
+	int updateCacheResetCapacity;
+	spBone** updateCacheReset;
 } _spSkeleton;
 } _spSkeleton;
 
 
 spSkeleton* spSkeleton_create (spSkeletonData* data) {
 spSkeleton* spSkeleton_create (spSkeletonData* data) {
@@ -65,15 +68,15 @@ spSkeleton* spSkeleton_create (spSkeletonData* data) {
 
 
 	for (i = 0; i < self->bonesCount; ++i) {
 	for (i = 0; i < self->bonesCount; ++i) {
 		spBoneData* boneData = self->data->bones[i];
 		spBoneData* boneData = self->data->bones[i];
-		spBone* bone;
+		spBone* newBone;
 		if (!boneData->parent)
 		if (!boneData->parent)
-			bone = spBone_create(boneData, self, 0);
+			newBone = spBone_create(boneData, self, 0);
 		else {
 		else {
 			spBone* parent = self->bones[boneData->parent->index];
 			spBone* parent = self->bones[boneData->parent->index];
-			bone = spBone_create(boneData, self, parent);
+			newBone = spBone_create(boneData, self, parent);
 			++childrenCounts[boneData->parent->index];
 			++childrenCounts[boneData->parent->index];
 		}
 		}
-		self->bones[i] = bone;
+		self->bones[i] = newBone;
 	}
 	}
 	for (i = 0; i < self->bonesCount; ++i) {
 	for (i = 0; i < self->bonesCount; ++i) {
 		spBoneData* boneData = self->data->bones[i];
 		spBoneData* boneData = self->data->bones[i];
@@ -101,7 +104,6 @@ spSkeleton* spSkeleton_create (spSkeletonData* data) {
 
 
 	self->ikConstraintsCount = data->ikConstraintsCount;
 	self->ikConstraintsCount = data->ikConstraintsCount;
 	self->ikConstraints = MALLOC(spIkConstraint*, self->ikConstraintsCount);
 	self->ikConstraints = MALLOC(spIkConstraint*, self->ikConstraintsCount);
-	self->ikConstraintsSorted = MALLOC(spIkConstraint*, self->ikConstraintsCount);
 	for (i = 0; i < self->data->ikConstraintsCount; ++i)
 	for (i = 0; i < self->data->ikConstraintsCount; ++i)
 		self->ikConstraints[i] = spIkConstraint_create(self->data->ikConstraints[i], self);
 		self->ikConstraints[i] = spIkConstraint_create(self->data->ikConstraints[i], self);
 
 
@@ -129,6 +131,7 @@ void spSkeleton_dispose (spSkeleton* self) {
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
 
 
 	FREE(internal->updateCache);
 	FREE(internal->updateCache);
+	FREE(internal->updateCacheReset);
 
 
 	for (i = 0; i < self->bonesCount; ++i)
 	for (i = 0; i < self->bonesCount; ++i)
 		spBone_dispose(self->bones[i]);
 		spBone_dispose(self->bones[i]);
@@ -141,7 +144,6 @@ void spSkeleton_dispose (spSkeleton* self) {
 	for (i = 0; i < self->ikConstraintsCount; ++i)
 	for (i = 0; i < self->ikConstraintsCount; ++i)
 		spIkConstraint_dispose(self->ikConstraints[i]);
 		spIkConstraint_dispose(self->ikConstraints[i]);
 	FREE(self->ikConstraints);
 	FREE(self->ikConstraints);
-	FREE(self->ikConstraintsSorted);
 
 
 	for (i = 0; i < self->transformConstraintsCount; ++i)
 	for (i = 0; i < self->transformConstraintsCount; ++i)
 		spTransformConstraint_dispose(self->transformConstraints[i]);
 		spTransformConstraint_dispose(self->transformConstraints[i]);
@@ -167,6 +169,15 @@ static void _addToUpdateCache(_spSkeleton* const internal, _spUpdateType type, v
 	++internal->updateCacheCount;
 	++internal->updateCacheCount;
 }
 }
 
 
+static void _addToUpdateCacheReset(_spSkeleton* const internal, spBone* bone) {
+	if (internal->updateCacheResetCount == internal->updateCacheResetCapacity) {
+		internal->updateCacheResetCapacity *= 2;
+		internal->updateCacheReset = realloc(internal->updateCacheReset, sizeof(spBone*) * internal->updateCacheResetCapacity);
+	}
+	internal->updateCacheReset[internal->updateCacheResetCount] = bone;
+	++internal->updateCacheResetCount;
+}
+
 static void _sortBone(_spSkeleton* const internal, spBone* bone) {
 static void _sortBone(_spSkeleton* const internal, spBone* bone) {
 	if (bone->sorted) return;
 	if (bone->sorted) return;
 	if (bone->parent) _sortBone(internal, bone->parent);
 	if (bone->parent) _sortBone(internal, bone->parent);
@@ -185,7 +196,7 @@ static void _sortPathConstraintAttachmentBones(_spSkeleton* const internal, spAt
 		_sortBone(internal, slotBone);
 		_sortBone(internal, slotBone);
 	else {
 	else {
 		spBone** bones = internal->super.bones;
 		spBone** bones = internal->super.bones;
-		int i = 0;
+		int i = 0, n;
 		while (i < pathBonesCount) {
 		while (i < pathBonesCount) {
 			int boneCount = pathBones[i++];
 			int boneCount = pathBones[i++];
 			int n;
 			int n;
@@ -212,113 +223,145 @@ static void _sortReset(spBone** bones, int bonesCount) {
 	}
 	}
 }
 }
 
 
+static void _sortIkConstraint (_spSkeleton* const internal, spIkConstraint* constraint) {
+	int /*bool*/ contains = 0;
+	int i;
+	spBone* target = constraint->target;
+	spBone** constrained;
+	spBone* parent;
+	_sortBone(internal, target);
+
+	constrained = constraint->bones;
+	parent = constrained[0];
+	_sortBone(internal, parent);
+
+	if (constraint->bonesCount > 1) {
+		spBone* child = constrained[constraint->bonesCount - 1];
+		contains = 0;
+		for (i = 0; i < internal->updateCacheCount; i++) {
+			_spUpdate update = internal->updateCache[i];
+			if (update.object == child) {
+				contains = -1;
+				break;
+			}
+		}
+		if (!contains)
+			_addToUpdateCacheReset(internal, child);
+	}
+
+	_addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint);
+
+	_sortReset(parent->children, parent->childrenCount);
+	constrained[constraint->bonesCount-1]->sorted = 1;
+}
+
+static void _sortPathConstraint(_spSkeleton* const internal, spPathConstraint* constraint) {
+	spSlot* slot = constraint->target;
+	int slotIndex = slot->data->index;
+	spBone* slotBone = slot->bone;
+	int ii, nn, boneCount;
+	spAttachment* attachment;
+	spBone** constrained;
+	spSkeleton* skeleton = SUPER_CAST(spSkeleton, internal);
+	if (skeleton->skin) _sortPathConstraintAttachment(internal, skeleton->skin, slotIndex, slotBone);
+	if (skeleton->data->defaultSkin && skeleton->data->defaultSkin != skeleton->skin)
+		_sortPathConstraintAttachment(internal, skeleton->data->defaultSkin, slotIndex, slotBone);
+	for (ii = 0, nn = skeleton->data->skinsCount; ii < nn; ii++)
+		_sortPathConstraintAttachment(internal, skeleton->data->skins[ii], slotIndex, slotBone);
+
+	attachment = slot->attachment;
+	if (attachment->type == SP_ATTACHMENT_PATH) _sortPathConstraintAttachmentBones(internal, attachment, slotBone);
+
+	constrained = constraint->bones;
+	boneCount = constraint->bonesCount;
+	for (ii = 0; ii < boneCount; ii++)
+		_sortBone(internal, constrained[ii]);
+
+	_addToUpdateCache(internal, SP_UPDATE_PATH_CONSTRAINT, constraint);
+
+	for (ii = 0; ii < boneCount; ii++)
+		_sortReset(constrained[ii]->children, constrained[ii]->childrenCount);
+	for (ii = 0; ii < boneCount; ii++)
+		constrained[ii]->sorted = 1;
+}
+
+static void _sortTransformConstraint(_spSkeleton* const internal, spTransformConstraint* constraint) {
+	int ii, boneCount;
+	spBone** constrained;
+	_sortBone(internal, constraint->target);
+
+	constrained = constraint->bones;
+	boneCount = constraint->bonesCount;
+	for (ii = 0; ii < boneCount; ii++)
+		_sortBone(internal, constrained[ii]);
+
+	_addToUpdateCache(internal, SP_UPDATE_TRANSFORM_CONSTRAINT, constraint);
+
+	for (ii = 0; ii < boneCount; ii++)
+		_sortReset(constrained[ii]->children, constrained[ii]->childrenCount);
+	for (ii = 0; ii < boneCount; ii++)
+		constrained[ii]->sorted = 1;
+}
+
 void spSkeleton_updateCache (spSkeleton* self) {
 void spSkeleton_updateCache (spSkeleton* self) {
-	int i, ii, n, nn, level;
+	int i, ii;
 	spBone** bones;
 	spBone** bones;
 	spIkConstraint** ikConstraints;
 	spIkConstraint** ikConstraints;
 	spPathConstraint** pathConstraints;
 	spPathConstraint** pathConstraints;
 	spTransformConstraint** transformConstraints;
 	spTransformConstraint** transformConstraints;
+	int ikCount, transformCount, pathCount, constraintCount;
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
-	internal->updateCacheCapacity = self->bonesCount + self->ikConstraintsCount + self->transformConstraintsCount + self->pathConstraintsCount;
 
 
+	internal->updateCacheCapacity = self->bonesCount + self->ikConstraintsCount + self->transformConstraintsCount + self->pathConstraintsCount;
 	FREE(internal->updateCache);
 	FREE(internal->updateCache);
 	internal->updateCache = MALLOC(_spUpdate, internal->updateCacheCapacity);
 	internal->updateCache = MALLOC(_spUpdate, internal->updateCacheCapacity);
 	internal->updateCacheCount = 0;
 	internal->updateCacheCount = 0;
 
 
+	internal->updateCacheResetCapacity = self->bonesCount;
+	FREE(internal->updateCacheReset);
+	internal->updateCacheReset = MALLOC(spBone*, internal->updateCacheResetCapacity);
+	internal->updateCacheResetCount = 0;
+
 	bones = self->bones;
 	bones = self->bones;
 	for (i = 0; i < self->bonesCount; ++i)
 	for (i = 0; i < self->bonesCount; ++i)
 		bones[i]->sorted = 0;
 		bones[i]->sorted = 0;
 
 
 	/* IK first, lowest hierarchy depth first. */
 	/* IK first, lowest hierarchy depth first. */
-	if (self->ikConstraintsSorted) FREE(self->ikConstraintsSorted);
-	self->ikConstraintsSorted = MALLOC(spIkConstraint*, self->ikConstraintsCount);
-	ikConstraints = self->ikConstraintsSorted;
-	for (i = 0; i < self->ikConstraintsCount; ++i)
-		ikConstraints[i] = self->ikConstraints[i];
-	for (i = 0; i < self->ikConstraintsCount; ++i) {
-		spIkConstraint* ik = ikConstraints[i];
-		spBone* bone = ik->bones[0]->parent;
-		for (level = 0; bone; ++level)
-			bone = bone->parent;
-		ik->level = level;
-	}
-	for (i = 1; i < self->ikConstraintsCount; ++i) {
-		spIkConstraint* ik = ikConstraints[i];
-		level = ik->level;
-		for (ii = i - 1; ii >= 0; --ii) {
-			spIkConstraint* other = ikConstraints[ii];
-			if (other->level < level) break;
-			ikConstraints[ii + 1] = other;
-		}
-		ikConstraints[ii + 1] = ik;
-	}
-	for (i = 0; i < self->ikConstraintsCount; ++i) {
-		spBone** constrained;
-		spBone* parent;
-		spIkConstraint* constraint = ikConstraints[i];
-		spBone* target = constraint->target;
-		_sortBone(internal, target);
-
-		constrained = constraint->bones;
-		parent = constrained[0];
-		_sortBone(internal, parent);
-
-		_addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint);
-
-		_sortReset(parent->children, parent->childrenCount);
-		constrained[constraint->bonesCount - 1]->sorted = 1;
-	}
-
-	pathConstraints = self->pathConstraints;
-	for (i = 0, n = self->pathConstraintsCount; i < n; i++) {
-		spAttachment* attachment;
-		spBone** constrained;
-		int boneCount;
-		spPathConstraint* constraint = pathConstraints[i];
-
-		spSlot* slot = constraint->target;
-		int slotIndex = slot->data->index;
-		spBone* slotBone = slot->bone;
-		if (self->skin) _sortPathConstraintAttachment(internal, self->skin, slotIndex, slotBone);
-		if (self->data->defaultSkin && self->data->defaultSkin != self->skin)
-			_sortPathConstraintAttachment(internal, self->data->defaultSkin, slotIndex, slotBone);
-		for (ii = 0, nn = self->data->skinsCount; ii < nn; ii++)
-			_sortPathConstraintAttachment(internal, self->data->skins[ii], slotIndex, slotBone);
-
-		attachment = slot->attachment;
-		if (attachment->type == SP_ATTACHMENT_PATH) _sortPathConstraintAttachmentBones(internal, attachment, slotBone);
-
-		constrained = constraint->bones;
-		boneCount = constraint->bonesCount;
-		for (ii = 0; ii < boneCount; ii++)
-			_sortBone(internal, constrained[ii]);
-
-		_addToUpdateCache(internal, SP_UPDATE_PATH_CONSTRAINT, constraint);
-
-		for (ii = 0; ii < boneCount; ii++)
-			_sortReset(constrained[ii]->children, constrained[ii]->childrenCount);
-		for (ii = 0; ii < boneCount; ii++)
-			constrained[ii]->sorted = 1;
-	}
-
+	ikConstraints = self->ikConstraints;
 	transformConstraints = self->transformConstraints;
 	transformConstraints = self->transformConstraints;
-	for (i = 0, n = self->transformConstraintsCount; i < n; ++i) {
-		spTransformConstraint* constraint = transformConstraints[i];
-		spBone** constrained = constraint->bones;
-
-		_sortBone(internal, constraint->target);
-
-		for (ii = 0; ii < constraint->bonesCount; ++ii)
-			_sortBone(internal, constrained[ii]);
+	pathConstraints = self->pathConstraints;
+	ikCount = self->ikConstraintsCount; transformCount = self->transformConstraintsCount; pathCount = self->pathConstraintsCount;
+	constraintCount = ikCount + transformCount + pathCount;
+
+	i = 0;
+	outer:
+	for (; i < constraintCount; i++) {
+		for (ii = 0; ii < ikCount; ii++) {
+			spIkConstraint* ikConstraint = ikConstraints[ii];
+			if (ikConstraint->data->order == i) {
+				_sortIkConstraint(internal, ikConstraint);
+				i++;
+				goto outer;
+			}
+		}
 
 
-		_addToUpdateCache(internal, SP_UPDATE_TRANSFORM_CONSTRAINT, constraint);
+		for (ii = 0; ii < transformCount; ii++) {
+			spTransformConstraint* transformConstraint = transformConstraints[ii];
+			if (transformConstraint->data->order == i) {
+				_sortTransformConstraint(internal, transformConstraint);
+				i++;
+				goto outer;
+			}
+		}
 
 
-		for (ii = 0; ii < constraint->bonesCount; ++ii) {
-			spBone* bone = constrained[ii];
-			_sortReset(bone->children, bone->childrenCount);
+		for (ii = 0; ii < pathCount; ii++) {
+			spPathConstraint* pathConstraint = pathConstraints[ii];
+			if (pathConstraint->data->order == i) {
+				_sortPathConstraint(internal, pathConstraint);
+				i++;
+				goto outer;
+			}
 		}
 		}
-		for (ii = 0; ii < constraint->bonesCount; ++ii)
-			constrained[ii]->sorted = 1;
 	}
 	}
 
 
 	for (i = 0; i < self->bonesCount; ++i)
 	for (i = 0; i < self->bonesCount; ++i)
@@ -328,6 +371,18 @@ void spSkeleton_updateCache (spSkeleton* self) {
 void spSkeleton_updateWorldTransform (const spSkeleton* self) {
 void spSkeleton_updateWorldTransform (const spSkeleton* self) {
 	int i;
 	int i;
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
+	spBone** updateCacheReset = internal->updateCacheReset;
+	for (i = 0; i < internal->updateCacheResetCount; i++) {
+		spBone* bone = updateCacheReset[i];
+		CONST_CAST(float, bone->ax) = bone->x;
+		CONST_CAST(float, bone->ay) = bone->y;
+		CONST_CAST(float, bone->arotation) = bone->rotation;
+		CONST_CAST(float, bone->ascaleX) = bone->scaleX;
+		CONST_CAST(float, bone->ascaleY) = bone->scaleY;
+		CONST_CAST(float, bone->ashearX) = bone->shearX;
+		CONST_CAST(float, bone->ashearY) = bone->shearY;
+		CONST_CAST(int, bone->appliedValid) = 1;
+	}
 
 
 	for (i = 0; i < internal->updateCacheCount; ++i) {
 	for (i = 0; i < internal->updateCacheCount; ++i) {
 		_spUpdate* update = internal->updateCache + i;
 		_spUpdate* update = internal->updateCache + i;

+ 19 - 5
spine-c/src/spine/SkeletonBinary.c

@@ -788,8 +788,8 @@ spSkin* spSkeletonBinary_readSkin(spSkeletonBinary* self, _dataInput* input,
 		int slotIndex = readVarint(input, 1);
 		int slotIndex = readVarint(input, 1);
 		for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) {
 		for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) {
 			const char* name = readString(input);
 			const char* name = readString(input);
-			spSkin_addAttachment(skin, slotIndex, name,
-					spSkeletonBinary_readAttachment(self, input, skin, slotIndex, name, nonessential));
+			spAttachment* attachment = spSkeletonBinary_readAttachment(self, input, skin, slotIndex, name, nonessential);
+			if (attachment) spSkin_addAttachment(skin, slotIndex, name, attachment);
 			FREE(name);
 			FREE(name);
 		}
 		}
 	}
 	}
@@ -842,13 +842,18 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 
 
 	nonessential = readBoolean(input);
 	nonessential = readBoolean(input);
 
 
-	if (nonessential) FREE(readString(input)); /* Skip images path. */
+	if (nonessential) {
+		/* Skip images path & fps */
+		readFloat(input);
+		FREE(readString(input));
+	}
 
 
 	/* Bones. */
 	/* Bones. */
 	skeletonData->bonesCount = readVarint(input, 1);
 	skeletonData->bonesCount = readVarint(input, 1);
 	skeletonData->bones = MALLOC(spBoneData*, skeletonData->bonesCount);
 	skeletonData->bones = MALLOC(spBoneData*, skeletonData->bonesCount);
 	for (i = 0; i < skeletonData->bonesCount; ++i) {
 	for (i = 0; i < skeletonData->bonesCount; ++i) {
 		spBoneData* data;
 		spBoneData* data;
+		int mode;
 		const char* name = readString(input);
 		const char* name = readString(input);
 		spBoneData* parent = i == 0 ? 0 : skeletonData->bones[readVarint(input, 1)];
 		spBoneData* parent = i == 0 ? 0 : skeletonData->bones[readVarint(input, 1)];
 		/* TODO Avoid copying of name */
 		/* TODO Avoid copying of name */
@@ -862,8 +867,14 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		data->shearX = readFloat(input);
 		data->shearX = readFloat(input);
 		data->shearY = readFloat(input);
 		data->shearY = readFloat(input);
 		data->length = readFloat(input) * self->scale;
 		data->length = readFloat(input) * self->scale;
-		data->inheritRotation = readBoolean(input);
-		data->inheritScale = readBoolean(input);
+		mode = readVarint(input, 1);
+		switch (mode) {
+			case 0: data->transformMode = SP_TRANSFORMMODE_NORMAL; break;
+			case 1: data->transformMode = SP_TRANSFORMMODE_ONLYTRANSLATION; break;
+			case 2: data->transformMode = SP_TRANSFORMMODE_NOROTATIONORREFLECTION; break;
+			case 3: data->transformMode = SP_TRANSFORMMODE_NOSCALE; break;
+			case 4: data->transformMode = SP_TRANSFORMMODE_NOSCALEORREFLECTION; break;
+		}
 		if (nonessential) readInt(input); /* Skip bone color. */
 		if (nonessential) readInt(input); /* Skip bone color. */
 		skeletonData->bones[i] = data;
 		skeletonData->bones[i] = data;
 	}
 	}
@@ -890,6 +901,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		const char* name = readString(input);
 		const char* name = readString(input);
 		/* TODO Avoid copying of name */
 		/* TODO Avoid copying of name */
 		spIkConstraintData* data = spIkConstraintData_create(name);
 		spIkConstraintData* data = spIkConstraintData_create(name);
+		data->order = readVarint(input, 1);
 		FREE(name);
 		FREE(name);
 		data->bonesCount = readVarint(input, 1);
 		data->bonesCount = readVarint(input, 1);
 		data->bones = MALLOC(spBoneData*, data->bonesCount);
 		data->bones = MALLOC(spBoneData*, data->bonesCount);
@@ -909,6 +921,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		const char* name = readString(input);
 		const char* name = readString(input);
 		/* TODO Avoid copying of name */
 		/* TODO Avoid copying of name */
 		spTransformConstraintData* data = spTransformConstraintData_create(name);
 		spTransformConstraintData* data = spTransformConstraintData_create(name);
+		data->order = readVarint(input, 1);
 		FREE(name);
 		FREE(name);
 		data->bonesCount = readVarint(input, 1);
 		data->bonesCount = readVarint(input, 1);
 		CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);
 		CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);
@@ -935,6 +948,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		const char* name = readString(input);
 		const char* name = readString(input);
 		/* TODO Avoid copying of name */
 		/* TODO Avoid copying of name */
 		spPathConstraintData* data = spPathConstraintData_create(name);
 		spPathConstraintData* data = spPathConstraintData_create(name);
+		data->order = readVarint(input, 1);
 		FREE(name);
 		FREE(name);
 		data->bonesCount = readVarint(input, 1);
 		data->bonesCount = readVarint(input, 1);
 		CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);
 		CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);

+ 16 - 2
spine-c/src/spine/SkeletonJson.c

@@ -604,6 +604,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 	skeletonData->bones = MALLOC(spBoneData*, bones->size);
 	skeletonData->bones = MALLOC(spBoneData*, bones->size);
 	for (boneMap = bones->child, i = 0; boneMap; boneMap = boneMap->next, ++i) {
 	for (boneMap = bones->child, i = 0; boneMap; boneMap = boneMap->next, ++i) {
 		spBoneData* data;
 		spBoneData* data;
+		const char* transformMode;
 
 
 		spBoneData* parent = 0;
 		spBoneData* parent = 0;
 		const char* parentName = Json_getString(boneMap, "parent", 0);
 		const char* parentName = Json_getString(boneMap, "parent", 0);
@@ -625,8 +626,18 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 		data->scaleY = Json_getFloat(boneMap, "scaleY", 1);
 		data->scaleY = Json_getFloat(boneMap, "scaleY", 1);
 		data->shearX = Json_getFloat(boneMap, "shearX", 0);
 		data->shearX = Json_getFloat(boneMap, "shearX", 0);
 		data->shearY = Json_getFloat(boneMap, "shearY", 0);
 		data->shearY = Json_getFloat(boneMap, "shearY", 0);
-		data->inheritRotation = Json_getInt(boneMap, "inheritRotation", 1);
-		data->inheritScale = Json_getInt(boneMap, "inheritScale", 1);
+		transformMode = Json_getString(boneMap, "transform", "normal");
+		data->transformMode = SP_TRANSFORMMODE_NORMAL;
+		if (strcmp(transformMode, "normal") == 0)
+			data->transformMode = SP_TRANSFORMMODE_NORMAL;
+		if (strcmp(transformMode, "onlyTranslation") == 0)
+			data->transformMode = SP_TRANSFORMMODE_ONLYTRANSLATION;
+		if (strcmp(transformMode, "noRotationOrReflection") == 0)
+			data->transformMode = SP_TRANSFORMMODE_NOROTATIONORREFLECTION;
+		if (strcmp(transformMode, "noScale") == 0)
+			data->transformMode = SP_TRANSFORMMODE_NOSCALE;
+		if (strcmp(transformMode, "noScaleOrReflection") == 0)
+			data->transformMode = SP_TRANSFORMMODE_NOSCALEORREFLECTION;
 
 
 		skeletonData->bones[i] = data;
 		skeletonData->bones[i] = data;
 		skeletonData->bonesCount++;
 		skeletonData->bonesCount++;
@@ -688,6 +699,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 			const char* targetName;
 			const char* targetName;
 
 
 			spIkConstraintData* data = spIkConstraintData_create(Json_getString(constraintMap, "name", 0));
 			spIkConstraintData* data = spIkConstraintData_create(Json_getString(constraintMap, "name", 0));
+			data->order = Json_getInt(constraintMap, "order", 0);
 
 
 			boneMap = Json_getItem(constraintMap, "bones");
 			boneMap = Json_getItem(constraintMap, "bones");
 			data->bonesCount = boneMap->size;
 			data->bonesCount = boneMap->size;
@@ -726,6 +738,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 			const char* name;
 			const char* name;
 
 
 			spTransformConstraintData* data = spTransformConstraintData_create(Json_getString(constraintMap, "name", 0));
 			spTransformConstraintData* data = spTransformConstraintData_create(Json_getString(constraintMap, "name", 0));
+			data->order = Json_getInt(constraintMap, "order", 0);
 
 
 			boneMap = Json_getItem(constraintMap, "bones");
 			boneMap = Json_getItem(constraintMap, "bones");
 			data->bonesCount = boneMap->size;
 			data->bonesCount = boneMap->size;
@@ -774,6 +787,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 			const char* item;
 			const char* item;
 
 
 			spPathConstraintData* data = spPathConstraintData_create(Json_getString(constraintMap, "name", 0));
 			spPathConstraintData* data = spPathConstraintData_create(Json_getString(constraintMap, "name", 0));
+			data->order = Json_getInt(constraintMap, "order", 0);
 
 
 			boneMap = Json_getItem(constraintMap, "bones");
 			boneMap = Json_getItem(constraintMap, "bones");
 			data->bonesCount = boneMap->size;
 			data->bonesCount = boneMap->size;

+ 14 - 6
spine-c/src/spine/TransformConstraint.c

@@ -57,11 +57,13 @@ void spTransformConstraint_apply (spTransformConstraint* self) {
 	float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix;
 	float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix;
 	spBone* target = self->target;
 	spBone* target = self->target;
 	float ta = target->a, tb = target->b, tc = target->c, td = target->d;
 	float ta = target->a, tb = target->b, tc = target->c, td = target->d;
+	int /*bool*/ modified;
 	int i;
 	int i;
 	for (i = 0; i < self->bonesCount; ++i) {
 	for (i = 0; i < self->bonesCount; ++i) {
 		spBone* bone = self->bones[i];
 		spBone* bone = self->bones[i];
+		modified = 0;
 
 
-		if (rotateMix > 0) {
+		if (rotateMix != 0) {
 			float a = bone->a, b = bone->b, c = bone->c, d = bone->d;
 			float a = bone->a, b = bone->b, c = bone->c, d = bone->d;
 			float r = ATAN2(tc, ta) - ATAN2(c, a) + self->data->offsetRotation * DEG_RAD;
 			float r = ATAN2(tc, ta) - ATAN2(c, a) + self->data->offsetRotation * DEG_RAD;
 			float cosine, sine;
 			float cosine, sine;
@@ -74,26 +76,29 @@ void spTransformConstraint_apply (spTransformConstraint* self) {
 			CONST_CAST(float, bone->b) = cosine * b - sine * d;
 			CONST_CAST(float, bone->b) = cosine * b - sine * d;
 			CONST_CAST(float, bone->c) = sine * a + cosine * c;
 			CONST_CAST(float, bone->c) = sine * a + cosine * c;
 			CONST_CAST(float, bone->d) = sine * b + cosine * d;
 			CONST_CAST(float, bone->d) = sine * b + cosine * d;
+			modified = 1;
 		}
 		}
 
 
-		if (translateMix > 0) {
+		if (translateMix != 0) {
 			float x, y;
 			float x, y;
 			spBone_localToWorld(target, self->data->offsetX, self->data->offsetY, &x, &y);
 			spBone_localToWorld(target, self->data->offsetX, self->data->offsetY, &x, &y);
 			CONST_CAST(float, bone->worldX) += (x - bone->worldX) * translateMix;
 			CONST_CAST(float, bone->worldX) += (x - bone->worldX) * translateMix;
 			CONST_CAST(float, bone->worldY) += (y - bone->worldY) * translateMix;
 			CONST_CAST(float, bone->worldY) += (y - bone->worldY) * translateMix;
+			modified = 1;
 		}
 		}
 
 
 		if (scaleMix > 0) {
 		if (scaleMix > 0) {
-			float bs = SQRT(bone->a * bone->a + bone->c * bone->c);
+			float s = SQRT(bone->a * bone->a + bone->c * bone->c);
 			float ts = SQRT(ta * ta + tc * tc);
 			float ts = SQRT(ta * ta + tc * tc);
-			float s = bs > 0.00001f ? (bs + (ts - bs + self->data->offsetScaleX) * scaleMix) / bs : 0;
+			if (s > 0.00001f) s = (s + (ts - s + self->data->offsetScaleX) * scaleMix) / s;
 			CONST_CAST(float, bone->a) *= s;
 			CONST_CAST(float, bone->a) *= s;
 			CONST_CAST(float, bone->c) *= s;
 			CONST_CAST(float, bone->c) *= s;
-			bs = SQRT(bone->b * bone->b + bone->d * bone->d);
+			s = SQRT(bone->b * bone->b + bone->d * bone->d);
 			ts = SQRT(tb * tb + td * td);
 			ts = SQRT(tb * tb + td * td);
-			s = bs > 0.00001f ? (bs + (ts - bs + self->data->offsetScaleY) * scaleMix) / bs : 0;
+			if (s > 0.00001f) s = (s + (ts - s + self->data->offsetScaleY) * scaleMix) / s;
 			CONST_CAST(float, bone->b) *= s;
 			CONST_CAST(float, bone->b) *= s;
 			CONST_CAST(float, bone->d) *= s;
 			CONST_CAST(float, bone->d) *= s;
+			modified = 1;
 		}
 		}
 
 
 		if (shearMix > 0) {
 		if (shearMix > 0) {
@@ -106,6 +111,9 @@ void spTransformConstraint_apply (spTransformConstraint* self) {
 			r = by + (r + self->data->offsetShearY * DEG_RAD) * shearMix;
 			r = by + (r + self->data->offsetShearY * DEG_RAD) * shearMix;
 			CONST_CAST(float, bone->b) = COS(r) * s;
 			CONST_CAST(float, bone->b) = COS(r) * s;
 			CONST_CAST(float, bone->d) = SIN(r) * s;
 			CONST_CAST(float, bone->d) = SIN(r) * s;
+			modified = 1;
 		}
 		}
+
+		if (modified) CONST_CAST(int, bone->appliedValid) = 0;
 	}
 	}
 }
 }

+ 5 - 7
spine-c/src/spine/VertexAttachment.c

@@ -43,7 +43,6 @@ void spVertexAttachment_computeWorldVertices (spVertexAttachment* self, spSlot*
 
 
 void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int start, int count, spSlot* slot, float* worldVertices, int offset) {
 void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int start, int count, spSlot* slot, float* worldVertices, int offset) {
 	spSkeleton* skeleton;
 	spSkeleton* skeleton;
-	float x, y;
 	int deformLength;
 	int deformLength;
 	float* deform;
 	float* deform;
 	float* vertices;
 	float* vertices;
@@ -51,8 +50,6 @@ void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int sta
 
 
 	count += offset;
 	count += offset;
 	skeleton = slot->bone->skeleton;
 	skeleton = slot->bone->skeleton;
-	x = skeleton->x;
-	y = skeleton->y;
 	deformLength = slot->attachmentVerticesCount;
 	deformLength = slot->attachmentVerticesCount;
 	deform = slot->attachmentVertices;
 	deform = slot->attachmentVertices;
 	vertices = self->vertices;
 	vertices = self->vertices;
@@ -60,10 +57,11 @@ void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int sta
 	if (!bones) {
 	if (!bones) {
 		spBone* bone;
 		spBone* bone;
 		int v, w;
 		int v, w;
+		float x, y;
 		if (deformLength > 0) vertices = deform;
 		if (deformLength > 0) vertices = deform;
 		bone = slot->bone;
 		bone = slot->bone;
-		x += bone->worldX;
-		y += bone->worldY;
+		x = bone->worldX;
+		y = bone->worldY;
 		for (v = start, w = offset; w < count; v += 2, w += 2) {
 		for (v = start, w = offset; w < count; v += 2, w += 2) {
 			float vx = vertices[v], vy = vertices[v + 1];
 			float vx = vertices[v], vy = vertices[v + 1];
 			worldVertices[w] = vx * bone->a + vy * bone->b + x;
 			worldVertices[w] = vx * bone->a + vy * bone->b + x;
@@ -81,7 +79,7 @@ void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int sta
 		if (deformLength == 0) {
 		if (deformLength == 0) {
 			int w, b;
 			int w, b;
 			for (w = offset, b = skip * 3; w < count; w += 2) {
 			for (w = offset, b = skip * 3; w < count; w += 2) {
-				float wx = x, wy = y;
+				float wx = 0, wy = 0;
 				int n = bones[v++];
 				int n = bones[v++];
 				n += v;
 				n += v;
 				for (; v < n; v++, b += 3) {
 				for (; v < n; v++, b += 3) {
@@ -96,7 +94,7 @@ void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int sta
 		} else {
 		} else {
 			int w, b, f;
 			int w, b, f;
 			for (w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) {
 			for (w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) {
-				float wx = x, wy = y;
+				float wx = 0, wy = 0;
 				int n = bones[v++];
 				int n = bones[v++];
 				n += v;
 				n += v;
 				for (; v < n; v++, b += 3, f += 2) {
 				for (; v < n; v++, b += 3, f += 2) {

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

@@ -294,7 +294,7 @@ void stretchyman (SkeletonData* skeletonData, Atlas* atlas) {
 	skeleton->flipX = false;
 	skeleton->flipX = false;
 	skeleton->flipY = false;
 	skeleton->flipY = false;
 
 
-	skeleton->x = 320;
+	skeleton->x = 100;
 	skeleton->y = 590;
 	skeleton->y = 590;
 	Skeleton_updateWorldTransform(skeleton);
 	Skeleton_updateWorldTransform(skeleton);
 
 
@@ -353,6 +353,6 @@ int main () {
 	testcase(raptor, "data/raptor.json", "data/raptor.skel", "data/raptor.atlas", 0.5f);
 	testcase(raptor, "data/raptor.json", "data/raptor.skel", "data/raptor.atlas", 0.5f);
 	testcase(spineboy, "data/spineboy.json", "data/spineboy.skel", "data/spineboy.atlas", 0.6f);
 	testcase(spineboy, "data/spineboy.json", "data/spineboy.skel", "data/spineboy.atlas", 0.6f);
 	testcase(goblins, "data/goblins-mesh.json", "data/goblins-mesh.skel", "data/goblins.atlas", 1.4f);
 	testcase(goblins, "data/goblins-mesh.json", "data/goblins-mesh.skel", "data/goblins.atlas", 1.4f);
-	testcase(stretchyman, "data/stretchyman.json", "data/stretchyman.skel", "data/stretchyman.atlas", 1.4f);
+	testcase(stretchyman, "data/stretchyman.json", "data/stretchyman.skel", "data/stretchyman.atlas", 0.6f);
 	return 0;
 	return 0;
 }
 }