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

Updated spine-c and spine-sfml to Spine v3.

NathanSweet 9 жил өмнө
parent
commit
d7d08d263a

+ 6 - 6
spine-c/.cproject

@@ -5,13 +5,13 @@
 			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.exe.debug.784427509" moduleId="org.eclipse.cdt.core.settings" name="Debug">
 				<externalSettings/>
 				<extensions>
+					<extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
 					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
 					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
 				</extensions>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
-				<configuration artifactExtension="a" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.staticLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.staticLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.exe.debug.784427509" name="Debug" parent="cdt.managedbuild.config.gnu.mingw.exe.debug">
+				<configuration artifactExtension="a" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.staticLib" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.staticLib,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.exe.debug.784427509" name="Debug" parent="cdt.managedbuild.config.gnu.mingw.exe.debug">
 					<folderInfo id="cdt.managedbuild.config.gnu.mingw.exe.debug.784427509." name="/" resourcePath="">
 						<toolChain id="cdt.managedbuild.toolchain.gnu.mingw.exe.debug.1244859277" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.exe.debug">
 							<targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.exe.debug.2141344127" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.exe.debug"/>
@@ -69,14 +69,14 @@
 			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.exe.release.486571591" moduleId="org.eclipse.cdt.core.settings" name="Release">
 				<externalSettings/>
 				<extensions>
+					<extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
 					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
 					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
 					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/>
 				</extensions>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
-				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.exe.release.486571591" name="Release" parent="cdt.managedbuild.config.gnu.mingw.exe.release">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.exe.release.486571591" name="Release" parent="cdt.managedbuild.config.gnu.mingw.exe.release">
 					<folderInfo id="cdt.managedbuild.config.gnu.mingw.exe.release.486571591." name="/" resourcePath="">
 						<toolChain id="cdt.managedbuild.toolchain.gnu.mingw.exe.release.547801112" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.exe.release">
 							<targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.exe.release.1049429369" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.exe.release"/>
@@ -117,10 +117,10 @@
 	</storageModule>
 	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
 	<storageModule moduleId="refreshScope" versionNumber="2">
-		<configuration configurationName="Release">
+		<configuration configurationName="Debug">
 			<resource resourceType="PROJECT" workspacePath="/spine-ctest"/>
 		</configuration>
-		<configuration configurationName="Debug">
+		<configuration configurationName="Release">
 			<resource resourceType="PROJECT" workspacePath="/spine-ctest"/>
 		</configuration>
 	</storageModule>

+ 1 - 33
spine-c/include/spine/Animation.h

@@ -94,9 +94,7 @@ typedef enum {
 	SP_TIMELINE_EVENT,
 	SP_TIMELINE_DRAWORDER,
 	SP_TIMELINE_FFD,
-	SP_TIMELINE_IKCONSTRAINT,
-	SP_TIMELINE_FLIPX,
-	SP_TIMELINE_FLIPY
+	SP_TIMELINE_IKCONSTRAINT
 } spTimelineType;
 
 struct spTimeline {
@@ -400,36 +398,6 @@ typedef spIkConstraintTimeline IkConstraintTimeline;
 
 /**/
 
-typedef struct spFlipTimeline {
-	spTimeline super;
-	int const x;
-	int const framesCount;
-	float* const frames; /* time, flip, ... */
-	int boneIndex;
-
-#ifdef __cplusplus
-	spFlipTimeline() :
-		super(),
-		x(0),
-		framesCount(0),
-		frames(0),
-		boneIndex(0) {
-	}
-#endif
-} spFlipTimeline;
-
-spFlipTimeline* spFlipTimeline_create (int framesCount, int/*bool*/x);
-
-void spFlipTimeline_setFrame (spFlipTimeline* self, int frameIndex, float time, int/*bool*/flip);
-
-#ifdef SPINE_SHORT_NAMES
-typedef spFlipTimeline FlipTimeline;
-#define FlipTimeline_create(...) spFlipTimeline_create(__VA_ARGS__)
-#define FlipTimeline_setFrame(...) spFlipTimeline_setFrame(__VA_ARGS__)
-#endif
-
-/**/
-
 #ifdef __cplusplus
 }
 #endif

+ 2 - 2
spine-c/include/spine/Attachment.h

