From c6a01d7a5f44d4698afc74e8255b96c41b8636c3 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Thu, 2 May 2024 20:20:57 +0200 Subject: [PATCH] [csharp][unity] Skeleton.getBounds() applies clipping, see #2515. Port of commits b043e5c, 637321a and 2049bed. --- spine-csharp/src/Skeleton.cs | 22 +++++- spine-csharp/src/SkeletonClipping.cs | 72 ++++++++++++++++++- spine-csharp/src/package.json | 2 +- .../spine-unity/Components/SkeletonGraphic.cs | 5 ++ .../Components/SkeletonRenderer.cs | 5 ++ .../Mesh Generation/MeshGenerator.cs | 5 ++ spine-unity/Assets/Spine/package.json | 2 +- 7 files changed, 107 insertions(+), 6 deletions(-) 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 @@ using System; 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 @@ namespace Spine { /// 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 @@ namespace Spine { 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 @@ namespace Spine { 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 @@ namespace Spine { 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 @@ namespace Spine { 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 @@ namespace Spine { 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 @@ namespace Spine { } } } - } - /** 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 @@ namespace Spine.Unity { 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 @@ namespace Spine.Unity { [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 @@ namespace Spine.Unity { } } + /// 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",