diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/ClippingTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/ClippingTest.java index eb7dc8b2c..f61683858 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/ClippingTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/ClippingTest.java @@ -90,13 +90,13 @@ public class ClippingTest extends ApplicationAdapter { ClippingAttachment clip = new ClippingAttachment("clip"); // Rectangle: clip.setVertices( - new float[] { 87, 288, 217, 371, 456, 361, 539, 175, 304, 194, 392, 290, 193, 214, 123, 15, 14, 137 }); -// new float[] { // -// -140, 50, // -// 250, 50, // -// 250, 350, // -// -140, 350, // -// }); +// new float[] { 87, 288, 217, 371, 456, 361, 539, 175, 304, 194, 392, 290, 193, 214, 123, 15, 14, 137 }); + new float[] { // + -140, 50, // + 250, 50, // + 250, 350, // + -140, 350, // + }); // Self intersection: // clip.setVertices(new float[] { // // -140, -50, // 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 84f574591..4307a635c 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java @@ -49,6 +49,7 @@ import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.RegionAttachment; import com.esotericsoftware.spine.attachments.SkeletonAttachment; import com.esotericsoftware.spine.utils.Clipper; +import com.esotericsoftware.spine.utils.ConvexDecomposer; import com.esotericsoftware.spine.utils.TwoColorPolygonBatch; public class SkeletonRenderer { @@ -57,12 +58,13 @@ public class SkeletonRenderer { private boolean softwareClipping; private boolean premultipliedAlpha; private final FloatArray vertices = new FloatArray(32); - - private Clipper clipper = new Clipper(); + private ClippingAttachment clipAttachment; private Slot clipEnd; - private FloatArray clippingArea = new FloatArray(); - private boolean clippingAreaClockwise; + private Clipper clipper = new Clipper(); + private ConvexDecomposer decomposer = new ConvexDecomposer(); + private FloatArray clippingPolygon = new FloatArray(400); + private Array convexClippingPolygons; private FloatArray clipOutput = new FloatArray(400); private FloatArray clippedVertices = new FloatArray(400); private ShortArray clippedTriangles = new ShortArray(400); @@ -404,18 +406,22 @@ public class SkeletonRenderer { Gdx.gl.glStencilOp(GL20.GL_KEEP, GL20.GL_KEEP, GL20.GL_KEEP); } else { int n = clip.getWorldVerticesLength(); - float[] vertices = this.clippingArea.setSize(n); + float[] vertices = this.clippingPolygon.setSize(n); clip.computeWorldVertices(slot, 0, n, vertices, 0, 2); - clippingAreaClockwise = Clipper.isClockwise(this.clippingArea); - if (!clippingAreaClockwise) { - Clipper.makeClockwise(clippingArea); + convexClippingPolygons = decomposer.decompose(clippingPolygon); + for (FloatArray poly: convexClippingPolygons) { + Clipper.makeClockwise(poly); + poly.add(poly.items[0]); + poly.add(poly.items[1]); } - clippingArea.add(clippingArea.items[0]); - clippingArea.add(clippingArea.items[1]); } } private void clipEnd() { + clippedVertices.clear(); + clippedTriangles.clear(); + clippingPolygon.clear(); + convexClippingPolygons = null; clipAttachment = null; clipEnd = null; if (!softwareClipping) Gdx.gl.glDisable(GL20.GL_STENCIL_TEST); @@ -425,124 +431,126 @@ public class SkeletonRenderer { short idx = 0; clippedVertices.clear(); clippedTriangles.clear(); - for (int i = 0; i < trianglesLength; i += 3) { - int vertexOffset = triangles[i] << 1; - float x1 = vertices[vertexOffset]; - float y1= vertices[vertexOffset + 1]; - float u1 = uvs[vertexOffset]; - float v1 = uvs[vertexOffset + 1]; - - vertexOffset = triangles[i + 1] << 1; - float x2 = vertices[vertexOffset]; - float y2 = vertices[vertexOffset + 1]; - float u2 = uvs[vertexOffset]; - float v2 = uvs[vertexOffset + 1]; - - vertexOffset = triangles[i + 2] << 1; - float x3 = vertices[vertexOffset]; - float y3 = vertices[vertexOffset + 1]; - float u3 = uvs[vertexOffset]; - float v3 = uvs[vertexOffset + 1]; - - boolean clipped = clipper.clip(x1, y1, x2, y2, x3, y3, clippingArea, clipOutput); - if (clipped) { - if (clipOutput.size == 0) continue; - float d0 = y2 - y3; - float d1 = x3 - x2; - float d2 = x1 - x3; - float d3 = y1 - y3; - float d4 = y3 - y1; + for (FloatArray convexClippingPolygon: convexClippingPolygons) { + for (int i = 0; i < trianglesLength; i += 3) { + int vertexOffset = triangles[i] << 1; + float x1 = vertices[vertexOffset]; + float y1= vertices[vertexOffset + 1]; + float u1 = uvs[vertexOffset]; + float v1 = uvs[vertexOffset + 1]; - float denom = 1 / (d0 * d2 + d1 * d3); + vertexOffset = triangles[i + 1] << 1; + float x2 = vertices[vertexOffset]; + float y2 = vertices[vertexOffset + 1]; + float u2 = uvs[vertexOffset]; + float v2 = uvs[vertexOffset + 1]; - float[] clipVertices = clipOutput.items; - int s = clippedVertices.size; - clippedVertices.setSize(s + (clipOutput.size >> 1) * (twoColor ? 6 : 5)); - final float[] clippedVerticesArray = clippedVertices.items; + vertexOffset = triangles[i + 2] << 1; + float x3 = vertices[vertexOffset]; + float y3 = vertices[vertexOffset + 1]; + float u3 = uvs[vertexOffset]; + float v3 = uvs[vertexOffset + 1]; - for (int j = 0, n = clipOutput.size; j < n; j += 2) { - float x = clipVertices[j]; - float y = clipVertices[j + 1]; + boolean clipped = clipper.clip(x1, y1, x2, y2, x3, y3, convexClippingPolygon, clipOutput); + if (clipped) { + if (clipOutput.size == 0) continue; + float d0 = y2 - y3; + float d1 = x3 - x2; + float d2 = x1 - x3; + float d3 = y1 - y3; + float d4 = y3 - y1; + + float denom = 1 / (d0 * d2 + d1 * d3); + + float[] clipVertices = clipOutput.items; + int s = clippedVertices.size; + clippedVertices.setSize(s + (clipOutput.size >> 1) * (twoColor ? 6 : 5)); + final float[] clippedVerticesArray = clippedVertices.items; + + for (int j = 0, n = clipOutput.size; j < n; j += 2) { + float x = clipVertices[j]; + float y = clipVertices[j + 1]; + + float c0 = x - x3; + float c1 = y - y3; + float a = (d0 * c0 + d1 * c1) * denom; + float b = (d4 * c0 + d2 * c1) * denom; + float c = 1.0f - a - b; - float c0 = x - x3; - float c1 = y - y3; - float a = (d0 * c0 + d1 * c1) * denom; - float b = (d4 * c0 + d2 * c1) * denom; - float c = 1.0f - a - b; + float u = u1 * a + u2 * b + u3 * c; + float v = v1 * a + v2 * b + v3 * c; + clippedVerticesArray[s++] = x; + clippedVerticesArray[s++] = y; + clippedVerticesArray[s++] = light; + if (twoColor) clippedVerticesArray[s++] = dark; + clippedVerticesArray[s++] = u; + clippedVerticesArray[s++] = v; + } - float u = u1 * a + u2 * b + u3 * c; - float v = v1 * a + v2 * b + v3 * c; - clippedVerticesArray[s++] = x; - clippedVerticesArray[s++] = y; - clippedVerticesArray[s++] = light; - if (twoColor) clippedVerticesArray[s++] = dark; - clippedVerticesArray[s++] = u; - clippedVerticesArray[s++] = v; - } - - s = clippedTriangles.size; - clippedTriangles.setSize(s + 3 * ((clipOutput.size >> 1) - 2)); - final short[] clippedTrianglesArray = clippedTriangles.items; - - for (int j = 1, n = (clipOutput.size >> 1) - 1; j < n; j++) { - clippedTrianglesArray[s++] = idx; - clippedTrianglesArray[s++] = (short)(idx + j); - clippedTrianglesArray[s++] = (short)(idx + j + 1); - } - - idx += clipOutput.size >> 1; - } else { - int s = clippedVertices.size; - clippedVertices.setSize(s + 3 * (twoColor ? 6 : 5)); - final float[] clippedVerticesArray = clippedVertices.items; - - if (!twoColor) { - clippedVerticesArray[s] = x1; - clippedVerticesArray[s + 1] = y1; - clippedVerticesArray[s + 2] = light; - clippedVerticesArray[s + 3] = u1; - clippedVerticesArray[s + 4] = v1; + s = clippedTriangles.size; + clippedTriangles.setSize(s + 3 * ((clipOutput.size >> 1) - 2)); + final short[] clippedTrianglesArray = clippedTriangles.items; - clippedVerticesArray[s + 5] = x2; - clippedVerticesArray[s + 6] = y2; - clippedVerticesArray[s + 7] = light; - clippedVerticesArray[s + 8] = u2; - clippedVerticesArray[s + 9] = v2; + for (int j = 1, n = (clipOutput.size >> 1) - 1; j < n; j++) { + clippedTrianglesArray[s++] = idx; + clippedTrianglesArray[s++] = (short)(idx + j); + clippedTrianglesArray[s++] = (short)(idx + j + 1); + } - clippedVerticesArray[s + 10] = x3; - clippedVerticesArray[s + 11] = y3; - clippedVerticesArray[s + 12] = light; - clippedVerticesArray[s + 13] = u3; - clippedVerticesArray[s + 14] = v3; + idx += clipOutput.size >> 1; } else { - clippedVerticesArray[s] = x1; - clippedVerticesArray[s + 1] = y1; - clippedVerticesArray[s + 2] = light; - clippedVerticesArray[s + 3] = dark; - clippedVerticesArray[s + 4] = u1; - clippedVerticesArray[s + 5] = v1; + int s = clippedVertices.size; + clippedVertices.setSize(s + 3 * (twoColor ? 6 : 5)); + final float[] clippedVerticesArray = clippedVertices.items; - clippedVerticesArray[s + 6] = x2; - clippedVerticesArray[s + 7] = y2; - clippedVerticesArray[s + 8] = light; - clippedVerticesArray[s + 9] = dark; - clippedVerticesArray[s + 10] = u2; - clippedVerticesArray[s + 11] = v2; + if (!twoColor) { + clippedVerticesArray[s] = x1; + clippedVerticesArray[s + 1] = y1; + clippedVerticesArray[s + 2] = light; + clippedVerticesArray[s + 3] = u1; + clippedVerticesArray[s + 4] = v1; + + clippedVerticesArray[s + 5] = x2; + clippedVerticesArray[s + 6] = y2; + clippedVerticesArray[s + 7] = light; + clippedVerticesArray[s + 8] = u2; + clippedVerticesArray[s + 9] = v2; + + clippedVerticesArray[s + 10] = x3; + clippedVerticesArray[s + 11] = y3; + clippedVerticesArray[s + 12] = light; + clippedVerticesArray[s + 13] = u3; + clippedVerticesArray[s + 14] = v3; + } else { + clippedVerticesArray[s] = x1; + clippedVerticesArray[s + 1] = y1; + clippedVerticesArray[s + 2] = light; + clippedVerticesArray[s + 3] = dark; + clippedVerticesArray[s + 4] = u1; + clippedVerticesArray[s + 5] = v1; + + clippedVerticesArray[s + 6] = x2; + clippedVerticesArray[s + 7] = y2; + clippedVerticesArray[s + 8] = light; + clippedVerticesArray[s + 9] = dark; + clippedVerticesArray[s + 10] = u2; + clippedVerticesArray[s + 11] = v2; + + clippedVerticesArray[s + 12] = x3; + clippedVerticesArray[s + 13] = y3; + clippedVerticesArray[s + 14] = light; + clippedVerticesArray[s + 15] = dark; + clippedVerticesArray[s + 16] = u3; + clippedVerticesArray[s + 17] = v3; + } - clippedVerticesArray[s + 12] = x3; - clippedVerticesArray[s + 13] = y3; - clippedVerticesArray[s + 14] = light; - clippedVerticesArray[s + 15] = dark; - clippedVerticesArray[s + 16] = u3; - clippedVerticesArray[s + 17] = v3; + s = clippedTriangles.size; + clippedTriangles.setSize(s + 3); + final short[] clippedTrianglesArray = clippedTriangles.items; + clippedTrianglesArray[s] = idx++; + clippedTrianglesArray[s + 1] = idx++; + clippedTrianglesArray[s + 2] = idx++; } - - s = clippedTriangles.size; - clippedTriangles.setSize(s + 3); - final short[] clippedTrianglesArray = clippedTriangles.items; - clippedTrianglesArray[s] = idx++; - clippedTrianglesArray[s + 1] = idx++; - clippedTrianglesArray[s + 2] = idx++; } } }