@@ -37,7 +37,7 @@ extern "C" {
 #endif
 
 typedef enum {
-	SP_ATTACHMENT_REGION, SP_ATTACHMENT_BOUNDING_BOX, SP_ATTACHMENT_MESH, SP_ATTACHMENT_SKINNED_MESH
+	SP_ATTACHMENT_REGION, SP_ATTACHMENT_BOUNDING_BOX, SP_ATTACHMENT_MESH, SP_ATTACHMENT_WEIGHTED_MESH
 } spAttachmentType;
 
 typedef struct spAttachment {
@@ -61,7 +61,7 @@ typedef spAttachmentType AttachmentType;
 #define ATTACHMENT_REGION SP_ATTACHMENT_REGION
 #define ATTACHMENT_BOUNDING_BOX SP_ATTACHMENT_BOUNDING_BOX
 #define ATTACHMENT_MESH SP_ATTACHMENT_MESH
-#define ATTACHMENT_SKINNED_MESH SP_ATTACHMENT_SKINNED_MESH
+#define ATTACHMENT_WEIGHTED_MESH SP_ATTACHMENT_WEIGHTED_MESH
 typedef spAttachment Attachment;
 #define Attachment_dispose(...) spAttachment_dispose(__VA_ARGS__)
 #endif

+ 22 - 19
spine-c/include/spine/Bone.h

@@ -45,32 +45,24 @@ struct spBone {
 	spBoneData* const data;
 	struct spSkeleton* const skeleton;
 	spBone* const parent;
-	float x, y;
-	float rotation, rotationIK;
-	float scaleX, scaleY;
-	int/*bool*/flipX, flipY;
+	float x, y, rotation, scaleX, scaleY;
+	float appliedRotation, appliedScaleX, appliedScaleY;
 
-	float const m00, m01, worldX; /* a b x */
-	float const m10, m11, worldY; /* c d y */
-	float const worldRotation;
-	float const worldScaleX, worldScaleY;
-	int/*bool*/const worldFlipX, worldFlipY;
+	float const a, b, worldX;
+	float const c, d, worldY;
+	float const worldSignX, worldSignY;
 
 #ifdef __cplusplus
 	spBone() :
 		data(0),
 		skeleton(0),
 		parent(0),
-		x(0), y(0),
-		rotation(0), rotationIK(0),
-		scaleX(0), scaleY(0),
-		flipX(0), flipY(0),
-
-		m00(0), m01(0), worldX(0),
-		m10(0), m11(0), worldY(0),
-		worldRotation(0),
-		worldScaleX(0), worldScaleY(0),
-		worldFlipX(0), worldFlipY(0) {
+		x(0), y(0), rotation(0), scaleX(0), scaleY(0),
+		appliedRotation(0), appliedScaleX(0), appliedScaleY(0),
+
+		a(0), b(0), worldX(0),
+		c(0), d(0), worldY(0),
+		worldSignX(0), worldSignY(0) {
 	}
 #endif
 };
@@ -85,6 +77,12 @@ void spBone_dispose (spBone* self);
 void spBone_setToSetupPose (spBone* self);
 
 void spBone_updateWorldTransform (spBone* self);
+void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY);
+
+float spBone_getWorldRotationX (spBone* self);
+float spBone_getWorldRotationY (spBone* self);
+float spBone_getWorldScaleX (spBone* self);
+float spBone_getWorldScaleY (spBone* self);
 
 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);
@@ -97,6 +95,11 @@ typedef spBone Bone;
 #define Bone_dispose(...) spBone_dispose(__VA_ARGS__)
 #define Bone_setToSetupPose(...) spBone_setToSetupPose(__VA_ARGS__)
 #define Bone_updateWorldTransform(...) spBone_updateWorldTransform(__VA_ARGS__)
+#define Bone_updateWorldTransformWith(...) spBone_updateWorldTransformWith(__VA_ARGS__)
+#define Bone_getWorldRotationX(...) spBone_getWorldRotationX(__VA_ARGS__)
+#define Bone_getWorldRotationY(...) spBone_getWorldRotationY(__VA_ARGS__)
+#define Bone_getWorldScaleX(...) spBone_getWorldScaleX(__VA_ARGS__)
+#define Bone_getWorldScaleY(...) spBone_getWorldScaleY(__VA_ARGS__)
 #define Bone_worldToLocal(...) spBone_worldToLocal(__VA_ARGS__)
 #define Bone_localToWorld(...) spBone_localToWorld(__VA_ARGS__)
 #endif

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

@@ -44,7 +44,6 @@ struct spBoneData {
 	float x, y;
 	float rotation;
 	float scaleX, scaleY;
-	int/*bool*/flipX, flipY;
 	int/*bool*/inheritScale, inheritRotation;
 
 #ifdef __cplusplus
@@ -55,7 +54,6 @@ struct spBoneData {
 		x(0), y(0),
 		rotation(0),
 		scaleX(0), scaleY(0),
-		flipX(0), flipY(0),
 		inheritScale(0), inheritRotation(0) {
 	}
 #endif

+ 3 - 1
spine-c/include/spine/Event.h

@@ -40,6 +40,7 @@ extern "C" {
 
 typedef struct spEvent {
 	spEventData* const data;
+	float const time;
 	int intValue;
 	float floatValue;
 	const char* stringValue;
@@ -47,6 +48,7 @@ typedef struct spEvent {
 #ifdef __cplusplus
 	spEvent() :
 		data(0),
+		time(0),
 		intValue(0),
 		floatValue(0),
 		stringValue(0) {
@@ -54,7 +56,7 @@ typedef struct spEvent {
 #endif
 } spEvent;
 
-spEvent* spEvent_create (spEventData* data);
+spEvent* spEvent_create (float time, spEventData* data);
 void spEvent_dispose (spEvent* self);
 
 #ifdef SPINE_SHORT_NAMES

+ 3 - 0
spine-c/include/spine/IkConstraint.h

@@ -75,6 +75,9 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
 typedef spIkConstraint IkConstraint;
 #define IkConstraint_create(...) spIkConstraint_create(__VA_ARGS__)
 #define IkConstraint_dispose(...) spIkConstraint_dispose(__VA_ARGS__)
+#define IkConstraint_apply(...) spIkConstraint_apply(__VA_ARGS__)
+#define IkConstraint_apply1(...) spIkConstraint_apply1(__VA_ARGS__)
+#define IkConstraint_apply2(...) spIkConstraint_apply2(__VA_ARGS__)
 #endif
 
 #ifdef __cplusplus

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

@@ -36,6 +36,7 @@
 #include <spine/Slot.h>
 #include <spine/Skin.h>
 #include <spine/IkConstraint.h>
+#include <spine/TransformConstraint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -55,6 +56,9 @@ typedef struct spSkeleton {
 	int ikConstraintsCount;
 	spIkConstraint** ikConstraints;
 
+	int transformConstraintsCount;
+	spTransformConstraint** transformConstraints;
+
 	spSkin* const skin;
 	float r, g, b, a;
 	float time;
@@ -74,6 +78,9 @@ typedef struct spSkeleton {
 		ikConstraintsCount(0),
 		ikConstraints(0),
 
+		transformConstraintsCount(0),
+		transformConstraints(0),
+
 		skin(0),
 		r(0), g(0), b(0), a(0),
 		time(0),
@@ -87,11 +94,13 @@ typedef struct spSkeleton {
 spSkeleton* spSkeleton_create (spSkeletonData* data);
 void spSkeleton_dispose (spSkeleton* self);
 
-/* Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */
+/* Caches information about bones and constraints. Must be called if bones or constraints are added or removed. */
 void spSkeleton_updateCache (const spSkeleton* self);
 void spSkeleton_updateWorldTransform (const spSkeleton* self);
 
+/* Sets the bones, constraints, and slots to their setup pose values. */
 void spSkeleton_setToSetupPose (const spSkeleton* self);
+/* Sets the bones and constraints to their setup pose values. */
 void spSkeleton_setBonesToSetupPose (const spSkeleton* self);
 void spSkeleton_setSlotsToSetupPose (const spSkeleton* self);
 
@@ -123,7 +132,10 @@ spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int
 int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName);
 
 /* Returns 0 if the IK constraint was not found. */
-spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* ikConstraintName);
+spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* constraintName);
+
+/* Returns 0 if the transform constraint was not found. */
+spTransformConstraint* spSkeleton_findTransformConstraint (const spSkeleton* self, const char* constraintName);
 
 void spSkeleton_update (spSkeleton* self, float deltaTime);
 

+ 7 - 1
spine-c/include/spine/SkeletonData.h

@@ -38,6 +38,7 @@
 #include <spine/EventData.h>
 #include <spine/Animation.h>
 #include <spine/IkConstraintData.h>
+#include <spine/TransformConstraintData.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -66,6 +67,9 @@ typedef struct spSkeletonData {
 
 	int ikConstraintsCount;
 	spIkConstraintData** ikConstraints;
+
+	int transformConstraintsCount;
+	spTransformConstraintData** transformConstraints;
 } spSkeletonData;
 
 spSkeletonData* spSkeletonData_create ();
@@ -83,7 +87,9 @@ spEventData* spSkeletonData_findEvent (const spSkeletonData* self, const char* e
 
 spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const char* animationName);
 
-spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* ikConstraintName);
+spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* constraintName);
+
+spTransformConstraintData* spSkeletonData_findTransformConstraint (const spSkeletonData* self, const char* constraintName);
 
 #ifdef SPINE_SHORT_NAMES
 typedef spSkeletonData SkeletonData;

+ 79 - 0
spine-c/include/spine/TransformConstraint.h

@@ -0,0 +1,79 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ * 
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ * 
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef SPINE_TRANSFORMCONSTRAINT_H_
+#define SPINE_TRANSFORMCONSTRAINT_H_
+
+#include <spine/TransformConstraintData.h>
+#include <spine/Bone.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spSkeleton;
+
+typedef struct spTransformConstraint {
+	spTransformConstraintData* const data;
+	spBone* bone;
+	spBone* target;
+	float translateMix;
+	float x, y;
+
+#ifdef __cplusplus
+	spTransformConstraint() :
+		data(0),
+		bone(0),
+		target(0),
+		translateMix(0),
+		x(0),
+		y(0) {
+	}
+#endif
+} spTransformConstraint;
+
+spTransformConstraint* spTransformConstraint_create (spTransformConstraintData* data, const struct spSkeleton* skeleton);
+void spTransformConstraint_dispose (spTransformConstraint* self);
+
+void spTransformConstraint_apply (spTransformConstraint* self);
+
+#ifdef SPINE_SHORT_NAMES
+typedef spTransformConstraint TransformConstraint;
+#define TransformConstraint_create(...) spTransformConstraint_create(__VA_ARGS__)
+#define TransformConstraint_dispose(...) spTransformConstraint_dispose(__VA_ARGS__)
+#define TransformConstraint_apply(...) spTransformConstraint_apply(__VA_ARGS__)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPINE_TRANSFORMCONSTRAINT_H_ */

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

@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ * 
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ * 
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef SPINE_TRANSFORMCONSTRAINTDATA_H_
+#define SPINE_TRANSFORMCONSTRAINTDATA_H_
+
+#include <spine/BoneData.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct spTransformConstraintData {
+	const char* const name;
+
+	spBoneData* bone;
+	spBoneData* target;
+	float translateMix;
+	float x, y;
+
+#ifdef __cplusplus
+	spTransformConstraintData() :
+		name(0),
+		bone(0),
+		target(0),
+		translateMix(0),
+		x(0),
+		y(0) {
+	}
+#endif
+} spTransformConstraintData;
+
+spTransformConstraintData* spTransformConstraintData_create (const char* name);
+void spTransformConstraintData_dispose (spTransformConstraintData* self);
+
+#ifdef SPINE_SHORT_NAMES
+typedef spTransformConstraintData TransformConstraintData;
+#define TransformConstraintData_create(...) spTransformConstraintData_create(__VA_ARGS__)
+#define TransformConstraintData_dispose(...) spTransformConstraintData_dispose(__VA_ARGS__)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPINE_TRANSFORMCONSTRAINTDATA_H_ */

+ 12 - 12
spine-c/include/spine/SkinnedMeshAttachment.h → spine-c/include/spine/WeightedMeshAttachment.h

@@ -29,8 +29,8 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
-#ifndef SPINE_SKINNEDMESHATTACHMENT_H_
-#define SPINE_SKINNEDMESHATTACHMENT_H_
+#ifndef SPINE_WEIGHTEDMESHATTACHMENT_H_
+#define SPINE_WEIGHTEDMESHATTACHMENT_H_
 
 #include <spine/Attachment.h>
 #include <spine/Slot.h>
@@ -39,7 +39,7 @@
 extern "C" {
 #endif
 
-typedef struct spSkinnedMeshAttachment {
+typedef struct spWeightedMeshAttachment {
 	spAttachment super;
 	const char* path;
 
@@ -70,21 +70,21 @@ typedef struct spSkinnedMeshAttachment {
 	int edgesCount;
 	int* edges;
 	float width, height;
-} spSkinnedMeshAttachment;
+} spWeightedMeshAttachment;
 
-spSkinnedMeshAttachment* spSkinnedMeshAttachment_create (const char* name);
-void spSkinnedMeshAttachment_updateUVs (spSkinnedMeshAttachment* self);
-void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self, spSlot* slot, float* worldVertices);
+spWeightedMeshAttachment* spWeightedMeshAttachment_create (const char* name);
+void spWeightedMeshAttachment_updateUVs (spWeightedMeshAttachment* self);
+void spWeightedMeshAttachment_computeWorldVertices (spWeightedMeshAttachment* self, spSlot* slot, float* worldVertices);
 
 #ifdef SPINE_SHORT_NAMES
-typedef spSkinnedMeshAttachment SkinnedMeshAttachment;
-#define SkinnedMeshAttachment_create(...) spSkinnedMeshAttachment_create(__VA_ARGS__)
-#define SkinnedMeshAttachment_updateUVs(...) spSkinnedMeshAttachment_updateUVs(__VA_ARGS__)
-#define SkinnedMeshAttachment_computeWorldVertices(...) spSkinnedMeshAttachment_computeWorldVertices(__VA_ARGS__)
+typedef spWeightedMeshAttachment WeightedMeshAttachment;
+#define WeightedMeshAttachment_create(...) spWeightedMeshAttachment_create(__VA_ARGS__)
+#define WeightedMeshAttachment_updateUVs(...) spWeightedMeshAttachment_updateUVs(__VA_ARGS__)
+#define WeightedMeshAttachment_computeWorldVertices(...) spWeightedMeshAttachment_computeWorldVertices(__VA_ARGS__)
 #endif
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* SPINE_SKINNEDMESHATTACHMENT_H_ */
+#endif /* SPINE_WEIGHTEDMESHATTACHMENT_H_ */

+ 3 - 1
spine-c/include/spine/extension.h

@@ -68,6 +68,7 @@
 #define COS(A) cosf(A)
 #define SQRT(A) sqrtf(A)
 #define ACOS(A) acosf(A)
+#define ABS(A) fabsf(A)
 #else
 #define FMOD(A,B) (float)fmod(A, B)
 #define ATAN2(A,B) (float)atan2(A, B)
@@ -75,6 +76,7 @@
 #define SIN(A) (float)sin(A)
 #define SQRT(A) (float)sqrt(A)
 #define ACOS(A) (float)acos(A)
+#define ABS(A) ((A) < 0 ? -(A) : (A))
 #endif
 
 #include <stdlib.h>
@@ -86,7 +88,7 @@
 #include <spine/AttachmentLoader.h>
 #include <spine/RegionAttachment.h>
 #include <spine/MeshAttachment.h>
-#include <spine/SkinnedMeshAttachment.h>
+#include <spine/WeightedMeshAttachment.h>
 #include <spine/BoundingBoxAttachment.h>
 #include <spine/AnimationState.h>
 

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

@@ -43,7 +43,7 @@
 #include <spine/BoneData.h>
 #include <spine/RegionAttachment.h>
 #include <spine/MeshAttachment.h>
-#include <spine/SkinnedMeshAttachment.h>
+#include <spine/WeightedMeshAttachment.h>
 #include <spine/BoundingBoxAttachment.h>
 #include <spine/Skeleton.h>
 #include <spine/SkeletonBounds.h>

+ 0 - 45
spine-c/src/spine/Animation.c

@@ -789,48 +789,3 @@ void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameInd
 }
 
 /**/
-
-void _spFlipTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
-		spEvent** firedEvents, int* eventsCount, float alpha) {
-	int frameIndex;
-	spFlipTimeline* self = (spFlipTimeline*)timeline;
-
-	if (time < self->frames[0]) {
-		if (lastTime > time) _spFlipTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, 0, 0, 0);
-		return;
-	} else if (lastTime > time) /**/
-		lastTime = -1;
-
-	frameIndex = (time >= self->frames[self->framesCount - 2] ?
-		self->framesCount : binarySearch(self->frames, self->framesCount, time, 2)) - 2;
-	if (self->frames[frameIndex] < lastTime) return;
-
-	if (self->x)
-		skeleton->bones[self->boneIndex]->flipX = (int)self->frames[frameIndex + 1];
-	else
-		skeleton->bones[self->boneIndex]->flipY = (int)self->frames[frameIndex + 1];
-}
-
-void _spFlipTimeline_dispose (spTimeline* timeline) {
-	spFlipTimeline* self = SUB_CAST(spFlipTimeline, timeline);
-	_spTimeline_deinit(SUPER(self));
-	FREE(self->frames);
-	FREE(self);
-}
-
-spFlipTimeline* spFlipTimeline_create (int framesCount, int/*bool*/x) {
-	spFlipTimeline* self = NEW(spFlipTimeline);
-	_spTimeline_init(SUPER(self), x ? SP_TIMELINE_FLIPX : SP_TIMELINE_FLIPY, _spFlipTimeline_dispose, _spFlipTimeline_apply);
-	CONST_CAST(int, self->x) = x;
-	CONST_CAST(int, self->framesCount) = framesCount << 1;
-	CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount);
-	return self;
-}
-
-void spFlipTimeline_setFrame (spFlipTimeline* self, int frameIndex, float time, int/*bool*/flip) {
-	frameIndex <<= 1;
-	self->frames[frameIndex] = time;
-	self->frames[frameIndex + 1] = (float)flip;
-}
-
-/**/

