|
@@ -0,0 +1,312 @@
|
|
|
+/******************************************************************************
|
|
|
+ * Spine Runtimes Software License v2.5
|
|
|
+ *
|
|
|
+ * Copyright (c) 2013-2016, Esoteric Software
|
|
|
+ * All rights reserved.
|
|
|
+ *
|
|
|
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
|
|
|
+ * non-transferable license to use, install, execute, and perform the Spine
|
|
|
+ * Runtimes software and derivative works solely for personal or internal
|
|
|
+ * use. Without the written permission of Esoteric Software (see Section 2 of
|
|
|
+ * the Spine Software License Agreement), you may not (a) modify, translate,
|
|
|
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
|
|
|
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
|
|
|
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
|
|
+ * or other intellectual property or proprietary rights notices on or in the
|
|
|
+ * Software, including any copy thereof. Redistributions in binary or source
|
|
|
+ * form must include this license and terms.
|
|
|
+ *
|
|
|
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
|
|
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
|
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
|
|
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
|
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
+ * POSSIBILITY OF SUCH DAMAGE.
|
|
|
+ *****************************************************************************/
|
|
|
+
|
|
|
+#include <spine/SkeletonClipping.h>
|
|
|
+#include <spine/extension.h>
|
|
|
+
|
|
|
+spSkeletonClipping* spSkeletonClipping_create() {
|
|
|
+ spSkeletonClipping* clipping = CALLOC(spSkeletonClipping, 1);
|
|
|
+
|
|
|
+ clipping->triangulator = spTriangulator_create();
|
|
|
+ clipping->clippingPolygon = spFloatArray_create(128);
|
|
|
+ clipping->clipOutput = spFloatArray_create(128);
|
|
|
+ clipping->clippedVertices = spFloatArray_create(128);
|
|
|
+ clipping->clippedUVs = spFloatArray_create(128);
|
|
|
+ clipping->clippedTriangles = spShortArray_create(128);
|
|
|
+ clipping->scratch = spFloatArray_create(128);
|
|
|
+
|
|
|
+ return clipping;
|
|
|
+}
|
|
|
+
|
|
|
+void spSkeletonClipping_dispose(spSkeletonClipping* self) {
|
|
|
+ spTriangulator_dispose(self->triangulator);
|
|
|
+ spFloatArray_dispose(self->clippingPolygon);
|
|
|
+ spFloatArray_dispose(self->clipOutput);
|
|
|
+ spFloatArray_dispose(self->clippedVertices);
|
|
|
+ spFloatArray_dispose(self->clippedUVs);
|
|
|
+ spShortArray_dispose(self->clippedTriangles);
|
|
|
+ spFloatArray_dispose(self->scratch);
|
|
|
+ FREE(self);
|
|
|
+}
|
|
|
+
|
|
|
+static void _makeClockwise (spFloatArray* polygon) {
|
|
|
+ int i, n, lastX;
|
|
|
+ float* vertices = polygon->items;
|
|
|
+ int verticeslength = polygon->size;
|
|
|
+
|
|
|
+ float area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x, p1y, p2x, p2y;
|
|
|
+ for (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 < 0) return;
|
|
|
+
|
|
|
+ for (i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) {
|
|
|
+ float x = vertices[i], y = vertices[i + 1];
|
|
|
+ int other = lastX - i;
|
|
|
+ vertices[i] = vertices[other];
|
|
|
+ vertices[i + 1] = vertices[other + 1];
|
|
|
+ vertices[other] = x;
|
|
|
+ vertices[other + 1] = y;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int spSkeletonClipping_clipStart(spSkeletonClipping* self, spSlot* slot, spClippingAttachment* clip) {
|
|
|
+ int i, n;
|
|
|
+ float* vertices;
|
|
|
+ if (self->clipAttachment) return 0;
|
|
|
+ self->clipAttachment = clip;
|
|
|
+
|
|
|
+ n = clip->super.worldVerticesLength;
|
|
|
+ vertices = spFloatArray_setSize(self->clippingPolygon, n)->items;
|
|
|
+ spVertexAttachment_computeWorldVertices(SUPER(clip), slot, 0, n, vertices, 0, 2);
|
|
|
+ _makeClockwise(self->clippingPolygon);
|
|
|
+ self->clippingPolygons = spTriangulator_decompose(self->triangulator, self->clippingPolygon, spTriangulator_triangulate(self->triangulator, self->clippingPolygon));
|
|
|
+ for (i = 0, n = self->clippingPolygons->size; i < n; i++) {
|
|
|
+ spFloatArray* polygon = self->clippingPolygons->items[i];
|
|
|
+ _makeClockwise(polygon);
|
|
|
+ spFloatArray_add(polygon, polygon->items[0]);
|
|
|
+ spFloatArray_add(polygon, polygon->items[1]);
|
|
|
+ }
|
|
|
+ return self->clippingPolygons->size;
|
|
|
+}
|
|
|
+
|
|
|
+void spSkeletonClipping_clipEnd(spSkeletonClipping* self, spSlot* slot) {
|
|
|
+ if (self->clipAttachment != 0 && self->clipAttachment->endSlot == slot->data) spSkeletonClipping_clipEnd2(self);
|
|
|
+}
|
|
|
+
|
|
|
+void spSkeletonClipping_clipEnd2(spSkeletonClipping* self) {
|
|
|
+ if (!self->clipAttachment) return;
|
|
|
+ self->clipAttachment = 0;
|
|
|
+ self->clippingPolygons = 0;
|
|
|
+ spFloatArray_clear(self->clippedVertices);
|
|
|
+ spFloatArray_clear(self->clippedUVs);
|
|
|
+ spShortArray_clear(self->clippedTriangles);
|
|
|
+ spFloatArray_clear(self->clippingPolygon);
|
|
|
+}
|
|
|
+
|
|
|
+int /*boolean*/ spSkeletonClipping_isClipping(spSkeletonClipping* self) {
|
|
|
+ return self->clipAttachment != 0;
|
|
|
+}
|
|
|
+
|
|
|
+int /*boolean*/ _clip(spSkeletonClipping* self, float x1, float y1, float x2, float y2, float x3, float y3, spFloatArray* clippingArea, spFloatArray* output) {
|
|
|
+ int i;
|
|
|
+ spFloatArray* originalOutput = output;
|
|
|
+ int clipped = 0;
|
|
|
+ float* clippingVertices;
|
|
|
+ int clippingVerticesLast;
|
|
|
+
|
|
|
+ spFloatArray* input = 0;
|
|
|
+ if (clippingArea->size % 4 >= 2) {
|
|
|
+ input = output;
|
|
|
+ output = self->scratch;
|
|
|
+ } else
|
|
|
+ input = self->scratch;
|
|
|
+
|
|
|
+ spFloatArray_clear(input);
|
|
|
+ spFloatArray_add(input, x1);
|
|
|
+ spFloatArray_add(input, y1);
|
|
|
+ spFloatArray_add(input, x2);
|
|
|
+ spFloatArray_add(input, y2);
|
|
|
+ spFloatArray_add(input, x3);
|
|
|
+ spFloatArray_add(input, y3);
|
|
|
+ spFloatArray_add(input, x1);
|
|
|
+ spFloatArray_add(input, y1);
|
|
|
+ spFloatArray_clear(output);
|
|
|
+
|
|
|
+ clippingVertices = clippingArea->items;
|
|
|
+ clippingVerticesLast = clippingArea->size - 4;
|
|
|
+ for (i = 0;; i += 2) {
|
|
|
+ int ii;
|
|
|
+ spFloatArray* temp;
|
|
|
+ float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1];
|
|
|
+ float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3];
|
|
|
+ float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2;
|
|
|
+
|
|
|
+ float* inputVertices = input->items;
|
|
|
+ int inputVerticesLength = input->size - 2, outputStart = output->size;
|
|
|
+ for (ii = 0; ii < inputVerticesLength; ii += 2) {
|
|
|
+ float inputX = inputVertices[ii], inputY = inputVertices[ii + 1];
|
|
|
+ float inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3];
|
|
|
+ int side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0;
|
|
|
+ if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) {
|
|
|
+ float c0, c2;
|
|
|
+ float ua;
|
|
|
+ if (side2) {
|
|
|
+ spFloatArray_add(output, inputX2);
|
|
|
+ spFloatArray_add(output, inputY2);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
|
|
+ ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
|
|
|
+ spFloatArray_add(output, edgeX + (edgeX2 - edgeX) * ua);
|
|
|
+ spFloatArray_add(output, edgeY + (edgeY2 - edgeY) * ua);
|
|
|
+ } else if (side2) {
|
|
|
+ float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
|
|
|
+ float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
|
|
|
+ spFloatArray_add(output, edgeX + (edgeX2 - edgeX) * ua);
|
|
|
+ spFloatArray_add(output, edgeY + (edgeY2 - edgeY) * ua);
|
|
|
+ spFloatArray_add(output, inputX2);
|
|
|
+ spFloatArray_add(output, inputY2);
|
|
|
+ }
|
|
|
+ clipped = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (outputStart == output->size) {
|
|
|
+ spFloatArray_clear(originalOutput);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ spFloatArray_add(output, output->items[0]);
|
|
|
+ spFloatArray_add(output, output->items[1]);
|
|
|
+
|
|
|
+ if (i == clippingVerticesLast) break;
|
|
|
+ temp = output;
|
|
|
+ output = input;
|
|
|
+ spFloatArray_clear(output);
|
|
|
+ input = temp;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (originalOutput != output) {
|
|
|
+ spFloatArray_clear(originalOutput);
|
|
|
+ spFloatArray_addAllValues(originalOutput, output->items, 0, output->size - 2);
|
|
|
+ } else
|
|
|
+ spFloatArray_setSize(originalOutput, originalOutput->size - 2);
|
|
|
+
|
|
|
+ return clipped;
|
|
|
+}
|
|
|
+
|
|
|
+void spSkeletonClipping_clipTriangles(spSkeletonClipping* self, float* vertices, int verticesLength, short* triangles, int trianglesLength, float* uvs) {
|
|
|
+ int i;
|
|
|
+ spFloatArray* clipOutput = self->clipOutput;
|
|
|
+ spFloatArray* clippedVertices = self->clippedVertices;
|
|
|
+ spFloatArray* clippedUVs = self->clippedUVs;
|
|
|
+ spShortArray* clippedTriangles = self->clippedTriangles;
|
|
|
+ spFloatArray** polygons = self->clippingPolygons->items;
|
|
|
+ int polygonsCount = self->clippingPolygons->size;
|
|
|
+ int vertexSize = 2;
|
|
|
+
|
|
|
+ short index = 0;
|
|
|
+ spFloatArray_clear(clippedVertices);
|
|
|
+ spFloatArray_clear(clippedUVs);
|
|
|
+ spShortArray_clear(clippedTriangles);
|
|
|
+ outer:
|
|
|
+ for (i = 0; i < trianglesLength; i += 3) {
|
|
|
+ int p;
|
|
|
+ int vertexOffset = triangles[i] << 1;
|
|
|
+ float x2, y2, u2, v2, x3, y3, u3, v3;
|
|
|
+ float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
|
|
|
+ float u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1];
|
|
|
+
|
|
|
+ vertexOffset = triangles[i + 1] << 1;
|
|
|
+ x2 = vertices[vertexOffset]; y2 = vertices[vertexOffset + 1];
|
|
|
+ u2 = uvs[vertexOffset]; v2 = uvs[vertexOffset + 1];
|
|
|
+
|
|
|
+ vertexOffset = triangles[i + 2] << 1;
|
|
|
+ x3 = vertices[vertexOffset]; y3 = vertices[vertexOffset + 1];
|
|
|
+ u3 = uvs[vertexOffset]; v3 = uvs[vertexOffset + 1];
|
|
|
+
|
|
|
+ for (p = 0; p < polygonsCount; p++) {
|
|
|
+ int s = clippedVertices->size;
|
|
|
+ if (_clip(self, x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) {
|
|
|
+ int ii;
|
|
|
+ float d0, d1, d2, d4, d;
|
|
|
+ short* clippedTrianglesItems;
|
|
|
+ int clipOutputCount;
|
|
|
+ float* clipOutputItems;
|
|
|
+ float* clippedVerticesItems;
|
|
|
+ float* clippedUVsItems;
|
|
|
+
|
|
|
+ int clipOutputLength = clipOutput->size;
|
|
|
+ if (clipOutputLength == 0) continue;
|
|
|
+ d0 = y2 - y3; d1 = x3 - x2; d2 = x1 - x3; d4 = y3 - y1;
|
|
|
+ d = 1 / (d0 * d2 + d1 * (y1 - y3));
|
|
|
+
|
|
|
+ clipOutputCount = clipOutputLength >> 1;
|
|
|
+ clipOutputItems = clipOutput->items;
|
|
|
+ clippedVerticesItems = spFloatArray_setSize(clippedVertices, s + clipOutputCount * vertexSize)->items;
|
|
|
+ clippedUVsItems = spFloatArray_setSize(clippedUVs, s + clipOutputCount * vertexSize)->items;
|
|
|
+ for (ii = 0; ii < clipOutputLength; ii += 2) {
|
|
|
+ float c0, c1, a, b, c;
|
|
|
+ float x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
|
|
|
+ clippedVerticesItems[s] = x;
|
|
|
+ clippedVerticesItems[s + 1] = y;
|
|
|
+ c0 = x - x3; c1 = y - y3;
|
|
|
+ a = (d0 * c0 + d1 * c1) * d;
|
|
|
+ b = (d4 * c0 + d2 * c1) * d;
|
|
|
+ c = 1 - a - b;
|
|
|
+ clippedUVsItems[s] = u1 * a + u2 * b + u3 * c;
|
|
|
+ clippedUVsItems[s + 1] = v1 * a + v2 * b + v3 * c;
|
|
|
+ s += 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ s = clippedTriangles->size;
|
|
|
+ clippedTrianglesItems = spShortArray_setSize(clippedTriangles, s + 3 * (clipOutputCount - 2))->items;
|
|
|
+ clipOutputCount--;
|
|
|
+ for (ii = 1; ii < clipOutputCount; ii++) {
|
|
|
+ clippedTrianglesItems[s] = index;
|
|
|
+ clippedTrianglesItems[s + 1] = (short)(index + ii);
|
|
|
+ clippedTrianglesItems[s + 2] = (short)(index + ii + 1);
|
|
|
+ s += 3;
|
|
|
+ }
|
|
|
+ index += clipOutputCount + 1;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ short* clippedTrianglesItems;
|
|
|
+ float* clippedVerticesItems = spFloatArray_setSize(clippedVertices, s + 3 * vertexSize)->items;
|
|
|
+ float* clippedUVsItems = spFloatArray_setSize(clippedUVs, s + 3 * vertexSize)->items;
|
|
|
+ clippedVerticesItems[s] = x1;
|
|
|
+ clippedVerticesItems[s + 1] = y1;
|
|
|
+ clippedVerticesItems[s + 2] = x2;
|
|
|
+ clippedVerticesItems[s + 3] = y2;
|
|
|
+ clippedVerticesItems[s + 4] = x3;
|
|
|
+ clippedVerticesItems[s + 5] = y3;
|
|
|
+
|
|
|
+ clippedUVsItems[s] = u1;
|
|
|
+ clippedUVsItems[s + 1] = v1;
|
|
|
+ clippedUVsItems[s + 2] = u2;
|
|
|
+ clippedUVsItems[s + 3] = v2;
|
|
|
+ clippedUVsItems[s + 4] = u3;
|
|
|
+ clippedUVsItems[s + 5] = v3;
|
|
|
+
|
|
|
+ s = clippedTriangles->size;
|
|
|
+ clippedTrianglesItems = spShortArray_setSize(clippedTriangles, s + 3)->items;
|
|
|
+ clippedTrianglesItems[s] = index;
|
|
|
+ clippedTrianglesItems[s + 1] = (short)(index + 1);
|
|
|
+ clippedTrianglesItems[s + 2] = (short)(index + 2);
|
|
|
+ index += 3;
|
|
|
+ goto outer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|