From 6205e51752df9be7000cb479560c8ffd7b5b76eb Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Tue, 30 Apr 2019 13:40:06 +0200 Subject: [PATCH] Added skin-specific bones and constraints which are only updated if the skeleton's current skin contains them. --- .../src/com/esotericsoftware/spine/Bone.java | 2 +- .../com/esotericsoftware/spine/BoneData.java | 12 +++++ .../esotericsoftware/spine/Constraint.java | 37 ------------- .../spine/ConstraintData.java | 44 +++++++++++++++ .../esotericsoftware/spine/IkConstraint.java | 6 +-- .../spine/IkConstraintData.java | 25 +-------- .../spine/PathConstraint.java | 6 +-- .../spine/PathConstraintData.java | 25 +-------- .../com/esotericsoftware/spine/Skeleton.java | 48 ++++++++++------- .../spine/SkeletonBinary.java | 27 +++++++--- .../esotericsoftware/spine/SkeletonJson.java | 54 +++++++++++++------ .../src/com/esotericsoftware/spine/Skin.java | 12 +++++ .../spine/TransformConstraint.java | 6 +-- .../spine/TransformConstraintData.java | 25 +-------- 14 files changed, 163 insertions(+), 166 deletions(-) delete mode 100644 spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java create mode 100644 spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/ConstraintData.java diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java index 028106efe..834e53967 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java @@ -55,7 +55,7 @@ public class Bone implements Updatable { float a, b, worldX; float c, d, worldY; - boolean sorted; + boolean sorted, update; /** @param parent May be null. */ public Bone (BoneData data, Skeleton skeleton, Bone parent) { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java index 0965f95e6..b9d74fa39 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java @@ -40,6 +40,7 @@ public class BoneData { float length; float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY; TransformMode transformMode = TransformMode.normal; + boolean skinRequired; // Nonessential. final Color color = new Color(0.61f, 0.61f, 0.61f, 1); // 9b9b9bff @@ -176,6 +177,17 @@ public class BoneData { this.transformMode = transformMode; } + /** When true, {@link Skeleton#updateWorldTransform()} only updates this bone if the {@link Skeleton#getSkin()} contains this + * bone. + * @see Skin#getBones() */ + public boolean getSkinRequired () { + return skinRequired; + } + + public void setSkinRequired (boolean skinRequired) { + this.skinRequired = skinRequired; + } + /** The color of the bone as it was in Spine. Available only when nonessential data was exported. Bones are not usually * rendered at runtime. */ public Color getColor () { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java deleted file mode 100644 index 8864b026b..000000000 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * Spine Runtimes Software License v2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "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 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 THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -package com.esotericsoftware.spine; - -/** The interface for all constraints. */ -public interface Constraint extends Updatable { - /** The ordinal for the order a skeleton's constraints will be applied. */ - public int getOrder (); -} diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/ConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/ConstraintData.java new file mode 100644 index 000000000..4a706e297 --- /dev/null +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/ConstraintData.java @@ -0,0 +1,44 @@ + +package com.esotericsoftware.spine; + +/** The base class for all constraint datas. */ +abstract public class ConstraintData { + final String name; + int order; + boolean skinRequired; + + public ConstraintData (String name) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + this.name = name; + } + + /** The constraint's name, which is unique across all constraints in the skeleton of the same type. */ + public String getName () { + return name; + } + + /** The ordinal of this constraint for the order a skeleton's constraints will be applied by + * {@link Skeleton#updateWorldTransform()}. */ + public int getOrder () { + return order; + } + + public void setOrder (int order) { + this.order = order; + } + + /** When true, {@link Skeleton#updateWorldTransform()} only updates this constraint if the {@link Skeleton#getSkin()} contains + * this constraint. + * @see Skin#getConstraints() */ + public boolean getSkinRequired () { + return skinRequired; + } + + public void setSkinRequired (boolean skinRequired) { + this.skinRequired = skinRequired; + } + + public String toString () { + return name; + } +} diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index 4fbcebab4..29b5895f8 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -38,7 +38,7 @@ import com.badlogic.gdx.utils.Array; * the last bone is as close to the target bone as possible. *

