소스 검색

[c] Ported skin bones/constraints changes. See #1346.

badlogic 6 년 전
부모
커밋
d9161d2020

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

@@ -54,6 +54,7 @@ struct spBone {
 	float const c, d, worldY;
 
 	int/*bool*/ sorted;
+	int/*bool*/ active;
 
 #ifdef __cplusplus
 	spBone() :
@@ -68,7 +69,7 @@ struct spBone {
 		a(0), b(0), worldX(0),
 		c(0), d(0), worldY(0),
 
-		sorted(0) {
+		sorted(0), active(0) {
 	}
 #endif
 };

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

@@ -52,6 +52,7 @@ struct spBoneData {
 	float length;
 	float x, y, rotation, scaleX, scaleY, shearX, shearY;
 	spTransformMode transformMode;
+	int/*bool*/ skinRequired;
 
 #ifdef __cplusplus
 	spBoneData() :
@@ -63,7 +64,8 @@ struct spBoneData {
 		rotation(0),
 		scaleX(0), scaleY(0),
 		shearX(0), shearY(0),
-		transformMode(SP_TRANSFORMMODE_NORMAL) {
+		transformMode(SP_TRANSFORMMODE_NORMAL),
+		skinRequired(0) {
 	}
 #endif
 };

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

@@ -52,6 +52,8 @@ typedef struct spIkConstraint {
 	int /*boolean*/ stretch;
 	float mix;
 
+	int /*boolean*/ active;
+
 #ifdef __cplusplus
 	spIkConstraint() :
 		data(0),
@@ -60,7 +62,8 @@ typedef struct spIkConstraint {
 		target(0),
 		bendDirection(0),
 		stretch(0),
-		mix(0) {
+		mix(0),
+		active(0) {
 	}
 #endif
 } spIkConstraint;

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

@@ -40,6 +40,7 @@ extern "C" {
 typedef struct spIkConstraintData {
 	const char* const name;
 	int order;
+	int /*boolean*/ skinRequired;
 	int bonesCount;
 	spBoneData** bones;
 
@@ -53,6 +54,8 @@ typedef struct spIkConstraintData {
 #ifdef __cplusplus
 	spIkConstraintData() :
 		name(0),
+		order(0),
+		skinRequired(0),
 		bonesCount(0),
 		bones(0),
 		target(0),

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

@@ -66,6 +66,8 @@ typedef struct spPathConstraint {
 
 	float segments[10];
 
+	int /*boolean*/ active;
+
 #ifdef __cplusplus
 	spPathConstraint() :
 		data(0),
@@ -85,7 +87,8 @@ typedef struct spPathConstraint {
 		curvesCount(0),
 		curves(0),
 		lengthsCount(0),
-		lengths(0) {
+		lengths(0),
+		active(0) {
 	}
 #endif
 } spPathConstraint;

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

@@ -53,6 +53,7 @@ typedef enum {
 typedef struct spPathConstraintData {
 	const char* const name;
 	int order;
+	int/*bool*/ skinRequired;
 	int bonesCount;
 	spBoneData** const bones;
 	spSlotData* target;
@@ -65,6 +66,8 @@ typedef struct spPathConstraintData {
 #ifdef __cplusplus
 	spPathConstraintData() :
 		name(0),
+		order(0),
+		skinRequired(0),
 		bonesCount(0),
 		bones(0),
 		target(0),

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

@@ -49,6 +49,9 @@ typedef struct spSkeletonData {
 	const char* hash;
 	float x, y, width, height;
 
+	int stringsCount;
+	char** strings;
+
 	int bonesCount;
 	spBoneData** bones;
 

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

@@ -46,6 +46,7 @@ typedef struct spTransformConstraint {
 	spBone** const bones;
 	spBone* target;
 	float rotateMix, translateMix, scaleMix, shearMix;
+	int /*boolean*/ active;
 
 #ifdef __cplusplus
 	spTransformConstraint() :
@@ -56,7 +57,8 @@ typedef struct spTransformConstraint {
 		rotateMix(0),
 		translateMix(0),
 		scaleMix(0),
-		shearMix(0) {
+		shearMix(0),
+		active(0) {
 	}
 #endif
 } spTransformConstraint;

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

@@ -40,6 +40,7 @@ extern "C" {
 typedef struct spTransformConstraintData {
 	const char* const name;
 	int order;
+	int/*bool*/ skinRequired;
 	int bonesCount;
 	spBoneData** const bones;
 	spBoneData* target;
@@ -51,6 +52,8 @@ typedef struct spTransformConstraintData {
 #ifdef __cplusplus
 	spTransformConstraintData() :
 		name(0),
+		order(0),
+		skinRequired(0),
 		bonesCount(0),
 		bones(0),
 		target(0),

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

@@ -245,6 +245,7 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
 	spRotateTimeline* self = SUB_CAST(spRotateTimeline, timeline);
 
 	bone = skeleton->bones[self->boneIndex];
+	if (!bone->active) return;
 	if (time < self->frames[0]) {
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:
@@ -333,6 +334,7 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
 	spTranslateTimeline* self = SUB_CAST(spTranslateTimeline, timeline);
 
 	bone = skeleton->bones[self->boneIndex];
+	if (!bone->active) return;
 	if (time < self->frames[0]) {
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:
@@ -415,6 +417,7 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
 	spScaleTimeline* self = SUB_CAST(spScaleTimeline, timeline);
 
 	bone = skeleton->bones[self->boneIndex];
+	if (!bone->active) return;
 	if (time < self->frames[0]) {
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:
@@ -533,6 +536,7 @@ void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
 	spShearTimeline* self = SUB_CAST(spShearTimeline, timeline);
 
 	bone = skeleton->bones[self->boneIndex];
+	if (!bone->active) return;
 	frames = self->frames;
 	framesCount = self->framesCount;
 	if (time < self->frames[0]) {
@@ -614,6 +618,7 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
 	spColor* setup;
 	spColorTimeline* self = (spColorTimeline*)timeline;
 	slot = skeleton->slots[self->slotIndex];
+	if (!slot->bone->active) return;
 
 	if (time < self->frames[0]) {
 		switch (blend) {
@@ -706,6 +711,7 @@ void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton
 	spColor* setupDark;
 	spColorTimeline* self = (spColorTimeline*)timeline;
 	slot = skeleton->slots[self->slotIndex];
+	if (!slot->bone->active) return;
 
 	if (time < self->frames[0]) {
 		switch (blend) {
@@ -809,6 +815,7 @@ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skelet
 	spAttachmentTimeline* self = (spAttachmentTimeline*)timeline;
 	int frameIndex;
 	spSlot* slot = skeleton->slots[self->slotIndex];
+	if (!slot->bone->active) return;
 
 	if (direction == SP_MIX_DIRECTION_OUT && blend == SP_MIX_BLEND_SETUP) {
 		attachmentName = slot->data->attachmentName;
@@ -893,6 +900,7 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
 	spDeformTimeline* self = (spDeformTimeline*)timeline;
 
 	spSlot *slot = skeleton->slots[self->slotIndex];
+	if (!slot->bone->active) return;
 
 	if (!slot->attachment) return;
 	switch (slot->attachment->type) {
@@ -1295,6 +1303,7 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
 	spIkConstraintTimeline* self = (spIkConstraintTimeline*)timeline;
 
 	constraint = skeleton->ikConstraints[self->ikConstraintIndex];
+	if (!constraint->active) return;
 
 	if (time < self->frames[0]) {
 		switch (blend) {
@@ -1410,6 +1419,8 @@ void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleto
 	int framesCount;
 
 	constraint = skeleton->transformConstraints[self->transformConstraintIndex];
+	if (!constraint->active) return;
+
 	if (time < self->frames[0]) {
 		spTransformConstraintData* data = constraint->data;
 		switch (blend) {
@@ -1508,6 +1519,8 @@ void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkele
 	int framesCount;
 
 	constraint = skeleton->pathConstraints[self->pathConstraintIndex];
+	if (!constraint->active) return;
+
 	if (time < self->frames[0]) {
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:
@@ -1576,6 +1589,8 @@ void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkelet
 	int framesCount;
 
 	constraint = skeleton->pathConstraints[self->pathConstraintIndex];
+	if (!constraint->active) return;
+
 	if (time < self->frames[0]) {
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:
@@ -1648,6 +1663,8 @@ void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton*
 	int framesCount;
 
 	constraint = skeleton->pathConstraints[self->pathConstraintIndex];
+	if (!constraint->active) return;
+
 	if (time < self->frames[0]) {
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:

+ 1 - 0
spine-c/spine-c/src/spine/AnimationState.c

@@ -541,6 +541,7 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
 	rotateTimeline = SUB_CAST(spRotateTimeline, timeline);
 	frames = rotateTimeline->frames;
 	bone = skeleton->bones[rotateTimeline->boneIndex];
+	if (!bone->active) return;
 	if (time < frames[0]) {
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:

+ 30 - 2
spine-c/spine-c/src/spine/Skeleton.c

@@ -219,6 +219,7 @@ static void _sortReset(spBone** bones, int bonesCount) {
 	int i;
 	for (i = 0; i < bonesCount; ++i) {
 		spBone* bone = bones[i];
+		if (!bone->active) continue;
 		if (bone->sorted) _sortReset(bone->children, bone->childrenCount);
 		bone->sorted = 0;
 	}
@@ -230,6 +231,10 @@ static void _sortIkConstraint (_spSkeleton* const internal, spIkConstraint* cons
 	spBone* target = constraint->target;
 	spBone** constrained;
 	spBone* parent;
+
+	constraint->active = constraint->target->active && (!constraint->data->skinRequired || (internal->super.skin != 0 && spIkConstraintDataArray_contains(internal->super.skin->ikConstraints, constraint->data)));
+	if (!constraint->active) return;
+
 	_sortBone(internal, target);
 
 	constrained = constraint->bones;
@@ -264,6 +269,10 @@ static void _sortPathConstraint(_spSkeleton* const internal, spPathConstraint* c
 	spAttachment* attachment;
 	spBone** constrained;
 	spSkeleton* skeleton = SUPER_CAST(spSkeleton, internal);
+
+	constraint->active = constraint->target->bone->active && (!constraint->data->skinRequired || (internal->super.skin != 0 && spPathConstraintDataArray_contains(internal->super.skin->pathConstraints, constraint->data)));
+	if (!constraint->active) return;
+
 	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);
@@ -291,6 +300,10 @@ static void _sortTransformConstraint(_spSkeleton* const internal, spTransformCon
 	spBone** constrained;
 	spBone* child;
 	int /*boolean*/ contains = 0;
+
+	constraint->active = constraint->target->active && (!constraint->data->skinRequired || (internal->super.skin != 0 && spTransformConstraintDataArray_contains(internal->super.skin->transformConstraints, constraint->data)));
+	if (!constraint->active) return;
+
 	_sortBone(internal, constraint->target);
 
 	constrained = constraint->bones;
@@ -342,8 +355,23 @@ void spSkeleton_updateCache (spSkeleton* self) {
 	internal->updateCacheResetCount = 0;
 
 	bones = self->bones;
-	for (i = 0; i < self->bonesCount; ++i)
-		bones[i]->sorted = 0;
+	for (i = 0; i < self->bonesCount; ++i) {
+		spBone* bone = bones[i];
+		bone->sorted = bone->data->skinRequired;
+		bone->active = !bone->sorted;
+	}
+
+	if (self->skin) {
+		spBoneDataArray* skinBones = self->skin->bones;
+		for(i = 0; i < skinBones->size; i++) {
+			spBone* bone = self->bones[skinBones->items[i]->index];
+			do {
+				bone->sorted = 0;
+				bone->active = -1;
+				bone = bone->parent;
+			} while (bone != 0);
+		}
+	}
 
 	/* IK first, lowest hierarchy depth first. */
 	ikConstraints = self->ikConstraints;

+ 69 - 47
spine-c/spine-c/src/spine/SkeletonBinary.c

@@ -74,10 +74,6 @@ void spSkeletonBinary_dispose (spSkeletonBinary* self) {
 	int i;
 	_spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self);
 	if (internal->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader);
-	for (i = 0; i < internal->linkedMeshCount; ++i) {
-		FREE(internal->linkedMeshes[i].parent);
-		FREE(internal->linkedMeshes[i].skin);
-	}
 	FREE(internal->linkedMeshes);
 	FREE(self->error);
 	FREE(self);
@@ -147,7 +143,7 @@ float readFloat (_dataInput* input) {
 
 char* readString (_dataInput* input) {
 	int length = readVarint(input, 1);
-	char* string;
+	char *string;
 	if (length == 0) {
 		return 0;
 	}
@@ -158,6 +154,11 @@ char* readString (_dataInput* input) {
 	return string;
 }
 
+static char* readStringRef(_dataInput* input, spSkeletonData* skeletonData) {
+	int index = readVarint(input, 1);
+	return index == 0 ? 0 : skeletonData->strings[index - 1];
+}
+
 static void readColor (_dataInput* input, float *r, float *g, float *b, float *a) {
 	*r = readByte(input) / 255.0f;
 	*g = readByte(input) / 255.0f;
@@ -269,10 +270,9 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
 					timeline->slotIndex = slotIndex;
 					for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
 						float time = readFloat(input);
-						const char* attachmentName = readString(input);
+						const char* attachmentName = readStringRef(input, skeletonData);
 						/* TODO Avoid copying of attachmentName inside */
 						spAttachmentTimeline_setFrame(timeline, frameIndex, time, attachmentName);
-						FREE(attachmentName);
 					}
 					spTimelineArray_add(timelines, (spTimeline*)timeline);
 					duration = MAX(duration, timeline->frames[frameCount - 1]);
@@ -478,7 +478,7 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
 				float* tempDeform;
 				spDeformTimeline *timeline;
 				int weighted, deformLength;
-				const char* attachmentName = readString(input);
+				const char* attachmentName = readStringRef(input, skeletonData);
 				int frameCount;
 
 				spVertexAttachment* attachment = SUB_CAST(spVertexAttachment,
@@ -488,10 +488,8 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
 						spTimeline_dispose(timelines->items[i]);
 					spTimelineArray_dispose(timelines);
 					_spSkeletonBinary_setError(self, "Attachment not found: ", attachmentName);
-					FREE(attachmentName);
 					return 0;
 				}
-				FREE(attachmentName);
 
 				weighted = attachment->bones != 0;
 				deformLength = weighted ? attachment->verticesCount / 3 * 2 : attachment->verticesCount;
@@ -680,21 +678,22 @@ spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput
 		spSkin* skin, int slotIndex, const char* attachmentName, spSkeletonData* skeletonData, int/*bool*/ nonessential) {
 	int i;
 	spAttachmentType type;
-	const char* name = readString(input);
-	int freeName = name != 0;
-	if (!name) {
-		freeName = 0;
-		name = attachmentName;
-	}
+	const char* name = readStringRef(input, skeletonData);
+	if (!name) name = attachmentName;
 
 	type = (spAttachmentType)readByte(input);
 
 	switch (type) {
 		case SP_ATTACHMENT_REGION: {
-			const char* path = readString(input);
+			const char* path = readStringRef(input, skeletonData);
 			spAttachment* attachment;
 			spRegionAttachment* region;
 			if (!path) MALLOC_STR(path, name);
+			else {
+				const char* tmp = 0;
+				MALLOC_STR(tmp, path);
+				path = tmp;
+			}
 			attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path);
 			region = SUB_CAST(spRegionAttachment, attachment);
 			region->path = path;
@@ -708,7 +707,6 @@ spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput
 			readColor(input, &region->color.r, &region->color.g, &region->color.b, &region->color.a);
 			spRegionAttachment_updateOffset(region);
 			spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
-			if (freeName) FREE(name);
 			return attachment;
 		}
 		case SP_ATTACHMENT_BOUNDING_BOX: {
@@ -717,15 +715,19 @@ spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput
 			_readVertices(self, input, SUB_CAST(spVertexAttachment, attachment), vertexCount);
 			if (nonessential) readInt(input); /* Skip color. */
 			spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
-			if (freeName) FREE(name);
 			return attachment;
 		}
 		case SP_ATTACHMENT_MESH: {
 			int vertexCount;
 			spAttachment* attachment;
 			spMeshAttachment* mesh;
-			const char* path = readString(input);
+			const char* path = readStringRef(input, skeletonData);
 			if (!path) MALLOC_STR(path, name);
+			else {
+				const char* tmp = 0;
+				MALLOC_STR(tmp, path);
+				path = tmp;
+			}
 			attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path);
 			mesh = SUB_CAST(spMeshAttachment, attachment);
 			mesh->path = path;
@@ -746,7 +748,6 @@ spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput
 				mesh->height = 0;
 			}
 			spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
-			if (freeName) FREE(name);
 			return attachment;
 		}
 		case SP_ATTACHMENT_LINKED_MESH: {
@@ -755,21 +756,25 @@ spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput
 			spAttachment* attachment;
 			spMeshAttachment* mesh;
 			int inheritDeform;
-			const char* path = readString(input);
+			const char* path = readStringRef(input, skeletonData);
 			if (!path) MALLOC_STR(path, name);
+			else {
+				const char* tmp = 0;
+				MALLOC_STR(tmp, path);
+				path = tmp;
+			}
 			attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path);
 			mesh = SUB_CAST(spMeshAttachment, attachment);
 			mesh->path = path;
 			readColor(input, &mesh->color.r, &mesh->color.g, &mesh->color.b, &mesh->color.a);
-			skinName = readString(input);
-			parent = readString(input);
+			skinName = readStringRef(input, skeletonData);
+			parent = readStringRef(input, skeletonData);
 			inheritDeform = readBoolean(input);
 			if (nonessential) {
 				mesh->width = readFloat(input) * self->scale;
 				mesh->height = readFloat(input) * self->scale;
 			}
 			_spSkeletonBinary_addLinkedMesh(self, mesh, skinName, slotIndex, parent, inheritDeform);
-			if (freeName) FREE(name);
 			return attachment;
 		}
 		case SP_ATTACHMENT_PATH: {
@@ -786,7 +791,6 @@ spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput
 				path->lengths[i] = readFloat(input) * self->scale;
 			}
 			if (nonessential) readInt(input); /* Skip color. */
-			if (freeName) FREE(name);
 			spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
 			return attachment;
 		}
@@ -812,30 +816,40 @@ spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput
 			if (nonessential) readInt(input); /* Skip color. */
 			clip->endSlot = skeletonData->slots[endSlotIndex];
 			spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
-			if (freeName) FREE(name);
 			return attachment;
 		}
 	}
 
-	if (freeName) FREE(name);
 	return 0;
 }
 
-spSkin* spSkeletonBinary_readSkin(spSkeletonBinary* self, _dataInput* input,
-		const char* skinName, spSkeletonData* skeletonData, int/*bool*/ nonessential) {
+spSkin* spSkeletonBinary_readSkin(spSkeletonBinary* self, _dataInput* input, int/*bool*/ defaultSkin,
+		spSkeletonData* skeletonData, int/*bool*/ nonessential) {
 	spSkin* skin;
-	int slotCount = readVarint(input, 1);
-	int i, ii, nn;
-	if (slotCount == 0)
-		return 0;
+	int i, n, ii, nn;
+	const char* skinName = defaultSkin ? "default" : readStringRef(input, skeletonData);
 	skin = spSkin_create(skinName);
-	for (i = 0; i < slotCount; ++i) {
+
+	if (!defaultSkin) {
+		for (i = 0, n = readVarint(input, 1); i < n; i++)
+			spBoneDataArray_add(skin->bones, spSkeletonData_findBone(skeletonData, readVarint(input, 1)));
+
+		for (i = 0, n = readVarint(input, 1); i < n; i++)
+			spIkConstraintDataArray_add(skin->ikConstraints, spSkeletonData_findIkConstraint(skeletonData, readVarint(input, 1)));
+
+		for (i = 0, n = readVarint(input, 1); i < n; i++)
+			spTransformConstraintDataArray_add(skin->transformConstraints, spSkeletonData_findTransformConstraint(skeletonData, readVarint(input, 1)));
+
+		for (i = 0, n = readVarint(input, 1); i < n; i++)
+			spPathConstraintDataArray_add(skin->pathConstraints, spSkeletonData_findPathConstraint(skeletonData, readVarint(input, 1)));
+	}
+
+	for (i = 0, n = readVarint(input, 1); i < n; ++i) {
 		int slotIndex = readVarint(input, 1);
 		for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) {
-			const char* name = readString(input);
+			const char* name = readStringRef(input, skeletonData);
 			spAttachment* attachment = spSkeletonBinary_readAttachment(self, input, skin, slotIndex, name, skeletonData, nonessential);
 			if (attachment) spSkin_setAttachment(skin, slotIndex, name, attachment);
-			FREE(name);
 		}
 	}
 	return skin;
@@ -856,7 +870,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, c
 
 spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const unsigned char* binary,
 		const int length) {
-	int i, ii, nonessential;
+	int i, n, ii, nonessential;
 	spSkeletonData* skeletonData;
 	_spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self);
 
@@ -896,6 +910,12 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		FREE(readString(input));
 	}
 
+	skeletonData->stringsCount = n = readVarint(input, 1);
+	skeletonData->strings = MALLOC(char*, skeletonData->stringsCount);
+	for (i = 0; i < n; i++) {
+		skeletonData->strings[i] = readString(input);
+	}
+
 	/* Bones. */
 	skeletonData->bonesCount = readVarint(input, 1);
 	skeletonData->bones = MALLOC(spBoneData*, skeletonData->bonesCount);
@@ -923,6 +943,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 			case 3: data->transformMode = SP_TRANSFORMMODE_NOSCALE; break;
 			case 4: data->transformMode = SP_TRANSFORMMODE_NOSCALEORREFLECTION; break;
 		}
+		data->skinRequired = readBoolean(input);
 		if (nonessential) readInt(input); /* Skip bone color. */
 		skeletonData->bones[i] = data;
 	}
@@ -932,6 +953,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 	skeletonData->slots = MALLOC(spSlotData*, skeletonData->slotsCount);
 	for (i = 0; i < skeletonData->slotsCount; ++i) {
 		int r, g, b, a;
+		const char* attachmentName;
 		const char* slotName = readString(input);
 		spBoneData* boneData = skeletonData->bones[readVarint(input, 1)];
 		/* TODO Avoid copying of slotName */
@@ -946,7 +968,9 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 			slotData->darkColor = spColor_create();
 			spColor_setFromFloats(slotData->darkColor, r / 255.0f, g / 255.0f, b / 255.0f, 1);
 		}
-		slotData->attachmentName = readString(input);
+		attachmentName = readStringRef(input, skeletonData);
+		if (attachmentName) MALLOC_STR(slotData->attachmentName, attachmentName);
+		else slotData->attachmentName = 0;
 		slotData->blendMode = (spBlendMode)readVarint(input, 1);
 		skeletonData->slots[i] = slotData;
 	}
@@ -959,6 +983,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		/* TODO Avoid copying of name */
 		spIkConstraintData* data = spIkConstraintData_create(name);
 		data->order = readVarint(input, 1);
+		data->skinRequired = readBoolean(input);
 		FREE(name);
 		data->bonesCount = readVarint(input, 1);
 		data->bones = MALLOC(spBoneData*, data->bonesCount);
@@ -982,6 +1007,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		/* TODO Avoid copying of name */
 		spTransformConstraintData* data = spTransformConstraintData_create(name);
 		data->order = readVarint(input, 1);
+		data->skinRequired = readBoolean(input);
 		FREE(name);
 		data->bonesCount = readVarint(input, 1);
 		CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);
@@ -1011,6 +1037,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 		/* TODO Avoid copying of name */
 		spPathConstraintData* data = spPathConstraintData_create(name);
 		data->order = readVarint(input, 1);
+		data->skinRequired = readBoolean(input);
 		FREE(name);
 		data->bonesCount = readVarint(input, 1);
 		CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount);
@@ -1031,7 +1058,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 	}
 
 	/* Default skin. */
-	skeletonData->defaultSkin = spSkeletonBinary_readSkin(self, input, "default", skeletonData, nonessential);
+	skeletonData->defaultSkin = spSkeletonBinary_readSkin(self, input, -1, skeletonData, nonessential);
 	skeletonData->skinsCount = readVarint(input, 1);
 
 	if (skeletonData->defaultSkin)
@@ -1044,10 +1071,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 
 	/* Skins. */
 	for (i = skeletonData->defaultSkin ? 1 : 0; i < skeletonData->skinsCount; ++i) {
-		const char* skinName = readString(input);
-		/* TODO Avoid copying of skinName */
-		skeletonData->skins[i] = spSkeletonBinary_readSkin(self, input, skinName, skeletonData, nonessential);
-		FREE(skinName);
+		skeletonData->skins[i] = spSkeletonBinary_readSkin(self, input, 0, skeletonData, nonessential);
 	}
 
 	/* Linked meshes. */
@@ -1078,10 +1102,8 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 	skeletonData->eventsCount = readVarint(input, 1);
 	skeletonData->events = MALLOC(spEventData*, skeletonData->eventsCount);
 	for (i = 0; i < skeletonData->eventsCount; ++i) {
-		const char* name = readString(input);
-		/* TODO Avoid copying of skinName */
+		const char* name = readStringRef(input, skeletonData);
 		spEventData* eventData = spEventData_create(name);
-		FREE(name);
 		eventData->intValue = readVarint(input, 0);
 		eventData->floatValue = readFloat(input);
 		eventData->stringValue = readString(input);

+ 5 - 0
spine-c/spine-c/src/spine/SkeletonData.c

@@ -37,6 +37,11 @@ spSkeletonData* spSkeletonData_create () {
 
 void spSkeletonData_dispose (spSkeletonData* self) {
 	int i;
+
+	for (i = 0; i < self->stringsCount; ++i)
+		FREE(self->strings[i]);
+	FREE(self->strings);
+
 	for (i = 0; i < self->bonesCount; ++i)
 		spBoneData_dispose(self->bones[i]);
 	FREE(self->bones);

+ 78 - 18
spine-c/spine-c/src/spine/SkeletonJson.c

@@ -110,13 +110,12 @@ static void readCurve (Json* frame, spCurveTimeline* timeline, int frameIndex) {
 	if (!curve) return;
 	if (curve->type == Json_String && strcmp(curve->valueString, "stepped") == 0)
 		spCurveTimeline_setStepped(timeline, frameIndex);
-	else if (curve->type == Json_Array) {
-		Json* child0 = curve->child;
-		Json* child1 = child0->next;
-		Json* child2 = child1->next;
-		Json* child3 = child2->next;
-		spCurveTimeline_setCurve(timeline, frameIndex, child0->valueFloat, child1->valueFloat, child2->valueFloat,
-				child3->valueFloat);
+	else {
+		float c1 = Json_getFloat(frame, "curve", 0);
+		float c2 = Json_getFloat(frame, "c2", 0);
+		float c3 = Json_getFloat(frame, "c3", 1);
+		float c4 = Json_getFloat(frame, "c4", 1);
+		spCurveTimeline_setCurve(timeline, frameIndex, c1, c2, c3, c4);
 	}
 }
 
@@ -264,16 +263,20 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
 				int isTranslate = strcmp(timelineMap->name, "translate") == 0;
 				int isShear = strcmp(timelineMap->name, "shear") == 0;
 				if (isScale || isTranslate || isShear) {
+					float defaultValue = 0;
 					float timelineScale = isTranslate ? self->scale: 1;
 					spTranslateTimeline *timeline = 0;
-					if (isScale) timeline = spScaleTimeline_create(timelineMap->size);
+					if (isScale) {
+						timeline = spScaleTimeline_create(timelineMap->size);
+						defaultValue = 1;
+					}
 					else if (isTranslate) timeline = spTranslateTimeline_create(timelineMap->size);
 					else if (isShear) timeline = spShearTimeline_create(timelineMap->size);
 					timeline->boneIndex = boneIndex;
 
 					for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) {
-						spTranslateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "x", 0) * timelineScale,
-								Json_getFloat(valueMap, "y", 0) * timelineScale);
+						spTranslateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "x", defaultValue) * timelineScale,
+								Json_getFloat(valueMap, "y", defaultValue) * timelineScale);
 						readCurve(valueMap, SUPER(timeline), frameIndex);
 					}
 					animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
@@ -648,6 +651,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 			data->transformMode = SP_TRANSFORMMODE_NOSCALE;
 		if (strcmp(transformMode, "noScaleOrReflection") == 0)
 			data->transformMode = SP_TRANSFORMMODE_NOSCALEORREFLECTION;
+		data->skinRequired = Json_getInt(boneMap, "skin", 0) ? 1 : 0;
 
 		skeletonData->bones[i] = data;
 		skeletonData->bonesCount++;
@@ -722,6 +726,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 
 			spIkConstraintData* data = spIkConstraintData_create(Json_getString(constraintMap, "name", 0));
 			data->order = Json_getInt(constraintMap, "order", 0);
+			data->skinRequired = Json_getInt(constraintMap, "skin", 0) ? 1 : 0;
 
 			boneMap = Json_getItem(constraintMap, "bones");
 			data->bonesCount = boneMap->size;
@@ -764,6 +769,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 
 			spTransformConstraintData* data = spTransformConstraintData_create(Json_getString(constraintMap, "name", 0));
 			data->order = Json_getInt(constraintMap, "order", 0);
+			data->skinRequired = Json_getInt(constraintMap, "skin", 0) ? 1 : 0;
 
 			boneMap = Json_getItem(constraintMap, "bones");
 			data->bonesCount = boneMap->size;
@@ -815,6 +821,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 
 			spPathConstraintData* data = spPathConstraintData_create(Json_getString(constraintMap, "name", 0));
 			data->order = Json_getInt(constraintMap, "order", 0);
+			data->skinRequired = Json_getInt(constraintMap, "skin", 0) ? 1 : 0;
 
 			boneMap = Json_getItem(constraintMap, "bones");
 			data->bonesCount = boneMap->size;
@@ -870,13 +877,66 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 		for (skinMap = skins->child, i = 0; skinMap; skinMap = skinMap->next, ++i) {
 			Json *attachmentsMap;
 			Json *curves;
-			spSkin *skin = spSkin_create(skinMap->name);
+			Json *skinPart;
+			spSkin *skin = spSkin_create(Json_getString(skinMap, "name", ""));
+
+			skinPart = Json_getItem(skinMap, "bones");
+			if (skinPart) {
+				for(skinPart = skinPart->child; skinPart; skinPart = skinPart->next) {
+					spBoneData* bone = spSkeletonData_findBone(skeletonData, skinPart->valueString);
+					if (!bone) {
+						spSkeletonData_dispose(skeletonData);
+						_spSkeletonJson_setError(self, root, "Skin bone constraint not found: ", skinPart->valueString);
+						return 0;
+					}
+					spBoneDataArray_add(skin->bones, bone);
+				}
+			}
+
+			skinPart = Json_getItem(skinMap, "ik");
+			if (skinPart) {
+				for(skinPart = skinPart->child; skinPart; skinPart = skinPart->next) {
+					spIkConstraintData* constraint = spSkeletonData_findIkConstraint(skeletonData, skinPart->valueString);
+					if (!constraint) {
+						spSkeletonData_dispose(skeletonData);
+						_spSkeletonJson_setError(self, root, "Skin IK constraint not found: ", skinPart->valueString);
+						return 0;
+					}
+					spIkConstraintDataArray_add(skin->ikConstraints, constraint);
+				}
+			}
+
+			skinPart = Json_getItem(skinMap, "path");
+			if (skinPart) {
+				for(skinPart = skinPart->child; skinPart; skinPart = skinPart->next) {
+					spPathConstraintData* constraint = spSkeletonData_findPathConstraint(skeletonData, skinPart->valueString);
+					if (!constraint) {
+						spSkeletonData_dispose(skeletonData);
+						_spSkeletonJson_setError(self, root, "Skin path constraint not found: ", skinPart->valueString);
+						return 0;
+					}
+					spPathConstraintDataArray_add(skin->pathConstraints, constraint);
+				}
+			}
+
+			skinPart = Json_getItem(skinMap, "transform");
+			if (skinPart) {
+				for(skinPart = skinPart->child; skinPart; skinPart = skinPart->next) {
+					spTransformConstraintData* constraint = spSkeletonData_findTransformConstraint(skeletonData, skinPart->valueString);
+					if (!constraint) {
+						spSkeletonData_dispose(skeletonData);
+						_spSkeletonJson_setError(self, root, "Skin transform constraint not found: ", skinPart->valueString);
+						return 0;
+					}
+					spTransformConstraintDataArray_add(skin->transformConstraints, constraint);
+				}
+			}
 
 			skeletonData->skins[skeletonData->skinsCount++] = skin;
-			if (strcmp(skinMap->name, "default") == 0) skeletonData->defaultSkin = skin;
+			if (strcmp(skin->name, "default") == 0) skeletonData->defaultSkin = skin;
 
-			for (attachmentsMap = skinMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) {
-				int slotIndex = spSkeletonData_findSlotIndex(skeletonData, attachmentsMap->name);
+			for (attachmentsMap = Json_getItem(skinMap, "attachments")->child; attachmentsMap; attachmentsMap = attachmentsMap->next) {
+				spSlotData* slot = spSkeletonData_findSlot(skeletonData, attachmentsMap->name);
 				Json *attachmentMap;
 
 				for (attachmentMap = attachmentsMap->child; attachmentMap; attachmentMap = attachmentMap->next) {
@@ -995,7 +1055,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 							spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment);
 						} else {
 							int inheritDeform = Json_getInt(attachmentMap, "deform", 1);
-							_spSkeletonJson_addLinkedMesh(self, SUB_CAST(spMeshAttachment, attachment), Json_getString(attachmentMap, "skin", 0), slotIndex,
+							_spSkeletonJson_addLinkedMesh(self, SUB_CAST(spMeshAttachment, attachment), Json_getString(attachmentMap, "skin", 0), slot->index,
 									entry->valueString, inheritDeform);
 						}
 						break;
@@ -1046,8 +1106,8 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 						int vertexCount = 0;
 						const char* end = Json_getString(attachmentMap, "end", 0);
 						if (end) {
-							spSlotData* slot = spSkeletonData_findSlot(skeletonData, end);
-							clip->endSlot = slot;
+							spSlotData* endSlot = spSkeletonData_findSlot(skeletonData, end);
+							clip->endSlot = endSlot;
 						}
 						vertexCount = Json_getInt(attachmentMap, "vertexCount", 0) << 1;
 						_readVertices(self, attachmentMap, SUPER(clip), vertexCount);
@@ -1056,7 +1116,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 					}
 					}
 
-					spSkin_setAttachment(skin, slotIndex, skinAttachmentName, attachment);
+					spSkin_setAttachment(skin, slot->index, skinAttachmentName, attachment);
 				}
 			}
 		}