Просмотр исходного кода

[libgdx] Breaking change: SkeletonRenderer no longer handles updating skeletons attached via SkeletonAttachment. Introduced new Skeleton#updateWorldTransform(Bone) that must be explicitely called by the user before rendering skeletons including attached skeletons. See SkeletonAttachmentTest for an example. Closes #1005

badlogic 8 лет назад
Родитель
Сommit
69923111b9

+ 3 - 1
CHANGELOG.md

@@ -154,6 +154,8 @@
   * Added `stride` parameter to `VertexAttachment.computeWorldVertices`.
   * Added `stride` parameter to `VertexAttachment.computeWorldVertices`.
   * Removed `RegionAttachment.vertices` field. The vertices array is provided to `RegionAttachment.computeWorldVertices` by the API user now.
   * Removed `RegionAttachment.vertices` field. The vertices array is provided to `RegionAttachment.computeWorldVertices` by the API user now.
   * Removed `RegionAttachment.updateWorldVertices`, added `RegionAttachment.computeWorldVertices`. The new method now computes the x/y positions of the 4 vertices of the corner and places them in the provided `worldVertices` array, starting at `offset`, then moving by `stride` array elements when advancing to the next vertex. This allows to directly compose the vertex buffer and avoids a copy. The computation of the full vertices, including vertex colors and texture coordinates, is now done by the backend's respective renderer.
   * Removed `RegionAttachment.updateWorldVertices`, added `RegionAttachment.computeWorldVertices`. The new method now computes the x/y positions of the 4 vertices of the corner and places them in the provided `worldVertices` array, starting at `offset`, then moving by `stride` array elements when advancing to the next vertex. This allows to directly compose the vertex buffer and avoids a copy. The computation of the full vertices, including vertex colors and texture coordinates, is now done by the backend's respective renderer.
