Browse Source

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

badlogic 6 years ago
parent
commit
5776e2467a

+ 6 - 2
spine-ts/build/spine-all.d.ts

@@ -175,10 +175,12 @@ declare module spine {
 		static ENTRIES: number;
 		static ENTRIES: number;
 		static PREV_TIME: number;
 		static PREV_TIME: number;
 		static PREV_MIX: number;
 		static PREV_MIX: number;
+		static PREV_SOFTNESS: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_COMPRESS: number;
 		static PREV_COMPRESS: number;
 		static PREV_STRETCH: number;
 		static PREV_STRETCH: number;
 		static MIX: number;
 		static MIX: number;
+		static SOFTNESS: number;
 		static BEND_DIRECTION: number;
 		static BEND_DIRECTION: number;
 		static COMPRESS: number;
 		static COMPRESS: number;
 		static STRETCH: number;
 		static STRETCH: number;
@@ -186,7 +188,7 @@ declare module spine {
 		frames: ArrayLike<number>;
 		frames: ArrayLike<number>;
 		constructor(frameCount: number);
 		constructor(frameCount: number);
 		getPropertyId(): number;
 		getPropertyId(): number;
-		setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean): void;
+		setFrame(frameIndex: number, time: number, mix: number, softness: number, bendDirection: number, compress: boolean, stretch: boolean): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 	}
 	}
 	class TransformConstraintTimeline extends CurveTimeline {
 	class TransformConstraintTimeline extends CurveTimeline {
@@ -534,13 +536,14 @@ declare module spine {
 		compress: boolean;
 		compress: boolean;
 		stretch: boolean;
 		stretch: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		active: boolean;
 		active: boolean;
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		isActive(): boolean;
 		isActive(): boolean;
 		apply(): void;
 		apply(): void;
 		update(): void;
 		update(): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
-		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number): void;
+		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, softness: number, alpha: number): void;
 	}
 	}
 }
 }
 declare module spine {
 declare module spine {
@@ -552,6 +555,7 @@ declare module spine {
 		stretch: boolean;
 		stretch: boolean;
 		uniform: boolean;
 		uniform: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		constructor(name: string);
 		constructor(name: string);
 	}
 	}
 }
 }

+ 52 - 17
spine-ts/build/spine-all.js

@@ -981,10 +981,11 @@ var spine;
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 		};
 		};
-		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) {
+		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, softness, bendDirection, compress, stretch) {
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
+			this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
@@ -998,12 +999,14 @@ var spine;
 				switch (blend) {
 				switch (blend) {
 					case MixBlend.setup:
 					case MixBlend.setup:
 						constraint.mix = constraint.data.mix;
 						constraint.mix = constraint.data.mix;
+						constraint.softness = constraint.data.softness;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
 						return;
 						return;
 					case MixBlend.first:
 					case MixBlend.first:
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
+						constraint.softness += (constraint.data.softness - constraint.softness) * alpha;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
@@ -1013,6 +1016,8 @@ var spine;
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 				if (blend == MixBlend.setup) {
 				if (blend == MixBlend.setup) {
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
+					constraint.softness = constraint.data.softness
+						+ (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha;
 					if (direction == MixDirection.mixOut) {
 					if (direction == MixDirection.mixOut) {
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
@@ -1026,6 +1031,7 @@ var spine;
 				}
 				}
 				else {
 				else {
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
+					constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha;
 					if (direction == MixDirection.mixIn) {
 					if (direction == MixDirection.mixIn) {
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1036,10 +1042,13 @@ var spine;
 			}
 			}
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
+			var softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS];
 			var frameTime = frames[frame];
 			var frameTime = frames[frame];
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			if (blend == MixBlend.setup) {
 			if (blend == MixBlend.setup) {
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
+				constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha;
 				if (direction == MixDirection.mixOut) {
 				if (direction == MixDirection.mixOut) {
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
@@ -1053,6 +1062,7 @@ var spine;
 			}
 			}
 			else {
 			else {
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
+				constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha;
 				if (direction == MixDirection.mixIn) {
 				if (direction == MixDirection.mixIn) {
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1060,16 +1070,18 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		IkConstraintTimeline.ENTRIES = 5;
-		IkConstraintTimeline.PREV_TIME = -5;
-		IkConstraintTimeline.PREV_MIX = -4;
+		IkConstraintTimeline.ENTRIES = 6;
+		IkConstraintTimeline.PREV_TIME = -6;
+		IkConstraintTimeline.PREV_MIX = -5;
+		IkConstraintTimeline.PREV_SOFTNESS = -4;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.MIX = 1;
 		IkConstraintTimeline.MIX = 1;
-		IkConstraintTimeline.BEND_DIRECTION = 2;
-		IkConstraintTimeline.COMPRESS = 3;
-		IkConstraintTimeline.STRETCH = 4;
+		IkConstraintTimeline.SOFTNESS = 2;
+		IkConstraintTimeline.BEND_DIRECTION = 3;
+		IkConstraintTimeline.COMPRESS = 4;
+		IkConstraintTimeline.STRETCH = 5;
 		return IkConstraintTimeline;
 		return IkConstraintTimeline;
 	}(CurveTimeline));
 	}(CurveTimeline));
 	spine.IkConstraintTimeline = IkConstraintTimeline;
 	spine.IkConstraintTimeline = IkConstraintTimeline;
@@ -2775,6 +2787,7 @@ var spine;
 			this.compress = false;
 			this.compress = false;
 			this.stretch = false;
 			this.stretch = false;
 			this.mix = 1;
 			this.mix = 1;
+			this.softness = 0;
 			this.active = false;
 			this.active = false;
 			if (data == null)
 			if (data == null)
 				throw new Error("data cannot be null.");
 				throw new Error("data cannot be null.");
@@ -2782,6 +2795,7 @@ var spine;
 				throw new Error("skeleton cannot be null.");
 				throw new Error("skeleton cannot be null.");
 			this.data = data;
 			this.data = data;
 			this.mix = data.mix;
 			this.mix = data.mix;
+			this.softness = data.softness;
 			this.bendDirection = data.bendDirection;
 			this.bendDirection = data.bendDirection;
 			this.compress = data.compress;
 			this.compress = data.compress;
 			this.stretch = data.stretch;
 			this.stretch = data.stretch;
@@ -2804,7 +2818,7 @@ var spine;
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					break;
 					break;
 				case 2:
 				case 2:
-					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
+					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix);
 					break;
 					break;
 			}
 			}
 		};
 		};
@@ -2834,7 +2848,7 @@ var spine;
 			}
 			}
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 		};
 		};
