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

[c] Added soft IK support. See #1383.

badlogic 6 жил өмнө
parent
commit
7a19650b5b

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

@@ -431,7 +431,7 @@ typedef spDeformTimeline DeformTimeline;
 
 /**/
 
-static const int IKCONSTRAINT_ENTRIES = 5;
+static const int IKCONSTRAINT_ENTRIES = 6;
 
 typedef struct spIkConstraintTimeline {
 	spCurveTimeline super;
@@ -451,7 +451,7 @@ typedef struct spIkConstraintTimeline {
 
 SP_API spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount);
 
-SP_API void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection, int /*boolean*/ compress, int /**boolean**/ stretch);
+SP_API void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, float softness, int bendDirection, int /*boolean*/ compress, int /**boolean**/ stretch);
 
 #ifdef SPINE_SHORT_NAMES
 typedef spIkConstraintTimeline IkConstraintTimeline;

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

@@ -51,6 +51,7 @@ typedef struct spIkConstraint {
 	int /*boolean*/ compress;
 	int /*boolean*/ stretch;
 	float mix;
+	float softness;
 
 	int /*boolean*/ active;
 
@@ -63,6 +64,7 @@ typedef struct spIkConstraint {
 		bendDirection(0),
 		stretch(0),
 		mix(0),
+		softness(0),
 		active(0) {
 	}
 #endif
@@ -74,7 +76,7 @@ SP_API void spIkConstraint_dispose (spIkConstraint* self);
 SP_API void spIkConstraint_apply (spIkConstraint* self);
 
 SP_API void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, int /*boolean*/ compress, int /*boolean*/ stretch, int /*boolean*/ uniform, float alpha);
-SP_API void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, int /*boolean*/ stretch, float alpha);
+SP_API void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, int /*boolean*/ stretch, float softness, float alpha);
 
 #ifdef SPINE_SHORT_NAMES
 typedef spIkConstraint IkConstraint;

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

