Эх сурвалжийг харах

Initial commit for spring constraints.

Nathan Sweet 4 жил өмнө
parent
commit
772f69be41

+ 95 - 31
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java

@@ -55,6 +55,7 @@ public class Skeleton {
 	final Array<IkConstraint> ikConstraints;
 	final Array<TransformConstraint> transformConstraints;
 	final Array<PathConstraint> pathConstraints;
+	final Array<SpringConstraint> springConstraints;
 	final Array<Updatable> updateCache = new Array();
 	@Null Skin skin;
 	final Color color;
@@ -101,6 +102,10 @@ public class Skeleton {
 		for (PathConstraintData pathConstraintData : data.pathConstraints)
 			pathConstraints.add(new PathConstraint(pathConstraintData, this));
 
+		springConstraints = new Array(data.springConstraints.size);
+		for (SpringConstraintData springConstraintData : data.springConstraints)
+			springConstraints.add(new SpringConstraint(springConstraintData, this));
+
 		color = new Color(1, 1, 1, 1);
 
 		updateCache();
@@ -146,6 +151,10 @@ public class Skeleton {
 		for (PathConstraint pathConstraint : skeleton.pathConstraints)
 			pathConstraints.add(new PathConstraint(pathConstraint, this));
 
+		springConstraints = new Array(skeleton.springConstraints.size);
+		for (SpringConstraint springConstraint : skeleton.springConstraints)
+			springConstraints.add(new SpringConstraint(springConstraint, this));
+
 		skin = skeleton.skin;
 		color = new Color(skeleton.color);
 		time = skeleton.time;
@@ -180,11 +189,11 @@ public class Skeleton {
 			}
 		}
 
-		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;
+		int ikCount = ikConstraints.size, transformCount = transformConstraints.size, pathCount = pathConstraints.size,
+			springCount = springConstraints.size;
+		Object[] ikConstraints = this.ikConstraints.items, transformConstraints = this.transformConstraints.items,
+			pathConstraints = this.pathConstraints.items, springConstraints = this.springConstraints.items;
+		int constraintCount = ikCount + transformCount + pathCount + springCount;
 		outer:
 		for (int i = 0; i < constraintCount; i++) {
 			for (int ii = 0; ii < ikCount; ii++) {
@@ -208,6 +217,13 @@ public class Skeleton {
 					continue outer;
 				}
 			}
+			for (int ii = 0; ii < springCount; ii++) {
+				SpringConstraint constraint = (SpringConstraint)springConstraints[ii];
+				if (constraint.data.order == i) {
+					sortSpringConstraint(constraint);
+					continue outer;
+				}
+			}
 		}
 
 		for (int i = 0; i < boneCount; i++)
@@ -239,25 +255,25 @@ public class Skeleton {
 		}
 	}
 
-	private void sortPathConstraint (PathConstraint constraint) {
-		constraint.active = constraint.target.bone.active
+	private void sortTransformConstraint (TransformConstraint constraint) {
+		constraint.active = constraint.target.active
 			&& (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true)));
 		if (!constraint.active) 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);
-
-		Attachment attachment = slot.attachment;
-		if (attachment instanceof PathAttachment) sortPathConstraintAttachment(attachment, slotBone);
+		sortBone(constraint.target);
 
 		Object[] constrained = constraint.bones.items;
 		int boneCount = constraint.bones.size;
-		for (int i = 0; i < boneCount; i++)
-			sortBone((Bone)constrained[i]);
+		if (constraint.data.local) {
+			for (int i = 0; i < boneCount; i++) {
+				Bone child = (Bone)constrained[i];
+				sortBone(child.parent);
+				sortBone(child);
+			}
+		} else {
+			for (int i = 0; i < boneCount; i++)
+				sortBone((Bone)constrained[i]);
+		}
 
 		updateCache.add(constraint);
 
@@ -267,25 +283,25 @@ public class Skeleton {
 			((Bone)constrained[i]).sorted = true;
 	}
 
-	private void sortTransformConstraint (TransformConstraint constraint) {
-		constraint.active = constraint.target.active
+	private void sortPathConstraint (PathConstraint constraint) {
+		constraint.active = constraint.target.bone.active
 			&& (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true)));
 		if (!constraint.active) return;
 
-		sortBone(constraint.target);
+		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);
+
+		Attachment attachment = slot.attachment;
+		if (attachment instanceof PathAttachment) sortPathConstraintAttachment(attachment, slotBone);
 
 		Object[] constrained = constraint.bones.items;
 		int boneCount = constraint.bones.size;
-		if (constraint.data.local) {
-			for (int i = 0; i < boneCount; i++) {
-				Bone child = (Bone)constrained[i];
-				sortBone(child.parent);
-				sortBone(child);
-			}
-		} else {
-			for (int i = 0; i < boneCount; i++)
-				sortBone((Bone)constrained[i]);
-		}
+		for (int i = 0; i < boneCount; i++)
+			sortBone((Bone)constrained[i]);
 
 		updateCache.add(constraint);
 