-		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) {
+		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) {
 			if (alpha == 0) {
 			if (alpha == 0) {
 				child.updateWorldTransform();
 				child.updateWorldTransform();
 				return;
 				return;
@@ -2881,12 +2895,29 @@ var spine;
 			b = pp.b;
 			b = pp.b;
 			c = pp.c;
 			c = pp.c;
 			d = pp.d;
 			d = pp.d;
-			var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY;
-			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty;
-			x = cwx - pp.worldX;
-			y = cwy - pp.worldY;
+			var id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
-			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0;
+			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
+			if (l1 < 0.0001) {
+				this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
+				child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
+				return;
+			}
+			x = targetX - pp.worldX;
+			y = targetY - pp.worldY;
+			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
+			var dd = tx * tx + ty * ty;
+			if (softness != 0) {
+				softness *= psx * (csx + 1) / 2;
+				var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
+				if (sd > 0) {
+					var p = Math.min(1, sd / (softness * 2)) - 1;
+					p = (sd - softness * (1 - p * p)) / td;
+					tx -= p * tx;
+					ty -= p * ty;
+					dd = tx * tx + ty * ty;
+				}
+			}
 			outer: if (u) {
 			outer: if (u) {
 				l2 *= psx;
 				l2 *= psx;
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@@ -2894,7 +2925,7 @@ var spine;
 					cos = -1;
 					cos = -1;
 				else if (cos > 1) {
 				else if (cos > 1) {
 					cos = 1;
 					cos = 1;
-					if (stretch && l1 + l2 > 0.0001)
+					if (stretch)
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 				}
 				}
 				a2 = Math.acos(cos) * bendDir;
 				a2 = Math.acos(cos) * bendDir;
@@ -2985,6 +3016,7 @@ var spine;
 			_this.stretch = false;
 			_this.stretch = false;
 			_this.uniform = false;
 			_this.uniform = false;
 			_this.mix = 1;
 			_this.mix = 1;
+			_this.softness = 0;
 			return _this;
 			return _this;
 		}
 		}
 		return IkConstraintData;
 		return IkConstraintData;
@@ -3804,6 +3836,7 @@ var spine;
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 				var constraint = ikConstraints[i];
 				var constraint = ikConstraints[i];
 				constraint.mix = constraint.data.mix;
 				constraint.mix = constraint.data.mix;
+				constraint.softness = constraint.data.softness;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.compress = constraint.data.compress;
 				constraint.compress = constraint.data.compress;
 				constraint.stretch = constraint.data.stretch;
 				constraint.stretch = constraint.data.stretch;
@@ -4090,6 +4123,7 @@ var spine;
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.mix = input.readFloat();
 				data.mix = input.readFloat();
+				data.softness = input.readFloat();
 				data.bendDirection = input.readByte();
 				data.bendDirection = input.readByte();
 				data.compress = input.readBoolean();
 				data.compress = input.readBoolean();
 				data.stretch = input.readBoolean();
 				data.stretch = input.readBoolean();
@@ -4521,7 +4555,7 @@ var spine;
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				timeline.ikConstraintIndex = index;
 				timeline.ikConstraintIndex = index;
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
-					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
+					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
 					if (frameIndex < frameCount - 1)
 					if (frameIndex < frameCount - 1)
 						this.readCurve(input, frameIndex, timeline);
 						this.readCurve(input, frameIndex, timeline);
 				}
 				}
@@ -5505,6 +5539,7 @@ var spine;
 					if (data.target == null)
 					if (data.target == null)
 						throw new Error("IK target bone not found: " + targetName);
 						throw new Error("IK target bone not found: " + targetName);
 					data.mix = this.getValue(constraintMap, "mix", 1);
 					data.mix = this.getValue(constraintMap, "mix", 1);
+					data.softness = this.getValue(constraintMap, "softness", 0);
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
@@ -5922,7 +5957,7 @@ var spine;
 					var frameIndex = 0;
 					var frameIndex = 0;
 					for (var i = 0; i < constraintMap.length; i++) {
 					for (var i = 0; i < constraintMap.length; i++) {
 						var valueMap = constraintMap[i];
 						var valueMap = constraintMap[i];
-						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
+						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 						this.readCurve(valueMap, timeline, frameIndex);
 						this.readCurve(valueMap, timeline, frameIndex);
 						frameIndex++;
 						frameIndex++;
 					}
 					}

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-all.js.map


+ 6 - 2
spine-ts/build/spine-canvas.d.ts

@@ -175,10 +175,12 @@ declare module spine {
 		static ENTRIES: number;
 		static ENTRIES: number;
 		static PREV_TIME: number;
 		static PREV_TIME: number;
 		static PREV_MIX: number;
 		static PREV_MIX: number;
+		static PREV_SOFTNESS: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_COMPRESS: number;
 		static PREV_COMPRESS: number;
 		static PREV_STRETCH: number;
 		static PREV_STRETCH: number;
 		static MIX: number;
 		static MIX: number;
+		static SOFTNESS: number;
 		static BEND_DIRECTION: number;
 		static BEND_DIRECTION: number;
 		static COMPRESS: number;
 		static COMPRESS: number;
 		static STRETCH: number;
 		static STRETCH: number;
@@ -186,7 +188,7 @@ declare module spine {
 		frames: ArrayLike<number>;
 		frames: ArrayLike<number>;
 		constructor(frameCount: number);
 		constructor(frameCount: number);
 		getPropertyId(): number;
 		getPropertyId(): number;
-		setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean): void;
+		setFrame(frameIndex: number, time: number, mix: number, softness: number, bendDirection: number, compress: boolean, stretch: boolean): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 	}
 	}
 	class TransformConstraintTimeline extends CurveTimeline {
 	class TransformConstraintTimeline extends CurveTimeline {
@@ -534,13 +536,14 @@ declare module spine {
 		compress: boolean;
 		compress: boolean;
 		stretch: boolean;
 		stretch: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		active: boolean;
 		active: boolean;
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		isActive(): boolean;
 		isActive(): boolean;
 		apply(): void;
 		apply(): void;
 		update(): void;
 		update(): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
-		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number): void;
+		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, softness: number, alpha: number): void;
 	}
 	}
 }
 }
 declare module spine {
 declare module spine {
@@ -552,6 +555,7 @@ declare module spine {
 		stretch: boolean;
 		stretch: boolean;
 		uniform: boolean;
 		uniform: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		constructor(name: string);
 		constructor(name: string);
 	}
 	}
 }
 }

+ 52 - 17
spine-ts/build/spine-canvas.js

@@ -981,10 +981,11 @@ var spine;
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 		};
 		};
-		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) {
+		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, softness, bendDirection, compress, stretch) {
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
+			this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
@@ -998,12 +999,14 @@ var spine;
 				switch (blend) {
 				switch (blend) {
 					case MixBlend.setup:
 					case MixBlend.setup:
 						constraint.mix = constraint.data.mix;
 						constraint.mix = constraint.data.mix;
+						constraint.softness = constraint.data.softness;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
 						return;
 						return;
 					case MixBlend.first:
 					case MixBlend.first:
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
+						constraint.softness += (constraint.data.softness - constraint.softness) * alpha;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
@@ -1013,6 +1016,8 @@ var spine;
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 				if (blend == MixBlend.setup) {
 				if (blend == MixBlend.setup) {
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
+					constraint.softness = constraint.data.softness
+						+ (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha;
 					if (direction == MixDirection.mixOut) {
 					if (direction == MixDirection.mixOut) {
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
@@ -1026,6 +1031,7 @@ var spine;
 				}
 				}
 				else {
 				else {
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
+					constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha;
 					if (direction == MixDirection.mixIn) {
 					if (direction == MixDirection.mixIn) {
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1036,10 +1042,13 @@ var spine;
 			}
 			}
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
+			var softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS];
 			var frameTime = frames[frame];
 			var frameTime = frames[frame];
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			if (blend == MixBlend.setup) {
 			if (blend == MixBlend.setup) {
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
+				constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha;
 				if (direction == MixDirection.mixOut) {
 				if (direction == MixDirection.mixOut) {
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
@@ -1053,6 +1062,7 @@ var spine;
 			}
 			}
 			else {
 			else {
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
+				constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha;
 				if (direction == MixDirection.mixIn) {
 				if (direction == MixDirection.mixIn) {
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1060,16 +1070,18 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		IkConstraintTimeline.ENTRIES = 5;
-		IkConstraintTimeline.PREV_TIME = -5;
-		IkConstraintTimeline.PREV_MIX = -4;
+		IkConstraintTimeline.ENTRIES = 6;
+		IkConstraintTimeline.PREV_TIME = -6;
+		IkConstraintTimeline.PREV_MIX = -5;
+		IkConstraintTimeline.PREV_SOFTNESS = -4;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.MIX = 1;
 		IkConstraintTimeline.MIX = 1;
-		IkConstraintTimeline.BEND_DIRECTION = 2;
-		IkConstraintTimeline.COMPRESS = 3;
-		IkConstraintTimeline.STRETCH = 4;
+		IkConstraintTimeline.SOFTNESS = 2;
+		IkConstraintTimeline.BEND_DIRECTION = 3;
+		IkConstraintTimeline.COMPRESS = 4;
+		IkConstraintTimeline.STRETCH = 5;
 		return IkConstraintTimeline;
 		return IkConstraintTimeline;
 	}(CurveTimeline));
 	}(CurveTimeline));
 	spine.IkConstraintTimeline = IkConstraintTimeline;
 	spine.IkConstraintTimeline = IkConstraintTimeline;
@@ -2775,6 +2787,7 @@ var spine;
 			this.compress = false;
 			this.compress = false;
 			this.stretch = false;
 			this.stretch = false;
 			this.mix = 1;
 			this.mix = 1;
+			this.softness = 0;
 			this.active = false;
 			this.active = false;
 			if (data == null)
 			if (data == null)
 				throw new Error("data cannot be null.");
 				throw new Error("data cannot be null.");
@@ -2782,6 +2795,7 @@ var spine;
 				throw new Error("skeleton cannot be null.");
 				throw new Error("skeleton cannot be null.");
 			this.data = data;
 			this.data = data;
 			this.mix = data.mix;
 			this.mix = data.mix;
+			this.softness = data.softness;
 			this.bendDirection = data.bendDirection;
 			this.bendDirection = data.bendDirection;
 			this.compress = data.compress;
 			this.compress = data.compress;
 			this.stretch = data.stretch;
 			this.stretch = data.stretch;
@@ -2804,7 +2818,7 @@ var spine;
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					break;
 					break;
 				case 2:
 				case 2:
-					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
+					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix);
 					break;
 					break;
 			}
 			}
 		};
 		};
@@ -2834,7 +2848,7 @@ var spine;
 			}
 			}
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 		};
 		};