@@ -50,6 +50,7 @@ typedef struct spIkConstraintData {
 	int /*boolean*/ stretch;
 	int /*boolean*/ uniform;
 	float mix;
+	float softness;
 
 #ifdef __cplusplus
 	spIkConstraintData() :
@@ -63,7 +64,8 @@ typedef struct spIkConstraintData {
 		compress(0),
 		stretch(0),
 		uniform(0),
-		mix(0) {
+		mix(0),
+		softness(0) {
 	}
 #endif
 } spIkConstraintData;

+ 14 - 4
spine-c/spine-c/src/spine/Animation.c

@@ -1290,13 +1290,13 @@ void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, fl
 
 /**/
 
-static const int IKCONSTRAINT_PREV_TIME = -5, IKCONSTRAINT_PREV_MIX = -4, IKCONSTRAINT_PREV_BEND_DIRECTION = -3, IKCONSTRAINT_PREV_COMPRESS = -2, IKCONSTRAINT_PREV_STRETCH = -1;
-static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2, IKCONSTRAINT_COMPRESS = 3, IKCONSTRAINT_STRETCH = 4;
+static const int IKCONSTRAINT_PREV_TIME = -6, IKCONSTRAINT_PREV_MIX = -5, IKCONSTRAINT_PREV_SOFTNESS = -4, IKCONSTRAINT_PREV_BEND_DIRECTION = -3, IKCONSTRAINT_PREV_COMPRESS = -2, IKCONSTRAINT_PREV_STRETCH = -1;
+static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_SOFTNESS = 2, IKCONSTRAINT_BEND_DIRECTION = 3, IKCONSTRAINT_COMPRESS = 4, IKCONSTRAINT_STRETCH = 5;
 
 void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
 		spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
 	int frame;
-	float frameTime, percent, mix;
+	float frameTime, percent, mix, softness;
 	float *frames;
 	int framesCount;
 	spIkConstraint* constraint;
@@ -1309,12 +1309,14 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
 		switch (blend) {
 			case SP_MIX_BLEND_SETUP:
 				constraint->mix = constraint->data->mix;
+				constraint->softness = constraint->data->softness;
 				constraint->bendDirection = constraint->data->bendDirection;
 				constraint->compress = constraint->data->compress;
 				constraint->stretch = constraint->data->stretch;
 				return;
 			case SP_MIX_BLEND_FIRST:
 				constraint->mix += (constraint->data->mix - constraint->mix) * alpha;
+				constraint->softness += (constraint->data->softness - constraint->softness) * alpha;
 				constraint->bendDirection = constraint->data->bendDirection;
 				constraint->compress = constraint->data->compress;
 				constraint->stretch = constraint->data->stretch;
@@ -1330,6 +1332,8 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
 	if (time >= frames[framesCount - IKCONSTRAINT_ENTRIES]) { /* Time is after last frame. */
 		if (blend == SP_MIX_BLEND_SETUP) {
 			constraint->mix = constraint->data->mix + (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->data->mix) * alpha;
+			constraint->softness = constraint->data->softness
+								  + (frames[framesCount + IKCONSTRAINT_PREV_SOFTNESS] - constraint->data->softness) * alpha;
 			if (direction == SP_MIX_DIRECTION_OUT) {
 				constraint->bendDirection = constraint->data->bendDirection;
 				constraint->compress = constraint->data->compress;
@@ -1341,6 +1345,7 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
 			}
 		} else {
 			constraint->mix += (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->mix) * alpha;
+			constraint->softness += (frames[framesCount + IKCONSTRAINT_PREV_SOFTNESS] - constraint->softness) * alpha;
 			if (direction == SP_MIX_DIRECTION_IN) {
 				constraint->bendDirection = (int)frames[framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION];
 				constraint->compress = frames[framesCount + IKCONSTRAINT_PREV_COMPRESS] ? 1 : 0;
@@ -1353,11 +1358,14 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
 	/* Interpolate between the previous frame and the current frame. */
 	frame = binarySearch(self->frames, self->framesCount, time, IKCONSTRAINT_ENTRIES);
 	mix = self->frames[frame + IKCONSTRAINT_PREV_MIX];
+	softness = frames[frame + IKCONSTRAINT_PREV_SOFTNESS];
 	frameTime = self->frames[frame];
 	percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / IKCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + IKCONSTRAINT_PREV_TIME] - frameTime));
 
 	if (blend == SP_MIX_BLEND_SETUP) {
 		constraint->mix = constraint->data->mix + (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->data->mix) * alpha;
+		constraint->softness = constraint->data->softness
+							  + (softness + (frames[frame + IKCONSTRAINT_SOFTNESS] - softness) * percent - constraint->data->softness) * alpha;
 		if (direction == SP_MIX_DIRECTION_OUT) {
 			constraint->bendDirection = constraint->data->bendDirection;
 			constraint->compress = constraint->data->compress;
@@ -1369,6 +1377,7 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
 		}
 	} else {
 		constraint->mix += (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->mix) * alpha;
+		constraint->softness += (softness + (frames[frame + IKCONSTRAINT_SOFTNESS] - softness) * percent - constraint->softness) * alpha;
 		if (direction == SP_MIX_DIRECTION_IN) {
 			constraint->bendDirection = (int)frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION];
 			constraint->compress = frames[frame + IKCONSTRAINT_PREV_COMPRESS] ? 1 : 0;
@@ -1389,10 +1398,11 @@ spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount) {
 	return (spIkConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_IKCONSTRAINT, IKCONSTRAINT_ENTRIES, _spIkConstraintTimeline_apply, _spIkConstraintTimeline_getPropertyId);
 }
 
-void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection, int /*boolean*/ compress, int /*boolean*/ stretch) {
+void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, float softness, int bendDirection, int /*boolean*/ compress, int /*boolean*/ stretch) {
 	frameIndex *= IKCONSTRAINT_ENTRIES;
 	self->frames[frameIndex] = time;
 	self->frames[frameIndex + IKCONSTRAINT_MIX] = mix;
+	self->frames[frameIndex + IKCONSTRAINT_SOFTNESS] = softness;
 	self->frames[frameIndex + IKCONSTRAINT_BEND_DIRECTION] = (float)bendDirection;
 	self->frames[frameIndex + IKCONSTRAINT_COMPRESS] = compress ? 1 : 0;
 	self->frames[frameIndex + IKCONSTRAINT_STRETCH] = stretch ? 1 : 0;

+ 35 - 12
spine-c/spine-c/src/spine/IkConstraint.c

@@ -41,6 +41,7 @@ spIkConstraint *spIkConstraint_create(spIkConstraintData *data, const spSkeleton
 	self->compress = data->compress;
 	self->stretch = data->stretch;
 	self->mix = data->mix;
+	self->softness = data->softness;
 
 	self->bonesCount = self->data->bonesCount;
 	self->bones = MALLOC(spBone*, self->bonesCount);
@@ -62,7 +63,7 @@ void spIkConstraint_apply(spIkConstraint *self) {
 			spIkConstraint_apply1(self->bones[0], self->target->worldX, self->target->worldY, self->compress, self->stretch, self->data->uniform, self->mix);
 			break;
 		case 2:
-			spIkConstraint_apply2(self->bones[0], self->bones[1], self->target->worldX, self->target->worldY, self->bendDirection, self->stretch, self->mix);
+			spIkConstraint_apply2(self->bones[0], self->bones[1], self->target->worldX, self->target->worldY, self->bendDirection, self->stretch, self->softness, self->mix);
 			break;
 	}
 }
@@ -92,12 +93,13 @@ void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, int /*bo
 		sy, bone->ashearX, bone->ashearY);
 }
 
-void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, int /*boolean*/ stretch, float alpha) {
+void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, int /*boolean*/ stretch, float softness, float alpha) {
+	float a, b, c, d;
 	float px, py, psx, sx, psy;
 	float cx, cy, csx, cwx, cwy;
 	int o1, o2, s2, u;
 	spBone* pp = parent->parent;
-	float tx, ty, dd, dx, dy, l1, l2, a1, a2, r;
+	float tx, ty, dd, dx, dy, l1, l2, a1, a2, r, td, sd, p;
 	float id, x, y;
 	if (alpha == 0) {
 		spBone_updateWorldTransform(child);
@@ -135,18 +137,39 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
 		cwx = parent->a * cx + parent->b * cy + parent->worldX;
 		cwy = parent->c * cx + parent->d * cy + parent->worldY;
 	}
-	id = 1 / (pp->a * pp->d - pp->b * pp->c);
-	x = targetX - pp->worldX;
-	y = targetY - pp->worldY;
-	tx = (x * pp->d - y * pp->b) * id - px;
-	ty = (y * pp->a - x * pp->c) * id - py;
-	dd = tx * tx + ty * ty;
+	a = pp->a;
+	b = pp->b;
+	c = pp->c;
+	d = pp->d;
+	id = 1 / (a * d - b * c);
 	x = cwx - pp->worldX;
 	y = cwy - pp->worldY;
-	dx = (x * pp->d - y * pp->b) * id - px;
-	dy = (y * pp->a - x * pp->c) * id - py;
+	dx = (x * d - y * b) * id - px;
+	dy = (y * a - x * c) * id - py;
 	l1 = SQRT(dx * dx + dy * dy);
 	l2 = child->data->length * csx;
+	if (l1 < 0.0001) {
+		spIkConstraint_apply1(parent, targetX, targetY, 0, stretch, 0, alpha);
+		spBone_updateWorldTransformWith(child, cx, cy, 0, child->ascaleX, child->ascaleY, child->ashearX, child->ashearY);
+		return;
+	}
+	x = targetX - pp->worldX;
+	y = targetY - pp->worldY;
+	tx = (x * d - y * b) * id - px;
+	ty = (y * a - x * c) * id - py;
+	dd = tx * tx + ty * ty;
+	if (softness != 0) {
+		softness *= psx * (csx + 1) / 2;
+		td = SQRT(dd);
+		sd = td - l1 - l2 * psx + softness;
+		if (sd > 0) {
+			p = MIN(1, sd / (softness * 2)) - 1;
+			p = (sd - softness * (1 - p * p)) / td;
+			tx -= p * tx;
+			ty -= p * ty;
+			dd = tx * tx + ty * ty;
+		}
+	}
 	if (u) {
 		float cosine, a, b;
 		l2 *= psx;
@@ -154,7 +177,7 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
 		if (cosine < -1) cosine = -1;
 		else if (cosine > 1) {
 			cosine = 1;
-			if (stretch && l1 + l2 > 0.0001f) sx *= (SQRT(dd) / (l1 + l2) - 1) * alpha + 1;
+			if (stretch) sx *= (SQRT(dd) / (l1 + l2) - 1) * alpha + 1;
 		}
 		a2 = ACOS(cosine) * bendDir;
 		a = l1 + l2 * cosine;

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

@@ -465,6 +465,7 @@ void spSkeleton_setBonesToSetupPose (const spSkeleton* self) {
 		ikConstraint->bendDirection = ikConstraint->data->bendDirection;
 		ikConstraint->compress = ikConstraint->data->compress;
 		ikConstraint->stretch = ikConstraint->data->stretch;
+		ikConstraint->softness = ikConstraint->data->softness;
 		ikConstraint->mix = ikConstraint->data->mix;
 	}
 

+ 3 - 1
spine-c/spine-c/src/spine/SkeletonBinary.c

@@ -390,10 +390,11 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
 		for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
 			float time = readFloat(input);
 			float mix = readFloat(input);
+			float softness = readFloat(input);
 			signed char bendDirection = readSByte(input);
 			int compress = readBoolean(input);
 			int stretch = readBoolean(input);
-			spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection, compress, stretch);
+			spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, softness, bendDirection, compress, stretch);
 			if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex);
 		}
 		spTimelineArray_add(timelines, (spTimeline*)timeline);