+ 3 - 3
spine-c/src/spine/AtlasAttachmentLoader.c

@@ -76,14 +76,14 @@ spAttachment* _spAtlasAttachmentLoader_newAttachment (spAttachmentLoader* loader
 		attachment->regionOriginalHeight = region->originalHeight;
 		return SUPER(attachment);
 	}
-	case SP_ATTACHMENT_SKINNED_MESH: {
-		spSkinnedMeshAttachment* attachment;
+	case SP_ATTACHMENT_WEIGHTED_MESH: {
+		spWeightedMeshAttachment* attachment;
 		spAtlasRegion* region = spAtlas_findRegion(self->atlas, path);
 		if (!region) {
 			_spAttachmentLoader_setError(loader, "Region not found: ", path);
 			return 0;
 		}
-		attachment = spSkinnedMeshAttachment_create(name);
+		attachment = spWeightedMeshAttachment_create(name);
 		attachment->rendererObject = region;
 		attachment->regionU = region->u;
 		attachment->regionV = region->v;

+ 152 - 53
spine-c/src/spine/Bone.c

@@ -56,47 +56,137 @@ void spBone_dispose (spBone* self) {
 }
 
 void spBone_updateWorldTransform (spBone* self) {
-	float radians, cosine, sine;
-	if (self->parent) {
-		CONST_CAST(float, self->worldX) = self->x * self->parent->m00 + self->y * self->parent->m01 + self->parent->worldX;
-		CONST_CAST(float, self->worldY) = self->x * self->parent->m10 + self->y * self->parent->m11 + self->parent->worldY;
-		if (self->data->inheritScale) {
-			CONST_CAST(float, self->worldScaleX) = self->parent->worldScaleX * self->scaleX;
-			CONST_CAST(float, self->worldScaleY) = self->parent->worldScaleY * self->scaleY;
-		} else {
-			CONST_CAST(float, self->worldScaleX) = self->scaleX;
-			CONST_CAST(float, self->worldScaleY) = self->scaleY;
+	spBone_updateWorldTransformWith(self, self->x, self->y, self->rotation, self->scaleX, self->scaleY);
+}
+
+void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY) {
+	float radians = rotation * DEG_RAD;
+	float cosine = COS(radians);
+	float sine = SIN(radians);
+	float la = cosine * scaleX, lb = -sine * scaleY, lc = sine * scaleX, ld = cosine * scaleY;
+	float pa, pb, pc, pd;
+	spBone* parent = self->parent;
+
+	CONST_CAST(float, self->appliedRotation) = rotation;
+	CONST_CAST(float, self->appliedScaleX) = scaleX;
+	CONST_CAST(float, self->appliedScaleY) = scaleY;
+
+	if (!parent) { /* Root bone. */
+		if (self->skeleton->flipX) {
+			x = -x;
+			la = -la;
+			lb = -lb;
 		}
-		CONST_CAST(float, self->worldRotation) =
-				self->data->inheritRotation ? self->parent->worldRotation + self->rotationIK : self->rotationIK;
-		CONST_CAST(int, self->worldFlipX) = self->parent->worldFlipX ^ self->flipX;
-		CONST_CAST(int, self->worldFlipY) = self->parent->worldFlipY ^ self->flipY;
-	} else {
-		int skeletonFlipX = self->skeleton->flipX, skeletonFlipY = self->skeleton->flipY;
-		CONST_CAST(float, self->worldX) = self->skeleton->flipX ? -self->x : self->x;
-		CONST_CAST(float, self->worldY) = self->skeleton->flipY != yDown ? -self->y : self->y;
-		CONST_CAST(float, self->worldScaleX) = self->scaleX;
-		CONST_CAST(float, self->worldScaleY) = self->scaleY;
-		CONST_CAST(float, self->worldRotation) = self->rotationIK;
-		CONST_CAST(int, self->worldFlipX) = skeletonFlipX ^ self->flipX;
-		CONST_CAST(int, self->worldFlipY) = skeletonFlipY ^ self->flipY;
-	}
-	radians = self->worldRotation * DEG_RAD;
-	cosine = COS(radians);
-	sine = SIN(radians);
-	if (self->worldFlipX) {
-		CONST_CAST(float, self->m00) = -cosine * self->worldScaleX;
-		CONST_CAST(float, self->m01) = sine * self->worldScaleY;
-	} else {
-		CONST_CAST(float, self->m00) = cosine * self->worldScaleX;
-		CONST_CAST(float, self->m01) = -sine * self->worldScaleY;
+		if (self->skeleton->flipY != yDown) {
+			y = -y;
+			lc = -lc;
+			ld = -ld;
+		}
+		CONST_CAST(float, self->a) = la;
+		CONST_CAST(float, self->b) = lb;
+		CONST_CAST(float, self->c) = lc;
+		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 : -1;
+		CONST_CAST(float, self->worldSignY) = scaleY > 0 ? 1 : -1;
+		return;
 	}
-	if (self->worldFlipY != yDown) {
-		CONST_CAST(float, self->m10) = -sine * self->worldScaleX;
-		CONST_CAST(float, self->m11) = -cosine * self->worldScaleY;
+
+	pa = parent->a;
+	pb = parent->b;
+	pc = parent->c;
+	pd = parent->d;
+
+	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->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. */
+		spBone* p = parent;
+		pa = 1;
+		pb = 0;
+		pc = 0;
+		pd = 1;
+		while (p) {
+			cosine = COS(p->appliedRotation * DEG_RAD);
+			sine = SIN(p->appliedRotation * DEG_RAD);
+			float a = pa * cosine + pb * sine;
+			float b = pa * -sine + pb * cosine;
+			float c = pc * cosine + pd * sine;
+			float d = pc * -sine + pd * cosine;
+			pa = a;
+			pb = b;
+			pc = c;
+			pd = d;
+			p = p->parent;
+		}
+		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;
+		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;
+		}
+	} else if (self->data->inheritScale) { /* No rotation inheritance. */
+		spBone* p = parent;
+		pa = 1;
+		pb = 0;
+		pc = 0;
+		pd = 1;
+		while (p) {
+			float r = p->rotation;
+			cosine = COS(r * DEG_RAD);
+			sine = SIN(r * DEG_RAD);
+			float psx = p->appliedScaleX, psy = p->appliedScaleY;
+			float za = cosine * psx, zb = -sine * psy, zc = sine * psx, zd = cosine * psy;
+			float temp = pa * za + pb * zc;
+			pb = pa * zb + pb * zd;
+			pa = temp;
+			temp = pc * za + pd * zc;
+			pd = pc * zb + pd * zd;
+			pc = temp;
+
+			if (psx < 0) r = -r;
+			cosine = COS(-r * DEG_RAD);
+			sine = SIN(-r * DEG_RAD);
+			temp = pa * cosine + pb * sine;
+			pb = pa * -sine + pb * cosine;
+			pa = temp;
+			temp = pc * cosine + pd * sine;
+			pd = pc * -sine + pd * cosine;
+			pc = temp;
+
+			p = p->parent;
+		}
+		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;
+		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;
+		}
 	} else {
-		CONST_CAST(float, self->m10) = sine * self->worldScaleX;
-		CONST_CAST(float, self->m11) = cosine * self->worldScaleY;
+		CONST_CAST(float, self->a) = la;
+		CONST_CAST(float, self->b) = lb;
+		CONST_CAST(float, self->c) = lc;
+		CONST_CAST(float, self->d) = ld;
 	}
 }
 
@@ -104,27 +194,36 @@ void spBone_setToSetupPose (spBone* self) {
 	self->x = self->data->x;
 	self->y = self->data->y;
 	self->rotation = self->data->rotation;
-	self->rotationIK = self->rotation;
 	self->scaleX = self->data->scaleX;
 	self->scaleY = self->data->scaleY;
-	self->flipX = self->data->flipX;
-	self->flipY = self->data->flipY;
+}
+
+float spBone_getWorldRotationX (spBone* self) {
+	return ATAN2(self->c, self->a) * RAD_DEG;
+}
+
+float spBone_getWorldRotationY (spBone* self) {
+	return ATAN2(self->d, self->b) * RAD_DEG;
+}
+
+float spBone_getWorldScaleX (spBone* self) {
+	return SQRT(self->a * self->a + self->b * self->b) * self->worldSignX;
+}
+
+float spBone_getWorldScaleY (spBone* self) {
+	return SQRT(self->c * self->c + self->d * self->d) * self->worldSignY;
 }
 
 void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY) {
-	float invDet;
-	float dx = worldX - self->worldX, dy = worldY - self->worldY;
-	float m00 = self->m00, m11 = self->m11;
-	if (self->worldFlipX != (self->worldFlipY != yDown)) {
-		m00 *= -1;
-		m11 *= -1;
-	}
-	invDet = 1 / (m00 * m11 - self->m01 * self->m10);
-	*localX = (dx * m00 * invDet - dy * self->m01 * invDet);
-	*localY = (dy * m11 * invDet - dx * self->m10 * invDet);
+	float x = worldX - self->worldX, y = worldY - self->worldY;
+	float a = self->a, b = self->b, c = self->c, d = self->d;
+	float invDet = 1 / (a * d - b * c);
+	*localX = (x * a * invDet - y * b * invDet);
+	*localY = (y * d * invDet - x * c * invDet);
 }
 
 void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY) {
-	*worldX = localX * self->m00 + localY * self->m01 + self->worldX;
-	*worldY = localX * self->m10 + localY * self->m11 + self->worldY;
+	float x = localX, y = localY;
+	*worldX = x * self->a + y * self->b + self->worldX;
+	*worldY = x * self->c + y * self->d + self->worldY;
 }

