Constraint order WIP.

This commit is contained in:
NathanSweet 2016-08-09 21:24:54 +02:00
parent 2dee5d6103
commit 1459abcb06
11 changed files with 201 additions and 158 deletions

View File

@ -44,7 +44,8 @@ public class Bone implements Updatable {
final Bone parent; final Bone parent;
final Array<Bone> children = new Array(); final Array<Bone> children = new Array();
float x, y, rotation, scaleX, scaleY, shearX, shearY; float x, y, rotation, scaleX, scaleY, shearX, shearY;
float appliedRotation; float ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY;
boolean appliedValid; // BOZO! - Use everywhere.
float a, b, worldX; float a, b, worldX;
float c, d, worldY; float c, d, worldY;
@ -91,7 +92,13 @@ public class Bone implements Updatable {
/** Computes the world transform using the parent bone and the specified local transform. */ /** Computes the world transform using the parent bone and the specified local transform. */
public void updateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { public void updateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) {
appliedRotation = rotation; ax = x;
ay = y;
arotation = rotation;
ascaleX = scaleX;
ascaleY = scaleY;
ashearX = shearX;
ashearY = shearY;
float rotationY = rotation + 90 + shearY; float rotationY = rotation + 90 + shearY;
float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY; float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY;
@ -160,8 +167,8 @@ public class Bone implements Updatable {
pc = 0; pc = 0;
pd = 1; pd = 1;
do { do {
float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation); float cos = cosDeg(parent.arotation), sin = sinDeg(parent.arotation);
float psx = parent.scaleX, psy = parent.scaleY; float psx = parent.ascaleX, psy = parent.ascaleY;
float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy;
float temp = pa * za + pb * zc; float temp = pa * za + pb * zc;
pb = pb * zd - pa * zb; pb = pb * zd - pa * zb;
@ -170,7 +177,8 @@ public class Bone implements Updatable {
pd = pd * zd - pc * zb; pd = pd * zd - pc * zb;
pc = temp; pc = temp;
if (psx >= 0) sin = -sin; if (psx >= 0) // BOZO! - Why? Should always do this? Fix in new code?
sin = -sin;
temp = pa * cos + pb * sin; temp = pa * cos + pb * sin;
pb = pb * cos - pa * sin; pb = pb * cos - pa * sin;
pa = temp; pa = temp;
@ -350,14 +358,14 @@ public class Bone implements Updatable {
public float worldToLocalRotationX () { public float worldToLocalRotationX () {
Bone parent = this.parent; Bone parent = this.parent;
if (parent == null) return rotation; if (parent == null) return arotation;
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c;
return atan2(pa * c - pc * a, pd * a - pb * c) * radDeg; return atan2(pa * c - pc * a, pd * a - pb * c) * radDeg;
} }
public float worldToLocalRotationY () { public float worldToLocalRotationY () {
Bone parent = this.parent; Bone parent = this.parent;
if (parent == null) return rotation; if (parent == null) return arotation;
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d;
return atan2(pa * d - pc * b, pd * b - pb * d) * radDeg; return atan2(pa * d - pc * b, pd * b - pb * d) * radDeg;
} }
@ -371,29 +379,27 @@ public class Bone implements Updatable {
this.d = sin * b + cos * d; this.d = sin * b + cos * d;
} }
/** Computes the local transform from the world transform. This can be useful to perform processing on the local transform /** Computes the individual applied transform values from the world transform. This can be useful to perform processing using
* after the world transform has been modified directly (eg, by a constraint). * the applied transform after the world transform has been modified directly (eg, by a constraint).
* <p> * <p>
* Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local * Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */
* transform values may differ from the original values but are functionally the same. */ public void updateAppliedTransform () {
public void updateLocalTransform () {
Bone parent = this.parent; Bone parent = this.parent;
if (parent == null) { if (parent == null) {
x = worldX; ax = worldX;
y = worldY; ay = worldY;
rotation = atan2(c, a) * radDeg; arotation = atan2(c, a) * radDeg;
scaleX = (float)Math.sqrt(a * a + c * c); ascaleX = (float)Math.sqrt(a * a + c * c);
scaleY = (float)Math.sqrt(b * b + d * d); ascaleY = (float)Math.sqrt(b * b + d * d);
float det = a * d - b * c; ashearX = 0;
shearX = 0; ashearY = atan2(a * b + c * d, a * d - b * c) * radDeg;
shearY = atan2(a * b + c * d, det) * radDeg;
return; return;
} }
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
float pid = 1 / (pa * pd - pb * pc); float pid = 1 / (pa * pd - pb * pc);
float dx = worldX - parent.worldX, dy = worldY - parent.worldY; float dx = worldX - parent.worldX, dy = worldY - parent.worldY;
x = (dx * pd * pid - dy * pb * pid); ax = (dx * pd * pid - dy * pb * pid);
y = (dy * pa * pid - dx * pc * pid); ay = (dy * pa * pid - dx * pc * pid);
float ia = pid * pd; float ia = pid * pd;
float id = pid * pa; float id = pid * pa;
float ib = pid * pb; float ib = pid * pb;
@ -402,20 +408,19 @@ public class Bone implements Updatable {
float rb = ia * b - ib * d; float rb = ia * b - ib * d;
float rc = id * c - ic * a; float rc = id * c - ic * a;
float rd = id * d - ic * b; float rd = id * d - ic * b;
shearX = 0; ashearX = 0;
scaleX = (float)Math.sqrt(ra * ra + rc * rc); ascaleX = (float)Math.sqrt(ra * ra + rc * rc);
if (scaleX > 0.0001f) { if (ascaleX > 0.0001f) {
float det = ra * rd - rb * rc; float det = ra * rd - rb * rc;
scaleY = det / scaleX; ascaleY = det / ascaleX;
shearY = atan2(ra * rb + rc * rd, det) * radDeg; ashearY = atan2(ra * rb + rc * rd, det) * radDeg;
rotation = atan2(rc, ra) * radDeg; arotation = atan2(rc, ra) * radDeg;
} else { } else {
scaleX = 0; ascaleX = 0;
scaleY = (float)Math.sqrt(rb * rb + rd * rd); ascaleY = (float)Math.sqrt(rb * rb + rd * rd);
shearY = 0; ashearY = 0;
rotation = 90 - atan2(rd, rb) * radDeg; arotation = 90 - atan2(rd, rb) * radDeg;
} }
appliedRotation = rotation;
} }
public Matrix3 getWorldTransform (Matrix3 worldTransform) { public Matrix3 getWorldTransform (Matrix3 worldTransform) {

View File

@ -0,0 +1,6 @@
package com.esotericsoftware.spine;
public interface Constraint extends Updatable {
public int getOrder ();
}

View File

@ -35,15 +35,13 @@ import static com.badlogic.gdx.math.MathUtils.*;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
public class IkConstraint implements Updatable { public class IkConstraint implements Constraint {
final IkConstraintData data; final IkConstraintData data;
final Array<Bone> bones; final Array<Bone> bones;
Bone target; Bone target;
float mix = 1; float mix = 1;
int bendDirection; int bendDirection;
int level;
public IkConstraint (IkConstraintData data, Skeleton skeleton) { public IkConstraint (IkConstraintData data, Skeleton skeleton) {
if (data == null) throw new IllegalArgumentException("data cannot be null."); if (data == null) throw new IllegalArgumentException("data cannot be null.");
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
@ -87,6 +85,10 @@ public class IkConstraint implements Updatable {
} }
} }
public int getOrder () {
return data.order;
}
public Array<Bone> getBones () { public Array<Bone> getBones () {
return bones; return bones;
} }
@ -126,17 +128,17 @@ public class IkConstraint implements Updatable {
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world /** 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. */ * coordinate system. */
static public void apply (Bone bone, float targetX, float targetY, float alpha) { static public void apply (Bone bone, float targetX, float targetY, float alpha) {
Bone pp = bone.parent; Bone p = bone.parent;
float id = 1 / (pp.a * pp.d - pp.b * pp.c); float id = 1 / (p.a * p.d - p.b * p.c);
float x = targetX - pp.worldX, y = targetY - pp.worldY; float x = targetX - p.worldX, y = targetY - p.worldY;
float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; float tx = (x * p.d - y * p.b) * id - bone.ax, ty = (y * p.a - x * p.c) * id - bone.ay;
float rotationIK = atan2(ty, tx) * radDeg - bone.shearX - bone.rotation; float rotationIK = atan2(ty, tx) * radDeg - bone.ashearX - bone.arotation;
if (bone.scaleX < 0) rotationIK += 180; if (bone.ascaleX < 0) rotationIK += 180;
if (rotationIK > 180) if (rotationIK > 180)
rotationIK -= 360; rotationIK -= 360;
else if (rotationIK < -180) rotationIK += 360; else if (rotationIK < -180) rotationIK += 360;
bone.updateWorldTransform(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, bone.updateWorldTransform(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, bone.ascaleX, bone.ascaleY, bone.ashearX,
bone.shearY); 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 /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
@ -147,7 +149,12 @@ public class IkConstraint implements Updatable {
child.updateWorldTransform(); child.updateWorldTransform();
return; return;
} }
float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX;
// BOZO! - Only when each bone needs it.
// child.updateLocalTransform();
// parent.updateLocalTransform();
float px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, csx = child.ascaleX;
int os1, os2, s2; int os1, os2, s2;
if (psx < 0) { if (psx < 0) {
psx = -psx; psx = -psx;
@ -166,14 +173,14 @@ public class IkConstraint implements Updatable {
os2 = 180; os2 = 180;
} else } else
os2 = 0; os2 = 0;
float cx = child.x, cy, cwx, cwy, a = parent.a, b = parent.b, c = parent.c, d = parent.d; float cx = child.ax, cy, cwx, cwy, a = parent.a, b = parent.b, c = parent.c, d = parent.d;
boolean u = Math.abs(psx - psy) <= 0.0001f; boolean u = Math.abs(psx - psy) <= 0.0001f;
if (!u) { if (!u) {
cy = 0; cy = 0;
cwx = a * cx + parent.worldX; cwx = a * cx + parent.worldX;
cwy = c * cx + parent.worldY; cwy = c * cx + parent.worldY;
} else { } else {
cy = child.y; cy = child.ay;
cwx = a * cx + b * cy + parent.worldX; cwx = a * cx + b * cy + parent.worldX;
cwy = c * cx + d * cy + parent.worldY; cwy = c * cx + d * cy + parent.worldY;
} }
@ -260,17 +267,17 @@ public class IkConstraint implements Updatable {
} }
} }
float os = atan2(cy, cx) * s2; float os = atan2(cy, cx) * s2;
float rotation = parent.rotation; float rotation = parent.arotation;
a1 = (a1 - os) * radDeg + os1 - rotation; a1 = (a1 - os) * radDeg + os1 - rotation;
if (a1 > 180) if (a1 > 180)
a1 -= 360; a1 -= 360;
else if (a1 < -180) a1 += 360; else if (a1 < -180) a1 += 360;
parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0);
rotation = child.rotation; rotation = child.arotation;
a2 = ((a2 + os) * radDeg - child.shearX) * s2 + os2 - rotation; a2 = ((a2 + os) * radDeg - child.ashearX) * s2 + os2 - rotation;
if (a2 > 180) if (a2 > 180)
a2 -= 360; a2 -= 360;
else if (a2 < -180) a2 += 360; else if (a2 < -180) a2 += 360;
child.updateWorldTransform(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); child.updateWorldTransform(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
} }
} }

View File

@ -35,6 +35,7 @@ import com.badlogic.gdx.utils.Array;
public class IkConstraintData { public class IkConstraintData {
final String name; final String name;
int order;
final Array<BoneData> bones = new Array(); final Array<BoneData> bones = new Array();
BoneData target; BoneData target;
int bendDirection = 1; int bendDirection = 1;
@ -49,6 +50,14 @@ public class IkConstraintData {
return name; return name;
} }
public int getOrder () {
return order;
}
public void setOrder (int order) {
this.order = order;
}
public Array<BoneData> getBones () { public Array<BoneData> getBones () {
return bones; return bones;
} }

View File

@ -11,7 +11,7 @@ import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.PathAttachment; import com.esotericsoftware.spine.attachments.PathAttachment;
public class PathConstraint implements Updatable { public class PathConstraint implements Constraint {
static private final int NONE = -1, BEFORE = -2, AFTER = -3; static private final int NONE = -1, BEFORE = -2, AFTER = -3;
final PathConstraintData data; final PathConstraintData data;
@ -382,6 +382,10 @@ public class PathConstraint implements Updatable {
if (tangents) out[o + 2] = atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); if (tangents) out[o + 2] = atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
} }
public int getOrder () {
return data.order;
}
public float getPosition () { public float getPosition () {
return position; return position;
} }

View File

@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.Array;
public class PathConstraintData { public class PathConstraintData {
final String name; final String name;
int order;
final Array<BoneData> bones = new Array(); final Array<BoneData> bones = new Array();
SlotData target; SlotData target;
PositionMode positionMode; PositionMode positionMode;
@ -18,6 +19,18 @@ public class PathConstraintData {
this.name = name; this.name = name;
} }
public String getName () {
return name;
}
public int getOrder () {
return order;
}
public void setOrder (int order) {
this.order = order;
}
public Array<BoneData> getBones () { public Array<BoneData> getBones () {
return bones; return bones;
} }
@ -94,10 +107,6 @@ public class PathConstraintData {
this.translateMix = translateMix; this.translateMix = translateMix;
} }
public String getName () {
return name;
}
public String toString () { public String toString () {
return name; return name;
} }

View File

@ -31,6 +31,8 @@
package com.esotericsoftware.spine; package com.esotericsoftware.spine;
import java.util.Comparator;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
@ -46,9 +48,10 @@ public class Skeleton {
final Array<Bone> bones; final Array<Bone> bones;
final Array<Slot> slots; final Array<Slot> slots;
Array<Slot> drawOrder; Array<Slot> drawOrder;
final Array<IkConstraint> ikConstraints, ikConstraintsSorted; final Array<IkConstraint> ikConstraints;
final Array<TransformConstraint> transformConstraints; final Array<TransformConstraint> transformConstraints;
final Array<PathConstraint> pathConstraints; final Array<PathConstraint> pathConstraints;
final Array<Constraint> sortedConstraints = new Array();
final Array<Updatable> updateCache = new Array(); final Array<Updatable> updateCache = new Array();
Skin skin; Skin skin;
final Color color; final Color color;
@ -56,6 +59,9 @@ public class Skeleton {
boolean flipX, flipY; boolean flipX, flipY;
float x, y; float x, y;
final Comparator<Constraint> constraintComparator = new Comparator<Constraint>() {
public int compare (Constraint o1,Constraint o2){return o1.getOrder()-o2.getOrder();}};
public Skeleton (SkeletonData data) { public Skeleton (SkeletonData data) {
if (data == null) throw new IllegalArgumentException("data cannot be null."); if (data == null) throw new IllegalArgumentException("data cannot be null.");
this.data = data; this.data = data;
@ -83,7 +89,6 @@ public class Skeleton {
} }
ikConstraints = new Array(data.ikConstraints.size); ikConstraints = new Array(data.ikConstraints.size);
ikConstraintsSorted = new Array(ikConstraints.size);
for (IkConstraintData ikConstraintData : data.ikConstraints) for (IkConstraintData ikConstraintData : data.ikConstraints)
ikConstraints.add(new IkConstraint(ikConstraintData, this)); ikConstraints.add(new IkConstraint(ikConstraintData, this));
@ -107,15 +112,8 @@ public class Skeleton {
bones = new Array(skeleton.bones.size); bones = new Array(skeleton.bones.size);
for (Bone bone : skeleton.bones) { for (Bone bone : skeleton.bones) {
Bone copy; Bone parent = bone.parent == null ? null : bones.get(bone.parent.data.index);
if (bone.parent == null) bones.add(new Bone(bone, this, parent));
copy = new Bone(bone, this, null);
else {
Bone parent = bones.get(bone.parent.data.index);
copy = new Bone(bone, this, parent);
parent.children.add(copy);
}
bones.add(copy);
} }
slots = new Array(skeleton.slots.size); slots = new Array(skeleton.slots.size);
@ -129,7 +127,6 @@ public class Skeleton {
drawOrder.add(slots.get(slot.data.index)); drawOrder.add(slots.get(slot.data.index));
ikConstraints = new Array(skeleton.ikConstraints.size); ikConstraints = new Array(skeleton.ikConstraints.size);
ikConstraintsSorted = new Array(ikConstraints.size);
for (IkConstraint ikConstraint : skeleton.ikConstraints) for (IkConstraint ikConstraint : skeleton.ikConstraints)
ikConstraints.add(new IkConstraint(ikConstraint, this)); ikConstraints.add(new IkConstraint(ikConstraint, this));
@ -160,95 +157,82 @@ public class Skeleton {
for (int i = 0, n = bones.size; i < n; i++) for (int i = 0, n = bones.size; i < n; i++)
bones.get(i).sorted = false; bones.get(i).sorted = false;
// IK first, lowest hierarchy depth first. Array<Constraint> constraints = sortedConstraints;
Array<IkConstraint> ikConstraints = this.ikConstraintsSorted; constraints.addAll(ikConstraints);
ikConstraints.clear(); constraints.addAll(transformConstraints);
ikConstraints.addAll(this.ikConstraints); constraints.addAll(pathConstraints);
int ikCount = ikConstraints.size; constraints.sort(constraintComparator);
for (int i = 0, level, n = ikCount; i < n; i++) { for (int i = 0, n = constraints.size; i < n; i++) {
IkConstraint ik = ikConstraints.get(i); Constraint constraint = constraints.get(i);
Bone bone = ik.bones.first().parent; if (constraint instanceof IkConstraint)
for (level = 0; bone != null; level++) sortIkConstraint((IkConstraint)constraint);
bone = bone.parent; else if (constraint instanceof TransformConstraint)
ik.level = level; sortTransformConstraint((TransformConstraint)constraint);
} else
for (int i = 1, ii; i < ikCount; i++) { sortPathConstraint((PathConstraint)constraint);
IkConstraint ik = ikConstraints.get(i);
int level = ik.level;
for (ii = i - 1; ii >= 0; ii--) {
IkConstraint other = ikConstraints.get(ii);
if (other.level < level) break;
ikConstraints.set(ii + 1, other);
}
ikConstraints.set(ii + 1, ik);
}
for (int i = 0, n = ikConstraints.size; i < n; i++) {
IkConstraint constraint = ikConstraints.get(i);
Bone target = constraint.target;
sortBone(target);
Array<Bone> constrained = constraint.bones;
Bone parent = constrained.first();
sortBone(parent);
updateCache.add(constraint);
sortReset(parent.children);
constrained.peek().sorted = true;
}
Array<PathConstraint> pathConstraints = this.pathConstraints;
for (int i = 0, n = pathConstraints.size; i < n; i++) {
PathConstraint constraint = pathConstraints.get(i);
Slot slot = constraint.target;
int slotIndex = slot.getData().index;
Bone slotBone = slot.bone;
if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone);
if (data.defaultSkin != null && data.defaultSkin != skin)
sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone);
for (int ii = 0, nn = data.skins.size; ii < nn; ii++)
sortPathConstraintAttachment(data.skins.get(ii), slotIndex, slotBone);
Attachment attachment = slot.attachment;
if (attachment instanceof PathAttachment) sortPathConstraintAttachment(attachment, slotBone);
Array<Bone> constrained = constraint.bones;
int boneCount = constrained.size;
for (int ii = 0; ii < boneCount; ii++)
sortBone(constrained.get(ii));
updateCache.add(constraint);
for (int ii = 0; ii < boneCount; ii++)
sortReset(constrained.get(ii).children);
for (int ii = 0; ii < boneCount; ii++)
constrained.get(ii).sorted = true;
}
Array<TransformConstraint> transformConstraints = this.transformConstraints;
for (int i = 0, n = transformConstraints.size; i < n; i++) {
TransformConstraint constraint = transformConstraints.get(i);
sortBone(constraint.target);
Array<Bone> constrained = constraint.bones;
int boneCount = constrained.size;
for (int ii = 0; ii < boneCount; ii++)
sortBone(constrained.get(ii));
updateCache.add(constraint);
for (int ii = 0; ii < boneCount; ii++)
sortReset(constrained.get(ii).children);
for (int ii = 0; ii < boneCount; ii++)
constrained.get(ii).sorted = true;
} }
constraints.clear();
for (int i = 0, n = bones.size; i < n; i++) for (int i = 0, n = bones.size; i < n; i++)
sortBone(bones.get(i)); sortBone(bones.get(i));
} }
private void sortIkConstraint (IkConstraint constraint) {
Bone target = constraint.target;
sortBone(target);
Array<Bone> constrained = constraint.bones;
Bone parent = constrained.first();
sortBone(parent);
updateCache.add(constraint);
sortReset(parent.children);
constrained.peek().sorted = true;
}
private void sortPathConstraint (PathConstraint constraint) {
Slot slot = constraint.target;
int slotIndex = slot.getData().index;
Bone slotBone = slot.bone;
if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone);
if (data.defaultSkin != null && data.defaultSkin != skin)
sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone);
for (int ii = 0, nn = data.skins.size; ii < nn; ii++)
sortPathConstraintAttachment(data.skins.get(ii), slotIndex, slotBone);
Attachment attachment = slot.attachment;
if (attachment instanceof PathAttachment) sortPathConstraintAttachment(attachment, slotBone);
Array<Bone> constrained = constraint.bones;
int boneCount = constrained.size;
for (int ii = 0; ii < boneCount; ii++)
sortBone(constrained.get(ii));
updateCache.add(constraint);
for (int ii = 0; ii < boneCount; ii++)
sortReset(constrained.get(ii).children);
for (int ii = 0; ii < boneCount; ii++)
constrained.get(ii).sorted = true;
}
private void sortTransformConstraint (TransformConstraint constraint) {
sortBone(constraint.target);
Array<Bone> constrained = constraint.bones;
int boneCount = constrained.size;
for (int ii = 0; ii < boneCount; ii++)
sortBone(constrained.get(ii));
updateCache.add(constraint);
for (int ii = 0; ii < boneCount; ii++)
sortReset(constrained.get(ii).children);
for (int ii = 0; ii < boneCount; ii++)
constrained.get(ii).sorted = true;
}
private void sortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) { private void sortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) {
for (Entry<Key, Attachment> entry : skin.attachments.entries()) for (Entry<Key, Attachment> entry : skin.attachments.entries())
if (entry.key.slotIndex == slotIndex) sortPathConstraintAttachment(entry.value, slotBone); if (entry.key.slotIndex == slotIndex) sortPathConstraintAttachment(entry.value, slotBone);

View File

@ -206,6 +206,7 @@ public class SkeletonBinary {
// IK constraints. // IK constraints.
for (int i = 0, n = input.readInt(true); i < n; i++) { for (int i = 0, n = input.readInt(true); i < n; i++) {
IkConstraintData data = new IkConstraintData(input.readString()); IkConstraintData data = new IkConstraintData(input.readString());
data.order = input.readInt(true);
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) for (int ii = 0, nn = input.readInt(true); ii < nn; ii++)
data.bones.add(skeletonData.bones.get(input.readInt(true))); data.bones.add(skeletonData.bones.get(input.readInt(true)));
data.target = skeletonData.bones.get(input.readInt(true)); data.target = skeletonData.bones.get(input.readInt(true));
@ -217,6 +218,7 @@ public class SkeletonBinary {
// Transform constraints. // Transform constraints.
for (int i = 0, n = input.readInt(true); i < n; i++) { for (int i = 0, n = input.readInt(true); i < n; i++) {
TransformConstraintData data = new TransformConstraintData(input.readString()); TransformConstraintData data = new TransformConstraintData(input.readString());
data.order = input.readInt(true);
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) for (int ii = 0, nn = input.readInt(true); ii < nn; ii++)
data.bones.add(skeletonData.bones.get(input.readInt(true))); data.bones.add(skeletonData.bones.get(input.readInt(true)));
data.target = skeletonData.bones.get(input.readInt(true)); data.target = skeletonData.bones.get(input.readInt(true));
@ -236,6 +238,7 @@ public class SkeletonBinary {
// Path constraints. // Path constraints.
for (int i = 0, n = input.readInt(true); i < n; i++) { for (int i = 0, n = input.readInt(true); i < n; i++) {
PathConstraintData data = new PathConstraintData(input.readString()); PathConstraintData data = new PathConstraintData(input.readString());
data.order = input.readInt(true);
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) for (int ii = 0, nn = input.readInt(true); ii < nn; ii++)
data.bones.add(skeletonData.bones.get(input.readInt(true))); data.bones.add(skeletonData.bones.get(input.readInt(true)));
data.target = skeletonData.slots.get(input.readInt(true)); data.target = skeletonData.slots.get(input.readInt(true));

View File

@ -157,6 +157,7 @@ public class SkeletonJson {
// IK constraints. // IK constraints.
for (JsonValue constraintMap = root.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { for (JsonValue constraintMap = root.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) {
IkConstraintData data = new IkConstraintData(constraintMap.getString("name")); IkConstraintData data = new IkConstraintData(constraintMap.getString("name"));
data.order = constraintMap.getInt("order", 0);
for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
String boneName = boneMap.asString(); String boneName = boneMap.asString();
@ -178,6 +179,7 @@ public class SkeletonJson {
// Transform constraints. // Transform constraints.
for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name")); TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name"));
data.order = constraintMap.getInt("order", 0);
for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
String boneName = boneMap.asString(); String boneName = boneMap.asString();
@ -208,6 +210,7 @@ public class SkeletonJson {
// Path constraints. // Path constraints.
for (JsonValue constraintMap = root.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) { for (JsonValue constraintMap = root.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) {
PathConstraintData data = new PathConstraintData(constraintMap.getString("name")); PathConstraintData data = new PathConstraintData(constraintMap.getString("name"));
data.order = constraintMap.getInt("order", 0);
for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
String boneName = boneMap.asString(); String boneName = boneMap.asString();

View File

@ -6,7 +6,7 @@ import static com.badlogic.gdx.math.MathUtils.*;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
public class TransformConstraint implements Updatable { public class TransformConstraint implements Constraint {
final TransformConstraintData data; final TransformConstraintData data;
final Array<Bone> bones; final Array<Bone> bones;
Bone target; Bone target;
@ -54,7 +54,7 @@ public class TransformConstraint implements Updatable {
for (int i = 0, n = bones.size; i < n; i++) { for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i); Bone bone = bones.get(i);
if (rotateMix > 0) { if (rotateMix != 0) {
float a = bone.a, b = bone.b, c = bone.c, d = bone.d; float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
float r = atan2(tc, ta) - atan2(c, a) + data.offsetRotation * degRad; float r = atan2(tc, ta) - atan2(c, a) + data.offsetRotation * degRad;
if (r > PI) if (r > PI)
@ -68,7 +68,7 @@ public class TransformConstraint implements Updatable {
bone.d = sin * b + cos * d; bone.d = sin * b + cos * d;
} }
if (translateMix > 0) { if (translateMix != 0) {
Vector2 temp = this.temp; Vector2 temp = this.temp;
target.localToWorld(temp.set(data.offsetX, data.offsetY)); target.localToWorld(temp.set(data.offsetX, data.offsetY));
bone.worldX += (temp.x - bone.worldX) * translateMix; bone.worldX += (temp.x - bone.worldX) * translateMix;
@ -103,6 +103,10 @@ public class TransformConstraint implements Updatable {
} }
} }
public int getOrder () {
return data.order;
}
public Array<Bone> getBones () { public Array<Bone> getBones () {
return bones; return bones;
} }

View File

@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.Array;
public class TransformConstraintData { public class TransformConstraintData {
final String name; final String name;
int order;
final Array<BoneData> bones = new Array(); final Array<BoneData> bones = new Array();
BoneData target; BoneData target;
float rotateMix, translateMix, scaleMix, shearMix; float rotateMix, translateMix, scaleMix, shearMix;
@ -19,6 +20,14 @@ public class TransformConstraintData {
return name; return name;
} }
public int getOrder () {
return order;
}
public void setOrder (int order) {
this.order = order;
}
public Array<BoneData> getBones () { public Array<BoneData> getBones () {
return bones; return bones;
} }