Multiple constrained bones for transform constraints.

This commit is contained in:
NathanSweet 2016-06-10 03:21:54 +02:00
parent 8b3b0169ad
commit 92d7ef32f4
6 changed files with 86 additions and 82 deletions

View File

@ -27,14 +27,14 @@ public class PathConstraint implements Updatable {
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.");
this.data = data; this.data = data;
position = data.position;
spacing = data.spacing;
rotateMix = data.rotateMix;
translateMix = data.translateMix;
bones = new Array(data.bones.size); bones = new Array(data.bones.size);
for (BoneData boneData : data.bones) for (BoneData boneData : data.bones)
bones.add(skeleton.findBone(boneData.name)); bones.add(skeleton.findBone(boneData.name));
target = skeleton.findSlot(data.target.name); target = skeleton.findSlot(data.target.name);
position = data.position;
spacing = data.spacing;
rotateMix = data.rotateMix;
translateMix = data.translateMix;
} }
/** Copy constructor. */ /** Copy constructor. */

View File

@ -227,21 +227,17 @@ public class Skeleton {
sortBone(constraint.target); sortBone(constraint.target);
// BOZO! - Update transform constraints to support multiple constrained bones. Array<Bone> constrained = constraint.bones;
// Array<Bone> constrained = constraint.bones; int boneCount = constrained.size;
// int boneCount = constrained.size; for (int ii = 0; ii < boneCount; ii++)
// for (int ii = 0; ii < boneCount; ii++) sortBone(constrained.get(ii));
// sortBone(constrained.get(ii));
sortBone(constraint.bone);
updateCache.add(constraint); updateCache.add(constraint);
// for (int ii = 0; ii < boneCount; ii++) for (int ii = 0; ii < boneCount; ii++)
// reset(constrained.get(ii).children); sortReset(constrained.get(ii).children);
sortReset(constraint.bone.children); // BOZO - Remove. for (int ii = 0; ii < boneCount; ii++)
// for (int ii = 0; ii < boneCount; ii++) constrained.get(ii).sorted = true;
// constrained.get(ii).sorted = true;
constraint.bone.sorted = true; // BOZO - Remove.
} }
for (int i = 0, n = bones.size; i < n; i++) for (int i = 0, n = bones.size; i < n; i++)

View File

@ -217,7 +217,8 @@ 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.bone = skeletonData.bones.get(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)); data.target = skeletonData.bones.get(input.readInt(true));
data.offsetRotation = input.readFloat(); data.offsetRotation = input.readFloat();
data.offsetX = input.readFloat() * scale; data.offsetX = input.readFloat() * scale;

View File

@ -179,9 +179,12 @@ public class SkeletonJson {
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"));
String boneName = constraintMap.getString("bone"); for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
data.bone = skeletonData.findBone(boneName); String boneName = boneMap.asString();
if (data.bone == null) throw new SerializationException("Bone not found: " + boneName); BoneData bone = skeletonData.findBone(boneName);
if (bone == null) throw new SerializationException("Path bone not found: " + boneName);
data.bones.add(bone);
}
String targetName = constraintMap.getString("target"); String targetName = constraintMap.getString("target");
data.target = skeletonData.findBone(targetName); data.target = skeletonData.findBone(targetName);

View File

