mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
Constraint order WIP.
This commit is contained in:
parent
2dee5d6103
commit
1459abcb06
@ -44,7 +44,8 @@ public class Bone implements Updatable {
|
||||
final Bone parent;
|
||||
final Array<Bone> children = new Array();
|
||||
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 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. */
|
||||
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 la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY;
|
||||
@ -160,8 +167,8 @@ public class Bone implements Updatable {
|
||||
pc = 0;
|
||||
pd = 1;
|
||||
do {
|
||||
float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation);
|
||||
float psx = parent.scaleX, psy = parent.scaleY;
|
||||
float cos = cosDeg(parent.arotation), sin = sinDeg(parent.arotation);
|
||||
float psx = parent.ascaleX, psy = parent.ascaleY;
|
||||
float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy;
|
||||
float temp = pa * za + pb * zc;
|
||||
pb = pb * zd - pa * zb;
|
||||
@ -170,7 +177,8 @@ public class Bone implements Updatable {
|
||||
pd = pd * zd - pc * zb;
|
||||
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;
|
||||
pb = pb * cos - pa * sin;
|
||||
pa = temp;
|
||||
@ -350,14 +358,14 @@ public class Bone implements Updatable {
|
||||
|
||||
public float worldToLocalRotationX () {
|
||||
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;
|
||||
return atan2(pa * c - pc * a, pd * a - pb * c) * radDeg;
|
||||
}
|
||||
|
||||
public float worldToLocalRotationY () {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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).
|
||||
/** 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 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. */
|
||||
public void updateLocalTransform () {
|
||||
* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */
|
||||
public void updateAppliedTransform () {
|
||||
Bone parent = this.parent;
|
||||
if (parent == null) {
|
||||
x = worldX;
|
||||
y = worldY;
|
||||
rotation = atan2(c, a) * radDeg;
|
||||
scaleX = (float)Math.sqrt(a * a + c * c);
|
||||
scaleY = (float)Math.sqrt(b * b + d * d);
|
||||
float det = a * d - b * c;
|
||||
shearX = 0;
|
||||
shearY = atan2(a * b + c * d, det) * radDeg;
|
||||
ax = worldX;
|
||||
ay = worldY;
|
||||
arotation = atan2(c, a) * radDeg;
|
||||
ascaleX = (float)Math.sqrt(a * a + c * c);
|
||||
ascaleY = (float)Math.sqrt(b * b + d * d);
|
||||
ashearX = 0;
|
||||
ashearY = atan2(a * b + c * d, a * d - b * c) * radDeg;
|
||||
return;
|
||||
}
|
||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d;
|
||||
float pid = 1 / (pa * pd - pb * pc);
|
||||
float dx = worldX - parent.worldX, dy = worldY - parent.worldY;
|
||||
x = (dx * pd * pid - dy * pb * pid);
|
||||
y = (dy * pa * pid - dx * pc * pid);
|
||||
ax = (dx * pd * pid - dy * pb * pid);
|
||||
ay = (dy * pa * pid - dx * pc * pid);
|
||||
float ia = pid * pd;
|
||||
float id = pid * pa;
|
||||
float ib = pid * pb;
|
||||
@ -402,20 +408,19 @@ public class Bone implements Updatable {
|
||||
float rb = ia * b - ib * d;
|
||||
float rc = id * c - ic * a;
|
||||
float rd = id * d - ic * b;
|
||||
shearX = 0;
|
||||
scaleX = (float)Math.sqrt(ra * ra + rc * rc);
|
||||
if (scaleX > 0.0001f) {
|
||||
ashearX = 0;
|
||||
ascaleX = (float)Math.sqrt(ra * ra + rc * rc);
|
||||
if (ascaleX > 0.0001f) {
|
||||
float det = ra * rd - rb * rc;
|
||||
scaleY = det / scaleX;
|
||||
shearY = atan2(ra * rb + rc * rd, det) * radDeg;
|
||||
rotation = atan2(rc, ra) * radDeg;
|
||||
ascaleY = det / ascaleX;
|
||||
ashearY = atan2(ra * rb + rc * rd, det) * radDeg;
|
||||
arotation = atan2(rc, ra) * radDeg;
|
||||
} else {
|
||||
scaleX = 0;
|
||||
scaleY = (float)Math.sqrt(rb * rb + rd * rd);
|
||||
shearY = 0;
|
||||
rotation = 90 - atan2(rd, rb) * radDeg;
|
||||
ascaleX = 0;
|
||||
ascaleY = (float)Math.sqrt(rb * rb + rd * rd);
|
||||
ashearY = 0;
|
||||
arotation = 90 - atan2(rd, rb) * radDeg;
|
||||
}
|
||||
appliedRotation = rotation;
|
||||
}
|
||||
|
||||
public Matrix3 getWorldTransform (Matrix3 worldTransform) {
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
public interface Constraint extends Updatable {
|
||||
public int getOrder ();
|
||||
}
|
||||
@ -35,15 +35,13 @@ import static com.badlogic.gdx.math.MathUtils.*;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class IkConstraint implements Updatable {
|
||||
public class IkConstraint implements Constraint {
|
||||
final IkConstraintData data;
|
||||
final Array<Bone> bones;
|
||||
Bone target;
|
||||
float mix = 1;
|
||||
int bendDirection;
|
||||
|
||||
int level;
|
||||
|
||||
public IkConstraint (IkConstraintData data, Skeleton skeleton) {
|
||||
if (data == null) throw new IllegalArgumentException("data 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 () {
|
||||
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
|
||||
* coordinate system. */
|
||||
static public void apply (Bone bone, float targetX, float targetY, float alpha) {
|
||||
Bone pp = bone.parent;
|
||||
float id = 1 / (pp.a * pp.d - pp.b * pp.c);
|
||||
float x = targetX - pp.worldX, y = targetY - pp.worldY;
|
||||
float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y;
|
||||
float rotationIK = atan2(ty, tx) * radDeg - bone.shearX - bone.rotation;
|
||||
if (bone.scaleX < 0) rotationIK += 180;
|
||||
Bone p = bone.parent;
|
||||
float id = 1 / (p.a * p.d - p.b * p.c);
|
||||
float x = targetX - p.worldX, y = targetY - p.worldY;
|
||||
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.ashearX - bone.arotation;
|
||||
if (bone.ascaleX < 0) rotationIK += 180;
|
||||
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.shearY);
|
||||
bone.updateWorldTransform(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
|
||||
@ -147,7 +149,12 @@ public class IkConstraint implements Updatable {
|
||||
child.updateWorldTransform();
|
||||
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;
|
||||
if (psx < 0) {
|
||||
psx = -psx;
|
||||
@ -166,14 +173,14 @@ public class IkConstraint implements Updatable {
|
||||
os2 = 180;
|
||||
} else
|
||||
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;
|
||||
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;
|
||||
}
|
||||
@ -260,17 +267,17 @@ public class IkConstraint implements Updatable {
|
||||
}
|
||||
}
|
||||
float os = atan2(cy, cx) * s2;
|
||||
float rotation = parent.rotation;
|
||||
float rotation = parent.arotation;
|
||||
a1 = (a1 - os) * radDeg + os1 - rotation;
|
||||
if (a1 > 180)
|
||||
a1 -= 360;
|
||||
else if (a1 < -180) a1 += 360;
|
||||
parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0);
|
||||
rotation = child.rotation;
|
||||
a2 = ((a2 + os) * radDeg - child.shearX) * s2 + os2 - rotation;
|
||||
parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0);
|
||||
rotation = child.arotation;
|
||||
a2 = ((a2 + os) * radDeg - child.ashearX) * s2 + os2 - rotation;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class IkConstraintData {
|
||||
final String name;
|
||||
int order;
|
||||
final Array<BoneData> bones = new Array();
|
||||
BoneData target;
|
||||
int bendDirection = 1;
|
||||
@ -49,6 +50,14 @@ public class IkConstraintData {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getOrder () {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder (int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public Array<BoneData> getBones () {
|
||||
return bones;
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
|
||||
import com.esotericsoftware.spine.attachments.Attachment;
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
public int getOrder () {
|
||||
return data.order;
|
||||
}
|
||||
|
||||
public float getPosition () {
|
||||
return position;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class PathConstraintData {
|
||||
final String name;
|
||||
int order;
|
||||
final Array<BoneData> bones = new Array();
|
||||
SlotData target;
|
||||
PositionMode positionMode;
|
||||
@ -18,6 +19,18 @@ public class PathConstraintData {
|
||||
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 () {
|
||||
return bones;
|
||||
}
|
||||
@ -94,10 +107,6 @@ public class PathConstraintData {
|
||||
this.translateMix = translateMix;
|
||||
}
|
||||
|
||||
public String getName () {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return name;
|
||||
}
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
@ -46,9 +48,10 @@ public class Skeleton {
|
||||
final Array<Bone> bones;
|
||||
final Array<Slot> slots;
|
||||
Array<Slot> drawOrder;
|
||||
final Array<IkConstraint> ikConstraints, ikConstraintsSorted;
|
||||
final Array<IkConstraint> ikConstraints;
|
||||
final Array<TransformConstraint> transformConstraints;
|
||||
final Array<PathConstraint> pathConstraints;
|
||||
final Array<Constraint> sortedConstraints = new Array();
|
||||
final Array<Updatable> updateCache = new Array();
|
||||
Skin skin;
|
||||
final Color color;
|
||||
@ -56,6 +59,9 @@ public class Skeleton {
|
||||
boolean flipX, flipY;
|
||||
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) {
|
||||
if (data == null) throw new IllegalArgumentException("data cannot be null.");
|
||||
this.data = data;
|
||||
@ -83,7 +89,6 @@ public class Skeleton {
|
||||
}
|
||||
|
||||
ikConstraints = new Array(data.ikConstraints.size);
|
||||
ikConstraintsSorted = new Array(ikConstraints.size);
|
||||
for (IkConstraintData ikConstraintData : data.ikConstraints)
|
||||
ikConstraints.add(new IkConstraint(ikConstraintData, this));
|
||||
|
||||
@ -107,15 +112,8 @@ public class Skeleton {
|
||||
|
||||
bones = new Array(skeleton.bones.size);
|
||||
for (Bone bone : skeleton.bones) {
|
||||
Bone copy;
|
||||
if (bone.parent == null)
|
||||
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);
|
||||
Bone parent = bone.parent == null ? null : bones.get(bone.parent.data.index);
|
||||
bones.add(new Bone(bone, this, parent));
|
||||
}
|
||||
|
||||
slots = new Array(skeleton.slots.size);
|
||||
@ -129,7 +127,6 @@ public class Skeleton {
|
||||
drawOrder.add(slots.get(slot.data.index));
|
||||
|
||||
ikConstraints = new Array(skeleton.ikConstraints.size);
|
||||
ikConstraintsSorted = new Array(ikConstraints.size);
|
||||
for (IkConstraint ikConstraint : skeleton.ikConstraints)
|
||||
ikConstraints.add(new IkConstraint(ikConstraint, this));
|
||||
|
||||
@ -155,100 +152,87 @@ public class Skeleton {
|
||||
public void updateCache () {
|
||||
Array<Updatable> updateCache = this.updateCache;
|
||||
updateCache.clear();
|
||||
|
||||
|
||||
Array<Bone> bones = this.bones;
|
||||
for (int i = 0, n = bones.size; i < n; i++)
|
||||
bones.get(i).sorted = false;
|
||||
|
||||
// IK first, lowest hierarchy depth first.
|
||||
Array<IkConstraint> ikConstraints = this.ikConstraintsSorted;
|
||||
ikConstraints.clear();
|
||||
ikConstraints.addAll(this.ikConstraints);
|
||||
int ikCount = ikConstraints.size;
|
||||
for (int i = 0, level, n = ikCount; i < n; i++) {
|
||||
IkConstraint ik = ikConstraints.get(i);
|
||||
Bone bone = ik.bones.first().parent;
|
||||
for (level = 0; bone != null; level++)
|
||||
bone = bone.parent;
|
||||
ik.level = level;
|
||||
|
||||
Array<Constraint> constraints = sortedConstraints;
|
||||
constraints.addAll(ikConstraints);
|
||||
constraints.addAll(transformConstraints);
|
||||
constraints.addAll(pathConstraints);
|
||||
constraints.sort(constraintComparator);
|
||||
for (int i = 0, n = constraints.size; i < n; i++) {
|
||||
Constraint constraint = constraints.get(i);
|
||||
if (constraint instanceof IkConstraint)
|
||||
sortIkConstraint((IkConstraint)constraint);
|
||||
else if (constraint instanceof TransformConstraint)
|
||||
sortTransformConstraint((TransformConstraint)constraint);
|
||||
else
|
||||
sortPathConstraint((PathConstraint)constraint);
|
||||
}
|
||||
for (int i = 1, ii; i < ikCount; i++) {
|
||||
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++)
|
||||
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) {
|
||||
for (Entry<Key, Attachment> entry : skin.attachments.entries())
|
||||
if (entry.key.slotIndex == slotIndex) sortPathConstraintAttachment(entry.value, slotBone);
|
||||
|
||||
@ -206,6 +206,7 @@ public class SkeletonBinary {
|
||||
// IK constraints.
|
||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||
IkConstraintData data = new IkConstraintData(input.readString());
|
||||
data.order = input.readInt(true);
|
||||
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++)
|
||||
data.bones.add(skeletonData.bones.get(input.readInt(true)));
|
||||
data.target = skeletonData.bones.get(input.readInt(true));
|
||||
@ -217,6 +218,7 @@ public class SkeletonBinary {
|
||||
// Transform constraints.
|
||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||
TransformConstraintData data = new TransformConstraintData(input.readString());
|
||||
data.order = input.readInt(true);
|
||||
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++)
|
||||
data.bones.add(skeletonData.bones.get(input.readInt(true)));
|
||||
data.target = skeletonData.bones.get(input.readInt(true));
|
||||
@ -236,6 +238,7 @@ public class SkeletonBinary {
|
||||
// Path constraints.
|
||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||
PathConstraintData data = new PathConstraintData(input.readString());
|
||||
data.order = input.readInt(true);
|
||||
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++)
|
||||
data.bones.add(skeletonData.bones.get(input.readInt(true)));
|
||||
data.target = skeletonData.slots.get(input.readInt(true));
|
||||
|
||||
@ -157,6 +157,7 @@ public class SkeletonJson {
|
||||
// IK constraints.
|
||||
for (JsonValue constraintMap = root.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) {
|
||||
IkConstraintData data = new IkConstraintData(constraintMap.getString("name"));
|
||||
data.order = constraintMap.getInt("order", 0);
|
||||
|
||||
for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
|
||||
String boneName = boneMap.asString();
|
||||
@ -178,6 +179,7 @@ public class SkeletonJson {
|
||||
// Transform constraints.
|
||||
for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
|
||||
TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name"));
|
||||
data.order = constraintMap.getInt("order", 0);
|
||||
|
||||
for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
|
||||
String boneName = boneMap.asString();
|
||||
@ -208,6 +210,7 @@ public class SkeletonJson {
|
||||
// Path constraints.
|
||||
for (JsonValue constraintMap = root.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) {
|
||||
PathConstraintData data = new PathConstraintData(constraintMap.getString("name"));
|
||||
data.order = constraintMap.getInt("order", 0);
|
||||
|
||||
for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
|
||||
String boneName = boneMap.asString();
|
||||
|
||||
@ -6,7 +6,7 @@ import static com.badlogic.gdx.math.MathUtils.*;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class TransformConstraint implements Updatable {
|
||||
public class TransformConstraint implements Constraint {
|
||||
final TransformConstraintData data;
|
||||
final Array<Bone> bones;
|
||||
Bone target;
|
||||
@ -54,7 +54,7 @@ public class TransformConstraint implements Updatable {
|
||||
for (int i = 0, n = bones.size; i < n; 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 r = atan2(tc, ta) - atan2(c, a) + data.offsetRotation * degRad;
|
||||
if (r > PI)
|
||||
@ -68,7 +68,7 @@ public class TransformConstraint implements Updatable {
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
|
||||
if (translateMix > 0) {
|
||||
if (translateMix != 0) {
|
||||
Vector2 temp = this.temp;
|
||||
target.localToWorld(temp.set(data.offsetX, data.offsetY));
|
||||
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 () {
|
||||
return bones;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class TransformConstraintData {
|
||||
final String name;
|
||||
int order;
|
||||
final Array<BoneData> bones = new Array();
|
||||
BoneData target;
|
||||
float rotateMix, translateMix, scaleMix, shearMix;
|
||||
@ -19,6 +20,14 @@ public class TransformConstraintData {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getOrder () {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder (int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public Array<BoneData> getBones () {
|
||||
return bones;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user