+ 2 - 2
spine-c/src/spine/BoundingBoxAttachment.c

@@ -55,7 +55,7 @@ void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self
 	for (i = 0; i < self->verticesCount; i += 2) {
 		px = vertices[i];
 		py = vertices[i + 1];
-		worldVertices[i] = px * bone->m00 + py * bone->m01 + x;
-		worldVertices[i + 1] = px * bone->m10 + py * bone->m11 + y;
+		worldVertices[i] = px * bone->a + py * bone->b + x;
+		worldVertices[i + 1] = px * bone->c + py * bone->d + y;
 	}
 }

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

@@ -32,9 +32,10 @@
 #include <spine/Event.h>
 #include <spine/extension.h>
 
-spEvent* spEvent_create (spEventData* data) {
+spEvent* spEvent_create (float time, spEventData* data) {
 	spEvent* self = NEW(spEvent);
 	CONST_CAST(spEventData*, self->data) = data;
+	CONST_CAST(float, self->time) = time;
 	return self;
 }
 

+ 118 - 57
spine-c/src/spine/IkConstraint.c

@@ -68,69 +68,130 @@ void spIkConstraint_apply (spIkConstraint* self) {
 }
 
 void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha) {
-	float parentRotation = (!bone->data->inheritRotation || !bone->parent) ? 0 : bone->parent->worldRotation;
+	float parentRotation = !bone->parent ? 0 : spBone_getWorldRotationX(bone->parent);
 	float rotation = bone->rotation;
-	float rotationIK = ATAN2(targetY - bone->worldY, targetX - bone->worldX) * RAD_DEG;
-	if (bone->worldFlipX != (bone->worldFlipY != spBone_isYDown())) rotationIK = -rotationIK;
-	rotationIK -= parentRotation;
-	bone->rotationIK = rotation + (rotationIK - rotation) * alpha;
+	float rotationIK = ATAN2(targetY - bone->worldY, targetX - bone->worldX) * RAD_DEG - parentRotation;
+	if (bone->worldSignX != bone->worldSignY) rotationIK = 360 - rotationIK;
+	if (rotationIK > 180) rotationIK -= 360;
+	else if (rotationIK < -180) rotationIK += 360;
+	spBone_updateWorldTransformWith(bone, bone->x, bone->y, rotation + (rotationIK - rotation) * alpha, bone->scaleX, bone->scaleY);
 }
 