@ -4,10 +4,12 @@ package com.esotericsoftware.spine;
import static com.badlogic.gdx.math.MathUtils.*; 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;
public class TransformConstraint implements Updatable { public class TransformConstraint implements Updatable {
final TransformConstraintData data; final TransformConstraintData data;
Bone bone, target; final Array<Bone> bones;
Bone target;
float rotateMix, translateMix, scaleMix, shearMix; float rotateMix, translateMix, scaleMix, shearMix;
final Vector2 temp = new Vector2(); final Vector2 temp = new Vector2();
@ -19,7 +21,9 @@ public class TransformConstraint implements Updatable {
translateMix = data.translateMix; translateMix = data.translateMix;
scaleMix = data.scaleMix; scaleMix = data.scaleMix;
shearMix = data.shearMix; shearMix = data.shearMix;
bone = skeleton.findBone(data.bone.name); bones = new Array(data.bones.size);
for (BoneData boneData : data.bones)
bones.add(skeleton.findBone(boneData.name));
target = skeleton.findBone(data.target.name); target = skeleton.findBone(data.target.name);
} }
@ -28,12 +32,14 @@ public class TransformConstraint implements Updatable {
if (constraint == null) throw new IllegalArgumentException("constraint cannot be null."); if (constraint == null) throw new IllegalArgumentException("constraint cannot be null.");
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
data = constraint.data; data = constraint.data;
bones = new Array(constraint.bones.size);
for (Bone bone : constraint.bones)
bones.add(skeleton.bones.get(bone.data.index));
target = skeleton.bones.get(constraint.target.data.index);
rotateMix = constraint.rotateMix; rotateMix = constraint.rotateMix;
translateMix = constraint.translateMix; translateMix = constraint.translateMix;
scaleMix = constraint.scaleMix; scaleMix = constraint.scaleMix;
shearMix = constraint.shearMix; shearMix = constraint.shearMix;
bone = skeleton.bones.get(constraint.bone.data.index);
target = skeleton.bones.get(constraint.target.data.index);
} }
public void apply () { public void apply () {
@ -41,64 +47,64 @@ public class TransformConstraint implements Updatable {
} }
public void update () { public void update () {
Bone bone = this.bone; float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
Bone target = this.target; Bone target = this.target;
float ta = target.a, tb = target.b, tc = target.c, td = target.d;
Array<Bone> bones = this.bones;
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 a = bone.a, b = bone.b, c = bone.c, d = bone.d;
float r = atan2(target.c, target.a) - atan2(c, a) + data.offsetRotation * degRad; float r = atan2(tc, ta) - atan2(c, a) + data.offsetRotation * degRad;
if (r > PI) if (r > PI)
r -= PI2; r -= PI2;
else if (r < -PI) r += PI2; else if (r < -PI) r += PI2;
r *= rotateMix; r *= rotateMix;
float cos = cos(r), sin = sin(r); float cos = cos(r), sin = sin(r);
bone.a = cos * a - sin * c; bone.a = cos * a - sin * c;
bone.b = cos * b - sin * d; bone.b = cos * b - sin * d;
bone.c = sin * a + cos * c; bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d; bone.d = sin * b + cos * d;
} }
if (scaleMix > 0) { if (translateMix > 0) {
float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c); Vector2 temp = this.temp;
float ts = (float)Math.sqrt(target.a * target.a + target.c * target.c); target.localToWorld(temp.set(data.offsetX, data.offsetY));
float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; bone.worldX += (temp.x - bone.worldX) * translateMix;
bone.a *= s; bone.worldY += (temp.y - bone.worldY) * translateMix;
bone.c *= s; }
bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
ts = (float)Math.sqrt(target.b * target.b + target.d * target.d);
s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0;
bone.b *= s;
bone.d *= s;
}
if (shearMix > 0) { if (scaleMix > 0) {
float b = bone.b, d = bone.d; float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
float by = atan2(d, b); float ts = (float)Math.sqrt(ta * ta + tc * tc);
float r = atan2(target.d, target.b) - atan2(target.c, target.a) - (by - atan2(bone.c, bone.a)); float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0;
if (r > PI) bone.a *= s;
r -= PI2; bone.c *= s;
else if (r < -PI) r += PI2; bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
r = by + (r + data.offsetShearY * degRad) * shearMix; ts = (float)Math.sqrt(tb * tb + td * td);
float s = (float)Math.sqrt(b * b + d * d); s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0;
bone.b = cos(r) * s; bone.b *= s;
bone.d = sin(r) * s; bone.d *= s;
} }
float translateMix = this.translateMix; if (shearMix > 0) {
if (translateMix > 0) { float b = bone.b, d = bone.d;
Vector2 temp = this.temp; float by = atan2(d, b);
target.localToWorld(temp.set(data.offsetX, data.offsetY)); float r = atan2(td, tb) - atan2(tc, ta) - (by - atan2(bone.c, bone.a));
bone.worldX += (temp.x - bone.worldX) * translateMix; if (r > PI)
bone.worldY += (temp.y - bone.worldY) * translateMix; r -= PI2;
else if (r < -PI) r += PI2;
r = by + (r + data.offsetShearY * degRad) * shearMix;
float s = (float)Math.sqrt(b * b + d * d);
bone.b = cos(r) * s;
bone.d = sin(r) * s;
}
} }
} }
public Bone getBone () { public Array<Bone> getBones () {
return bone; return bones;
}
public void setBone (Bone bone) {
this.bone = bone;
} }
public Bone getTarget () { public Bone getTarget () {

View File

@ -1,9 +1,12 @@
package com.esotericsoftware.spine; package com.esotericsoftware.spine;
import com.badlogic.gdx.utils.Array;
public class TransformConstraintData { public class TransformConstraintData {
final String name; final String name;
BoneData bone, target; final Array<BoneData> bones = new Array();
BoneData target;
float rotateMix, translateMix, scaleMix, shearMix; float rotateMix, translateMix, scaleMix, shearMix;
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
@ -16,13 +19,8 @@ public class TransformConstraintData {
return name; return name;
} }
public BoneData getBone () { public Array<BoneData> getBones () {
return bone; return bones;
}
public void setBone (BoneData bone) {
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
this.bone = bone;
} }
public BoneData getTarget () { public BoneData getTarget () {