From 938db420162c767a18d919c1b7410e9153d2dd37 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Sun, 27 Nov 2016 02:19:50 +0100 Subject: [PATCH] Refactored attachments to fill an array rather than store vertices for rendering. --- .../spine/PathConstraint.java | 16 +-- .../com/esotericsoftware/spine/Skeleton.java | 23 ++-- .../spine/SkeletonBounds.java | 3 +- .../spine/SkeletonMeshRenderer.java | 37 +++++- .../spine/SkeletonRenderer.java | 26 +++- .../spine/SkeletonRendererDebug.java | 44 ++++--- .../src/com/esotericsoftware/spine/Slot.java | 2 +- .../spine/attachments/MeshAttachment.java | 110 ++++------------- .../spine/attachments/RegionAttachment.java | 113 ++++++++---------- .../attachments/RegionSequenceAttachment.java | 100 ---------------- .../spine/attachments/VertexAttachment.java | 23 ++-- 11 files changed, 184 insertions(+), 313 deletions(-) delete mode 100644 spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java 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 08e83a4b6..a3bea9e9e 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -211,14 +211,14 @@ public class PathConstraint implements Constraint { } else if (p < 0) { if (prevCurve != BEFORE) { prevCurve = BEFORE; - path.computeWorldVertices(target, 2, 4, world, 0); + path.computeWorldVertices(target, 2, 4, world, 0, 2); } addBeforePosition(p, world, 0, out, o); continue; } else if (p > pathLength) { if (prevCurve != AFTER) { prevCurve = AFTER; - path.computeWorldVertices(target, verticesLength - 6, 4, world, 0); + path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); } addAfterPosition(p - pathLength, world, 0, out, o); continue; @@ -239,10 +239,10 @@ public class PathConstraint implements Constraint { if (curve != prevCurve) { prevCurve = curve; if (closed && curve == curveCount) { - path.computeWorldVertices(target, verticesLength - 4, 4, world, 0); - path.computeWorldVertices(target, 0, 4, world, 4); + path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(target, 0, 4, world, 4, 2); } else - path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0); + path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); } addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, tangents || (i > 0 && space == 0)); @@ -254,15 +254,15 @@ public class PathConstraint implements Constraint { if (closed) { verticesLength += 2; world = this.world.setSize(verticesLength); - path.computeWorldVertices(target, 2, verticesLength - 4, world, 0); - path.computeWorldVertices(target, 0, 2, world, verticesLength - 4); + path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); world[verticesLength - 2] = world[0]; world[verticesLength - 1] = world[1]; } else { curveCount--; verticesLength -= 4; world = this.world.setSize(verticesLength); - path.computeWorldVertices(target, 2, verticesLength, world, 0); + path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); } // Curve lengths. 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 c772db37d..c946bc6cc 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -33,6 +33,7 @@ package com.esotericsoftware.spine; 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.attachments.Attachment; @@ -565,22 +566,30 @@ public class Skeleton { /** 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. */ - public void getBounds (Vector2 offset, Vector2 size) { + * @param size An output value, the width and height of the AABB. + * @param temp Working memory. */ + public void getBounds (Vector2 offset, Vector2 size, FloatArray temp) { if (offset == null) throw new IllegalArgumentException("offset cannot be null."); if (size == null) throw new IllegalArgumentException("size cannot be null."); Array drawOrder = this.drawOrder; float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; for (int i = 0, n = drawOrder.size; i < n; i++) { Slot slot = drawOrder.get(i); + int verticesLength = 0; float[] vertices = null; Attachment attachment = slot.attachment; - if (attachment instanceof RegionAttachment) - vertices = ((RegionAttachment)attachment).updateWorldVertices(slot, false); - else if (attachment instanceof MeshAttachment) // - vertices = ((MeshAttachment)attachment).updateWorldVertices(slot, true); + if (attachment instanceof RegionAttachment) { + verticesLength = 8; + vertices = temp.setSize(8); + ((RegionAttachment)attachment).computeWorldVertices(slot, vertices, 0, 2); + } else if (attachment instanceof MeshAttachment) { + MeshAttachment mesh = (MeshAttachment)attachment; + verticesLength = mesh.getWorldVerticesLength(); + vertices = temp.setSize(verticesLength); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } if (vertices != null) { - for (int ii = 0, nn = vertices.length; ii < nn; ii += 5) { + for (int ii = 0; ii < verticesLength; ii += 2) { float x = vertices[ii], y = vertices[ii + 1]; minX = Math.min(minX, x); minY = Math.min(minY, y); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java index d57be8a49..1946316f2 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java @@ -72,7 +72,8 @@ public class SkeletonBounds { FloatArray polygon = polygonPool.obtain(); polygons.add(polygon); - boundingBox.computeWorldVertices(slot, polygon.setSize(boundingBox.getWorldVerticesLength())); + boundingBox.computeWorldVertices(slot, 0, boundingBox.getWorldVerticesLength(), + polygon.setSize(boundingBox.getWorldVerticesLength()), 0, 2); } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java index 67d74b891..5ef9a13c0 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java @@ -30,9 +30,12 @@ package com.esotericsoftware.spine; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.FloatArray; +import com.badlogic.gdx.utils.NumberUtils; import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.RegionAttachment; import com.esotericsoftware.spine.attachments.SkeletonAttachment; @@ -41,29 +44,41 @@ import com.esotericsoftware.spine.attachments.MeshAttachment; public class SkeletonMeshRenderer extends SkeletonRenderer { static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0}; + private final FloatArray vertices = new FloatArray(32); + @SuppressWarnings("null") public void draw (PolygonSpriteBatch batch, Skeleton skeleton) { boolean premultipliedAlpha = this.premultipliedAlpha; BlendMode blendMode = null; - float[] vertices = null; + int verticesLength = 0; + float[] vertices = null, uvs = null; short[] triangles = null; + Texture texture = null; + Color color = null, skeletonColor = skeleton.color; Array drawOrder = skeleton.drawOrder; for (int i = 0, n = drawOrder.size; i < n; i++) { Slot slot = drawOrder.get(i); Attachment attachment = slot.attachment; - Texture texture = null; if (attachment instanceof RegionAttachment) { RegionAttachment region = (RegionAttachment)attachment; - vertices = region.updateWorldVertices(slot, premultipliedAlpha); + verticesLength = 20; + vertices = this.vertices.items; + region.computeWorldVertices(slot, vertices, 0, 5); triangles = quadTriangles; texture = region.getRegion().getTexture(); + uvs = region.getUVs(); + color = region.getColor(); } else if (attachment instanceof MeshAttachment) { MeshAttachment mesh = (MeshAttachment)attachment; - vertices = mesh.updateWorldVertices(slot, premultipliedAlpha); + verticesLength = (mesh.getWorldVerticesLength() >> 1) * 5; + vertices = this.vertices.setSize(verticesLength); + mesh.computeWorldVertices(slot, 0, mesh.getWorldVerticesLength(), vertices, 0, 5); triangles = mesh.getTriangles(); texture = mesh.getRegion().getTexture(); + uvs = mesh.getUVs(); + color = mesh.getColor(); } else if (attachment instanceof SkeletonAttachment) { Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton(); @@ -76,7 +91,7 @@ public class SkeletonMeshRenderer extends SkeletonRenderer { attachmentSkeleton.setPosition(bone.getWorldX(), bone.getWorldY()); // rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX); // rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY); - // Set shear. + // Also set shear. rootBone.setRotation(oldRotation + bone.getWorldRotationX()); attachmentSkeleton.updateWorldTransform(); @@ -89,6 +104,18 @@ public class SkeletonMeshRenderer extends SkeletonRenderer { } if (texture != null) { + Color slotColor = slot.getColor(); + float alpha = skeletonColor.a * slotColor.a * color.a * 255; + float c = NumberUtils.intToFloatColor(((int)alpha << 24) // + | ((int)(skeletonColor.b * slotColor.b * color.b * alpha) << 16) // + | ((int)(skeletonColor.g * slotColor.g * color.g * alpha) << 8) // + | (int)(skeletonColor.r * slotColor.r * color.r * alpha)); + for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) { + vertices[v] = c; + vertices[v + 1] = uvs[u]; + vertices[v + 2] = uvs[u + 1]; + } + BlendMode slotBlendMode = slot.data.getBlendMode(); if (slotBlendMode != blendMode) { blendMode = slotBlendMode; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java index ae6604720..65610ea9f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java @@ -30,29 +30,47 @@ package com.esotericsoftware.spine; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.NumberUtils; import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.RegionAttachment; import com.esotericsoftware.spine.attachments.SkeletonAttachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; public class SkeletonRenderer { boolean premultipliedAlpha; + private final float[] vertices = new float[20]; public void draw (T batch, Skeleton skeleton) { boolean premultipliedAlpha = this.premultipliedAlpha; + float[] vertices = this.vertices; + Color skeletonColor = skeleton.color; Array drawOrder = skeleton.drawOrder; for (int i = 0, n = drawOrder.size; i < n; i++) { Slot slot = drawOrder.get(i); Attachment attachment = slot.attachment; if (attachment instanceof RegionAttachment) { - RegionAttachment regionAttachment = (RegionAttachment)attachment; - float[] vertices = regionAttachment.updateWorldVertices(slot, premultipliedAlpha); + RegionAttachment region = (RegionAttachment)attachment; + region.computeWorldVertices(slot, vertices, 0, 5); + Color color = region.getColor(), slotColor = slot.getColor(); + float alpha = skeletonColor.a * slotColor.a * color.a * 255; + float c = NumberUtils.intToFloatColor(((int)alpha << 24) // + | ((int)(skeletonColor.b * slotColor.b * color.b * alpha) << 16) // + | ((int)(skeletonColor.g * slotColor.g * color.g * alpha) << 8) // + | (int)(skeletonColor.r * slotColor.r * color.r * alpha)); + float[] uvs = region.getUVs(); + for (int u = 0, v = 2; u < 8; u += 2, v += 5) { + vertices[v] = c; + vertices[v + 1] = uvs[u]; + vertices[v + 2] = uvs[u + 1]; + } + BlendMode blendMode = slot.data.getBlendMode(); batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest()); - batch.draw(regionAttachment.getRegion().getTexture(), vertices, 0, 20); + batch.draw(region.getRegion().getTexture(), vertices, 0, 20); } else if (attachment instanceof MeshAttachment) { throw new RuntimeException("SkeletonMeshRenderer is required to render meshes."); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java index f30cfdb00..4db4adee0 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java @@ -30,8 +30,6 @@ package com.esotericsoftware.spine; -import static com.badlogic.gdx.graphics.g2d.Batch.*; - import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; @@ -56,7 +54,7 @@ public class SkeletonRendererDebug { private boolean drawBones = true, drawRegionAttachments = true, drawBoundingBoxes = true; private boolean drawMeshHull = true, drawMeshTriangles = true, drawPaths = true; private final SkeletonBounds bounds = new SkeletonBounds(); - private final FloatArray temp = new FloatArray(); + private final FloatArray vertices = new FloatArray(32); private float scale = 1; private float boneWidth = 2; private boolean premultipliedAlpha; @@ -106,12 +104,13 @@ public class SkeletonRendererDebug { Slot slot = slots.get(i); Attachment attachment = slot.attachment; if (attachment instanceof RegionAttachment) { - RegionAttachment regionAttachment = (RegionAttachment)attachment; - float[] vertices = regionAttachment.updateWorldVertices(slot, false); - shapes.line(vertices[X1], vertices[Y1], vertices[X2], vertices[Y2]); - shapes.line(vertices[X2], vertices[Y2], vertices[X3], vertices[Y3]); - shapes.line(vertices[X3], vertices[Y3], vertices[X4], vertices[Y4]); - shapes.line(vertices[X4], vertices[Y4], vertices[X1], vertices[Y1]); + RegionAttachment region = (RegionAttachment)attachment; + float[] vertices = this.vertices.items; + 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]); + shapes.line(vertices[6], vertices[7], vertices[0], vertices[1]); } } } @@ -123,14 +122,14 @@ public class SkeletonRendererDebug { Attachment attachment = slot.attachment; if (!(attachment instanceof MeshAttachment)) continue; MeshAttachment mesh = (MeshAttachment)attachment; - mesh.updateWorldVertices(slot, false); - float[] vertices = mesh.getWorldVertices(); + float[] vertices = this.vertices.setSize(mesh.getWorldVerticesLength()); + mesh.computeWorldVertices(slot, 0, mesh.getWorldVerticesLength(), vertices, 0, 2); short[] triangles = mesh.getTriangles(); int hullLength = mesh.getHullLength(); if (drawMeshTriangles) { shapes.setColor(triangleLineColor); for (int ii = 0, nn = triangles.length; ii < nn; ii += 3) { - int v1 = triangles[ii] * 5, v2 = triangles[ii + 1] * 5, v3 = triangles[ii + 2] * 5; + int v1 = triangles[ii] * 2, v2 = triangles[ii + 1] * 2, v3 = triangles[ii + 2] * 2; shapes.triangle(vertices[v1], vertices[v1 + 1], // vertices[v2], vertices[v2 + 1], // vertices[v3], vertices[v3 + 1] // @@ -139,8 +138,7 @@ public class SkeletonRendererDebug { } if (drawMeshHull && hullLength > 0) { shapes.setColor(attachmentLineColor); - hullLength = (hullLength >> 1) * 5; - float lastX = vertices[hullLength - 5], lastY = vertices[hullLength - 4]; + float lastX = vertices[hullLength - 2], lastY = vertices[hullLength - 1]; for (int ii = 0, nn = hullLength; ii < nn; ii += 5) { float x = vertices[ii], y = vertices[ii + 1]; shapes.line(x, y, lastX, lastY); @@ -173,15 +171,15 @@ public class SkeletonRendererDebug { if (!(attachment instanceof PathAttachment)) continue; PathAttachment path = (PathAttachment)attachment; int nn = path.getWorldVerticesLength(); - float[] world = temp.setSize(nn); - path.computeWorldVertices(slot, world); + float[] vertices = this.vertices.setSize(nn); + path.computeWorldVertices(slot, 0, nn, vertices, 0, 2); Color color = path.getColor(); - float x1 = world[2], y1 = world[3], x2 = 0, y2 = 0; + float x1 = vertices[2], y1 = vertices[3], x2 = 0, y2 = 0; if (path.getClosed()) { shapes.setColor(color); - float cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1]; - x2 = world[nn - 4]; - y2 = world[nn - 3]; + float cx1 = vertices[0], cy1 = vertices[1], cx2 = vertices[nn - 2], cy2 = vertices[nn - 1]; + x2 = vertices[nn - 4]; + y2 = vertices[nn - 3]; shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); shapes.setColor(Color.LIGHT_GRAY); shapes.line(x1, y1, cx1, cy1); @@ -189,9 +187,9 @@ public class SkeletonRendererDebug { } nn -= 4; for (int ii = 4; ii < nn; ii += 6) { - float cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3]; - x2 = world[ii + 4]; - y2 = world[ii + 5]; + float cx1 = vertices[ii], cy1 = vertices[ii + 1], cx2 = vertices[ii + 2], cy2 = vertices[ii + 3]; + x2 = vertices[ii + 4]; + y2 = vertices[ii + 5]; shapes.setColor(color); shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); shapes.setColor(Color.LIGHT_GRAY); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java index 72d6b7b98..5bef94a78 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java @@ -115,7 +115,7 @@ public class Slot { /** Vertices to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a * weighted mesh, the entries are an offset for each vertex which will be added to the mesh's local vertex positions. *

