mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 17:26: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.math.MathUtils;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
|
||||
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.PointAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
||||
import com.esotericsoftware.spine.attachments.Sequence;
|
||||
|
||||
public class AnimationStateTests {
|
||||
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;
|
||||
}
|
||||
|
||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public SequenceAttachment newSequenceAttachment (Skin skin, String name, String path, int frameCount) {
|
||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -893,7 +890,6 @@ public class AnimationStateTests {
|
||||
state.apply(skeleton);
|
||||
while (time < endTime) {
|
||||
time += incr;
|
||||
skeleton.update(incr);
|
||||
state.update(incr);
|
||||
|
||||
// Reduce float discrepancies for tests.
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
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.PointAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
||||
import com.esotericsoftware.spine.attachments.Sequence;
|
||||
|
||||
public class BonePlotting {
|
||||
static public void main (String[] args) throws Exception {
|
||||
// This example shows how to load skeleton data and plot a bone transform for each animation.
|
||||
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;
|
||||
}
|
||||
|
||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public SequenceAttachment newSequenceAttachment (Skin skin, String name, String path, int frameCount) {
|
||||
public MeshAttachment newMeshAttachment (Skin skin, String name, String path, @Null Sequence sequence) {
|
||||
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.World;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.Sequence;
|
||||
|
||||
public class Box2DExample extends ApplicationAdapter {
|
||||
SpriteBatch batch;
|
||||
@ -85,7 +87,7 @@ public class Box2DExample extends ApplicationAdapter {
|
||||
// This loader creates Box2dAttachments instead of RegionAttachments for an easy way to keep
|
||||
// track of the Box2D body for each attachment.
|
||||
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);
|
||||
AtlasRegion region = atlas.findRegion(attachment.getName());
|
||||
if (region == null) throw new RuntimeException("Region not found in atlas: " + attachment);
|
||||
|
||||
@ -125,7 +125,6 @@ public class MixTest extends ApplicationAdapter {
|
||||
}
|
||||
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.update(Gdx.graphics.getDeltaTime());
|
||||
|
||||
batch.begin();
|
||||
renderer.draw(batch, skeleton);
|
||||
|
||||
@ -134,7 +134,6 @@ public class NormalMapTest extends ApplicationAdapter {
|
||||
time += Gdx.graphics.getDeltaTime();
|
||||
if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, MixBlend.first, MixDirection.in);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.update(Gdx.graphics.getDeltaTime());
|
||||
|
||||
lightPosition.x = Gdx.input.getX();
|
||||
lightPosition.y = (Gdx.graphics.getHeight() - 1 - Gdx.input.getY());
|
||||
|
||||
@ -85,7 +85,6 @@ public class VertexEffectTest extends ApplicationAdapter {
|
||||
public void render () {
|
||||
// Update the skeleton and animation time.
|
||||
float delta = Gdx.graphics.getDeltaTime();
|
||||
skeleton.update(delta);
|
||||
state.update(delta);
|
||||
|
||||
swirlTime += delta;
|
||||
|
||||
@ -40,6 +40,9 @@ import com.badlogic.gdx.utils.Null;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
|
||||
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;
|
||||
|
||||
/** Stores a list of timelines to animate a skeleton's pose over time. */
|
||||
@ -175,7 +178,8 @@ public class Animation {
|
||||
attachment, deform, //
|
||||
event, drawOrder, //
|
||||
ikConstraint, transformConstraint, //
|
||||
pathConstraintPosition, pathConstraintSpacing, pathConstraintMix
|
||||
pathConstraintPosition, pathConstraintSpacing, pathConstraintMix, //
|
||||
sequence
|
||||
}
|
||||
|
||||
/** The base class for all timelines. */
|
||||
@ -1646,7 +1650,7 @@ public class Animation {
|
||||
|
||||
/** The attachment that will be deformed.
|
||||
* <p>
|
||||
* See {@link VertexAttachment#getDeformAttachment()}. */
|
||||
* See {@link VertexAttachment#getTimelineAttachment()}. */
|
||||
public VertexAttachment getAttachment () {
|
||||
return attachment;
|
||||
}
|
||||
@ -1724,9 +1728,9 @@ public class Animation {
|
||||
if (!slot.bone.active) return;
|
||||
Attachment slotAttachment = slot.attachment;
|
||||
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;
|
||||
|
||||
float[][] vertices = this.vertices;
|
||||
@ -1734,7 +1738,6 @@ public class Animation {
|
||||
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) { // Time is before first frame.
|
||||
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
||||
switch (blend) {
|
||||
case setup:
|
||||
deformArray.clear();
|
||||
@ -1745,6 +1748,7 @@ public class Animation {
|
||||
return;
|
||||
}
|
||||
float[] deform = deformArray.setSize(vertexCount);
|
||||
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
||||
if (vertexAttachment.getBones() == null) {
|
||||
// Unweighted vertex positions.
|
||||
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;
|
||||
}
|
||||
|
||||
/** Uses {@link #getTrackTime()} to compute the <code>animationTime</code>, which is between {@link #getAnimationStart()}
|
||||
* and {@link #getAnimationEnd()}. When the <code>trackTime</code> is 0, the <code>animationTime</code> is equal to the
|
||||
* <code>animationStart</code> time. */
|
||||
/** Uses {@link #getTrackTime()} to compute the <code>animationTime</code>. When the <code>trackTime</code> is 0, the
|
||||
* <code>animationTime</code> is equal to the <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 () {
|
||||
if (loop) {
|
||||
float duration = animationEnd - animationStart;
|
||||
if (duration == 0) return 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
|
||||
|
||||
@ -42,7 +42,6 @@ import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.MeshAttachment;
|
||||
import com.esotericsoftware.spine.attachments.PathAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
||||
|
||||
/** Stores the current pose for a skeleton.
|
||||
* <p>
|
||||
@ -60,7 +59,6 @@ public class Skeleton {
|
||||
final Array<Updatable> updateCache = new Array();
|
||||
@Null Skin skin;
|
||||
final Color color;
|
||||
float time;
|
||||
float scaleX = 1, scaleY = 1;
|
||||
float x, y;
|
||||
|
||||
@ -158,7 +156,6 @@ public class Skeleton {
|
||||
|
||||
skin = skeleton.skin;
|
||||
color = new Color(skeleton.color);
|
||||
time = skeleton.time;
|
||||
scaleX = skeleton.scaleX;
|
||||
scaleY = skeleton.scaleY;
|
||||
|
||||
@ -722,11 +719,11 @@ public class Skeleton {
|
||||
int verticesLength = 0;
|
||||
float[] vertices = null;
|
||||
Attachment attachment = slot.attachment;
|
||||
if (attachment instanceof SequenceAttachment) attachment = ((SequenceAttachment)attachment).updateAttachment(slot);
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
verticesLength = 8;
|
||||
vertices = temp.setSize(8);
|
||||
((RegionAttachment)attachment).computeWorldVertices(slot.getBone(), vertices, 0, 2);
|
||||
region.computeWorldVertices(slot, vertices, 0, 2);
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
MeshAttachment mesh = (MeshAttachment)attachment;
|
||||
verticesLength = mesh.getWorldVerticesLength();
|
||||
@ -812,22 +809,6 @@ public class Skeleton {
|
||||
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 () {
|
||||
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.ScaleXTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
|
||||
import com.esotericsoftware.spine.Animation.SequenceTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ShearXTimeline;
|
||||
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.PointAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SequenceAttachment.SequenceMode;
|
||||
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;
|
||||
|
||||
/** 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_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_SPACING = 1;
|
||||
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);
|
||||
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, 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.updateRegion();
|
||||
if (linkedMesh.mesh.getSequence() == null) linkedMesh.mesh.updateRegion();
|
||||
}
|
||||
linkedMeshes.clear();
|
||||
|
||||
@ -398,9 +401,10 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
float width = input.readFloat();
|
||||
float height = input.readFloat();
|
||||
int color = input.readInt();
|
||||
Sequence sequence = readSequence(input);
|
||||
|
||||
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;
|
||||
region.setPath(path);
|
||||
region.setX(x * scale);
|
||||
@ -411,7 +415,8 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
region.setWidth(width * scale);
|
||||
region.setHeight(height * scale);
|
||||
Color.rgba8888ToColor(region.getColor(), color);
|
||||
region.updateRegion();
|
||||
region.setSequence(sequence);
|
||||
if (sequence == null) region.updateRegion();
|
||||
return region;
|
||||
}
|
||||
case boundingbox: {
|
||||
@ -435,6 +440,7 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
short[] triangles = readShortArray(input);
|
||||
Vertices vertices = readVertices(input, vertexCount);
|
||||
int hullLength = input.readInt(true);
|
||||
Sequence sequence = readSequence(input);
|
||||
short[] edges = null;
|
||||
float width = 0, height = 0;
|
||||
if (nonessential) {
|
||||
@ -444,7 +450,7 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
}
|
||||
|
||||
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;
|
||||
mesh.setPath(path);
|
||||
Color.rgba8888ToColor(mesh.getColor(), color);
|
||||
@ -453,8 +459,9 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
mesh.setWorldVerticesLength(vertexCount << 1);
|
||||
mesh.setTriangles(triangles);
|
||||
mesh.setRegionUVs(uvs);
|
||||
mesh.updateRegion();
|
||||
if (sequence == null) mesh.updateRegion();
|
||||
mesh.setHullLength(hullLength << 1);
|
||||
mesh.setSequence(sequence);
|
||||
if (nonessential) {
|
||||
mesh.setEdges(edges);
|
||||
mesh.setWidth(width * scale);
|
||||
@ -467,7 +474,8 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
int color = input.readInt();
|
||||
String skinName = input.readStringRef();
|
||||
String parent = input.readStringRef();
|
||||
boolean inheritDeform = input.readBoolean();
|
||||
boolean inheritTimelines = input.readBoolean();
|
||||
Sequence sequence = readSequence(input);
|
||||
float width = 0, height = 0;
|
||||
if (nonessential) {
|
||||
width = input.readFloat();
|
||||
@ -475,15 +483,16 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
}
|
||||
|
||||
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;
|
||||
mesh.setPath(path);
|
||||
Color.rgba8888ToColor(mesh.getColor(), color);
|
||||
mesh.setSequence(sequence);
|
||||
if (nonessential) {
|
||||
mesh.setWidth(width * 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;
|
||||
}
|
||||
case path: {
|
||||
@ -521,7 +530,7 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
if (nonessential) Color.rgba8888ToColor(point.getColor(), color);
|
||||
return point;
|
||||
}
|
||||
case clipping: {
|
||||
case clipping:
|
||||
int endSlotIndex = input.readInt(true);
|
||||
int vertexCount = input.readInt(true);
|
||||
Vertices vertices = readVertices(input, vertexCount);
|
||||
@ -536,28 +545,18 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
if (nonessential) Color.rgba8888ToColor(clip.getColor(), color);
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
float scale = this.scale;
|
||||
int verticesLength = vertexCount << 1;
|
||||
@ -767,7 +766,6 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
a = a2;
|
||||
}
|
||||
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++) {
|
||||
Skin skin = skeletonData.skins.get(input.readInt(true));
|
||||
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
|
||||
int slotIndex = input.readInt(true);
|
||||
for (int iii = 0, nnn = input.readInt(true); iii < nnn; iii++) {
|
||||
String attachmentName = input.readStringRef();
|
||||
VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, attachmentName);
|
||||
if (attachment == null) throw new SerializationException("Vertex attachment not found: " + attachmentName);
|
||||
boolean weighted = attachment.getBones() != null;
|
||||
float[] vertices = attachment.getVertices();
|
||||
int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
|
||||
Attachment attachment = skin.getAttachment(slotIndex, attachmentName);
|
||||
if (attachment == null) throw new SerializationException("Timeline attachment not found: " + attachmentName);
|
||||
|
||||
int frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||
DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, attachment);
|
||||
int timelineType = input.readByte(), frameCount = input.readInt(true), frameLast = frameCount - 1;
|
||||
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();
|
||||
for (int frame = 0, bezier = 0;; frame++) {
|
||||
float[] deform;
|
||||
int end = input.readInt(true);
|
||||
if (end == 0)
|
||||
deform = weighted ? new float[deformLength] : vertices;
|
||||
else {
|
||||
deform = new float[deformLength];
|
||||
int start = input.readInt(true);
|
||||
end += start;
|
||||
if (scale == 1) {
|
||||
for (int v = start; v < end; v++)
|
||||
deform[v] = input.readFloat();
|
||||
} else {
|
||||
for (int v = start; v < end; v++)
|
||||
deform[v] = input.readFloat() * scale;
|
||||
DeformTimeline timeline = new DeformTimeline(frameCount, input.readInt(true), slotIndex, vertexAttachment);
|
||||
|
||||
float time = input.readFloat();
|
||||
for (int frame = 0, bezier = 0;; frame++) {
|
||||
float[] deform;
|
||||
int end = input.readInt(true);
|
||||
if (end == 0)
|
||||
deform = weighted ? new float[deformLength] : vertices;
|
||||
else {
|
||||
deform = new float[deformLength];
|
||||
int start = input.readInt(true);
|
||||
end += start;
|
||||
if (scale == 1) {
|
||||
for (int v = start; v < end; v++)
|
||||
deform[v] = input.readFloat();
|
||||
} 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) {
|
||||
for (int v = 0, vn = deform.length; v < vn; v++)
|
||||
deform[v] += vertices[v];
|
||||
timeline.setFrame(frame, time, deform);
|
||||
if (frame == frameLast) break;
|
||||
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);
|
||||
if (frame == frameLast) break;
|
||||
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;
|
||||
timelines.add(timeline);
|
||||
break;
|
||||
}
|
||||
case ATTACHMENT_SEQUENCE:
|
||||
SequenceTimeline timeline = new SequenceTimeline(frameCount, slotIndex, attachment);
|
||||
for (int frame = 0; frame < frameCount; frame++) {
|
||||
float time = input.readFloat();
|
||||
int modeAndIndex = input.readInt();
|
||||
timeline.setFrame(frame, time, SequenceMode.values[modeAndIndex & 0xf], modeAndIndex >> 4,
|
||||
input.readFloat());
|
||||
}
|
||||
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.JsonReader;
|
||||
import com.badlogic.gdx.utils.JsonValue;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
import com.badlogic.gdx.utils.SerializationException;
|
||||
|
||||
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.ScaleXTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ScaleYTimeline;
|
||||
import com.esotericsoftware.spine.Animation.SequenceTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ShearTimeline;
|
||||
import com.esotericsoftware.spine.Animation.ShearXTimeline;
|
||||
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.PointAttachment;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SequenceAttachment;
|
||||
import com.esotericsoftware.spine.attachments.SequenceAttachment.SequenceMode;
|
||||
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;
|
||||
|
||||
/** 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);
|
||||
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, 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.updateRegion();
|
||||
if (linkedMesh.mesh.getRegion() != null) linkedMesh.mesh.updateRegion();
|
||||
}
|
||||
linkedMeshes.clear();
|
||||
|
||||
@ -369,7 +370,8 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
switch (AttachmentType.valueOf(map.getString("type", AttachmentType.region.name()))) {
|
||||
case region: {
|
||||
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;
|
||||
region.setPath(path);
|
||||
region.setX(map.getFloat("x", 0) * scale);
|
||||
@ -379,11 +381,12 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
region.setRotation(map.getFloat("rotation", 0));
|
||||
region.setWidth(map.getFloat("width") * scale);
|
||||
region.setHeight(map.getFloat("height") * scale);
|
||||
region.setSequence(sequence);
|
||||
|
||||
String color = map.getString("color", null);
|
||||
if (color != null) Color.valueOf(color, region.getColor());
|
||||
|
||||
region.updateRegion();
|
||||
if (region.getRegion() != null) region.updateRegion();
|
||||
return region;
|
||||
}
|
||||
case boundingbox: {
|
||||
@ -398,7 +401,8 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
case mesh:
|
||||
case linkedmesh: {
|
||||
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;
|
||||
mesh.setPath(path);
|
||||
|
||||
@ -407,11 +411,12 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
|
||||
mesh.setWidth(map.getFloat("width", 0) * scale);
|
||||
mesh.setHeight(map.getFloat("height", 0) * scale);
|
||||
mesh.setSequence(sequence);
|
||||
|
||||
String parent = map.getString("parent", null);
|
||||
if (parent != null) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -419,7 +424,7 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
readVertices(map, mesh, uvs.length);
|
||||
mesh.setTriangles(map.require("triangles").asShortArray());
|
||||
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("edges")) mesh.setEdges(map.require("edges").asShortArray());
|
||||
@ -455,7 +460,7 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
if (color != null) Color.valueOf(color, point.getColor());
|
||||
return point;
|
||||
}
|
||||
case clipping: {
|
||||
case clipping:
|
||||
ClippingAttachment clip = attachmentLoader.newClippingAttachment(skin, name);
|
||||
if (clip == null) return null;
|
||||
|
||||
@ -472,23 +477,18 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
if (color != null) Color.valueOf(color, clip.getColor());
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
attachment.setWorldVerticesLength(verticesLength);
|
||||
float[] vertices = map.require("vertices").asFloatArray();
|
||||
@ -533,7 +533,7 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
if (timelineName.equals("attachment")) {
|
||||
AttachmentTimeline timeline = new AttachmentTimeline(frames, slot.index);
|
||||
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);
|
||||
|
||||
} else if (timelineName.equals("rgba")) {
|
||||
@ -877,57 +877,72 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
}
|
||||
}
|
||||
|
||||
// Deform timelines.
|
||||
for (JsonValue deformMap = map.getChild("deform"); deformMap != null; deformMap = deformMap.next) {
|
||||
Skin skin = skeletonData.findSkin(deformMap.name);
|
||||
if (skin == null) throw new SerializationException("Skin not found: " + deformMap.name);
|
||||
for (JsonValue slotMap = deformMap.child; slotMap != null; slotMap = slotMap.next) {
|
||||
// Attachment timelines.
|
||||
for (JsonValue attachmentsMap = map.getChild("attachments"); attachmentsMap != null; attachmentsMap = attachmentsMap.next) {
|
||||
Skin skin = skeletonData.findSkin(attachmentsMap.name);
|
||||
if (skin == null) throw new SerializationException("Skin not found: " + attachmentsMap.name);
|
||||
for (JsonValue slotMap = attachmentsMap.child; slotMap != null; slotMap = slotMap.next) {
|
||||
SlotData slot = skeletonData.findSlot(slotMap.name);
|
||||
if (slot == null) throw new SerializationException("Slot not found: " + slotMap.name);
|
||||
for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) {
|
||||
JsonValue keyMap = timelineMap.child;
|
||||
if (keyMap == null) continue;
|
||||
for (JsonValue attachmentMap = slotMap.child; attachmentMap != null; attachmentMap = attachmentMap.next) {
|
||||
Attachment attachment = skin.getAttachment(slot.index, attachmentMap.name);
|
||||
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);
|
||||
if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name);
|
||||
boolean weighted = attachment.getBones() != null;
|
||||
float[] vertices = attachment.getVertices();
|
||||
int deformLength = weighted ? (vertices.length / 3) << 1 : vertices.length;
|
||||
DeformTimeline timeline = new DeformTimeline(frames, frames, slot.index, vertexAttachment);
|
||||
float time = keyMap.getFloat("time", 0);
|
||||
for (int frame = 0, bezier = 0;; frame++) {
|
||||
float[] deform;
|
||||
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);
|
||||
float time = keyMap.getFloat("time", 0);
|
||||
for (int frame = 0, bezier = 0;; frame++) {
|
||||
float[] deform;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
if (!weighted) {
|
||||
for (int i = 0; i < deformLength; i++)
|
||||
deform[i] += vertices[i];
|
||||
timelines.add(timeline);
|
||||
} else if (timelineName.equals("sequence")) {
|
||||
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;
|
||||
int slotIndex;
|
||||
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.skin = skin;
|
||||
this.slotIndex = slotIndex;
|
||||
this.parent = parent;
|
||||
this.inheritDeform = inheritDeform;
|
||||
this.inheritTimelines = inheritTimelines;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ public class SkeletonRenderer {
|
||||
Attachment attachment = slot.attachment;
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
region.computeWorldVertices(slot.getBone(), vertices, 0, 5);
|
||||
region.computeWorldVertices(slot, vertices, 0, 5);
|
||||
Color color = region.getColor(), slotColor = slot.getColor();
|
||||
float alpha = a * slotColor.a * color.a * 255;
|
||||
float multiplier = pmaColors ? alpha : 255;
|
||||
@ -183,7 +183,7 @@ public class SkeletonRenderer {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
verticesLength = vertexSize << 2;
|
||||
vertices = this.vertices.items;
|
||||
region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize);
|
||||
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
||||
triangles = quadTriangles;
|
||||
texture = region.getRegion().getTexture();
|
||||
uvs = region.getUVs();
|
||||
@ -309,7 +309,7 @@ public class SkeletonRenderer {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
verticesLength = vertexSize << 2;
|
||||
vertices = this.vertices.items;
|
||||
region.computeWorldVertices(slot.getBone(), vertices, 0, vertexSize);
|
||||
region.computeWorldVertices(slot, vertices, 0, vertexSize);
|
||||
triangles = quadTriangles;
|
||||
texture = region.getRegion().getTexture();
|
||||
uvs = region.getUVs();
|
||||
|
||||
@ -127,7 +127,7 @@ public class SkeletonRendererDebug {
|
||||
if (attachment instanceof RegionAttachment) {
|
||||
RegionAttachment region = (RegionAttachment)attachment;
|
||||
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[2], vertices[3], vertices[4], vertices[5]);
|
||||
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.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.Sequence;
|
||||
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
|
||||
@ -46,8 +47,8 @@ public class Slot {
|
||||
final Color color = new Color();
|
||||
@Null final Color darkColor;
|
||||
@Null Attachment attachment;
|
||||
private float attachmentTime;
|
||||
private FloatArray deform = new FloatArray();
|
||||
int sequenceIndex;
|
||||
FloatArray deform = new FloatArray();
|
||||
|
||||
int attachmentState;
|
||||
|
||||
@ -69,7 +70,7 @@ public class Slot {
|
||||
color.set(slot.color);
|
||||
darkColor = slot.darkColor == null ? null : new Color(slot.darkColor);
|
||||
attachment = slot.attachment;
|
||||
attachmentTime = slot.attachmentTime;
|
||||
sequenceIndex = slot.sequenceIndex;
|
||||
deform.addAll(slot.deform);
|
||||
}
|
||||
|
||||
@ -105,27 +106,28 @@ public class Slot {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
/** Sets the slot's attachment and, if the attachment changed, resets {@link #attachmentTime} and clears the {@link #deform}.
|
||||
* The deform is not cleared if the old attachment has the same {@link VertexAttachment#getDeformAttachment()} as the specified
|
||||
* attachment. */
|
||||
/** 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#getTimelineAttachment()} as the
|
||||
* specified attachment. */
|
||||
public void setAttachment (@Null Attachment attachment) {
|
||||
if (this.attachment == attachment) return;
|
||||
if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment)
|
||||
|| ((VertexAttachment)attachment).getDeformAttachment() != ((VertexAttachment)this.attachment).getDeformAttachment()) {
|
||||
|| ((VertexAttachment)attachment).getTimelineAttachment() != ((VertexAttachment)this.attachment)
|
||||
.getTimelineAttachment()) {
|
||||
deform.clear();
|
||||
}
|
||||
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
|
||||
* {@link Skeleton#time}. */
|
||||
public float getAttachmentTime () {
|
||||
return bone.skeleton.time - attachmentTime;
|
||||
/** The index of the texture region to display when the slot's attachment has a {@link Sequence}. -1 represents the
|
||||
* {@link Sequence#getSetupIndex()}. */
|
||||
public int getSequenceIndex () {
|
||||
return sequenceIndex;
|
||||
}
|
||||
|
||||
public void setAttachmentTime (float time) {
|
||||
attachmentTime = bone.skeleton.time - time;
|
||||
public void setSequenceIndex (int sequenceIndex) {
|
||||
this.sequenceIndex = sequenceIndex;
|
||||
}
|
||||
|
||||
/** 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.AtlasRegion;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
|
||||
import com.esotericsoftware.spine.Skin;
|
||||
|
||||
@ -47,32 +49,39 @@ public class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
this.atlas = atlas;
|
||||
}
|
||||
|
||||
public RegionAttachment newRegionAttachment (Skin skin, String name, String path) {
|
||||
AtlasRegion region = atlas.findRegion(path);
|
||||
if (region == null) throw new RuntimeException("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
RegionAttachment attachment = new RegionAttachment(name);
|
||||
attachment.setRegion(region);
|
||||
return attachment;
|
||||
}
|
||||
|
||||
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 + ")");
|
||||
private void loadSequence (String name, String basePath, Sequence sequence) {
|
||||
TextureRegion[] regions = sequence.getRegions();
|
||||
for (int i = 0, n = regions.length; i < n; i++) {
|
||||
String path = sequence.getPath(basePath, i);
|
||||
regions[i] = atlas.findRegion(path);
|
||||
if (regions[i] == null) throw new RuntimeException("Region not found in atlas: " + path + " (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) {
|
||||
|
||||
@ -31,13 +31,18 @@ package com.esotericsoftware.spine.attachments;
|
||||
|
||||
/** The base class for all attachments. */
|
||||
abstract public class Attachment {
|
||||
String name;
|
||||
final String name;
|
||||
|
||||
public Attachment (String name) {
|
||||
if (name == null) throw new IllegalArgumentException("name cannot be null.");
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
protected Attachment (Attachment other) {
|
||||
name = other.name;
|
||||
}
|
||||
|
||||
/** The attachment's name. */
|
||||
public String getName () {
|
||||
return name;
|
||||
|
||||
@ -39,13 +39,10 @@ import com.esotericsoftware.spine.Skin;
|
||||
* Runtimes Guide. */
|
||||
public interface AttachmentLoader {
|
||||
/** @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. */
|
||||
public @Null MeshAttachment newMeshAttachment (Skin skin, String name, String path);
|
||||
|
||||
/** @return May be null to not load the attachment. */
|
||||
public @Null SequenceAttachment newSequenceAttachment (Skin skin, String name, String path, int frameCount);
|
||||
public @Null MeshAttachment newMeshAttachment (Skin skin, String name, String path, @Null Sequence sequence);
|
||||
|
||||
/** @return May be null to not load the attachment. */
|
||||
public @Null BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name);
|
||||
|
||||
@ -46,16 +46,19 @@ public class BoundingBoxAttachment extends VertexAttachment {
|
||||
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
|
||||
* are not usually rendered at runtime. */
|
||||
public Color getColor () {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Attachment copy () {
|
||||
BoundingBoxAttachment copy = new BoundingBoxAttachment(name);
|
||||
copyTo(copy);
|
||||
copy.color.set(color);
|
||||
return copy;
|
||||
public BoundingBoxAttachment copy () {
|
||||
return new BoundingBoxAttachment(name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,13 @@ public class ClippingAttachment extends VertexAttachment {
|
||||
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
|
||||
* the skeleton's rendering. */
|
||||
public @Null SlotData getEndSlot () {
|
||||
@ -61,11 +68,7 @@ public class ClippingAttachment extends VertexAttachment {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Attachment copy () {
|
||||
ClippingAttachment copy = new ClippingAttachment(name);
|
||||
copyTo(copy);
|
||||
copy.endSlot = endSlot;
|
||||
copy.color.set(color);
|
||||
return copy;
|
||||
public ClippingAttachment copy () {
|
||||
return new ClippingAttachment(name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.esotericsoftware.spine.attachments;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
|
||||
public interface HasTextureRegion {
|
||||
/** The name used to find the {@link #getRegion()}. */
|
||||
@ -10,16 +11,20 @@ public interface HasTextureRegion {
|
||||
|
||||
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 ();
|
||||
|
||||
/** Updates any values the attachment calculates using the {@link #getRegion()}. Must be called after changing the region or
|
||||
* the region's properties. */
|
||||
/** Sets the region used to draw the attachment. After setting the region or if the region's properties are changed,
|
||||
* {@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 ();
|
||||
|
||||
/** The color to tint the attachment. */
|
||||
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.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
|
||||
* supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh.
|
||||
* <p>
|
||||
@ -48,6 +50,7 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
||||
private final Color color = new Color(1, 1, 1, 1);
|
||||
private int hullLength;
|
||||
private @Null MeshAttachment parentMesh;
|
||||
private @Null Sequence sequence;
|
||||
|
||||
// Nonessential.
|
||||
private @Null short[] edges;
|
||||
@ -57,18 +60,47 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
||||
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) {
|
||||
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public TextureRegion getRegion () {
|
||||
if (region == null) throw new IllegalStateException("Region has not been set: " + this);
|
||||
public @Null TextureRegion getRegion () {
|
||||
return region;
|
||||
}
|
||||
|
||||
/** Calculates {@link #uvs} using {@link #regionUVs} and the {@link #region}. Must be called after changing the region or the
|
||||
* region's properties. */
|
||||
/** Calculates {@link #uvs} using the {@link #regionUVs} and {@link #region}. Must be called if the {@link #region},
|
||||
* {@link #regionUVs}, or the region's properties are changed. */
|
||||
public void updateRegion () {
|
||||
float[] regionUVs = this.regionUVs;
|
||||
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. */
|
||||
public short[] getTriangles () {
|
||||
return triangles;
|
||||
@ -210,6 +248,14 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
||||
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},
|
||||
* {@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). */
|
||||
@ -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. */
|
||||
public MeshAttachment newLinkedMesh () {
|
||||
MeshAttachment mesh = new MeshAttachment(name);
|
||||
mesh.timelineAttachment = timelineAttachment;
|
||||
mesh.region = region;
|
||||
mesh.path = path;
|
||||
mesh.color.set(color);
|
||||
mesh.deformAttachment = deformAttachment;
|
||||
mesh.setParentMesh(parentMesh != null ? parentMesh : this);
|
||||
mesh.updateRegion();
|
||||
if (mesh.getRegion() != null) mesh.updateRegion();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public MeshAttachment copy () {
|
||||
return parentMesh != null ? newLinkedMesh() : new MeshAttachment(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,18 @@ public class PathAttachment extends VertexAttachment {
|
||||
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. */
|
||||
public boolean getClosed () {
|
||||
return closed;
|
||||
@ -83,14 +95,7 @@ public class PathAttachment extends VertexAttachment {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Attachment copy () {
|
||||
PathAttachment copy = new PathAttachment(name);
|
||||
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;
|
||||
public PathAttachment copy () {
|
||||
return new PathAttachment(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +51,15 @@ public class PointAttachment extends Attachment {
|
||||
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 () {
|
||||
return x;
|
||||
}
|
||||
@ -94,12 +103,7 @@ public class PointAttachment extends Attachment {
|
||||
return (float)Math.atan2(y, x) * radDeg;
|
||||
}
|
||||
|
||||
public Attachment copy () {
|
||||
PointAttachment copy = new PointAttachment(name);
|
||||
copy.x = x;
|
||||
copy.y = y;
|
||||
copy.rotation = rotation;
|
||||
copy.color.set(color);
|
||||
return copy;
|
||||
public PointAttachment copy () {
|
||||
return new PointAttachment(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,21 +34,19 @@ import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
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.Bone;
|
||||
import com.esotericsoftware.spine.Slot;
|
||||
|
||||
/** An attachment that displays a textured quadrilateral.
|
||||
* <p>
|
||||
* See <a href="http://esotericsoftware.com/spine-regions">Region attachments</a> in the Spine User Guide. */
|
||||
public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
static public final int BLX = 0;
|
||||
static public final int BLY = 1;
|
||||
static public final int ULX = 2;
|
||||
static public final int ULY = 3;
|
||||
static public final int URX = 4;
|
||||
static public final int URY = 5;
|
||||
static public final int BRX = 6;
|
||||
static public final int BRY = 7;
|
||||
static public final int BLX = 0, BLY = 1;
|
||||
static public final int ULX = 2, ULY = 3;
|
||||
static public final int URX = 4, URY = 5;
|
||||
static public final int BRX = 6, BRY = 7;
|
||||
|
||||
private TextureRegion region;
|
||||
private String path;
|
||||
@ -56,13 +54,31 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
private final float[] uvs = new float[8];
|
||||
private final float[] offset = new float[8];
|
||||
private final Color color = new Color(1, 1, 1, 1);
|
||||
private @Null Sequence sequence;
|
||||
|
||||
public RegionAttachment (String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/** Calculates the {@link #offset} using the {@link #region}. Must be called after changing the region or the region's
|
||||
* properties. */
|
||||
/** Copy constructor. */
|
||||
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 () {
|
||||
float width = getWidth();
|
||||
float height = getHeight();
|
||||
@ -70,11 +86,13 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
float localY2 = height / 2;
|
||||
float localX = -localX2;
|
||||
float localY = -localY2;
|
||||
boolean rotated = false;
|
||||
if (region instanceof AtlasRegion) {
|
||||
AtlasRegion region = (AtlasRegion)this.region;
|
||||
localX += region.offsetX / region.originalWidth * width;
|
||||
localY += region.offsetY / region.originalHeight * height;
|
||||
if (region.degrees == 90) {
|
||||
rotated = true;
|
||||
localX2 -= (region.originalWidth - region.offsetX - region.packedHeight) / region.originalWidth * width;
|
||||
localY2 -= (region.originalHeight - region.offsetY - region.packedWidth) / region.originalHeight * height;
|
||||
} else {
|
||||
@ -110,13 +128,9 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
offset[URY] = localY2Cos + localX2Sin;
|
||||
offset[BRX] = localX2Cos - localYSin;
|
||||
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;
|
||||
if (region instanceof AtlasRegion && ((AtlasRegion)region).degrees == 90) {
|
||||
if (rotated) {
|
||||
uvs[URX] = region.getU();
|
||||
uvs[URY] = region.getV2();
|
||||
uvs[BRX] = region.getU();
|
||||
@ -137,20 +151,28 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
}
|
||||
}
|
||||
|
||||
public TextureRegion getRegion () {
|
||||
if (region == null) throw new IllegalStateException("Region has not been set: " + name);
|
||||
public void setRegion (TextureRegion region) {
|
||||
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
public @Null TextureRegion getRegion () {
|
||||
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>
|
||||
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
|
||||
* Runtimes Guide.
|
||||
* @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 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;
|
||||
Bone bone = slot.getBone();
|
||||
float x = bone.getWorldX(), y = bone.getWorldY();
|
||||
float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD();
|
||||
float offsetX, offsetY;
|
||||
@ -265,20 +287,15 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Attachment copy () {
|
||||
RegionAttachment copy = new RegionAttachment(name);
|
||||
copy.region = region;
|
||||
copy.path = path;
|
||||
copy.x = x;
|
||||
copy.y = y;
|
||||
copy.scaleX = scaleX;
|
||||
copy.scaleY = scaleY;
|
||||
copy.rotation = rotation;
|
||||
copy.width = width;
|
||||
copy.height = height;
|
||||
arraycopy(uvs, 0, copy.uvs, 0, 8);
|
||||
arraycopy(offset, 0, copy.offset, 0, 8);
|
||||
copy.color.set(color);
|
||||
return copy;
|
||||
public @Null Sequence getSequence () {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public void setSequence (@Null Sequence sequence) {
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
public RegionAttachment copy () {
|
||||
return new RegionAttachment(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/** @return May return null. */
|
||||
public Skeleton getSkeleton () {
|
||||
/** Copy constructor. */
|
||||
protected SkeletonAttachment (SkeletonAttachment other) {
|
||||
super(other);
|
||||
skeleton = other.skeleton;
|
||||
}
|
||||
|
||||
public @Null Skeleton getSkeleton () {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
@ -50,9 +55,7 @@ public class SkeletonAttachment extends Attachment {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
public Attachment copy () {
|
||||
SkeletonAttachment copy = new SkeletonAttachment(name);
|
||||
copy.skeleton = skeleton;
|
||||
return copy;
|
||||
public SkeletonAttachment copy () {
|
||||
return new SkeletonAttachment(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,15 +44,35 @@ abstract public class VertexAttachment extends Attachment {
|
||||
static private int nextID;
|
||||
|
||||
private final int id = nextID();
|
||||
@Null Attachment timelineAttachment = this;
|
||||
@Null int[] bones;
|
||||
float[] vertices;
|
||||
int worldVerticesLength;
|
||||
@Null VertexAttachment deformAttachment = this;
|
||||
|
||||
public VertexAttachment (String 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
|
||||
* not empty, it is used to deform the vertices.
|
||||
* <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 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. */
|
||||
@ -164,29 +173,22 @@ abstract public class VertexAttachment extends Attachment {
|
||||
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. */
|
||||
public int getId () {
|
||||
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 () {
|
||||
return nextID++;
|
||||
}
|
||||
|
||||
@ -258,7 +258,6 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
skeleton.setSlotsToSetupPose();
|
||||
|
||||
delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue();
|
||||
skeleton.update(delta);
|
||||
state.update(delta);
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user