Refactored skin API, see #841. This commit is missing Skin#copy(Skin) which has to handle linked mesh attachments properly.

This commit is contained in:
badlogic 2019-04-30 15:34:44 +02:00
parent 6205e51752
commit 86c3aa02ba
14 changed files with 179 additions and 59 deletions

View File

@ -54,8 +54,8 @@ public class AttachmentTimelineTests {
Attachment attachment2 = new Attachment("attachment2") {};
Skin skin = new Skin("skin");
skin.addAttachment(0, "attachment1", attachment1);
skin.addAttachment(0, "attachment2", attachment2);
skin.setAttachment(0, "attachment1", attachment1);
skin.setAttachment(0, "attachment2", attachment2);
skeletonData.setDefaultSkin(skin);
skeleton = new Skeleton(skeletonData);

View File

@ -30,15 +30,14 @@
package com.esotericsoftware.spine;
import static com.esotericsoftware.spine.utils.SpineUtils.*;
import static com.esotericsoftware.spine.utils.SpineUtils.cosDeg;
import static com.esotericsoftware.spine.utils.SpineUtils.sinDeg;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.ObjectMap.Entry;
import com.esotericsoftware.spine.Skin.Key;
import com.esotericsoftware.spine.Skin.SkinEntry;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.MeshAttachment;
import com.esotericsoftware.spine.attachments.PathAttachment;
@ -279,8 +278,8 @@ public class Skeleton {
}
private void sortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) {
for (Entry<Key, Attachment> entry : skin.attachments.entries())
if (entry.key.slotIndex == slotIndex) sortPathConstraintAttachment(entry.value, slotBone);
for (SkinEntry entry : skin.attachments.keys())
if (entry.getSlotIndex() == slotIndex) sortPathConstraintAttachment(entry.getAttachment(), slotBone);
}
private void sortPathConstraintAttachment (Attachment attachment, Bone slotBone) {

View File

@ -362,7 +362,7 @@ public class SkeletonBinary {
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
String name = input.readString();
Attachment attachment = readAttachment(input, skeletonData, skin, slotIndex, name, nonessential);
if (attachment != null) skin.addAttachment(slotIndex, name, attachment);
if (attachment != null) skin.setAttachment(slotIndex, name, attachment);
}
}
return skin;

View File

