[ts] Updated to 3.5, constraint order from export, applied bone attributes. Changes to Animation and AnimationState have not been ported yet

This commit is contained in:
badlogic 2016-10-17 13:48:12 +02:00
parent 02130d242e
commit bf5f0d808e
18 changed files with 8206 additions and 7989 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -35,11 +35,11 @@ module spine {
parent: Bone;
children = new Array<Bone>();
x = 0; y = 0; rotation = 0; scaleX = 0; scaleY = 0; shearX = 0; shearY = 0;
appliedRotation = 0;
ax = 0; ay = 0; arotation = 0; ascaleX = 0; ascaleY = 0; ashearX = 0; ashearY = 0;
appliedValid = false;
a = 0; b = 0; worldX = 0;
c = 0; d = 0; worldY = 0;
worldSignX = 0; worldSignY = 0;
sorted = false;
@ -65,14 +65,22 @@ module spine {
/** Computes the world transform using the parent bone and the specified local transform. */
updateWorldTransformWith (x: number, y: number, rotation: number, scaleX: number, scaleY: number, shearX: number, shearY: number) {
this.appliedRotation = rotation;
let rotationY = rotation + 90 + shearY;
let la = MathUtils.cosDeg(rotation + shearX) * scaleX, lb = MathUtils.cosDeg(rotationY) * scaleY;
let lc = MathUtils.sinDeg(rotation + shearX) * scaleX, ld = MathUtils.sinDeg(rotationY) * scaleY;
this.ax = x;
this.ay = y;
this.arotation = rotation;
this.ascaleX = scaleX;
this.ascaleY = scaleY;
this.ashearX = shearX;
this.ashearY = shearY;
this.appliedValid = true;
let parent = this.parent;
if (parent == null) { // Root bone.
let rotationY = rotation + 90 + shearY;
let la = MathUtils.cosDeg(rotation + shearX) * scaleX;
let lb = MathUtils.cosDeg(rotationY) * scaleY;
let lc = MathUtils.sinDeg(rotation + shearX) * scaleX;
let ld = MathUtils.sinDeg(rotationY) * scaleY;
let skeleton = this.skeleton;
if (skeleton.flipX) {
x = -x;
@ -88,91 +96,102 @@ module spine {
this.b = lb;
this.c = lc;
this.d = ld;
this.worldX = x;
this.worldY = y;
this.worldSignX = MathUtils.signum(scaleX);
this.worldSignY = MathUtils.signum(scaleY);
this.worldX = x + skeleton.x;
this.worldY = y + skeleton.y;
return;
}
let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
this.worldX = pa * x + pb * y + parent.worldX;
this.worldY = pc * x + pd * y + parent.worldY;
this.worldSignX = parent.worldSignX * MathUtils.signum(scaleX);
this.worldSignY = parent.worldSignY * MathUtils.signum(scaleY);
if (this.data.inheritRotation && this.data.inheritScale) {
switch (this.data.transformMode) {
case TransformMode.Normal: {
let rotationY = rotation + 90 + shearY;
let la = MathUtils.cosDeg(rotation + shearX) * scaleX;
let lb = MathUtils.cosDeg(rotationY) * scaleY;
let lc = MathUtils.sinDeg(rotation + shearX) * scaleX;
let ld = MathUtils.sinDeg(rotationY) * scaleY;
this.a = pa * la + pb * lc;
this.b = pa * lb + pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
} else {
if (this.data.inheritRotation) { // No scale inheritance.
pa = 1;
pb = 0;
pc = 0;
pd = 1;
do {
let cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation);
let temp = pa * cos + pb * sin;
pb = pb * cos - pa * sin;
pa = temp;
temp = pc * cos + pd * sin;
pd = pd * cos - pc * sin;
pc = temp;
if (!parent.data.inheritRotation) break;
parent = parent.parent;
} while (parent != null);
this.a = pa * la + pb * lc;
this.b = pa * lb + pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
} else if (this.data.inheritScale) { // No rotation inheritance.
pa = 1;
pb = 0;
pc = 0;
pd = 1;
do {
let cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation);
let psx = parent.scaleX, psy = parent.scaleY;
let za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy;
let temp = pa * za + pb * zc;
pb = pb * zd - pa * zb;
pa = temp;
temp = pc * za + pd * zc;
pd = pd * zd - pc * zb;
pc = temp;
if (psx >= 0) sin = -sin;
temp = pa * cos + pb * sin;
pb = pb * cos - pa * sin;
pa = temp;
temp = pc * cos + pd * sin;
pd = pd * cos - pc * sin;
pc = temp;
if (!parent.data.inheritScale) break;
parent = parent.parent;
} while (parent != null);
this.a = pa * la + pb * lc;
this.b = pa * lb + pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
return;
}
case TransformMode.OnlyTranslation: {
let rotationY = rotation + 90 + shearY;
this.a = MathUtils.cosDeg(rotation + shearX) * scaleX;
this.b = MathUtils.cosDeg(rotationY) * scaleY;
this.c = MathUtils.sinDeg(rotation + shearX) * scaleX;
this.d = MathUtils.sinDeg(rotationY) * scaleY;
break;
}
case TransformMode.NoRotationOrReflection: {
let psx = Math.sqrt(pa * pa + pc * pc)
let psy = 0;
let prx = 0;
if (psx > 0.0001) {
psy = Math.abs((pa * pd - pb * pc) / psx);
prx = Math.atan2(pc, pa) * MathUtils.radDeg;
} else {
this.a = la;
this.b = lb;
this.c = lc;
this.d = ld;
psx = 0;
psy = Math.sqrt(pb * pb + pd * pd);
prx = 90 - Math.atan2(pd, pb) * MathUtils.radDeg;
}
if (this.skeleton.flipX) {
this.a = -this.a;
let cos = MathUtils.cosDeg(prx);
let sin = MathUtils.sinDeg(prx);
pa = cos * psx;
pb = -sin * psy;
pc = sin * psx;
pd = cos * psy;
let rx = rotation + shearX - prx;
let ry = rotation + shearY - prx + 90;
let la = MathUtils.cosDeg(rx) * scaleX;
let lb = MathUtils.cosDeg(ry) * scaleY;
let lc = MathUtils.sinDeg(rx) * scaleX;
let ld = MathUtils.sinDeg(ry) * scaleY;
this.a = pa * la + pb * lc;
this.b = pa * lb + pb * ld;
this.c = pc * la + pd * lc;
this.d = pc * lb + pd * ld;
break;
}
case TransformMode.NoScale:
case TransformMode.NoScaleOrReflection: {
let cos = MathUtils.cosDeg(rotation);
let sin = MathUtils.sinDeg(rotation);
let za = pa * cos + pb * sin;
let zc = pc * cos + pd * sin;
let s = Math.sqrt(za * za + zc * zc);
if (s > 0.00001) s = 1 / s;
za *= s;
zc *= s;
s = Math.sqrt(za * za + zc * zc);
let r = Math.PI / 2 + Math.atan2(zc, za);
let zb = Math.cos(r) * s;
let zd = Math.sin(r) * s;
let la = MathUtils.cosDeg(shearX) * scaleX;
let lb = MathUtils.cosDeg(90 + shearY) * scaleY;
let lc = MathUtils.sinDeg(shearX) * scaleX;
let ld = MathUtils.sinDeg(90 + shearY) * scaleY;
this.a = za * la + zb * lc;
this.b = za * lb + zb * ld;
this.c = zc * la + zd * lc;
this.d = zc * lb + zd * ld;
if (this.data.transformMode != TransformMode.NoScaleOrReflection ? pa * pd - pb * pc < 0 : this.skeleton.flipX != this.skeleton.flipY) {
this.b = -this.b;
}
if (this.skeleton.flipY) {
this.c = -this.c;
this.d = -this.d;
}
return;
}
}
if (this.skeleton.flipX) {
this.a = -this.a;
this.b = -this.b;
}
if (this.skeleton.flipY) {
this.c = -this.c;
this.d = -this.d;
}
}
@ -196,23 +215,23 @@ module spine {
}
getWorldScaleX () {
return Math.sqrt(this.a * this.a + this.b * this.b) * this.worldSignX;
return Math.sqrt(this.a * this.a + this.c * this.c);
}
getWorldScaleY () {
return Math.sqrt(this.c * this.c + this.d * this.d) * this.worldSignY;
return Math.sqrt(this.b * this.b + this.d * this.d);
}
worldToLocalRotationX () {
let parent = this.parent;
if (parent == null) return this.rotation;
if (parent == null) return this.arotation;
let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c;
return Math.atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg;
}
worldToLocalRotationY () {
let parent = this.parent;
if (parent == null) return this.rotation;
if (parent == null) return this.arotation;
let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d;
return Math.atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg;
}
@ -224,31 +243,31 @@ module spine {
this.b = cos * b - sin * d;
this.c = sin * a + cos * c;
this.d = sin * b + cos * d;
this.appliedValid = false;
}
/** Computes the local transform from the world transform. This can be useful to perform processing on the local transform
* after the world transform has been modified directly (eg, by a constraint).
* <p>
* Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local
* transform values may differ from the original values but are functionally the same. */
updateLocalTransform () {
/** Computes the individual applied transform values from the world transform. This can be useful to perform processing using
* the applied transform after the world transform has been modified directly (eg, by a constraint).
* <p>
* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */
updateAppliedTransform () {
this.appliedValid = true;
let parent = this.parent;
if (parent == null) {
this.x = this.worldX;
this.y = this.worldY;
this.rotation = Math.atan2(this.c, this.a) * MathUtils.radDeg;
this.scaleX = Math.sqrt(this.a * this.a + this.c * this.c);
this.scaleY = Math.sqrt(this.b * this.b + this.d * this.d);
let det = this.a * this.d - this.b * this.c;
this.shearX = 0;
this.shearY = Math.atan2(this.a * this.b + this.c * this.d, det) * MathUtils.radDeg;
this.ax = this.worldX;
this.ay = this.worldY;
this.arotation = Math.atan2(this.c, this.a) * MathUtils.radDeg;
this.ascaleX = Math.sqrt(this.a * this.a + this.c * this.c);
this.ascaleY = Math.sqrt(this.b * this.b + this.d * this.d);
this.ashearX = 0;
this.ashearY = Math.atan2(this.a * this.b + this.c * this.d, this.a * this.d - this.b * this.c) * MathUtils.radDeg;
return;
}
let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
let pid = 1 / (pa * pd - pb * pc);
let dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY;
this.x = (dx * pd * pid - dy * pb * pid);
this.y = (dy * pa * pid - dx * pc * pid);
this.ax = (dx * pd * pid - dy * pb * pid);
this.ay = (dy * pa * pid - dx * pc * pid);
let ia = pid * pd;
let id = pid * pa;
let ib = pid * pb;
@ -257,20 +276,19 @@ module spine {
let rb = ia * this.b - ib * this.d;
let rc = id * this.c - ic * this.a;
let rd = id * this.d - ic * this.b;
this.shearX = 0;
this.scaleX = Math.sqrt(ra * ra + rc * rc);
if (this.scaleX > 0.0001) {
this.ashearX = 0;
this.ascaleX = Math.sqrt(ra * ra + rc * rc);
if (this.ascaleX > 0.0001) {
let det = ra * rd - rb * rc;
this.scaleY = det / this.scaleX;
this.shearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg;
this.rotation = Math.atan2(rc, ra) * MathUtils.radDeg;
this.ascaleY = det / this.ascaleX;
this.ashearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg;
this.arotation = Math.atan2(rc, ra) * MathUtils.radDeg;
} else {
this.scaleX = 0;
this.scaleY = Math.sqrt(rb * rb + rd * rd);
this.shearY = 0;
this.rotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg;
}
this.appliedRotation = this.rotation;
this.ascaleX = 0;
this.ascaleY = Math.sqrt(rb * rb + rd * rd);
this.ashearY = 0;
this.arotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg;
}
}
worldToLocal (world: Vector2) {

View File

@ -35,7 +35,7 @@ module spine {
parent: BoneData;
length: number;
x = 0; y = 0; rotation = 0; scaleX = 1; scaleY = 1; shearX = 0; shearY = 0;
inheritRotation = true; inheritScale = true;
transformMode = TransformMode.Normal;
constructor (index: number, name: string, parent: BoneData) {
if (index < 0) throw new Error("index must be >= 0.");
@ -45,4 +45,8 @@ module spine {
this.parent = parent;
}
}
export enum TransformMode {
Normal, OnlyTranslation, NoRotationOrReflection, NoScale, NoScaleOrReflection
}
}

View File

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

View File

@ -29,14 +29,12 @@
*****************************************************************************/
module spine {
export class IkConstraint implements Updatable {
export class IkConstraint implements Constraint {
data: IkConstraintData;
bones: Array<Bone>;
target: Bone;
mix = 1;
bendDirection = 0;
level = 0;
bendDirection = 0;
constructor (data: IkConstraintData, skeleton: Skeleton) {
if (data == null) throw new Error("data cannot be null.");
@ -51,6 +49,10 @@ module spine {
this.target = skeleton.findBone(data.target.name);
}
getOrder () {
return this.data.order;
}
apply () {
this.update();
}
@ -71,17 +73,17 @@ module spine {
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world
* coordinate system. */
apply1 (bone: Bone, targetX: number, targetY: number, alpha: number) {
let pp = bone.parent;
let id = 1 / (pp.a * pp.d - pp.b * pp.c);
let x = targetX - pp.worldX, y = targetY - pp.worldY;
let tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y;
let rotationIK = Math.atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation;
if (bone.scaleX < 0) rotationIK += 180;
let p = bone.parent;
let id = 1 / (p.a * p.d - p.b * p.c);
let x = targetX - p.worldX, y = targetY - p.worldY;
let tx = (x * p.d - y * p.b) * id - bone.ax, ty = (y * p.a - x * p.c) * id - bone.ay;
let rotationIK = Math.atan2(ty, tx) * MathUtils.radDeg - bone.ashearX - bone.arotation;
if (bone.ascaleX < 0) rotationIK += 180;
if (rotationIK > 180)
rotationIK -= 360;
else if (rotationIK < -180) rotationIK += 360;
bone.updateWorldTransformWith(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX,
bone.shearY);
bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, bone.ascaleX, bone.ascaleY, bone.ashearX,
bone.ashearY);
}
/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
@ -92,7 +94,9 @@ module spine {
child.updateWorldTransform();
return;
}
let px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX;
if (!parent.appliedValid) parent.updateAppliedTransform();
if (!child.appliedValid) child.updateAppliedTransform();
let px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, csx = child.ascaleX;
let os1 = 0, os2 = 0, s2 = 0;
if (psx < 0) {
psx = -psx;
@ -111,14 +115,14 @@ module spine {
os2 = 180;
} else
os2 = 0;
let cx = child.x, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d;
let cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d;
let u = Math.abs(psx - psy) <= 0.0001;
if (!u) {
cy = 0;
cwx = a * cx + parent.worldX;
cwy = c * cx + parent.worldY;
} else {
cy = child.y;
cy = child.ay;
cwx = a * cx + b * cy + parent.worldX;
cwy = c * cx + d * cy + parent.worldY;
}
@ -205,18 +209,18 @@ module spine {
}
}
let os = Math.atan2(cy, cx) * s2;
let rotation = parent.rotation;
let rotation = parent.arotation;
a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation;
if (a1 > 180)
a1 -= 360;
else if (a1 < -180) a1 += 360;
parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0);
rotation = child.rotation;
a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation;
parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0);
rotation = child.arotation;
a2 = ((a2 + os) * MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation;
if (a2 > 180)
a2 -= 360;
else if (a2 < -180) a2 += 360;
child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY);
child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
}
}
}

View File

@ -31,6 +31,7 @@
module spine {
export class IkConstraintData {
name: string;
order = 0;
bones = new Array<BoneData>();
target: BoneData;
bendDirection = 1;

View File

@ -29,7 +29,7 @@
*****************************************************************************/
module spine {
export class PathConstraint implements Updatable {
export class PathConstraint implements Constraint {
static NONE = -1; static BEFORE = -2; static AFTER = -3;
data: PathConstraintData;
@ -92,14 +92,12 @@ module spine {
let positions = this.computeWorldPositions(<PathAttachment>attachment, spacesCount, tangents,
data.positionMode == PositionMode.Percent, spacingMode == SpacingMode.Percent);
let skeleton = this.target.bone.skeleton;
let skeletonX = skeleton.x, skeletonY = skeleton.y;
let boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation;
let tip = rotateMode == RotateMode.Chain && offsetRotation == 0;
for (let i = 0, p = 3; i < boneCount; i++, p += 3) {
let bone = bones[i];
bone.worldX += (boneX - skeletonX - bone.worldX) * translateMix;
bone.worldY += (boneY - skeletonY - bone.worldY) * translateMix;
bone.worldX += (boneX - bone.worldX) * translateMix;
bone.worldY += (boneY - bone.worldY) * translateMix;
let x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
if (scale) {
let length = lengths[i];
@ -139,6 +137,7 @@ module spine {
bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d;
}
bone.appliedValid = false;
}
}
@ -375,7 +374,7 @@ module spine {
addCurvePosition (p: number, x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number,
out: Array<number>, o: number, tangents: boolean) {
if (p == 0) p = 0.0001;
if (p == 0 || isNaN(p)) p = 0.0001;
let tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u;
let ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p;
let x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;

View File

@ -31,6 +31,7 @@
module spine {
export class PathConstraintData {
name: string;
order = 0;
bones = new Array<BoneData>();
target: SlotData;
positionMode: PositionMode;

View File

@ -34,10 +34,11 @@ module spine {
bones: Array<Bone>;
slots: Array<Slot>;
drawOrder: Array<Slot>;
ikConstraints: Array<IkConstraint>; ikConstraintsSorted: Array<IkConstraint>;
ikConstraints: Array<IkConstraint>;
transformConstraints: Array<TransformConstraint>;
pathConstraints: Array<PathConstraint>;
_updateCache = new Array<Updatable>();
updateCacheReset = new Array<Updatable>();
skin: Skin;
color: Color;
time = 0;
@ -72,8 +73,7 @@ module spine {
this.drawOrder.push(slot);
}
this.ikConstraints = new Array<IkConstraint>();
this.ikConstraintsSorted = new Array<IkConstraint>();
this.ikConstraints = new Array<IkConstraint>();
for (let i = 0; i < data.ikConstraints.length; i++) {
let ikConstraintData = data.ikConstraints[i];
this.ikConstraints.push(new IkConstraint(ikConstraintData, this));
@ -104,93 +104,100 @@ module spine {
bones[i].sorted = false;
// IK first, lowest hierarchy depth first.
let ikConstraints = this.ikConstraintsSorted;
ikConstraints.length = 0;
for (let i = 0; i < this.ikConstraints.length; i++)
ikConstraints.push(this.ikConstraints[i]);
let ikCount = ikConstraints.length;
for (let i = 0, level = 0, n = ikCount; i < n; i++) {
let ik = ikConstraints[i];
let bone = ik.bones[0].parent;
for (level = 0; bone != null; level++)
bone = bone.parent;
ik.level = level;
}
for (let i = 1, ii = 0; i < ikCount; i++) {
let ik = ikConstraints[i];
let level = ik.level;
for (ii = i - 1; ii >= 0; ii--) {
let other = ikConstraints[ii];
if (other.level < level) break;
ikConstraints[ii + 1] = other;
}
ikConstraints[ii + 1] = ik;
}
for (let i = 0, n = ikConstraints.length; i < n; i++) {
let constraint = ikConstraints[i];
let target = constraint.target;
this.sortBone(target);
let constrained = constraint.bones;
let parent = constrained[0];
this.sortBone(parent);
updateCache.push(constraint);
this.sortReset(parent.children);
constrained[constrained.length - 1].sorted = true;
}
let pathConstraints = this.pathConstraints;
for (let i = 0, n = pathConstraints.length; i < n; i++) {
let constraint = pathConstraints[i];
let slot = constraint.target;
let slotIndex = slot.data.index;
let slotBone = slot.bone;
if (this.skin != null) this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone);
if (this.data.defaultSkin != null && this.data.defaultSkin != this.skin)
this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone);
for (let ii = 0, nn = this.data.skins.length; ii < nn; ii++)
this.sortPathConstraintAttachment(this.data.skins[ii], slotIndex, slotBone);
let attachment = slot.getAttachment();
if (attachment instanceof PathAttachment) this.sortPathConstraintAttachmentWith(attachment, slotBone);
let constrained = constraint.bones;
let boneCount = constrained.length;
for (let ii = 0; ii < boneCount; ii++)
this.sortBone(constrained[ii]);
updateCache.push(constraint);
for (let ii = 0; ii < boneCount; ii++)
this.sortReset(constrained[ii].children);
for (let ii = 0; ii < boneCount; ii++)
constrained[ii].sorted = true;
}
let ikConstraints = this.ikConstraints;
let transformConstraints = this.transformConstraints;
for (let i = 0, n = transformConstraints.length; i < n; i++) {
let constraint = transformConstraints[i];
this.sortBone(constraint.target);
let constrained = constraint.bones;
let boneCount = constrained.length;
for (let ii = 0; ii < boneCount; ii++)
this.sortBone(constrained[ii]);
updateCache.push(constraint);
for (let ii = 0; ii < boneCount; ii++)
this.sortReset(constrained[ii].children);
for (let ii = 0; ii < boneCount; ii++)
constrained[ii].sorted = true;
let pathConstraints = this.pathConstraints;
let ikCount = ikConstraints.length, transformCount = transformConstraints.length, pathCount = pathConstraints.length;
let constraintCount = ikCount + transformCount + pathCount;
outer:
for (let i = 0; i < constraintCount; i++) {
for (let ii = 0; ii < ikCount; ii++) {
let constraint = ikConstraints[ii];
if (constraint.data.order == i) {
this.sortIkConstraint(constraint);
continue outer;
}
}
for (let ii = 0; ii < transformCount; ii++) {
let constraint = transformConstraints[ii];
if (constraint.data.order == i) {
this.sortTransformConstraint(constraint);
continue outer;
}
}
for (let ii = 0; ii < pathCount; ii++) {
let constraint = pathConstraints[ii];
if (constraint.data.order == i) {
this.sortPathConstraint(constraint);
continue outer;
}
}
}
for (let i = 0, n = bones.length; i < n; i++)
this.sortBone(bones[i]);
this.sortBone(bones[i]);
}
sortIkConstraint (constraint: IkConstraint) {
let target = constraint.target;
this.sortBone(target);
let constrained = constraint.bones;
let parent = constrained[0];
this.sortBone(parent);
if (constrained.length > 1) {
let child = constrained[constrained.length - 1];
if (!(this._updateCache.indexOf(child) > -1)) this.updateCacheReset.push(child);
}
this._updateCache.push(constraint);
this.sortReset(parent.children);
constrained[constrained.length - 1].sorted = true;
}
sortPathConstraint (constraint: PathConstraint) {
let slot = constraint.target;
let slotIndex = slot.data.index;
let slotBone = slot.bone;
if (this.skin != null) this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone);
if (this.data.defaultSkin != null && this.data.defaultSkin != this.skin)
this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone);
for (let ii = 0, nn = this.data.skins.length; ii < nn; ii++)
this.sortPathConstraintAttachment(this.data.skins[ii], slotIndex, slotBone);
let attachment = slot.getAttachment();
if (attachment instanceof PathAttachment) this.sortPathConstraintAttachmentWith(attachment, slotBone);
let constrained = constraint.bones;
let boneCount = constrained.length;
for (let ii = 0; ii < boneCount; ii++)
this.sortBone(constrained[ii]);
this._updateCache.push(constraint);
for (let ii = 0; ii < boneCount; ii++)
this.sortReset(constrained[ii].children);
for (let ii = 0; ii < boneCount; ii++)
constrained[ii].sorted = true;
}
sortTransformConstraint (constraint: TransformConstraint) {
this.sortBone(constraint.target);
let constrained = constraint.bones;
let boneCount = constrained.length;
for (let ii = 0; ii < boneCount; ii++)
this.sortBone(constrained[ii]);
this._updateCache.push(constraint);
for (let ii = 0; ii < boneCount; ii++)
this.sortReset(constrained[ii].children);
for (let ii = 0; ii < boneCount; ii++)
constrained[ii].sorted = true;
}
sortPathConstraintAttachment (skin: Skin, slotIndex: number, slotBone: Bone) {
@ -237,6 +244,18 @@ module spine {
/** Updates the world transform for each bone and applies constraints. */
updateWorldTransform () {
let updateCacheReset = this.updateCacheReset;
for (let i = 0, n = updateCacheReset.length; i < n; i++) {
let bone = updateCacheReset[i] as Bone;
bone.ax = bone.x;
bone.ay = bone.y;
bone.arotation = bone.rotation;
bone.ascaleX = bone.scaleX;
bone.ascaleY = bone.scaleY;
bone.ashearX = bone.shearX;
bone.ashearY = bone.shearY;
bone.appliedValid = true;
}
let updateCache = this._updateCache;
for (let i = 0, n = updateCache.length; i < n; i++)
updateCache[i].update();

View File

@ -41,7 +41,11 @@ module spine {
transformConstraints = new Array<TransformConstraintData>();
pathConstraints = new Array<PathConstraintData>();
width: number; height: number;
version: string; hash: string; imagesPath: string;
version: string; hash: string;
// Nonessential
fps = 0;
imagesPath: string;
findBone (boneName: string) {
if (boneName == null) throw new Error("boneName cannot be null.");

View File

@ -50,6 +50,7 @@ module spine {
skeletonData.version = skeletonMap.spine;
skeletonData.width = skeletonMap.width;
skeletonData.height = skeletonMap.height;
skeletonData.fps = skeletonMap.fps;
skeletonData.imagesPath = skeletonMap.images;
}
@ -73,8 +74,7 @@ module spine {
data.scaleY = this.getValue(boneMap, "scaleY", 1);
data.shearX = this.getValue(boneMap, "shearX", 0);
data.shearY = this.getValue(boneMap, "shearY", 0);
data.inheritRotation = this.getValue(boneMap, "inheritRotation", true);
data.inheritScale = this.getValue(boneMap, "inheritScale", true);
data.transformMode = SkeletonJson.transformModeFromString(this.getValue(boneMap, "transform", "normal"));
skeletonData.bones.push(data);
}
@ -104,6 +104,7 @@ module spine {
for (let i = 0; i < root.ik.length; i++) {
let constraintMap = root.ik[i];
let data = new IkConstraintData(constraintMap.name);
data.order = this.getValue(constraintMap, "order", 0);
for (let j = 0; j < constraintMap.bones.length; j++) {
let boneName = constraintMap.bones[j];
@ -128,6 +129,7 @@ module spine {
for (let i = 0; i < root.transform.length; i++) {
let constraintMap = root.transform[i];
let data = new TransformConstraintData(constraintMap.name);
data.order = this.getValue(constraintMap, "order", 0);
for (let j = 0; j < constraintMap.bones.length; j++) {
let boneName = constraintMap.bones[j];
@ -161,6 +163,7 @@ module spine {
for (let i = 0; i < root.path.length; i++) {
let constraintMap = root.path[i];
let data = new PathConstraintData(constraintMap.name);
data.order = this.getValue(constraintMap, "order", 0);
for (let j = 0; j < constraintMap.bones.length; j++) {
let boneName = constraintMap.bones[j];
@ -702,6 +705,16 @@ module spine {
if (str == "chainscale") return RotateMode.ChainScale;
throw new Error(`Unknown rotate mode: ${str}`);
}
static transformModeFromString(str: string) {
str = str.toLowerCase();
if (str == "normal") return TransformMode.Normal;
if (str == "onlytranslation") return TransformMode.OnlyTranslation;
if (str == "norotationorreflection") return TransformMode.NoRotationOrReflection;
if (str == "noscale") return TransformMode.NoScale;
if (str == "noscaleorreflection") return TransformMode.NoScaleOrReflection;
throw new Error(`Unknown transform mode: ${str}`);
}
}
class LinkedMesh {

View File

@ -29,7 +29,7 @@
*****************************************************************************/
module spine {
export class TransformConstraint implements Updatable {
export class TransformConstraint implements Constraint {
data: TransformConstraintData;
bones: Array<Bone>;
target: Bone;
@ -61,8 +61,9 @@ module spine {
let bones = this.bones;
for (let i = 0, n = bones.length; i < n; i++) {
let bone = bones[i];
let modified = false;
if (rotateMix > 0) {
if (rotateMix != 0) {
let a = bone.a, b = bone.b, c = bone.c, d = bone.d;
let r = Math.atan2(tc, ta) - Math.atan2(c, a) + this.data.offsetRotation * MathUtils.degRad;
if (r > MathUtils.PI)
@ -75,26 +76,29 @@ module spine {
bone.b = cos * b - sin * d;
bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d;
modified = true;
}
if (translateMix > 0) {
if (translateMix != 0) {
let temp = this.temp;
target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY));
bone.worldX += (temp.x - bone.worldX) * translateMix;
bone.worldY += (temp.y - bone.worldY) * translateMix;
modified = true;
}
if (scaleMix > 0) {
let bs = Math.sqrt(bone.a * bone.a + bone.c * bone.c);
let s = Math.sqrt(bone.a * bone.a + bone.c * bone.c);
let ts = Math.sqrt(ta * ta + tc * tc);
let s = bs > 0.00001 ? (bs + (ts - bs + this.data.offsetScaleX) * scaleMix) / bs : 0;
if (s > 0.00001) s = (s + (ts - s + this.data.offsetScaleX) * scaleMix) / s;
bone.a *= s;
bone.c *= s;
bs = Math.sqrt(bone.b * bone.b + bone.d * bone.d);
s = Math.sqrt(bone.b * bone.b + bone.d * bone.d);
ts = Math.sqrt(tb * tb + td * td);
s = bs > 0.00001 ? (bs + (ts - bs + this.data.offsetScaleY) * scaleMix) / bs : 0;
if (s > 0.00001) s = (s + (ts - s + this.data.offsetScaleY) * scaleMix) / s;
bone.b *= s;
bone.d *= s;
modified = true;
}
if (shearMix > 0) {
@ -109,8 +113,15 @@ module spine {
let s = Math.sqrt(b * b + d * d);
bone.b = Math.cos(r) * s;
bone.d = Math.sin(r) * s;
modified = true;
}
if (modified) bone.appliedValid = false;
}
}
getOrder () {
return this.data.order;
}
}
}

View File

@ -31,6 +31,7 @@
module spine {
export class TransformConstraintData {
name: string;
order = 0;
bones = new Array<BoneData>();
target: BoneData;
rotateMix = 0; translateMix = 0; scaleMix = 0; shearMix = 0;

View File

@ -58,16 +58,15 @@ module spine {
* @param offset The worldVertices index to begin writing values. */
computeWorldVerticesWith (slot: Slot, start: number, count: number, worldVertices: ArrayLike<number>, offset: number) {
count += offset;
let skeleton = slot.bone.skeleton;
let x = skeleton.x, y = skeleton.y;
let skeleton = slot.bone.skeleton;
let deformArray = slot.attachmentVertices;
let vertices = this.vertices;
let bones = this.bones;
if (bones == null) {
if (deformArray.length > 0) vertices = deformArray;
let bone = slot.bone;
x += bone.worldX;
y += bone.worldY;
let x = bone.worldX;
let y = bone.worldY;
let a = bone.a, b = bone.b, c = bone.c, d = bone.d;
for (let v = start, w = offset; w < count; v += 2, w += 2) {
let vx = vertices[v], vy = vertices[v + 1];
@ -85,7 +84,7 @@ module spine {
let skeletonBones = skeleton.bones;
if (deformArray.length == 0) {
for (let w = offset, b = skip * 3; w < count; w += 2) {
let wx = x, wy = y;
let wx = 0, wy = 0;
let n = bones[v++];
n += v;
for (; v < n; v++, b += 3) {
@ -100,7 +99,7 @@ module spine {
} else {
let deform = deformArray;
for (let w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) {
let wx = x, wy = y;
let wx = 0, wy = 0;
let n = bones[v++];
n += v;
for (; v < n; v++, b += 3, f += 2) {

View File

@ -85,8 +85,7 @@ module spine {
skeletonColor.g * slotColor.g * meshColor.g * multiplier,
skeletonColor.b * slotColor.b * meshColor.b * multiplier,
alpha);
let x = skeleton.x, y = skeleton.y;
let deformArray = slot.attachmentVertices;
let vertices = this.vertices, worldVertices = this.worldVertices;
let bones = this.bones;
@ -94,8 +93,8 @@ module spine {
let verticesLength = vertices.length;
if (deformArray.length > 0) vertices = deformArray;
let bone = slot.bone;
x += bone.worldX;
y += bone.worldY;
let x = bone.worldX;
let y = bone.worldY;
let a = bone.a, b = bone.b, c = bone.c, d = bone.d;
for (let v = 0, w = 0; v < verticesLength; v += 2, w += 8) {
let vx = vertices[v], vy = vertices[v + 1];
@ -111,7 +110,7 @@ module spine {
let skeletonBones = skeleton.bones;
if (deformArray.length == 0) {
for (let w = 0, v = 0, b = 0, n = bones.length; v < n; w += 8) {
let wx = x, wy = y;
let wx = 0, wy = 0;
let nn = bones[v++] + v;
for (; v < nn; v++, b += 3) {
let bone = skeletonBones[bones[v]];
@ -129,7 +128,7 @@ module spine {
} else {
let deform = deformArray;
for (let w = 0, v = 0, b = 0, f = 0, n = bones.length; v < n; w += 8) {
let wx = x, wy = y;
let wx = 0, wy = 0;
let nn = bones[v++] + v;
for (; v < nn; v++, b += 3, f += 2) {
let bone = skeletonBones[bones[v]];

View File

@ -160,7 +160,7 @@ module spine {
let vertices = this.vertices;
let offset = this.offset;
let bone = slot.bone;
let x = skeleton.x + bone.worldX, y = skeleton.y + bone.worldY;
let x = bone.worldX, y = bone.worldY;
let a = bone.a, b = bone.b, c = bone.c, d = bone.d;
let offsetX = 0, offsetY = 0;