-		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) {
+		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) {
 			if (alpha == 0) {
 			if (alpha == 0) {
 				child.updateWorldTransform();
 				child.updateWorldTransform();
 				return;
 				return;
@@ -2881,12 +2895,29 @@ var spine;
 			b = pp.b;
 			b = pp.b;
 			c = pp.c;
 			c = pp.c;
 			d = pp.d;
 			d = pp.d;
-			var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY;
-			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty;
-			x = cwx - pp.worldX;
-			y = cwy - pp.worldY;
+			var id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
-			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0;
+			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
+			if (l1 < 0.0001) {
+				this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
+				child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
+				return;
+			}
+			x = targetX - pp.worldX;
+			y = targetY - pp.worldY;
+			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
+			var dd = tx * tx + ty * ty;
+			if (softness != 0) {
+				softness *= psx * (csx + 1) / 2;
+				var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
+				if (sd > 0) {
+					var p = Math.min(1, sd / (softness * 2)) - 1;
+					p = (sd - softness * (1 - p * p)) / td;
+					tx -= p * tx;
+					ty -= p * ty;
+					dd = tx * tx + ty * ty;
+				}
+			}
 			outer: if (u) {
 			outer: if (u) {
 				l2 *= psx;
 				l2 *= psx;
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@@ -2894,7 +2925,7 @@ var spine;
 					cos = -1;
 					cos = -1;
 				else if (cos > 1) {
 				else if (cos > 1) {
 					cos = 1;
 					cos = 1;
-					if (stretch && l1 + l2 > 0.0001)
+					if (stretch)
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 				}
 				}
 				a2 = Math.acos(cos) * bendDir;
 				a2 = Math.acos(cos) * bendDir;
@@ -2985,6 +3016,7 @@ var spine;
 			_this.stretch = false;
 			_this.stretch = false;
 			_this.uniform = false;
 			_this.uniform = false;
 			_this.mix = 1;
 			_this.mix = 1;
+			_this.softness = 0;
 			return _this;
 			return _this;
 		}
 		}
 		return IkConstraintData;
 		return IkConstraintData;
@@ -3804,6 +3836,7 @@ var spine;
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 				var constraint = ikConstraints[i];
 				var constraint = ikConstraints[i];
 				constraint.mix = constraint.data.mix;
 				constraint.mix = constraint.data.mix;
+				constraint.softness = constraint.data.softness;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.compress = constraint.data.compress;
 				constraint.compress = constraint.data.compress;
 				constraint.stretch = constraint.data.stretch;
 				constraint.stretch = constraint.data.stretch;
@@ -4090,6 +4123,7 @@ var spine;
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.mix = input.readFloat();
 				data.mix = input.readFloat();
+				data.softness = input.readFloat();
 				data.bendDirection = input.readByte();
 				data.bendDirection = input.readByte();
 				data.compress = input.readBoolean();
 				data.compress = input.readBoolean();
 				data.stretch = input.readBoolean();
 				data.stretch = input.readBoolean();
@@ -4521,7 +4555,7 @@ var spine;
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				timeline.ikConstraintIndex = index;
 				timeline.ikConstraintIndex = index;
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
-					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
+					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
 					if (frameIndex < frameCount - 1)
 					if (frameIndex < frameCount - 1)
 						this.readCurve(input, frameIndex, timeline);
 						this.readCurve(input, frameIndex, timeline);
 				}
 				}
@@ -5505,6 +5539,7 @@ var spine;
 					if (data.target == null)
 					if (data.target == null)
 						throw new Error("IK target bone not found: " + targetName);
 						throw new Error("IK target bone not found: " + targetName);
 					data.mix = this.getValue(constraintMap, "mix", 1);
 					data.mix = this.getValue(constraintMap, "mix", 1);
+					data.softness = this.getValue(constraintMap, "softness", 0);
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
@@ -5922,7 +5957,7 @@ var spine;
 					var frameIndex = 0;
 					var frameIndex = 0;
 					for (var i = 0; i < constraintMap.length; i++) {
 					for (var i = 0; i < constraintMap.length; i++) {
 						var valueMap = constraintMap[i];
 						var valueMap = constraintMap[i];
-						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
+						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 						this.readCurve(valueMap, timeline, frameIndex);
 						this.readCurve(valueMap, timeline, frameIndex);
 						frameIndex++;
 						frameIndex++;
 					}
 					}

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-canvas.js.map


+ 6 - 2
spine-ts/build/spine-core.d.ts

@@ -175,10 +175,12 @@ declare module spine {
 		static ENTRIES: number;
 		static ENTRIES: number;
 		static PREV_TIME: number;
 		static PREV_TIME: number;
 		static PREV_MIX: number;
 		static PREV_MIX: number;
+		static PREV_SOFTNESS: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_COMPRESS: number;
 		static PREV_COMPRESS: number;
 		static PREV_STRETCH: number;
 		static PREV_STRETCH: number;
 		static MIX: number;
 		static MIX: number;
+		static SOFTNESS: number;
 		static BEND_DIRECTION: number;
 		static BEND_DIRECTION: number;
 		static COMPRESS: number;
 		static COMPRESS: number;
 		static STRETCH: number;
 		static STRETCH: number;
@@ -186,7 +188,7 @@ declare module spine {
 		frames: ArrayLike<number>;
 		frames: ArrayLike<number>;
 		constructor(frameCount: number);
 		constructor(frameCount: number);
 		getPropertyId(): number;
 		getPropertyId(): number;
-		setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean): void;
+		setFrame(frameIndex: number, time: number, mix: number, softness: number, bendDirection: number, compress: boolean, stretch: boolean): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 	}
 	}
 	class TransformConstraintTimeline extends CurveTimeline {
 	class TransformConstraintTimeline extends CurveTimeline {
@@ -534,13 +536,14 @@ declare module spine {
 		compress: boolean;
 		compress: boolean;
 		stretch: boolean;
 		stretch: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		active: boolean;
 		active: boolean;
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		isActive(): boolean;
 		isActive(): boolean;
 		apply(): void;
 		apply(): void;
 		update(): void;
 		update(): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
-		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number): void;
+		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, softness: number, alpha: number): void;
 	}
 	}
 }
 }
 declare module spine {
 declare module spine {
@@ -552,6 +555,7 @@ declare module spine {
 		stretch: boolean;
 		stretch: boolean;
 		uniform: boolean;
 		uniform: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		constructor(name: string);
 		constructor(name: string);
 	}
 	}
 }
 }

+ 52 - 17
spine-ts/build/spine-core.js

@@ -981,10 +981,11 @@ var spine;
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 		};
 		};
-		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) {
+		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, softness, bendDirection, compress, stretch) {
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
+			this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
@@ -998,12 +999,14 @@ var spine;
 				switch (blend) {
 				switch (blend) {
 					case MixBlend.setup:
 					case MixBlend.setup:
 						constraint.mix = constraint.data.mix;
 						constraint.mix = constraint.data.mix;
+						constraint.softness = constraint.data.softness;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
 						return;
 						return;
 					case MixBlend.first:
 					case MixBlend.first:
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
+						constraint.softness += (constraint.data.softness - constraint.softness) * alpha;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
@@ -1013,6 +1016,8 @@ var spine;
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 				if (blend == MixBlend.setup) {
 				if (blend == MixBlend.setup) {
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
+					constraint.softness = constraint.data.softness
+						+ (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha;
 					if (direction == MixDirection.mixOut) {
 					if (direction == MixDirection.mixOut) {
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
@@ -1026,6 +1031,7 @@ var spine;
 				}
 				}
 				else {
 				else {
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
+					constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha;
 					if (direction == MixDirection.mixIn) {
 					if (direction == MixDirection.mixIn) {
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1036,10 +1042,13 @@ var spine;
 			}
 			}
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
+			var softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS];
 			var frameTime = frames[frame];
 			var frameTime = frames[frame];
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			if (blend == MixBlend.setup) {
 			if (blend == MixBlend.setup) {
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
+				constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha;
 				if (direction == MixDirection.mixOut) {
 				if (direction == MixDirection.mixOut) {
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
@@ -1053,6 +1062,7 @@ var spine;
 			}
 			}
 			else {
 			else {
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
+				constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha;
 				if (direction == MixDirection.mixIn) {
 				if (direction == MixDirection.mixIn) {
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1060,16 +1070,18 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		IkConstraintTimeline.ENTRIES = 5;
-		IkConstraintTimeline.PREV_TIME = -5;
-		IkConstraintTimeline.PREV_MIX = -4;
+		IkConstraintTimeline.ENTRIES = 6;
+		IkConstraintTimeline.PREV_TIME = -6;
+		IkConstraintTimeline.PREV_MIX = -5;
+		IkConstraintTimeline.PREV_SOFTNESS = -4;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.MIX = 1;
 		IkConstraintTimeline.MIX = 1;
-		IkConstraintTimeline.BEND_DIRECTION = 2;
-		IkConstraintTimeline.COMPRESS = 3;
-		IkConstraintTimeline.STRETCH = 4;
+		IkConstraintTimeline.SOFTNESS = 2;
+		IkConstraintTimeline.BEND_DIRECTION = 3;
+		IkConstraintTimeline.COMPRESS = 4;
+		IkConstraintTimeline.STRETCH = 5;
 		return IkConstraintTimeline;
 		return IkConstraintTimeline;
 	}(CurveTimeline));
 	}(CurveTimeline));
 	spine.IkConstraintTimeline = IkConstraintTimeline;
 	spine.IkConstraintTimeline = IkConstraintTimeline;
@@ -2775,6 +2787,7 @@ var spine;
 			this.compress = false;
 			this.compress = false;
 			this.stretch = false;
 			this.stretch = false;
 			this.mix = 1;
 			this.mix = 1;
+			this.softness = 0;
 			this.active = false;
 			this.active = false;
 			if (data == null)
 			if (data == null)
 				throw new Error("data cannot be null.");
 				throw new Error("data cannot be null.");
@@ -2782,6 +2795,7 @@ var spine;
 				throw new Error("skeleton cannot be null.");
 				throw new Error("skeleton cannot be null.");
 			this.data = data;
 			this.data = data;
 			this.mix = data.mix;
 			this.mix = data.mix;
+			this.softness = data.softness;
 			this.bendDirection = data.bendDirection;
 			this.bendDirection = data.bendDirection;
 			this.compress = data.compress;
 			this.compress = data.compress;
 			this.stretch = data.stretch;
 			this.stretch = data.stretch;
@@ -2804,7 +2818,7 @@ var spine;
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					break;
 					break;
 				case 2:
 				case 2:
-					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
+					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix);
 					break;
 					break;
 			}
 			}
 		};
 		};
@@ -2834,7 +2848,7 @@ var spine;
 			}
 			}
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 		};
 		};