-void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, float alpha) {
-	float positionX, positionY, childX, childY, offset, len1, len2, cosDenom, cos, childAngle, adjacent, opposite, parentAngle, rotation;
-	spBone* parentParent;
-	float childRotation = child->rotation, parentRotation = parent->rotation;
-	if (alpha == 0) {
-		child->rotationIK = childRotation;
-		parent->rotationIK = parentRotation;
-		return;
-	}
-	parentParent = parent->parent;
-	if (parentParent) {
-		spBone_worldToLocal(parentParent, targetX, targetY, &positionX, &positionY);
-		targetX = (positionX - parent->x) * parentParent->worldScaleX;
-		targetY = (positionY - parent->y) * parentParent->worldScaleY;
+void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, float alpha) {
+	if (alpha == 0) return;
+	float px = parent->x, py = parent->y, psx = parent->scaleX, psy = parent->scaleY, csx = child->scaleX, cy = child->y;
+	int offset1, offset2, sign2;
+	if (psx < 0) {
+		psx = -psx;
+		offset1 = 180;
+		sign2 = -1;
 	} else {
-		targetX -= parent->x;
-		targetY -= parent->y;
+		offset1 = 0;
+		sign2 = 1;
+	}
+	if (psy < 0) {
+		psy = -psy;
+		sign2 = -sign2;
 	}
-	if (child->parent == parent) {
-		positionX = child->x;
-		positionY = child->y;
+	if (csx < 0) {
+		csx = -csx;
+		offset2 = 180;
+	} else
+		offset2 = 0;
+	spBone* pp = parent->parent;
+	float tx, ty, dx, dy;
+	if (!pp) {
+		tx = targetX - px;
+		ty = targetY - py;
+		dx = child->worldX - px;
+		dy = child->worldY - py;
 	} else {
-		spBone_localToWorld(child->parent, child->x, child->y, &positionX, &positionY);
-		spBone_worldToLocal(parent, positionX, positionY, &positionX, &positionY);
+		float a = pp->a, b = pp->b, c = pp->c, d = pp->d, invDet = 1 / (a * d - b * c);
+		float wx = pp->worldX, wy = pp->worldY, x = targetX - wx, y = targetY - wy;
+		tx = (x * d - y * b) * invDet - px;
+		ty = (y * a - x * c) * invDet - py;
+		x = child->worldX - wx;
+		y = child->worldY - wy;
+		dx = (x * d - y * b) * invDet - px;
+		dy = (y * a - x * c) * invDet - py;
 	}
-	childX = positionX * parent->worldScaleX;
-	childY = positionY * parent->worldScaleY;
-	offset = ATAN2(childY, childX);
-	len1 = SQRT(childX * childX + childY * childY);
-	len2 = child->data->length * child->worldScaleX;
-	/* Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/ */
-	cosDenom = 2 * len1 * len2;
-	if (cosDenom < 0.0001f) {
-		child->rotationIK = childRotation + (ATAN2(targetY, targetX) * RAD_DEG - parentRotation - childRotation) * alpha;
-		return;
+	float l1 = SQRT(dx * dx + dy * dy), l2 = child->data->length * csx, a1, a2;
+	if (ABS(psx - psy) <= 0.0001f) {
+		l2 *= psx;
+		float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2);
+		if (cos < -1) cos = -1;
+		else if (cos > 1) cos = 1;
+		a2 = ACOS(cos) * bendDir;
+		float a = l1 + l2 * cos, o = l2 * SIN(a2);
+		a1 = ATAN2(ty * a - tx * o, tx * a + ty * o);
+	} else {
+		cy = 0;
+		float a = psx * l2, b = psy * l2, ta = ATAN2(ty, tx);
+		float aa = a * a, bb = b * b, ll = l1 * l1, dd = tx * tx + ty * ty;
+		float c0 = bb * ll + aa * dd - aa * bb, c1 = -2 * bb * l1, c2 = bb - aa;
+		float d = c1 * c1 - 4 * c2 * c0;
+		if (d >= 0) {
+			float q = SQRT(d);
+			if (c1 < 0) q = -q;
+			q = -(c1 + q) / 2;
+			float r0 = q / c2, r1 = c0 / q;
+			float r = ABS(r0) < ABS(r1) ? r0 : r1;
+			if (r * r <= dd) {
+				float y1 = SQRT(dd - r * r) * bendDir;
+				a1 = ta - ATAN2(y1, r);
+				a2 = ATAN2(y1 / psy, (r - l1) / psx);
+				goto outer;
+			}
+		}
+		float minAngle = 0, minDist = 999999999, minX = 0, minY = 0;
+		float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0;
+		float x = l1 + a, dist = x * x;
+		if (dist > maxDist) {
+			maxAngle = 0;
+			maxDist = dist;
+			maxX = x;
+		}
+		x = l1 - a;
+		dist = x * x;
+		if (dist < minDist) {
+			minAngle = PI;
+			minDist = dist;
+			minX = x;
+		}
+		float angle = ACOS(-a * l1 / (aa - bb));
+		x = a * COS(angle) + l1;
+		float y = b * SIN(angle);
+		dist = x * x + y * y;
+		if (dist < minDist) {
+			minAngle = angle;
+			minDist = dist;
+			minX = x;
+			minY = y;
+		}
+		if (dist > maxDist) {
+			maxAngle = angle;
+			maxDist = dist;
+			maxX = x;
+			maxY = y;
+		}
+		if (dd <= (minDist + maxDist) / 2) {
+			a1 = ta - ATAN2(minY * bendDir, minX);
+			a2 = minAngle * bendDir;
+		} else {
+			a1 = ta - ATAN2(maxY * bendDir, maxX);
+			a2 = maxAngle * bendDir;
+		}
 	}
-	cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom;
-	if (cos < -1)
-		cos = -1;
-	else if (cos > 1) /**/
-		cos = 1;
-	childAngle = ACOS(cos) * bendDirection;
-	adjacent = len1 + len2 * cos;
-	opposite = len2 * SIN(childAngle);
-	parentAngle = ATAN2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite);
-	rotation = (parentAngle - offset) * RAD_DEG - parentRotation;
-	if (rotation > 180)
-		rotation -= 360;
-	else if (rotation < -180) /**/
-		rotation += 360;
-	parent->rotationIK = parentRotation + rotation * alpha;
-	rotation = (childAngle + offset) * RAD_DEG - childRotation;
-	if (rotation > 180)
-		rotation -= 360;
-	else if (rotation < -180) /**/
-		rotation += 360;
-	child->rotationIK = childRotation + (rotation + parent->worldRotation - child->parent->worldRotation) * alpha;
+outer: {}
+	float offset = ATAN2(cy, child->x) * sign2;
+	a1 = (a1 - offset) * RAD_DEG + offset1;
+	a2 = (a2 + offset) * RAD_DEG * sign2 + offset2;
+	if (a1 > 180) a1 -= 360;
+	else if (a1 < -180) a1 += 360;
+	if (a2 > 180) a2 -= 360;
+	else if (a2 < -180) a2 += 360;
+	float rotation = parent->rotation;
+	spBone_updateWorldTransformWith(parent, parent->x, parent->y, rotation + (a1 - rotation) * alpha, parent->scaleX, parent->scaleY);
+	rotation = child->rotation;
+	spBone_updateWorldTransformWith(child, child->x, cy, rotation + (a2 - rotation) * alpha, child->scaleX, child->scaleY);
 }

+ 2 - 2
spine-c/src/spine/MeshAttachment.c

@@ -80,7 +80,7 @@ void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot
 	if (slot->attachmentVerticesCount == self->verticesCount) vertices = slot->attachmentVertices;
 	for (i = 0; i < self->verticesCount; i += 2) {
 		const float vx = vertices[i], vy = vertices[i + 1];
-		worldVertices[i] = vx * bone->m00 + vy * bone->m01 + x;
-		worldVertices[i + 1] = vx * bone->m10 + vy * bone->m11 + y;
+		worldVertices[i] = vx * bone->a + vy * bone->b + x;
+		worldVertices[i + 1] = vx * bone->c + vy * bone->d + y;
 	}
 }

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

@@ -103,12 +103,12 @@ void spRegionAttachment_updateOffset (spRegionAttachment* self) {
 void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices) {
 	const float* offset = self->offset;
 	float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY;
-	vertices[SP_VERTEX_X1] = offset[SP_VERTEX_X1] * bone->m00 + offset[SP_VERTEX_Y1] * bone->m01 + x;
-	vertices[SP_VERTEX_Y1] = offset[SP_VERTEX_X1] * bone->m10 + offset[SP_VERTEX_Y1] * bone->m11 + y;
-	vertices[SP_VERTEX_X2] = offset[SP_VERTEX_X2] * bone->m00 + offset[SP_VERTEX_Y2] * bone->m01 + x;
-	vertices[SP_VERTEX_Y2] = offset[SP_VERTEX_X2] * bone->m10 + offset[SP_VERTEX_Y2] * bone->m11 + y;
-	vertices[SP_VERTEX_X3] = offset[SP_VERTEX_X3] * bone->m00 + offset[SP_VERTEX_Y3] * bone->m01 + x;
-	vertices[SP_VERTEX_Y3] = offset[SP_VERTEX_X3] * bone->m10 + offset[SP_VERTEX_Y3] * bone->m11 + y;
-	vertices[SP_VERTEX_X4] = offset[SP_VERTEX_X4] * bone->m00 + offset[SP_VERTEX_Y4] * bone->m01 + x;
-	vertices[SP_VERTEX_Y4] = offset[SP_VERTEX_X4] * bone->m10 + offset[SP_VERTEX_Y4] * bone->m11 + y;
+	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_X2] = offset[SP_VERTEX_X2] * bone->a + offset[SP_VERTEX_Y2] * bone->b + x;
+	vertices[SP_VERTEX_Y2] = offset[SP_VERTEX_X2] * bone->c + offset[SP_VERTEX_Y2] * bone->d + y;
+	vertices[SP_VERTEX_X3] = offset[SP_VERTEX_X3] * bone->a + offset[SP_VERTEX_Y3] * bone->b + x;
+	vertices[SP_VERTEX_Y3] = offset[SP_VERTEX_X3] * bone->c + offset[SP_VERTEX_Y3] * bone->d + y;
+	vertices[SP_VERTEX_X4] = offset[SP_VERTEX_X4] * bone->a + offset[SP_VERTEX_Y4] * bone->b + x;
+	vertices[SP_VERTEX_Y4] = offset[SP_VERTEX_X4] * bone->c + offset[SP_VERTEX_Y4] * bone->d + y;
 }