* See IK constraints in the Spine User Guide. */ -public class IkConstraint implements Constraint { +public class IkConstraint implements Updatable { final IkConstraintData data; final Array bones; Bone target; @@ -94,10 +94,6 @@ public class IkConstraint implements Constraint { } } - public int getOrder () { - return data.order; - } - /** The bones that will be modified by this IK constraint. */ public Array getBones () { return bones; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java index 0ef63a675..a78f97428 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java @@ -35,9 +35,7 @@ import com.badlogic.gdx.utils.Array; /** Stores the setup pose for an {@link IkConstraint}. *

* See IK constraints in the Spine User Guide. */ -public class IkConstraintData { - final String name; - int order; +public class IkConstraintData extends ConstraintData { final Array bones = new Array(); BoneData target; int bendDirection = 1; @@ -45,22 +43,7 @@ public class IkConstraintData { float mix = 1; public IkConstraintData (String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.name = name; - } - - /** The IK constraint's name, which is unique within the skeleton. */ - public String getName () { - return name; - } - - /** See {@link Constraint#getOrder()}. */ - public int getOrder () { - return order; - } - - public void setOrder (int order) { - this.order = order; + super(name); } /** The bones that are constrained by this IK constraint. */ @@ -124,8 +107,4 @@ public class IkConstraintData { public void setUniform (boolean uniform) { this.uniform = uniform; } - - public String toString () { - return name; - } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java index 4901f4522..b26f4bfe4 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -43,7 +43,7 @@ import com.esotericsoftware.spine.utils.SpineUtils; * constrained bones so they follow a {@link PathAttachment}. *

* See Path constraints in the Spine User Guide. */ -public class PathConstraint implements Constraint { +public class PathConstraint implements Updatable { static private final int NONE = -1, BEFORE = -2, AFTER = -3; static private final float epsilon = 0.00001f; @@ -449,10 +449,6 @@ public class PathConstraint implements Constraint { } } - public int getOrder () { - return data.order; - } - /** The position along the path. */ public float getPosition () { return position; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java index 4007a142c..62ccec5f2 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java @@ -35,9 +35,7 @@ import com.badlogic.gdx.utils.Array; /** Stores the setup pose for a {@link PathConstraint}. *

* See Path constraints in the Spine User Guide. */ -public class PathConstraintData { - final String name; - int order; +public class PathConstraintData extends ConstraintData { final Array bones = new Array(); SlotData target; PositionMode positionMode; @@ -47,22 +45,7 @@ public class PathConstraintData { float position, spacing, rotateMix, translateMix; public PathConstraintData (String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.name = name; - } - - /** The path constraint's name, which is unique within the skeleton. */ - public String getName () { - return name; - } - - /** See {@link Constraint#getOrder()}. */ - public int getOrder () { - return order; - } - - public void setOrder (int order) { - this.order = order; + super(name); } /** The bones that will be modified by this path constraint. */ @@ -151,10 +134,6 @@ public class PathConstraintData { this.translateMix = translateMix; } - public String toString () { - return name; - } - /** Controls how the first bone is positioned along the path. *

* See Position mode in the Spine User Guide. */ diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java index 498dd54d2..819167734 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -156,40 +156,44 @@ public class Skeleton { updateCache(); } - /** Caches information about bones and constraints. Must be called if bones, constraints, or weighted path attachments are - * added or removed. */ + /** Caches information about bones and constraints. Must be called if the skin is changed or if bones, constraints, or weighted + * path attachments are added or removed. */ public void updateCache () { Array updateCache = this.updateCache; updateCache.clear(); updateCacheReset.clear(); - Array bones = this.bones; - for (int i = 0, n = bones.size; i < n; i++) - bones.get(i).sorted = false; + int boneCount = bones.size; + Object[] bones = this.bones.items; + for (int i = 0; i < boneCount; i++) { + Bone bone = (Bone)bones[i]; + bone.update = !bone.data.skinRequired || (skin != null && skin.bones.contains(bone.data, true)); + bone.sorted = !bone.update; + } - Array ikConstraints = this.ikConstraints; - Array transformConstraints = this.transformConstraints; - Array pathConstraints = this.pathConstraints; int ikCount = ikConstraints.size, transformCount = transformConstraints.size, pathCount = pathConstraints.size; + Object[] ikConstraints = this.ikConstraints.items; + Object[] transformConstraints = this.transformConstraints.items; + Object[] pathConstraints = this.pathConstraints.items; int constraintCount = ikCount + transformCount + pathCount; outer: for (int i = 0; i < constraintCount; i++) { for (int ii = 0; ii < ikCount; ii++) { - IkConstraint constraint = ikConstraints.get(ii); + IkConstraint constraint = (IkConstraint)ikConstraints[ii]; if (constraint.data.order == i) { sortIkConstraint(constraint); continue outer; } } for (int ii = 0; ii < transformCount; ii++) { - TransformConstraint constraint = transformConstraints.get(ii); + TransformConstraint constraint = (TransformConstraint)transformConstraints[ii]; if (constraint.data.order == i) { sortTransformConstraint(constraint); continue outer; } } for (int ii = 0; ii < pathCount; ii++) { - PathConstraint constraint = pathConstraints.get(ii); + PathConstraint constraint = (PathConstraint)pathConstraints[ii]; if (constraint.data.order == i) { sortPathConstraint(constraint); continue outer; @@ -197,11 +201,13 @@ public class Skeleton { } } - for (int i = 0, n = bones.size; i < n; i++) - sortBone(bones.get(i)); + for (int i = 0; i < boneCount; i++) + sortBone((Bone)bones[i]); } private void sortIkConstraint (IkConstraint constraint) { + if (constraint.data.skinRequired && (skin == null || !skin.constraints.contains(constraint.data, true))) return; + Bone target = constraint.target; sortBone(target); @@ -221,14 +227,14 @@ public class Skeleton { } private void sortPathConstraint (PathConstraint constraint) { + if (constraint.data.skinRequired && (skin == null || !skin.constraints.contains(constraint.data, true))) return; + Slot slot = constraint.target; int slotIndex = slot.getData().index; Bone slotBone = slot.bone; if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone); if (data.defaultSkin != null && data.defaultSkin != skin) sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone); - for (int ii = 0, nn = data.skins.size; ii < nn; ii++) - sortPathConstraintAttachment(data.skins.get(ii), slotIndex, slotBone); Attachment attachment = slot.attachment; if (attachment instanceof PathAttachment) sortPathConstraintAttachment(attachment, slotBone); @@ -247,6 +253,8 @@ public class Skeleton { } private void sortTransformConstraint (TransformConstraint constraint) { + if (constraint.data.skinRequired && (skin == null || !skin.constraints.contains(constraint.data, true))) return; + sortBone(constraint.target); Array constrained = constraint.bones; @@ -302,6 +310,7 @@ public class Skeleton { private void sortReset (Array bones) { for (int i = 0, n = bones.size; i < n; i++) { Bone bone = bones.get(i); + if (!bone.update) continue; if (bone.sorted) sortReset(bone.children); bone.sorted = false; } @@ -332,8 +341,8 @@ public class Skeleton { updateCache.get(i).update(); } - /** Updates the world transform for each bone and applies all constraints. The root bone will be temporarily parented to the - * specified bone. + /** Temporarily sets the root bone as a child of the specified bone, then updates the world transform for each bone and applies + * all constraints. *

* See World transforms in the Spine * Runtimes Guide. */ @@ -354,8 +363,7 @@ public class Skeleton { bone.appliedValid = true; } - // Apply the parent bone transform to the root bone. The root bone - // always inherits scale, rotation and reflection. + // Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection. Bone rootBone = getRootBone(); float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; rootBone.worldX = pa * x + pb * y + parent.worldX; @@ -515,6 +523,7 @@ public class Skeleton { * skeleton is rendered to allow any attachment keys in the current animation(s) to hide or show attachments from the new skin. * @param newSkin May be null. */ public void setSkin (Skin newSkin) { + if (newSkin == skin) return; if (newSkin != null) { if (skin != null) newSkin.attachAll(this, skin); @@ -531,6 +540,7 @@ public class Skeleton { } } skin = newSkin; + updateCache(); } /** Finds an attachment by looking in the {@link #skin} and {@link SkeletonData#defaultSkin} using the slot name and attachment diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java index 6f19ace48..3652ee824 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -41,6 +41,7 @@ import com.badlogic.gdx.utils.DataInput; import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.IntArray; import com.badlogic.gdx.utils.SerializationException; + import com.esotericsoftware.spine.Animation.AttachmentTimeline; import com.esotericsoftware.spine.Animation.ColorTimeline; import com.esotericsoftware.spine.Animation.CurveTimeline; @@ -206,6 +207,7 @@ public class SkeletonBinary { data.shearY = input.readFloat(); data.length = input.readFloat() * scale; data.transformMode = TransformMode.values[input.readInt(true)]; + data.skinRequired = input.readBoolean(); if (nonessential) Color.rgba8888ToColor(data.color, input.readInt()); skeletonData.bones.add(data); } @@ -229,6 +231,7 @@ public class SkeletonBinary { for (int i = 0, n = input.readInt(true); i < n; i++) { IkConstraintData data = new IkConstraintData(input.readString()); data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) data.bones.add(skeletonData.bones.get(input.readInt(true))); data.target = skeletonData.bones.get(input.readInt(true)); @@ -244,6 +247,7 @@ public class SkeletonBinary { for (int i = 0, n = input.readInt(true); i < n; i++) { TransformConstraintData data = new TransformConstraintData(input.readString()); data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) data.bones.add(skeletonData.bones.get(input.readInt(true))); data.target = skeletonData.bones.get(input.readInt(true)); @@ -266,6 +270,7 @@ public class SkeletonBinary { for (int i = 0, n = input.readInt(true); i < n; i++) { PathConstraintData data = new PathConstraintData(input.readString()); data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) data.bones.add(skeletonData.bones.get(input.readInt(true))); data.target = skeletonData.slots.get(input.readInt(true)); @@ -283,7 +288,7 @@ public class SkeletonBinary { } // Default skin. - Skin defaultSkin = readSkin(input, skeletonData, "default", nonessential); + Skin defaultSkin = readSkin(input, skeletonData, true, nonessential); if (defaultSkin != null) { skeletonData.defaultSkin = defaultSkin; skeletonData.skins.add(defaultSkin); @@ -291,7 +296,7 @@ public class SkeletonBinary { // Skins. for (int i = 0, n = input.readInt(true); i < n; i++) - skeletonData.skins.add(readSkin(input, skeletonData, input.readString(), nonessential)); + skeletonData.skins.add(readSkin(input, skeletonData, false, nonessential)); // Linked meshes. for (int i = 0, n = linkedMeshes.size; i < n; i++) { @@ -341,12 +346,18 @@ public class SkeletonBinary { return skeletonData; } - /** @return May be null. */ - private Skin readSkin (DataInput input, SkeletonData skeletonData, String skinName, boolean nonessential) throws IOException { - int slotCount = input.readInt(true); - if (slotCount == 0) return null; - Skin skin = new Skin(skinName); - for (int i = 0; i < slotCount; i++) { + private Skin readSkin (DataInput input, SkeletonData skeletonData, boolean defaultSkin, boolean nonessential) + throws IOException { + Skin skin = new Skin(defaultSkin ? "default" : input.readString()); + for (int i = 0, n = input.readInt(true); i < n; i++) + skin.bones.add(skeletonData.bones.get(input.readInt(true))); + for (int i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.add(skeletonData.ikConstraints.get(input.readInt(true))); + for (int i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.add(skeletonData.transformConstraints.get(input.readInt(true))); + for (int i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.add(skeletonData.pathConstraints.get(input.readInt(true))); + for (int i = 0, n = input.readInt(true); i < n; i++) { int slotIndex = input.readInt(true); for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { String name = input.readString(); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java index 10fa289b4..e61592f97 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -149,6 +149,7 @@ public class SkeletonJson { data.shearX = boneMap.getFloat("shearX", 0); data.shearY = boneMap.getFloat("shearY", 0); data.transformMode = TransformMode.valueOf(boneMap.getString("transform", TransformMode.normal.name())); + data.skinRequired = boneMap.getBoolean("skin", false); String color = boneMap.getString("color", null); if (color != null) data.getColor().set(Color.valueOf(color)); @@ -179,11 +180,11 @@ public class SkeletonJson { for (JsonValue constraintMap = root.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { IkConstraintData data = new IkConstraintData(constraintMap.getString("name")); data.order = constraintMap.getInt("order", 0); + data.skinRequired = constraintMap.getBoolean("skin", false); - for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - String boneName = boneMap.asString(); - BoneData bone = skeletonData.findBone(boneName); - if (bone == null) throw new SerializationException("IK bone not found: " + boneName); + for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { + BoneData bone = skeletonData.findBone(entry.asString()); + if (bone == null) throw new SerializationException("IK bone not found: " + entry); data.bones.add(bone); } @@ -204,11 +205,11 @@ public class SkeletonJson { for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name")); data.order = constraintMap.getInt("order", 0); + data.skinRequired = constraintMap.getBoolean("skin", false); - for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - String boneName = boneMap.asString(); - BoneData bone = skeletonData.findBone(boneName); - if (bone == null) throw new SerializationException("Transform constraint bone not found: " + boneName); + for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { + BoneData bone = skeletonData.findBone(entry.asString()); + if (bone == null) throw new SerializationException("Transform constraint bone not found: " + entry); data.bones.add(bone); } @@ -238,11 +239,11 @@ public class SkeletonJson { for (JsonValue constraintMap = root.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) { PathConstraintData data = new PathConstraintData(constraintMap.getString("name")); data.order = constraintMap.getInt("order", 0); + data.skinRequired = constraintMap.getBoolean("skin", false); - for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - String boneName = boneMap.asString(); - BoneData bone = skeletonData.findBone(boneName); - if (bone == null) throw new SerializationException("Path bone not found: " + boneName); + for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { + BoneData bone = skeletonData.findBone(entry.asString()); + if (bone == null) throw new SerializationException("Path bone not found: " + entry); data.bones.add(bone); } @@ -266,8 +267,28 @@ public class SkeletonJson { // Skins. for (JsonValue skinMap = root.getChild("skins"); skinMap != null; skinMap = skinMap.next) { - Skin skin = new Skin(skinMap.name); - for (JsonValue slotEntry = skinMap.child; slotEntry != null; slotEntry = slotEntry.next) { + Skin skin = new Skin(skinMap.getString("name")); + for (JsonValue entry = skinMap.getChild("bones"); entry != null; entry = entry.next) { + BoneData bone = skeletonData.findBone(entry.asString()); + if (bone == null) throw new SerializationException("Skin bone not found: " + entry); + skin.bones.add(bone); + } + for (JsonValue entry = skinMap.getChild("ik"); entry != null; entry = entry.next) { + IkConstraintData constraint = skeletonData.findIkConstraint(entry.asString()); + if (constraint == null) throw new SerializationException("Skin IK constraint not found: " + entry); + skin.constraints.add(constraint); + } + for (JsonValue entry = skinMap.getChild("transform"); entry != null; entry = entry.next) { + TransformConstraintData constraint = skeletonData.findTransformConstraint(entry.asString()); + if (constraint == null) throw new SerializationException("Skin transform constraint not found: " + entry); + skin.constraints.add(constraint); + } + for (JsonValue entry = skinMap.getChild("path"); entry != null; entry = entry.next) { + PathConstraintData constraint = skeletonData.findPathConstraint(entry.asString()); + if (constraint == null) throw new SerializationException("Skin path constraint not found: " + entry); + skin.constraints.add(constraint); + } + for (JsonValue slotEntry = skinMap.getChild("attachments"); slotEntry != null; slotEntry = slotEntry.next) { SlotData slot = skeletonData.findSlot(slotEntry.name); if (slot == null) throw new SerializationException("Slot not found: " + slotEntry.name); for (JsonValue entry = slotEntry.child; entry != null; entry = entry.next) { @@ -608,7 +629,7 @@ public class SkeletonJson { } // Path constraint timelines. - for (JsonValue constraintMap = map.getChild("paths"); constraintMap != null; constraintMap = constraintMap.next) { + for (JsonValue constraintMap = map.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) { PathConstraintData data = skeletonData.findPathConstraint(constraintMap.name); if (data == null) throw new SerializationException("Path constraint not found: " + constraintMap.name); int index = skeletonData.pathConstraints.indexOf(data, true); @@ -768,9 +789,8 @@ public class SkeletonJson { if (curve == null) return; if (curve.isString() && curve.asString().equals("stepped")) timeline.setStepped(frameIndex); - else if (curve.isArray()) { + else if (curve.isArray()) timeline.setCurve(frameIndex, curve.getFloat(0), curve.getFloat(1), curve.getFloat(2), curve.getFloat(3)); - } } static class LinkedMesh { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java index 5c5f205fd..9d9addcb9 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java @@ -44,6 +44,8 @@ import com.esotericsoftware.spine.attachments.Attachment; public class Skin { final String name; final ObjectMap attachments = new ObjectMap(); + final Array bones = new Array(); + final Array constraints = new Array(); private final Key lookup = new Key(); final Pool keyPool = new Pool(64) { protected Object newObject () { @@ -105,6 +107,16 @@ public class Skin { for (Key key : attachments.keys()) keyPool.free(key); attachments.clear(1024); + bones.clear(); + constraints.clear(); + } + + public Array getBones () { + return bones; + } + + public Array getConstraints () { + return constraints; } public int size () { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java index 5376f9288..16640a221 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java @@ -39,7 +39,7 @@ import com.badlogic.gdx.utils.Array; * bones to match that of the target bone. *

* See Transform constraints in the Spine User Guide. */ -public class TransformConstraint implements Constraint { +public class TransformConstraint implements Updatable { final TransformConstraintData data; final Array bones; Bone target; @@ -289,10 +289,6 @@ public class TransformConstraint implements Constraint { } } - public int getOrder () { - return data.order; - } - /** The bones that will be modified by this transform constraint. */ public Array getBones () { return bones; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java index a4c048352..4428a9120 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java @@ -35,9 +35,7 @@ import com.badlogic.gdx.utils.Array; /** Stores the setup pose for a {@link TransformConstraint}. *

* See Transform constraints in the Spine User Guide. */ -public class TransformConstraintData { - final String name; - int order; +public class TransformConstraintData extends ConstraintData { final Array bones = new Array(); BoneData target; float rotateMix, translateMix, scaleMix, shearMix; @@ -45,22 +43,7 @@ public class TransformConstraintData { boolean relative, local; public TransformConstraintData (String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.name = name; - } - - /** The transform constraint's name, which is unique within the skeleton. */ - public String getName () { - return name; - } - - /** See {@link Constraint#getOrder()}. */ - public int getOrder () { - return order; - } - - public void setOrder (int order) { - this.order = order; + super(name); } /** The bones that will be modified by this transform constraint. */ @@ -183,8 +166,4 @@ public class TransformConstraintData { public void setLocal (boolean local) { this.local = local; } - - public String toString () { - return name; - } }