-		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) {
+		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) {
 			if (alpha == 0) {
 			if (alpha == 0) {
 				child.updateWorldTransform();
 				child.updateWorldTransform();
 				return;
 				return;
@@ -2881,12 +2895,29 @@ var spine;
 			b = pp.b;
 			b = pp.b;
 			c = pp.c;
 			c = pp.c;
 			d = pp.d;
 			d = pp.d;
-			var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY;
-			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty;
-			x = cwx - pp.worldX;
-			y = cwy - pp.worldY;
+			var id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
-			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0;
+			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
+			if (l1 < 0.0001) {
+				this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
+				child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
+				return;
+			}
+			x = targetX - pp.worldX;
+			y = targetY - pp.worldY;
+			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
+			var dd = tx * tx + ty * ty;
+			if (softness != 0) {
+				softness *= psx * (csx + 1) / 2;
+				var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
+				if (sd > 0) {
+					var p = Math.min(1, sd / (softness * 2)) - 1;
+					p = (sd - softness * (1 - p * p)) / td;
+					tx -= p * tx;
+					ty -= p * ty;
+					dd = tx * tx + ty * ty;
+				}
+			}
 			outer: if (u) {
 			outer: if (u) {
 				l2 *= psx;
 				l2 *= psx;
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@@ -2894,7 +2925,7 @@ var spine;
 					cos = -1;
 					cos = -1;
 				else if (cos > 1) {
 				else if (cos > 1) {
 					cos = 1;
 					cos = 1;
-					if (stretch && l1 + l2 > 0.0001)
+					if (stretch)
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 				}
 				}
 				a2 = Math.acos(cos) * bendDir;
 				a2 = Math.acos(cos) * bendDir;
@@ -2985,6 +3016,7 @@ var spine;
 			_this.stretch = false;
 			_this.stretch = false;
 			_this.uniform = false;
 			_this.uniform = false;
 			_this.mix = 1;
 			_this.mix = 1;
+			_this.softness = 0;
 			return _this;
 			return _this;
 		}
 		}
 		return IkConstraintData;
 		return IkConstraintData;
@@ -3804,6 +3836,7 @@ var spine;
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 				var constraint = ikConstraints[i];
 				var constraint = ikConstraints[i];
 				constraint.mix = constraint.data.mix;
 				constraint.mix = constraint.data.mix;
+				constraint.softness = constraint.data.softness;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.compress = constraint.data.compress;
 				constraint.compress = constraint.data.compress;
 				constraint.stretch = constraint.data.stretch;
 				constraint.stretch = constraint.data.stretch;
@@ -4090,6 +4123,7 @@ var spine;
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.mix = input.readFloat();
 				data.mix = input.readFloat();
+				data.softness = input.readFloat();
 				data.bendDirection = input.readByte();
 				data.bendDirection = input.readByte();
 				data.compress = input.readBoolean();
 				data.compress = input.readBoolean();
 				data.stretch = input.readBoolean();
 				data.stretch = input.readBoolean();
@@ -4521,7 +4555,7 @@ var spine;
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				timeline.ikConstraintIndex = index;
 				timeline.ikConstraintIndex = index;
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
-					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
+					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
 					if (frameIndex < frameCount - 1)
 					if (frameIndex < frameCount - 1)
 						this.readCurve(input, frameIndex, timeline);
 						this.readCurve(input, frameIndex, timeline);
 				}
 				}
@@ -5505,6 +5539,7 @@ var spine;
 					if (data.target == null)
 					if (data.target == null)
 						throw new Error("IK target bone not found: " + targetName);
 						throw new Error("IK target bone not found: " + targetName);
 					data.mix = this.getValue(constraintMap, "mix", 1);
 					data.mix = this.getValue(constraintMap, "mix", 1);
+					data.softness = this.getValue(constraintMap, "softness", 0);
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
@@ -5922,7 +5957,7 @@ var spine;
 					var frameIndex = 0;
 					var frameIndex = 0;
 					for (var i = 0; i < constraintMap.length; i++) {
 					for (var i = 0; i < constraintMap.length; i++) {
 						var valueMap = constraintMap[i];
 						var valueMap = constraintMap[i];
-						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
+						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 						this.readCurve(valueMap, timeline, frameIndex);
 						this.readCurve(valueMap, timeline, frameIndex);
 						frameIndex++;
 						frameIndex++;
 					}
 					}

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-core.js.map


+ 6 - 2
spine-ts/build/spine-player.d.ts

@@ -175,10 +175,12 @@ declare module spine {
 		static ENTRIES: number;
 		static ENTRIES: number;
 		static PREV_TIME: number;
 		static PREV_TIME: number;
 		static PREV_MIX: number;
 		static PREV_MIX: number;
+		static PREV_SOFTNESS: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_COMPRESS: number;
 		static PREV_COMPRESS: number;
 		static PREV_STRETCH: number;
 		static PREV_STRETCH: number;
 		static MIX: number;
 		static MIX: number;
+		static SOFTNESS: number;
 		static BEND_DIRECTION: number;
 		static BEND_DIRECTION: number;
 		static COMPRESS: number;
 		static COMPRESS: number;
 		static STRETCH: number;
 		static STRETCH: number;
@@ -186,7 +188,7 @@ declare module spine {
 		frames: ArrayLike<number>;
 		frames: ArrayLike<number>;
 		constructor(frameCount: number);
 		constructor(frameCount: number);
 		getPropertyId(): number;
 		getPropertyId(): number;
-		setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean): void;
+		setFrame(frameIndex: number, time: number, mix: number, softness: number, bendDirection: number, compress: boolean, stretch: boolean): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 	}
 	}
 	class TransformConstraintTimeline extends CurveTimeline {
 	class TransformConstraintTimeline extends CurveTimeline {
@@ -534,13 +536,14 @@ declare module spine {
 		compress: boolean;
 		compress: boolean;
 		stretch: boolean;
 		stretch: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		active: boolean;
 		active: boolean;
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		isActive(): boolean;
 		isActive(): boolean;
 		apply(): void;
 		apply(): void;
 		update(): void;
 		update(): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
-		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number): void;
+		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, softness: number, alpha: number): void;
 	}
 	}
 }
 }
 declare module spine {
 declare module spine {
@@ -552,6 +555,7 @@ declare module spine {
 		stretch: boolean;
 		stretch: boolean;
 		uniform: boolean;
 		uniform: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		constructor(name: string);
 		constructor(name: string);
 	}
 	}
 }
 }

+ 52 - 17
spine-ts/build/spine-player.js

@@ -981,10 +981,11 @@ var spine;
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 		};
 		};
-		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) {
+		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, softness, bendDirection, compress, stretch) {
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
+			this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
@@ -998,12 +999,14 @@ var spine;
 				switch (blend) {
 				switch (blend) {
 					case MixBlend.setup:
 					case MixBlend.setup:
 						constraint.mix = constraint.data.mix;
 						constraint.mix = constraint.data.mix;
+						constraint.softness = constraint.data.softness;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
 						return;
 						return;
 					case MixBlend.first:
 					case MixBlend.first:
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
+						constraint.softness += (constraint.data.softness - constraint.softness) * alpha;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
@@ -1013,6 +1016,8 @@ var spine;
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 				if (blend == MixBlend.setup) {
 				if (blend == MixBlend.setup) {
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
+					constraint.softness = constraint.data.softness
+						+ (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha;
 					if (direction == MixDirection.mixOut) {
 					if (direction == MixDirection.mixOut) {
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
@@ -1026,6 +1031,7 @@ var spine;
 				}
 				}
 				else {
 				else {
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
+					constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha;
 					if (direction == MixDirection.mixIn) {
 					if (direction == MixDirection.mixIn) {
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1036,10 +1042,13 @@ var spine;
 			}
 			}
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
+			var softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS];
 			var frameTime = frames[frame];
 			var frameTime = frames[frame];
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			if (blend == MixBlend.setup) {
 			if (blend == MixBlend.setup) {
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
+				constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha;
 				if (direction == MixDirection.mixOut) {
 				if (direction == MixDirection.mixOut) {
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
@@ -1053,6 +1062,7 @@ var spine;
 			}
 			}
 			else {
 			else {
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
+				constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha;
 				if (direction == MixDirection.mixIn) {
 				if (direction == MixDirection.mixIn) {
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1060,16 +1070,18 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		IkConstraintTimeline.ENTRIES = 5;
-		IkConstraintTimeline.PREV_TIME = -5;
-		IkConstraintTimeline.PREV_MIX = -4;
+		IkConstraintTimeline.ENTRIES = 6;
+		IkConstraintTimeline.PREV_TIME = -6;
+		IkConstraintTimeline.PREV_MIX = -5;
+		IkConstraintTimeline.PREV_SOFTNESS = -4;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.MIX = 1;
 		IkConstraintTimeline.MIX = 1;
-		IkConstraintTimeline.BEND_DIRECTION = 2;
-		IkConstraintTimeline.COMPRESS = 3;
-		IkConstraintTimeline.STRETCH = 4;
+		IkConstraintTimeline.SOFTNESS = 2;
+		IkConstraintTimeline.BEND_DIRECTION = 3;
+		IkConstraintTimeline.COMPRESS = 4;
+		IkConstraintTimeline.STRETCH = 5;
 		return IkConstraintTimeline;
 		return IkConstraintTimeline;
 	}(CurveTimeline));
 	}(CurveTimeline));
 	spine.IkConstraintTimeline = IkConstraintTimeline;
 	spine.IkConstraintTimeline = IkConstraintTimeline;
@@ -2775,6 +2787,7 @@ var spine;
 			this.compress = false;
 			this.compress = false;
 			this.stretch = false;
 			this.stretch = false;
 			this.mix = 1;
 			this.mix = 1;
+			this.softness = 0;
 			this.active = false;
 			this.active = false;
 			if (data == null)
 			if (data == null)
 				throw new Error("data cannot be null.");
 				throw new Error("data cannot be null.");
@@ -2782,6 +2795,7 @@ var spine;
 				throw new Error("skeleton cannot be null.");
 				throw new Error("skeleton cannot be null.");
 			this.data = data;
 			this.data = data;
 			this.mix = data.mix;
 			this.mix = data.mix;
+			this.softness = data.softness;
 			this.bendDirection = data.bendDirection;
 			this.bendDirection = data.bendDirection;
 			this.compress = data.compress;
 			this.compress = data.compress;
 			this.stretch = data.stretch;
 			this.stretch = data.stretch;
@@ -2804,7 +2818,7 @@ var spine;
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					break;
 					break;
 				case 2:
 				case 2:
-					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
+					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix);
 					break;
 					break;
 			}
 			}
 		};
 		};
@@ -2834,7 +2848,7 @@ var spine;
 			}
 			}
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 		};
 		};
