Skip to content

Commit

Permalink
[csharp][unity] Skeleton.getBounds() applies clipping, see #2515. Por…
Browse files Browse the repository at this point in the history
…t of commits b043e5c, 637321a and 2049bed.
  • Loading branch information
HaraldCsaszar committed May 2, 2024
1 parent 2049bed commit c6a01d7
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 6 deletions.
22 changes: 21 additions & 1 deletion spine-csharp/src/Skeleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Bone> bones;
internal ExposedList<Slot> slots;
Expand Down Expand Up @@ -696,7 +697,9 @@ public class Skeleton {
/// <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;
Expand All @@ -706,24 +709,39 @@ 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) {
verticesLength = 8;
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) {
verticesLength = mesh.WorldVerticesLength;
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);
Expand All @@ -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;
Expand Down
72 changes: 69 additions & 3 deletions spine-csharp/src/SkeletonClipping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,73 @@ public class SkeletonClipping {
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;
Expand Down Expand Up @@ -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. */
///<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;
Expand Down
2 changes: 1 addition & 1 deletion spine-csharp/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,11 @@ public enum LayoutMode {
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; } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();

/// <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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ public struct Settings {
}
}

/// <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();
}
Expand Down
2 changes: 1 addition & 1 deletion spine-unity/Assets/Spine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit c6a01d7

Please sign in to comment.