[libgdx] Added convex decomposition to SkeletonRenderer.

This commit is contained in:
badlogic 2017-03-31 10:22:25 +02:00
parent b8a603d6af
commit ace38dca5f
2 changed files with 132 additions and 124 deletions

View File

@ -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, //

View File

@ -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<FloatArray> 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++;
}
}
}