-		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) {
+		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) {
 			if (alpha == 0) {
 			if (alpha == 0) {
 				child.updateWorldTransform();
 				child.updateWorldTransform();
 				return;
 				return;
@@ -2881,12 +2895,29 @@ var spine;
 			b = pp.b;
 			b = pp.b;
 			c = pp.c;
 			c = pp.c;
 			d = pp.d;
 			d = pp.d;
-			var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY;
-			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty;
-			x = cwx - pp.worldX;
-			y = cwy - pp.worldY;
+			var id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
-			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0;
+			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
+			if (l1 < 0.0001) {
+				this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
+				child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
+				return;
+			}
+			x = targetX - pp.worldX;
+			y = targetY - pp.worldY;
+			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
+			var dd = tx * tx + ty * ty;
+			if (softness != 0) {
+				softness *= psx * (csx + 1) / 2;
+				var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
+				if (sd > 0) {
+					var p = Math.min(1, sd / (softness * 2)) - 1;
+					p = (sd - softness * (1 - p * p)) / td;
+					tx -= p * tx;
+					ty -= p * ty;
+					dd = tx * tx + ty * ty;
+				}
+			}
 			outer: if (u) {
 			outer: if (u) {
 				l2 *= psx;
 				l2 *= psx;
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@@ -2894,7 +2925,7 @@ var spine;
 					cos = -1;
 					cos = -1;
 				else if (cos > 1) {
 				else if (cos > 1) {
 					cos = 1;
 					cos = 1;
-					if (stretch && l1 + l2 > 0.0001)
+					if (stretch)
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 				}
 				}
 				a2 = Math.acos(cos) * bendDir;
 				a2 = Math.acos(cos) * bendDir;
@@ -2985,6 +3016,7 @@ var spine;
 			_this.stretch = false;
 			_this.stretch = false;
 			_this.uniform = false;
 			_this.uniform = false;
 			_this.mix = 1;
 			_this.mix = 1;
+			_this.softness = 0;
 			return _this;
 			return _this;
 		}
 		}
 		return IkConstraintData;
 		return IkConstraintData;
@@ -3804,6 +3836,7 @@ var spine;
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 				var constraint = ikConstraints[i];
 				var constraint = ikConstraints[i];
 				constraint.mix = constraint.data.mix;
 				constraint.mix = constraint.data.mix;
+				constraint.softness = constraint.data.softness;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.compress = constraint.data.compress;
 				constraint.compress = constraint.data.compress;
 				constraint.stretch = constraint.data.stretch;
 				constraint.stretch = constraint.data.stretch;
@@ -4090,6 +4123,7 @@ var spine;
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.mix = input.readFloat();
 				data.mix = input.readFloat();
+				data.softness = input.readFloat();
 				data.bendDirection = input.readByte();
 				data.bendDirection = input.readByte();
 				data.compress = input.readBoolean();
 				data.compress = input.readBoolean();
 				data.stretch = input.readBoolean();
 				data.stretch = input.readBoolean();
@@ -4521,7 +4555,7 @@ var spine;
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				timeline.ikConstraintIndex = index;
 				timeline.ikConstraintIndex = index;
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
-					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
+					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
 					if (frameIndex < frameCount - 1)
 					if (frameIndex < frameCount - 1)
 						this.readCurve(input, frameIndex, timeline);
 						this.readCurve(input, frameIndex, timeline);
 				}
 				}
@@ -5505,6 +5539,7 @@ var spine;
 					if (data.target == null)
 					if (data.target == null)
 						throw new Error("IK target bone not found: " + targetName);
 						throw new Error("IK target bone not found: " + targetName);
 					data.mix = this.getValue(constraintMap, "mix", 1);
 					data.mix = this.getValue(constraintMap, "mix", 1);
+					data.softness = this.getValue(constraintMap, "softness", 0);
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
@@ -5922,7 +5957,7 @@ var spine;
 					var frameIndex = 0;
 					var frameIndex = 0;
 					for (var i = 0; i < constraintMap.length; i++) {
 					for (var i = 0; i < constraintMap.length; i++) {
 						var valueMap = constraintMap[i];
 						var valueMap = constraintMap[i];
-						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
+						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 						this.readCurve(valueMap, timeline, frameIndex);
 						this.readCurve(valueMap, timeline, frameIndex);
 						frameIndex++;
 						frameIndex++;
 					}
 					}

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-player.js.map


+ 6 - 2
spine-ts/build/spine-threejs.d.ts

@@ -175,10 +175,12 @@ declare module spine {
 		static ENTRIES: number;
 		static ENTRIES: number;
 		static PREV_TIME: number;
 		static PREV_TIME: number;
 		static PREV_MIX: number;
 		static PREV_MIX: number;
+		static PREV_SOFTNESS: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_COMPRESS: number;
 		static PREV_COMPRESS: number;
 		static PREV_STRETCH: number;
 		static PREV_STRETCH: number;
 		static MIX: number;
 		static MIX: number;
+		static SOFTNESS: number;
 		static BEND_DIRECTION: number;
 		static BEND_DIRECTION: number;
 		static COMPRESS: number;
 		static COMPRESS: number;
 		static STRETCH: number;
 		static STRETCH: number;
@@ -186,7 +188,7 @@ declare module spine {
 		frames: ArrayLike<number>;
 		frames: ArrayLike<number>;
 		constructor(frameCount: number);
 		constructor(frameCount: number);
 		getPropertyId(): number;
 		getPropertyId(): number;
-		setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean): void;
+		setFrame(frameIndex: number, time: number, mix: number, softness: number, bendDirection: number, compress: boolean, stretch: boolean): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 	}
 	}
 	class TransformConstraintTimeline extends CurveTimeline {
 	class TransformConstraintTimeline extends CurveTimeline {
@@ -534,13 +536,14 @@ declare module spine {
 		compress: boolean;
 		compress: boolean;
 		stretch: boolean;
 		stretch: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		active: boolean;
 		active: boolean;
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		isActive(): boolean;
 		isActive(): boolean;
 		apply(): void;
 		apply(): void;
 		update(): void;
 		update(): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
-		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number): void;
+		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, softness: number, alpha: number): void;
 	}
 	}
 }
 }
 declare module spine {
 declare module spine {
@@ -552,6 +555,7 @@ declare module spine {
 		stretch: boolean;
 		stretch: boolean;
 		uniform: boolean;
 		uniform: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		constructor(name: string);
 		constructor(name: string);
 	}
 	}
 }
 }

+ 52 - 17
spine-ts/build/spine-threejs.js

@@ -981,10 +981,11 @@ var spine;
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 		};
 		};
-		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) {
+		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, softness, bendDirection, compress, stretch) {
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
+			this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
@@ -998,12 +999,14 @@ var spine;
 				switch (blend) {
 				switch (blend) {
 					case MixBlend.setup:
 					case MixBlend.setup:
 						constraint.mix = constraint.data.mix;
 						constraint.mix = constraint.data.mix;
+						constraint.softness = constraint.data.softness;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
 						return;
 						return;
 					case MixBlend.first:
 					case MixBlend.first:
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
+						constraint.softness += (constraint.data.softness - constraint.softness) * alpha;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
@@ -1013,6 +1016,8 @@ var spine;
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 				if (blend == MixBlend.setup) {
 				if (blend == MixBlend.setup) {
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
+					constraint.softness = constraint.data.softness
+						+ (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha;
 					if (direction == MixDirection.mixOut) {
 					if (direction == MixDirection.mixOut) {
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
@@ -1026,6 +1031,7 @@ var spine;
 				}
 				}
 				else {
 				else {
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
+					constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha;
 					if (direction == MixDirection.mixIn) {
 					if (direction == MixDirection.mixIn) {
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1036,10 +1042,13 @@ var spine;
 			}
 			}
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
+			var softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS];
 			var frameTime = frames[frame];
 			var frameTime = frames[frame];
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			if (blend == MixBlend.setup) {
 			if (blend == MixBlend.setup) {
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
+				constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha;
 				if (direction == MixDirection.mixOut) {
 				if (direction == MixDirection.mixOut) {
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
@@ -1053,6 +1062,7 @@ var spine;
 			}
 			}
 			else {
 			else {
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
+				constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha;
 				if (direction == MixDirection.mixIn) {
 				if (direction == MixDirection.mixIn) {
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1060,16 +1070,18 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		IkConstraintTimeline.ENTRIES = 5;
-		IkConstraintTimeline.PREV_TIME = -5;
-		IkConstraintTimeline.PREV_MIX = -4;
+		IkConstraintTimeline.ENTRIES = 6;
+		IkConstraintTimeline.PREV_TIME = -6;
+		IkConstraintTimeline.PREV_MIX = -5;
+		IkConstraintTimeline.PREV_SOFTNESS = -4;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.MIX = 1;
 		IkConstraintTimeline.MIX = 1;
-		IkConstraintTimeline.BEND_DIRECTION = 2;
-		IkConstraintTimeline.COMPRESS = 3;
-		IkConstraintTimeline.STRETCH = 4;
+		IkConstraintTimeline.SOFTNESS = 2;
+		IkConstraintTimeline.BEND_DIRECTION = 3;
+		IkConstraintTimeline.COMPRESS = 4;
+		IkConstraintTimeline.STRETCH = 5;
 		return IkConstraintTimeline;
 		return IkConstraintTimeline;
 	}(CurveTimeline));
 	}(CurveTimeline));
 	spine.IkConstraintTimeline = IkConstraintTimeline;
 	spine.IkConstraintTimeline = IkConstraintTimeline;
@@ -2775,6 +2787,7 @@ var spine;
 			this.compress = false;
 			this.compress = false;
 			this.stretch = false;
 			this.stretch = false;
 			this.mix = 1;
 			this.mix = 1;
+			this.softness = 0;
 			this.active = false;
 			this.active = false;
 			if (data == null)
 			if (data == null)
 				throw new Error("data cannot be null.");
 				throw new Error("data cannot be null.");
@@ -2782,6 +2795,7 @@ var spine;
 				throw new Error("skeleton cannot be null.");
 				throw new Error("skeleton cannot be null.");
 			this.data = data;
 			this.data = data;
 			this.mix = data.mix;
 			this.mix = data.mix;
+			this.softness = data.softness;
 			this.bendDirection = data.bendDirection;
 			this.bendDirection = data.bendDirection;
 			this.compress = data.compress;
 			this.compress = data.compress;
 			this.stretch = data.stretch;
 			this.stretch = data.stretch;
@@ -2804,7 +2818,7 @@ var spine;
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					break;
 					break;
 				case 2:
 				case 2:
-					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
+					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix);
 					break;
 					break;
 			}
 			}
 		};
 		};
@@ -2834,7 +2848,7 @@ var spine;
 			}
 			}
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 		};
 		};