+  * Skeleton attachments: Moved update of attached skeleton out of libGDX `SkeletonRenderer`, added overloaded method `Skeleton#updateWorldTransform(Bone), used for `SkeletonAttachment`. You now MUST call this new method
+  with the bone of the parent skeleton to which the child skeleton is attached. See `SkeletonAttachmentTest` for and example.
  * **Additions**  
  * **Additions**  
   * Added support for local and relative transform constraint calculation, including additional fields in `TransformConstraintData`
   * Added support for local and relative transform constraint calculation, including additional fields in `TransformConstraintData`
   * Added `Bone.localToWorldRotation`(rotation given relative to x-axis, counter-clockwise, in degrees).  
   * Added `Bone.localToWorldRotation`(rotation given relative to x-axis, counter-clockwise, in degrees).  
@@ -162,7 +164,7 @@
   * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
   * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
   * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
   * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
-  * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
+  * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans  
 
 
 ### libGDX
 ### libGDX
  * Fixed renderer to work with 3.6 changes
  * Fixed renderer to work with 3.6 changes

+ 5 - 2
spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SkeletonAttachmentTest.java

@@ -46,6 +46,7 @@ public class SkeletonAttachmentTest extends ApplicationAdapter {
 
 
 	Skeleton spineboy, goblin;
 	Skeleton spineboy, goblin;
 	AnimationState spineboyState, goblinState;
 	AnimationState spineboyState, goblinState;
+	Bone attachmentBone;
 
 
 	public void create () {
 	public void create () {
 		camera = new OrthographicCamera();
 		camera = new OrthographicCamera();
@@ -82,7 +83,9 @@ public class SkeletonAttachmentTest extends ApplicationAdapter {
 			// Instead of a right shoulder, spineboy will have a goblin!
 			// Instead of a right shoulder, spineboy will have a goblin!
 			SkeletonAttachment skeletonAttachment = new SkeletonAttachment("goblin");
 			SkeletonAttachment skeletonAttachment = new SkeletonAttachment("goblin");
 			skeletonAttachment.setSkeleton(goblin);
 			skeletonAttachment.setSkeleton(goblin);
-			spineboy.findSlot("front-upper-arm").setAttachment(skeletonAttachment);
+			Slot slot = spineboy.findSlot("front-upper-arm");
+			slot.setAttachment(skeletonAttachment);
+			attachmentBone = slot.getBone();
 		}
 		}
 	}
 	}
 
 
@@ -93,7 +96,7 @@ public class SkeletonAttachmentTest extends ApplicationAdapter {
 
 
 		goblinState.update(Gdx.graphics.getDeltaTime());
 		goblinState.update(Gdx.graphics.getDeltaTime());
 		goblinState.apply(goblin);
 		goblinState.apply(goblin);
-		goblin.updateWorldTransform();
+		goblin.updateWorldTransform(attachmentBone);
 
 
 		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
 		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
 
 

+ 59 - 0
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java

@@ -30,6 +30,9 @@
 
 
 package com.esotericsoftware.spine;
 package com.esotericsoftware.spine;
 
 
+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.graphics.Color;
 import com.badlogic.gdx.math.Vector2;
 import com.badlogic.gdx.math.Vector2;
 import com.badlogic.gdx.utils.Array;
 import com.badlogic.gdx.utils.Array;
@@ -328,6 +331,62 @@ public class Skeleton {
 		for (int i = 0, n = updateCache.size; i < n; i++)
 		for (int i = 0, n = updateCache.size; i < n; i++)
 			updateCache.get(i).update();
 			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.
+	 * <p>
+	 * See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
+	 * Runtimes Guide. */
+	public void updateWorldTransform (Bone parent) {
+		// This partial update avoids computing the world transform for constrained bones when 1) the bone is not updated
+		// before the constraint, 2) the constraint only needs to access the applied local transform, and 3) the constraint calls
+		// updateWorldTransform.
+		Array<Bone> updateCacheReset = this.updateCacheReset;
+		for (int i = 0, n = updateCacheReset.size; i < n; i++) {
+			Bone bone = updateCacheReset.get(i);
+			bone.ax = bone.x;
+			bone.ay = bone.y;
+			bone.arotation = bone.rotation;
+			bone.ascaleX = bone.scaleX;
+			bone.ascaleY = bone.scaleY;
+			bone.ashearX = bone.shearX;
+			bone.ashearY = bone.shearY;
+			bone.appliedValid = true;
+		}
+		
+		// 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;
+		rootBone.worldY = pc * x + pd * y + parent.worldY;
+
+		float rotationY = rootBone.rotation + 90 + rootBone.shearY;
+		float la = cosDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX;
+		float lb = cosDeg(rotationY) * rootBone.scaleY;
+		float lc = sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX;
+		float ld = sinDeg(rotationY) * rootBone.scaleY;
+		rootBone.a = pa * la + pb * lc;
+		rootBone.b = pa * lb + pb * ld;
+		rootBone.c = pc * la + pd * lc;
+		rootBone.d = pc * lb + pd * ld;
+		
+		if (flipY) {
+			rootBone.a = -rootBone.a;
+			rootBone.b = -rootBone.b;
+		}
+		if (flipX) {
+			rootBone.c = -rootBone.c;
+			rootBone.d = -rootBone.d;
+		}
+		
+		// Update everything except root bone.
+		Array<Updatable> updateCache = this.updateCache;
+		for (int i = 0, n = updateCache.size; i < n; i++) {
+			Updatable updatable = updateCache.get(i);
+			if (updatable != rootBone) updatable.update();
+		}
+	}
 
 
 	/** Sets the bones, constraints, slots, and draw order to their setup pose values. */
 	/** Sets the bones, constraints, slots, and draw order to their setup pose values. */
 	public void setToSetupPose () {
 	public void setToSetupPose () {

+ 3 - 65
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java

@@ -106,29 +106,7 @@ public class SkeletonRenderer {
 
 
 			} else if (attachment instanceof SkeletonAttachment) {
 			} else if (attachment instanceof SkeletonAttachment) {
 				Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
 				Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
-				if (attachmentSkeleton != null) {
-					Bone bone = slot.getBone();
-					Bone rootBone = attachmentSkeleton.getRootBone();
-					float oldScaleX = rootBone.getScaleX();
-					float oldScaleY = rootBone.getScaleY();
-					float oldRotation = rootBone.getRotation();
-					attachmentSkeleton.setPosition(bone.getWorldX(), bone.getWorldY());
-					// rootBone.setScaleX(1 + bone.getWorldScaleX() -
-					// oldScaleX);
-					// rootBone.setScaleY(1 + bone.getWorldScaleY() -
-					// oldScaleY);
-					// Set shear.
-					rootBone.setRotation(oldRotation + bone.getWorldRotationX());
-					attachmentSkeleton.updateWorldTransform();
-
-					draw(batch, attachmentSkeleton);
-
-					attachmentSkeleton.setX(0);
-					attachmentSkeleton.setY(0);
-					rootBone.setScaleX(oldScaleX);
-					rootBone.setScaleY(oldScaleY);
-					rootBone.setRotation(oldRotation);
-				}
+				if (attachmentSkeleton != null) draw(batch, attachmentSkeleton);
 			}
 			}
 
 
 			clipper.clipEnd(slot);
 			clipper.clipEnd(slot);
@@ -189,28 +167,7 @@ public class SkeletonRenderer {
 
 
 			} else if (attachment instanceof SkeletonAttachment) {
 			} else if (attachment instanceof SkeletonAttachment) {
 				Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
 				Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
-				if (attachmentSkeleton != null) {
-					Bone bone = slot.getBone();
-					Bone rootBone = attachmentSkeleton.getRootBone();
-					float oldScaleX = rootBone.getScaleX();
-					float oldScaleY = rootBone.getScaleY();
-					float oldRotation = rootBone.getRotation();
-					attachmentSkeleton.setPosition(bone.getWorldX(), bone.getWorldY());
-					// rootBone.setScaleX(1 + bone.getWorldScaleX() -
-					// oldScaleX);
-					// rootBone.setScaleY(1 + bone.getWorldScaleY() -
-					// oldScaleY);
-					// Also set shear.
-					rootBone.setRotation(oldRotation + bone.getWorldRotationX());
-					attachmentSkeleton.updateWorldTransform();
-
-					draw(batch, attachmentSkeleton);
-
-					attachmentSkeleton.setPosition(0, 0);
-					rootBone.setScaleX(oldScaleX);
-					rootBone.setScaleY(oldScaleY);
-					rootBone.setRotation(oldRotation);
-				}
+				if (attachmentSkeleton != null) draw(batch, attachmentSkeleton);
 			}
 			}
 
 
 			if (texture != null) {
 			if (texture != null) {
@@ -321,26 +278,7 @@ public class SkeletonRenderer {
 
 
 			} else if (attachment instanceof SkeletonAttachment) {
 			} else if (attachment instanceof SkeletonAttachment) {
 				Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
 				Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton();
-				if (attachmentSkeleton != null) {
-					Bone bone = slot.getBone();
-					Bone rootBone = attachmentSkeleton.getRootBone();
-					float oldScaleX = rootBone.getScaleX();
-					float oldScaleY = rootBone.getScaleY();
-					float oldRotation = rootBone.getRotation();
-					attachmentSkeleton.setPosition(bone.getWorldX(), bone.getWorldY());
-					// rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX);
-					// rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY);
-					// Also set shear.
-					rootBone.setRotation(oldRotation + bone.getWorldRotationX());
-					attachmentSkeleton.updateWorldTransform();
-
-					draw(batch, attachmentSkeleton);
-
-					attachmentSkeleton.setPosition(0, 0);
-					rootBone.setScaleX(oldScaleX);
-					rootBone.setScaleY(oldScaleY);
-					rootBone.setRotation(oldRotation);
-				}
+				if (attachmentSkeleton != null) draw(batch, attachmentSkeleton);
 			}
 			}
 
 
 			if (texture != null) {
 			if (texture != null) {