@@ -319,6 +335,23 @@ public class Skeleton {
 		}
 	}
 
+	private void sortSpringConstraint (SpringConstraint constraint) {
+		constraint.active = !constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true));
+		if (!constraint.active) return;
+
+		Object[] constrained = constraint.bones.items;
+		int boneCount = constraint.bones.size;
+		for (int i = 0; i < boneCount; i++)
+			sortBone((Bone)constrained[i]);
+
+		updateCache.add(constraint);
+
+		for (int i = 0; i < boneCount; i++)
+			sortReset(((Bone)constrained[i]).children);
+		for (int i = 0; i < boneCount; i++)
+			((Bone)constrained[i]).sorted = true;
+	}
+
 	private void sortBone (Bone bone) {
 		if (bone.sorted) return;
 		Bone parent = bone.parent;
@@ -435,6 +468,20 @@ public class Skeleton {
 			constraint.mixX = data.mixX;
 			constraint.mixY = data.mixY;
 		}
+
+		Object[] springConstraints = this.springConstraints.items;
+		for (int i = 0, n = this.springConstraints.size; i < n; i++) {
+			SpringConstraint constraint = (SpringConstraint)springConstraints[i];
+			SpringConstraintData data = constraint.data;
+			constraint.mix = data.mix;
+			constraint.friction = data.friction;
+			constraint.gravity = data.gravity;
+			constraint.wind = data.wind;
+			constraint.stiffness = data.stiffness;
+			constraint.damping = data.damping;
+			constraint.rope = data.rope;
+			constraint.stretch = data.stretch;
+		}
 	}
 
 	/** Sets the slots and draw order to their setup pose values. */
@@ -641,6 +688,23 @@ public class Skeleton {
 		return null;
 	}
 
+	/** The skeleton's spring constraints. */
+	public Array<SpringConstraint> getSpringConstraints () {
+		return springConstraints;
+	}
+
+	/** Finds a spring constraint by comparing each spring constraint's name. It is more efficient to cache the results of this
+	 * method than to call it repeatedly. */
+	public @Null SpringConstraint findSpringConstraint (String constraintName) {
+		if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
+		Object[] springConstraints = this.springConstraints.items;
+		for (int i = 0, n = this.springConstraints.size; i < n; i++) {
+			SpringConstraint constraint = (SpringConstraint)springConstraints[i];
+			if (constraint.data.name.equals(constraintName)) return constraint;
+		}
+		return null;
+	}
+
 	/** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose.
 	 * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB.
 	 * @param size An output value, the width and height of the AABB.

+ 20 - 0
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java

@@ -47,6 +47,7 @@ public class SkeletonData {
 	final Array<IkConstraintData> ikConstraints = new Array();
 	final Array<TransformConstraintData> transformConstraints = new Array();
 	final Array<PathConstraintData> pathConstraints = new Array();
+	final Array<SpringConstraintData> springConstraints = new Array();
 	float x, y, width, height;
 	@Null String version, hash;
 
@@ -215,6 +216,25 @@ public class SkeletonData {
 		return null;
 	}
 
+	// --- Spring constraints
+
+	/** The skeleton's spring constraints. */
+	public Array<SpringConstraintData> getSpringConstraints () {
+		return springConstraints;
+	}
+
+	/** Finds a spring constraint by comparing each spring constraint's name. It is more efficient to cache the results of this
+	 * method than to call it multiple times. */
+	public @Null SpringConstraintData findSpringConstraint (String constraintName) {
+		if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
+		Object[] springConstraints = this.springConstraints.items;
+		for (int i = 0, n = this.springConstraints.size; i < n; i++) {
+			SpringConstraintData constraint = (SpringConstraintData)springConstraints[i];
+			if (constraint.name.equals(constraintName)) return constraint;
+		}
+		return null;
+	}
+
 	// ---
 
 	/** The skeleton's name, which by default is the name of the skeleton data file when possible, or null when a name hasn't been

+ 168 - 0
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SpringConstraint.java

@@ -0,0 +1,168 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, 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;
+
+import com.badlogic.gdx.utils.Array;
+
+/** Stores the current pose for a spring constraint. A spring constraint applies physics to bones.
+ * <p>
+ * See <a href="http://esotericsoftware.com/spine-spring-constraints">Spring constraints</a> in the Spine User Guide. */
+public class SpringConstraint implements Updatable {
+	final SpringConstraintData data;
+	final Array<Bone> bones;
+	float mix, friction, gravity, wind, stiffness, damping;
+	boolean rope, stretch;
+
+	boolean active;
+
+	public SpringConstraint (SpringConstraintData data, Skeleton skeleton) {
+		if (data == null) throw new IllegalArgumentException("data cannot be null.");
+		if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
+		this.data = data;
+		mix = data.mix;
+		friction = data.friction;
+		gravity = data.gravity;
+		wind = data.wind;
+		stiffness = data.stiffness;
+		damping = data.damping;
+		rope = data.rope;
+		stretch = data.stretch;
+
+		bones = new Array(data.bones.size);
+		for (BoneData boneData : data.bones)
+			bones.add(skeleton.bones.get(boneData.index));
+	}
+
+	/** Copy constructor. */
+	public SpringConstraint (SpringConstraint constraint, Skeleton skeleton) {
+		if (constraint == null) throw new IllegalArgumentException("constraint cannot be null.");
+		if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
+		data = constraint.data;
+		bones = new Array(constraint.bones.size);
+		for (Bone bone : constraint.bones)
+			bones.add(skeleton.bones.get(bone.data.index));
+		mix = constraint.mix;
+		friction = constraint.friction;
+		gravity = constraint.gravity;
+		wind = constraint.wind;
+		stiffness = constraint.stiffness;
+		damping = constraint.damping;
+		rope = constraint.rope;
+		stretch = constraint.stretch;
+	}
+
+	/** Applies the constraint to the constrained bones. */
+	public void update () {
+
+	}
+
+	/** The bones that will be modified by this spring constraint. */
+	public Array<Bone> getBones () {
+		return bones;
+	}
+
+	/** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
+	public float getMix () {
+		return mix;
+	}
+
+	public void setMix (float mix) {
+		this.mix = mix;
+	}
+
+	public float getFriction () {
+		return friction;
+	}
+
+	public void setFriction (float friction) {
+		this.friction = friction;
+	}
+
+	public float getGravity () {
+		return gravity;
+	}
+
+	public void setGravity (float gravity) {
+		this.gravity = gravity;
+	}
+
+	public float getWind () {
+		return wind;
+	}
+
+	public void setWind (float wind) {
+		this.wind = wind;
+	}
+
+	public float getStiffness () {
+		return stiffness;
+	}
+
+	public void setStiffness (float stiffness) {
+		this.stiffness = stiffness;
+	}
+
+	public float getDamping () {
+		return damping;
+	}
+
+	public void setDamping (float damping) {
+		this.damping = damping;
+	}
+
+	public boolean getRope () {
+		return rope;
+	}
+
+	public void setRope (boolean rope) {
+		this.rope = rope;
+	}
+
+	public boolean getStretch () {
+		return stretch;
+	}
+
+	public void setStretch (boolean stretch) {
+		this.stretch = stretch;
+	}
+
+	public boolean isActive () {
+		return active;
+	}
+
+	/** The spring constraint's setup pose data. */
+	public SpringConstraintData getData () {
+		return data;
+	}
+
+	public String toString () {
+		return data.name;
+	}
+}

