mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Value space timelines, multiple property IDs per timeline, rotation not limited -180/180, clean up.
* Timeline is an abstract base class rather than an interface. * Timelines have a list of String property IDs rather than a single int ID. * CurveTimeline is separated into percent and value timelines and the API is cleaned up. * CurveTimeline stores Bezier curves more efficiently. Linear/stepped keys used to take up memory they didn't use (18 floats/key). * Binary format knows how many keys are Bezier up front for more efficient loading. * RotateTimeline is no longer limited to -180/180. * ScaleTimeline and ShearTimeline no longer extend TranslateTimeline. * PathConstraintSpacingTimeline no longer extends PathConstraintPositionTimeline.
This commit is contained in:
parent
bb003b6636
commit
93ca505864
@ -68,7 +68,7 @@ public class AttachmentTimelineTests {
|
|||||||
skeleton = new Skeleton(skeletonData);
|
skeleton = new Skeleton(skeletonData);
|
||||||
slot = skeleton.findSlot("slot");
|
slot = skeleton.findSlot("slot");
|
||||||
|
|
||||||
AttachmentTimeline timeline = new AttachmentTimeline(2);
|
AttachmentTimeline timeline = new AttachmentTimeline(2, 0);
|
||||||
timeline.setFrame(0, 0, "attachment1");
|
timeline.setFrame(0, 0, "attachment1");
|
||||||
timeline.setFrame(1, 0.5f, "attachment2");
|
timeline.setFrame(1, 0.5f, "attachment2");
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -29,12 +29,12 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
import static com.esotericsoftware.spine.Animation.RotateTimeline.*;
|
import static com.esotericsoftware.spine.Animation.ValueCurveTimeline.*;
|
||||||
|
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
import com.badlogic.gdx.utils.FloatArray;
|
import com.badlogic.gdx.utils.FloatArray;
|
||||||
import com.badlogic.gdx.utils.IntArray;
|
import com.badlogic.gdx.utils.IntArray;
|
||||||
import com.badlogic.gdx.utils.IntSet;
|
import com.badlogic.gdx.utils.ObjectSet;
|
||||||
import com.badlogic.gdx.utils.Pool;
|
import com.badlogic.gdx.utils.Pool;
|
||||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||||
import com.badlogic.gdx.utils.SnapshotArray;
|
import com.badlogic.gdx.utils.SnapshotArray;
|
||||||
@ -90,7 +90,7 @@ public class AnimationState {
|
|||||||
private final Array<Event> events = new Array();
|
private final Array<Event> events = new Array();
|
||||||
final SnapshotArray<AnimationStateListener> listeners = new SnapshotArray();
|
final SnapshotArray<AnimationStateListener> listeners = new SnapshotArray();
|
||||||
private final EventQueue queue = new EventQueue();
|
private final EventQueue queue = new EventQueue();
|
||||||
private final IntSet propertyIDs = new IntSet();
|
private final ObjectSet<String> propertyIds = new ObjectSet();
|
||||||
boolean animationsChanged;
|
boolean animationsChanged;
|
||||||
private float timeScale = 1;
|
private float timeScale = 1;
|
||||||
|
|
||||||
@ -367,19 +367,13 @@ public class AnimationState {
|
|||||||
} else {
|
} else {
|
||||||
r1 = blend == MixBlend.setup ? bone.data.rotation : bone.rotation;
|
r1 = blend == MixBlend.setup ? bone.data.rotation : bone.rotation;
|
||||||
if (time >= frames[frames.length - ENTRIES]) // Time is after last frame.
|
if (time >= frames[frames.length - ENTRIES]) // Time is after last frame.
|
||||||
r2 = bone.data.rotation + frames[frames.length + PREV_ROTATION];
|
r2 = bone.data.rotation + frames[frames.length + PREV_VALUE];
|
||||||
else {
|
else {
|
||||||
// Interpolate between the previous frame and the current frame.
|
// Interpolate between the previous frame and the current frame.
|
||||||
int frame = Animation.binarySearch(frames, time, ENTRIES);
|
int frame = Animation.binarySearch(frames, time, ENTRIES);
|
||||||
float prevRotation = frames[frame + PREV_ROTATION];
|
r2 = bone.data.rotation + timeline.getCurveValue((frame >> 1) - 1, time, //
|
||||||
float frameTime = frames[frame];
|
frames[frame + PREV_TIME], frames[frame + PREV_VALUE], //
|
||||||
float percent = timeline.getCurvePercent((frame >> 1) - 1,
|
frames[frame], frames[frame + VALUE]);
|
||||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
|
||||||
|
|
||||||
r2 = frames[frame + ROTATION] - prevRotation;
|
|
||||||
r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
|
||||||
r2 = prevRotation + r2 * percent + bone.data.rotation;
|
|
||||||
r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,8 +403,7 @@ public class AnimationState {
|
|||||||
timelinesRotation[i] = total;
|
timelinesRotation[i] = total;
|
||||||
}
|
}
|
||||||
timelinesRotation[i + 1] = diff;
|
timelinesRotation[i + 1] = diff;
|
||||||
r1 += total * alpha;
|
bone.rotation = r1 + total * alpha;
|
||||||
bone.rotation = r1 - (16384 - (int)(16384.499999999996 - r1 / 360)) * 360;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void queueEvents (TrackEntry entry, float animationTime) {
|
private void queueEvents (TrackEntry entry, float animationTime) {
|
||||||
@ -700,7 +693,7 @@ public class AnimationState {
|
|||||||
animationsChanged = false;
|
animationsChanged = false;
|
||||||
|
|
||||||
// Process in the order that animations are applied.
|
// Process in the order that animations are applied.
|
||||||
propertyIDs.clear(2048);
|
propertyIds.clear(2048);
|
||||||
for (int i = 0, n = tracks.size; i < n; i++) {
|
for (int i = 0, n = tracks.size; i < n; i++) {
|
||||||
TrackEntry entry = tracks.get(i);
|
TrackEntry entry = tracks.get(i);
|
||||||
if (entry == null) continue;
|
if (entry == null) continue;
|
||||||
@ -713,7 +706,7 @@ public class AnimationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process in the reverse order that animations are applied.
|
// Process in the reverse order that animations are applied.
|
||||||
propertyIDs.clear(2048);
|
propertyIds.clear(2048);
|
||||||
for (int i = tracks.size - 1; i >= 0; i--) {
|
for (int i = tracks.size - 1; i >= 0; i--) {
|
||||||
TrackEntry entry = tracks.get(i);
|
TrackEntry entry = tracks.get(i);
|
||||||
while (entry != null) {
|
while (entry != null) {
|
||||||
@ -730,11 +723,11 @@ public class AnimationState {
|
|||||||
int[] timelineMode = entry.timelineMode.setSize(timelinesCount);
|
int[] timelineMode = entry.timelineMode.setSize(timelinesCount);
|
||||||
entry.timelineHoldMix.clear();
|
entry.timelineHoldMix.clear();
|
||||||
Object[] timelineHoldMix = entry.timelineHoldMix.setSize(timelinesCount);
|
Object[] timelineHoldMix = entry.timelineHoldMix.setSize(timelinesCount);
|
||||||
IntSet propertyIDs = this.propertyIDs;
|
ObjectSet<String> propertyIds = this.propertyIds;
|
||||||
|
|
||||||
if (to != null && to.holdPrevious) {
|
if (to != null && to.holdPrevious) {
|
||||||
for (int i = 0; i < timelinesCount; i++) {
|
for (int i = 0; i < timelinesCount; i++) {
|
||||||
propertyIDs.add(((Timeline)timelines[i]).getPropertyId());
|
propertyIds.addAll(((Timeline)timelines[i]).getPropertyIds());
|
||||||
timelineMode[i] = HOLD;
|
timelineMode[i] = HOLD;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -743,15 +736,15 @@ public class AnimationState {
|
|||||||
outer:
|
outer:
|
||||||
for (int i = 0; i < timelinesCount; i++) {
|
for (int i = 0; i < timelinesCount; i++) {
|
||||||
Timeline timeline = (Timeline)timelines[i];
|
Timeline timeline = (Timeline)timelines[i];
|
||||||
int id = timeline.getPropertyId();
|
String[] ids = timeline.getPropertyIds();
|
||||||
if (!propertyIDs.add(id))
|
if (!propertyIds.addAll(ids))
|
||||||
timelineMode[i] = SUBSEQUENT;
|
timelineMode[i] = SUBSEQUENT;
|
||||||
else if (to == null || timeline instanceof AttachmentTimeline || timeline instanceof DrawOrderTimeline
|
else if (to == null || timeline instanceof AttachmentTimeline || timeline instanceof DrawOrderTimeline
|
||||||
|| timeline instanceof EventTimeline || !to.animation.hasTimeline(id)) {
|
|| timeline instanceof EventTimeline || !to.animation.hasTimeline(ids)) {
|
||||||
timelineMode[i] = FIRST;
|
timelineMode[i] = FIRST;
|
||||||
} else {
|
} else {
|
||||||
for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) {
|
for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) {
|
||||||
if (next.animation.hasTimeline(id)) continue;
|
if (next.animation.hasTimeline(ids)) continue;
|
||||||
if (next.mixDuration > 0) {
|
if (next.mixDuration > 0) {
|
||||||
timelineMode[i] = HOLD_MIX;
|
timelineMode[i] = HOLD_MIX;
|
||||||
timelineHoldMix[i] = next;
|
timelineHoldMix[i] = next;
|
||||||
@ -768,12 +761,12 @@ public class AnimationState {
|
|||||||
Object[] timelines = entry.animation.timelines.items;
|
Object[] timelines = entry.animation.timelines.items;
|
||||||
int timelinesCount = entry.animation.timelines.size;
|
int timelinesCount = entry.animation.timelines.size;
|
||||||
int[] timelineMode = entry.timelineMode.items;
|
int[] timelineMode = entry.timelineMode.items;
|
||||||
IntSet propertyIDs = this.propertyIDs;
|
ObjectSet<String> propertyIds = this.propertyIds;
|
||||||
|
|
||||||
for (int i = 0; i < timelinesCount; i++) {
|
for (int i = 0; i < timelinesCount; i++) {
|
||||||
if (timelines[i] instanceof AttachmentTimeline) {
|
if (timelines[i] instanceof AttachmentTimeline) {
|
||||||
AttachmentTimeline timeline = (AttachmentTimeline)timelines[i];
|
AttachmentTimeline timeline = (AttachmentTimeline)timelines[i];
|
||||||
if (!propertyIDs.add(timeline.slotIndex)) timelineMode[i] |= NOT_LAST;
|
if (!propertyIds.addAll(timeline.getPropertyIds())) timelineMode[i] |= NOT_LAST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,6 @@ import com.badlogic.gdx.utils.SerializationException;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ColorTimeline;
|
import com.esotericsoftware.spine.Animation.ColorTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.CurveTimeline;
|
|
||||||
import com.esotericsoftware.spine.Animation.DeformTimeline;
|
import com.esotericsoftware.spine.Animation.DeformTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.EventTimeline;
|
import com.esotericsoftware.spine.Animation.EventTimeline;
|
||||||
@ -51,6 +50,7 @@ import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
|
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
|
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
|
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.PercentCurveTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
||||||
@ -58,6 +58,7 @@ import com.esotericsoftware.spine.Animation.Timeline;
|
|||||||
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
|
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.TwoColorTimeline;
|
import com.esotericsoftware.spine.Animation.TwoColorTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.ValueCurveTimeline;
|
||||||
import com.esotericsoftware.spine.BoneData.TransformMode;
|
import com.esotericsoftware.spine.BoneData.TransformMode;
|
||||||
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
|
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
|
||||||
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
|
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
|
||||||
@ -574,7 +575,6 @@ public class SkeletonBinary {
|
|||||||
private Animation readAnimation (SkeletonInput input, String name, SkeletonData skeletonData) {
|
private Animation readAnimation (SkeletonInput input, String name, SkeletonData skeletonData) {
|
||||||
Array<Timeline> timelines = new Array(32);
|
Array<Timeline> timelines = new Array(32);
|
||||||
float scale = this.scale;
|
float scale = this.scale;
|
||||||
float duration = 0;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Slot timelines.
|
// Slot timelines.
|
||||||
@ -582,43 +582,37 @@ public class SkeletonBinary {
|
|||||||
int slotIndex = input.readInt(true);
|
int slotIndex = 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++) {
|
||||||
int timelineType = input.readByte();
|
int timelineType = input.readByte();
|
||||||
int frameCount = input.readInt(true);
|
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||||
switch (timelineType) {
|
switch (timelineType) {
|
||||||
case SLOT_ATTACHMENT: {
|
case SLOT_ATTACHMENT: {
|
||||||
AttachmentTimeline timeline = new AttachmentTimeline(frameCount);
|
AttachmentTimeline timeline = new AttachmentTimeline(frameCount, slotIndex);
|
||||||
timeline.slotIndex = slotIndex;
|
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readStringRef());
|
timeline.setFrame(frameIndex, input.readFloat(), input.readStringRef());
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[frameCount - 1]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SLOT_COLOR: {
|
case SLOT_COLOR: {
|
||||||
ColorTimeline timeline = new ColorTimeline(frameCount);
|
ColorTimeline timeline = new ColorTimeline(frameCount, input.readInt(true), slotIndex);
|
||||||
timeline.slotIndex = slotIndex;
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
||||||
float time = input.readFloat();
|
float time = input.readFloat();
|
||||||
Color.rgba8888ToColor(tempColor1, input.readInt());
|
Color.rgba8888ToColor(tempColor1, input.readInt());
|
||||||
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a);
|
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a);
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * ColorTimeline.ENTRIES]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SLOT_TWO_COLOR: {
|
case SLOT_TWO_COLOR: {
|
||||||
TwoColorTimeline timeline = new TwoColorTimeline(frameCount);
|
TwoColorTimeline timeline = new TwoColorTimeline(frameCount, input.readInt(true), slotIndex);
|
||||||
timeline.slotIndex = slotIndex;
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
||||||
float time = input.readFloat();
|
float time = input.readFloat();
|
||||||
Color.rgba8888ToColor(tempColor1, input.readInt());
|
Color.rgba8888ToColor(tempColor1, input.readInt());
|
||||||
Color.rgb888ToColor(tempColor2, input.readInt());
|
Color.rgb888ToColor(tempColor2, input.readInt());
|
||||||
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r,
|
timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r,
|
||||||
tempColor2.g, tempColor2.b);
|
tempColor2.g, tempColor2.b);
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * TwoColorTimeline.ENTRIES]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -630,40 +624,44 @@ public class SkeletonBinary {
|
|||||||
int boneIndex = input.readInt(true);
|
int boneIndex = 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++) {
|
||||||
int timelineType = input.readByte();
|
int timelineType = input.readByte();
|
||||||
int frameCount = input.readInt(true);
|
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||||
switch (timelineType) {
|
switch (timelineType) {
|
||||||
case BONE_ROTATE: {
|
case BONE_ROTATE: {
|
||||||
RotateTimeline timeline = new RotateTimeline(frameCount);
|
RotateTimeline timeline = new RotateTimeline(frameCount, input.readInt(true), boneIndex);
|
||||||
timeline.boneIndex = boneIndex;
|
float value = input.readFloat();
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat());
|
timeline.setFrame(frameIndex, input.readFloat(), value);
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast)
|
||||||
|
readCurve(input, timeline, frameIndex, bezierIndex, value, value = input.readFloat());
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * RotateTimeline.ENTRIES]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BONE_TRANSLATE:
|
case BONE_TRANSLATE: {
|
||||||
case BONE_SCALE:
|
TranslateTimeline timeline = new TranslateTimeline(frameCount, input.readInt(true), boneIndex);
|
||||||
case BONE_SHEAR: {
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
TranslateTimeline timeline;
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * scale, input.readFloat() * scale);
|
||||||
float timelineScale = 1;
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
if (timelineType == BONE_SCALE)
|
}
|
||||||
timeline = new ScaleTimeline(frameCount);
|
timelines.add(timeline);
|
||||||
else if (timelineType == BONE_SHEAR)
|
break;
|
||||||
timeline = new ShearTimeline(frameCount);
|
}
|
||||||
else {
|
case BONE_SCALE: {
|
||||||
timeline = new TranslateTimeline(frameCount);
|
ScaleTimeline timeline = new ScaleTimeline(frameCount, input.readInt(true), boneIndex);
|
||||||
timelineScale = scale;
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
}
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
|
||||||
timeline.boneIndex = boneIndex;
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
}
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale,
|
timelines.add(timeline);
|
||||||
input.readFloat() * timelineScale);
|
break;
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
}
|
||||||
|
case BONE_SHEAR: {
|
||||||
|
ShearTimeline timeline = new ShearTimeline(frameCount, input.readInt(true), boneIndex);
|
||||||
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
|
||||||
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * TranslateTimeline.ENTRIES]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -673,31 +671,27 @@ public class SkeletonBinary {
|
|||||||
// IK constraint timelines.
|
// IK constraint timelines.
|
||||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||||
int index = input.readInt(true);
|
int index = input.readInt(true);
|
||||||
int frameCount = input.readInt(true);
|
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||||
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount);
|
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index);
|
||||||
timeline.ikConstraintIndex = index;
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat() * scale, input.readByte(),
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat() * scale, input.readByte(),
|
||||||
input.readBoolean(), input.readBoolean());
|
input.readBoolean(), input.readBoolean());
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * IkConstraintTimeline.ENTRIES]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform constraint timelines.
|
// Transform constraint timelines.
|
||||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||||
int index = input.readInt(true);
|
int index = input.readInt(true);
|
||||||
int frameCount = input.readInt(true);
|
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||||
TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount);
|
TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index);
|
||||||
timeline.transformConstraintIndex = index;
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(),
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(),
|
||||||
input.readFloat());
|
input.readFloat());
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path constraint timelines.
|
// Path constraint timelines.
|
||||||
@ -706,37 +700,38 @@ public class SkeletonBinary {
|
|||||||
PathConstraintData data = skeletonData.pathConstraints.get(index);
|
PathConstraintData data = skeletonData.pathConstraints.get(index);
|
||||||
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
|
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
|
||||||
int timelineType = input.readByte();
|
int timelineType = input.readByte();
|
||||||
int frameCount = input.readInt(true);
|
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||||
switch (timelineType) {
|
switch (timelineType) {
|
||||||
case PATH_POSITION:
|
case PATH_POSITION: {
|
||||||
case PATH_SPACING: {
|
PathConstraintSpacingTimeline timeline = new PathConstraintSpacingTimeline(frameCount, input.readInt(true),
|
||||||
PathConstraintPositionTimeline timeline;
|
index);
|
||||||
float timelineScale = 1;
|
float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale
|
||||||
if (timelineType == PATH_SPACING) {
|
: 1;
|
||||||
timeline = new PathConstraintSpacingTimeline(frameCount);
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale;
|
|
||||||
} else {
|
|
||||||
timeline = new PathConstraintPositionTimeline(frameCount);
|
|
||||||
if (data.positionMode == PositionMode.fixed) timelineScale = scale;
|
|
||||||
}
|
|
||||||
timeline.pathConstraintIndex = index;
|
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale);
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale);
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PATH_SPACING: {
|
||||||
|
PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(frameCount, input.readInt(true),
|
||||||
|
index);
|
||||||
|
float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1;
|
||||||
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale);
|
||||||
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PATH_MIX: {
|
case PATH_MIX: {
|
||||||
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount);
|
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount, input.readInt(true), index);
|
||||||
timeline.pathConstraintIndex = index;
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
|
||||||
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
|
timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -754,12 +749,10 @@ public class SkeletonBinary {
|
|||||||
float[] vertices = attachment.getVertices();
|
float[] vertices = attachment.getVertices();
|
||||||
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
||||||
|
|
||||||
int frameCount = input.readInt(true);
|
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||||
DeformTimeline timeline = new DeformTimeline(frameCount);
|
DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, attachment);
|
||||||
timeline.slotIndex = slotIndex;
|
|
||||||
timeline.attachment = attachment;
|
|
||||||
|
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
for (int frameIndex = 0, bezierIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||||
float time = input.readFloat();
|
float time = input.readFloat();
|
||||||
float[] deform;
|
float[] deform;
|
||||||
int end = input.readInt(true);
|
int end = input.readInt(true);
|
||||||
@ -783,10 +776,9 @@ public class SkeletonBinary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeline.setFrame(frameIndex, time, deform);
|
timeline.setFrame(frameIndex, time, deform);
|
||||||
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline);
|
if (frameIndex < frameLast) bezierIndex = readCurve(input, timeline, frameIndex, bezierIndex);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[frameCount - 1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -821,7 +813,6 @@ public class SkeletonBinary {
|
|||||||
timeline.setFrame(i, time, drawOrder);
|
timeline.setFrame(i, time, drawOrder);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[drawOrderCount - 1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event timeline.
|
// Event timeline.
|
||||||
@ -842,29 +833,43 @@ public class SkeletonBinary {
|
|||||||
timeline.setFrame(i, event);
|
timeline.setFrame(i, event);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[eventCount - 1]);
|
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new SerializationException("Error reading skeleton file.", ex);
|
throw new SerializationException("Error reading skeleton file.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
timelines.shrink();
|
timelines.shrink();
|
||||||
|
float duration = 0;
|
||||||
|
for (int i = 0, n = timelines.size; i < n; i++)
|
||||||
|
duration = Math.max(duration, timelines.get(i).getDuration());
|
||||||
return new Animation(name, timelines, duration);
|
return new Animation(name, timelines, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readCurve (SkeletonInput input, int frameIndex, CurveTimeline timeline) throws IOException {
|
int readCurve (SkeletonInput input, PercentCurveTimeline timeline, int frameIndex, int bezierIndex) throws IOException {
|
||||||
switch (input.readByte()) {
|
switch (input.readByte()) {
|
||||||
case CURVE_STEPPED:
|
case CURVE_STEPPED:
|
||||||
timeline.setStepped(frameIndex);
|
timeline.setStepped(frameIndex);
|
||||||
break;
|
break;
|
||||||
case CURVE_BEZIER:
|
case CURVE_BEZIER:
|
||||||
setCurve(timeline, frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat());
|
timeline.setBezier(frameIndex, bezierIndex++, input.readFloat(), input.readFloat(), input.readFloat(),
|
||||||
|
input.readFloat());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return bezierIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCurve (CurveTimeline timeline, int frameIndex, float cx1, float cy1, float cx2, float cy2) {
|
int readCurve (SkeletonInput input, ValueCurveTimeline timeline, int frameIndex, int bezierIndex, float value1, float value2)
|
||||||
timeline.setCurve(frameIndex, cx1, cy1, cx2, cy2);
|
throws IOException {
|
||||||
|
switch (input.readByte()) {
|
||||||
|
case CURVE_STEPPED:
|
||||||
|
timeline.setStepped(frameIndex);
|
||||||
|
break;
|
||||||
|
case CURVE_BEZIER:
|
||||||
|
timeline.setBezier(frameIndex, bezierIndex++, value1, input.readFloat(), input.readFloat(), input.readFloat(),
|
||||||
|
input.readFloat(), value2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return bezierIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Vertices {
|
static class Vertices {
|
||||||
|
|||||||
@ -55,6 +55,10 @@ public class SkeletonData {
|
|||||||
|
|
||||||
// --- Bones.
|
// --- Bones.
|
||||||
|
|
||||||
|
public SkeletonData () {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
/** The skeleton's bones, sorted parent first. The root bone is always the first bone. */
|
/** The skeleton's bones, sorted parent first. The root bone is always the first bone. */
|
||||||
public Array<BoneData> getBones () {
|
public Array<BoneData> getBones () {
|
||||||
return bones;
|
return bones;
|
||||||
|
|||||||
@ -43,7 +43,6 @@ import com.badlogic.gdx.utils.SerializationException;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ColorTimeline;
|
import com.esotericsoftware.spine.Animation.ColorTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.CurveTimeline;
|
|
||||||
import com.esotericsoftware.spine.Animation.DeformTimeline;
|
import com.esotericsoftware.spine.Animation.DeformTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.EventTimeline;
|
import com.esotericsoftware.spine.Animation.EventTimeline;
|
||||||
@ -51,6 +50,7 @@ import com.esotericsoftware.spine.Animation.IkConstraintTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
|
import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
|
import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
|
import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.PercentCurveTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
||||||
@ -58,6 +58,7 @@ import com.esotericsoftware.spine.Animation.Timeline;
|
|||||||
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
|
import com.esotericsoftware.spine.Animation.TransformConstraintTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.TwoColorTimeline;
|
import com.esotericsoftware.spine.Animation.TwoColorTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.ValueCurveTimeline;
|
||||||
import com.esotericsoftware.spine.BoneData.TransformMode;
|
import com.esotericsoftware.spine.BoneData.TransformMode;
|
||||||
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
|
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
|
||||||
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
|
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
|
||||||
@ -500,7 +501,6 @@ public class SkeletonJson {
|
|||||||
private void readAnimation (JsonValue map, String name, SkeletonData skeletonData) {
|
private void readAnimation (JsonValue map, String name, SkeletonData skeletonData) {
|
||||||
float scale = this.scale;
|
float scale = this.scale;
|
||||||
Array<Timeline> timelines = new Array();
|
Array<Timeline> timelines = new Array();
|
||||||
float duration = 0;
|
|
||||||
|
|
||||||
// Slot timelines.
|
// Slot timelines.
|
||||||
for (JsonValue slotMap = map.getChild("slots"); slotMap != null; slotMap = slotMap.next) {
|
for (JsonValue slotMap = map.getChild("slots"); slotMap != null; slotMap = slotMap.next) {
|
||||||
@ -508,45 +508,34 @@ public class SkeletonJson {
|
|||||||
if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name);
|
if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name);
|
||||||
for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
||||||
String timelineName = timelineMap.name;
|
String timelineName = timelineMap.name;
|
||||||
if (timelineName.equals("attachment")) {
|
int frameIndex = 0, bezierIndex = 0;
|
||||||
AttachmentTimeline timeline = new AttachmentTimeline(timelineMap.size);
|
|
||||||
timeline.slotIndex = slot.index;
|
|
||||||
|
|
||||||
int frameIndex = 0;
|
if (timelineName.equals("attachment")) {
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next)
|
AttachmentTimeline timeline = new AttachmentTimeline(timelineMap.size, slot.index);
|
||||||
timeline.setFrame(frameIndex++, valueMap.getFloat("time", 0), valueMap.getString("name"));
|
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++)
|
||||||
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getString("name"));
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]);
|
|
||||||
|
|
||||||
} else if (timelineName.equals("color")) {
|
} else if (timelineName.equals("color")) {
|
||||||
ColorTimeline timeline = new ColorTimeline(timelineMap.size);
|
ColorTimeline timeline = new ColorTimeline(timelineMap.size, 0, slot.index);
|
||||||
timeline.slotIndex = slot.index;
|
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
|
|
||||||
int frameIndex = 0;
|
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
|
||||||
Color color = Color.valueOf(valueMap.getString("color"));
|
Color color = Color.valueOf(valueMap.getString("color"));
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), color.r, color.g, color.b, color.a);
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), color.r, color.g, color.b, color.a);
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * ColorTimeline.ENTRIES]);
|
|
||||||
|
|
||||||
} else if (timelineName.equals("twoColor")) {
|
} else if (timelineName.equals("twoColor")) {
|
||||||
TwoColorTimeline timeline = new TwoColorTimeline(timelineMap.size);
|
TwoColorTimeline timeline = new TwoColorTimeline(timelineMap.size, 0, slot.index);
|
||||||
timeline.slotIndex = slot.index;
|
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
|
Color light = Color.valueOf(valueMap.getString("light")), dark = Color.valueOf(valueMap.getString("dark"));
|
||||||
int frameIndex = 0;
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), light.r, light.g, light.b, light.a, //
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
dark.r, dark.g, dark.b);
|
||||||
Color light = Color.valueOf(valueMap.getString("light"));
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
Color dark = Color.valueOf(valueMap.getString("dark"));
|
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), light.r, light.g, light.b, light.a, dark.r, dark.g,
|
|
||||||
dark.b);
|
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * TwoColorTimeline.ENTRIES]);
|
|
||||||
|
|
||||||
} else
|
} else
|
||||||
throw new RuntimeException("Invalid timeline type for a slot: " + timelineName + " (" + slotMap.name + ")");
|
throw new RuntimeException("Invalid timeline type for a slot: " + timelineName + " (" + slotMap.name + ")");
|
||||||
@ -558,43 +547,53 @@ public class SkeletonJson {
|
|||||||
BoneData bone = skeletonData.findBone(boneMap.name);
|
BoneData bone = skeletonData.findBone(boneMap.name);
|
||||||
if (bone == null) throw new SerializationException("Bone not found: " + boneMap.name);
|
if (bone == null) throw new SerializationException("Bone not found: " + boneMap.name);
|
||||||
for (JsonValue timelineMap = boneMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
for (JsonValue timelineMap = boneMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
||||||
|
JsonValue valueMap = timelineMap.child;
|
||||||
|
if (valueMap == null) continue;
|
||||||
String timelineName = timelineMap.name;
|
String timelineName = timelineMap.name;
|
||||||
|
int frameIndex = 0, bezierIndex = 0;
|
||||||
|
|
||||||
if (timelineName.equals("rotate")) {
|
if (timelineName.equals("rotate")) {
|
||||||
RotateTimeline timeline = new RotateTimeline(timelineMap.size);
|
RotateTimeline timeline = new RotateTimeline(timelineMap.size, 0, bone.index);
|
||||||
timeline.boneIndex = bone.index;
|
float rotation = valueMap.getFloat("angle", 0);
|
||||||
|
for (;; frameIndex++) {
|
||||||
int frameIndex = 0;
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), rotation);
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
valueMap = valueMap.next;
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("angle", 0));
|
if (valueMap == null) break;
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex, rotation,
|
||||||
frameIndex++;
|
rotation = valueMap.getFloat("angle", 0));
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * RotateTimeline.ENTRIES]);
|
|
||||||
|
|
||||||
} else if (timelineName.equals("translate") || timelineName.equals("scale") || timelineName.equals("shear")) {
|
} else if (timelineName.equals("translate")) {
|
||||||
TranslateTimeline timeline;
|
TranslateTimeline timeline = new TranslateTimeline(timelineMap.size, 0, bone.index);
|
||||||
float timelineScale = 1, defaultValue = 0;
|
for (; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
if (timelineName.equals("scale")) {
|
float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0);
|
||||||
timeline = new ScaleTimeline(timelineMap.size);
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x * scale, y * scale);
|
||||||
defaultValue = 1;
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
} else if (timelineName.equals("shear"))
|
|
||||||
timeline = new ShearTimeline(timelineMap.size);
|
|
||||||
else {
|
|
||||||
timeline = new TranslateTimeline(timelineMap.size);
|
|
||||||
timelineScale = scale;
|
|
||||||
}
|
|
||||||
timeline.boneIndex = bone.index;
|
|
||||||
|
|
||||||
int frameIndex = 0;
|
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
|
||||||
float x = valueMap.getFloat("x", defaultValue), y = valueMap.getFloat("y", defaultValue);
|
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x * timelineScale, y * timelineScale);
|
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
|
timelines.add(timeline);
|
||||||
|
|
||||||
|
} else if (timelineName.equals("scale")) {
|
||||||
|
ScaleTimeline timeline = new ScaleTimeline(timelineMap.size, 0, bone.index);
|
||||||
|
for (; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
|
float x = valueMap.getFloat("x", 1), y = valueMap.getFloat("y", 1);
|
||||||
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x, y);
|
||||||
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
|
timelines.add(timeline);
|
||||||
|
|
||||||
|
} else if (timelineName.equals("shear")) {
|
||||||
|
ShearTimeline timeline = new ShearTimeline(timelineMap.size, 0, bone.index);
|
||||||
|
for (; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
|
float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0);
|
||||||
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), x, y);
|
||||||
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * TranslateTimeline.ENTRIES]);
|
|
||||||
|
|
||||||
} else
|
} else
|
||||||
throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")");
|
throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")");
|
||||||
@ -604,35 +603,32 @@ public class SkeletonJson {
|
|||||||
// IK constraint timelines.
|
// IK constraint timelines.
|
||||||
for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) {
|
for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) {
|
||||||
IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name);
|
IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name);
|
||||||
IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size);
|
IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size, 0,
|
||||||
timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(constraint, true);
|
skeletonData.getIkConstraints().indexOf(constraint, true));
|
||||||
int frameIndex = 0;
|
int frameIndex = 0, bezierIndex = 0;
|
||||||
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) {
|
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("mix", 1),
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("mix", 1),
|
||||||
valueMap.getFloat("softness", 0) * scale, valueMap.getBoolean("bendPositive", true) ? 1 : -1,
|
valueMap.getFloat("softness", 0) * scale, valueMap.getBoolean("bendPositive", true) ? 1 : -1,
|
||||||
valueMap.getBoolean("compress", false), valueMap.getBoolean("stretch", false));
|
valueMap.getBoolean("compress", false), valueMap.getBoolean("stretch", false));
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * IkConstraintTimeline.ENTRIES]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform constraint timelines.
|
// Transform constraint timelines.
|
||||||
for (JsonValue constraintMap = map.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
|
for (JsonValue constraintMap = map.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
|
||||||
TransformConstraintData constraint = skeletonData.findTransformConstraint(constraintMap.name);
|
TransformConstraintData constraint = skeletonData.findTransformConstraint(constraintMap.name);
|
||||||
TransformConstraintTimeline timeline = new TransformConstraintTimeline(constraintMap.size);
|
TransformConstraintTimeline timeline = new TransformConstraintTimeline(constraintMap.size, 0,
|
||||||
timeline.transformConstraintIndex = skeletonData.getTransformConstraints().indexOf(constraint, true);
|
skeletonData.getTransformConstraints().indexOf(constraint, true));
|
||||||
int frameIndex = 0;
|
int frameIndex = 0, bezierIndex = 0;
|
||||||
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) {
|
for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1),
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1),
|
||||||
valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1));
|
valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1));
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration,
|
|
||||||
timeline.getFrames()[(timeline.getFrameCount() - 1) * TransformConstraintTimeline.ENTRIES]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path constraint timelines.
|
// Path constraint timelines.
|
||||||
@ -642,39 +638,37 @@ public class SkeletonJson {
|
|||||||
int index = skeletonData.pathConstraints.indexOf(data, true);
|
int index = skeletonData.pathConstraints.indexOf(data, true);
|
||||||
for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
||||||
String timelineName = timelineMap.name;
|
String timelineName = timelineMap.name;
|
||||||
if (timelineName.equals("position") || timelineName.equals("spacing")) {
|
int frameIndex = 0, bezierIndex = 0;
|
||||||
PathConstraintPositionTimeline timeline;
|
|
||||||
float timelineScale = 1;
|
if (timelineName.equals("position")) {
|
||||||
if (timelineName.equals("spacing")) {
|
PathConstraintPositionTimeline timeline = new PathConstraintPositionTimeline(timelineMap.size, 0, index);
|
||||||
timeline = new PathConstraintSpacingTimeline(timelineMap.size);
|
float timelineScale = data.positionMode == PositionMode.fixed ? scale : 1;
|
||||||
if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale;
|
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
} else {
|
|
||||||
timeline = new PathConstraintPositionTimeline(timelineMap.size);
|
|
||||||
if (data.positionMode == PositionMode.fixed) timelineScale = scale;
|
|
||||||
}
|
|
||||||
timeline.pathConstraintIndex = index;
|
|
||||||
int frameIndex = 0;
|
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat(timelineName, 0) * timelineScale);
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat(timelineName, 0) * timelineScale);
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration,
|
|
||||||
timeline.getFrames()[(timeline.getFrameCount() - 1) * PathConstraintPositionTimeline.ENTRIES]);
|
} else if (timelineName.equals("spacing")) {
|
||||||
|
PathConstraintSpacingTimeline timeline = new PathConstraintSpacingTimeline(timelineMap.size, 0, index);
|
||||||
|
float timelineScale = data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1;
|
||||||
|
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat(timelineName, 0) * timelineScale);
|
||||||
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
|
timelines.add(timeline);
|
||||||
|
|
||||||
} else if (timelineName.equals("mix")) {
|
} else if (timelineName.equals("mix")) {
|
||||||
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size);
|
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size, 0, index);
|
||||||
timeline.pathConstraintIndex = index;
|
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
int frameIndex = 0;
|
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1),
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), valueMap.getFloat("rotateMix", 1),
|
||||||
valueMap.getFloat("translateMix", 1));
|
valueMap.getFloat("translateMix", 1));
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration,
|
|
||||||
timeline.getFrames()[(timeline.getFrameCount() - 1) * PathConstraintMixTimeline.ENTRIES]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -693,12 +687,9 @@ public class SkeletonJson {
|
|||||||
float[] vertices = attachment.getVertices();
|
float[] vertices = attachment.getVertices();
|
||||||
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length;
|
||||||
|
|
||||||
DeformTimeline timeline = new DeformTimeline(timelineMap.size);
|
DeformTimeline timeline = new DeformTimeline(timelineMap.size, 0, slot.index, attachment);
|
||||||
timeline.slotIndex = slot.index;
|
int frameIndex = 0, bezierIndex = 0;
|
||||||
timeline.attachment = attachment;
|
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next, frameIndex++) {
|
||||||
|
|
||||||
int frameIndex = 0;
|
|
||||||
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
|
|
||||||
float[] deform;
|
float[] deform;
|
||||||
JsonValue verticesValue = valueMap.get("vertices");
|
JsonValue verticesValue = valueMap.get("vertices");
|
||||||
if (verticesValue == null)
|
if (verticesValue == null)
|
||||||
@ -718,11 +709,10 @@ public class SkeletonJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), deform);
|
timeline.setFrame(frameIndex, valueMap.getFloat("time", 0), deform);
|
||||||
readCurve(valueMap, timeline, frameIndex);
|
bezierIndex = readCurve(valueMap, timeline, frameIndex, bezierIndex);
|
||||||
frameIndex++;
|
|
||||||
}
|
}
|
||||||
|
timeline.shrink(bezierIndex);
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -734,7 +724,7 @@ public class SkeletonJson {
|
|||||||
DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrdersMap.size);
|
DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrdersMap.size);
|
||||||
int slotCount = skeletonData.slots.size;
|
int slotCount = skeletonData.slots.size;
|
||||||
int frameIndex = 0;
|
int frameIndex = 0;
|
||||||
for (JsonValue drawOrderMap = drawOrdersMap.child; drawOrderMap != null; drawOrderMap = drawOrderMap.next) {
|
for (JsonValue drawOrderMap = drawOrdersMap.child; drawOrderMap != null; drawOrderMap = drawOrderMap.next, frameIndex++) {
|
||||||
int[] drawOrder = null;
|
int[] drawOrder = null;
|
||||||
JsonValue offsets = drawOrderMap.get("offsets");
|
JsonValue offsets = drawOrderMap.get("offsets");
|
||||||
if (offsets != null) {
|
if (offsets != null) {
|
||||||
@ -759,10 +749,9 @@ public class SkeletonJson {
|
|||||||
for (int i = slotCount - 1; i >= 0; i--)
|
for (int i = slotCount - 1; i >= 0; i--)
|
||||||
if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex];
|
if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex];
|
||||||
}
|
}
|
||||||
timeline.setFrame(frameIndex++, drawOrderMap.getFloat("time", 0), drawOrder);
|
timeline.setFrame(frameIndex, drawOrderMap.getFloat("time", 0), drawOrder);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event timeline.
|
// Event timeline.
|
||||||
@ -770,7 +759,7 @@ public class SkeletonJson {
|
|||||||
if (eventsMap != null) {
|
if (eventsMap != null) {
|
||||||
EventTimeline timeline = new EventTimeline(eventsMap.size);
|
EventTimeline timeline = new EventTimeline(eventsMap.size);
|
||||||
int frameIndex = 0;
|
int frameIndex = 0;
|
||||||
for (JsonValue eventMap = eventsMap.child; eventMap != null; eventMap = eventMap.next) {
|
for (JsonValue eventMap = eventsMap.child; eventMap != null; eventMap = eventMap.next, frameIndex++) {
|
||||||
EventData eventData = skeletonData.findEvent(eventMap.getString("name"));
|
EventData eventData = skeletonData.findEvent(eventMap.getString("name"));
|
||||||
if (eventData == null) throw new SerializationException("Event not found: " + eventMap.getString("name"));
|
if (eventData == null) throw new SerializationException("Event not found: " + eventMap.getString("name"));
|
||||||
Event event = new Event(eventMap.getFloat("time", 0), eventData);
|
Event event = new Event(eventMap.getFloat("time", 0), eventData);
|
||||||
@ -781,23 +770,42 @@ public class SkeletonJson {
|
|||||||
event.volume = eventMap.getFloat("volume", eventData.volume);
|
event.volume = eventMap.getFloat("volume", eventData.volume);
|
||||||
event.balance = eventMap.getFloat("balance", eventData.balance);
|
event.balance = eventMap.getFloat("balance", eventData.balance);
|
||||||
}
|
}
|
||||||
timeline.setFrame(frameIndex++, event);
|
timeline.setFrame(frameIndex, event);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
timelines.shrink();
|
timelines.shrink();
|
||||||
|
float duration = 0;
|
||||||
|
for (int i = 0, n = timelines.size; i < n; i++)
|
||||||
|
duration = Math.max(duration, timelines.get(i).getDuration());
|
||||||
skeletonData.animations.add(new Animation(name, timelines, duration));
|
skeletonData.animations.add(new Animation(name, timelines, duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
void readCurve (JsonValue map, CurveTimeline timeline, int frameIndex) {
|
int readCurve (JsonValue map, PercentCurveTimeline timeline, int frameIndex, int bezierIndex) {
|
||||||
JsonValue curve = map.get("curve");
|
JsonValue curve = map.get("curve");
|
||||||
if (curve == null) return;
|
if (curve != null) {
|
||||||
if (curve.isString())
|
if (curve.isString())
|
||||||
timeline.setStepped(frameIndex);
|
timeline.setStepped(frameIndex);
|
||||||
else
|
else {
|
||||||
timeline.setCurve(frameIndex, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1), map.getFloat("c4", 1));
|
timeline.setBezier(frameIndex, bezierIndex++, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1),
|
||||||
|
map.getFloat("c4", 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bezierIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int readCurve (JsonValue map, ValueCurveTimeline timeline, int frameIndex, int bezierIndex, float value1, float value2) {
|
||||||
|
JsonValue curve = map.get("curve");
|
||||||
|
if (curve != null) {
|
||||||
|
if (curve.isString())
|
||||||
|
timeline.setStepped(frameIndex);
|
||||||
|
else {
|
||||||
|
timeline.setBezier(frameIndex, bezierIndex++, value1, curve.asFloat(), map.getFloat("c2", 0), map.getFloat("c3", 1),
|
||||||
|
map.getFloat("c4", 1), value2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bezierIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static class LinkedMesh {
|
static class LinkedMesh {
|
||||||
|
|||||||
@ -42,7 +42,7 @@ import com.esotericsoftware.spine.Slot;
|
|||||||
abstract public class VertexAttachment extends Attachment {
|
abstract public class VertexAttachment extends Attachment {
|
||||||
static private int nextID;
|
static private int nextID;
|
||||||
|
|
||||||
private final int id = (nextID() & 65535) << 11;
|
private final int id = nextID();
|
||||||
int[] bones;
|
int[] bones;
|
||||||
float[] vertices;
|
float[] vertices;
|
||||||
int worldVerticesLength;
|
int worldVerticesLength;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user