+ 67 - 79
spine-c/src/spine/Skeleton.c

@@ -33,12 +33,16 @@
 #include <string.h>
 #include <spine/extension.h>
 
+typedef enum {
+	SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT
+} _spUpdateType;
+
 typedef struct {
 	spSkeleton super;
 
-	int boneCacheCount;
-	int* boneCacheCounts;
-	spBone*** boneCache;
+	int updateCacheCount;
+	void** updateCache;
+	_spUpdateType* updateCacheType;
 } _spSkeleton;
 
 spSkeleton* spSkeleton_create (spSkeletonData* data) {
@@ -96,6 +100,11 @@ spSkeleton* spSkeleton_create (spSkeletonData* data) {
 	for (i = 0; i < self->data->ikConstraintsCount; ++i)
 		self->ikConstraints[i] = spIkConstraint_create(self->data->ikConstraints[i], self);
 
+	self->transformConstraintsCount = data->transformConstraintsCount;
+	self->transformConstraints = MALLOC(spTransformConstraint*, self->transformConstraintsCount);
+	for (i = 0; i < self->data->transformConstraintsCount; ++i)
+		self->transformConstraints[i] = spTransformConstraint_create(self->data->transformConstraints[i], self);
+
 	spSkeleton_updateCache(self);
 
 	return self;
@@ -103,12 +112,6 @@ spSkeleton* spSkeleton_create (spSkeletonData* data) {
 
 void spSkeleton_dispose (spSkeleton* self) {
 	int i;
-	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
-
-	for (i = 0; i < internal->boneCacheCount; ++i)
-		FREE(internal->boneCache[i]);
-	FREE(internal->boneCache);
-	FREE(internal->boneCacheCounts);
 
 	for (i = 0; i < self->bonesCount; ++i)
 		spBone_dispose(self->bones[i]);
@@ -122,6 +125,10 @@ void spSkeleton_dispose (spSkeleton* self) {
 		spIkConstraint_dispose(self->ikConstraints[i]);
 	FREE(self->ikConstraints);
 
+	for (i = 0; i < self->transformConstraintsCount; ++i)
+		spTransformConstraint_dispose(self->transformConstraints[i]);
+	FREE(self->transformConstraints);
+
 	FREE(self->drawOrder);
 	FREE(self);
 }
@@ -130,84 +137,51 @@ void spSkeleton_updateCache (const spSkeleton* self) {
 	int i, ii;
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
 
-	for (i = 0; i < internal->boneCacheCount; ++i)
-		FREE(internal->boneCache[i]);
-	FREE(internal->boneCache);
-	FREE(internal->boneCacheCounts);
-
-	internal->boneCacheCount = self->ikConstraintsCount + 1;
-	internal->boneCache = MALLOC(spBone**, internal->boneCacheCount);
-	internal->boneCacheCounts = CALLOC(int, internal->boneCacheCount);
-
-	/* Compute array sizes. */
-	for (i = 0; i < self->bonesCount; ++i) {
-		spBone* current = self->bones[i];
-		do {
-			for (ii = 0; ii < self->ikConstraintsCount; ++ii) {
-				spIkConstraint* ikConstraint = self->ikConstraints[ii];
-				spBone* parent = ikConstraint->bones[0];
-				spBone* child = ikConstraint->bones[ikConstraint->bonesCount - 1];
-				while (1) {
-					if (current == child) {
-						internal->boneCacheCounts[ii]++;
-						internal->boneCacheCounts[ii + 1]++;
-						goto outer1;
-					}
-					if (child == parent) break;
-					child = child->parent;
-				}
-			}
-			current = current->parent;
-		} while (current);
-		internal->boneCacheCounts[0]++;
-		outer1: {}
-	}
+	FREE(internal->updateCache);
+	FREE(internal->updateCacheType);
+	internal->updateCache = MALLOC(void*, self->bonesCount + self->transformConstraintsCount + self->ikConstraintsCount);
+	internal->updateCacheType = MALLOC(_spUpdateType, self->bonesCount + self->transformConstraintsCount + self->ikConstraintsCount);
+	internal->updateCacheCount = 0;
 
-	for (i = 0; i < internal->boneCacheCount; ++i)
-		internal->boneCache[i] = MALLOC(spBone*, internal->boneCacheCounts[i]);
-	memset(internal->boneCacheCounts, 0, internal->boneCacheCount * sizeof(int));
-
-	/* Populate arrays. */
 	for (i = 0; i < self->bonesCount; ++i) {
 		spBone* bone = self->bones[i];
-		spBone* current = bone;
-		do {
-			for (ii = 0; ii < self->ikConstraintsCount; ++ii) {
-				spIkConstraint* ikConstraint = self->ikConstraints[ii];
-				spBone* parent = ikConstraint->bones[0];
-				spBone* child = ikConstraint->bones[ikConstraint->bonesCount - 1];
-				while (1) {
-					if (current == child) {
-						internal->boneCache[ii][internal->boneCacheCounts[ii]++] = bone;
-						internal->boneCache[ii + 1][internal->boneCacheCounts[ii + 1]++] = bone;
-						goto outer2;
-					}
-					if (child == parent) break;
-					child = child->parent;
-				}
+		internal->updateCache[internal->updateCacheCount] = bone;
+		internal->updateCacheType[internal->updateCacheCount++] = SP_UPDATE_BONE;
+		for (ii = 0; ii < self->transformConstraintsCount; ++ii) {
+			spTransformConstraint* transformConstraint = self->transformConstraints[ii];
+			if (bone == transformConstraint->bone) {
+				internal->updateCache[internal->updateCacheCount] = transformConstraint;
+				internal->updateCacheType[internal->updateCacheCount++] = SP_UPDATE_TRANSFORM_CONSTRAINT;
+				break;
 			}
-			current = current->parent;
-		} while (current);
-		internal->boneCache[0][internal->boneCacheCounts[0]++] = bone;
-		outer2: {}
+		}
+		for (ii = 0; ii < self->ikConstraintsCount; ++ii) {
+			spIkConstraint* ikConstraint = self->ikConstraints[ii];
+			if (bone == ikConstraint->bones[ikConstraint->bonesCount - 1]) {
+				internal->updateCache[internal->updateCacheCount] = ikConstraint;
+				internal->updateCacheType[internal->updateCacheCount++] = SP_UPDATE_IK_CONSTRAINT;
+				break;
+			}
+		}
 	}
 }
 
 void spSkeleton_updateWorldTransform (const spSkeleton* self) {
-	int i, ii, nn, last;
+	int i;
 	_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
 
-	for (i = 0; i < self->bonesCount; ++i)
-		self->bones[i]->rotationIK = self->bones[i]->rotation;
-
-	i = 0;
-	last = internal->boneCacheCount - 1;
-	while (1) {
-		for (ii = 0, nn = internal->boneCacheCounts[i]; ii < nn; ++ii)
-			spBone_updateWorldTransform(internal->boneCache[i][ii]);
-		if (i == last) break;
-		spIkConstraint_apply(self->ikConstraints[i]);
-		i++;
+	for (i = 0; i < internal->updateCacheCount; ++i) {
+		switch (internal->updateCacheType[i]) {
+		case SP_UPDATE_BONE:
+			spBone_updateWorldTransform((spBone*)internal->updateCache[i]);
+			break;
+		case SP_UPDATE_IK_CONSTRAINT:
+			spIkConstraint_apply((spIkConstraint*)internal->updateCache[i]);
+			break;
+		case SP_UPDATE_TRANSFORM_CONSTRAINT:
+			spTransformConstraint_apply((spTransformConstraint*)internal->updateCache[i]);
+			break;
+		}
 	}
 }
 
@@ -226,6 +200,13 @@ void spSkeleton_setBonesToSetupPose (const spSkeleton* self) {
 		ikConstraint->bendDirection = ikConstraint->data->bendDirection;
 		ikConstraint->mix = ikConstraint->data->mix;
 	}
+
+	for (i = 0; i < self->transformConstraintsCount; ++i) {
+		spTransformConstraint* transformConstraint = self->transformConstraints[i];
+		transformConstraint->translateMix = transformConstraint->data->translateMix;
+		transformConstraint->x = transformConstraint->data->x;
+		transformConstraint->y = transformConstraint->data->y;
+	}
 }
 
 void spSkeleton_setSlotsToSetupPose (const spSkeleton* self) {
@@ -330,10 +311,17 @@ int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char
 	return 0;
 }
 
-spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* ikConstraintName) {
+spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* constraintName) {
 	int i;
 	for (i = 0; i < self->ikConstraintsCount; ++i)
-		if (strcmp(self->ikConstraints[i]->data->name, ikConstraintName) == 0) return self->ikConstraints[i];
+		if (strcmp(self->ikConstraints[i]->data->name, constraintName) == 0) return self->ikConstraints[i];
+	return 0;
+}
+
+spTransformConstraint* spSkeleton_findTransformConstraint (const spSkeleton* self, const char* constraintName) {
+	int i;
+	for (i = 0; i < self->transformConstraintsCount; ++i)
+		if (strcmp(self->transformConstraints[i]->data->name, constraintName) == 0) return self->transformConstraints[i];
 	return 0;
 }
 

+ 13 - 2
spine-c/src/spine/SkeletonData.c

@@ -63,6 +63,10 @@ void spSkeletonData_dispose (spSkeletonData* self) {
 		spIkConstraintData_dispose(self->ikConstraints[i]);
 	FREE(self->ikConstraints);
 
+	for (i = 0; i < self->transformConstraintsCount; ++i)
+		spTransformConstraintData_dispose(self->transformConstraints[i]);
+	FREE(self->transformConstraints);
+
 	FREE(self->hash);
 	FREE(self->version);
 
@@ -118,9 +122,16 @@ spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const cha
 	return 0;
 }
 
-spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* ikConstraintName) {
+spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* constraintName) {
 	int i;
 	for (i = 0; i < self->ikConstraintsCount; ++i)
-		if (strcmp(self->ikConstraints[i]->name, ikConstraintName) == 0) return self->ikConstraints[i];
+		if (strcmp(self->ikConstraints[i]->name, constraintName) == 0) return self->ikConstraints[i];
+	return 0;
+}
+
+spTransformConstraintData* spSkeletonData_findTransformConstraint (const spSkeletonData* self, const char* constraintName) {
+	int i;
+	for (i = 0; i < self->transformConstraintsCount; ++i)
+		if (strcmp(self->transformConstraints[i]->name, constraintName) == 0) return self->transformConstraints[i];
 	return 0;
 }

+ 46 - 26
spine-c/src/spine/SkeletonJson.c

@@ -116,8 +116,6 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
 	Json* ffd = Json_getItem(root, "ffd");
 	Json* drawOrder = Json_getItem(root, "drawOrder");
 	Json* events = Json_getItem(root, "events");
-	Json* flipX = Json_getItem(root, "flipx");
-	Json* flipY = Json_getItem(root, "flipy");
 	Json *boneMap, *slotMap, *ikMap, *ffdMap;
 	if (!drawOrder) drawOrder = Json_getItem(root, "draworder");
 
@@ -131,8 +129,6 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
 			timelinesCount += slotMap->size;
 	if (drawOrder) ++timelinesCount;
 	if (events) ++timelinesCount;
-	if (flipX) ++timelinesCount;
-	if (flipY) ++timelinesCount;
 
 	animation = spAnimation_create(root->name, timelinesCount);
 	animation->timelinesCount = 0;
@@ -221,16 +217,6 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
 					animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
 					duration = timeline->frames[timelineArray->size * 3 - 3];
 					if (duration > animation->duration) animation->duration = duration;
-				} else if (strcmp(timelineArray->name, "flipX") == 0 || strcmp(timelineArray->name, "flipY") == 0) {
-					int x = strcmp(timelineArray->name, "flipX") == 0;
-					const char* field = x ? "x" : "y";
-					spFlipTimeline *timeline = spFlipTimeline_create(timelineArray->size, x);
-					timeline->boneIndex = boneIndex;
-					for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i)
-						spFlipTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getInt(frame, field, 0));
-					animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
-					duration = timeline->frames[timelineArray->size * 2 - 2];
-					if (duration > animation->duration) animation->duration = duration;
 
 				} else {
 					spAnimation_dispose(animation);
@@ -281,8 +267,8 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
 				}
 				if (attachment->type == SP_ATTACHMENT_MESH)
 					verticesCount = SUB_CAST(spMeshAttachment, attachment)->verticesCount;