+ 115 - 0
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SpringConstraintData.java

@@ -0,0 +1,115 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated January 1, 2020. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2020, 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;
+
+import com.badlogic.gdx.utils.Array;
+
+/** Stores the setup pose for a {@link SpringConstraint}.
+ * <p>
+ * See <a href="http://esotericsoftware.com/spine-spring-constraints">Spring constraints</a> in the Spine User Guide. */
+public class SpringConstraintData extends ConstraintData {
+	final Array<BoneData> bones = new Array();
+	float mix, friction, gravity, wind, stiffness, damping;
+	boolean rope, stretch;
+
+	public SpringConstraintData (String name) {
+		super(name);
+	}
+
+	/** The bones that are constrained by this spring constraint. */
+	public Array<BoneData> getBones () {
+		return bones;
+	}
+
+	/** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
+	public float getMix () {
+		return mix;
+	}
+
+	public void setMix (float mix) {
+		this.mix = mix;
+	}
+
+	public float getFriction () {
+		return friction;
+	}
+
+	public void setFriction (float friction) {
+		this.friction = friction;
+	}
+
+	public float getGravity () {
+		return gravity;
+	}
+
+	public void setGravity (float gravity) {
+		this.gravity = gravity;
+	}
+
+	public float getWind () {
+		return wind;
+	}
+
+	public void setWind (float wind) {
+		this.wind = wind;
+	}
+
+	public float getStiffness () {
+		return stiffness;
+	}
+
+	public void setStiffness (float stiffness) {
+		this.stiffness = stiffness;
+	}
+
+	public float getDamping () {
+		return damping;
+	}
+
+	public void setDamping (float damping) {
+		this.damping = damping;
+	}
+
+	public boolean getRope () {
+		return rope;
+	}
+
+	public void setRope (boolean rope) {
+		this.rope = rope;
+	}
+
+	public boolean getStretch () {
+		return stretch;
+	}
+
+	public void setStretch (boolean stretch) {
+		this.stretch = stretch;
+	}
+}