-		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) {
+		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) {
 			if (alpha == 0) {
 			if (alpha == 0) {
 				child.updateWorldTransform();
 				child.updateWorldTransform();
 				return;
 				return;
@@ -2881,12 +2895,29 @@ var spine;
 			b = pp.b;
 			b = pp.b;
 			c = pp.c;
 			c = pp.c;
 			d = pp.d;
 			d = pp.d;
-			var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY;
-			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty;
-			x = cwx - pp.worldX;
-			y = cwy - pp.worldY;
+			var id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
-			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0;
+			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
+			if (l1 < 0.0001) {
+				this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
+				child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
+				return;
+			}
+			x = targetX - pp.worldX;
+			y = targetY - pp.worldY;
+			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
+			var dd = tx * tx + ty * ty;
+			if (softness != 0) {
+				softness *= psx * (csx + 1) / 2;
+				var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
+				if (sd > 0) {
+					var p = Math.min(1, sd / (softness * 2)) - 1;
+					p = (sd - softness * (1 - p * p)) / td;
+					tx -= p * tx;
+					ty -= p * ty;
+					dd = tx * tx + ty * ty;
+				}
+			}
 			outer: if (u) {
 			outer: if (u) {
 				l2 *= psx;
 				l2 *= psx;
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@@ -2894,7 +2925,7 @@ var spine;
 					cos = -1;
 					cos = -1;
 				else if (cos > 1) {
 				else if (cos > 1) {
 					cos = 1;
 					cos = 1;
-					if (stretch && l1 + l2 > 0.0001)
+					if (stretch)
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 				}
 				}
 				a2 = Math.acos(cos) * bendDir;
 				a2 = Math.acos(cos) * bendDir;
@@ -2985,6 +3016,7 @@ var spine;
 			_this.stretch = false;
 			_this.stretch = false;
 			_this.uniform = false;
 			_this.uniform = false;
 			_this.mix = 1;
 			_this.mix = 1;
+			_this.softness = 0;
 			return _this;
 			return _this;
 		}
 		}
 		return IkConstraintData;
 		return IkConstraintData;
@@ -3804,6 +3836,7 @@ var spine;
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 				var constraint = ikConstraints[i];
 				var constraint = ikConstraints[i];
 				constraint.mix = constraint.data.mix;
 				constraint.mix = constraint.data.mix;
+				constraint.softness = constraint.data.softness;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.compress = constraint.data.compress;
 				constraint.compress = constraint.data.compress;
 				constraint.stretch = constraint.data.stretch;
 				constraint.stretch = constraint.data.stretch;
@@ -4090,6 +4123,7 @@ var spine;
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.mix = input.readFloat();
 				data.mix = input.readFloat();
+				data.softness = input.readFloat();
 				data.bendDirection = input.readByte();
 				data.bendDirection = input.readByte();
 				data.compress = input.readBoolean();
 				data.compress = input.readBoolean();
 				data.stretch = input.readBoolean();
 				data.stretch = input.readBoolean();
@@ -4521,7 +4555,7 @@ var spine;
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				timeline.ikConstraintIndex = index;
 				timeline.ikConstraintIndex = index;
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
-					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
+					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
 					if (frameIndex < frameCount - 1)
 					if (frameIndex < frameCount - 1)
 						this.readCurve(input, frameIndex, timeline);
 						this.readCurve(input, frameIndex, timeline);
 				}
 				}
@@ -5505,6 +5539,7 @@ var spine;
 					if (data.target == null)
 					if (data.target == null)
 						throw new Error("IK target bone not found: " + targetName);
 						throw new Error("IK target bone not found: " + targetName);
 					data.mix = this.getValue(constraintMap, "mix", 1);
 					data.mix = this.getValue(constraintMap, "mix", 1);
+					data.softness = this.getValue(constraintMap, "softness", 0);
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
@@ -5922,7 +5957,7 @@ var spine;
 					var frameIndex = 0;
 					var frameIndex = 0;
 					for (var i = 0; i < constraintMap.length; i++) {
 					for (var i = 0; i < constraintMap.length; i++) {
 						var valueMap = constraintMap[i];
 						var valueMap = constraintMap[i];
-						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
+						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 						this.readCurve(valueMap, timeline, frameIndex);
 						this.readCurve(valueMap, timeline, frameIndex);
 						frameIndex++;
 						frameIndex++;
 					}
 					}

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-threejs.js.map


+ 6 - 2
spine-ts/build/spine-webgl.d.ts

@@ -175,10 +175,12 @@ declare module spine {
 		static ENTRIES: number;
 		static ENTRIES: number;
 		static PREV_TIME: number;
 		static PREV_TIME: number;
 		static PREV_MIX: number;
 		static PREV_MIX: number;
+		static PREV_SOFTNESS: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_BEND_DIRECTION: number;
 		static PREV_COMPRESS: number;
 		static PREV_COMPRESS: number;
 		static PREV_STRETCH: number;
 		static PREV_STRETCH: number;
 		static MIX: number;
 		static MIX: number;
+		static SOFTNESS: number;
 		static BEND_DIRECTION: number;
 		static BEND_DIRECTION: number;
 		static COMPRESS: number;
 		static COMPRESS: number;
 		static STRETCH: number;
 		static STRETCH: number;
@@ -186,7 +188,7 @@ declare module spine {
 		frames: ArrayLike<number>;
 		frames: ArrayLike<number>;
 		constructor(frameCount: number);
 		constructor(frameCount: number);
 		getPropertyId(): number;
 		getPropertyId(): number;
-		setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean): void;
+		setFrame(frameIndex: number, time: number, mix: number, softness: number, bendDirection: number, compress: boolean, stretch: boolean): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 		apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
 	}
 	}
 	class TransformConstraintTimeline extends CurveTimeline {
 	class TransformConstraintTimeline extends CurveTimeline {
@@ -534,13 +536,14 @@ declare module spine {
 		compress: boolean;
 		compress: boolean;
 		stretch: boolean;
 		stretch: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		active: boolean;
 		active: boolean;
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		constructor(data: IkConstraintData, skeleton: Skeleton);
 		isActive(): boolean;
 		isActive(): boolean;
 		apply(): void;
 		apply(): void;
 		update(): void;
 		update(): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
 		apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
-		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number): void;
+		apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, softness: number, alpha: number): void;
 	}
 	}
 }
 }
 declare module spine {
 declare module spine {
@@ -552,6 +555,7 @@ declare module spine {
 		stretch: boolean;
 		stretch: boolean;
 		uniform: boolean;
 		uniform: boolean;
 		mix: number;
 		mix: number;
+		softness: number;
 		constructor(name: string);
 		constructor(name: string);
 	}
 	}
 }
 }

+ 52 - 17
spine-ts/build/spine-webgl.js

@@ -981,10 +981,11 @@ var spine;
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 		IkConstraintTimeline.prototype.getPropertyId = function () {
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 		};
 		};
