瀏覽代碼

[csharp][unity] Skeleton.getBounds() applies clipping, see #2515. Port of commits b043e5c, 637321a and 2049bed.

Harald Csaszar 1 年之前
父節點
當前提交
c6a01d7a5f

+ 21 - 1
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<Bone> bones;
 		internal ExposedList<Slot> slots;
@@ -696,7 +697,9 @@ namespace Spine {
 		/// <param name="width">The width of the AABB</param>
 		/// <param name="height">The height of the AABB.</param>
 		/// <param name="vertexBuffer">Reference to hold a float[]. May be a null reference. This method will assign it a new float[] with the appropriate size as needed.</param>
-		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;

+ 69 - 3
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<float> clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
+			ExposedList<int> clippedTriangles = this.clippedTriangles;
+			ExposedList<float>[] 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<float> clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
 			ExposedList<int> 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. */
+		///<summary>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.</summary>
 		internal bool Clip (float x1, float y1, float x2, float y2, float x3, float y3, ExposedList<float> clippingArea, ExposedList<float> output) {
 			ExposedList<float> originalOutput = output;
 			bool clipped = false;

+ 1 - 1
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",

+ 5 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs

@@ -645,6 +645,11 @@ namespace Spine.Unity {
 		readonly ExposedList<Material> usedMaterials = new ExposedList<Material>();
 		readonly ExposedList<Texture> usedTextures = new ExposedList<Texture>();
 
+		/// <summary>Returns the <see cref="SkeletonClipping"/> used by this renderer for use with e.g.
+		/// <see cref="Skeleton.GetBounds(out float, out float, out float, out float, ref float[], SkeletonClipping)"/>
+		/// </summary>
+		public SkeletonClipping SkeletonClipping { get { return meshGenerator.SkeletonClipping; } }
+
 		public ExposedList<Mesh> MeshesMultipleCanvasRenderers { get { return meshes; } }
 		public ExposedList<Material> MaterialsMultipleCanvasRenderers { get { return usedMaterials; } }
 		public ExposedList<Texture> TexturesMultipleCanvasRenderers { get { return usedTextures; } }

+ 5 - 0
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();
+
+		/// <summary>Returns the <see cref="SkeletonClipping"/> used by this renderer for use with e.g.
+		/// <see cref="Skeleton.GetBounds(out float, out float, out float, out float, ref float[], SkeletonClipping)"/>
+		/// </summary>
+		public SkeletonClipping SkeletonClipping { get { return meshGenerator.SkeletonClipping; } }
 		#endregion
 
 		#region Cached component references

+ 5 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs

@@ -156,6 +156,11 @@ namespace Spine.Unity {
 			}
 		}
 
+		/// <summary>Returns the <see cref="SkeletonClipping"/> used by this mesh generator for use with e.g.
+		/// <see cref="Skeleton.GetBounds(out float, out float, out float, out float, ref float[], SkeletonClipping)"/>
+		/// </summary>
+		public SkeletonClipping SkeletonClipping { get { return clipper; } }
+
 		public MeshGenerator () {
 			submeshes.TrimExcess();
 		}

+ 1 - 1
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",