Skip to content

Commit f4f22cd

Browse files
committed
[libgdx] Added bone transform inheritance timeline.
* Renamed TransformMode to Inherit. * Inherit has setup pose and skeleton instance values. * Skip 2-bone IK for non-normal inheritance.
1 parent c83a867 commit f4f22cd

File tree

6 files changed

+102
-25
lines changed

6 files changed

+102
-25
lines changed

spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java

+46-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.badlogic.gdx.utils.Null;
4040
import com.badlogic.gdx.utils.ObjectSet;
4141

42+
import com.esotericsoftware.spine.BoneData.Inherit;
4243
import com.esotericsoftware.spine.attachments.Attachment;
4344
import com.esotericsoftware.spine.attachments.HasTextureRegion;
4445
import com.esotericsoftware.spine.attachments.Sequence;
@@ -173,7 +174,7 @@ static public enum MixDirection {
173174
}
174175

175176
static private enum Property {
176-
rotate, x, y, scaleX, scaleY, shearX, shearY, //
177+
rotate, x, y, scaleX, scaleY, shearX, shearY, inherit, //
177178
rgb, alpha, rgb2, //
178179
attachment, deform, //
179180
event, drawOrder, //
@@ -944,6 +945,50 @@ public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Ev
944945
}
945946
}
946947