- * See {@link VertexAttachment#computeWorldVertices(Slot, int, int, float[], int)} and {@link DeformTimeline}. */ + * See {@link VertexAttachment#computeWorldVertices(Slot, int, int, float[], int, int)} and {@link DeformTimeline}. */ public FloatArray getAttachmentVertices () { return attachmentVertices; } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java index 46cffde55..be5d14f83 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java @@ -33,12 +33,7 @@ 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.badlogic.gdx.utils.FloatArray; -import com.badlogic.gdx.utils.NumberUtils; import com.esotericsoftware.spine.Animation.DeformTimeline; -import com.esotericsoftware.spine.Bone; -import com.esotericsoftware.spine.Skeleton; -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. @@ -47,7 +42,7 @@ import com.esotericsoftware.spine.Slot; public class MeshAttachment extends VertexAttachment { private TextureRegion region; private String path; - private float[] regionUVs, worldVertices; + private float[] regionUVs, uvs; private short[] triangles; private final Color color = new Color(1, 1, 1, 1); private int hullLength; @@ -72,14 +67,9 @@ public class MeshAttachment extends VertexAttachment { return region; } - /** Calculates {@link #worldVertices} UVs using {@link #regionUVs} and the {@link #region}. Must be called after changing the - * region UVs or region. */ + /** Calculates {@link #uvs} using {@link #regionUVs} and the {@link #region}. Must be called after changing the region UVs or + * region. */ public void updateUVs () { - float[] regionUVs = this.regionUVs; - int verticesLength = regionUVs.length; - int worldVerticesLength = (verticesLength >> 1) * 5; - if (worldVertices == null || worldVertices.length != worldVerticesLength) worldVertices = new float[worldVerticesLength]; - float u, v, width, height; if (region == null) { u = v = 0; @@ -90,92 +80,28 @@ public class MeshAttachment extends VertexAttachment { width = region.getU2() - u; height = region.getV2() - v; } + float[] regionUVs = this.regionUVs; + if (this.uvs == null || this.uvs.length != regionUVs.length) this.uvs = new float[regionUVs.length]; + float[] uvs = this.uvs; if (region instanceof AtlasRegion && ((AtlasRegion)region).rotate) { - for (int i = 0, w = 3; i < verticesLength; i += 2, w += 5) { - worldVertices[w] = u + regionUVs[i + 1] * width; - worldVertices[w + 1] = v + height - regionUVs[i] * height; + for (int i = 0, n = uvs.length; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + height - regionUVs[i] * height; } } else { - for (int i = 0, w = 3; i < verticesLength; i += 2, w += 5) { - worldVertices[w] = u + regionUVs[i] * width; - worldVertices[w + 1] = v + regionUVs[i + 1] * height; + for (int i = 0, n = uvs.length; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; } } } - /** @return The updated world vertices. */ - public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { - Skeleton skeleton = slot.getSkeleton(); - Color skeletonColor = skeleton.getColor(), slotColor = slot.getColor(), meshColor = color; - float alpha = skeletonColor.a * slotColor.a * meshColor.a * 255; - float multiplier = premultipliedAlpha ? alpha : 255; - float color = NumberUtils.intToFloatColor( // - ((int)alpha << 24) // - | ((int)(skeletonColor.b * slotColor.b * meshColor.b * multiplier) << 16) // - | ((int)(skeletonColor.g * slotColor.g * meshColor.g * multiplier) << 8) // - | (int)(skeletonColor.r * slotColor.r * meshColor.r * multiplier)); - - FloatArray deformArray = slot.getAttachmentVertices(); - float[] vertices = this.vertices, worldVertices = this.worldVertices; - int[] bones = this.bones; - if (bones == null) { - int verticesLength = vertices.length; - if (deformArray.size > 0) vertices = deformArray.items; - Bone bone = slot.getBone(); - float x = bone.getWorldX(), y = bone.getWorldY(); - float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); - for (int v = 0, w = 0; v < verticesLength; v += 2, w += 5) { - float vx = vertices[v], vy = vertices[v + 1]; - worldVertices[w] = vx * a + vy * b + x; - worldVertices[w + 1] = vx * c + vy * d + y; - worldVertices[w + 2] = color; - } - return worldVertices; - } - Object[] skeletonBones = skeleton.getBones().items; - if (deformArray.size == 0) { - for (int w = 0, v = 0, b = 0, n = bones.length; v < n; w += 5) { - float wx = 0, wy = 0; - int nn = bones[v++] + v; - for (; v < nn; v++, b += 3) { - Bone bone = (Bone)skeletonBones[bones[v]]; - float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; - wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; - wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - worldVertices[w + 2] = color; - } - } else { - float[] deform = deformArray.items; - for (int w = 0, v = 0, b = 0, f = 0, n = bones.length; v < n; w += 5) { - float wx = 0, wy = 0; - int nn = bones[v++] + v; - for (; v < nn; v++, b += 3, f += 2) { - Bone bone = (Bone)skeletonBones[bones[v]]; - float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; - wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; - wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - worldVertices[w + 2] = color; - } - } - return worldVertices; - } - /** Returns true if the sourceAttachment is this mesh, else returns true if {@link #inheritDeform} is true and the * the sourceAttachment is the {@link #parentMesh}. */ public boolean applyDeform (VertexAttachment sourceAttachment) { return this == sourceAttachment || (inheritDeform && parentMesh == sourceAttachment); } - public float[] getWorldVertices () { - return worldVertices; - } - /** Triplets of vertex indices which describe the mesh's triangulation. */ public short[] getTriangles () { return triangles; @@ -185,6 +111,7 @@ public class MeshAttachment extends VertexAttachment { this.triangles = triangles; } + /** The UV pair for each vertex, normalized within the texture region. */ public float[] getRegionUVs () { return regionUVs; } @@ -194,6 +121,17 @@ public class MeshAttachment extends VertexAttachment { this.regionUVs = regionUVs; } + /** The UV pair for each vertex, normalized within the entire texture. + *

+ * See {@link #updateUVs}. */ + public float[] getUVs () { + return uvs; + } + + public void setUVs (float[] uvs) { + this.uvs = uvs; + } + /** The color to tint the mesh. */ public Color getColor () { return color; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java index 08981f758..d2014e523 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java @@ -30,15 +30,11 @@ package com.esotericsoftware.spine.attachments; -import static com.badlogic.gdx.graphics.g2d.Batch.*; - 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.math.MathUtils; -import com.badlogic.gdx.utils.NumberUtils; import com.esotericsoftware.spine.Bone; -import com.esotericsoftware.spine.Skeleton; import com.esotericsoftware.spine.Slot; /** An attachment that displays a textured quadrilateral. @@ -57,7 +53,7 @@ public class RegionAttachment extends Attachment { private TextureRegion region; private String path; private float x, y, scaleX = 1, scaleY = 1, rotation, width, height; - private final float[] vertices = new float[20]; + private final float[] uvs = new float[8]; private final float[] offset = new float[8]; private final Color color = new Color(1, 1, 1, 1); @@ -120,25 +116,25 @@ public class RegionAttachment extends Attachment { public void setRegion (TextureRegion region) { if (region == null) throw new IllegalArgumentException("region cannot be null."); this.region = region; - float[] vertices = this.vertices; + float[] uvs = this.uvs; if (region instanceof AtlasRegion && ((AtlasRegion)region).rotate) { - vertices[U3] = region.getU(); - vertices[V3] = region.getV2(); - vertices[U4] = region.getU(); - vertices[V4] = region.getV(); - vertices[U1] = region.getU2(); - vertices[V1] = region.getV(); - vertices[U2] = region.getU2(); - vertices[V2] = region.getV2(); + uvs[4] = region.getU(); + uvs[5] = region.getV2(); + uvs[6] = region.getU(); + uvs[7] = region.getV(); + uvs[0] = region.getU2(); + uvs[1] = region.getV(); + uvs[2] = region.getU2(); + uvs[3] = region.getV2(); } else { - vertices[U2] = region.getU(); - vertices[V2] = region.getV2(); - vertices[U3] = region.getU(); - vertices[V3] = region.getV(); - vertices[U4] = region.getU2(); - vertices[V4] = region.getV(); - vertices[U1] = region.getU2(); - vertices[V1] = region.getV2(); + uvs[2] = region.getU(); + uvs[3] = region.getV2(); + uvs[4] = region.getU(); + uvs[5] = region.getV(); + uvs[6] = region.getU2(); + uvs[7] = region.getV(); + uvs[0] = region.getU2(); + uvs[1] = region.getV2(); } } @@ -147,55 +143,42 @@ public class RegionAttachment extends Attachment { return region; } - /** @return The updated world vertices. */ - public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { - Skeleton skeleton = slot.getSkeleton(); - Color skeletonColor = skeleton.getColor(); - Color slotColor = slot.getColor(); - Color regionColor = color; - float alpha = skeletonColor.a * slotColor.a * regionColor.a * 255; - float multiplier = premultipliedAlpha ? alpha : 255; - float color = NumberUtils.intToFloatColor( // - ((int)alpha << 24) // - | ((int)(skeletonColor.b * slotColor.b * regionColor.b * multiplier) << 16) // - | ((int)(skeletonColor.g * slotColor.g * regionColor.g * multiplier) << 8) // - | (int)(skeletonColor.r * slotColor.r * regionColor.r * multiplier)); - - float[] vertices = this.vertices; - float[] offset = this.offset; + /** Transforms the attachment's four vertices to world coordinates. + *

+ * See World transforms in the Spine + * Runtimes Guide. + * @param worldVertices The output world vertices. Must have a length >= offset + 8. + * @param offset The worldVertices index to begin writing values. + * @param stride The number of worldVertices entries between the value pairs written. */ + public void computeWorldVertices (Slot slot, float[] worldVertices, int offset, int stride) { + 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; - offsetX = offset[BRX]; - offsetY = offset[BRY]; - vertices[X1] = offsetX * a + offsetY * b + x; // br - vertices[Y1] = offsetX * c + offsetY * d + y; - vertices[C1] = color; + offsetX = vertexOffset[BRX]; + offsetY = vertexOffset[BRY]; + worldVertices[offset] = offsetX * a + offsetY * b + x; // br + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; - offsetX = offset[BLX]; - offsetY = offset[BLY]; - vertices[X2] = offsetX * a + offsetY * b + x; // bl - vertices[Y2] = offsetX * c + offsetY * d + y; - vertices[C2] = color; + offsetX = vertexOffset[BLX]; + offsetY = vertexOffset[BLY]; + worldVertices[offset] = offsetX * a + offsetY * b + x; // bl + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; - offsetX = offset[ULX]; - offsetY = offset[ULY]; - vertices[X3] = offsetX * a + offsetY * b + x; // ul - vertices[Y3] = offsetX * c + offsetY * d + y; - vertices[C3] = color; + offsetX = vertexOffset[ULX]; + offsetY = vertexOffset[ULY]; + worldVertices[offset] = offsetX * a + offsetY * b + x; // ul + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; - offsetX = offset[URX]; - offsetY = offset[URY]; - vertices[X4] = offsetX * a + offsetY * b + x; // ur - vertices[Y4] = offsetX * c + offsetY * d + y; - vertices[C4] = color; - return vertices; - } - - public float[] getWorldVertices () { - return vertices; + offsetX = vertexOffset[URX]; + offsetY = vertexOffset[URY]; + worldVertices[offset] = offsetX * a + offsetY * b + x; // ur + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; } /** For each of the 4 vertices, a pair of x,y values that is the local position of the vertex. @@ -205,6 +188,10 @@ public class RegionAttachment extends Attachment { return offset; } + public float[] getUVs () { + return uvs; + } + /** The local x translation. */ public float getX () { return x; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java deleted file mode 100644 index 0af1c5884..000000000 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java +++ /dev/null @@ -1,100 +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.attachments; - -import com.esotericsoftware.spine.Slot; - -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.math.MathUtils; - -/** Attachment that displays various texture regions over time. */ -public class RegionSequenceAttachment extends RegionAttachment { - private Mode mode; - private float frameTime; - private TextureRegion[] regions; - - public RegionSequenceAttachment (String name) { - super(name); - } - - public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { - if (regions == null) throw new IllegalStateException("Regions have not been set: " + this); - - int frameIndex = (int)(slot.getAttachmentTime() / frameTime); - switch (mode) { - case forward: - frameIndex = Math.min(regions.length - 1, frameIndex); - break; - case forwardLoop: - frameIndex = frameIndex % regions.length; - break; - case pingPong: - frameIndex = frameIndex % (regions.length << 1); - if (frameIndex >= regions.length) frameIndex = regions.length - 1 - (frameIndex - regions.length); - break; - case random: - frameIndex = MathUtils.random(regions.length - 1); - break; - case backward: - frameIndex = Math.max(regions.length - frameIndex - 1, 0); - break; - case backwardLoop: - frameIndex = frameIndex % regions.length; - frameIndex = regions.length - frameIndex - 1; - break; - } - setRegion(regions[frameIndex]); - - return super.updateWorldVertices(slot, premultipliedAlpha); - } - - public TextureRegion[] getRegions () { - if (regions == null) throw new IllegalStateException("Regions have not been set: " + this); - return regions; - } - - public void setRegions (TextureRegion[] regions) { - this.regions = regions; - } - - /** Sets the time in seconds each frame is shown. */ - public void setFrameTime (float frameTime) { - this.frameTime = frameTime; - } - - public void setMode (Mode mode) { - this.mode = mode; - } - - static public enum Mode { - forward, backward, forwardLoop, backwardLoop, pingPong, random - } -} diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java index 9ecf01a3f..954c0ad14 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java @@ -46,14 +46,6 @@ public class VertexAttachment extends Attachment { super(name); } - /** Transforms the attachment's local {@link #getVertices()} to world coordinates, using 0 for start and - * offset. - *

- * See {@link #computeWorldVertices(Slot, int, int, float[], int)}. */ - public void computeWorldVertices (Slot slot, float[] worldVertices) { - computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0); - } - /** Transforms the attachment's local {@link #getVertices()} to world coordinates. If the slot has * {@link Slot#getAttachmentVertices()}, they are used to deform the vertices. *

@@ -62,9 +54,10 @@ public class VertexAttachment extends Attachment { * @param start The index of the first {@link #getVertices()} value to transform. Each vertex has 2 values, x and y. * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start. * @param worldVertices The output world vertices. Must have a length >= offset + count. - * @param offset The worldVertices index to begin writing values. */ - public void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) { - count += offset; + * @param offset The worldVertices index to begin writing values. + * @param stride The number of worldVertices entries between the value pairs written. */ + public void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset, int stride) { + count = offset + (count >> 1) * stride; Skeleton skeleton = slot.getSkeleton(); FloatArray deformArray = slot.getAttachmentVertices(); float[] vertices = this.vertices; @@ -74,7 +67,7 @@ public class VertexAttachment extends Attachment { Bone bone = slot.getBone(); float x = bone.getWorldX(), y = bone.getWorldY(); float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); - for (int v = start, w = offset; w < count; v += 2, w += 2) { + for (int v = start, w = offset; w < count; v += 2, w += stride) { float vx = vertices[v], vy = vertices[v + 1]; worldVertices[w] = vx * a + vy * b + x; worldVertices[w + 1] = vx * c + vy * d + y; @@ -89,7 +82,7 @@ public class VertexAttachment extends Attachment { } Object[] skeletonBones = skeleton.getBones().items; if (deformArray.size == 0) { - for (int w = offset, b = skip * 3; w < count; w += 2) { + for (int w = offset, b = skip * 3; w < count; w += stride) { float wx = 0, wy = 0; int n = bones[v++]; n += v; @@ -104,7 +97,7 @@ public class VertexAttachment extends Attachment { } } else { float[] deform = deformArray.items; - for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { + for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { float wx = 0, wy = 0; int n = bones[v++]; n += v; @@ -150,7 +143,7 @@ public class VertexAttachment extends Attachment { } /** The maximum length required of the worldVertices passed to - * {@link #computeWorldVertices(Slot, int, int, float[], int)}. */ + * {@link #computeWorldVertices(Slot, int, int, float[], int, int)}. */ public int getWorldVerticesLength () { return worldVerticesLength; }