|
@@ -39,6 +39,8 @@ public class Skeleton {
|
|
final SkeletonData data;
|
|
final SkeletonData data;
|
|
final Array<Bone> bones;
|
|
final Array<Bone> bones;
|
|
final Array<Slot> slots;
|
|
final Array<Slot> slots;
|
|
|
|
+ final Array<IkConstraint> ikConstraints;
|
|
|
|
+ private final Array<Array<Bone>> updateBonesCache = new Array();
|
|
Array<Slot> drawOrder;
|
|
Array<Slot> drawOrder;
|
|
Skin skin;
|
|
Skin skin;
|
|
final Color color;
|
|
final Color color;
|
|
@@ -65,7 +67,13 @@ public class Skeleton {
|
|
drawOrder.add(slot);
|
|
drawOrder.add(slot);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ikConstraints = new Array(data.ikConstraints.size);
|
|
|
|
+ for (IkConstraintData ikConstraintData : data.ikConstraints)
|
|
|
|
+ ikConstraints.add(new IkConstraint(ikConstraintData, this));
|
|
|
|
+
|
|
color = new Color(1, 1, 1, 1);
|
|
color = new Color(1, 1, 1, 1);
|
|
|
|
+
|
|
|
|
+ updateCache();
|
|
}
|
|
}
|
|
|
|
|
|
/** Copy constructor. */
|
|
/** Copy constructor. */
|
|
@@ -82,26 +90,84 @@ public class Skeleton {
|
|
slots = new Array(skeleton.slots.size);
|
|
slots = new Array(skeleton.slots.size);
|
|
for (Slot slot : skeleton.slots) {
|
|
for (Slot slot : skeleton.slots) {
|
|
Bone bone = bones.get(skeleton.bones.indexOf(slot.bone, true));
|
|
Bone bone = bones.get(skeleton.bones.indexOf(slot.bone, true));
|
|
- Slot newSlot = new Slot(slot, this, bone);
|
|
|
|
- slots.add(newSlot);
|
|
|
|
|
|
+ slots.add(new Slot(slot, this, bone));
|
|
}
|
|
}
|
|
|
|
|
|
drawOrder = new Array(slots.size);
|
|
drawOrder = new Array(slots.size);
|
|
for (Slot slot : skeleton.drawOrder)
|
|
for (Slot slot : skeleton.drawOrder)
|
|
drawOrder.add(slots.get(skeleton.slots.indexOf(slot, true)));
|
|
drawOrder.add(slots.get(skeleton.slots.indexOf(slot, true)));
|
|
|
|
|
|
|
|
+ ikConstraints = new Array(skeleton.ikConstraints.size);
|
|
|
|
+ for (IkConstraint ikConstraint : skeleton.ikConstraints)
|
|
|
|
+ ikConstraints.add(new IkConstraint(ikConstraint));
|
|
|
|
+
|
|
skin = skeleton.skin;
|
|
skin = skeleton.skin;
|
|
color = new Color(skeleton.color);
|
|
color = new Color(skeleton.color);
|
|
time = skeleton.time;
|
|
time = skeleton.time;
|
|
|
|
+
|
|
|
|
+ updateCache();
|
|
}
|
|
}
|
|
|
|
|
|
- /** Updates the world transform for each bone. */
|
|
|
|
|
|
+ /** Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */
|
|
|
|
+ public void updateCache () {
|
|
|
|
+ Array<Array<Bone>> updateBonesCache = this.updateBonesCache;
|
|
|
|
+ Array<IkConstraint> ikConstraints = this.ikConstraints;
|
|
|
|
+ int ikConstraintsCount = ikConstraints.size;
|
|
|
|
+
|
|
|
|
+ int arrayCount = ikConstraintsCount + 1;
|
|
|
|
+ updateBonesCache.truncate(arrayCount);
|
|
|
|
+ for (int i = 0, n = updateBonesCache.size; i < n; i++)
|
|
|
|
+ updateBonesCache.get(i).clear();
|
|
|
|
+ while (updateBonesCache.size < arrayCount)
|
|
|
|
+ updateBonesCache.add(new Array());
|
|
|
|
+
|
|
|
|
+ Array<Bone> nonIkBones = updateBonesCache.first();
|
|
|
|
+
|
|
|
|
+ outer:
|
|
|
|
+ for (int i = 0, n = bones.size; i < n; i++) {
|
|
|
|
+ Bone bone = bones.get(i);
|
|
|
|
+ Bone current = bone;
|
|
|
|
+ do {
|
|
|
|
+ for (int ii = 0; ii < ikConstraintsCount; ii++) {
|
|
|
|
+ IkConstraint ikConstraint = ikConstraints.get(ii);
|
|
|
|
+ Bone parent = ikConstraint.bones.first();
|
|
|
|
+ Bone child = ikConstraint.bones.peek();
|
|
|
|
+ while (true) {
|
|
|
|
+ if (current == child) {
|
|
|
|
+ updateBonesCache.get(ii).add(bone);
|
|
|
|
+ updateBonesCache.get(ii + 1).add(bone);
|
|
|
|
+ continue outer;
|
|
|
|
+ }
|
|
|
|
+ if (child == parent) break;
|
|
|
|
+ child = child.parent;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ current = current.parent;
|
|
|
|
+ } while (current != null);
|
|
|
|
+ nonIkBones.add(bone);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Updates the world transform for each bone and applies IK constraints. */
|
|
public void updateWorldTransform () {
|
|
public void updateWorldTransform () {
|
|
|
|
+ Array<Bone> bones = this.bones;
|
|
|
|
+ for (int i = 0, nn = bones.size; i < nn; i++) {
|
|
|
|
+ Bone bone = bones.get(i);
|
|
|
|
+ bone.rotationIK = bone.rotation;
|
|
|
|
+ }
|
|
boolean flipX = this.flipX;
|
|
boolean flipX = this.flipX;
|
|
boolean flipY = this.flipY;
|
|
boolean flipY = this.flipY;
|
|
- Array<Bone> bones = this.bones;
|
|
|
|
- for (int i = 0, n = bones.size; i < n; i++)
|
|
|
|
- bones.get(i).updateWorldTransform(flipX, flipY);
|
|
|
|
|
|
+ Array<Array<Bone>> updateBonesCache = this.updateBonesCache;
|
|
|
|
+ Array<IkConstraint> ikConstraints = this.ikConstraints;
|
|
|
|
+ int i = 0, last = updateBonesCache.size - 1;
|
|
|
|
+ while (true) {
|
|
|
|
+ Array<Bone> updateBones = updateBonesCache.get(i);
|
|
|
|
+ for (int ii = 0, nn = updateBones.size; ii < nn; ii++)
|
|
|
|
+ updateBones.get(ii).updateWorldTransform(flipX, flipY);
|
|
|
|
+ if (i == last) break;
|
|
|
|
+ ikConstraints.get(i).apply();
|
|
|
|
+ i++;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/** Sets the bones and slots to their setup pose values. */
|
|
/** Sets the bones and slots to their setup pose values. */
|
|
@@ -114,6 +180,13 @@ public class Skeleton {
|
|
Array<Bone> bones = this.bones;
|
|
Array<Bone> bones = this.bones;
|
|
for (int i = 0, n = bones.size; i < n; i++)
|
|
for (int i = 0, n = bones.size; i < n; i++)
|
|
bones.get(i).setToSetupPose();
|
|
bones.get(i).setToSetupPose();
|
|
|
|
+
|
|
|
|
+ Array<IkConstraint> ikConstraints = this.ikConstraints;
|
|
|
|
+ for (int i = 0, n = ikConstraints.size; i < n; i++) {
|
|
|
|
+ IkConstraint ikConstraint = ikConstraints.get(i);
|
|
|
|
+ ikConstraint.bendDirection = ikConstraint.data.bendDirection;
|
|
|
|
+ ikConstraint.mix = ikConstraint.data.mix;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
public void setSlotsToSetupPose () {
|
|
public void setSlotsToSetupPose () {
|
|
@@ -263,6 +336,21 @@ public class Skeleton {
|
|
throw new IllegalArgumentException("Slot not found: " + slotName);
|
|
throw new IllegalArgumentException("Slot not found: " + slotName);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public Array<IkConstraint> getIkConstraints () {
|
|
|
|
+ return ikConstraints;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** @return May be null. */
|
|
|
|
+ public IkConstraint findIkConstraint (String ikConstraintName) {
|
|
|
|
+ if (ikConstraintName == null) throw new IllegalArgumentException("ikConstraintName cannot be null.");
|
|
|
|
+ Array<IkConstraint> ikConstraints = this.ikConstraints;
|
|
|
|
+ for (int i = 0, n = ikConstraints.size; i < n; i++) {
|
|
|
|
+ IkConstraint ikConstraint = ikConstraints.get(i);
|
|
|
|
+ if (ikConstraint.data.name.equals(ikConstraintName)) return ikConstraint;
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
public Color getColor () {
|
|
public Color getColor () {
|
|
return color;
|
|
return color;
|
|
}
|
|
}
|