-				else if (attachment->type == SP_ATTACHMENT_SKINNED_MESH)
-					verticesCount = SUB_CAST(spSkinnedMeshAttachment, attachment)->weightsCount / 3 * 2;
+				else if (attachment->type == SP_ATTACHMENT_WEIGHTED_MESH)
+					verticesCount = SUB_CAST(spWeightedMeshAttachment, attachment)->weightsCount / 3 * 2;
 
 				timeline = spFFDTimeline_create(timelineArray->size, verticesCount);
 				timeline->slotIndex = slotIndex;
@@ -384,18 +370,19 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
 		for (frame = events->child, i = 0; frame; frame = frame->next, ++i) {
 			spEvent* event;
 			const char* stringValue;
+			float time = Json_getFloat(frame, "time", 0);
 			spEventData* eventData = spSkeletonData_findEvent(skeletonData, Json_getString(frame, "name", 0));
 			if (!eventData) {
 				spAnimation_dispose(animation);
 				_spSkeletonJson_setError(self, 0, "Event not found: ", Json_getString(frame, "name", 0));
 				return 0;
 			}
-			event = spEvent_create(eventData);
+			event = spEvent_create(time, eventData);
 			event->intValue = Json_getInt(frame, "int", eventData->intValue);
 			event->floatValue = Json_getFloat(frame, "float", eventData->floatValue);
 			stringValue = Json_getString(frame, "string", eventData->stringValue);
 			if (stringValue) MALLOC_STR(event->stringValue, stringValue);
-			spEventTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), event);
+			spEventTimeline_setFrame(timeline, i, time, event);
 		}
 		animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
 		duration = timeline->frames[events->size - 1];
@@ -421,7 +408,7 @@ spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const
 spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const char* json) {
 	int i, ii;
 	spSkeletonData* skeletonData;
-	Json *root, *skeleton, *bones, *boneMap, *ik, *slots, *skins, *animations, *events;
+	Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *slots, *skins, *animations, *events;
 	char* oldLocale;
 
 	FREE(self->error);
@@ -471,8 +458,6 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 		boneData->scaleY = Json_getFloat(boneMap, "scaleY", 1);
 		boneData->inheritScale = Json_getInt(boneMap, "inheritScale", 1);
 		boneData->inheritRotation = Json_getInt(boneMap, "inheritRotation", 1);
-		boneData->flipX = Json_getInt(boneMap, "flipX", 0);
-		boneData->flipY = Json_getInt(boneMap, "flipY", 0);
 
 		skeletonData->bones[i] = boneData;
 		skeletonData->bonesCount++;
@@ -515,6 +500,41 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 		}
 	}
 
