|
@@ -40,7 +40,8 @@ spine.BoneData.prototype = {
|
|
|
rotation: 0,
|
|
|
scaleX: 1, scaleY: 1,
|
|
|
inheritScale: true,
|
|
|
- inheritRotation: true
|
|
|
+ inheritRotation: true,
|
|
|
+ flipX: false, flipY: false
|
|
|
};
|
|
|
|
|
|
spine.SlotData = function (name, boneData) {
|
|
@@ -53,21 +54,34 @@ spine.SlotData.prototype = {
|
|
|
additiveBlending: false
|
|
|
};
|
|
|
|
|
|
-spine.Bone = function (boneData, parent) {
|
|
|
+spine.IkConstraintData = function (name) {
|
|
|
+ this.name = name;
|
|
|
+ this.bones = [];
|
|
|
+};
|
|
|
+spine.IkConstraintData.prototype = {
|
|
|
+ target: null,
|
|
|
+ bendDirection: 1,
|
|
|
+ mix: 1
|
|
|
+};
|
|
|
+
|
|
|
+spine.Bone = function (boneData, skeleton, parent) {
|
|
|
this.data = boneData;
|
|
|
+ this.skeleton = skeleton;
|
|
|
this.parent = parent;
|
|
|
this.setToSetupPose();
|
|
|
};
|
|
|
spine.Bone.yDown = false;
|
|
|
spine.Bone.prototype = {
|
|
|
x: 0, y: 0,
|
|
|
- rotation: 0,
|
|
|
+ rotation: 0, rotationIK: 0,
|
|
|
scaleX: 1, scaleY: 1,
|
|
|
+ flipX: false, flipY: false,
|
|
|
m00: 0, m01: 0, worldX: 0, // a b x
|
|
|
m10: 0, m11: 0, worldY: 0, // c d y
|
|
|
worldRotation: 0,
|
|
|
worldScaleX: 1, worldScaleY: 1,
|
|
|
- updateWorldTransform: function (flipX, flipY) {
|
|
|
+ worldFlipX: false, worldFlipY: false,
|
|
|
+ updateWorldTransform: function () {
|
|
|
var parent = this.parent;
|
|
|
if (parent != null) {
|
|
|
this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX;
|
|
@@ -79,28 +93,35 @@ spine.Bone.prototype = {
|
|
|
this.worldScaleX = this.scaleX;
|
|
|
this.worldScaleY = this.scaleY;
|
|
|
}
|
|
|
- this.worldRotation = this.data.inheritRotation ? parent.worldRotation + this.rotation : this.rotation;
|
|
|
+ this.worldRotation = this.data.inheritRotation ? parent.worldRotation + this.rotationIK : this.rotationIK;
|
|
|
+ this.worldFlipX = parent.worldFlipX != this.flipX;
|
|
|
+ this.worldFlipY = parent.worldFlipY != this.flipY;
|
|
|
} else {
|
|
|
- this.worldX = flipX ? -this.x : this.x;
|
|
|
- this.worldY = flipY != spine.Bone.yDown ? -this.y : this.y;
|
|
|
+ var skeletonFlipX = skeleton.flipX, skeletonFlipY = skeleton.flipY;
|
|
|
+ this.worldX = skeletonFlipX ? -this.x : this.x;
|
|
|
+ this.worldY = skeletonFlipY != spine.Bone.yDown ? -this.y : this.y;
|
|
|
this.worldScaleX = this.scaleX;
|
|
|
this.worldScaleY = this.scaleY;
|
|
|
- this.worldRotation = this.rotation;
|
|
|
+ this.worldRotation = this.rotationIK;
|
|
|
+ this.worldFlipX = skeletonFlipX != this.flipX;
|
|
|
+ this.worldFlipY = skeletonFlipY != this.flipY;
|
|
|
}
|
|
|
var radians = this.worldRotation * Math.PI / 180;
|
|
|
var cos = Math.cos(radians);
|
|
|
var sin = Math.sin(radians);
|
|
|
- this.m00 = cos * this.worldScaleX;
|
|
|
- this.m10 = sin * this.worldScaleX;
|
|
|
- this.m01 = -sin * this.worldScaleY;
|
|
|
- this.m11 = cos * this.worldScaleY;
|
|
|
- if (flipX) {
|
|
|
- this.m00 = -this.m00;
|
|
|
- this.m01 = -this.m01;
|
|
|
+ if (this.worldFlipX) {
|
|
|
+ this.m00 = -cos * this.worldScaleX;
|
|
|
+ this.m10 = sin * this.worldScaleX;
|
|
|
+ } else {
|
|
|
+ this.m00 = cos * this.worldScaleX;
|
|
|
+ this.m10 = -sin * this.worldScaleX;
|
|
|
}
|
|
|
- if (flipY != spine.Bone.yDown) {
|
|
|
- this.m10 = -this.m10;
|
|
|
- this.m11 = -this.m11;
|
|
|
+ if (this.worldFlipY != spine.Bone.yDown) {
|
|
|
+ this.m01 = -sin * this.worldScaleY;
|
|
|
+ this.m11 = -cos * this.worldScaleY;
|
|
|
+ } else {
|
|
|
+ this.m01 = sin * this.worldScaleY;
|
|
|
+ this.m11 = cos * this.worldScaleY;
|
|
|
}
|
|
|
},
|
|
|
setToSetupPose: function () {
|
|
@@ -108,14 +129,32 @@ spine.Bone.prototype = {
|
|
|
this.x = data.x;
|
|
|
this.y = data.y;
|
|
|
this.rotation = data.rotation;
|
|
|
+ this.rotationIK = this.rotation;
|
|
|
this.scaleX = data.scaleX;
|
|
|
this.scaleY = data.scaleY;
|
|
|
+ this.flipX = data.flipX;
|
|
|
+ this.flipY = data.flipY;
|
|
|
+ },
|
|
|
+ worldToLocal: function (world) void {
|
|
|
+ var dx = world[0] - this.worldX, dy = world[1] - this.worldY;
|
|
|
+ var m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11;
|
|
|
+ if (this.worldFlipX != (this.worldFlipY != spine.Bone.yDown)) {
|
|
|
+ m00 = -m00;
|
|
|
+ m11 = -m11;
|
|
|
+ }
|
|
|
+ var invDet = 1 / (m00 * m11 - m01 * m10);
|
|
|
+ world[0] = (dx * m00 * invDet - dy * m01 * invDet);
|
|
|
+ world[1] = (dy * m11 * invDet - dx * m10 * invDet);
|
|
|
+ },
|
|
|
+ localToWorld: function (local) {
|
|
|
+ var localX = local[0], localY = local[1];
|
|
|
+ local[0] = localX * this.m00 + localY * this.m01 + this.worldX;
|
|
|
+ local[1] = localX * this.m10 + localY * this.m11 + this.worldY;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-spine.Slot = function (slotData, skeleton, bone) {
|
|
|
+spine.Slot = function (slotData, bone) {
|
|
|
this.data = slotData;
|
|
|
- this.skeleton = skeleton;
|
|
|
this.bone = bone;
|
|
|
this.setToSetupPose();
|
|
|
};
|
|
@@ -126,14 +165,14 @@ spine.Slot.prototype = {
|
|
|
attachmentVertices: [],
|
|
|
setAttachment: function (attachment) {
|
|
|
this.attachment = attachment;
|
|
|
- this._attachmentTime = this.skeleton.time;
|
|
|
+ this._attachmentTime = this.bone.skeleton.time;
|
|
|
this.attachmentVertices.length = 0;
|
|
|
},
|
|
|
setAttachmentTime: function (time) {
|
|
|
- this._attachmentTime = this.skeleton.time - time;
|
|
|
+ this._attachmentTime = this.bone.skeleton.time - time;
|
|
|
},
|
|
|
getAttachmentTime: function () {
|
|
|
- return this.skeleton.time - this._attachmentTime;
|
|
|
+ return this.bone.skeleton.time - this._attachmentTime;
|
|
|
},
|
|
|
setToSetupPose: function () {
|
|
|
var data = this.data;
|
|
@@ -142,16 +181,28 @@ spine.Slot.prototype = {
|
|
|
this.b = data.b;
|
|
|
this.a = data.a;
|
|
|
|
|
|
- var slotDatas = this.skeleton.data.slots;
|
|
|
+ var slotDatas = this.bone.skeleton.data.slots;
|
|
|
for (var i = 0, n = slotDatas.length; i < n; i++) {
|
|
|
if (slotDatas[i] == data) {
|
|
|
- this.setAttachment(!data.attachmentName ? null : this.skeleton.getAttachmentBySlotIndex(i, data.attachmentName));
|
|
|
+ this.setAttachment(!data.attachmentName ? null : this.bone.skeleton.getAttachmentBySlotIndex(i, data.attachmentName));
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+spine.IkConstraint = function (data, skeleton) {
|
|
|
+ this.data = data;
|
|
|
+ this.mix = data.mix;
|
|
|
+ this.bendDirection = data.bendDirection;
|
|
|
+
|
|
|
+ this.bones = [];
|
|
|
+ for (var i = 0, n = data.bones.length; i < n; i++)
|
|
|
+ this.bones.push(skeleton.findBone(data.bones[i].name));
|
|
|
+ this.target = skeleton.findBone(data.target.name);
|
|
|
+};
|
|
|
+spine.IkConstraint.prototype = {};
|
|
|
+
|
|
|
spine.Skin = function (name) {
|
|
|
this.name = name;
|
|
|
this.attachments = {};
|
|
@@ -217,6 +268,20 @@ spine.binarySearch = function (values, target, step) {
|
|
|
current = (low + high) >>> 1;
|
|
|
}
|
|
|
};
|
|
|
+spine.binarySearch1 = function (values, target) {
|
|
|
+ var low = 0;
|
|
|
+ var high = values.length - 2;
|
|
|
+ if (high == 0) return step;
|
|
|
+ var current = high >>> 1;
|
|
|
+ while (true) {
|
|
|
+ if (values[current + 1] <= target)
|
|
|
+ low = current + 1;
|
|
|
+ else
|
|
|
+ high = current;
|
|
|
+ if (low == high) return low + 1;
|
|
|
+ current = (low + high) >>> 1;
|
|
|
+ }
|
|
|
+};
|
|
|
spine.linearSearch = function (values, target, step) {
|
|
|
for (var i = 0, last = values.length - step; i <= last; i += step)
|
|
|
if (values[i] > target) return i;
|
|
@@ -224,62 +289,35 @@ spine.linearSearch = function (values, target, step) {
|
|
|
};
|
|
|
|
|
|
spine.Curves = function (frameCount) {
|
|
|
- this.curves = []; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ...
|
|
|
- this.curves.length = (frameCount - 1) * 6;
|
|
|
+ this.curves = []; // type, x, y, ...
|
|
|
+ this.curves.length = (frameCount - 1) * 19/*BEZIER_SIZE*/;
|
|
|
};
|
|
|
spine.Curves.prototype = {
|
|
|
setLinear: function (frameIndex) {
|
|
|
- this.curves[frameIndex * 6] = 0/*LINEAR*/;
|
|
|
+ this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 0/*LINEAR*/;
|
|
|
},
|
|
|
setStepped: function (frameIndex) {
|
|
|
- this.curves[frameIndex * 6] = -1/*STEPPED*/;
|
|
|
+ this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 1/*STEPPED*/;
|
|
|
},
|
|
|
/** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next.
|
|
|
* cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of
|
|
|
* the difference between the keyframe's values. */
|
|
|
setCurve: function (frameIndex, cx1, cy1, cx2, cy2) {
|
|
|
- var subdiv_step = 1 / 10/*BEZIER_SEGMENTS*/;
|
|
|
- var subdiv_step2 = subdiv_step * subdiv_step;
|
|
|
- var subdiv_step3 = subdiv_step2 * subdiv_step;
|
|
|
- var pre1 = 3 * subdiv_step;
|
|
|
- var pre2 = 3 * subdiv_step2;
|
|
|
- var pre4 = 6 * subdiv_step2;
|
|
|
- var pre5 = 6 * subdiv_step3;
|
|
|
- var tmp1x = -cx1 * 2 + cx2;
|
|
|
- var tmp1y = -cy1 * 2 + cy2;
|
|
|
- var tmp2x = (cx1 - cx2) * 3 + 1;
|
|
|
- var tmp2y = (cy1 - cy2) * 3 + 1;
|
|
|
- var i = frameIndex * 6;
|
|
|
+ var subdiv1 = 1f / 10/*BEZIER_SEGMENTS*/, subdiv2 = subdiv1 * subdiv1, subdiv3 = subdiv2 * subdiv1;
|
|
|
+ var pre1 = 3 * subdiv1, pre2 = 3 * subdiv2, pre4 = 6 * subdiv2, pre5 = 6 * subdiv3;
|
|
|
+ var tmp1x = -cx1 * 2 + cx2, tmp1y = -cy1 * 2 + cy2, tmp2x = (cx1 - cx2) * 3 + 1, tmp2y = (cy1 - cy2) * 3 + 1;
|
|
|
+ var dfx = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv3, dfy = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv3;
|
|
|
+ var ddfx = tmp1x * pre4 + tmp2x * pre5, ddfy = tmp1y * pre4 + tmp2y * pre5;
|
|
|
+ var dddfx = tmp2x * pre5, dddfy = tmp2y * pre5;
|
|
|
+
|
|
|
+ var i = frameIndex * 19/*BEZIER_SIZE*/;
|
|
|
var curves = this.curves;
|
|
|
- curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3;
|
|
|
- curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3;
|
|
|
- curves[i + 2] = tmp1x * pre4 + tmp2x * pre5;
|
|
|
- curves[i + 3] = tmp1y * pre4 + tmp2y * pre5;
|
|
|
- curves[i + 4] = tmp2x * pre5;
|
|
|
- curves[i + 5] = tmp2y * pre5;
|
|
|
- },
|
|
|
- getCurvePercent: function (frameIndex, percent) {
|
|
|
- percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent);
|
|
|
- var curveIndex = frameIndex * 6;
|
|
|
- var curves = this.curves;
|
|
|
- var dfx = curves[curveIndex];
|
|
|
- if (!dfx/*LINEAR*/) return percent;
|
|
|
- if (dfx == -1/*STEPPED*/) return 0;
|
|
|
- var dfy = curves[curveIndex + 1];
|
|
|
- var ddfx = curves[curveIndex + 2];
|
|
|
- var ddfy = curves[curveIndex + 3];
|
|
|
- var dddfx = curves[curveIndex + 4];
|
|
|
- var dddfy = curves[curveIndex + 5];
|
|
|
+ curves[i++] = 2/*BEZIER*/;
|
|
|
+
|
|
|
var x = dfx, y = dfy;
|
|
|
- var i = 10/*BEZIER_SEGMENTS*/ - 2;
|
|
|
- while (true) {
|
|
|
- if (x >= percent) {
|
|
|
- var lastX = x - dfx;
|
|
|
- var lastY = y - dfy;
|
|
|
- return lastY + (y - lastY) * (percent - lastX) / (x - lastX);
|
|
|
- }
|
|
|
- if (i == 0) break;
|
|
|
- i--;
|
|
|
+ for (var n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) {
|
|
|
+ curves[i] = x;
|
|
|
+ curves[i + 1] = y;
|
|
|
dfx += ddfx;
|
|
|
dfy += ddfy;
|
|
|
ddfx += dddfx;
|
|
@@ -287,6 +325,31 @@ spine.Curves.prototype = {
|
|
|
x += dfx;
|
|
|
y += dfy;
|
|
|
}
|
|
|
+ },
|
|
|
+ getCurvePercent: function (frameIndex, percent) {
|
|
|
+ percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent);
|
|
|
+ var curves = this.curves;
|
|
|
+ var i = frameIndex * 10/*BEZIER_SIZE*/;
|
|
|
+ var type = curves[i];
|
|
|
+ if (type == 0/*LINEAR*/) return percent;
|
|
|
+ if (type == 1/*STEPPED*/) return 0;
|
|
|
+ i++;
|
|
|
+ var x = 0;
|
|
|
+ for (var start = i, n = i + 10/*BEZIER_SIZE*/ - 1; i < n; i += 2) {
|
|
|
+ x = curves[i];
|
|
|
+ if (x >= percent) {
|
|
|
+ var prevX, prevY;
|
|
|
+ if (i == start) {
|
|
|
+ prevX = 0;
|
|
|
+ prevY = 0;
|
|
|
+ } else {
|
|
|
+ prevX = curves[i - 2];
|
|
|
+ prevY = curves[i - 1];
|
|
|
+ }
|
|
|
+ return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var y = curves[i - 1];
|
|
|
return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
|
|
|
}
|
|
|
};
|
|
@@ -322,19 +385,19 @@ spine.RotateTimeline.prototype = {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // Interpolate between the last frame and the current frame.
|
|
|
+ // Interpolate between the previous frame and the current frame.
|
|
|
var frameIndex = spine.binarySearch(frames, time, 2);
|
|
|
- var lastFrameValue = frames[frameIndex - 1];
|
|
|
+ var prevFrameValue = frames[frameIndex - 1];
|
|
|
var frameTime = frames[frameIndex];
|
|
|
- var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*LAST_FRAME_TIME*/] - frameTime);
|
|
|
+ var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*PREV_FRAME_TIME*/] - frameTime);
|
|
|
percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent);
|
|
|
|
|
|
- var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - lastFrameValue;
|
|
|
+ var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - prevFrameValue;
|
|
|
while (amount > 180)
|
|
|
amount -= 360;
|
|
|
while (amount < -180)
|
|
|
amount += 360;
|
|
|
- amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation;
|
|
|
+ amount = bone.data.rotation + (prevFrameValue + amount * percent) - bone.rotation;
|
|
|
while (amount > 180)
|
|
|
amount -= 360;
|
|
|
while (amount < -180)
|
|
@@ -371,16 +434,16 @@ spine.TranslateTimeline.prototype = {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // Interpolate between the last frame and the current frame.
|
|
|
+ // Interpolate between the previous frame and the current frame.
|
|
|
var frameIndex = spine.binarySearch(frames, time, 3);
|
|
|
- var lastFrameX = frames[frameIndex - 2];
|
|
|
- var lastFrameY = frames[frameIndex - 1];
|
|
|
+ var prevFrameX = frames[frameIndex - 2];
|
|
|
+ var prevFrameY = frames[frameIndex - 1];
|
|
|
var frameTime = frames[frameIndex];
|
|
|
- var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime);
|
|
|
+ var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime);
|
|
|
percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
|
|
|
|
|
|
- bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent - bone.x) * alpha;
|
|
|
- bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent - bone.y) * alpha;
|
|
|
+ bone.x += (bone.data.x + prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent - bone.x) * alpha;
|
|
|
+ bone.y += (bone.data.y + prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent - bone.y) * alpha;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -412,16 +475,16 @@ spine.ScaleTimeline.prototype = {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // Interpolate between the last frame and the current frame.
|
|
|
+ // Interpolate between the previous frame and the current frame.
|
|
|
var frameIndex = spine.binarySearch(frames, time, 3);
|
|
|
- var lastFrameX = frames[frameIndex - 2];
|
|
|
- var lastFrameY = frames[frameIndex - 1];
|
|
|
+ var prevFrameX = frames[frameIndex - 2];
|
|
|
+ var prevFrameY = frames[frameIndex - 1];
|
|
|
var frameTime = frames[frameIndex];
|
|
|
- var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*LAST_FRAME_TIME*/] - frameTime);
|
|
|
+ var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime);
|
|
|
percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
|
|
|
|
|
|
- bone.scaleX += (bone.data.scaleX * (lastFrameX + (frames[frameIndex + 1/*FRAME_X*/] - lastFrameX) * percent) - bone.scaleX) * alpha;
|
|
|
- bone.scaleY += (bone.data.scaleY * (lastFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - lastFrameY) * percent) - bone.scaleY) * alpha;
|
|
|
+ bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent) - bone.scaleX) * alpha;
|
|
|
+ bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent) - bone.scaleY) * alpha;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -456,20 +519,20 @@ spine.ColorTimeline.prototype = {
|
|
|
b = frames[i - 1];
|
|
|
a = frames[i];
|
|
|
} else {
|
|
|
- // Interpolate between the last frame and the current frame.
|
|
|
+ // Interpolate between the previous frame and the current frame.
|
|
|
var frameIndex = spine.binarySearch(frames, time, 5);
|
|
|
- var lastFrameR = frames[frameIndex - 4];
|
|
|
- var lastFrameG = frames[frameIndex - 3];
|
|
|
- var lastFrameB = frames[frameIndex - 2];
|
|
|
- var lastFrameA = frames[frameIndex - 1];
|
|
|
+ var prevFrameR = frames[frameIndex - 4];
|
|
|
+ var prevFrameG = frames[frameIndex - 3];
|
|
|
+ var prevFrameB = frames[frameIndex - 2];
|
|
|
+ var prevFrameA = frames[frameIndex - 1];
|
|
|
var frameTime = frames[frameIndex];
|
|
|
- var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*LAST_FRAME_TIME*/] - frameTime);
|
|
|
+ var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*PREV_FRAME_TIME*/] - frameTime);
|
|
|
percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent);
|
|
|
|
|
|
- r = lastFrameR + (frames[frameIndex + 1/*FRAME_R*/] - lastFrameR) * percent;
|
|
|
- g = lastFrameG + (frames[frameIndex + 2/*FRAME_G*/] - lastFrameG) * percent;
|
|
|
- b = lastFrameB + (frames[frameIndex + 3/*FRAME_B*/] - lastFrameB) * percent;
|
|
|
- a = lastFrameA + (frames[frameIndex + 4/*FRAME_A*/] - lastFrameA) * percent;
|
|
|
+ r = prevFrameR + (frames[frameIndex + 1/*FRAME_R*/] - prevFrameR) * percent;
|
|
|
+ g = prevFrameG + (frames[frameIndex + 2/*FRAME_G*/] - prevFrameG) * percent;
|
|
|
+ b = prevFrameB + (frames[frameIndex + 3/*FRAME_B*/] - prevFrameB) * percent;
|
|
|
+ a = prevFrameA + (frames[frameIndex + 4/*FRAME_A*/] - prevFrameA) * percent;
|
|
|
}
|
|
|
var slot = skeleton.slots[this.slotIndex];
|
|
|
if (alpha < 1) {
|
|
@@ -504,16 +567,18 @@ spine.AttachmentTimeline.prototype = {
|
|
|
},
|
|
|
apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
|
var frames = this.frames;
|
|
|
- if (time < frames[0]) return; // Time is before first frame.
|
|
|
+ if (time < frames[0]) {
|
|
|
+ if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0);
|
|
|
+ return;
|
|
|
+ } else if (lastTime > time) //
|
|
|
+ lastTime = -1;
|
|
|
|
|
|
- var frameIndex;
|
|
|
- if (time >= frames[frames.length - 1]) // Time is after last frame.
|
|
|
- frameIndex = frames.length - 1;
|
|
|
- else
|
|
|
- frameIndex = spine.binarySearch(frames, time, 1) - 1;
|
|
|
+ var frameIndex = time >= frames[frames.length - 1] ? frames.length - 1 : spine.binarySearch1(frames, time) - 1;
|
|
|
+ if (frames[frameIndex] < lastTime) return;
|
|
|
|
|
|
var attachmentName = this.attachmentNames[frameIndex];
|
|
|
- skeleton.slots[this.slotIndex].setAttachment(!attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName));
|
|
|
+ skeleton.slots[this.slotIndex].setAttachment(
|
|
|
+ !attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName));
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -549,7 +614,7 @@ spine.EventTimeline.prototype = {
|
|
|
if (lastTime < frames[0])
|
|
|
frameIndex = 0;
|
|
|
else {
|
|
|
- frameIndex = spine.binarySearch(frames, lastTime, 1);
|
|
|
+ frameIndex = spine.binarySearch1(frames, lastTime);
|
|
|
var frame = frames[frameIndex];
|
|
|
while (frameIndex > 0) { // Fire multiple events with the same frame.
|
|
|
if (frames[frameIndex - 1] != frame) break;
|
|
@@ -584,7 +649,7 @@ spine.DrawOrderTimeline.prototype = {
|
|
|
if (time >= frames[frames.length - 1]) // Time is after last frame.
|
|
|
frameIndex = frames.length - 1;
|
|
|
else
|
|
|
- frameIndex = spine.binarySearch(frames, time, 1) - 1;
|
|
|
+ frameIndex = spine.binarySearch1(frames, time) - 1;
|
|
|
|
|
|
var drawOrder = skeleton.drawOrder;
|
|
|
var slots = skeleton.slots;
|
|
@@ -647,7 +712,7 @@ spine.FfdTimeline.prototype = {
|
|
|
}
|
|
|
|
|
|
// Interpolate between the previous frame and the current frame.
|
|
|
- var frameIndex = spine.binarySearch(frames, time, 1);
|
|
|
+ var frameIndex = spine.binarySearch1(frames, time);
|
|
|
var frameTime = frames[frameIndex];
|
|
|
var percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime);
|
|
|
percent = this.curves.getCurvePercent(frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
|
@@ -669,15 +734,115 @@ spine.FfdTimeline.prototype = {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+spine.IkConstraintTimeline = function (frameCount) {
|
|
|
+ this.curves = new spine.Curves(frameCount);
|
|
|
+ this.frames = []; // time, mix, bendDirection, ...
|
|
|
+ this.frames.length = frameCount * 3;
|
|
|
+};
|
|
|
+spine.IkConstraintTimeline.prototype = {
|
|
|
+ ikConstraintIndex: 0,
|
|
|
+ getFrameCount: function () {
|
|
|
+ return this.frames.length / 3;
|
|
|
+ },
|
|
|
+ setFrame: function (frameIndex, time, mix, bendDirection) {
|
|
|
+ frameIndex *= 3;
|
|
|
+ this.frames[frameIndex] = time;
|
|
|
+ this.frames[frameIndex + 1] = mix;
|
|
|
+ this.frames[frameIndex + 2] = bendDirection;
|
|
|
+ },
|
|
|
+ apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
|
+ var frames = this.frames;
|
|
|
+ if (time < frames[0]) return; // Time is before first frame.
|
|
|
+
|
|
|
+ var ikConstraint = skeleton.ikConstraints[this.ikConstraintIndex];
|
|
|
+
|
|
|
+ if (time >= frames[frames.length - 3]) { // Time is after last frame.
|
|
|
+ ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha;
|
|
|
+ ikConstraint.bendDirection = frames[frames.length - 1];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Interpolate between the previous frame and the current frame.
|
|
|
+ var frameIndex = spine.binarySearch(frames, time, 3);
|
|
|
+ var prevFrameMix = frames[frameIndex + -2/*PREV_FRAME_MIX*/];
|
|
|
+ var frameTime = frames[frameIndex];
|
|
|
+ var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime);
|
|
|
+ percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent);
|
|
|
+
|
|
|
+ var mix = prevFrameMix + (frames[frameIndex + 1/*FRAME_MIX*/] - prevFrameMix) * percent;
|
|
|
+ ikConstraint.mix += (mix - ikConstraint.mix) * alpha;
|
|
|
+ ikConstraint.bendDirection = frames[frameIndex + -1/*PREV_FRAME_BEND_DIRECTION*/];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+spine.FlipXTimeline = function (frameCount) {
|
|
|
+ this.curves = new spine.Curves(frameCount);
|
|
|
+ this.frames = []; // time, flip, ...
|
|
|
+ this.frames.length = frameCount * 2;
|
|
|
+};
|
|
|
+spine.FlipXTimeline.prototype = {
|
|
|
+ boneIndex: 0,
|
|
|
+ getFrameCount: function () {
|
|
|
+ return this.frames.length / 2;
|
|
|
+ },
|
|
|
+ setFrame: function (frameIndex, time, flip) {
|
|
|
+ frameIndex *= 2;
|
|
|
+ this.frames[frameIndex] = time;
|
|
|
+ this.frames[frameIndex + 1] = flip ? 1 : 0;
|
|
|
+ },
|
|
|
+ apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
|
+ var frames = this.frames;
|
|
|
+ if (time < frames[0]) {
|
|
|
+ if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0);
|
|
|
+ return;
|
|
|
+ } else if (lastTime > time) //
|
|
|
+ lastTime = -1;
|
|
|
+ var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.binarySearch(frames, time, 2)) - 2;
|
|
|
+ if (frames[frameIndex] < lastTime) return;
|
|
|
+ bone.flipX = skeleton.bones.get(boneIndex), frames[frameIndex + 1] != 0;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+spine.FlipYTimeline = function (frameCount) {
|
|
|
+ this.curves = new spine.Curves(frameCount);
|
|
|
+ this.frames = []; // time, flip, ...
|
|
|
+ this.frames.length = frameCount * 2;
|
|
|
+};
|
|
|
+spine.FlipYTimeline.prototype = {
|
|
|
+ boneIndex: 0,
|
|
|
+ getFrameCount: function () {
|
|
|
+ return this.frames.length / 2;
|
|
|
+ },
|
|
|
+ setFrame: function (frameIndex, time, flip) {
|
|
|
+ frameIndex *= 2;
|
|
|
+ this.frames[frameIndex] = time;
|
|
|
+ this.frames[frameIndex + 1] = flip ? 1 : 0;
|
|
|
+ },
|
|
|
+ apply: function (skeleton, lastTime, time, firedEvents, alpha) {
|
|
|
+ var frames = this.frames;
|
|
|
+ if (time < frames[0]) {
|
|
|
+ if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0);
|
|
|
+ return;
|
|
|
+ } else if (lastTime > time) //
|
|
|
+ lastTime = -1;
|
|
|
+ var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.binarySearch(frames, time, 2)) - 2;
|
|
|
+ if (frames[frameIndex] < lastTime) return;
|
|
|
+ bone.flipY = skeleton.bones.get(boneIndex), frames[frameIndex + 1] != 0;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
spine.SkeletonData = function () {
|
|
|
this.bones = [];
|
|
|
this.slots = [];
|
|
|
this.skins = [];
|
|
|
this.events = [];
|
|
|
this.animations = [];
|
|
|
+ this.ikConstraints = [];
|
|
|
};
|
|
|
spine.SkeletonData.prototype = {
|
|
|
defaultSkin: null,
|
|
|
+ width: 0, height: 0,
|
|
|
+ version: null, hash: null,
|
|
|
/** @return May be null. */
|
|
|
findBone: function (boneName) {
|
|
|
var bones = this.bones;
|
|
@@ -727,6 +892,13 @@ spine.SkeletonData.prototype = {
|
|
|
for (var i = 0, n = animations.length; i < n; i++)
|
|
|
if (animations[i].name == animationName) return animations[i];
|
|
|
return null;
|
|
|
+ },
|
|
|
+ /** @return May be null. */
|
|
|
+ findIkConstraint: function (ikConstraintName) {
|
|
|
+ var ikConstraints = this.ikConstraints;
|
|
|
+ for (var i = 0, n = ikConstraints.length; i < n; i++)
|
|
|
+ if (ikConstraints[i].name == ikConstraintName) return ikConstraints[i];
|
|
|
+ return null;
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -737,7 +909,7 @@ spine.Skeleton = function (skeletonData) {
|
|
|
for (var i = 0, n = skeletonData.bones.length; i < n; i++) {
|
|
|
var boneData = skeletonData.bones[i];
|
|
|
var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)];
|
|
|
- this.bones.push(new spine.Bone(boneData, parent));
|
|
|
+ this.bones.push(new spine.Bone(boneData, this, parent));
|
|
|
}
|
|
|
|
|
|
this.slots = [];
|
|
@@ -745,10 +917,17 @@ spine.Skeleton = function (skeletonData) {
|
|
|
for (var i = 0, n = skeletonData.slots.length; i < n; i++) {
|
|
|
var slotData = skeletonData.slots[i];
|
|
|
var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)];
|
|
|
- var slot = new spine.Slot(slotData, this, bone);
|
|
|
+ var slot = new spine.Slot(slotData, bone);
|
|
|
this.slots.push(slot);
|
|
|
this.drawOrder.push(slot);
|
|
|
}
|
|
|
+
|
|
|
+ this.ikConstraints = [];
|
|
|
+ for (var i = 0, n = skeletonData.ikConstraints.length; i < n; i++)
|
|
|
+ this.ikConstraints.push(new spine.IkConstraint(skeletonData.ikConstraints[i], this));
|
|
|
+
|
|
|
+ this.boneCache = [];
|
|
|
+ this.updateCache();
|
|
|
};
|
|
|
spine.Skeleton.prototype = {
|
|
|
x: 0, y: 0,
|
|
@@ -756,13 +935,63 @@ spine.Skeleton.prototype = {
|
|
|
r: 1, g: 1, b: 1, a: 1,
|
|
|
time: 0,
|
|
|
flipX: false, flipY: false,
|
|
|
+ updateCache: function () {
|
|
|
+ var ikConstraints = this.ikConstraints;
|
|
|
+ var ikConstraintsCount = ikConstraints.length;
|
|
|
+
|
|
|
+ var arrayCount = ikConstraintsCount + 1;
|
|
|
+ var boneCache = this.boneCache;
|
|
|
+ if (boneCache.length > arrayCount) boneCache.splice(arrayCount, boneCache.length - arrayCount);
|
|
|
+
|
|
|
+ for (var i = 0, n = boneCache.length; i < n; i++)
|
|
|
+ boneCache[i].length = 0;
|
|
|
+ while (boneCache.length < arrayCount)
|
|
|
+ boneCache[boneCache.length] = [];
|
|
|
+
|
|
|
+ var nonIkBones = boneCache[0];
|
|
|
+ var bones = this.bones;
|
|
|
+
|
|
|
+ outer:
|
|
|
+ for (var i = 0, n = bones.length; i < n; i++) {
|
|
|
+ var bone = bones[i];
|
|
|
+ var current = bone;
|
|
|
+ do {
|
|
|
+ for (var ii = 0, nn = bones.length; ii < nn; ii++) {
|
|
|
+ var ikConstraint = ikConstraints[ii];
|
|
|
+ var parent = ikConstraint.bones[0];
|
|
|
+ var child= ikConstraint.bones[ikConstraint.bones.length - 1];
|
|
|
+ while (true) {
|
|
|
+ if (current == child) {
|
|
|
+ boneCache[ii].push(bone);
|
|
|
+ boneCache[ii + 1].push(bone);
|
|
|
+ continue outer;
|
|
|
+ }
|
|
|
+ if (child == parent) break;
|
|
|
+ child = child.parent;
|
|
|
+ }
|
|
|
+ ii++;
|
|
|
+ }
|
|
|
+ current = current.parent;
|
|
|
+ } while (current != null);
|
|
|
+ nonIkBones[nonIkBones.length] = bone;
|
|
|
+ }
|
|
|
+ },
|
|
|
/** Updates the world transform for each bone. */
|
|
|
updateWorldTransform: function () {
|
|
|
- var flipX = this.flipX;
|
|
|
- var flipY = this.flipY;
|
|
|
var bones = this.bones;
|
|
|
- for (var i = 0, n = bones.length; i < n; i++)
|
|
|
- bones[i].updateWorldTransform(flipX, flipY);
|
|
|
+ for (var i = 0, n = bones.length; i < n; i++) {
|
|
|
+ var bone = bones[i];
|
|
|
+ bone.rotationIK = bone.rotation;
|
|
|
+ }
|
|
|
+ var i = 0, last = this.boneCache.length - 1;
|
|
|
+ while (true) {
|
|
|
+ var cacheBones = this.boneCache[i];
|
|
|
+ for (var ii = 0, nn = cacheBones.length; ii < nn; ii++)
|
|
|
+ cacheBones[ii].updateWorldTransform();
|
|
|
+ if (i == last) break;
|
|
|
+ this.ikConstraints[i].apply();
|
|
|
+ i++;
|
|
|
+ }
|
|
|
},
|
|
|
/** Sets the bones and slots to their setup pose values. */
|
|
|
setToSetupPose: function () {
|
|
@@ -773,6 +1002,13 @@ spine.Skeleton.prototype = {
|
|
|
var bones = this.bones;
|
|
|
for (var i = 0, n = bones.length; i < n; i++)
|
|
|
bones[i].setToSetupPose();
|
|
|
+
|
|
|
+ var ikConstraints = this.ikConstraints;
|
|
|
+ for (var i = 0, n = ikConstraints.length; i < n; i++) {
|
|
|
+ var ikConstraint = ikConstraints[i];
|
|
|
+ ikConstraint.bendDirection = ikConstraint.data.bendDirection;
|
|
|
+ ikConstraint.mix = ikConstraint.data.mix;
|
|
|
+ }
|
|
|
},
|
|
|
setSlotsToSetupPose: function () {
|
|
|
var slots = this.slots;
|
|
@@ -871,6 +1107,12 @@ spine.Skeleton.prototype = {
|
|
|
}
|
|
|
throw "Slot not found: " + slotName;
|
|
|
},
|
|
|
+ findIkConstraint: function (ikConstraintName) {
|
|
|
+ var ikConstraints = this.ikConstraints;
|
|
|
+ for (var i = 0, n = ikConstraints.length; i < n; i++)
|
|
|
+ if (ikConstraints[i].data.name == ikConstraintName) return ikConstraints[i];
|
|
|
+ return null;
|
|
|
+ },
|
|
|
update: function (delta) {
|
|
|
this.time += delta;
|
|
|
}
|
|
@@ -1081,7 +1323,7 @@ spine.SkinnedMeshAttachment.prototype = {
|
|
|
}
|
|
|
},
|
|
|
computeWorldVertices: function (x, y, slot, worldVertices) {
|
|
|
- var skeletonBones = slot.skeleton.bones;
|
|
|
+ var skeletonBones = slot.bone.skeleton.bones;
|
|
|
var weights = this.weights;
|
|
|
var bones = this.bones;
|
|
|
|
|
@@ -1386,6 +1628,28 @@ spine.SkeletonJson.prototype = {
|
|
|
skeletonData.bones.push(boneData);
|
|
|
}
|
|
|
|
|
|
+ // IK constraints.
|
|
|
+ var ik = root["ik"];
|
|
|
+ for (var i = 0, n = ik.length; i < n; i++) {
|
|
|
+ var ikMap = ik[i];
|
|
|
+ var ikConstraintData = new spine.IkConstraintData(ikMap["name"]);
|
|
|
+
|
|
|
+ var bones = ikMap["bones"];
|
|
|
+ for (var ii = 0, nn = bones.length; ii < nn; ii++) {
|
|
|
+ var bone = skeletonData.findBone(bones[ii]);
|
|
|
+ if (!bone) throw "IK bone not found: " + bones[ii];
|
|
|
+ ikConstraintData.bones.push(bone);
|
|
|
+ }
|
|
|
+
|
|
|
+ ikConstraintData.target = skeletonData.findBone(ikMap["target"]);
|
|
|
+ if (!ikConstraintData.target) throw "Target bone not found: " + ikMap["target"];
|
|
|
+
|
|
|
+ ikConstraintData.bendDirection = (!ikMap.hasOwnProperty("bendPositive") || ikMap["bendPositive"]) ? 1 : -1;
|
|
|
+ ikConstraintData.mix = ikMap.hasOwnProperty("mix") ? ikMap["mix"] : 1;
|
|
|
+
|
|
|
+ skeletonData.ikConstraints.push(ikConstraintData);
|
|
|
+ }
|
|
|
+
|
|
|
// Slots.
|
|
|
var slots = root["slots"];
|
|
|
for (var i = 0, n = slots.length; i < n; i++) {
|
|
@@ -1649,6 +1913,26 @@ spine.SkeletonJson.prototype = {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ var ikMap = map["ik"];
|
|
|
+ for (var ikConstraintName in ikMap) {
|
|
|
+ if (!ikMap.hasOwnProperty(ikConstraintName)) continue;
|
|
|
+ var ikConstraint = skeletonData.findIkConstraint(ikConstraintName);
|
|
|
+ var values = ikMap[ikConstraintName];
|
|
|
+ var timeline = new spine.IkConstraintTimeline(values.length);
|
|
|
+ timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(ikConstraint);
|
|
|
+ var frameIndex = 0;
|
|
|
+ for (var i = 0, n = values.length; i < n; i++) {
|
|
|
+ var valueMap = values[i];
|
|
|
+ var mix = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1;
|
|
|
+ var bendDirection = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1;
|
|
|
+ timeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection);
|
|
|
+ this.readCurve(timeline, frameIndex, valueMap);
|
|
|
+ frameIndex++;
|
|
|
+ }
|
|
|
+ timelines.push(timeline);
|
|
|
+ duration = Math.max(duration, timeline.frames[timeline.frameCount * 3 - 3]);
|
|
|
+ }
|
|
|
+
|
|
|
var ffd = map["ffd"];
|
|
|
for (var skinName in ffd) {
|
|
|
var skin = skeletonData.findSkin(skinName);
|