mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-12 10:08:44 +08:00
Rewrote sequence attachment as a sequence property on region and mesh attachments.
This commit is contained in:
parent
920604dff7
commit
6e938b32ea
@ -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,89 @@ public class Animation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Changes a slot's {@link Slot#getSequenceIndex()} for an attachment's {@link Sequence}. */
|
||||
static public class SequenceTimeline<T extends Attachment & HasTextureRegion> extends Timeline implements SlotTimeline {
|
||||
static public final int ENTRIES = 3;
|
||||
static private final int MODE = 1, FRAME_TIME = 2;
|
||||
|
||||
final int slotIndex;
|
||||
final T attachment;
|
||||
|
||||
public SequenceTimeline (int frameCount, int slotIndex, T attachment) {
|
||||
super(frameCount, Property.sequence.ordinal() + "|" + slotIndex + "|" + attachment.getSequence().getId());
|
||||
this.slotIndex = slotIndex;
|
||||
this.attachment = attachment;
|
||||
}
|
||||
|
||||
public int getFrameEntries () {
|
||||
return ENTRIES;
|
||||
}
|
||||
|
||||
public int getSlotIndex () {
|
||||
return slotIndex;
|
||||
}
|
||||
|
||||
public T getAttachment () {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
/** Sets the time, mode, index, and frame time for the specified frame.
|
||||
* @param frame Between 0 and <code>frameCount</code>, inclusive.
|
||||
* @param time The frame time in seconds. */
|
||||
public void setFrame (int frame, float time, SequenceMode mode, int index, float frameTime) {
|
||||
frame *= ENTRIES;
|
||||
frames[frame] = time;
|
||||
frames[frame + MODE] = mode.ordinal() | (index << 4);
|
||||
frames[frame + FRAME_TIME] = frameTime;
|
||||
}
|
||||
|
||||
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 frameTime = frames[i + FRAME_TIME];
|
||||
|
||||
int index = modeAndIndex >> 4, count = attachment.getSequence().getRegions().length;
|
||||
SequenceMode mode = SequenceMode.values[modeAndIndex & 0xf];
|
||||
if (mode != SequenceMode.stop) {
|
||||
index += (time - before) / frameTime;
|
||||
switch (mode) {
|
||||
case play:
|
||||
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 playReverse:
|
||||
index = Math.max(count - 1 - index, 0);
|
||||
break;
|
||||
case loopReverse:
|
||||
index = count - 1 - (index % count);
|
||||
}
|
||||
}
|
||||
slot.setSequenceIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -85,9 +85,6 @@ 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.VertexAttachment;
|
||||
|
||||
/** Loads skeleton data in the Spine binary format.
|
||||
@ -303,7 +300,7 @@ 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();
|
||||
}
|
||||
@ -399,8 +396,10 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
float height = input.readFloat();
|
||||
int color = input.readInt();
|
||||
|
||||
// BOZO! - Read sequence.
|
||||
|
||||
if (path == null) path = name;
|
||||
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path);
|
||||
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, null);
|
||||
if (region == null) return null;
|
||||
region.setPath(path);
|
||||
region.setX(x * scale);
|
||||
@ -443,8 +442,10 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
height = input.readFloat();
|
||||
}
|
||||
|
||||
// BOZO! - Read sequence.
|
||||
|
||||
if (path == null) path = name;
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, null);
|
||||
if (mesh == null) return null;
|
||||
mesh.setPath(path);
|
||||
Color.rgba8888ToColor(mesh.getColor(), color);
|
||||
@ -467,15 +468,17 @@ 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();
|
||||
float width = 0, height = 0;
|
||||
if (nonessential) {
|
||||
width = input.readFloat();
|
||||
height = input.readFloat();
|
||||
}
|
||||
|
||||
// BOZO! - Read sequence.
|
||||
|
||||
if (path == null) path = name;
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, null);
|
||||
if (mesh == null) return null;
|
||||
mesh.setPath(path);
|
||||
Color.rgba8888ToColor(mesh.getColor(), color);
|
||||
@ -483,7 +486,7 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
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 +524,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,25 +539,6 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@ -84,9 +84,6 @@ 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.VertexAttachment;
|
||||
|
||||
/** Loads skeleton data in the Spine JSON format.
|
||||
@ -324,7 +321,7 @@ 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();
|
||||
}
|
||||
@ -369,7 +366,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);
|
||||
// BOZO! - Read sequence.
|
||||
RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path, null);
|
||||
if (region == null) return null;
|
||||
region.setPath(path);
|
||||
region.setX(map.getFloat("x", 0) * scale);
|
||||
@ -398,7 +396,8 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
case mesh:
|
||||
case linkedmesh: {
|
||||
String path = map.getString("path", name);
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
||||
// BOZO! - Read sequence.
|
||||
MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path, null);
|
||||
if (mesh == null) return null;
|
||||
mesh.setPath(path);
|
||||
|
||||
@ -411,7 +410,7 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -455,7 +454,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,20 +471,6 @@ 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;
|
||||
}
|
||||
|
||||
@ -1068,14 +1053,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,6 +60,36 @@ 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;
|
||||
@ -67,8 +100,8 @@ public class MeshAttachment extends VertexAttachment implements HasTextureRegion
|
||||
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 +164,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 +249,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 +279,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();
|
||||
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,29 @@ public class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
}
|
||||
}
|
||||
|
||||
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: " + name);
|
||||
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 +288,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,124 @@
|
||||
/******************************************************************************
|
||||
* 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;
|
||||
else 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, play, loop, pingpong, playReverse, 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