-		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) {
+		IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, softness, bendDirection, compress, stretch) {
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
+			this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
@@ -998,12 +999,14 @@ var spine;
 				switch (blend) {
 				switch (blend) {
 					case MixBlend.setup:
 					case MixBlend.setup:
 						constraint.mix = constraint.data.mix;
 						constraint.mix = constraint.data.mix;
+						constraint.softness = constraint.data.softness;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
 						return;
 						return;
 					case MixBlend.first:
 					case MixBlend.first:
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
 						constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
+						constraint.softness += (constraint.data.softness - constraint.softness) * alpha;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
 						constraint.stretch = constraint.data.stretch;
 						constraint.stretch = constraint.data.stretch;
@@ -1013,6 +1016,8 @@ var spine;
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) {
 				if (blend == MixBlend.setup) {
 				if (blend == MixBlend.setup) {
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
+					constraint.softness = constraint.data.softness
+						+ (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha;
 					if (direction == MixDirection.mixOut) {
 					if (direction == MixDirection.mixOut) {
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
@@ -1026,6 +1031,7 @@ var spine;
 				}
 				}
 				else {
 				else {
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
+					constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha;
 					if (direction == MixDirection.mixIn) {
 					if (direction == MixDirection.mixIn) {
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1036,10 +1042,13 @@ var spine;
 			}
 			}
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
 			var mix = frames[frame + IkConstraintTimeline.PREV_MIX];
+			var softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS];
 			var frameTime = frames[frame];
 			var frameTime = frames[frame];
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 			if (blend == MixBlend.setup) {
 			if (blend == MixBlend.setup) {
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
+				constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha;
 				if (direction == MixDirection.mixOut) {
 				if (direction == MixDirection.mixOut) {
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
@@ -1053,6 +1062,7 @@ var spine;
 			}
 			}
 			else {
 			else {
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
+				constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha;
 				if (direction == MixDirection.mixIn) {
 				if (direction == MixDirection.mixIn) {
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1060,16 +1070,18 @@ var spine;
 				}
 				}
 			}
 			}
 		};
 		};
-		IkConstraintTimeline.ENTRIES = 5;
-		IkConstraintTimeline.PREV_TIME = -5;
-		IkConstraintTimeline.PREV_MIX = -4;
+		IkConstraintTimeline.ENTRIES = 6;
+		IkConstraintTimeline.PREV_TIME = -6;
+		IkConstraintTimeline.PREV_MIX = -5;
+		IkConstraintTimeline.PREV_SOFTNESS = -4;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_COMPRESS = -2;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.PREV_STRETCH = -1;
 		IkConstraintTimeline.MIX = 1;
 		IkConstraintTimeline.MIX = 1;
-		IkConstraintTimeline.BEND_DIRECTION = 2;
-		IkConstraintTimeline.COMPRESS = 3;
-		IkConstraintTimeline.STRETCH = 4;
+		IkConstraintTimeline.SOFTNESS = 2;
+		IkConstraintTimeline.BEND_DIRECTION = 3;
+		IkConstraintTimeline.COMPRESS = 4;
+		IkConstraintTimeline.STRETCH = 5;
 		return IkConstraintTimeline;
 		return IkConstraintTimeline;
 	}(CurveTimeline));
 	}(CurveTimeline));
 	spine.IkConstraintTimeline = IkConstraintTimeline;
 	spine.IkConstraintTimeline = IkConstraintTimeline;
@@ -2775,6 +2787,7 @@ var spine;
 			this.compress = false;
 			this.compress = false;
 			this.stretch = false;
 			this.stretch = false;
 			this.mix = 1;
 			this.mix = 1;
+			this.softness = 0;
 			this.active = false;
 			this.active = false;
 			if (data == null)
 			if (data == null)
 				throw new Error("data cannot be null.");
 				throw new Error("data cannot be null.");
@@ -2782,6 +2795,7 @@ var spine;
 				throw new Error("skeleton cannot be null.");
 				throw new Error("skeleton cannot be null.");
 			this.data = data;
 			this.data = data;
 			this.mix = data.mix;
 			this.mix = data.mix;
+			this.softness = data.softness;
 			this.bendDirection = data.bendDirection;
 			this.bendDirection = data.bendDirection;
 			this.compress = data.compress;
 			this.compress = data.compress;
 			this.stretch = data.stretch;
 			this.stretch = data.stretch;
@@ -2804,7 +2818,7 @@ var spine;
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 					break;
 					break;
 				case 2:
 				case 2:
-					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
+					this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix);
 					break;
 					break;
 			}
 			}
 		};
 		};
@@ -2834,7 +2848,7 @@ var spine;
 			}
 			}
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 			bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
 		};
 		};
-		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) {
+		IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) {
 			if (alpha == 0) {
 			if (alpha == 0) {
 				child.updateWorldTransform();
 				child.updateWorldTransform();
 				return;
 				return;
@@ -2881,12 +2895,29 @@ var spine;
 			b = pp.b;
 			b = pp.b;
 			c = pp.c;
 			c = pp.c;
 			d = pp.d;
 			d = pp.d;
-			var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY;
-			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty;
-			x = cwx - pp.worldX;
-			y = cwy - pp.worldY;
+			var id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
 			var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
-			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0;
+			var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
+			if (l1 < 0.0001) {
+				this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
+				child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
+				return;
+			}
+			x = targetX - pp.worldX;
+			y = targetY - pp.worldY;
+			var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
+			var dd = tx * tx + ty * ty;
+			if (softness != 0) {
+				softness *= psx * (csx + 1) / 2;
+				var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
+				if (sd > 0) {
+					var p = Math.min(1, sd / (softness * 2)) - 1;
+					p = (sd - softness * (1 - p * p)) / td;
+					tx -= p * tx;
+					ty -= p * ty;
+					dd = tx * tx + ty * ty;
+				}
+			}
 			outer: if (u) {
 			outer: if (u) {
 				l2 *= psx;
 				l2 *= psx;
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
 				var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2);
@@ -2894,7 +2925,7 @@ var spine;
 					cos = -1;
 					cos = -1;
 				else if (cos > 1) {
 				else if (cos > 1) {
 					cos = 1;
 					cos = 1;
-					if (stretch && l1 + l2 > 0.0001)
+					if (stretch)
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 						sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 				}
 				}
 				a2 = Math.acos(cos) * bendDir;
 				a2 = Math.acos(cos) * bendDir;
@@ -2985,6 +3016,7 @@ var spine;
 			_this.stretch = false;
 			_this.stretch = false;
 			_this.uniform = false;
 			_this.uniform = false;
 			_this.mix = 1;
 			_this.mix = 1;
+			_this.softness = 0;
 			return _this;
 			return _this;
 		}
 		}
 		return IkConstraintData;
 		return IkConstraintData;
@@ -3804,6 +3836,7 @@ var spine;
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 			for (var i = 0, n = ikConstraints.length; i < n; i++) {
 				var constraint = ikConstraints[i];
 				var constraint = ikConstraints[i];
 				constraint.mix = constraint.data.mix;
 				constraint.mix = constraint.data.mix;
+				constraint.softness = constraint.data.softness;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.compress = constraint.data.compress;
 				constraint.compress = constraint.data.compress;
 				constraint.stretch = constraint.data.stretch;
 				constraint.stretch = constraint.data.stretch;
@@ -4090,6 +4123,7 @@ var spine;
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.mix = input.readFloat();
 				data.mix = input.readFloat();
+				data.softness = input.readFloat();
 				data.bendDirection = input.readByte();
 				data.bendDirection = input.readByte();
 				data.compress = input.readBoolean();
 				data.compress = input.readBoolean();
 				data.stretch = input.readBoolean();
 				data.stretch = input.readBoolean();
@@ -4521,7 +4555,7 @@ var spine;
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				var timeline = new spine.IkConstraintTimeline(frameCount);
 				timeline.ikConstraintIndex = index;
 				timeline.ikConstraintIndex = index;
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
 				for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) {
-					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
+					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(), input.readBoolean());
 					if (frameIndex < frameCount - 1)
 					if (frameIndex < frameCount - 1)
 						this.readCurve(input, frameIndex, timeline);
 						this.readCurve(input, frameIndex, timeline);
 				}
 				}
@@ -5505,6 +5539,7 @@ var spine;
 					if (data.target == null)
 					if (data.target == null)
 						throw new Error("IK target bone not found: " + targetName);
 						throw new Error("IK target bone not found: " + targetName);
 					data.mix = this.getValue(constraintMap, "mix", 1);
 					data.mix = this.getValue(constraintMap, "mix", 1);
+					data.softness = this.getValue(constraintMap, "softness", 0);
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
@@ -5922,7 +5957,7 @@ var spine;
 					var frameIndex = 0;
 					var frameIndex = 0;
 					for (var i = 0; i < constraintMap.length; i++) {
 					for (var i = 0; i < constraintMap.length; i++) {
 						var valueMap = constraintMap[i];
 						var valueMap = constraintMap[i];
-						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
+						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 						this.readCurve(valueMap, timeline, frameIndex);
 						this.readCurve(valueMap, timeline, frameIndex);
 						frameIndex++;
 						frameIndex++;
 					}
 					}

File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-webgl.js.map


+ 16 - 6
spine-ts/core/src/Animation.ts