@@ -991,6 +992,7 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
 			data->bones[ii] = skeletonData->bones[readVarint(input, 1)];
 		data->target = skeletonData->bones[readVarint(input, 1)];
 		data->mix = readFloat(input);
+		data->softness = readFloat(input);
 		data->bendDirection = readSByte(input);
 		data->compress = readBoolean(input);
 		data->stretch = readBoolean(input);

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

@@ -302,7 +302,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
 			}
 		}
 		for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) {
-			spIkConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "mix", 1),
+			spIkConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "mix", 1), Json_getFloat(valueMap, "softness", 0),
 					Json_getInt(valueMap, "bendPositive", 1) ? 1 : -1, Json_getInt(valueMap, "compress", 0) ? 1 : 0, Json_getInt(valueMap, "stretch", 0) ? 1 : 0);
 			readCurve(valueMap, SUPER(timeline), frameIndex);
 		}
@@ -753,6 +753,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
 			data->stretch = Json_getInt(constraintMap, "stretch", 0) ? 1 : 0;
 			data->uniform = Json_getInt(constraintMap, "uniform", 0) ? 1 : 0;
 			data->mix = Json_getFloat(constraintMap, "mix", 1);
+			data->softness = Json_getFloat(constraintMap, "softness", 0);
 
 			skeletonData->ikConstraints[i] = data;
 		}