mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 23:34:53 +08:00
Applied Nate's beautifier and standard set of useless optimizations.
This commit is contained in:
parent
241c7980f8
commit
57535b68dd
@ -32,7 +32,6 @@ package com.esotericsoftware.spine;
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
|
||||
@ -38,170 +38,155 @@ import com.esotericsoftware.spine.utils.Clipper;
|
||||
import com.esotericsoftware.spine.utils.ConvexDecomposer;
|
||||
|
||||
public class SkeletonClipping {
|
||||
private final Clipper clipper = new Clipper();
|
||||
private final ConvexDecomposer decomposer = new ConvexDecomposer();
|
||||
private final FloatArray clippingPolygon = new FloatArray();
|
||||
private final FloatArray clipOutput = new FloatArray(400);
|
||||
private final FloatArray clippedVertices = new FloatArray(400);
|
||||
private final ShortArray clippedTriangles = new ShortArray(400);
|
||||
|
||||
private ClippingAttachment clipAttachment;
|
||||
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);
|
||||
|
||||
public void clipStart (Slot slot, ClippingAttachment clip) {
|
||||
if (clipAttachment != null) return;
|
||||
clipAttachment = clip;
|
||||
|
||||
int n = clip.getWorldVerticesLength();
|
||||
float[] vertices = this.clippingPolygon.setSize(n);
|
||||
float[] vertices = clippingPolygon.setSize(n);
|
||||
clip.computeWorldVertices(slot, 0, n, vertices, 0, 2);
|
||||
convexClippingPolygons = decomposer.decompose(clippingPolygon);
|
||||
for (FloatArray poly : convexClippingPolygons) {
|
||||
Clipper.makeClockwise(poly);
|
||||
poly.add(poly.items[0]);
|
||||
poly.add(poly.items[1]);
|
||||
for (FloatArray polygon : convexClippingPolygons) {
|
||||
Clipper.makeClockwise(polygon);
|
||||
polygon.add(polygon.items[0]);
|
||||
polygon.add(polygon.items[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public void clipEnd () {
|
||||
public void clipEnd (int index) {
|
||||
if (clipAttachment == null || clipAttachment.getEndSlot() != index) return;
|
||||
clipAttachment = null;
|
||||
convexClippingPolygons = null;
|
||||
clippedVertices.clear();
|
||||
clippedTriangles.clear();
|
||||
clippingPolygon.clear();
|
||||
convexClippingPolygons = null;
|
||||
clipAttachment = null;
|
||||
}
|
||||
|
||||
public boolean isClipping () {
|
||||
return clipAttachment != null;
|
||||
}
|
||||
|
||||
public ClippingAttachment getClippingAttachment () {
|
||||
return clipAttachment;
|
||||
}
|
||||
public void clipTriangles (float[] vertices, int verticesLength, short[] triangles, int trianglesLength, float uvs[],
|
||||
float dark, float light, boolean twoColor) {
|
||||
|
||||
public void clipTriangles (final float[] vertices, final int verticesLength, final short[] triangles,
|
||||
final int trianglesLength, final float uvs[], final float dark, final float light, final boolean twoColor) {
|
||||
short idx = 0;
|
||||
Clipper clipper = this.clipper;
|
||||
FloatArray clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
|
||||
ShortArray clippedTriangles = this.clippedTriangles;
|
||||
int vertexSize = twoColor ? 6 : 5;
|
||||
|
||||
short index = 0;
|
||||
clippedVertices.clear();
|
||||
clippedTriangles.clear();
|
||||
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 x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
|
||||
float u1 = uvs[vertexOffset], 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];
|
||||
float x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1];
|
||||
float u2 = uvs[vertexOffset], 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];
|
||||
float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1];
|
||||
float u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1];
|
||||
|
||||
boolean clipped = clipper.clip(x1, y1, x2, y2, x3, y3, convexClippingPolygon, clipOutput);
|
||||
if (clipped) {
|
||||
int s = clippedVertices.size;
|
||||
if (clipper.clip(x1, y1, x2, y2, x3, y3, convexClippingPolygon, clipOutput)) {
|
||||
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 d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
|
||||
float d = 1 / (d0 * d2 + d1 * (y1 - y3));
|
||||
|
||||
float[] clipOutputItems = clipOutput.items;
|
||||
float[] clippedVerticesItems = clippedVertices.setSize(s + (clipOutput.size >> 1) * vertexSize);
|
||||
for (int ii = 0, nn = clipOutput.size; ii < nn; ii += 2) {
|
||||
float x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
|
||||
float c0 = x - x3, c1 = y - y3;
|
||||
float a = (d0 * c0 + d1 * c1) * d;
|
||||
float b = (d4 * c0 + d2 * c1) * d;
|
||||
float c = 1 - 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;
|
||||
clippedVerticesItems[s] = x;
|
||||
clippedVerticesItems[s + 1] = y;
|
||||
clippedVerticesItems[s + 2] = light;
|
||||
if (twoColor) {
|
||||
clippedVerticesItems[s + 3] = dark;
|
||||
clippedVerticesItems[s + 4] = u;
|
||||
clippedVerticesItems[s + 5] = v;
|
||||
s += 6;
|
||||
} else {
|
||||
clippedVerticesItems[s + 3] = u;
|
||||
clippedVerticesItems[s + 4] = v;
|
||||
s += 5;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
short[] clippedTrianglesItems = clippedTriangles.setSize(s + 3 * ((clipOutput.size >> 1) - 2));
|
||||
for (int ii = 1, nn = (clipOutput.size >> 1) - 1; ii < nn; ii++) {
|
||||
clippedTrianglesItems[s] = index;
|
||||
clippedTrianglesItems[s + 1] = (short)(index + ii);
|
||||
clippedTrianglesItems[s + 2] = (short)(index + ii + 1);
|
||||
s += 3;
|
||||
}
|
||||
index += clipOutput.size >> 1;
|
||||
|
||||
idx += clipOutput.size >> 1;
|
||||
} else {
|
||||
int s = clippedVertices.size;
|
||||
clippedVertices.setSize(s + 3 * (twoColor ? 6 : 5));
|
||||
final float[] clippedVerticesArray = clippedVertices.items;
|
||||
|
||||
float[] clippedVerticesItems = clippedVertices.setSize(s + 3 * vertexSize);
|
||||
clippedVerticesItems[s] = x1;
|
||||
clippedVerticesItems[s + 1] = y1;
|
||||
clippedVerticesItems[s + 2] = light;
|
||||
if (!twoColor) {
|
||||
clippedVerticesArray[s] = x1;
|
||||
clippedVerticesArray[s + 1] = y1;
|
||||
clippedVerticesArray[s + 2] = light;
|
||||
clippedVerticesArray[s + 3] = u1;
|
||||
clippedVerticesArray[s + 4] = v1;
|
||||
clippedVerticesItems[s + 3] = u1;
|
||||
clippedVerticesItems[s + 4] = v1;
|
||||
|
||||
clippedVerticesArray[s + 5] = x2;
|
||||
clippedVerticesArray[s + 6] = y2;
|
||||
clippedVerticesArray[s + 7] = light;
|
||||
clippedVerticesArray[s + 8] = u2;
|
||||
clippedVerticesArray[s + 9] = v2;
|
||||
clippedVerticesItems[s + 5] = x2;
|
||||
clippedVerticesItems[s + 6] = y2;
|
||||
clippedVerticesItems[s + 7] = light;
|
||||
clippedVerticesItems[s + 8] = u2;
|
||||
clippedVerticesItems[s + 9] = v2;
|
||||
|
||||
clippedVerticesArray[s + 10] = x3;
|
||||
clippedVerticesArray[s + 11] = y3;
|
||||
clippedVerticesArray[s + 12] = light;
|
||||
clippedVerticesArray[s + 13] = u3;
|
||||
clippedVerticesArray[s + 14] = v3;
|
||||
clippedVerticesItems[s + 10] = x3;
|
||||
clippedVerticesItems[s + 11] = y3;
|
||||
clippedVerticesItems[s + 12] = light;
|
||||
clippedVerticesItems[s + 13] = u3;
|
||||
clippedVerticesItems[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;
|
||||
clippedVerticesItems[s + 3] = dark;
|
||||
clippedVerticesItems[s + 4] = u1;
|
||||
clippedVerticesItems[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;
|
||||
clippedVerticesItems[s + 6] = x2;
|
||||
clippedVerticesItems[s + 7] = y2;
|
||||
clippedVerticesItems[s + 8] = light;
|
||||
clippedVerticesItems[s + 9] = dark;
|
||||
clippedVerticesItems[s + 10] = u2;
|
||||
clippedVerticesItems[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;
|
||||
clippedVerticesItems[s + 12] = x3;
|
||||
clippedVerticesItems[s + 13] = y3;
|
||||
clippedVerticesItems[s + 14] = light;
|
||||
clippedVerticesItems[s + 15] = dark;
|
||||
clippedVerticesItems[s + 16] = u3;
|
||||
clippedVerticesItems[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++;
|
||||
short[] clippedTrianglesItems = clippedTriangles.setSize(s + 3);
|
||||
clippedTrianglesItems[s] = index++;
|
||||
clippedTrianglesItems[s + 1] = index++;
|
||||
clippedTrianglesItems[s + 2] = index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,8 +85,7 @@ public class SkeletonRenderer implements Disposable {
|
||||
batch.draw(region.getRegion().getTexture(), vertices, 0, 20);
|
||||
|
||||
} else if (attachment instanceof ClippingAttachment) {
|
||||
ClippingAttachment clip = (ClippingAttachment)attachment;
|
||||
clipper.clipStart(slot, clip);
|
||||
clipper.clipStart(slot, (ClippingAttachment)attachment);
|
||||
continue;
|
||||
|
||||
} else if (attachment instanceof MeshAttachment) {
|
||||
@ -119,9 +118,9 @@ public class SkeletonRenderer implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
if (clipper.isClipping() && clipper.getClippingAttachment().getEndSlot() == i) clipper.clipEnd();
|
||||
clipper.clipEnd(i);
|
||||
}
|
||||
if (clipper.isClipping()) clipper.clipEnd();
|
||||
clipper.clipEnd(-1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@ -221,9 +220,9 @@ public class SkeletonRenderer implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
if (clipper.isClipping() && clipper.getClippingAttachment().getEndSlot() == i) clipper.clipEnd();
|
||||
clipper.clipEnd(i);
|
||||
}
|
||||
if (clipper.isClipping()) clipper.clipEnd();
|
||||
clipper.clipEnd(-1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
@ -330,9 +329,9 @@ public class SkeletonRenderer implements Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
if (clipper.isClipping() && clipper.getClippingAttachment().getEndSlot() == i) clipper.clipEnd();
|
||||
clipper.clipEnd(i);
|
||||
}
|
||||
if (clipper.isClipping()) clipper.clipEnd();
|
||||
clipper.clipEnd(-1);
|
||||
}
|
||||
|
||||
public void setPremultipliedAlpha (boolean premultipliedAlpha) {
|
||||
@ -342,4 +341,4 @@ public class SkeletonRenderer implements Disposable {
|
||||
public void dispose () {
|
||||
renderer.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,22 +33,22 @@ package com.esotericsoftware.spine.utils;
|
||||
import com.badlogic.gdx.utils.FloatArray;
|
||||
|
||||
public class Clipper {
|
||||
final FloatArray scratch = new FloatArray();
|
||||
private final FloatArray scratch = new FloatArray();
|
||||
|
||||
/** Clips the input triangle against the convex clipping area, which needs to be clockwise. 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 clipping area, which needs to be clockwise. 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. */
|
||||
public boolean clip (float x1, float y1, float x2, float y2, float x3, float y3, FloatArray clippingArea, FloatArray output) {
|
||||
final FloatArray originalOutput = output;
|
||||
FloatArray originalOutput = output;
|
||||
boolean clipped = false;
|
||||
|
||||
// Avoid copy at the end.
|
||||
FloatArray input = null;
|
||||
// avoid copy at the end
|
||||
if ((clippingArea.size / 2) % 2 != 0) {
|
||||
if (clippingArea.size % 4 >= 2) {
|
||||
input = output;
|
||||
output = scratch;
|
||||
} else {
|
||||
} else
|
||||
input = scratch;
|
||||
}
|
||||
|
||||
input.clear();
|
||||
input.add(x1);
|
||||
@ -61,77 +61,51 @@ public class Clipper {
|
||||
input.add(y1);
|
||||
output.clear();
|
||||
|
||||
final float[] clippingVertices = clippingArea.items;
|
||||
final int clippingVerticesLength = clippingArea.size - 2;
|
||||
float[] clippingVertices = clippingArea.items;
|
||||
int clippingVerticesLength = clippingArea.size - 2;
|
||||
for (int i = 0; i < clippingVerticesLength; i += 2) {
|
||||
float edgeX = clippingVertices[i];
|
||||
float edgeY = clippingVertices[i + 1];
|
||||
float edgeX2 = clippingVertices[i + 2];
|
||||
float edgeY2 = clippingVertices[i + 3];
|
||||
float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1];
|
||||
float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3];
|
||||
float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2;
|
||||
|
||||
final float deltaX = edgeX - edgeX2;
|
||||
final float deltaY = edgeY - edgeY2;
|
||||
|
||||
final float[] inputVertices = input.items;
|
||||
final int inputVerticesLength = input.size - 2;
|
||||
|
||||
int numOutside = 0;
|
||||
|
||||
for (int j = 0; j < inputVerticesLength; j += 2) {
|
||||
final float inputX = inputVertices[j];
|
||||
final float inputY = inputVertices[j + 1];
|
||||
final float inputX2 = inputVertices[j + 2];
|
||||
final float inputY2 = inputVertices[j + 3];
|
||||
|
||||
final int side = deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0 ? 1 : -1;
|
||||
final int side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0 ? 1 : -1;
|
||||
float[] inputVertices = input.items;
|
||||
int inputVerticesLength = input.size - 2;
|
||||
int numOutside = 0;
|
||||
for (int ii = 0; ii < inputVerticesLength; ii += 2) {
|
||||
float inputX = inputVertices[ii], inputY = inputVertices[ii + 1];
|
||||
float inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3];
|
||||
|
||||
int side = deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0 ? 1 : -1;
|
||||
int side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0 ? 1 : -1;
|
||||
if (side >= 0) {
|
||||
// v1 inside, v2 inside
|
||||
if (side2 >= 0) {
|
||||
if (side2 >= 0) { // v1 inside, v2 inside
|
||||
output.add(inputX2);
|
||||
output.add(inputY2);
|
||||
}
|
||||
// v1 inside, v2 outside
|
||||
else {
|
||||
float c0 = inputY2 - inputY;
|
||||
float c1 = edgeX2 - edgeX;
|
||||
float c2 = inputX2 - inputX;
|
||||
float c3 = edgeY2 - edgeY;
|
||||
float d = c0 * c1 - c2 * c3;
|
||||
|
||||
} else { // v1 inside, v2 outside
|
||||
float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
||||
float d = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY);
|
||||
float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / d;
|
||||
output.add(edgeX + (edgeX2 - edgeX) * ua);
|
||||
output.add(edgeY + (edgeY2 - edgeY) * ua);
|
||||
clipped = true;
|
||||
}
|
||||
} else {
|
||||
// v1 outside, v2 outside
|
||||
if (side2 < 0) {
|
||||
// no output
|
||||
clipped = true;
|
||||
if (side2 < 0) // v1 outside, v2 outside: no output
|
||||
numOutside += 2;
|
||||
}
|
||||
// v1 outside, v2 inside
|
||||
else {
|
||||
float c0 = inputY2 - inputY;
|
||||
float c1 = edgeX2 - edgeX;
|
||||
float c2 = inputX2 - inputX;
|
||||
float c3 = edgeY2 - edgeY;
|
||||
float d = c0 * c1 - c2 * c3;
|
||||
|
||||
else { // v1 outside, v2 inside
|
||||
float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
||||
float d = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY);
|
||||
float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / d;
|
||||
output.add(edgeX + (edgeX2 - edgeX) * ua);
|
||||
output.add(edgeY + (edgeY2 - edgeY) * ua);
|
||||
|
||||
output.add(inputX2);
|
||||
output.add(inputY2);
|
||||
clipped = true;
|
||||
}
|
||||
clipped = true;
|
||||
}
|
||||
}
|
||||
|
||||
// early out if all edges were outside
|
||||
|
||||
// Early out if all edges were outside.
|
||||
if (numOutside == inputVerticesLength) {
|
||||
originalOutput.clear();
|
||||
return true;
|
||||
@ -141,57 +115,43 @@ public class Clipper {
|
||||
output.add(output.items[1]);
|
||||
|
||||
if (i < clippingVerticesLength - 2) {
|
||||
FloatArray tmp = output;
|
||||
FloatArray temp = output;
|
||||
output = input;
|
||||
output.clear();
|
||||
input = tmp;
|
||||
input = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (originalOutput != output) {
|
||||
originalOutput.clear();
|
||||
originalOutput.addAll(output.items, 0, output.size);
|
||||
}
|
||||
|
||||
originalOutput.setSize(originalOutput.size - 2);
|
||||
originalOutput.addAll(output.items, 0, output.size - 2);
|
||||
} else
|
||||
originalOutput.setSize(originalOutput.size - 2);
|
||||
|
||||
return clipped;
|
||||
}
|
||||
|
||||
public static void makeClockwise (FloatArray poly) {
|
||||
if (isClockwise(poly)) return;
|
||||
|
||||
int lastX = poly.size - 2;
|
||||
final float[] polygon = poly.items;
|
||||
for (int i = 0, n = poly.size / 2; i < n; i += 2) {
|
||||
|
||||
static public void makeClockwise (FloatArray polygon) {
|
||||
float[] vertices = polygon.items;
|
||||
int verticeslength = polygon.size;
|
||||
|
||||
float area = 0, p1x, p1y, p2x, p2y;
|
||||
for (int i = 0, n = verticeslength - 3; i < n; i += 2) {
|
||||
p1x = vertices[i];
|
||||
p1y = vertices[i + 1];
|
||||
p2x = vertices[i + 2];
|
||||
p2y = vertices[i + 3];
|
||||
area += p1x * p2y - p2x * p1y;
|
||||
}
|
||||
if (area + vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1] < 0) return;
|
||||
|
||||
for (int i = 0, lastX = verticeslength - 2, n = verticeslength / 2; i < n; i += 2) {
|
||||
float x = vertices[i], y = vertices[i + 1];
|
||||
int other = lastX - i;
|
||||
float x = polygon[i];
|
||||
float y = polygon[i + 1];
|
||||
polygon[i] = polygon[other];
|
||||
polygon[i + 1] = polygon[other + 1];
|
||||
polygon[other] = x;
|
||||
polygon[other + 1] = y;
|
||||
vertices[i] = vertices[other];
|
||||
vertices[i + 1] = vertices[other + 1];
|
||||
vertices[other] = x;
|
||||
vertices[other + 1] = y;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isClockwise (FloatArray poly) {
|
||||
return area(poly) < 0;
|
||||
}
|
||||
|
||||
public static float area (FloatArray poly) {
|
||||
float area = 0;
|
||||
|
||||
final float[] polyVertices = poly.items;
|
||||
final int polySize = poly.size;
|
||||
for (int i = 0; i < polySize; i += 2) {
|
||||
float x = polyVertices[i];
|
||||
float y = polyVertices[i + 1];
|
||||
float x2 = polyVertices[(i + 2) % poly.size];
|
||||
float y2 = polyVertices[(i + 3) % poly.size];
|
||||
|
||||
area += x * y2 - y * x2;
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,70 +33,61 @@ package com.esotericsoftware.spine.utils;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.BooleanArray;
|
||||
import com.badlogic.gdx.utils.FloatArray;
|
||||
import com.badlogic.gdx.utils.IntArray;
|
||||
import com.badlogic.gdx.utils.Pool;
|
||||
import com.badlogic.gdx.utils.ShortArray;
|
||||
|
||||
public class ConvexDecomposer {
|
||||
static private final int CONCAVE = -1;
|
||||
static private final int CONVEX = 1;
|
||||
|
||||
private Pool<FloatArray> polygonPool = new Pool<FloatArray>() {
|
||||
@Override
|
||||
protected FloatArray newObject () {
|
||||
return new FloatArray(16);
|
||||
}
|
||||
};
|
||||
|
||||
private Pool<ShortArray> polygonIndicesPool = new Pool<ShortArray>() {
|
||||
@Override
|
||||
protected ShortArray newObject () {
|
||||
return new ShortArray(16);
|
||||
}
|
||||
};
|
||||
|
||||
private Array<FloatArray> convexPolygons = new Array<FloatArray>();
|
||||
private Array<ShortArray> convexPolygonsIndices = new Array<ShortArray>();
|
||||
private final Array<FloatArray> convexPolygons = new Array();
|
||||
private final Array<ShortArray> convexPolygonsIndices = new Array();
|
||||
|
||||
private final ShortArray indicesArray = new ShortArray();
|
||||
private short[] indices;
|
||||
private float[] vertices;
|
||||
private int vertexCount;
|
||||
private final IntArray vertexTypes = new IntArray();
|
||||
private final BooleanArray isConcaveArray = new BooleanArray();
|
||||
private final ShortArray triangles = new ShortArray();
|
||||
|
||||
public Array<FloatArray> decompose (FloatArray polygon) {
|
||||
this.vertices = polygon.items;
|
||||
int vertexCount = this.vertexCount = polygon.size / 2;
|
||||
private final Pool<FloatArray> polygonPool = new Pool<FloatArray>() {
|
||||
protected FloatArray newObject () {
|
||||
return new FloatArray(16);
|
||||
}
|
||||
};
|
||||
|
||||
private final Pool<ShortArray> polygonIndicesPool = new Pool<ShortArray>() {
|
||||
protected ShortArray newObject () {
|
||||
return new ShortArray(16);
|
||||
}
|
||||
};
|
||||
|
||||
public Array<FloatArray> decompose (FloatArray input) {
|
||||
vertices = input.items;
|
||||
int vertexCount = this.vertexCount = input.size / 2;
|
||||
|
||||
ShortArray indicesArray = this.indicesArray;
|
||||
indicesArray.clear();
|
||||
indicesArray.ensureCapacity(vertexCount);
|
||||
indicesArray.size = vertexCount;
|
||||
short[] indices = this.indices = indicesArray.items;
|
||||
short[] indices = this.indices = indicesArray.setSize(vertexCount);
|
||||
for (short i = 0; i < vertexCount; i++)
|
||||
indices[i] = i;
|
||||
|
||||
IntArray vertexTypes = this.vertexTypes;
|
||||
vertexTypes.clear();
|
||||
vertexTypes.ensureCapacity(vertexCount);
|
||||
boolean[] isConcave = isConcaveArray.setSize(vertexCount);
|
||||
for (int i = 0, n = vertexCount; i < n; ++i)
|
||||
vertexTypes.add(classifyVertex(i));
|
||||
isConcave[i] = isConcave(i);
|
||||
|
||||
ShortArray triangles = this.triangles;
|
||||
triangles.clear();
|
||||
triangles.ensureCapacity(Math.max(0, vertexCount - 2) * 4);
|
||||
|
||||
// Triangulate
|
||||
// Triangulate.
|
||||
while (this.vertexCount > 3) {
|
||||
int earTipIndex = findEarTip();
|
||||
cutEarTip(earTipIndex);
|
||||
|
||||
int previousIndex = previousIndex(earTipIndex);
|
||||
int nextIndex = earTipIndex == vertexCount ? 0 : earTipIndex;
|
||||
vertexTypes.set(previousIndex, classifyVertex(previousIndex));
|
||||
vertexTypes.set(nextIndex, classifyVertex(nextIndex));
|
||||
isConcave[previousIndex] = isConcave(previousIndex);
|
||||
isConcave[nextIndex] = isConcave(nextIndex);
|
||||
}
|
||||
|
||||
if (this.vertexCount == 3) {
|
||||
@ -110,102 +101,91 @@ public class ConvexDecomposer {
|
||||
polygonIndicesPool.freeAll(convexPolygonsIndices);
|
||||
convexPolygonsIndices.clear();
|
||||
|
||||
ShortArray polyIndices = polygonIndicesPool.obtain();
|
||||
polyIndices.clear();
|
||||
FloatArray poly = polygonPool.obtain();
|
||||
poly.clear();
|
||||
int fanBaseIndex = -1;
|
||||
int lastWinding = 0;
|
||||
ShortArray polygonIndices = polygonIndicesPool.obtain();
|
||||
polygonIndices.clear();
|
||||
FloatArray polygon = polygonPool.obtain();
|
||||
polygon.clear();
|
||||
int fanBaseIndex = -1, lastWinding = 0;
|
||||
|
||||
// Merge subsequent triangles if they form a triangle fan
|
||||
// Merge subsequent triangles if they form a triangle fan.
|
||||
for (int i = 0, n = triangles.size; i < n; i += 3) {
|
||||
int idx1 = triangles.get(i) << 1;
|
||||
int idx2 = triangles.get(i + 1) << 1;
|
||||
int idx3 = triangles.get(i + 2) << 1;
|
||||
int t1 = triangles.get(i) << 1, t2 = triangles.get(i + 1) << 1, t3 = triangles.get(i + 2) << 1;
|
||||
float x1 = input.get(t1), y1 = input.get(t1 + 1);
|
||||
float x2 = input.get(t2), y2 = input.get(t2 + 1);
|
||||
float x3 = input.get(t3), y3 = input.get(t3 + 1);
|
||||
|
||||
float x1 = polygon.get(idx1);
|
||||
float y1 = polygon.get(idx1 + 1);
|
||||
float x2 = polygon.get(idx2);
|
||||
float y2 = polygon.get(idx2 + 1);
|
||||
float x3 = polygon.get(idx3);
|
||||
float y3 = polygon.get(idx3 + 1);
|
||||
|
||||
// if the base of the last triangle
|
||||
// is the same as this triangle's base
|
||||
// check if they form a convex polygon (triangle fan)
|
||||
// If the base of the last triangle is the same as this triangle's base, check if they form a convex polygon (triangle
|
||||
// fan).
|
||||
boolean merged = false;
|
||||
if (fanBaseIndex == idx1) {
|
||||
int o = poly.size - 4;
|
||||
int winding1 = winding(poly.get(o), poly.get(o + 1), poly.get(o + 2), poly.get(o + 3), x3, y3);
|
||||
int winding2 = winding(x3, y3, poly.get(0), poly.get(1), poly.get(2), poly.get(3));
|
||||
if (fanBaseIndex == t1) {
|
||||
int o = polygon.size - 4;
|
||||
int winding1 = winding(polygon.get(o), polygon.get(o + 1), polygon.get(o + 2), polygon.get(o + 3), x3, y3);
|
||||
int winding2 = winding(x3, y3, polygon.get(0), polygon.get(1), polygon.get(2), polygon.get(3));
|
||||
if (winding1 == lastWinding && winding2 == lastWinding) {
|
||||
poly.add(x3);
|
||||
poly.add(y3);
|
||||
polyIndices.add(idx3);
|
||||
polygon.add(x3);
|
||||
polygon.add(y3);
|
||||
polygonIndices.add(t3);
|
||||
merged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise make this triangle
|
||||
// the new base
|
||||
// Otherwise make this triangle the new base.
|
||||
if (!merged) {
|
||||
if (poly.size > 0) {
|
||||
convexPolygons.add(poly);
|
||||
convexPolygonsIndices.add(polyIndices);
|
||||
if (polygon.size > 0) {
|
||||
convexPolygons.add(polygon);
|
||||
convexPolygonsIndices.add(polygonIndices);
|
||||
}
|
||||
poly = polygonPool.obtain();
|
||||
poly.clear();
|
||||
poly.add(x1);
|
||||
poly.add(y1);
|
||||
poly.add(x2);
|
||||
poly.add(y2);
|
||||
poly.add(x3);
|
||||
poly.add(y3);
|
||||
polyIndices = polygonIndicesPool.obtain();
|
||||
polyIndices.clear();
|
||||
polyIndices.add(idx1);
|
||||
polyIndices.add(idx2);
|
||||
polyIndices.add(idx3);
|
||||
polygon = polygonPool.obtain();
|
||||
polygon.clear();
|
||||
polygon.add(x1);
|
||||
polygon.add(y1);
|
||||
polygon.add(x2);
|
||||
polygon.add(y2);
|
||||
polygon.add(x3);
|
||||
polygon.add(y3);
|
||||
polygonIndices = polygonIndicesPool.obtain();
|
||||
polygonIndices.clear();
|
||||
polygonIndices.add(t1);
|
||||
polygonIndices.add(t2);
|
||||
polygonIndices.add(t3);
|
||||
lastWinding = winding(x1, y1, x2, y2, x3, y3);
|
||||
fanBaseIndex = idx1;
|
||||
fanBaseIndex = t1;
|
||||
}
|
||||
}
|
||||
|
||||
if (poly.size > 0) {
|
||||
convexPolygons.add(poly);
|
||||
convexPolygonsIndices.add(polyIndices);
|
||||
if (polygon.size > 0) {
|
||||
convexPolygons.add(polygon);
|
||||
convexPolygonsIndices.add(polygonIndices);
|
||||
}
|
||||
|
||||
// go through the list of polygons and try
|
||||
// to merge the remaining triangles with
|
||||
// the found triangle fans
|
||||
// Go through the list of polygons and try to merge the remaining triangles with the found triangle fans.
|
||||
for (int i = 0, n = convexPolygons.size; i < n; i++) {
|
||||
polyIndices = convexPolygonsIndices.get(i);
|
||||
if (polyIndices.size == 0) continue;
|
||||
int firstIndex = polyIndices.get(0);
|
||||
int lastIndex = polyIndices.get(polyIndices.size - 1);
|
||||
polygonIndices = convexPolygonsIndices.get(i);
|
||||
if (polygonIndices.size == 0) continue;
|
||||
int firstIndex = polygonIndices.get(0);
|
||||
int lastIndex = polygonIndices.get(polygonIndices.size - 1);
|
||||
|
||||
poly = convexPolygons.get(i);
|
||||
int o = poly.size - 4;
|
||||
float prevPrevX = poly.get(o);
|
||||
float prevPrevY = poly.get(o + 1);
|
||||
float prevX = poly.get(o + 2);
|
||||
float prevY = poly.get(o + 3);
|
||||
float firstX = poly.get(0);
|
||||
float firstY = poly.get(1);
|
||||
float secondX = poly.get(2);
|
||||
float secondY = poly.get(3);
|
||||
polygon = convexPolygons.get(i);
|
||||
int o = polygon.size - 4;
|
||||
float prevPrevX = polygon.get(o);
|
||||
float prevPrevY = polygon.get(o + 1);
|
||||
float prevX = polygon.get(o + 2);
|
||||
float prevY = polygon.get(o + 3);
|
||||
float firstX = polygon.get(0);
|
||||
float firstY = polygon.get(1);
|
||||
float secondX = polygon.get(2);
|
||||
float secondY = polygon.get(3);
|
||||
int winding = winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY);
|
||||
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (j == i) continue;
|
||||
ShortArray otherIndices = convexPolygonsIndices.get(j);
|
||||
for (int ii = 0; ii < n; ii++) {
|
||||
if (ii == i) continue;
|
||||
ShortArray otherIndices = convexPolygonsIndices.get(ii);
|
||||
if (otherIndices.size != 3) continue;
|
||||
int otherFirstIndex = otherIndices.get(0);
|
||||
int otherSecondIndex = otherIndices.get(1);
|
||||
int otherLastIndex = otherIndices.get(2);
|
||||
|
||||
FloatArray otherPoly = convexPolygons.get(j);
|
||||
FloatArray otherPoly = convexPolygons.get(ii);
|
||||
float x3 = otherPoly.get(otherPoly.size - 2);
|
||||
float y3 = otherPoly.get(otherPoly.size - 1);
|
||||
|
||||
@ -215,40 +195,38 @@ public class ConvexDecomposer {
|
||||
if (winding1 == winding && winding2 == winding) {
|
||||
otherPoly.clear();
|
||||
otherIndices.clear();
|
||||
poly.add(x3);
|
||||
poly.add(y3);
|
||||
polyIndices.add(otherLastIndex);
|
||||
polygon.add(x3);
|
||||
polygon.add(y3);
|
||||
polygonIndices.add(otherLastIndex);
|
||||
prevPrevX = prevX;
|
||||
prevPrevY = prevY;
|
||||
prevX = x3;
|
||||
prevY = y3;
|
||||
j = 0;
|
||||
ii = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove empty polygons that resulted from the
|
||||
// merge step above
|
||||
Iterator<FloatArray> polyIter = convexPolygons.iterator();
|
||||
while (polyIter.hasNext()) {
|
||||
poly = polyIter.next();
|
||||
if (poly.size == 0) {
|
||||
polyIter.remove();
|
||||
polygonPool.free(poly);
|
||||
// Remove empty polygons that resulted from the merge step above.
|
||||
for (Iterator<FloatArray> iter = convexPolygons.iterator(); iter.hasNext();) {
|
||||
polygon = iter.next();
|
||||
if (polygon.size == 0) {
|
||||
iter.remove();
|
||||
polygonPool.free(polygon);
|
||||
}
|
||||
}
|
||||
|
||||
return convexPolygons;
|
||||
}
|
||||
|
||||
private int classifyVertex (int index) {
|
||||
private boolean isConcave (int index) {
|
||||
short[] indices = this.indices;
|
||||
int previous = indices[previousIndex(index)] * 2;
|
||||
int current = indices[index] * 2;
|
||||
int next = indices[nextIndex(index)] * 2;
|
||||
float[] vertices = this.vertices;
|
||||
return computeSpannedAreaSign(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1],
|
||||
vertices[next], vertices[next + 1]);
|
||||
return !positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next],
|
||||
vertices[next + 1]);
|
||||
}
|
||||
|
||||
private int findEarTip () {
|
||||
@ -256,15 +234,15 @@ public class ConvexDecomposer {
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
if (isEarTip(i)) return i;
|
||||
|
||||
int[] vertexTypes = this.vertexTypes.items;
|
||||
boolean[] isConcave = this.isConcaveArray.items;
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
if (vertexTypes[i] != CONCAVE) return i;
|
||||
if (!isConcave[i]) return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean isEarTip (int earTipIndex) {
|
||||
int[] vertexTypes = this.vertexTypes.items;
|
||||
if (vertexTypes[earTipIndex] == CONCAVE) return false;
|
||||
boolean[] isConcave = this.isConcaveArray.items;
|
||||
if (isConcave[earTipIndex]) return false;
|
||||
|
||||
int previousIndex = previousIndex(earTipIndex);
|
||||
int nextIndex = nextIndex(earTipIndex);
|
||||
@ -278,13 +256,12 @@ public class ConvexDecomposer {
|
||||
float p3x = vertices[p3], p3y = vertices[p3 + 1];
|
||||
|
||||
for (int i = nextIndex(nextIndex); i != previousIndex; i = nextIndex(i)) {
|
||||
if (vertexTypes[i] != CONVEX) {
|
||||
if (isConcave[i]) {
|
||||
int v = indices[i] * 2;
|
||||
float vx = vertices[v];
|
||||
float vy = vertices[v + 1];
|
||||
if (computeSpannedAreaSign(p3x, p3y, p1x, p1y, vx, vy) >= 0) {
|
||||
if (computeSpannedAreaSign(p1x, p1y, p2x, p2y, vx, vy) >= 0) {
|
||||
if (computeSpannedAreaSign(p2x, p2y, p3x, p3y, vx, vy) >= 0) return false;
|
||||
float vx = vertices[v], vy = vertices[v + 1];
|
||||
if (positiveArea(p3x, p3y, p1x, p1y, vx, vy)) {
|
||||
if (positiveArea(p1x, p1y, p2x, p2y, vx, vy)) {
|
||||
if (positiveArea(p2x, p2y, p3x, p3y, vx, vy)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -296,15 +273,12 @@ public class ConvexDecomposer {
|
||||
short[] indices = this.indices;
|
||||
ShortArray triangles = this.triangles;
|
||||
|
||||
short idx1 = indices[previousIndex(earTipIndex)];
|
||||
short idx2 = indices[earTipIndex];
|
||||
short idx3 = indices[nextIndex(earTipIndex)];
|
||||
triangles.add(idx1);
|
||||
triangles.add(idx2);
|
||||
triangles.add(idx3);
|
||||
triangles.add(indices[previousIndex(earTipIndex)]);
|
||||
triangles.add(indices[earTipIndex]);
|
||||
triangles.add(indices[nextIndex(earTipIndex)]);
|
||||
|
||||
indicesArray.removeIndex(earTipIndex);
|
||||
vertexTypes.removeIndex(earTipIndex);
|
||||
isConcaveArray.removeIndex(earTipIndex);
|
||||
vertexCount--;
|
||||
}
|
||||
|
||||
@ -316,16 +290,12 @@ public class ConvexDecomposer {
|
||||
return (index + 1) % vertexCount;
|
||||
}
|
||||
|
||||
static private int computeSpannedAreaSign (float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
|
||||
float area = p1x * (p3y - p2y);
|
||||
area += p2x * (p1y - p3y);
|
||||
area += p3x * (p2y - p1y);
|
||||
return (int)Math.signum(area);
|
||||
static private boolean positiveArea (float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
|
||||
return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0;
|
||||
}
|
||||
|
||||
public static int winding (float v1x, float v1y, float v2x, float v2y, float v3x, float v3y) {
|
||||
float vx = v2x - v1x;
|
||||
float vy = v2y - v1y;
|
||||
return v3x * vy - v3y * vx + vx * v1y - v1x * vy >= 0 ? 1 : -1;
|
||||
static private int winding (float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) {
|
||||
float px = p2x - p1x, py = p2y - p1y;
|
||||
return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user