+	/* Transform constraints. */
+	transform = Json_getItem(root, "transform");
+	if (transform) {
+		Json *transformMap;
+		skeletonData->transformConstraintsCount = transform->size;
+		skeletonData->transformConstraints = MALLOC(spTransformConstraintData*, transform->size);
+		for (transformMap = transform->child, i = 0; transformMap; transformMap = transformMap->next, ++i) {
+			const char* name;
+
+			spTransformConstraintData* transformConstraintData = spTransformConstraintData_create(Json_getString(transformMap, "name", 0));
+
+			name = Json_getString(transformMap, "bone", 0);
+			transformConstraintData->bone = spSkeletonData_findBone(skeletonData, name);
+			if (!transformConstraintData->bone) {
+				spSkeletonData_dispose(skeletonData);
+				_spSkeletonJson_setError(self, root, "Bone not found: ", boneMap->name);
+				return 0;
+			}
+
+			name = Json_getString(transformMap, "target", 0);
+			transformConstraintData->target = spSkeletonData_findBone(skeletonData, name);
+			if (!transformConstraintData->target) {
+				spSkeletonData_dispose(skeletonData);
+				_spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name);
+				return 0;
+			}
+
+			transformConstraintData->translateMix = Json_getFloat(transformMap, "translateMix", 1);
+			transformConstraintData->x = Json_getFloat(transformMap, "x", 0);
+			transformConstraintData->y = Json_getFloat(transformMap, "y", 0);
+
+			skeletonData->transformConstraints[i] = transformConstraintData;
+		}
+	}
+
 	/* Slots. */
 	slots = Json_getItem(root, "slots");
 	if (slots) {
@@ -593,8 +613,8 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 						type = SP_ATTACHMENT_REGION;
 					else if (strcmp(typeString, "mesh") == 0)
 						type = SP_ATTACHMENT_MESH;
-					else if (strcmp(typeString, "skinnedmesh") == 0)
-						type = SP_ATTACHMENT_SKINNED_MESH;
+					else if (strcmp(typeString, "weightedmesh") == 0 || strcmp(typeString, "skinnedmesh") == 0)
+						type = SP_ATTACHMENT_WEIGHTED_MESH;
 					else if (strcmp(typeString, "boundingbox") == 0)
 						type = SP_ATTACHMENT_BOUNDING_BOX;
 					else {
@@ -682,8 +702,8 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 						mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale;
 						break;
 					}
-					case SP_ATTACHMENT_SKINNED_MESH: {
-						spSkinnedMeshAttachment* mesh = SUB_CAST(spSkinnedMeshAttachment, attachment);
+					case SP_ATTACHMENT_WEIGHTED_MESH: {
+						spWeightedMeshAttachment* mesh = SUB_CAST(spWeightedMeshAttachment, attachment);
 						int verticesCount, b, w, nn;
 						float* vertices;
 
@@ -729,7 +749,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 						for (entry = entry->child, i = 0; entry; entry = entry->next, ++i)
 							mesh->triangles[i] = entry->valueInt;
 
-						spSkinnedMeshAttachment_updateUVs(mesh);
+						spWeightedMeshAttachment_updateUVs(mesh);
 
 						color = Json_getString(attachmentMap, "color", 0);
 						if (color) {

+ 58 - 0
spine-c/src/spine/TransformConstraint.c

@@ -0,0 +1,58 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ * 
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ * 
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <spine/TransformConstraint.h>
+#include <spine/Skeleton.h>
+#include <spine/extension.h>
+
+spTransformConstraint* spTransformConstraint_create (spTransformConstraintData* data, const spSkeleton* skeleton) {
+	spTransformConstraint* self = NEW(spTransformConstraint);
+	CONST_CAST(spTransformConstraintData*, self->data) = data;
+	self->translateMix = data->translateMix;
+	self->x = data->x;
+	self->y = data->y;
+	self->bone = spSkeleton_findBone(skeleton, self->data->bone->name);
+	self->target = spSkeleton_findBone(skeleton, self->data->target->name);
+	return self;
+}
+
+void spTransformConstraint_dispose (spTransformConstraint* self) {
+	FREE(self);
+}
+
+void spTransformConstraint_apply (spTransformConstraint* self) {
+	if (self->translateMix > 0) {
+		float tx, ty;
+		spBone_localToWorld(self->target, self->x, self->y, &tx, &ty);
+		CONST_CAST(float, self->bone->worldX) = self->bone->worldX + (tx - self->bone->worldX) * self->translateMix;
+		CONST_CAST(float, self->bone->worldY) = self->bone->worldY + (ty - self->bone->worldY) * self->translateMix;
+	}
+}

+ 44 - 0
spine-c/src/spine/TransformConstraintData.c

@@ -0,0 +1,44 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ * 
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ * 
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#include <spine/TransformConstraintData.h>
+#include <spine/extension.h>
+
+spTransformConstraintData* spTransformConstraintData_create (const char* name) {
+	spTransformConstraintData* self = NEW(spTransformConstraintData);
+	MALLOC_STR(self->name, name);
+	return self;
+}
+
+void spTransformConstraintData_dispose (spTransformConstraintData* self) {
+	FREE(self->name);
+	FREE(self);
+}

+ 12 - 12
spine-c/src/spine/SkinnedMeshAttachment.c → spine-c/src/spine/WeightedMeshAttachment.c

@@ -29,11 +29,11 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
-#include <spine/SkinnedMeshAttachment.h>
+#include <spine/WeightedMeshAttachment.h>
 #include <spine/extension.h>
 
-void _spSkinnedMeshAttachment_dispose (spAttachment* attachment) {
-	spSkinnedMeshAttachment* self = SUB_CAST(spSkinnedMeshAttachment, attachment);
+void _spWeightedMeshAttachment_dispose (spAttachment* attachment) {
+	spWeightedMeshAttachment* self = SUB_CAST(spWeightedMeshAttachment, attachment);
 	_spAttachment_deinit(attachment);
 	FREE(self->path);
 	FREE(self->bones);
@@ -45,17 +45,17 @@ void _spSkinnedMeshAttachment_dispose (spAttachment* attachment) {
 	FREE(self);
 }
 
-spSkinnedMeshAttachment* spSkinnedMeshAttachment_create (const char* name) {
-	spSkinnedMeshAttachment* self = NEW(spSkinnedMeshAttachment);
+spWeightedMeshAttachment* spWeightedMeshAttachment_create (const char* name) {
+	spWeightedMeshAttachment* self = NEW(spWeightedMeshAttachment);
 	self->r = 1;
 	self->g = 1;
 	self->b = 1;
 	self->a = 1;
-	_spAttachment_init(SUPER(self), name, SP_ATTACHMENT_SKINNED_MESH, _spSkinnedMeshAttachment_dispose);
+	_spAttachment_init(SUPER(self), name, SP_ATTACHMENT_WEIGHTED_MESH, _spWeightedMeshAttachment_dispose);
 	return self;
 }
 
-void spSkinnedMeshAttachment_updateUVs (spSkinnedMeshAttachment* self) {
+void spWeightedMeshAttachment_updateUVs (spWeightedMeshAttachment* self) {
 	int i;
 	float width = self->regionU2 - self->regionU, height = self->regionV2 - self->regionV;
 	FREE(self->uvs);
@@ -73,7 +73,7 @@ void spSkinnedMeshAttachment_updateUVs (spSkinnedMeshAttachment* self) {
 	}
 }
 
-void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self, spSlot* slot, float* worldVertices) {
+void spWeightedMeshAttachment_computeWorldVertices (spWeightedMeshAttachment* self, spSlot* slot, float* worldVertices) {
 	int w = 0, v = 0, b = 0, f = 0;
 	float x = slot->bone->skeleton->x, y = slot->bone->skeleton->y;
 	spBone** skeletonBones = slot->bone->skeleton->bones;
@@ -85,8 +85,8 @@ void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self
 			for (; v <= nn; v++, b += 3) {
 				const spBone* bone = skeletonBones[self->bones[v]];
 				const float vx = self->weights[b], vy = self->weights[b + 1], weight = self->weights[b + 2];
-				wx += (vx * bone->m00 + vy * bone->m01 + bone->worldX) * weight;
-				wy += (vx * bone->m10 + vy * bone->m11 + bone->worldY) * weight;
+				wx += (vx * bone->a + vy * bone->b + bone->worldX) * weight;
+				wy += (vx * bone->c + vy * bone->d + bone->worldY) * weight;
 			}
 			worldVertices[w] = wx + x;
 			worldVertices[w + 1] = wy + y;
@@ -100,8 +100,8 @@ void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self
 			for (; v <= nn; v++, b += 3, f += 2) {
 				const spBone* bone = skeletonBones[self->bones[v]];
 				const float vx = self->weights[b] + ffd[f], vy = self->weights[b + 1] + ffd[f + 1], weight = self->weights[b + 2];
-				wx += (vx * bone->m00 + vy * bone->m01 + bone->worldX) * weight;
-				wy += (vx * bone->m10 + vy * bone->m11 + bone->worldY) * weight;
+				wx += (vx * bone->a + vy * bone->b + bone->worldX) * weight;
+				wy += (vx * bone->c + vy * bone->d + bone->worldY) * weight;
 			}
 			worldVertices[w] = wx + x;
 			worldVertices[w + 1] = wy + y;

+ 1 - 1
spine-sfml/.settings/org.eclipse.cdt.core.prefs

@@ -155,7 +155,7 @@ org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line=false
 org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line=false
 org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line=false
 org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.cdt.core.formatter.lineSplit=80
+org.eclipse.cdt.core.formatter.lineSplit=130
 org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve=1
 org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line=true
 org.eclipse.cdt.core.formatter.tabulation.char=tab

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

@@ -196,11 +196,11 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 				vertexArray->append(vertex);
 			}
 
-		} else if (attachment->type == ATTACHMENT_SKINNED_MESH) {
-			SkinnedMeshAttachment* mesh = (SkinnedMeshAttachment*)attachment;
+		} else if (attachment->type == ATTACHMENT_WEIGHTED_MESH) {
+			WeightedMeshAttachment* mesh = (WeightedMeshAttachment*)attachment;
 			if (mesh->uvsCount > SPINE_MESH_VERTEX_COUNT_MAX) continue;
 			texture = (Texture*)((AtlasRegion*)mesh->rendererObject)->page->rendererObject;
-			SkinnedMeshAttachment_computeWorldVertices(mesh, slot, worldVertices);
+			WeightedMeshAttachment_computeWorldVertices(mesh, slot, worldVertices);
 
 			Uint8 r = static_cast<Uint8>(skeleton->r * slot->r * 255);
 			Uint8 g = static_cast<Uint8>(skeleton->g * slot->g * 255);