@@ -1044,12 +1044,12 @@ module spine {
 	}
 	}
 
 
 	export class IkConstraintTimeline extends CurveTimeline {
 	export class IkConstraintTimeline extends CurveTimeline {
-		static ENTRIES = 5;
-		static PREV_TIME = -5; static PREV_MIX = -4; static PREV_BEND_DIRECTION = -3; static PREV_COMPRESS = -2; static PREV_STRETCH = -1;
-		static MIX = 1; static BEND_DIRECTION = 2; static COMPRESS = 3; static STRETCH = 4;
+		static ENTRIES = 6;
+		static PREV_TIME = -6; static PREV_MIX = -5; static PREV_SOFTNESS = -4; static PREV_BEND_DIRECTION = -3; static PREV_COMPRESS = -2; static PREV_STRETCH = -1;
+		static MIX = 1; static SOFTNESS = 2; static BEND_DIRECTION = 3; static COMPRESS = 4; static STRETCH = 5;
 
 
 		ikConstraintIndex: number;
 		ikConstraintIndex: number;
-		frames: ArrayLike<number>; // time, mix, bendDirection, compress, stretch, ...
+		frames: ArrayLike<number>; // time, mix, softness, bendDirection, compress, stretch, ...
 
 
 		constructor (frameCount: number) {
 		constructor (frameCount: number) {
 			super(frameCount);
 			super(frameCount);
@@ -1060,11 +1060,12 @@ module spine {
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 			return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
 		}
 		}
 
 
-		/** Sets the time, mix and bend direction of the specified keyframe. */
-		setFrame (frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean) {
+		/** Sets the time, mix, softness, and bend direction of the specified keyframe. */
+		setFrame (frameIndex: number, time: number, mix: number, softness: number, bendDirection: number, compress: boolean, stretch: boolean) {
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			frameIndex *= IkConstraintTimeline.ENTRIES;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex] = time;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
 			this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
+			this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
 			this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
@@ -1078,12 +1079,14 @@ module spine {
 				switch (blend) {
 				switch (blend) {
 				case MixBlend.setup:
 				case MixBlend.setup:
 					constraint.mix = constraint.data.mix;
 					constraint.mix = constraint.data.mix;
+					constraint.softness = constraint.data.softness;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
 					constraint.stretch = constraint.data.stretch;
 					constraint.stretch = constraint.data.stretch;
 					return;
 					return;
 				case MixBlend.first:
 				case MixBlend.first:
 					constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
 					constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
+					constraint.softness += (constraint.data.softness - constraint.softness) * alpha;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
 					constraint.stretch = constraint.data.stretch;
 					constraint.stretch = constraint.data.stretch;
@@ -1094,6 +1097,8 @@ module spine {
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) { // Time is after last frame.
 			if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) { // Time is after last frame.
 				if (blend == MixBlend.setup) {
 				if (blend == MixBlend.setup) {
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
 					constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
+					constraint.softness = constraint.data.softness
+						+ (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha;
 					if (direction == MixDirection.mixOut) {
 					if (direction == MixDirection.mixOut) {
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.bendDirection = constraint.data.bendDirection;
 						constraint.compress = constraint.data.compress;
 						constraint.compress = constraint.data.compress;
@@ -1105,6 +1110,7 @@ module spine {
 					}
 					}
 				} else {
 				} else {
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
 					constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
+					constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha;
 					if (direction == MixDirection.mixIn) {
 					if (direction == MixDirection.mixIn) {
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
 						constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
@@ -1117,12 +1123,15 @@ module spine {
 			// Interpolate between the previous frame and the current frame.
 			// Interpolate between the previous frame and the current frame.
 			let frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			let frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES);
 			let mix = frames[frame + IkConstraintTimeline.PREV_MIX];
 			let mix = frames[frame + IkConstraintTimeline.PREV_MIX];
+			let softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS];
 			let frameTime = frames[frame];
 			let frameTime = frames[frame];
 			let percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1,
 			let percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1,
 				1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 				1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime));
 
 
 			if (blend == MixBlend.setup) {
 			if (blend == MixBlend.setup) {
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
 				constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
+				constraint.softness = constraint.data.softness
+					+ (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha;
 				if (direction == MixDirection.mixOut) {
 				if (direction == MixDirection.mixOut) {
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.bendDirection = constraint.data.bendDirection;
 					constraint.compress = constraint.data.compress;
 					constraint.compress = constraint.data.compress;
@@ -1134,6 +1143,7 @@ module spine {
 				}
 				}
 			} else {
 			} else {
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
 				constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
+				constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha;
 				if (direction == MixDirection.mixIn) {
 				if (direction == MixDirection.mixIn) {
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
 					constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;

+ 27 - 8
spine-ts/core/src/IkConstraint.ts

@@ -36,6 +36,7 @@ module spine {
 		compress = false;
 		compress = false;
 		stretch = false;
 		stretch = false;
 		mix = 1;
 		mix = 1;
+		softness = 0;
 		active = false;
 		active = false;
 
 
 		constructor (data: IkConstraintData, skeleton: Skeleton) {
 		constructor (data: IkConstraintData, skeleton: Skeleton) {
@@ -43,6 +44,7 @@ module spine {
 			if (skeleton == null) throw new Error("skeleton cannot be null.");
 			if (skeleton == null) throw new Error("skeleton cannot be null.");
 			this.data = data;
 			this.data = data;
 			this.mix = data.mix;
 			this.mix = data.mix;
+			this.softness = data.softness;
 			this.bendDirection = data.bendDirection;
 			this.bendDirection = data.bendDirection;
 			this.compress = data.compress;
 			this.compress = data.compress;
 			this.stretch = data.stretch;
 			this.stretch = data.stretch;
@@ -69,7 +71,7 @@ module spine {
 				this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 				this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
 				break;
 				break;
 			case 2:
 			case 2:
-				this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
+				this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix);
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -103,7 +105,7 @@ module spine {
 		/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
 		/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
 		 * target is specified in the world coordinate system.
 		 * target is specified in the world coordinate system.
 		 * @param child A direct descendant of the parent bone. */
 		 * @param child A direct descendant of the parent bone. */
-		apply2 (parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number) {
+		apply2 (parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, softness: number, alpha: number) {
 			if (alpha == 0) {
 			if (alpha == 0) {
 				child.updateWorldTransform();
 				child.updateWorldTransform();
 				return;
 				return;
@@ -145,12 +147,29 @@ module spine {
 			b = pp.b;
 			b = pp.b;
 			c = pp.c;
 			c = pp.c;
 			d = pp.d;
 			d = pp.d;
-			let id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY;
-			let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty;
-			x = cwx - pp.worldX;
-			y = cwy - pp.worldY;
+			let id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY;
 			let dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
 			let dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
-			let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0;
+			let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2;
+			if (l1 < 0.0001) {
+				this.apply1(parent, targetX, targetY, false, stretch, false, alpha);
+				child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
+				return;
+			}
+			x = targetX - pp.worldX;
+			y = targetY - pp.worldY;
+			let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py;
+			let dd = tx * tx + ty * ty;
+			if (softness != 0) {
+				softness *= psx * (csx + 1) / 2;
+				let td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness;
+				if (sd > 0) {
+					let p = Math.min(1, sd / (softness * 2)) - 1;
+					p = (sd - softness * (1 - p * p)) / td;
+					tx -= p * tx;
+					ty -= p * ty;
+					dd = tx * tx + ty * ty;
+				}
+			}
 			outer:
 			outer:
 			if (u) {
 			if (u) {
 				l2 *= psx;
 				l2 *= psx;
@@ -159,7 +178,7 @@ module spine {
 					cos = -1;
 					cos = -1;
 				else if (cos > 1) {
 				else if (cos > 1) {
 					cos = 1;
 					cos = 1;
-					if (stretch && l1 + l2 > 0.0001) sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
+					if (stretch) sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1;
 				}
 				}
 				a2 = Math.acos(cos) * bendDir;
 				a2 = Math.acos(cos) * bendDir;
 				a = l1 + l2 * cos;
 				a = l1 + l2 * cos;

+ 1 - 0
spine-ts/core/src/IkConstraintData.ts

@@ -36,6 +36,7 @@ module spine {
 		stretch = false;
 		stretch = false;
 		uniform = false;
 		uniform = false;
 		mix = 1;
 		mix = 1;
+		softness = 0;
 
 
 		constructor (name: string) {
 		constructor (name: string) {
 			super(name, 0, false);
 			super(name, 0, false);

+ 1 - 0
spine-ts/core/src/Skeleton.ts

@@ -311,6 +311,7 @@ module spine {
 			for (let i = 0, n = ikConstraints.length; i < n; i++) {
 			for (let i = 0, n = ikConstraints.length; i < n; i++) {
 				let constraint = ikConstraints[i];
 				let constraint = ikConstraints[i];
 				constraint.mix = constraint.data.mix;
 				constraint.mix = constraint.data.mix;
+				constraint.softness = constraint.data.softness;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.bendDirection = constraint.data.bendDirection;
 				constraint.compress = constraint.data.compress;
 				constraint.compress = constraint.data.compress;
 				constraint.stretch = constraint.data.stretch;
 				constraint.stretch = constraint.data.stretch;

+ 2 - 1
spine-ts/core/src/SkeletonBinary.ts

@@ -137,6 +137,7 @@ module spine {
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 					data.bones.push(skeletonData.bones[input.readInt(true)]);
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.target = skeletonData.bones[input.readInt(true)];
 				data.mix = input.readFloat();
 				data.mix = input.readFloat();
+				data.softness = input.readFloat();
 				data.bendDirection = input.readByte();
 				data.bendDirection = input.readByte();
 				data.compress = input.readBoolean();
 				data.compress = input.readBoolean();
 				data.stretch = input.readBoolean();
 				data.stretch = input.readBoolean();
@@ -583,7 +584,7 @@ module spine {
 				let timeline = new IkConstraintTimeline(frameCount);
 				let timeline = new IkConstraintTimeline(frameCount);
 				timeline.ikConstraintIndex = index;
 				timeline.ikConstraintIndex = index;
 				for (let frameIndex = 0; frameIndex < frameCount; frameIndex++) {
 				for (let frameIndex = 0; frameIndex < frameCount; frameIndex++) {
-					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(),
+					timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(),
 						input.readBoolean());
 						input.readBoolean());
 					if (frameIndex < frameCount - 1) this.readCurve(input, frameIndex, timeline);
 					if (frameIndex < frameCount - 1) this.readCurve(input, frameIndex, timeline);
 				}
 				}

+ 2 - 1
spine-ts/core/src/SkeletonJson.ts

@@ -127,6 +127,7 @@ module spine {
 					if (data.target == null) throw new Error("IK target bone not found: " + targetName);
 					if (data.target == null) throw new Error("IK target bone not found: " + targetName);
 
 
 					data.mix = this.getValue(constraintMap, "mix", 1);
 					data.mix = this.getValue(constraintMap, "mix", 1);
+					data.softness = this.getValue(constraintMap, "softness", 0);
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.compress = this.getValue(constraintMap, "compress", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
 					data.stretch = this.getValue(constraintMap, "stretch", false);
@@ -570,7 +571,7 @@ module spine {
 					let frameIndex = 0;
 					let frameIndex = 0;
 					for (let i = 0; i < constraintMap.length; i++) {
 					for (let i = 0; i < constraintMap.length; i++) {
 						let valueMap = constraintMap[i];
 						let valueMap = constraintMap[i];
-						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1),
+						timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0),
 							this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 							this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
 						this.readCurve(valueMap, timeline, frameIndex);
 						this.readCurve(valueMap, timeline, frameIndex);
 						frameIndex++;
 						frameIndex++;

Some files were not shown because too many files changed in this diff