948+
/** Changes a bone's {@link Bone#getInherit()}. */
949+
static public class InheritTimeline extends Timeline implements BoneTimeline {
950+
static public final int ENTRIES = 2;
951+
static private final int INHERIT = 1;
952+
953+
final int boneIndex;
954+
955+
public InheritTimeline (int frameCount, int boneIndex) {
956+
super(frameCount, Property.inherit.ordinal() + "|" + boneIndex);
957+
this.boneIndex = boneIndex;
958+
}
959+
960+
public int getBoneIndex () {
961+
return boneIndex;
962+
}
963+
964+
public int getFrameEntries () {
965+
return ENTRIES;
966+
}
967+
968+
/** Sets the transform mode for the specified frame.
969+
* @param frame Between 0 and <code>frameCount</code>, inclusive.
970+
* @param time The frame time in seconds. */
971+
public void setFrame (int frame, float time, Inherit inherit) {
972+
frame *= ENTRIES;
973+
frames[frame] = time;
974+
frames[frame + INHERIT] = inherit.ordinal();
975+
}
976+
977+
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
978+
MixDirection direction) {
979+
980+
Bone bone = skeleton.bones.get(boneIndex);
981+
if (!bone.active) return;
982+
983+
float[] frames = this.frames;
984+
if (time < frames[0]) {
985+
if (blend == setup || blend == first) bone.inherit = bone.data.inherit;
986+
return;
987+
}
988+
bone.inherit = Inherit.values[(int)frames[search(frames, time, ENTRIES) + INHERIT]];
989+
}
990+
}
991+
947992
/** Changes a slot's {@link Slot#getColor()}. */
948993
static public class RGBATimeline extends CurveTimeline implements SlotTimeline {
949994
static public final int ENTRIES = 5;

spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java

+19-7
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import com.badlogic.gdx.utils.Array;
3838
import com.badlogic.gdx.utils.Null;
3939

40-
import com.esotericsoftware.spine.BoneData.TransformMode;
40+
import com.esotericsoftware.spine.BoneData.Inherit;
4141
import com.esotericsoftware.spine.Skeleton.Physics;
4242

4343
/** Stores a bone's current pose.
@@ -54,6 +54,7 @@ public class Bone implements Updatable {
5454
float ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY;
5555
float a, b, worldX;
5656
float c, d, worldY;
57+
Inherit inherit;
5758

5859
boolean sorted, active;
5960

@@ -80,6 +81,7 @@ public Bone (Bone bone, Skeleton skeleton, @Null Bone parent) {
8081
scaleY = bone.scaleY;
8182
shearX = bone.shearX;
8283
shearY = bone.shearY;
84+
inherit = bone.inherit;
8385
}
8486

8587
/** Computes the world transform using the parent bone and this bone's local applied transform. */
@@ -127,7 +129,7 @@ public void updateWorldTransform (float x, float y, float rotation, float scaleX
127129
worldX = pa * x + pb * y + parent.worldX;
128130
worldY = pc * x + pd * y + parent.worldY;
129131

130-
switch (data.transformMode) {
132+
switch (inherit) {
131133
case normal: {
132134
float rx = (rotation + shearX) * degRad;
133135
float ry = (rotation + 90 + shearY) * degRad;
@@ -187,8 +189,7 @@ public void updateWorldTransform (float x, float y, float rotation, float scaleX
187189
za *= s;
188190
zc *= s;
189191
s = (float)Math.sqrt(za * za + zc * zc);
190-
if (data.transformMode == TransformMode.noScale
191-
&& (pa * pd - pb * pc < 0) != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
192+
if (inherit == Inherit.noScale && (pa * pd - pb * pc < 0) != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
192193
rotation = PI / 2 + atan2(zc, za);
193194
float zb = cos(rotation) * s;
194195
float zd = sin(rotation) * s;
@@ -219,6 +220,7 @@ public void setToSetupPose () {
219220
scaleY = data.scaleY;
220221
shearX = data.shearX;
221222
shearY = data.shearY;
223+
inherit = data.inherit;
222224
}
223225

224226
/** The bone's setup pose data. */
@@ -325,6 +327,16 @@ public void setShearY (float shearY) {
325327
this.shearY = shearY;
326328
}
327329

330+
/** Controls how parent world transforms affect this bone. */
331+
public Inherit getInherit () {
332+
return inherit;
333+
}
334+
335+
public void setInherit (Inherit inherit) {
336+
if (inherit == null) throw new IllegalArgumentException("inherit cannot be null.");
337+
this.inherit = inherit;
338+
}
339+
328340
// -- Applied transform
329341

330342
/** The applied local x translation. */
@@ -420,13 +432,13 @@ public void updateAppliedTransform () {
420432
ay = (dy * id - dx * ic);
421433

422434
float ra, rb, rc, rd;
423-
if (data.transformMode == TransformMode.onlyTranslation) {
435+
if (inherit == Inherit.onlyTranslation) {
424436
ra = a;
425437
rb = b;
426438
rc = c;
427439
rd = d;
428440
} else {
429-
switch (data.transformMode) {
441+
switch (inherit) {
430442
case noRotationOrReflection: {
431443
float s = Math.abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
432444
float sa = pa / skeleton.scaleX;
@@ -448,7 +460,7 @@ public void updateAppliedTransform () {
448460
pa *= s;
449461
pc *= s;
450462
s = (float)Math.sqrt(pa * pa + pc * pc);
451-
if (data.transformMode == TransformMode.noScale && pid < 0 != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
463+
if (inherit == Inherit.noScale && pid < 0 != (skeleton.scaleX < 0 != skeleton.scaleY < 0)) s = -s;
452464
r = PI / 2 + atan2(pc, pa);
453465
pb = cos(r) * s;
454466
pd = sin(r) * s;

spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class BoneData {
4141
@Null final BoneData parent;
4242
float length;
4343
float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY;
44-
TransformMode transformMode = TransformMode.normal;
44+
Inherit inherit = Inherit.normal;
4545
boolean skinRequired;
4646

4747
// Nonessential.
@@ -169,14 +169,14 @@ public void setShearY (float shearY) {
169169
this.shearY = shearY;
170170
}
171171

172-
/** The transform mode for how parent world transforms affect this bone. */
173-
public TransformMode getTransformMode () {
174-
return transformMode;
172+
/** Determines how parent world transforms affect this bone. */
173+
public Inherit getInherit () {
174+
return inherit;
175175
}
176176

177-
public void setTransformMode (TransformMode transformMode) {
178-
if (transformMode == null) throw new IllegalArgumentException("transformMode cannot be null.");
179-
this.transformMode = transformMode;
177+
public void setInherit (Inherit inherit) {
178+
if (inherit == null) throw new IllegalArgumentException("inherit cannot be null.");
179+
this.inherit = inherit;
180180
}
181181

182182
/** When true, {@link Skeleton#updateWorldTransform(Physics)} only updates this bone if the {@link Skeleton#getSkin()} contains
@@ -220,9 +220,9 @@ public String toString () {
220220
}
221221

222222
/** Determines how a bone inherits world transforms from parent bones. */
223-
static public enum TransformMode {
223+
static public enum Inherit {
224224
normal, onlyTranslation, noRotationOrReflection, noScale, noScaleOrReflection;
225225

226-
static public final TransformMode[] values = TransformMode.values();
226+
static public final Inherit[] values = Inherit.values();
227227
}
228228
}

spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import com.badlogic.gdx.utils.Array;
3535

36+
import com.esotericsoftware.spine.BoneData.Inherit;
3637
import com.esotericsoftware.spine.Skeleton.Physics;
3738

3839
/** Stores the current pose for an IK constraint. An IK constraint adjusts the rotation of 1 or 2 constrained bones so the tip of
@@ -189,7 +190,7 @@ static public void apply (Bone bone, float targetX, float targetY, boolean compr
189190
Bone p = bone.parent;
190191
float pa = p.a, pb = p.b, pc = p.c, pd = p.d;
191192
float rotationIK = -bone.ashearX - bone.arotation, tx, ty;
192-
switch (bone.data.transformMode) {
193+
switch (bone.inherit) {
193194
case onlyTranslation:
194195
tx = (targetX - bone.worldX) * Math.signum(bone.skeleton.scaleX);
195196
ty = (targetY - bone.worldY) * Math.signum(bone.skeleton.scaleY);
@@ -221,7 +222,7 @@ else if (rotationIK < -180) //
221222
rotationIK += 360;
222223
float sx = bone.ascaleX, sy = bone.ascaleY;
223224
if (compress || stretch) {
224-
switch (bone.data.transformMode) {
225+
switch (bone.inherit) {
225226
case noScale:
226227
case noScaleOrReflection:
227228
tx = targetX - bone.worldX;
@@ -246,6 +247,7 @@ static public void apply (Bone parent, Bone child, float targetX, float targetY,
246247
float softness, float alpha) {
247248
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
248249
if (child == null) throw new IllegalArgumentException("child cannot be null.");
250+
if (parent.inherit != Inherit.normal || child.inherit != Inherit.normal) return;
249251
float px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, sx = psx, sy = psy, csx = child.ascaleX;
250252
int os1, os2, s2;
251253
if (psx < 0) {

spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
5353
import com.esotericsoftware.spine.Animation.EventTimeline;
5454
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
55+
import com.esotericsoftware.spine.Animation.InheritTimeline;
5556
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
5657
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
5758
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
@@ -80,7 +81,7 @@
8081
import com.esotericsoftware.spine.Animation.TranslateTimeline;
8182
import com.esotericsoftware.spine.Animation.TranslateXTimeline;
8283
import com.esotericsoftware.spine.Animation.TranslateYTimeline;
83-
import com.esotericsoftware.spine.BoneData.TransformMode;
84+
import com.esotericsoftware.spine.BoneData.Inherit;
8485
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
8586
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
8687
import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
@@ -113,6 +114,7 @@ public class SkeletonBinary extends SkeletonLoader {
113114
static public final int BONE_SHEAR = 7;
114115
static public final int BONE_SHEARX = 8;
115116
static public final int BONE_SHEARY = 9;
117+
static public final int BONE_INHERIT = 10;
116118

117119
static public final int SLOT_ATTACHMENT = 0;
118120
static public final int SLOT_RGBA = 1;
@@ -209,7 +211,7 @@ public SkeletonData readSkeletonData (InputStream dataInput) {
209211
data.shearX = input.readFloat();
210212
data.shearY = input.readFloat();
211213
data.length = input.readFloat() * scale;
212-
data.transformMode = TransformMode.values[input.readInt(true)];
214+
data.inherit = Inherit.values[input.readByte()];
213215
data.skinRequired = input.readBoolean();
214216
if (nonessential) {
215217
Color.rgba8888ToColor(data.color, input.readInt());
@@ -844,7 +846,15 @@ private Animation readAnimation (SkeletonInput input, String name, SkeletonData
844846
for (int i = 0, n = input.readInt(true); i < n; i++) {
845847
int boneIndex = input.readInt(true);
846848
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
847-
int type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true);
849+
int type = input.readByte(), frameCount = input.readInt(true);
850+
if (type == BONE_INHERIT) {
851+
InheritTimeline timeline = new InheritTimeline(frameCount, boneIndex);
852+
for (int frame = 0; frame < frameCount; frame++)
853+
timeline.setFrame(frame, input.readFloat(), Inherit.values[input.readByte()]);
854+
timelines.add(timeline);
855+
continue;
856+
}
857+
int bezierCount = input.readInt(true);
848858
switch (type) {
849859
case BONE_ROTATE:
850860
readTimeline(input, timelines, new RotateTimeline(frameCount, bezierCount, boneIndex), 1);

spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
5454
import com.esotericsoftware.spine.Animation.EventTimeline;
5555
import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
56+
import com.esotericsoftware.spine.Animation.InheritTimeline;
5657
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
5758
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
5859
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
@@ -81,7 +82,7 @@
8182
import com.esotericsoftware.spine.Animation.TranslateTimeline;
8283
import com.esotericsoftware.spine.Animation.TranslateXTimeline;
8384
import com.esotericsoftware.spine.Animation.TranslateYTimeline;
84-
import com.esotericsoftware.spine.BoneData.TransformMode;
85+
import com.esotericsoftware.spine.BoneData.Inherit;
8586
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
8687
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
8788
import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
@@ -166,7 +167,7 @@ public SkeletonData readSkeletonData (JsonValue root) {
166167
data.scaleY = boneMap.getFloat("scaleY", 1);
167168
data.shearX = boneMap.getFloat("shearX", 0);
168169
data.shearY = boneMap.getFloat("shearY", 0);
169-
data.transformMode = TransformMode.valueOf(boneMap.getString("transform", TransformMode.normal.name()));
170+
data.inherit = Inherit.valueOf(boneMap.getString("inherit", Inherit.normal.name()));
170171
data.skinRequired = boneMap.getBoolean("skin", false);
171172

172173
String color = boneMap.getString("color", null);
@@ -812,7 +813,14 @@ else if (timelineName.equals("shear")) {
812813
timelines.add(readTimeline(keyMap, new ShearXTimeline(frames, frames, bone.index), 0, 1));
813814
else if (timelineName.equals("sheary"))
814815
timelines.add(readTimeline(keyMap, new ShearYTimeline(frames, frames, bone.index), 0, 1));
815-
else
816+
else if (timelineName.equals("inherit")) {
817+
InheritTimeline timeline = new InheritTimeline(frames, bone.index);
818+
for (int frame = 0; keyMap != null; keyMap = keyMap.next, frame++) {
819+
float time = keyMap.getFloat("time", 0);
820+
timeline.setFrame(frame, time, Inherit.valueOf(keyMap.getString("inherit", Inherit.normal.name())));
821+
}
822+
timelines.add(timeline);
823+
} else
816824
throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")");
817825
}
818826
}

0 commit comments

Comments
 (0)