diff --git a/spine-csharp/src/Skeleton.cs b/spine-csharp/src/Skeleton.cs index 522b27fc6..4debe9bf7 100644 --- a/spine-csharp/src/Skeleton.cs +++ b/spine-csharp/src/Skeleton.cs @@ -31,6 +31,7 @@ namespace Spine { public class Skeleton { + static private readonly int[] quadTriangles = { 0, 1, 2, 2, 3, 0 }; internal SkeletonData data; internal ExposedList bones; internal ExposedList slots; @@ -696,7 +697,9 @@ public class Skeleton { /// The width of the AABB /// The height of the AABB. /// Reference to hold a float[]. May be a null reference. This method will assign it a new float[] with the appropriate size as needed. - public void GetBounds (out float x, out float y, out float width, out float height, ref float[] vertexBuffer) { + public void GetBounds (out float x, out float y, out float width, out float height, ref float[] vertexBuffer, + SkeletonClipping clipper = null) { + float[] temp = vertexBuffer; temp = temp ?? new float[8]; Slot[] drawOrder = this.drawOrder.Items; @@ -706,6 +709,7 @@ public class Skeleton { if (!slot.bone.active) continue; int verticesLength = 0; float[] vertices = null; + int[] triangles = null; Attachment attachment = slot.attachment; RegionAttachment region = attachment as RegionAttachment; if (region != null) { @@ -713,6 +717,7 @@ public class Skeleton { vertices = temp; if (vertices.Length < 8) vertices = temp = new float[8]; region.ComputeWorldVertices(slot, temp, 0, 2); + triangles = quadTriangles; } else { MeshAttachment mesh = attachment as MeshAttachment; if (mesh != null) { @@ -720,10 +725,23 @@ public class Skeleton { vertices = temp; if (vertices.Length < verticesLength) vertices = temp = new float[verticesLength]; mesh.ComputeWorldVertices(slot, 0, verticesLength, temp, 0, 2); + triangles = mesh.Triangles; + } else if (clipper != null) { + ClippingAttachment clip = attachment as ClippingAttachment; + if (clip != null) { + clipper.ClipStart(slot, clip); + continue; + } } } if (vertices != null) { + if (clipper != null && clipper.IsClipping) { + clipper.ClipTriangles(vertices, verticesLength, triangles, triangles.Length); + vertices = clipper.ClippedVertices.Items; + verticesLength = clipper.ClippedVertices.Count; + } + for (int ii = 0; ii < verticesLength; ii += 2) { float vx = vertices[ii], vy = vertices[ii + 1]; minX = Math.Min(minX, vx); @@ -732,7 +750,9 @@ public class Skeleton { maxY = Math.Max(maxY, vy); } } + if (clipper != null) clipper.ClipEnd(slot); } + if (clipper != null) clipper.ClipEnd(); x = minX; y = minY; width = maxX - minX; diff --git a/spine-csharp/src/SkeletonClipping.cs b/spine-csharp/src/SkeletonClipping.cs index 281a9f1a7..29555be77 100644 --- a/spine-csharp/src/SkeletonClipping.cs +++ b/spine-csharp/src/SkeletonClipping.cs @@ -78,6 +78,73 @@ public class SkeletonClipping { clippingPolygon.Clear(); } + public void ClipTriangles (float[] vertices, int verticesLength, int[] triangles, int trianglesLength) { + ExposedList clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + ExposedList clippedTriangles = this.clippedTriangles; + ExposedList[] polygons = clippingPolygons.Items; + int polygonsCount = clippingPolygons.Count; + + int index = 0; + clippedVertices.Clear(); + clippedTriangles.Clear(); + //outer: + for (int i = 0; i < trianglesLength; i += 3) { + int vertexOffset = triangles[i] << 1; + float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + + vertexOffset = triangles[i + 1] << 1; + float x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + + vertexOffset = triangles[i + 2] << 1; + float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + + for (int p = 0; p < polygonsCount; p++) { + int s = clippedVertices.Count; + if (Clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + int clipOutputLength = clipOutput.Count; + if (clipOutputLength == 0) continue; + + int clipOutputCount = clipOutputLength >> 1; + float[] clipOutputItems = clipOutput.Items; + float[] clippedVerticesItems = clippedVertices.Resize(s + clipOutputCount * 2).Items; + for (int ii = 0; ii < clipOutputLength; ii += 2) { + float x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + s += 2; + } + + s = clippedTriangles.Count; + int[] clippedTrianglesItems = clippedTriangles.Resize(s + 3 * (clipOutputCount - 2)).Items; + clipOutputCount--; + for (int ii = 1; ii < clipOutputCount; ii++) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + ii; + clippedTrianglesItems[s + 2] = index + ii + 1; + s += 3; + } + index += clipOutputCount + 1; + } else { + float[] clippedVerticesItems = clippedVertices.Resize(s + 3 * 2).Items; + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = x2; + clippedVerticesItems[s + 3] = y2; + clippedVerticesItems[s + 4] = x3; + clippedVerticesItems[s + 5] = y3; + + s = clippedTriangles.Count; + int[] clippedTrianglesItems = clippedTriangles.Resize(s + 3).Items; + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + 1; + clippedTrianglesItems[s + 2] = index + 2; + index += 3; + break; //continue outer; + } + } + } + } + public void ClipTriangles (float[] vertices, int verticesLength, int[] triangles, int trianglesLength, float[] uvs) { ExposedList clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; ExposedList clippedTriangles = this.clippedTriangles; @@ -164,11 +231,10 @@ public class SkeletonClipping { } } } - } - /** Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping - * area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices list. */ + ///Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping + /// area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices list. internal bool Clip (float x1, float y1, float x2, float y2, float x3, float y3, ExposedList clippingArea, ExposedList output) { ExposedList originalOutput = output; bool clipped = false; diff --git a/spine-csharp/src/package.json b/spine-csharp/src/package.json index e581b197d..67160d5a1 100644 --- a/spine-csharp/src/package.json +++ b/spine-csharp/src/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.spine-csharp", "displayName": "spine-csharp Runtime", "description": "This plugin provides the spine-csharp core runtime.", - "version": "4.2.21", + "version": "4.2.22", "unity": "2018.3", "author": { "name": "Esoteric Software", diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs index a00f12b19..d04c9ce4e 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -645,6 +645,11 @@ public enum LayoutMode { readonly ExposedList usedMaterials = new ExposedList(); readonly ExposedList usedTextures = new ExposedList(); + /// Returns the used by this renderer for use with e.g. + /// + /// + public SkeletonClipping SkeletonClipping { get { return meshGenerator.SkeletonClipping; } } + public ExposedList MeshesMultipleCanvasRenderers { get { return meshes; } } public ExposedList MaterialsMultipleCanvasRenderers { get { return usedMaterials; } } public ExposedList TexturesMultipleCanvasRenderers { get { return usedTextures; } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index caf1786f3..487d51883 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -270,6 +270,11 @@ public class SpriteMaskInteractionMaterials { [System.NonSerialized] readonly SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction(); readonly MeshGenerator meshGenerator = new MeshGenerator(); [System.NonSerialized] readonly MeshRendererBuffers rendererBuffers = new MeshRendererBuffers(); + + /// Returns the used by this renderer for use with e.g. + /// + /// + public SkeletonClipping SkeletonClipping { get { return meshGenerator.SkeletonClipping; } } #endregion #region Cached component references diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs index 864431ea3..ee83977e2 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs @@ -156,6 +156,11 @@ public struct Settings { } } + /// Returns the used by this mesh generator for use with e.g. + /// + /// + public SkeletonClipping SkeletonClipping { get { return clipper; } } + public MeshGenerator () { submeshes.TrimExcess(); } diff --git a/spine-unity/Assets/Spine/package.json b/spine-unity/Assets/Spine/package.json index 22c91da9a..2690ae430 100644 --- a/spine-unity/Assets/Spine/package.json +++ b/spine-unity/Assets/Spine/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.spine-unity", "displayName": "spine-unity Runtime", "description": "This plugin provides the spine-unity runtime core.", - "version": "4.2.61", + "version": "4.2.62", "unity": "2018.3", "author": { "name": "Esoteric Software",