@ -294,7 +294,7 @@ public class SkeletonJson {
for (JsonValue entry = slotEntry.child; entry != null; entry = entry.next) {
try {
Attachment attachment = readAttachment(entry, skin, slot.index, entry.name, skeletonData);
if (attachment != null) skin.addAttachment(slot.index, entry.name, attachment);
if (attachment != null) skin.setAttachment(slot.index, entry.name, attachment);
} catch (Throwable ex) {
throw new SerializationException("Error reading attachment: " + entry.name + ", skin: " + skin, ex);
}

View File

@ -32,9 +32,6 @@ package com.esotericsoftware.spine;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectMap.Entry;
import com.badlogic.gdx.utils.Pool;
import com.esotericsoftware.spine.attachments.Attachment;
/** Stores attachments by slot index and attachment name.
@ -43,15 +40,10 @@ import com.esotericsoftware.spine.attachments.Attachment;
* <a href="http://esotericsoftware.com/spine-runtime-skins">Runtime skins</a> in the Spine Runtimes Guide. */
public class Skin {
final String name;
final ObjectMap<Key, Attachment> attachments = new ObjectMap();
final ObjectMap<SkinEntry, Attachment> attachments = new ObjectMap();
final Array<BoneData> bones = new Array();
final Array<ConstraintData> constraints = new Array();
private final Key lookup = new Key();
final Pool<Key> keyPool = new Pool(64) {
protected Object newObject () {
return new Key();
}
};
private final SkinEntry lookup = new SkinEntry();
public Skin (String name) {
if (name == null) throw new IllegalArgumentException("name cannot be null.");
@ -59,53 +51,49 @@ public class Skin {
}
/** Adds an attachment to the skin for the specified slot index and name. */
public void addAttachment (int slotIndex, String name, Attachment attachment) {
public void setAttachment (int slotIndex, String name, Attachment attachment) {
if (attachment == null) throw new IllegalArgumentException("attachment cannot be null.");
if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0.");
Key key = keyPool.obtain();
key.set(slotIndex, name);
attachments.put(key, attachment);
attachments.put(new SkinEntry(slotIndex, name, attachment), attachment);
}
/** Adds all attachments from the specified skin to this skin. */
public void addAttachments (Skin skin) {
for (Entry<Key, Attachment> entry : skin.attachments.entries())
addAttachment(entry.key.slotIndex, entry.key.name, entry.value);
public void addSkin (Skin skin) {
for (SkinEntry entry : skin.attachments.keys())
setAttachment(entry.getSlotIndex(), entry.getName(), entry.getAttachment());
}
/** Returns the attachment for the specified slot index and name, or null. */
public Attachment getAttachment (int slotIndex, String name) {
if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0.");
lookup.set(slotIndex, name);
lookup.set(slotIndex, name, null);
return attachments.get(lookup);
}
/** Removes the attachment in the skin for the specified slot index and name, if any. */
public void removeAttachment (int slotIndex, String name) {
if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0.");
Key key = keyPool.obtain();
key.set(slotIndex, name);
attachments.remove(key);
keyPool.free(key);
lookup.set(slotIndex, name, null);
attachments.remove(lookup);
}
public void findNamesForSlot (int slotIndex, Array<String> names) {
if (names == null) throw new IllegalArgumentException("names cannot be null.");
if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0.");
for (Key key : attachments.keys())
if (key.slotIndex == slotIndex) names.add(key.name);
/** Returns all attachments contained in this skin. */
public Array<SkinEntry> getAttachments () {
Array<SkinEntry> entries = new Array();
for (SkinEntry entry : this.attachments.keys())
entries.add(entry);
return entries;
}
public void findAttachmentsForSlot (int slotIndex, Array<Attachment> attachments) {
if (attachments == null) throw new IllegalArgumentException("attachments cannot be null.");
if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0.");
for (Entry<Key, Attachment> entry : this.attachments.entries())
if (entry.key.slotIndex == slotIndex) attachments.add(entry.value);
/** Returns all {@link SkinEntry} instances for the given slot contained in this skin. */
public Array<SkinEntry> getEntries (int slotIndex) {
Array<SkinEntry> entries = new Array();
for (SkinEntry entry : this.attachments.keys())
if (entry.getSlotIndex() == slotIndex) entries.add(entry);
return entries;
}
public void clear () {
for (Key key : attachments.keys())
keyPool.free(key);
attachments.clear(1024);
bones.clear();
constraints.clear();
@ -134,26 +122,49 @@ public class Skin {
/** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */
void attachAll (Skeleton skeleton, Skin oldSkin) {
for (Entry<Key, Attachment> entry : oldSkin.attachments.entries()) {
int slotIndex = entry.key.slotIndex;
for (SkinEntry entry : oldSkin.attachments.keys()) {
int slotIndex = entry.getSlotIndex();
Slot slot = skeleton.slots.get(slotIndex);
if (slot.attachment == entry.value) {
Attachment attachment = getAttachment(slotIndex, entry.key.name);
if (slot.attachment == entry.getAttachment()) {
Attachment attachment = getAttachment(slotIndex, entry.getName());
if (attachment != null) slot.setAttachment(attachment);
}
}
}
static class Key {
int slotIndex;
String name;
int hashCode;
/** Stores an entry in the skin consisting of the slot index, name, and attachment **/
public static class SkinEntry {
private int slotIndex;
private String name;
private Attachment attachment;
private int hashCode;
public void set (int slotIndex, String name) {
SkinEntry () {
set(0, "", null);
}
SkinEntry (int slotIndex, String name, Attachment attachment) {
set(slotIndex, name, attachment);
}
void set (int slotIndex, String name, Attachment attachment) {
if (name == null) throw new IllegalArgumentException("name cannot be null.");
this.slotIndex = slotIndex;
this.name = name;
hashCode = name.hashCode() + slotIndex * 37;
this.attachment = attachment;
this.hashCode = name.hashCode() + slotIndex * 37;
}
public int getSlotIndex () {
return slotIndex;
}
public String getName () {
return name;
}
public Attachment getAttachment () {
return attachment;
}
public int hashCode () {
@ -162,7 +173,7 @@ public class Skin {
public boolean equals (Object object) {
if (object == null) return false;
Key other = (Key)object;
SkinEntry other = (SkinEntry)object;
if (slotIndex != other.slotIndex) return false;
if (!name.equals(other.name)) return false;
return true;

View File

@ -47,4 +47,7 @@ abstract public class Attachment {
public String toString () {
return getName();
}
/** Returns a copy of the attachment. **/
public abstract Attachment copy ();
}

View File

@ -51,4 +51,11 @@ public class BoundingBoxAttachment extends VertexAttachment {
public Color getColor () {
return color;
}
public Attachment copy () {
BoundingBoxAttachment copy = new BoundingBoxAttachment(name);
copyTo(copy);
copy.color.set(color);
return copy;
}
}

View File

@ -59,4 +59,12 @@ public class ClippingAttachment extends VertexAttachment {
public Color getColor () {
return color;
}
public Attachment copy () {
ClippingAttachment copy = new ClippingAttachment(name);
copyTo(copy);
copy.endSlot = endSlot;
copy.color.set(color);
return copy;
}
}

View File

@ -33,7 +33,6 @@ package com.esotericsoftware.spine.attachments;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.esotericsoftware.spine.Animation.DeformTimeline;
/** An attachment that displays a textured mesh. A mesh has hull vertices and internal vertices within the hull. Holes are not
@ -253,4 +252,35 @@ public class MeshAttachment extends VertexAttachment {
public void setInheritDeform (boolean inheritDeform) {
this.inheritDeform = inheritDeform;
}
public Attachment copy () {
MeshAttachment copy = new MeshAttachment(name);
copy.region = region;
copy.path = path;
if (parentMesh == null) {
copyTo(copy);
copy.regionUVs = new float[regionUVs.length];
System.arraycopy(regionUVs, 0, copy.regionUVs, 0, regionUVs.length);
copy.uvs = new float[uvs.length];
System.arraycopy(uvs, 0, copy.uvs, 0, uvs.length);
copy.triangles = new short[triangles.length];
System.arraycopy(triangles, 0, copy.triangles, 0, triangles.length);
copy.color.set(color);
copy.hullLength = hullLength;
copy.inheritDeform = inheritDeform;
// Nonessential.
if (edges != null) {
copy.edges = new short[edges.length];
System.arraycopy(edges, 0, copy.edges, 0, edges.length);
}
copy.width = width;
copy.height = height;
} else
copy.setParentMesh(parentMesh);
return copy;
}
}

View File

@ -80,4 +80,14 @@ public class PathAttachment extends VertexAttachment {
public Color getColor () {
return color;
}
public Attachment copy () {
PathAttachment copy = new PathAttachment(name);
copyTo(copy);
copy.lengths = new float[lengths.length];
System.arraycopy(lengths, 0, copy.lengths, 0, lengths.length);
copy.closed = closed;
copy.constantSpeed = constantSpeed;
return copy;
}
}

View File

@ -30,7 +30,9 @@
package com.esotericsoftware.spine.attachments;
import static com.badlogic.gdx.math.MathUtils.*;
import static com.badlogic.gdx.math.MathUtils.cosDeg;
import static com.badlogic.gdx.math.MathUtils.radDeg;
import static com.badlogic.gdx.math.MathUtils.sinDeg;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;
@ -93,4 +95,14 @@ public class PointAttachment extends Attachment {
float y = cos * bone.getC() + sin * bone.getD();
return (float)Math.atan2(y, x) * radDeg;
}
public Attachment copy () {
PointAttachment copy = new PointAttachment(name);
copy.name = name;
copy.x = x;
copy.y = y;
copy.rotation = rotation;
copy.color.set(color);
return copy;
}
}

View File

@ -264,4 +264,21 @@ public class RegionAttachment extends Attachment {
public void setPath (String path) {
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;
System.arraycopy(uvs, 0, copy.uvs, 0, uvs.length);
System.arraycopy(offset, 0, copy.offset, 0, offset.length);
copy.color.set(color);
return copy;
}
}

View File

@ -49,4 +49,10 @@ public class SkeletonAttachment extends Attachment {
public void setSkeleton (Skeleton skeleton) {
this.skeleton = skeleton;
}
public Attachment copy () {
SkeletonAttachment copy = new SkeletonAttachment(name);
copy.skeleton = skeleton;
return copy;
}
}

View File

@ -31,14 +31,13 @@
package com.esotericsoftware.spine.attachments;
import com.badlogic.gdx.utils.FloatArray;
import com.esotericsoftware.spine.Bone;
import com.esotericsoftware.spine.Skeleton;
import com.esotericsoftware.spine.Slot;
/** Base class for an attachment with vertices that are transformed by one or more bones and can be deformed by a slot's
* {@link Slot#getDeform()}. */
public class VertexAttachment extends Attachment {
public abstract class VertexAttachment extends Attachment {
static private int nextID;
private final int id = (nextID() & 65535) << 11;
@ -162,6 +161,24 @@ public class VertexAttachment extends Attachment {
return id;
}
/** Internal method used by VertexAttachment subclasses to copy basic data. Does not copy id (generated) and name (set on
* construction). **/
void copyTo (VertexAttachment attachment) {
if (bones != null) {
attachment.bones = new int[bones.length];
System.arraycopy(bones, 0, attachment.bones, 0, bones.length);
} else
attachment.bones = null;
if (vertices != null) {
attachment.vertices = new float[vertices.length];
System.arraycopy(vertices, 0, attachment.vertices, 0, vertices.length);
} else
attachment.vertices = null;
attachment.worldVerticesLength = worldVerticesLength;
}
static private synchronized int nextID () {
return nextID++;
}