mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Merge branch '4.1-beta' of https://github.com/esotericsoftware/spine-runtimes into 4.1-beta
This commit is contained in:
commit
f5c5b09a2e
@ -36,6 +36,7 @@ import com.badlogic.gdx.Files.FileType;
|
|||||||
import com.badlogic.gdx.backends.lwjgl.LwjglFileHandle;
|
import com.badlogic.gdx.backends.lwjgl.LwjglFileHandle;
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.Null;
|
||||||
import com.badlogic.gdx.utils.Pool;
|
import com.badlogic.gdx.utils.Pool;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.AnimationState.AnimationStateListener;
|
import com.esotericsoftware.spine.AnimationState.AnimationStateListener;
|
||||||
@ -47,19 +48,15 @@ import com.esotericsoftware.spine.attachments.MeshAttachment;
|
|||||||
import com.esotericsoftware.spine.attachments.PathAttachment;
|
import com.esotericsoftware.spine.attachments.PathAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.PointAttachment;
|
import com.esotericsoftware.spine.attachments.PointAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
|
|
||||||
public class AnimationStateTests {
|
public class AnimationStateTests {
|
||||||
final SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
final SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
||||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path) {
|
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path) {
|
public MeshAttachment newMeshAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SequenceAttachment newSequenceAttachment (Skin skin, String name, String path, int frameCount) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -893,7 +890,6 @@ public class AnimationStateTests {
|
|||||||
state.apply(skeleton);
|
state.apply(skeleton);
|
||||||
while (time < endTime) {
|
while (time < endTime) {
|
||||||
time += incr;
|
time += incr;
|
||||||
skeleton.update(incr);
|
|
||||||
state.update(incr);
|
state.update(incr);
|
||||||
|
|
||||||
// Reduce float discrepancies for tests.
|
// Reduce float discrepancies for tests.
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
|
import com.badlogic.gdx.utils.Null;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
@ -40,21 +41,17 @@ import com.esotericsoftware.spine.attachments.MeshAttachment;
|
|||||||
import com.esotericsoftware.spine.attachments.PathAttachment;
|
import com.esotericsoftware.spine.attachments.PathAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.PointAttachment;
|
import com.esotericsoftware.spine.attachments.PointAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
|
|
||||||
public class BonePlotting {
|
public class BonePlotting {
|
||||||
static public void main (String[] args) throws Exception {
|
static public void main (String[] args) throws Exception {
|
||||||
// This example shows how to load skeleton data and plot a bone transform for each animation.
|
// This example shows how to load skeleton data and plot a bone transform for each animation.
|
||||||
SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
SkeletonJson json = new SkeletonJson(new AttachmentLoader() {
|
||||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path) {
|
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path) {
|
public MeshAttachment newMeshAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SequenceAttachment newSequenceAttachment (Skin skin, String name, String path, int frameCount) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,12 +49,14 @@ import com.badlogic.gdx.physics.box2d.FixtureDef;
|
|||||||
import com.badlogic.gdx.physics.box2d.PolygonShape;
|
import com.badlogic.gdx.physics.box2d.PolygonShape;
|
||||||
import com.badlogic.gdx.physics.box2d.World;
|
import com.badlogic.gdx.physics.box2d.World;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.Null;
|
||||||
import com.badlogic.gdx.utils.ScreenUtils;
|
import com.badlogic.gdx.utils.ScreenUtils;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
|
|
||||||
public class Box2DExample extends ApplicationAdapter {
|
public class Box2DExample extends ApplicationAdapter {
|
||||||
SpriteBatch batch;
|
SpriteBatch batch;
|
||||||
@ -85,7 +87,7 @@ public class Box2DExample extends ApplicationAdapter {
|
|||||||
// This loader creates Box2dAttachments instead of RegionAttachments for an easy way to keep
|
// This loader creates Box2dAttachments instead of RegionAttachments for an easy way to keep
|
||||||
// track of the Box2D body for each attachment.
|
// track of the Box2D body for each attachment.
|
||||||
AtlasAttachmentLoader atlasLoader = new AtlasAttachmentLoader(atlas) {
|
AtlasAttachmentLoader atlasLoader = new AtlasAttachmentLoader(atlas) {
|
||||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path) {
|
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
Box2dAttachment attachment = new Box2dAttachment(name);
|
Box2dAttachment attachment = new Box2dAttachment(name);
|
||||||
AtlasRegion region = atlas.findRegion(attachment.getName());
|
AtlasRegion region = atlas.findRegion(attachment.getName());
|
||||||
if (region == null) throw new RuntimeException("Region not found in atlas: " + attachment);
|
if (region == null) throw new RuntimeException("Region not found in atlas: " + attachment);
|
||||||
|
|||||||
@ -125,7 +125,6 @@ public class MixTest extends ApplicationAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
skeleton.update(Gdx.graphics.getDeltaTime());
|
|
||||||
|
|
||||||
batch.begin();
|
batch.begin();
|
||||||
renderer.draw(batch, skeleton);
|
renderer.draw(batch, skeleton);
|
||||||
|
|||||||
@ -134,7 +134,6 @@ public class NormalMapTest extends ApplicationAdapter {
|
|||||||
time += Gdx.graphics.getDeltaTime();
|
time += Gdx.graphics.getDeltaTime();
|
||||||
if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, MixBlend.first, MixDirection.in);
|
if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, MixBlend.first, MixDirection.in);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
skeleton.update(Gdx.graphics.getDeltaTime());
|
|
||||||
|
|
||||||
lightPosition.x = Gdx.input.getX();
|
lightPosition.x = Gdx.input.getX();
|
||||||
lightPosition.y = (Gdx.graphics.getHeight() - 1 - Gdx.input.getY());
|
lightPosition.y = (Gdx.graphics.getHeight() - 1 - Gdx.input.getY());
|
||||||
|
|||||||
@ -85,7 +85,6 @@ public class VertexEffectTest extends ApplicationAdapter {
|
|||||||
public void render () {
|
public void render () {
|
||||||
// Update the skeleton and animation time.
|
// Update the skeleton and animation time.
|
||||||
float delta = Gdx.graphics.getDeltaTime();
|
float delta = Gdx.graphics.getDeltaTime();
|
||||||
skeleton.update(delta);
|
|
||||||
state.update(delta);
|
state.update(delta);
|
||||||
|
|
||||||
swirlTime += delta;
|
swirlTime += delta;
|
||||||
|
|||||||
@ -40,6 +40,9 @@ import com.badlogic.gdx.utils.Null;
|
|||||||
import com.badlogic.gdx.utils.ObjectSet;
|
import com.badlogic.gdx.utils.ObjectSet;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.HasTextureRegion;
|
||||||
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
|
import com.esotericsoftware.spine.attachments.Sequence.SequenceMode;
|
||||||
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
||||||
|
|
||||||
/** Stores a list of timelines to animate a skeleton's pose over time. */
|
/** Stores a list of timelines to animate a skeleton's pose over time. */
|
||||||
@ -175,7 +178,8 @@ public class Animation {
|
|||||||
attachment, deform, //
|
attachment, deform, //
|
||||||
event, drawOrder, //
|
event, drawOrder, //
|
||||||
ikConstraint, transformConstraint, //
|
ikConstraint, transformConstraint, //
|
||||||
pathConstraintPosition, pathConstraintSpacing, pathConstraintMix
|
pathConstraintPosition, pathConstraintSpacing, pathConstraintMix, //
|
||||||
|
sequence
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The base class for all timelines. */
|
/** The base class for all timelines. */
|
||||||
@ -1646,7 +1650,7 @@ public class Animation {
|
|||||||
|
|
||||||
/** The attachment that will be deformed.
|
/** The attachment that will be deformed.
|
||||||
* <p>
|
* <p>
|
||||||
* See {@link VertexAttachment#getDeformAttachment()}. */
|
* See {@link VertexAttachment#getTimelineAttachment()}. */
|
||||||
public VertexAttachment getAttachment () {
|
public VertexAttachment getAttachment () {
|
||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
@ -1724,9 +1728,9 @@ public class Animation {
|
|||||||
if (!slot.bone.active) return;
|
if (!slot.bone.active) return;
|
||||||
Attachment slotAttachment = slot.attachment;
|
Attachment slotAttachment = slot.attachment;
|
||||||
if (!(slotAttachment instanceof VertexAttachment)
|
if (!(slotAttachment instanceof VertexAttachment)
|
||||||
|| ((VertexAttachment)slotAttachment).getDeformAttachment() != attachment) return;
|
|| ((VertexAttachment)slotAttachment).getTimelineAttachment() != attachment) return;
|
||||||
|
|
||||||
FloatArray deformArray = slot.getDeform();
|
FloatArray deformArray = slot.deform;
|
||||||
if (deformArray.size == 0) blend = setup;
|
if (deformArray.size == 0) blend = setup;
|
||||||
|
|
||||||
float[][] vertices = this.vertices;
|
float[][] vertices = this.vertices;
|
||||||
@ -1734,7 +1738,6 @@ public class Animation {
|
|||||||
|
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
|
||||||
switch (blend) {
|
switch (blend) {
|
||||||
case setup:
|
case setup:
|
||||||
deformArray.clear();
|
deformArray.clear();
|
||||||
@ -1745,6 +1748,7 @@ public class Animation {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float[] deform = deformArray.setSize(vertexCount);
|
float[] deform = deformArray.setSize(vertexCount);
|
||||||
|
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
||||||
if (vertexAttachment.getBones() == null) {
|
if (vertexAttachment.getBones() == null) {
|
||||||
// Unweighted vertex positions.
|
// Unweighted vertex positions.
|
||||||
float[] setupVertices = vertexAttachment.getVertices();
|
float[] setupVertices = vertexAttachment.getVertices();
|
||||||
@ -2419,4 +2423,90 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Changes a slot's {@link Slot#getSequenceIndex()} for an attachment's {@link Sequence}. */
|
||||||
|
static public class SequenceTimeline extends Timeline implements SlotTimeline {
|
||||||
|
static public final int ENTRIES = 3;
|
||||||
|
static private final int MODE = 1, DELAY = 2;
|
||||||
|
|
||||||
|
final int slotIndex;
|
||||||
|
final HasTextureRegion attachment;
|
||||||
|
|
||||||
|
public <T extends Attachment & HasTextureRegion> SequenceTimeline (int frameCount, int slotIndex, Attachment attachment) {
|
||||||
|
super(frameCount,
|
||||||
|
Property.sequence.ordinal() + "|" + slotIndex + "|" + ((HasTextureRegion)attachment).getSequence().getId());
|
||||||
|
this.slotIndex = slotIndex;
|
||||||
|
this.attachment = (HasTextureRegion)attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFrameEntries () {
|
||||||
|
return ENTRIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSlotIndex () {
|
||||||
|
return slotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Attachment getAttachment () {
|
||||||
|
return (Attachment)attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the time, mode, index, and frame time for the specified frame.
|
||||||
|
* @param frame Between 0 and <code>frameCount</code>, inclusive.
|
||||||
|
* @param time Seconds between frames. */
|
||||||
|
public void setFrame (int frame, float time, SequenceMode mode, int index, float delay) {
|
||||||
|
frame *= ENTRIES;
|
||||||
|
frames[frame] = time;
|
||||||
|
frames[frame + MODE] = mode.ordinal() | (index << 4);
|
||||||
|
frames[frame + DELAY] = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
|
||||||
|
MixDirection direction) {
|
||||||
|
|
||||||
|
Slot slot = skeleton.slots.get(slotIndex);
|
||||||
|
if (!slot.bone.active) return;
|
||||||
|
Attachment slotAttachment = slot.attachment;
|
||||||
|
if (slotAttachment != attachment) {
|
||||||
|
if (!(slotAttachment instanceof VertexAttachment)
|
||||||
|
|| ((VertexAttachment)slotAttachment).getTimelineAttachment() != attachment) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] frames = this.frames;
|
||||||
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
|
if (blend == setup || blend == first) slot.setSequenceIndex(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = search(frames, time, ENTRIES);
|
||||||
|
float before = frames[i];
|
||||||
|
int modeAndIndex = (int)frames[i + MODE];
|
||||||
|
float delay = frames[i + DELAY];
|
||||||
|
|
||||||
|
int index = modeAndIndex >> 4, count = attachment.getSequence().getRegions().length;
|
||||||
|
SequenceMode mode = SequenceMode.values[modeAndIndex & 0xf];
|
||||||
|
if (mode != SequenceMode.stop) {
|
||||||
|
index += (time - before) / delay + 0.00001f;
|
||||||
|
switch (mode) {
|
||||||
|
case once:
|
||||||
|
index = Math.min(count - 1, index);
|
||||||
|
break;
|
||||||
|
case loop:
|
||||||
|
index %= count;
|
||||||
|
break;
|
||||||
|
case pingpong:
|
||||||
|
int n = (count << 1) - 2;
|
||||||
|
index %= n;
|
||||||
|
if (index >= count) index = n - index;
|
||||||
|
break;
|
||||||
|
case onceReverse:
|
||||||
|
index = Math.max(count - 1 - index, 0);
|
||||||
|
break;
|
||||||
|
case loopReverse:
|
||||||
|
index = count - 1 - (index % count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slot.setSequenceIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1012,16 +1012,20 @@ public class AnimationState {
|
|||||||
nextAnimationLast = animationLast;
|
nextAnimationLast = animationLast;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Uses {@link #getTrackTime()} to compute the <code>animationTime</code>, which is between {@link #getAnimationStart()}
|
/** Uses {@link #getTrackTime()} to compute the <code>animationTime</code>. When the <code>trackTime</code> is 0, the
|
||||||
* and {@link #getAnimationEnd()}. When the <code>trackTime</code> is 0, the <code>animationTime</code> is equal to the
|
* <code>animationTime</code> is equal to the <code>animationStart</code> time.
|
||||||
* <code>animationStart</code> time. */
|
* <p>
|
||||||
|
* The <code>animationTime</code> is between {@link #getAnimationStart()} and {@link #getAnimationEnd()}, except if this
|
||||||
|
* track entry is non-looping and {@link #getAnimationEnd()} is >= to the animation {@link Animation#duration}, then
|
||||||
|
* <code>animationTime</code> continues to increase past {@link #getAnimationEnd()}. */
|
||||||
public float getAnimationTime () {
|
public float getAnimationTime () {
|
||||||
if (loop) {
|
if (loop) {
|
||||||
float duration = animationEnd - animationStart;
|
float duration = animationEnd - animationStart;
|
||||||
if (duration == 0) return animationStart;
|
if (duration == 0) return animationStart;
|
||||||
return (trackTime % duration) + animationStart;
|
return (trackTime % duration) + animationStart;
|
||||||
}
|
}
|
||||||
return Math.min(trackTime + animationStart, animationEnd);
|
float animationTime = trackTime + animationStart;
|
||||||
|
return animationEnd >= animation.duration ? animationTime : Math.min(animationTime, animationEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or
|
/** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or
|
||||||
|
|||||||
@ -42,7 +42,6 @@ import com.esotericsoftware.spine.attachments.Attachment;
|
|||||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.PathAttachment;
|
import com.esotericsoftware.spine.attachments.PathAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
|
||||||
|
|
||||||
/** Stores the current pose for a skeleton.
|
/** Stores the current pose for a skeleton.
|
||||||
* <p>
|
* <p>
|
||||||
@ -60,7 +59,6 @@ public class Skeleton {
|
|||||||
final Array<Updatable> updateCache = new Array();
|
final Array<Updatable> updateCache = new Array();
|
||||||
@Null Skin skin;
|
@Null Skin skin;
|
||||||
final Color color;
|
final Color color;
|
||||||
float time;
|
|
||||||
float scaleX = 1, scaleY = 1;
|
float scaleX = 1, scaleY = 1;
|
||||||
float x, y;
|
float x, y;
|
||||||
|
|
||||||
@ -158,7 +156,6 @@ public class Skeleton {
|
|||||||
|
|
||||||
skin = skeleton.skin;
|
skin = skeleton.skin;
|
||||||
color = new Color(skeleton.color);
|
color = new Color(skeleton.color);
|
||||||
time = skeleton.time;
|
|
||||||
scaleX = skeleton.scaleX;
|
scaleX = skeleton.scaleX;
|
||||||
scaleY = skeleton.scaleY;
|
scaleY = skeleton.scaleY;
|
||||||
|
|
||||||
@ -722,11 +719,11 @@ public class Skeleton {
|
|||||||
int verticesLength = 0;
|
int verticesLength = 0;
|
||||||
float[] vertices = null;
|
float[] vertices = null;
|
||||||
Attachment attachment = slot.attachment;
|
Attachment attachment = slot.attachment;
|
||||||
if (attachment instanceof SequenceAttachment) attachment = ((SequenceAttachment)attachment).updateAttachment(slot);
|
|
||||||
if (attachment instanceof RegionAttachment) {
|
if (attachment instanceof RegionAttachment) {
|
||||||
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
verticesLength = 8;
|
verticesLength = 8;
|
||||||
vertices = temp.setSize(8);
|
vertices = temp.setSize(8);
|
||||||
((RegionAttachment)attachment).computeWorldVertices(slot.getBone(), vertices, 0, 2);
|
region.computeWorldVertices(slot, vertices, 0, 2);
|
||||||
} else if (attachment instanceof MeshAttachment) {
|
} else if (attachment instanceof MeshAttachment) {
|
||||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||||
verticesLength = mesh.getWorldVerticesLength();
|
verticesLength = mesh.getWorldVerticesLength();
|
||||||
@ -812,22 +809,6 @@ public class Skeleton {
|
|||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the skeleton's time. This can be used for tracking, such as with Slot {@link Slot#getAttachmentTime()}.
|
|
||||||
* <p>
|
|
||||||
* See {@link #update(float)}. */
|
|
||||||
public float getTime () {
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTime (float time) {
|
|
||||||
this.time = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Increments the skeleton's {@link #time}. */
|
|
||||||
public void update (float delta) {
|
|
||||||
time += delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString () {
|
public String toString () {
|
||||||
return data.name != null ? data.name : super.toString();
|
return data.name != null ? data.name : super.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,6 +63,7 @@ import com.esotericsoftware.spine.Animation.RotateTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ScaleXTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleXTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.SequenceTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearXTimeline;
|
import com.esotericsoftware.spine.Animation.ShearXTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearYTimeline;
|
import com.esotericsoftware.spine.Animation.ShearYTimeline;
|
||||||
@ -85,9 +86,8 @@ import com.esotericsoftware.spine.attachments.MeshAttachment;
|
|||||||
import com.esotericsoftware.spine.attachments.PathAttachment;
|
import com.esotericsoftware.spine.attachments.PathAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.PointAttachment;
|
import com.esotericsoftware.spine.attachments.PointAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
import com.esotericsoftware.spine.attachments.SequenceAttachment.SequenceMode;
|
import com.esotericsoftware.spine.attachments.Sequence.SequenceMode;
|
||||||
import com.esotericsoftware.spine.attachments.HasTextureRegion;
|
|
||||||
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
||||||
|
|
||||||
/** Loads skeleton data in the Spine binary format.
|
/** Loads skeleton data in the Spine binary format.
|
||||||
@ -114,6 +114,9 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
static public final int SLOT_RGB2 = 4;
|
static public final int SLOT_RGB2 = 4;
|
||||||
static public final int SLOT_ALPHA = 5;
|
static public final int SLOT_ALPHA = 5;
|
||||||
|
|
||||||
|
static public final int ATTACHMENT_DEFORM = 0;
|
||||||
|
static public final int ATTACHMENT_SEQUENCE = 1;
|
||||||
|
|
||||||
static public final int PATH_POSITION = 0;
|
static public final int PATH_POSITION = 0;
|
||||||
static public final int PATH_SPACING = 1;
|
static public final int PATH_SPACING = 1;
|
||||||
static public final int PATH_MIX = 2;
|
static public final int PATH_MIX = 2;
|
||||||
@ -303,9 +306,9 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin);
|
if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin);
|
||||||
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
||||||
if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent);
|
if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent);
|
||||||
linkedMesh.mesh.setDeformAttachment(linkedMesh.inheritDeform ? (VertexAttachment)parent : linkedMesh.mesh);
|
linkedMesh.mesh.setTimelineAttachment(linkedMesh.inheritTimelines ? (VertexAttachment)parent : linkedMesh.mesh);
|
||||||
linkedMesh.mesh.setParentMesh((MeshAttachment)parent);
|
linkedMesh.mesh.setParentMesh((MeshAttachment)parent);
|
||||||
linkedMesh.mesh.updateRegion();
|
if (linkedMesh.mesh.getSequence() == null) linkedMesh.mesh.updateRegion();
|
||||||
}
|
}
|
||||||
linkedMeshes.clear();
|
linkedMeshes.clear();
|
||||||
|
|
||||||
@ -398,9 +401,10 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
float width = input.readFloat();
|
float width = input.readFloat();
|
||||||
float height = input.readFloat();
|
float height = input.readFloat();
|
||||||
int color = input.readInt();
|
int color = input.readInt();
|
||||||
|
Sequence sequence = readSequence(input);
|
||||||
|
|
||||||
if (path == null) path = name;
|
if (path == null) path = name;
|
||||||
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path);
|
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, sequence);
|
||||||
if (region == null) return null;
|
if (region == null) return null;
|
||||||
region.setPath(path);
|
region.setPath(path);
|
||||||
region.setX(x * scale);
|
region.setX(x * scale);
|
||||||
@ -411,7 +415,8 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
region.setWidth(width * scale);
|
region.setWidth(width * scale);
|
||||||
region.setHeight(height * scale);
|
region.setHeight(height * scale);
|
||||||
Color.rgba8888ToColor(region.getColor(), color);
|
Color.rgba8888ToColor(region.getColor(), color);
|
||||||
region.updateRegion();
|
region.setSequence(sequence);
|
||||||
|
if (sequence == null) region.updateRegion();
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
case boundingbox: {
|
case boundingbox: {
|
||||||
@ -435,6 +440,7 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
short[] triangles = readShortArray(input);
|
short[] triangles = readShortArray(input);
|
||||||
Vertices vertices = readVertices(input, vertexCount);
|
Vertices vertices = readVertices(input, vertexCount);
|
||||||
int hullLength = input.readInt(true);
|
int hullLength = input.readInt(true);
|
||||||
|
Sequence sequence = readSequence(input);
|
||||||
short[] edges = null;
|
short[] edges = null;
|
||||||
float width = 0, height = 0;
|
float width = 0, height = 0;
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
@ -444,7 +450,7 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (path == null) path = name;
|
if (path == null) path = name;
|
||||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||||
if (mesh == null) return null;
|
if (mesh == null) return null;
|
||||||
mesh.setPath(path);
|
mesh.setPath(path);
|
||||||
Color.rgba8888ToColor(mesh.getColor(), color);
|
Color.rgba8888ToColor(mesh.getColor(), color);
|
||||||
@ -453,8 +459,9 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
mesh.setWorldVerticesLength(vertexCount << 1);
|
mesh.setWorldVerticesLength(vertexCount << 1);
|
||||||
mesh.setTriangles(triangles);
|
mesh.setTriangles(triangles);
|
||||||
mesh.setRegionUVs(uvs);
|
mesh.setRegionUVs(uvs);
|
||||||
mesh.updateRegion();
|
if (sequence == null) mesh.updateRegion();
|
||||||
mesh.setHullLength(hullLength << 1);
|
mesh.setHullLength(hullLength << 1);
|
||||||
|
mesh.setSequence(sequence);
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
mesh.setEdges(edges);
|
mesh.setEdges(edges);
|
||||||
mesh.setWidth(width * scale);
|
mesh.setWidth(width * scale);
|
||||||
@ -467,7 +474,8 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
int color = input.readInt();
|
int color = input.readInt();
|
||||||
String skinName = input.readStringRef();
|
String skinName = input.readStringRef();
|
||||||
String parent = input.readStringRef();
|
String parent = input.readStringRef();
|
||||||
boolean inheritDeform = input.readBoolean();
|
boolean inheritTimelines = input.readBoolean();
|
||||||
|
Sequence sequence = readSequence(input);
|
||||||
float width = 0, height = 0;
|
float width = 0, height = 0;
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
width = input.readFloat();
|
width = input.readFloat();
|
||||||
@ -475,15 +483,16 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (path == null) path = name;
|
if (path == null) path = name;
|
||||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||||
if (mesh == null) return null;
|
if (mesh == null) return null;
|
||||||
mesh.setPath(path);
|
mesh.setPath(path);
|
||||||
Color.rgba8888ToColor(mesh.getColor(), color);
|
Color.rgba8888ToColor(mesh.getColor(), color);
|
||||||
|
mesh.setSequence(sequence);
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
mesh.setWidth(width * scale);
|
mesh.setWidth(width * scale);
|
||||||
mesh.setHeight(height * scale);
|
mesh.setHeight(height * scale);
|
||||||
}
|
}
|
||||||
linkedMeshes.add(new LinkedMesh(mesh, skinName, slotIndex, parent, inheritDeform));
|
linkedMeshes.add(new LinkedMesh(mesh, skinName, slotIndex, parent, inheritTimelines));
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
case path: {
|
case path: {
|
||||||
@ -521,7 +530,7 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
if (nonessential) Color.rgba8888ToColor(point.getColor(), color);
|
if (nonessential) Color.rgba8888ToColor(point.getColor(), color);
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
case clipping: {
|
case clipping:
|
||||||
int endSlotIndex = input.readInt(true);
|
int endSlotIndex = input.readInt(true);
|
||||||
int vertexCount = input.readInt(true);
|
int vertexCount = input.readInt(true);
|
||||||
Vertices vertices = readVertices(input, vertexCount);
|
Vertices vertices = readVertices(input, vertexCount);
|
||||||
@ -536,28 +545,18 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
if (nonessential) Color.rgba8888ToColor(clip.getColor(), color);
|
if (nonessential) Color.rgba8888ToColor(clip.getColor(), color);
|
||||||
return clip;
|
return clip;
|
||||||
}
|
}
|
||||||
case sequence:
|
|
||||||
Attachment attachment = readAttachment(input, skeletonData, skin, slotIndex, attachmentName, nonessential);
|
|
||||||
int frameCount = input.readInt(true);
|
|
||||||
float frameTime = input.readFloat();
|
|
||||||
SequenceMode mode = SequenceMode.values[input.readInt(true)];
|
|
||||||
|
|
||||||
if (attachment == null) return null;
|
|
||||||
String path = ((HasTextureRegion)attachment).getPath();
|
|
||||||
|
|
||||||
SequenceAttachment sequence = attachmentLoader.newSequenceAttachment(skin, name, path, frameCount);
|
|
||||||
if (sequence == null) return null;
|
|
||||||
|
|
||||||
sequence.setAttachment(attachment);
|
|
||||||
sequence.setPath(path);
|
|
||||||
sequence.setFrameCount(frameCount);
|
|
||||||
sequence.setFrameTime(frameTime);
|
|
||||||
sequence.setMode(mode);
|
|
||||||
return sequence;
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Sequence readSequence (SkeletonInput input) throws IOException {
|
||||||
|
if (!input.readBoolean()) return null;
|
||||||
|
Sequence sequence = new Sequence(input.readInt(true));
|
||||||
|
sequence.setStart(input.readInt(true));
|
||||||
|
sequence.setDigits(input.readInt(true));
|
||||||
|
sequence.setSetupIndex(input.readInt(true));
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
private Vertices readVertices (SkeletonInput input, int vertexCount) throws IOException {
|
private Vertices readVertices (SkeletonInput input, int vertexCount) throws IOException {
|
||||||
float scale = this.scale;
|
float scale = this.scale;
|
||||||
int verticesLength = vertexCount << 1;
|
int verticesLength = vertexCount << 1;
|
||||||
@ -767,7 +766,6 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
a = a2;
|
a = a2;
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -913,57 +911,73 @@ public class SkeletonBinary extends SkeletonLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deform timelines.
|
// Attachment timelines.
|
||||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||||
Skin skin = skeletonData.skins.get(input.readInt(true));
|
Skin skin = skeletonData.skins.get(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 slotIndex = input.readInt(true);
|
int slotIndex = input.readInt(true);
|
||||||
for (int iii = 0, nnn = input.readInt(true); iii < nnn; iii++) {
|
for (int iii = 0, nnn = input.readInt(true); iii < nnn; iii++) {
|
||||||
String attachmentName = input.readStringRef();
|
String attachmentName = input.readStringRef();
|
||||||
VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, attachmentName);
|
Attachment attachment = skin.getAttachment(slotIndex, attachmentName);
|
||||||
if (attachment == null) throw new SerializationException("Vertex attachment not found: " + attachmentName);
|
if (attachment == null) throw new SerializationException("Timeline attachment not found: " + attachmentName);
|
||||||
boolean weighted = attachment.getBones() != null;
|
|
||||||
float[] vertices = attachment.getVertices();
|
|
||||||
int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
|
|
||||||
|
|
||||||
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
int timelineType = input.readByte(), frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||||
DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, attachment);
|
switch (timelineType) {
|
||||||
|
case ATTACHMENT_DEFORM: {
|
||||||
|
VertexAttachment vertexAttachment = (VertexAttachment)attachment;
|
||||||
|
boolean weighted = vertexAttachment.getBones() != null;
|
||||||
|
float[] vertices = vertexAttachment.getVertices();
|
||||||
|
int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
|
||||||
|
|
||||||
float time = input.readFloat();
|
DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, vertexAttachment);
|
||||||
for (int frame = 0, bezier = 0;; frame++) {
|
|
||||||
float[] deform;
|
float time = input.readFloat();
|
||||||
int end = input.readInt(true);
|
for (int frame = 0, bezier = 0;; frame++) {
|
||||||
if (end == 0)
|
float[] deform;
|
||||||
deform = weighted ? new float[deformLength] : vertices;
|
int end = input.readInt(true);
|
||||||
else {
|
if (end == 0)
|
||||||
deform = new float[deformLength];
|
deform = weighted ? new float[deformLength] : vertices;
|
||||||
int start = input.readInt(true);
|
else {
|
||||||
end += start;
|
deform = new float[deformLength];
|
||||||
if (scale == 1) {
|
int start = input.readInt(true);
|
||||||
for (int v = start; v < end; v++)
|
end += start;
|
||||||
deform[v] = input.readFloat();
|
if (scale == 1) {
|
||||||
} else {
|
for (int v = start; v < end; v++)
|
||||||
for (int v = start; v < end; v++)
|
deform[v] = input.readFloat();
|
||||||
deform[v] = input.readFloat() * scale;
|
} else {
|
||||||
|
for (int v = start; v < end; v++)
|
||||||
|
deform[v] = input.readFloat() * scale;
|
||||||
|
}
|
||||||
|
if (!weighted) {
|
||||||
|
for (int v = 0, vn = deform.length; v < vn; v++)
|
||||||
|
deform[v] += vertices[v];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!weighted) {
|
timeline.setFrame(frame, time, deform);
|
||||||
for (int v = 0, vn = deform.length; v < vn; v++)
|
if (frame == frameLast) break;
|
||||||
deform[v] += vertices[v];
|
float time2 = input.readFloat();
|
||||||
|
switch (input.readByte()) {
|
||||||
|
case CURVE_STEPPED:
|
||||||
|
timeline.setStepped(frame);
|
||||||
|
break;
|
||||||
|
case CURVE_BEZIER:
|
||||||
|
setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1);
|
||||||
}
|
}
|
||||||
|
time = time2;
|
||||||
}
|
}
|
||||||
timeline.setFrame(frame, time, deform);
|
timelines.add(timeline);
|
||||||
if (frame == frameLast) break;
|
break;
|
||||||
float time2 = input.readFloat();
|
}
|
||||||
switch (input.readByte()) {
|
case ATTACHMENT_SEQUENCE:
|
||||||
case CURVE_STEPPED:
|
SequenceTimeline timeline = new SequenceTimeline(frameCount, slotIndex, attachment);
|
||||||
timeline.setStepped(frame);
|
for (int frame = 0; frame < frameCount; frame++) {
|
||||||
break;
|
float time = input.readFloat();
|
||||||
case CURVE_BEZIER:
|
int modeAndIndex = input.readInt();
|
||||||
setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1);
|
timeline.setFrame(frame, time, SequenceMode.values[modeAndIndex & 0xf], modeAndIndex >> 4,
|
||||||
}
|
input.readFloat());
|
||||||
time = time2;
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import com.badlogic.gdx.utils.FloatArray;
|
|||||||
import com.badlogic.gdx.utils.IntArray;
|
import com.badlogic.gdx.utils.IntArray;
|
||||||
import com.badlogic.gdx.utils.JsonReader;
|
import com.badlogic.gdx.utils.JsonReader;
|
||||||
import com.badlogic.gdx.utils.JsonValue;
|
import com.badlogic.gdx.utils.JsonValue;
|
||||||
|
import com.badlogic.gdx.utils.Null;
|
||||||
import com.badlogic.gdx.utils.SerializationException;
|
import com.badlogic.gdx.utils.SerializationException;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.Animation.AlphaTimeline;
|
import com.esotericsoftware.spine.Animation.AlphaTimeline;
|
||||||
@ -63,6 +64,7 @@ import com.esotericsoftware.spine.Animation.RotateTimeline;
|
|||||||
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ScaleXTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleXTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
|
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.SequenceTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearXTimeline;
|
import com.esotericsoftware.spine.Animation.ShearXTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.ShearYTimeline;
|
import com.esotericsoftware.spine.Animation.ShearYTimeline;
|
||||||
@ -84,9 +86,8 @@ import com.esotericsoftware.spine.attachments.MeshAttachment;
|
|||||||
import com.esotericsoftware.spine.attachments.PathAttachment;
|
import com.esotericsoftware.spine.attachments.PathAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.PointAttachment;
|
import com.esotericsoftware.spine.attachments.PointAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
import com.esotericsoftware.spine.attachments.SequenceAttachment.SequenceMode;
|
import com.esotericsoftware.spine.attachments.Sequence.SequenceMode;
|
||||||
import com.esotericsoftware.spine.attachments.HasTextureRegion;
|
|
||||||
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
||||||
|
|
||||||
/** Loads skeleton data in the Spine JSON format.
|
/** Loads skeleton data in the Spine JSON format.
|
||||||
@ -324,9 +325,9 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin);
|
if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin);
|
||||||
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
||||||
if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent);
|
if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent);
|
||||||
linkedMesh.mesh.setDeformAttachment(linkedMesh.inheritDeform ? (VertexAttachment)parent : linkedMesh.mesh);
|
linkedMesh.mesh.setTimelineAttachment(linkedMesh.inheritTimelines ? (VertexAttachment)parent : linkedMesh.mesh);
|
||||||
linkedMesh.mesh.setParentMesh((MeshAttachment)parent);
|
linkedMesh.mesh.setParentMesh((MeshAttachment)parent);
|
||||||
linkedMesh.mesh.updateRegion();
|
if (linkedMesh.mesh.getRegion() != null) linkedMesh.mesh.updateRegion();
|
||||||
}
|
}
|
||||||
linkedMeshes.clear();
|
linkedMeshes.clear();
|
||||||
|
|
||||||
@ -369,7 +370,8 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
switch (AttachmentType.valueOf(map.getString("type", AttachmentType.region.name()))) {
|
switch (AttachmentType.valueOf(map.getString("type", AttachmentType.region.name()))) {
|
||||||
case region: {
|
case region: {
|
||||||
String path = map.getString("path", name);
|
String path = map.getString("path", name);
|
||||||
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path);
|
Sequence sequence = readSequence(map.get("sequence"));
|
||||||
|
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, sequence);
|
||||||
if (region == null) return null;
|
if (region == null) return null;
|
||||||
region.setPath(path);
|
region.setPath(path);
|
||||||
region.setX(map.getFloat("x", 0) * scale);
|
region.setX(map.getFloat("x", 0) * scale);
|
||||||
@ -379,11 +381,12 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
region.setRotation(map.getFloat("rotation", 0));
|
region.setRotation(map.getFloat("rotation", 0));
|
||||||
region.setWidth(map.getFloat("width") * scale);
|
region.setWidth(map.getFloat("width") * scale);
|
||||||
region.setHeight(map.getFloat("height") * scale);
|
region.setHeight(map.getFloat("height") * scale);
|
||||||
|
region.setSequence(sequence);
|
||||||
|
|
||||||
String color = map.getString("color", null);
|
String color = map.getString("color", null);
|
||||||
if (color != null) Color.valueOf(color, region.getColor());
|
if (color != null) Color.valueOf(color, region.getColor());
|
||||||
|
|
||||||
region.updateRegion();
|
if (region.getRegion() != null) region.updateRegion();
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
case boundingbox: {
|
case boundingbox: {
|
||||||
@ -398,7 +401,8 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
case mesh:
|
case mesh:
|
||||||
case linkedmesh: {
|
case linkedmesh: {
|
||||||
String path = map.getString("path", name);
|
String path = map.getString("path", name);
|
||||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
Sequence sequence = readSequence(map.get("sequence"));
|
||||||
|
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||||
if (mesh == null) return null;
|
if (mesh == null) return null;
|
||||||
mesh.setPath(path);
|
mesh.setPath(path);
|
||||||
|
|
||||||
@ -407,11 +411,12 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
|
|
||||||
mesh.setWidth(map.getFloat("width", 0) * scale);
|
mesh.setWidth(map.getFloat("width", 0) * scale);
|
||||||
mesh.setHeight(map.getFloat("height", 0) * scale);
|
mesh.setHeight(map.getFloat("height", 0) * scale);
|
||||||
|
mesh.setSequence(sequence);
|
||||||
|
|
||||||
String parent = map.getString("parent", null);
|
String parent = map.getString("parent", null);
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
linkedMeshes
|
linkedMeshes
|
||||||
.add(new LinkedMesh(mesh, map.getString("skin", null), slotIndex, parent, map.getBoolean("deform", true)));
|
.add(new LinkedMesh(mesh, map.getString("skin", null), slotIndex, parent, map.getBoolean("timelines", true)));
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +424,7 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
readVertices(map, mesh, uvs.length);
|
readVertices(map, mesh, uvs.length);
|
||||||
mesh.setTriangles(map.require("triangles").asShortArray());
|
mesh.setTriangles(map.require("triangles").asShortArray());
|
||||||
mesh.setRegionUVs(uvs);
|
mesh.setRegionUVs(uvs);
|
||||||
mesh.updateRegion();
|
if (mesh.getRegion() != null) mesh.updateRegion();
|
||||||
|
|
||||||
if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt() << 1);
|
if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt() << 1);
|
||||||
if (map.has("edges")) mesh.setEdges(map.require("edges").asShortArray());
|
if (map.has("edges")) mesh.setEdges(map.require("edges").asShortArray());
|
||||||
@ -455,7 +460,7 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
if (color != null) Color.valueOf(color, point.getColor());
|
if (color != null) Color.valueOf(color, point.getColor());
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
case clipping: {
|
case clipping:
|
||||||
ClippingAttachment clip = attachmentLoader.newClippingAttachment(skin, name);
|
ClippingAttachment clip = attachmentLoader.newClippingAttachment(skin, name);
|
||||||
if (clip == null) return null;
|
if (clip == null) return null;
|
||||||
|
|
||||||
@ -472,23 +477,18 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
if (color != null) Color.valueOf(color, clip.getColor());
|
if (color != null) Color.valueOf(color, clip.getColor());
|
||||||
return clip;
|
return clip;
|
||||||
}
|
}
|
||||||
case sequence:
|
|
||||||
Attachment attachment = readAttachment(map.getChild("attachment"), skin, slotIndex, name, skeletonData);
|
|
||||||
if (attachment == null) return null;
|
|
||||||
String path = ((HasTextureRegion)attachment).getPath();
|
|
||||||
int frameCount = map.getInt("count");
|
|
||||||
SequenceAttachment sequence = attachmentLoader.newSequenceAttachment(skin, name, path, frameCount);
|
|
||||||
if (sequence == null) return null;
|
|
||||||
sequence.setAttachment(attachment);
|
|
||||||
sequence.setPath(path);
|
|
||||||
sequence.setFrameCount(frameCount);
|
|
||||||
sequence.setFrameTime(map.getInt("time"));
|
|
||||||
sequence.setMode(SequenceMode.valueOf(map.getString("mode", SequenceMode.forward.name())));
|
|
||||||
return sequence;
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Sequence readSequence (@Null JsonValue map) {
|
||||||
|
if (map == null) return null;
|
||||||
|
Sequence sequence = new Sequence(map.getInt("count"));
|
||||||
|
sequence.setStart(map.getInt("start", 1));
|
||||||
|
sequence.setDigits(map.getInt("digits", 0));
|
||||||
|
sequence.setSetupIndex(map.getInt("setup", 0));
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
private void readVertices (JsonValue map, VertexAttachment attachment, int verticesLength) {
|
private void readVertices (JsonValue map, VertexAttachment attachment, int verticesLength) {
|
||||||
attachment.setWorldVerticesLength(verticesLength);
|
attachment.setWorldVerticesLength(verticesLength);
|
||||||
float[] vertices = map.require("vertices").asFloatArray();
|
float[] vertices = map.require("vertices").asFloatArray();
|
||||||
@ -533,7 +533,7 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
if (timelineName.equals("attachment")) {
|
if (timelineName.equals("attachment")) {
|
||||||
AttachmentTimeline timeline = new AttachmentTimeline(frames, slot.index);
|
AttachmentTimeline timeline = new AttachmentTimeline(frames, slot.index);
|
||||||
for (int frame = 0; keyMap != null; keyMap = keyMap.next, frame++)
|
for (int frame = 0; keyMap != null; keyMap = keyMap.next, frame++)
|
||||||
timeline.setFrame(frame, keyMap.getFloat("time", 0), keyMap.getString("name"));
|
timeline.setFrame(frame, keyMap.getFloat("time", 0), keyMap.getString("name", null));
|
||||||
timelines.add(timeline);
|
timelines.add(timeline);
|
||||||
|
|
||||||
} else if (timelineName.equals("rgba")) {
|
} else if (timelineName.equals("rgba")) {
|
||||||
@ -877,57 +877,72 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deform timelines.
|
// Attachment timelines.
|
||||||
for (JsonValue deformMap = map.getChild("deform"); deformMap != null; deformMap = deformMap.next) {
|
for (JsonValue attachmentsMap = map.getChild("attachments"); attachmentsMap != null; attachmentsMap = attachmentsMap.next) {
|
||||||
Skin skin = skeletonData.findSkin(deformMap.name);
|
Skin skin = skeletonData.findSkin(attachmentsMap.name);
|
||||||
if (skin == null) throw new SerializationException("Skin not found: " + deformMap.name);
|
if (skin == null) throw new SerializationException("Skin not found: " + attachmentsMap.name);
|
||||||
for (JsonValue slotMap = deformMap.child; slotMap != null; slotMap = slotMap.next) {
|
for (JsonValue slotMap = attachmentsMap.child; slotMap != null; slotMap = slotMap.next) {
|
||||||
SlotData slot = skeletonData.findSlot(slotMap.name);
|
SlotData slot = skeletonData.findSlot(slotMap.name);
|
||||||
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 attachmentMap = slotMap.child; attachmentMap != null; attachmentMap = attachmentMap.next) {
|
||||||
JsonValue keyMap = timelineMap.child;
|
Attachment attachment = skin.getAttachment(slot.index, attachmentMap.name);
|
||||||
if (keyMap == null) continue;
|
if (attachment == null) throw new SerializationException("Timeline attachment not found: " + attachmentMap.name);
|
||||||
|
for (JsonValue timelineMap = attachmentMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
||||||
|
JsonValue keyMap = timelineMap.child;
|
||||||
|
int frames = timelineMap.size;
|
||||||
|
String timelineName = timelineMap.name;
|
||||||
|
if (timelineName.equals("deform")) {
|
||||||
|
VertexAttachment vertexAttachment = (VertexAttachment)attachment;
|
||||||
|
boolean weighted = vertexAttachment.getBones() != null;
|
||||||
|
float[] vertices = vertexAttachment.getVertices();
|
||||||
|
int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
|
||||||
|
|
||||||
VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slot.index, timelineMap.name);
|
DeformTimeline timeline = new DeformTimeline(frames, frames, slot.index, vertexAttachment);
|
||||||
if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name);
|
float time = keyMap.getFloat("time", 0);
|
||||||
boolean weighted = attachment.getBones() != null;
|
for (int frame = 0, bezier = 0;; frame++) {
|
||||||
float[] vertices = attachment.getVertices();
|
float[] deform;
|
||||||
int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
|
JsonValue verticesValue = keyMap.get("vertices");
|
||||||
|
if (verticesValue == null)
|
||||||
|
deform = weighted ? new float[deformLength] : vertices;
|
||||||
|
else {
|
||||||
|
deform = new float[deformLength];
|
||||||
|
int start = keyMap.getInt("offset", 0);
|
||||||
|
arraycopy(verticesValue.asFloatArray(), 0, deform, start, verticesValue.size);
|
||||||
|
if (scale != 1) {
|
||||||
|
for (int i = start, n = i + verticesValue.size; i < n; i++)
|
||||||
|
deform[i] *= scale;
|
||||||
|
}
|
||||||
|
if (!weighted) {
|
||||||
|
for (int i = 0; i < deformLength; i++)
|
||||||
|
deform[i] += vertices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DeformTimeline timeline = new DeformTimeline(timelineMap.size, timelineMap.size, slot.index, attachment);
|
timeline.setFrame(frame, time, deform);
|
||||||
float time = keyMap.getFloat("time", 0);
|
JsonValue nextMap = keyMap.next;
|
||||||
for (int frame = 0, bezier = 0;; frame++) {
|
if (nextMap == null) {
|
||||||
float[] deform;
|
timeline.shrink(bezier);
|
||||||
JsonValue verticesValue = keyMap.get("vertices");
|
break;
|
||||||
if (verticesValue == null)
|
}
|
||||||
deform = weighted ? new float[deformLength] : vertices;
|
float time2 = nextMap.getFloat("time", 0);
|
||||||
else {
|
JsonValue curve = keyMap.get("curve");
|
||||||
deform = new float[deformLength];
|
if (curve != null) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1);
|
||||||
int start = keyMap.getInt("offset", 0);
|
time = time2;
|
||||||
arraycopy(verticesValue.asFloatArray(), 0, deform, start, verticesValue.size);
|
keyMap = nextMap;
|
||||||
if (scale != 1) {
|
|
||||||
for (int i = start, n = i + verticesValue.size; i < n; i++)
|
|
||||||
deform[i] *= scale;
|
|
||||||
}
|
}
|
||||||
if (!weighted) {
|
timelines.add(timeline);
|
||||||
for (int i = 0; i < deformLength; i++)
|
} else if (timelineName.equals("sequence")) {
|
||||||
deform[i] += vertices[i];
|
SequenceTimeline timeline = new SequenceTimeline(frames, slot.index, attachment);
|
||||||
|
float lastDelay = 0;
|
||||||
|
for (int frame = 0; keyMap != null; keyMap = keyMap.next, frame++) {
|
||||||
|
float delay = keyMap.getFloat("delay", lastDelay);
|
||||||
|
timeline.setFrame(frame, keyMap.getFloat("time", 0),
|
||||||
|
SequenceMode.valueOf(keyMap.getString("mode", "stop")), keyMap.getInt("index", 0), delay);
|
||||||
|
lastDelay = delay;
|
||||||
}
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeline.setFrame(frame, time, deform);
|
|
||||||
JsonValue nextMap = keyMap.next;
|
|
||||||
if (nextMap == null) {
|
|
||||||
timeline.shrink(bezier);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
float time2 = nextMap.getFloat("time", 0);
|
|
||||||
JsonValue curve = keyMap.get("curve");
|
|
||||||
if (curve != null) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1);
|
|
||||||
time = time2;
|
|
||||||
keyMap = nextMap;
|
|
||||||
}
|
}
|
||||||
timelines.add(timeline);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1068,14 +1083,14 @@ public class SkeletonJson extends SkeletonLoader {
|
|||||||
String parent, skin;
|
String parent, skin;
|
||||||
int slotIndex;
|
int slotIndex;
|
||||||
MeshAttachment mesh;
|
MeshAttachment mesh;
|
||||||
boolean inheritDeform;
|
boolean inheritTimelines;
|
||||||
|
|
||||||
public LinkedMesh (MeshAttachment mesh, String skin, int slotIndex, String parent, boolean inheritDeform) {
|
public LinkedMesh (MeshAttachment mesh, String skin, int slotIndex, String parent, boolean inheritTimelines) {
|
||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
this.skin = skin;
|
this.skin = skin;
|
||||||
this.slotIndex = slotIndex;
|
this.slotIndex = slotIndex;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.inheritDeform = inheritDeform;
|
this.inheritTimelines = inheritTimelines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,7 +98,7 @@ public class SkeletonRenderer {
|
|||||||
Attachment attachment = slot.attachment;
|
Attachment attachment = slot.attachment;
|
||||||
if (attachment instanceof RegionAttachment) {
|
if (attachment instanceof RegionAttachment) {
|
||||||
RegionAttachment region = (RegionAttachment)attachment;
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
region.computeWorldVertices(slot.getBone(), vertices, 0, 5);
|
region.computeWorldVertices(slot, vertices, 0, 5);
|
||||||
Color color = region.getColor(), slotColor = slot.getColor();
|
Color color = region.getColor(), slotColor = slot.getColor();
|
||||||
float alpha = a * slotColor.a * color.a * 255;
|
float alpha = a * slotColor.a * color.a * 255;
|
||||||
float multiplier = pmaColors ? alpha : 255;
|
float multiplier = pmaColors ? alpha : 255;
|
||||||
@ -183,7 +183,7 @@ public class SkeletonRenderer {
|
|||||||
RegionAttachment region = (RegionAttachment)attachment;
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
verticesLength = vertexSize << 2;
|
verticesLength = vertexSize << 2;
|
||||||
vertices = this.vertices.items;
|
vertices = this.vertices.items;
|
||||||
region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize);
|
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
||||||
triangles = quadTriangles;
|
triangles = quadTriangles;
|
||||||
texture = region.getRegion().getTexture();
|
texture = region.getRegion().getTexture();
|
||||||
uvs = region.getUVs();
|
uvs = region.getUVs();
|
||||||
@ -309,7 +309,7 @@ public class SkeletonRenderer {
|
|||||||
RegionAttachment region = (RegionAttachment)attachment;
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
verticesLength = vertexSize << 2;
|
verticesLength = vertexSize << 2;
|
||||||
vertices = this.vertices.items;
|
vertices = this.vertices.items;
|
||||||
region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize);
|
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
||||||
triangles = quadTriangles;
|
triangles = quadTriangles;
|
||||||
texture = region.getRegion().getTexture();
|
texture = region.getRegion().getTexture();
|
||||||
uvs = region.getUVs();
|
uvs = region.getUVs();
|
||||||
|
|||||||
@ -127,7 +127,7 @@ public class SkeletonRendererDebug {
|
|||||||
if (attachment instanceof RegionAttachment) {
|
if (attachment instanceof RegionAttachment) {
|
||||||
RegionAttachment region = (RegionAttachment)attachment;
|
RegionAttachment region = (RegionAttachment)attachment;
|
||||||
float[] vertices = this.vertices.items;
|
float[] vertices = this.vertices.items;
|
||||||
region.computeWorldVertices(slot.getBone(), vertices, 0, 2);
|
region.computeWorldVertices(slot, vertices, 0, 2);
|
||||||
shapes.line(vertices[0], vertices[1], vertices[2], vertices[3]);
|
shapes.line(vertices[0], vertices[1], vertices[2], vertices[3]);
|
||||||
shapes.line(vertices[2], vertices[3], vertices[4], vertices[5]);
|
shapes.line(vertices[2], vertices[3], vertices[4], vertices[5]);
|
||||||
shapes.line(vertices[4], vertices[5], vertices[6], vertices[7]);
|
shapes.line(vertices[4], vertices[5], vertices[6], vertices[7]);
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import com.badlogic.gdx.utils.Null;
|
|||||||
|
|
||||||
import com.esotericsoftware.spine.Animation.DeformTimeline;
|
import com.esotericsoftware.spine.Animation.DeformTimeline;
|
||||||
import com.esotericsoftware.spine.attachments.Attachment;
|
import com.esotericsoftware.spine.attachments.Attachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.Sequence;
|
||||||
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
import com.esotericsoftware.spine.attachments.VertexAttachment;
|
||||||
|
|
||||||
/** Stores a slot's current pose. Slots organize attachments for {@link Skeleton#drawOrder} purposes and provide a place to store
|
/** Stores a slot's current pose. Slots organize attachments for {@link Skeleton#drawOrder} purposes and provide a place to store
|
||||||
@ -46,8 +47,8 @@ public class Slot {
|
|||||||
final Color color = new Color();
|
final Color color = new Color();
|
||||||
@Null final Color darkColor;
|
@Null final Color darkColor;
|
||||||
@Null Attachment attachment;
|
@Null Attachment attachment;
|
||||||
private float attachmentTime;
|
int sequenceIndex;
|
||||||
private FloatArray deform = new FloatArray();
|
FloatArray deform = new FloatArray();
|
||||||
|
|
||||||
int attachmentState;
|
int attachmentState;
|
||||||
|
|
||||||
@ -69,7 +70,7 @@ public class Slot {
|
|||||||
color.set(slot.color);
|
color.set(slot.color);
|
||||||
darkColor = slot.darkColor == null ? null : new Color(slot.darkColor);
|
darkColor = slot.darkColor == null ? null : new Color(slot.darkColor);
|
||||||
attachment = slot.attachment;
|
attachment = slot.attachment;
|
||||||
attachmentTime = slot.attachmentTime;
|
sequenceIndex = slot.sequenceIndex;
|
||||||
deform.addAll(slot.deform);
|
deform.addAll(slot.deform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,27 +106,28 @@ public class Slot {
|
|||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the slot's attachment and, if the attachment changed, resets {@link #attachmentTime} and clears the {@link #deform}.
|
/** Sets the slot's attachment and, if the attachment changed, resets {@link #sequenceIndex} and clears the {@link #deform}.
|
||||||
* The deform is not cleared if the old attachment has the same {@link VertexAttachment#getDeformAttachment()} as the specified
|
* The deform is not cleared if the old attachment has the same {@link VertexAttachment#getTimelineAttachment()} as the
|
||||||
* attachment. */
|
* specified attachment. */
|
||||||
public void setAttachment (@Null Attachment attachment) {
|
public void setAttachment (@Null Attachment attachment) {
|
||||||
if (this.attachment == attachment) return;
|
if (this.attachment == attachment) return;
|
||||||
if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment)
|
if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment)
|
||||||
|| ((VertexAttachment)attachment).getDeformAttachment() != ((VertexAttachment)this.attachment).getDeformAttachment()) {
|
|| ((VertexAttachment)attachment).getTimelineAttachment() != ((VertexAttachment)this.attachment)
|
||||||
|
.getTimelineAttachment()) {
|
||||||
deform.clear();
|
deform.clear();
|
||||||
}
|
}
|
||||||
this.attachment = attachment;
|
this.attachment = attachment;
|
||||||
attachmentTime = bone.skeleton.time;
|
sequenceIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The time that has elapsed since the last time the attachment was set or cleared. Relies on Skeleton
|
/** The index of the texture region to display when the slot's attachment has a {@link Sequence}. -1 represents the
|
||||||
* {@link Skeleton#time}. */
|
* {@link Sequence#getSetupIndex()}. */
|
||||||
public float getAttachmentTime () {
|
public int getSequenceIndex () {
|
||||||
return bone.skeleton.time - attachmentTime;
|
return sequenceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAttachmentTime (float time) {
|
public void setSequenceIndex (int sequenceIndex) {
|
||||||
attachmentTime = bone.skeleton.time - time;
|
this.sequenceIndex = sequenceIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a
|
/** Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a
|
||||||
|
|||||||
@ -31,6 +31,8 @@ package com.esotericsoftware.spine.attachments;
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.utils.Null;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.Skin;
|
import com.esotericsoftware.spine.Skin;
|
||||||
|
|
||||||
@ -47,32 +49,39 @@ public class AtlasAttachmentLoader implements AttachmentLoader {
|
|||||||
this.atlas = atlas;
|
this.atlas = atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path) {
|
private void loadSequence (String name, String basePath, Sequence sequence) {
|
||||||
AtlasRegion region = atlas.findRegion(path);
|
TextureRegion[] regions = sequence.getRegions();
|
||||||
if (region == null) throw new RuntimeException("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
for (int i = 0, n = regions.length; i < n; i++) {
|
||||||
RegionAttachment attachment = new RegionAttachment(name);
|
String path = sequence.getPath(basePath, i);
|
||||||
attachment.setRegion(region);
|
regions[i] = atlas.findRegion(path);
|
||||||
return attachment;
|
if (regions[i] == null) throw new RuntimeException("Region not found in atlas: " + path + " (sequence: " + name + ")");
|
||||||
}
|
|
||||||
|
|
||||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path) {
|
|
||||||
AtlasRegion region = atlas.findRegion(path);
|
|
||||||
if (region == null) throw new RuntimeException("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
|
||||||
MeshAttachment attachment = new MeshAttachment(name);
|
|
||||||
attachment.setRegion(region);
|
|
||||||
return attachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SequenceAttachment newSequenceAttachment (Skin skin, String name, String path, int frameCount) {
|
|
||||||
AtlasRegion[] regions = new AtlasRegion[frameCount];
|
|
||||||
for (int i = 0; i < frameCount; i++) {
|
|
||||||
AtlasRegion region = atlas.findRegion(path + frameCount); // BOZO - Zero pad?
|
|
||||||
if (region == null)
|
|
||||||
throw new RuntimeException("Region not found in atlas: " + path + frameCount + " (sequence: " + name + ")");
|
|
||||||
}
|
}
|
||||||
SequenceAttachment sequence = new SequenceAttachment(name);
|
}
|
||||||
sequence.setRegions(regions);
|
|
||||||
return sequence;
|
public RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
|
RegionAttachment attachment = new RegionAttachment(name);
|
||||||
|
if (sequence != null)
|
||||||
|
loadSequence(name, path, sequence);
|
||||||
|
else {
|
||||||
|
AtlasRegion region = atlas.findRegion(path);
|
||||||
|
if (region == null)
|
||||||
|
throw new RuntimeException("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||||
|
attachment.setRegion(region);
|
||||||
|
}
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MeshAttachment newMeshAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||||
|
MeshAttachment attachment = new MeshAttachment(name);
|
||||||
|
if (sequence != null)
|
||||||
|
loadSequence(name, path, sequence);
|
||||||
|
else {
|
||||||
|
AtlasRegion region = atlas.findRegion(path);
|
||||||
|
if (region == null)
|
||||||
|
throw new RuntimeException("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||||
|
attachment.setRegion(region);
|
||||||
|
}
|
||||||
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) {
|
public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) {
|
||||||
|
|||||||
@ -31,13 +31,18 @@ package com.esotericsoftware.spine.attachments;
|
|||||||
|
|
||||||
/** The base class for all attachments. */
|
/** The base class for all attachments. */
|
||||||
abstract public class Attachment {
|
abstract public class Attachment {
|
||||||
String name;
|
final String name;
|
||||||
|
|
||||||
public Attachment (String name) {
|
public Attachment (String name) {
|
||||||
if (name == null) throw new IllegalArgumentException("name cannot be null.");
|
if (name == null) throw new IllegalArgumentException("name cannot be null.");
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
protected Attachment (Attachment other) {
|
||||||
|
name = other.name;
|
||||||
|
}
|
||||||
|
|
||||||
/** The attachment's name. */
|
/** The attachment's name. */
|
||||||
public String getName () {
|
public String getName () {
|
||||||
return name;
|
return name;
|
||||||
|
|||||||
@ -39,13 +39,10 @@ import com.esotericsoftware.spine.Skin;
|
|||||||
* Runtimes Guide. */
|
* Runtimes Guide. */
|
||||||
public interface AttachmentLoader {
|
public interface AttachmentLoader {
|
||||||
/** @return May be null to not load the attachment. */
|
/** @return May be null to not load the attachment. */
|
||||||
public @Null RegionAttachment newRegionAttachment (Skin skin, String name, String path);
|
public @Null RegionAttachment newRegionAttachment (Skin skin, String name, String path, @Null Sequence sequence);
|
||||||
|
|
||||||
/** @return May be null to not load the attachment. In that case null should also be returned for child meshes. */
|
/** @return May be null to not load the attachment. In that case null should also be returned for child meshes. */
|
||||||
public @Null MeshAttachment newMeshAttachment (Skin skin, String name, String path);
|
public @Null MeshAttachment newMeshAttachment (Skin skin, String name, String path, @Null Sequence sequence);
|
||||||
|
|
||||||
/** @return May be null to not load the attachment. */
|
|
||||||
public @Null SequenceAttachment newSequenceAttachment (Skin skin, String name, String path, int frameCount);
|
|
||||||
|
|
||||||
/** @return May be null to not load the attachment. */
|
/** @return May be null to not load the attachment. */
|
||||||
public @Null BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name);
|
public @Null BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name);
|
||||||
|
|||||||
@ -46,16 +46,19 @@ public class BoundingBoxAttachment extends VertexAttachment {
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
protected BoundingBoxAttachment (BoundingBoxAttachment other) {
|
||||||
|
super(other);
|
||||||
|
color.set(other.color);
|
||||||
|
}
|
||||||
|
|
||||||
/** The color of the bounding box as it was in Spine, or a default color if nonessential data was not exported. Bounding boxes
|
/** The color of the bounding box as it was in Spine, or a default color if nonessential data was not exported. Bounding boxes
|
||||||
* are not usually rendered at runtime. */
|
* are not usually rendered at runtime. */
|
||||||
public Color getColor () {
|
public Color getColor () {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment copy () {
|
public BoundingBoxAttachment copy () {
|
||||||
BoundingBoxAttachment copy = new BoundingBoxAttachment(name);
|
return new BoundingBoxAttachment(name);
|
||||||
copyTo(copy);
|
|
||||||
copy.color.set(color);
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,13 @@ public class ClippingAttachment extends VertexAttachment {
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
protected ClippingAttachment (ClippingAttachment other) {
|
||||||
|
super(other);
|
||||||
|
endSlot = other.endSlot;
|
||||||
|
color.set(other.color);
|
||||||
|
}
|
||||||
|
|
||||||
/** Clipping is performed between the clipping attachment's slot and the end slot. If null clipping is done until the end of
|
/** Clipping is performed between the clipping attachment's slot and the end slot. If null clipping is done until the end of
|
||||||
* the skeleton's rendering. */
|
* the skeleton's rendering. */
|
||||||
public @Null SlotData getEndSlot () {
|
public @Null SlotData getEndSlot () {
|
||||||
@ -61,11 +68,7 @@ public class ClippingAttachment extends VertexAttachment {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment copy () {
|
public ClippingAttachment copy () {
|
||||||
ClippingAttachment copy = new ClippingAttachment(name);
|
return new ClippingAttachment(name);
|
||||||
copyTo(copy);
|
|
||||||
copy.endSlot = endSlot;
|
|
||||||
copy.color.set(color);
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.esotericsoftware.spine.attachments;
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.utils.Null;
|
||||||
|
|
||||||
public interface HasTextureRegion {
|
public interface HasTextureRegion {
|
||||||
/** The name used to find the {@link #getRegion()}. */
|
/** The name used to find the {@link #getRegion()}. */
|
||||||
@ -10,16 +11,20 @@ public interface HasTextureRegion {
|
|||||||
|
|
||||||
public void setPath (String path);
|
public void setPath (String path);
|
||||||
|
|
||||||
/** Sets the region used to draw the attachment. If the region or its properties are changed, {@link #updateRegion()} must be
|
|
||||||
* called. */
|
|
||||||
public void setRegion (TextureRegion region);
|
|
||||||
|
|
||||||
public TextureRegion getRegion ();
|
public TextureRegion getRegion ();
|
||||||
|
|
||||||
/** Updates any values the attachment calculates using the {@link #getRegion()}. Must be called after changing the region or
|
/** Sets the region used to draw the attachment. After setting the region or if the region's properties are changed,
|
||||||
* the region's properties. */
|
* {@link #updateRegion()} must be called. */
|
||||||
|
public void setRegion (TextureRegion region);
|
||||||
|
|
||||||
|
/** Updates any values the attachment calculates using the {@link #getRegion()}. Must be called after setting the
|
||||||
|
* {@link #getRegion()} or if the region's properties are changed. */
|
||||||
public void updateRegion ();
|
public void updateRegion ();
|
||||||
|
|
||||||
/** The color to tint the attachment. */
|
/** The color to tint the attachment. */
|
||||||
public Color getColor ();
|
public Color getColor ();
|
||||||
|
|
||||||
|
public @Null Sequence getSequence ();
|
||||||
|
|
||||||
|
public void setSequence (@Null Sequence sequence);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,8 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
|||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import com.badlogic.gdx.utils.Null;
|
import com.badlogic.gdx.utils.Null;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Slot;
|
||||||
|
|
||||||
/** An attachment that displays a textured mesh. A mesh has hull vertices and internal vertices within the hull. Holes are not
|
/** An attachment that displays a textured mesh. A mesh has hull vertices and internal vertices within the hull. Holes are not
|
||||||
* supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh.
|
* supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh.
|
||||||
* <p>
|
* <p>
|
||||||
@ -48,6 +50,7 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
|||||||
private final Color color = new Color(1, 1, 1, 1);
|
private final Color color = new Color(1, 1, 1, 1);
|
||||||
private int hullLength;
|
private int hullLength;
|
||||||
private @Null MeshAttachment parentMesh;
|
private @Null MeshAttachment parentMesh;
|
||||||
|
private @Null Sequence sequence;
|
||||||
|
|
||||||
// Nonessential.
|
// Nonessential.
|
||||||
private @Null short[] edges;
|
private @Null short[] edges;
|
||||||
@ -57,18 +60,47 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. Use {@link #newLinkedMesh()} if the other mesh is a linked mesh. */
|
||||||
|
protected MeshAttachment (MeshAttachment other) {
|
||||||
|
super(other);
|
||||||
|
|
||||||
|
if (parentMesh != null) throw new IllegalArgumentException("Use newLinkedMesh to copy a linked mesh.");
|
||||||
|
|
||||||
|
region = other.region;
|
||||||
|
path = other.path;
|
||||||
|
color.set(other.color);
|
||||||
|
|
||||||
|
regionUVs = new float[other.regionUVs.length];
|
||||||
|
arraycopy(other.regionUVs, 0, regionUVs, 0, regionUVs.length);
|
||||||
|
|
||||||
|
uvs = new float[other.uvs.length];
|
||||||
|
arraycopy(other.uvs, 0, uvs, 0, uvs.length);
|
||||||
|
|
||||||
|
triangles = new short[other.triangles.length];
|
||||||
|
arraycopy(other.triangles, 0, triangles, 0, triangles.length);
|
||||||
|
|
||||||
|
hullLength = other.hullLength;
|
||||||
|
|
||||||
|
// Nonessential.
|
||||||
|
if (other.edges != null) {
|
||||||
|
edges = new short[other.edges.length];
|
||||||
|
arraycopy(other.edges, 0, edges, 0, edges.length);
|
||||||
|
}
|
||||||
|
width = other.width;
|
||||||
|
height = other.height;
|
||||||
|
}
|
||||||
|
|
||||||
public void setRegion (TextureRegion region) {
|
public void setRegion (TextureRegion region) {
|
||||||
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
||||||
this.region = region;
|
this.region = region;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureRegion getRegion () {
|
public @Null TextureRegion getRegion () {
|
||||||
if (region == null) throw new IllegalStateException("Region has not been set: " + this);
|
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculates {@link #uvs} using {@link #regionUVs} and the {@link #region}. Must be called after changing the region or the
|
/** Calculates {@link #uvs} using the {@link #regionUVs} and {@link #region}. Must be called if the {@link #region},
|
||||||
* region's properties. */
|
* {@link #regionUVs}, or the region's properties are changed. */
|
||||||
public void updateRegion () {
|
public void updateRegion () {
|
||||||
float[] regionUVs = this.regionUVs;
|
float[] regionUVs = this.regionUVs;
|
||||||
if (this.uvs == null || this.uvs.length != regionUVs.length) this.uvs = new float[regionUVs.length];
|
if (this.uvs == null || this.uvs.length != regionUVs.length) this.uvs = new float[regionUVs.length];
|
||||||
@ -131,6 +163,12 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** If the attachment has a {@link #sequence}, the {@link #region} may be changed. */
|
||||||
|
public void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset, int stride) {
|
||||||
|
if (sequence != null) sequence.apply(slot, this);
|
||||||
|
super.computeWorldVertices(slot, start, count, worldVertices, offset, stride);
|
||||||
|
}
|
||||||
|
|
||||||
/** Triplets of vertex indices which describe the mesh's triangulation. */
|
/** Triplets of vertex indices which describe the mesh's triangulation. */
|
||||||
public short[] getTriangles () {
|
public short[] getTriangles () {
|
||||||
return triangles;
|
return triangles;
|
||||||
@ -210,6 +248,14 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
|||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Null Sequence getSequence () {
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSequence (@Null Sequence sequence) {
|
||||||
|
this.sequence = sequence;
|
||||||
|
}
|
||||||
|
|
||||||
/** The parent mesh if this is a linked mesh, else null. A linked mesh shares the {@link #bones}, {@link #vertices},
|
/** The parent mesh if this is a linked mesh, else null. A linked mesh shares the {@link #bones}, {@link #vertices},
|
||||||
* {@link #regionUVs}, {@link #triangles}, {@link #hullLength}, {@link #edges}, {@link #width}, and {@link #height} with the
|
* {@link #regionUVs}, {@link #triangles}, {@link #hullLength}, {@link #edges}, {@link #width}, and {@link #height} with the
|
||||||
* parent mesh, but may have a different {@link #name} or {@link #path} (and therefore a different texture). */
|
* parent mesh, but may have a different {@link #name} or {@link #path} (and therefore a different texture). */
|
||||||
@ -232,42 +278,19 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment copy () {
|
|
||||||
if (parentMesh != null) return newLinkedMesh();
|
|
||||||
|
|
||||||
MeshAttachment copy = new MeshAttachment(name);
|
|
||||||
copy.region = region;
|
|
||||||
copy.path = path;
|
|
||||||
copy.color.set(color);
|
|
||||||
|
|
||||||
copyTo(copy);
|
|
||||||
copy.regionUVs = new float[regionUVs.length];
|
|
||||||
arraycopy(regionUVs, 0, copy.regionUVs, 0, regionUVs.length);
|
|
||||||
copy.uvs = new float[uvs.length];
|
|
||||||
arraycopy(uvs, 0, copy.uvs, 0, uvs.length);
|
|
||||||
copy.triangles = new short[triangles.length];
|
|
||||||
arraycopy(triangles, 0, copy.triangles, 0, triangles.length);
|
|
||||||
copy.hullLength = hullLength;
|
|
||||||
|
|
||||||
// Nonessential.
|
|
||||||
if (edges != null) {
|
|
||||||
copy.edges = new short[edges.length];
|
|
||||||
arraycopy(edges, 0, copy.edges, 0, edges.length);
|
|
||||||
}
|
|
||||||
copy.width = width;
|
|
||||||
copy.height = height;
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a new mesh with the {@link #parentMesh} set to this mesh's parent mesh, if any, else to this mesh. */
|
/** Returns a new mesh with the {@link #parentMesh} set to this mesh's parent mesh, if any, else to this mesh. */
|
||||||
public MeshAttachment newLinkedMesh () {
|
public MeshAttachment newLinkedMesh () {
|
||||||
MeshAttachment mesh = new MeshAttachment(name);
|
MeshAttachment mesh = new MeshAttachment(name);
|
||||||
|
mesh.timelineAttachment = timelineAttachment;
|
||||||
mesh.region = region;
|
mesh.region = region;
|
||||||
mesh.path = path;
|
mesh.path = path;
|
||||||
mesh.color.set(color);
|
mesh.color.set(color);
|
||||||
mesh.deformAttachment = deformAttachment;
|
|
||||||
mesh.setParentMesh(parentMesh != null ? parentMesh : this);
|
mesh.setParentMesh(parentMesh != null ? parentMesh : this);
|
||||||
mesh.updateRegion();
|
if (mesh.getRegion() != null) mesh.updateRegion();
|
||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MeshAttachment copy () {
|
||||||
|
return parentMesh != null ? newLinkedMesh() : new MeshAttachment(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,18 @@ public class PathAttachment extends VertexAttachment {
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
protected PathAttachment (PathAttachment other) {
|
||||||
|
super(other);
|
||||||
|
|
||||||
|
lengths = new float[other.lengths.length];
|
||||||
|
arraycopy(other.lengths, 0, lengths, 0, lengths.length);
|
||||||
|
|
||||||
|
closed = other.closed;
|
||||||
|
constantSpeed = other.constantSpeed;
|
||||||
|
color.set(other.color);
|
||||||
|
}
|
||||||
|
|
||||||
/** If true, the start and end knots are connected. */
|
/** If true, the start and end knots are connected. */
|
||||||
public boolean getClosed () {
|
public boolean getClosed () {
|
||||||
return closed;
|
return closed;
|
||||||
@ -83,14 +95,7 @@ public class PathAttachment extends VertexAttachment {
|
|||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment copy () {
|
public PathAttachment copy () {
|
||||||
PathAttachment copy = new PathAttachment(name);
|
return new PathAttachment(this);
|
||||||
copyTo(copy);
|
|
||||||
copy.lengths = new float[lengths.length];
|
|
||||||
arraycopy(lengths, 0, copy.lengths, 0, lengths.length);
|
|
||||||
copy.closed = closed;
|
|
||||||
copy.constantSpeed = constantSpeed;
|
|
||||||
copy.color.set(color);
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,15 @@ public class PointAttachment extends Attachment {
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
protected PointAttachment (PointAttachment other) {
|
||||||
|
super(other);
|
||||||
|
x = other.x;
|
||||||
|
y = other.y;
|
||||||
|
rotation = other.rotation;
|
||||||
|
color.set(other.color);
|
||||||
|
}
|
||||||
|
|
||||||
public float getX () {
|
public float getX () {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
@ -94,12 +103,7 @@ public class PointAttachment extends Attachment {
|
|||||||
return (float)Math.atan2(y, x) * radDeg;
|
return (float)Math.atan2(y, x) * radDeg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment copy () {
|
public PointAttachment copy () {
|
||||||
PointAttachment copy = new PointAttachment(name);
|
return new PointAttachment(this);
|
||||||
copy.x = x;
|
|
||||||
copy.y = y;
|
|
||||||
copy.rotation = rotation;
|
|
||||||
copy.color.set(color);
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,21 +34,19 @@ import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
|||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.utils.Null;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.Bone;
|
import com.esotericsoftware.spine.Bone;
|
||||||
|
import com.esotericsoftware.spine.Slot;
|
||||||
|
|
||||||
/** An attachment that displays a textured quadrilateral.
|
/** An attachment that displays a textured quadrilateral.
|
||||||
* <p>
|
* <p>
|
||||||
* See <a href="http://esotericsoftware.com/spine-regions">Region attachments</a> in the Spine User Guide. */
|
* See <a href="http://esotericsoftware.com/spine-regions">Region attachments</a> in the Spine User Guide. */
|
||||||
public class RegionAttachment extends Attachment implements HasTextureRegion {
|
public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||||
static public final int BLX = 0;
|
static public final int BLX = 0, BLY = 1;
|
||||||
static public final int BLY = 1;
|
static public final int ULX = 2, ULY = 3;
|
||||||
static public final int ULX = 2;
|
static public final int URX = 4, URY = 5;
|
||||||
static public final int ULY = 3;
|
static public final int BRX = 6, BRY = 7;
|
||||||
static public final int URX = 4;
|
|
||||||
static public final int URY = 5;
|
|
||||||
static public final int BRX = 6;
|
|
||||||
static public final int BRY = 7;
|
|
||||||
|
|
||||||
private TextureRegion region;
|
private TextureRegion region;
|
||||||
private String path;
|
private String path;
|
||||||
@ -56,13 +54,31 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
private final float[] uvs = new float[8];
|
private final float[] uvs = new float[8];
|
||||||
private final float[] offset = new float[8];
|
private final float[] offset = new float[8];
|
||||||
private final Color color = new Color(1, 1, 1, 1);
|
private final Color color = new Color(1, 1, 1, 1);
|
||||||
|
private @Null Sequence sequence;
|
||||||
|
|
||||||
public RegionAttachment (String name) {
|
public RegionAttachment (String name) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculates the {@link #offset} using the {@link #region}. Must be called after changing the region or the region's
|
/** Copy constructor. */
|
||||||
* properties. */
|
protected RegionAttachment (RegionAttachment other) {
|
||||||
|
super(other);
|
||||||
|
region = other.region;
|
||||||
|
path = other.path;
|
||||||
|
x = other.x;
|
||||||
|
y = other.y;
|
||||||
|
scaleX = other.scaleX;
|
||||||
|
scaleY = other.scaleY;
|
||||||
|
rotation = other.rotation;
|
||||||
|
width = other.width;
|
||||||
|
height = other.height;
|
||||||
|
arraycopy(other.uvs, 0, uvs, 0, 8);
|
||||||
|
arraycopy(other.offset, 0, offset, 0, 8);
|
||||||
|
color.set(other.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculates the {@link #offset} and {@link #uvs} using the {@link #region} and the attachment's transform. Must be called if
|
||||||
|
* the {@link #region}, transform, or the region's properties are changed. */
|
||||||
public void updateRegion () {
|
public void updateRegion () {
|
||||||
float width = getWidth();
|
float width = getWidth();
|
||||||
float height = getHeight();
|
float height = getHeight();
|
||||||
@ -70,11 +86,13 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
float localY2 = height / 2;
|
float localY2 = height / 2;
|
||||||
float localX = -localX2;
|
float localX = -localX2;
|
||||||
float localY = -localY2;
|
float localY = -localY2;
|
||||||
|
boolean rotated = false;
|
||||||
if (region instanceof AtlasRegion) {
|
if (region instanceof AtlasRegion) {
|
||||||
AtlasRegion region = (AtlasRegion)this.region;
|
AtlasRegion region = (AtlasRegion)this.region;
|
||||||
localX += region.offsetX / region.originalWidth * width;
|
localX += region.offsetX / region.originalWidth * width;
|
||||||
localY += region.offsetY / region.originalHeight * height;
|
localY += region.offsetY / region.originalHeight * height;
|
||||||
if (region.degrees == 90) {
|
if (region.degrees == 90) {
|
||||||
|
rotated = true;
|
||||||
localX2 -= (region.originalWidth - region.offsetX - region.packedHeight) / region.originalWidth * width;
|
localX2 -= (region.originalWidth - region.offsetX - region.packedHeight) / region.originalWidth * width;
|
||||||
localY2 -= (region.originalHeight - region.offsetY - region.packedWidth) / region.originalHeight * height;
|
localY2 -= (region.originalHeight - region.offsetY - region.packedWidth) / region.originalHeight * height;
|
||||||
} else {
|
} else {
|
||||||
@ -110,13 +128,9 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
offset[URY] = localY2Cos + localX2Sin;
|
offset[URY] = localY2Cos + localX2Sin;
|
||||||
offset[BRX] = localX2Cos - localYSin;
|
offset[BRX] = localX2Cos - localYSin;
|
||||||
offset[BRY] = localYCos + localX2Sin;
|
offset[BRY] = localYCos + localX2Sin;
|
||||||
}
|
|
||||||
|
|
||||||
public void setRegion (TextureRegion region) {
|
|
||||||
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
|
||||||
this.region = region;
|
|
||||||
float[] uvs = this.uvs;
|
float[] uvs = this.uvs;
|
||||||
if (region instanceof AtlasRegion && ((AtlasRegion)region).degrees == 90) {
|
if (rotated) {
|
||||||
uvs[URX] = region.getU();
|
uvs[URX] = region.getU();
|
||||||
uvs[URY] = region.getV2();
|
uvs[URY] = region.getV2();
|
||||||
uvs[BRX] = region.getU();
|
uvs[BRX] = region.getU();
|
||||||
@ -137,20 +151,28 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureRegion getRegion () {
|
public void setRegion (TextureRegion region) {
|
||||||
if (region == null) throw new IllegalStateException("Region has not been set: " + name);
|
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
||||||
|
this.region = region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Null TextureRegion getRegion () {
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transforms the attachment's four vertices to world coordinates.
|
/** Transforms the attachment's four vertices to world coordinates. If the attachment has a {@link #sequence}, the
|
||||||
|
* {@link #region} may be changed.
|
||||||
* <p>
|
* <p>
|
||||||
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
|
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
|
||||||
* Runtimes Guide.
|
* Runtimes Guide.
|
||||||
* @param worldVertices The output world vertices. Must have a length >= <code>offset</code> + 8.
|
* @param worldVertices The output world vertices. Must have a length >= <code>offset</code> + 8.
|
||||||
* @param offset The <code>worldVertices</code> index to begin writing values.
|
* @param offset The <code>worldVertices</code> index to begin writing values.
|
||||||
* @param stride The number of <code>worldVertices</code> entries between the value pairs written. */
|
* @param stride The number of <code>worldVertices</code> entries between the value pairs written. */
|
||||||
public void computeWorldVertices (Bone bone, float[] worldVertices, int offset, int stride) {
|
public void computeWorldVertices (Slot slot, float[] worldVertices, int offset, int stride) {
|
||||||
|
if (sequence != null) sequence.apply(slot, this);
|
||||||
|
|
||||||
float[] vertexOffset = this.offset;
|
float[] vertexOffset = this.offset;
|
||||||
|
Bone bone = slot.getBone();
|
||||||
float x = bone.getWorldX(), y = bone.getWorldY();
|
float x = bone.getWorldX(), y = bone.getWorldY();
|
||||||
float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD();
|
float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD();
|
||||||
float offsetX, offsetY;
|
float offsetX, offsetY;
|
||||||
@ -265,20 +287,15 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment copy () {
|
public @Null Sequence getSequence () {
|
||||||
RegionAttachment copy = new RegionAttachment(name);
|
return sequence;
|
||||||
copy.region = region;
|
}
|
||||||
copy.path = path;
|
|
||||||
copy.x = x;
|
public void setSequence (@Null Sequence sequence) {
|
||||||
copy.y = y;
|
this.sequence = sequence;
|
||||||
copy.scaleX = scaleX;
|
}
|
||||||
copy.scaleY = scaleY;
|
|
||||||
copy.rotation = rotation;
|
public RegionAttachment copy () {
|
||||||
copy.width = width;
|
return new RegionAttachment(this);
|
||||||
copy.height = height;
|
|
||||||
arraycopy(uvs, 0, copy.uvs, 0, 8);
|
|
||||||
arraycopy(offset, 0, copy.offset, 0, 8);
|
|
||||||
copy.color.set(color);
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,122 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated September 24, 2021. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2021, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
package com.esotericsoftware.spine.attachments;
|
||||||
|
|
||||||
|
import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Slot;
|
||||||
|
|
||||||
|
public class Sequence {
|
||||||
|
static private int nextID;
|
||||||
|
|
||||||
|
private final int id = nextID();
|
||||||
|
private final TextureRegion[] regions;
|
||||||
|
private int start, digits, setupIndex;
|
||||||
|
|
||||||
|
public Sequence (int count) {
|
||||||
|
regions = new TextureRegion[count];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
protected Sequence (Sequence other) {
|
||||||
|
regions = new TextureRegion[other.regions.length];
|
||||||
|
arraycopy(other.regions, 0, regions, 0, regions.length);
|
||||||
|
|
||||||
|
start = other.start;
|
||||||
|
digits = other.digits;
|
||||||
|
setupIndex = other.setupIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Attachment & HasTextureRegion> void apply (Slot slot, T attachment) {
|
||||||
|
int index = slot.getSequenceIndex();
|
||||||
|
if (index == -1) index = setupIndex;
|
||||||
|
if (index >= regions.length) index = regions.length - 1;
|
||||||
|
TextureRegion region = regions[index];
|
||||||
|
if (attachment.getRegion() != region) {
|
||||||
|
attachment.setRegion(region);
|
||||||
|
attachment.updateRegion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath (String basePath, int index) {
|
||||||
|
StringBuilder buffer = new StringBuilder(basePath.length() + digits);
|
||||||
|
buffer.append(basePath);
|
||||||
|
buffer.append(start + index);
|
||||||
|
while (buffer.length() < digits)
|
||||||
|
buffer.append('0');
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStart () {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStart (int start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDigits () {
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDigits (int digits) {
|
||||||
|
this.digits = digits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The index of the region to show for the setup pose. */
|
||||||
|
public int getSetupIndex () {
|
||||||
|
return setupIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSetupIndex (int index) {
|
||||||
|
this.setupIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureRegion[] getRegions () {
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a unique ID for this attachment. */
|
||||||
|
public int getId () {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static private synchronized int nextID () {
|
||||||
|
return nextID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public enum SequenceMode {
|
||||||
|
stop, once, loop, pingpong, onceReverse, loopReverse, pingpongReverse;
|
||||||
|
|
||||||
|
static public final SequenceMode[] values = values();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,151 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Spine Runtimes License Agreement
|
|
||||||
* Last updated September 24, 2021. Replaces all prior versions.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013-2021, Esoteric Software LLC
|
|
||||||
*
|
|
||||||
* Integration of the Spine Runtimes into software or otherwise creating
|
|
||||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
|
||||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
|
||||||
* http://esotericsoftware.com/spine-editor-license
|
|
||||||
*
|
|
||||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
|
||||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
|
||||||
* "Products"), provided that each user of the Products must obtain their own
|
|
||||||
* Spine Editor license and redistribution of the Products in any form must
|
|
||||||
* include this license and copyright notice.
|
|
||||||
*
|
|
||||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
|
||||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
|
||||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
|
||||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
||||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
package com.esotericsoftware.spine.attachments;
|
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
|
||||||
|
|
||||||
import com.esotericsoftware.spine.Slot;
|
|
||||||
|
|
||||||
/** An attachment that applies a sequence of texture atlas regions to a region or mesh attachment.
|
|
||||||
* <p>
|
|
||||||
* See <a href="http://esotericsoftware.com/spine-sequences">Sequence attachments</a> in the Spine User Guide. */
|
|
||||||
public class SequenceAttachment<T extends Attachment & HasTextureRegion> extends Attachment {
|
|
||||||
private T attachment;
|
|
||||||
private String path;
|
|
||||||
private int frameCount;
|
|
||||||
private float frameTime;
|
|
||||||
private SequenceMode mode;
|
|
||||||
private TextureRegion[] regions;
|
|
||||||
|
|
||||||
public SequenceAttachment (String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Updates the {@link #attachment} with the {@link #regions region} for the slot's {@link Slot#getAttachmentTime()} and
|
|
||||||
* returns it. */
|
|
||||||
public T updateAttachment (Slot slot) {
|
|
||||||
int index = (int)(slot.getAttachmentTime() / frameTime);
|
|
||||||
switch (mode) {
|
|
||||||
case forward:
|
|
||||||
index = Math.min(frameCount - 1, index);
|
|
||||||
break;
|
|
||||||
case backward:
|
|
||||||
index = Math.max(frameCount - index - 1, 0);
|
|
||||||
break;
|
|
||||||
case forwardLoop:
|
|
||||||
index = index % frameCount;
|
|
||||||
break;
|
|
||||||
case backwardLoop:
|
|
||||||
index = frameCount - (index % frameCount) - 1;
|
|
||||||
break;
|
|
||||||
case pingPong:
|
|
||||||
index = index % (frameCount << 1);
|
|
||||||
if (index >= frameCount) index = frameCount - 1 - (index - frameCount);
|
|
||||||
break;
|
|
||||||
case random:
|
|
||||||
index = MathUtils.random(frameCount - 1);
|
|
||||||
}
|
|
||||||
attachment.setRegion(regions[index]);
|
|
||||||
attachment.updateRegion();
|
|
||||||
return attachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttachment (T attachment) {
|
|
||||||
this.attachment = attachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getAttachment () {
|
|
||||||
return attachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The prefix used to find the {@link #regions} for this attachment. */
|
|
||||||
public String getPath () {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPath (String path) {
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SequenceMode getMode () {
|
|
||||||
return mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMode (SequenceMode mode) {
|
|
||||||
if (mode == null) throw new IllegalArgumentException("mode cannot be null.");
|
|
||||||
this.mode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getFrameCount () {
|
|
||||||
return frameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFrameCount (int frameCount) {
|
|
||||||
this.frameCount = frameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The time in seconds each frame is shown. */
|
|
||||||
public float getFrameTime () {
|
|
||||||
return frameTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFrameTime (float frameTime) {
|
|
||||||
this.frameTime = frameTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextureRegion[] getRegions () {
|
|
||||||
if (regions == null) throw new IllegalStateException("Regions have not been set: " + name);
|
|
||||||
return regions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRegions (TextureRegion[] regions) {
|
|
||||||
if (regions == null) throw new IllegalArgumentException("regions cannot be null.");
|
|
||||||
this.regions = regions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Attachment copy () {
|
|
||||||
SequenceAttachment copy = new SequenceAttachment(name);
|
|
||||||
copy.attachment = attachment.copy();
|
|
||||||
copy.path = path;
|
|
||||||
copy.frameCount = frameCount;
|
|
||||||
copy.frameTime = frameTime;
|
|
||||||
copy.frameTime = frameTime;
|
|
||||||
copy.mode = mode;
|
|
||||||
copy.regions = regions;
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
static public enum SequenceMode {
|
|
||||||
forward, backward, forwardLoop, backwardLoop, pingPong, random;
|
|
||||||
|
|
||||||
static public final SequenceMode[] values = values();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -41,8 +41,13 @@ public class SkeletonAttachment extends Attachment {
|
|||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return May return null. */
|
/** Copy constructor. */
|
||||||
public Skeleton getSkeleton () {
|
protected SkeletonAttachment (SkeletonAttachment other) {
|
||||||
|
super(other);
|
||||||
|
skeleton = other.skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Null Skeleton getSkeleton () {
|
||||||
return skeleton;
|
return skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,9 +55,7 @@ public class SkeletonAttachment extends Attachment {
|
|||||||
this.skeleton = skeleton;
|
this.skeleton = skeleton;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment copy () {
|
public SkeletonAttachment copy () {
|
||||||
SkeletonAttachment copy = new SkeletonAttachment(name);
|
return new SkeletonAttachment(this);
|
||||||
copy.skeleton = skeleton;
|
|
||||||
return copy;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,15 +44,35 @@ abstract public class VertexAttachment extends Attachment {
|
|||||||
static private int nextID;
|
static private int nextID;
|
||||||
|
|
||||||
private final int id = nextID();
|
private final int id = nextID();
|
||||||
|
@Null Attachment timelineAttachment = this;
|
||||||
@Null int[] bones;
|
@Null int[] bones;
|
||||||
float[] vertices;
|
float[] vertices;
|
||||||
int worldVerticesLength;
|
int worldVerticesLength;
|
||||||
@Null VertexAttachment deformAttachment = this;
|
|
||||||
|
|
||||||
public VertexAttachment (String name) {
|
public VertexAttachment (String name) {
|
||||||
super(name);
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
public VertexAttachment (VertexAttachment other) {
|
||||||
|
super(other);
|
||||||
|
timelineAttachment = other.timelineAttachment;
|
||||||
|
|
||||||
|
if (other.bones != null) {
|
||||||
|
bones = new int[other.bones.length];
|
||||||
|
arraycopy(other.bones, 0, bones, 0, bones.length);
|
||||||
|
} else
|
||||||
|
bones = null;
|
||||||
|
|
||||||
|
if (other.vertices != null) {
|
||||||
|
vertices = new float[other.vertices.length];
|
||||||
|
arraycopy(other.vertices, 0, vertices, 0, vertices.length);
|
||||||
|
} else
|
||||||
|
vertices = null;
|
||||||
|
|
||||||
|
worldVerticesLength = other.worldVerticesLength;
|
||||||
|
}
|
||||||
|
|
||||||
/** Transforms the attachment's local {@link #getVertices()} to world coordinates. If the slot's {@link Slot#getDeform()} is
|
/** Transforms the attachment's local {@link #getVertices()} to world coordinates. If the slot's {@link Slot#getDeform()} is
|
||||||
* not empty, it is used to deform the vertices.
|
* not empty, it is used to deform the vertices.
|
||||||
* <p>
|
* <p>
|
||||||
@ -120,17 +140,6 @@ abstract public class VertexAttachment extends Attachment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Deform keys for the deform attachment are also applied to this attachment.
|
|
||||||
* @return May be null if no deform keys should be applied. */
|
|
||||||
public @Null VertexAttachment getDeformAttachment () {
|
|
||||||
return deformAttachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param deformAttachment May be null if no deform keys should be applied. */
|
|
||||||
public void setDeformAttachment (@Null VertexAttachment deformAttachment) {
|
|
||||||
this.deformAttachment = deformAttachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The bones which affect the {@link #getVertices()}. The array entries are, for each vertex, the number of bones affecting
|
/** The bones which affect the {@link #getVertices()}. The array entries are, for each vertex, the number of bones affecting
|
||||||
* the vertex followed by that many bone indices, which is the index of the bone in {@link Skeleton#getBones()}. Will be null
|
* the vertex followed by that many bone indices, which is the index of the bone in {@link Skeleton#getBones()}. Will be null
|
||||||
* if this attachment has no weights. */
|
* if this attachment has no weights. */
|
||||||
@ -164,29 +173,22 @@ abstract public class VertexAttachment extends Attachment {
|
|||||||
this.worldVerticesLength = worldVerticesLength;
|
this.worldVerticesLength = worldVerticesLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Timelines for the timeline attachment are also applied to this attachment.
|
||||||
|
* @return May be null if no attachment-specific timelines should be applied. */
|
||||||
|
public @Null Attachment getTimelineAttachment () {
|
||||||
|
return timelineAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param timelineAttachment May be null if no attachment-specific timelines should be applied. */
|
||||||
|
public void setTimelineAttachment (Attachment timelineAttachment) {
|
||||||
|
this.timelineAttachment = timelineAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a unique ID for this attachment. */
|
/** Returns a unique ID for this attachment. */
|
||||||
public int getId () {
|
public int getId () {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Does not copy id (generated) or name (set on construction). */
|
|
||||||
void copyTo (VertexAttachment attachment) {
|
|
||||||
if (bones != null) {
|
|
||||||
attachment.bones = new int[bones.length];
|
|
||||||
arraycopy(bones, 0, attachment.bones, 0, bones.length);
|
|
||||||
} else
|
|
||||||
attachment.bones = null;
|
|
||||||
|
|
||||||
if (vertices != null) {
|
|
||||||
attachment.vertices = new float[vertices.length];
|
|
||||||
arraycopy(vertices, 0, attachment.vertices, 0, vertices.length);
|
|
||||||
} else
|
|
||||||
attachment.vertices = null;
|
|
||||||
|
|
||||||
attachment.worldVerticesLength = worldVerticesLength;
|
|
||||||
attachment.deformAttachment = deformAttachment;
|
|
||||||
}
|
|
||||||
|
|
||||||
static private synchronized int nextID () {
|
static private synchronized int nextID () {
|
||||||
return nextID++;
|
return nextID++;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -258,7 +258,6 @@ public class SkeletonViewer extends ApplicationAdapter {
|
|||||||
skeleton.setSlotsToSetupPose();
|
skeleton.setSlotsToSetupPose();
|
||||||
|
|
||||||
delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue();
|
delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue();
|
||||||
skeleton.update(delta);
|
|
||||||
state.update(delta);
|
state.update(delta);
|
||||||
state.apply(skeleton);
|
state.apply(skeleton);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user