From 59eb90eb66195483d9756b2c110e83058b91a9be Mon Sep 17 00:00:00 2001 From: badlogic Date: Mon, 24 Apr 2017 13:58:55 +0200 Subject: [PATCH] [c] Added Triangulator. Decomposition is leaking. --- .../minicppunit/MiniCppUnit.hxx | 2 +- .../tests/MemoryTestFixture.cpp | 37 ++ .../tests/MemoryTestFixture.h | 2 + spine-c/spine-c/include/spine/Array.h | 16 +- spine-c/spine-c/include/spine/Triangulator.h | 56 +-- spine-c/spine-c/include/spine/spine.h | 1 + spine-c/spine-c/src/spine/Array.c | 2 + spine-c/spine-c/src/spine/Triangulator.c | 359 ++++++++++++++++++ .../spine/utils/Triangulator.java | 11 + 9 files changed, 443 insertions(+), 43 deletions(-) create mode 100644 spine-c/spine-c/src/spine/Triangulator.c diff --git a/spine-c/spine-c-unit-tests/minicppunit/MiniCppUnit.hxx b/spine-c/spine-c-unit-tests/minicppunit/MiniCppUnit.hxx index b19cbbb57..7ce3d8fd6 100755 --- a/spine-c/spine-c-unit-tests/minicppunit/MiniCppUnit.hxx +++ b/spine-c/spine-c-unit-tests/minicppunit/MiniCppUnit.hxx @@ -201,7 +201,7 @@ public: << errmsgTag_expected() << " " << expected << " " << errmsgTag_butWas() << " " << result << "\n"; - TestsListener::theInstance().errorsLog() << anError; + // TestsListener::theInstance().errorsLog() << anError; TestsListener::theInstance().testHasFailed(anError.str().c_str(), file, linia); } diff --git a/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.cpp b/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.cpp index ee4a8cff9..c6ec41380 100755 --- a/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.cpp +++ b/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.cpp @@ -219,4 +219,41 @@ void MemoryTestFixture::reproduceIssue_Loop() DisposeAll(skeleton, state, stateData, skeletonData, atlas); } +void MemoryTestFixture::triangulator() { + spTriangulator* triangulator = spTriangulator_create(); + spFloatArray* polygon = spFloatArray_create(16); + spFloatArray_add(polygon, 0); + spFloatArray_add(polygon, 0); + spFloatArray_add(polygon, 100); + spFloatArray_add(polygon, 0); + spFloatArray_add(polygon, 100); + spFloatArray_add(polygon, 100); + spFloatArray_add(polygon, 0); + spFloatArray_add(polygon, 100); + + spShortArray* triangles = spTriangulator_triangulate(triangulator, polygon); + ASSERT(triangles->size == 6); + ASSERT(triangles->items[0] == 3); + ASSERT(triangles->items[1] == 0); + ASSERT(triangles->items[2] == 1); + ASSERT(triangles->items[3] == 3); + ASSERT(triangles->items[4] == 1); + ASSERT(triangles->items[5] == 2); + + spArrayFloatArray* polys = spTriangulator_decompose(triangulator, polygon, triangles); + ASSERT(polys->size == 1); + ASSERT(polys->items[0]->size == 8); + ASSERT(polys->items[0]->items[0] == 0); + ASSERT(polys->items[0]->items[1] == 100); + ASSERT(polys->items[0]->items[2] == 0); + ASSERT(polys->items[0]->items[3] == 0); + ASSERT(polys->items[0]->items[4] == 100); + ASSERT(polys->items[0]->items[5] == 0); + ASSERT(polys->items[0]->items[6] == 100); + ASSERT(polys->items[0]->items[7] == 100); + + spFloatArray_dispose(polygon); + spTriangulator_dispose(triangulator); +} + diff --git a/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.h b/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.h index daeff7cd6..bca38e93f 100755 --- a/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.h +++ b/spine-c/spine-c-unit-tests/tests/MemoryTestFixture.h @@ -18,6 +18,7 @@ public: TEST_CASE(reproduceIssue_776); TEST_CASE(reproduceIssue_777); TEST_CASE(reproduceIssue_Loop); + TEST_CASE(triangulator); initialize(); } @@ -31,6 +32,7 @@ public: void reproduceIssue_776(); void reproduceIssue_777(); void reproduceIssue_Loop(); // http://esotericsoftware.com/forum/spine-c-3-5-animation-jerking-7451 + void triangulator(); ////////////////////////////////////////////////////////////////////////// // test fixture setup diff --git a/spine-c/spine-c/include/spine/Array.h b/spine-c/spine-c/include/spine/Array.h index b2af06236..f1a53a71c 100644 --- a/spine-c/spine-c/include/spine/Array.h +++ b/spine-c/spine-c/include/spine/Array.h @@ -40,7 +40,7 @@ extern "C" { name* name##_create(int initialCapacity); \ void name##_dispose(name* self); \ void name##_clear(name* self); \ - void name##_setSize(name* self, int newSize); \ + name* name##_setSize(name* self, int newSize); \ void name##_ensureCapacity(name* self, int newCapacity); \ void name##_add(name* self, itemType value); \ void name##_removeAt(name* self, int index); \ @@ -50,7 +50,7 @@ extern "C" { #define _SP_ARRAY_IMPLEMENT_TYPE(name, itemType) \ name* name##_create(int initialCapacity) { \ - name* array = MALLOC(name, 1); \ + name* array = CALLOC(name, 1); \ array->size = 0; \ array->capacity = initialCapacity; \ array->items = CALLOC(itemType, initialCapacity); \ @@ -63,12 +63,13 @@ extern "C" { void name##_clear(name* self) { \ self->size = 0; \ } \ - void name##_setSize(name* self, int newSize) { \ + name* name##_setSize(name* self, int newSize) { \ self->size = newSize; \ if (self->capacity < newSize) { \ self->capacity = MAX(8, (int)(self->size * 1.75f)); \ self->items = REALLOC(self->items, itemType, self->capacity); \ } \ + return self; \ } \ void name##_ensureCapacity(name* self, int newCapacity) { \ if (self->capacity >= newCapacity) return; \ @@ -82,6 +83,12 @@ extern "C" { } \ self->items[self->size++] = value; \ } \ + void name##_addAll(name* self, name* other) { \ + int i = 0; \ + for (; i < other->size; i++) { \ + name##_add(self, other->items[i]); \ + } \ + } \ void name##_removeAt(name* self, int index) { \ self->size--; \ memmove(self->items + index, self->items + index + 1, sizeof(itemType) * (self->size - index)); \ @@ -107,6 +114,9 @@ extern "C" { _SP_ARRAY_DECLARE_TYPE(spFloatArray, float) _SP_ARRAY_DECLARE_TYPE(spIntArray, int) _SP_ARRAY_DECLARE_TYPE(spShortArray, short) +_SP_ARRAY_DECLARE_TYPE(spArrayFloatArray, spFloatArray*) +_SP_ARRAY_DECLARE_TYPE(spArrayShortArray, spShortArray*) + #ifdef __cplusplus } diff --git a/spine-c/spine-c/include/spine/Triangulator.h b/spine-c/spine-c/include/spine/Triangulator.h index 74d7f30fa..14fa25fd1 100644 --- a/spine-c/spine-c/include/spine/Triangulator.h +++ b/spine-c/spine-c/include/spine/Triangulator.h @@ -31,54 +31,32 @@ #ifndef SPINE_TRIANGULATOR_H #define SPINE_TRIANGULATOR_H +#include + #ifdef __cplusplus extern "C" { #endif -typedef struct spTransformConstraintData { - const char* const name; - int order; - int bonesCount; - spBoneData** const bones; - spBoneData* target; - float rotateMix, translateMix, scaleMix, shearMix; - float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; - int /*boolean*/ relative; - int /*boolean*/ local; +typedef struct spTriangulator { + spArrayFloatArray* convexPolygons; + spArrayShortArray* convexPolygonsIndices; -#ifdef __cplusplus - spTransformConstraintData() : - name(0), - bonesCount(0), - bones(0), - target(0), - rotateMix(0), - translateMix(0), - scaleMix(0), - shearMix(0), - offsetRotation(0), - offsetX(0), - offsetY(0), - offsetScaleX(0), - offsetScaleY(0), - offsetShearY(0), - relative(0), - local(0) { - } -#endif -} spTransformConstraintData; + spShortArray* indicesArray; + spIntArray* isConcaveArray; + spShortArray* triangles; -spTransformConstraintData* spTransformConstraintData_create (const char* name); -void spTransformConstraintData_dispose (spTransformConstraintData* self); + spArrayFloatArray* polygonPool; + spArrayShortArray* polygonIndicesPool; +} spTriangulator; + +spTriangulator* spTriangulator_create(); +spShortArray* spTriangulator_triangulate(spTriangulator* self, spFloatArray* verticesArray); +spArrayFloatArray* spTriangulator_decompose(spTriangulator* self, spFloatArray* verticesArray, spShortArray* triangles); +void spTriangulator_dispose(spTriangulator* self); -#ifdef SPINE_SHORT_NAMES -typedef spTransformConstraintData TransformConstraintData; -#define TransformConstraintData_create(...) spTransformConstraintData_create(__VA_ARGS__) -#define TransformConstraintData_dispose(...) spTransformConstraintData_dispose(__VA_ARGS__) -#endif #ifdef __cplusplus } #endif -#endif /* SPINE_TRIANGULATOR_H_ */ \ No newline at end of file +#endif /* SPINE_TRIANGULATOR_H_ */ diff --git a/spine-c/spine-c/include/spine/spine.h b/spine-c/spine-c/include/spine/spine.h index 96a0d73ba..4837ac31d 100644 --- a/spine-c/spine-c/include/spine/spine.h +++ b/spine-c/spine-c/include/spine/spine.h @@ -54,6 +54,7 @@ #include #include #include +#include #include #include diff --git a/spine-c/spine-c/src/spine/Array.c b/spine-c/spine-c/src/spine/Array.c index 26c6cc35a..e0d827e6a 100644 --- a/spine-c/spine-c/src/spine/Array.c +++ b/spine-c/spine-c/src/spine/Array.c @@ -34,3 +34,5 @@ _SP_ARRAY_IMPLEMENT_TYPE(spFloatArray, float) _SP_ARRAY_IMPLEMENT_TYPE(spIntArray, int) _SP_ARRAY_IMPLEMENT_TYPE(spShortArray, short) +_SP_ARRAY_IMPLEMENT_TYPE(spArrayFloatArray, spFloatArray*) +_SP_ARRAY_IMPLEMENT_TYPE(spArrayShortArray, spShortArray*) diff --git a/spine-c/spine-c/src/spine/Triangulator.c b/spine-c/spine-c/src/spine/Triangulator.c new file mode 100644 index 000000000..11136a54e --- /dev/null +++ b/spine-c/spine-c/src/spine/Triangulator.c @@ -0,0 +1,359 @@ +/****************************************************************************** + * 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 +#include +#include + +spTriangulator* spTriangulator_create() { + spTriangulator* triangulator = CALLOC(spTriangulator, 1); + + triangulator->convexPolygons = spArrayFloatArray_create(16); + triangulator->convexPolygonsIndices = spArrayShortArray_create(16); + triangulator->indicesArray = spShortArray_create(128); + triangulator->isConcaveArray = spIntArray_create(128); + triangulator->triangles = spShortArray_create(128); + triangulator->polygonPool = spArrayFloatArray_create(16); + triangulator->polygonIndicesPool = spArrayShortArray_create(128); + + return triangulator; +} + +void spTriangulator_dispose(spTriangulator* self) { + int i; + + for (i = 0; i < self->convexPolygons->size; i++) { + spFloatArray_dispose(self->convexPolygons->items[i]); + } + spArrayFloatArray_dispose(self->convexPolygons); + + for (i = 0; i < self->convexPolygonsIndices->size; i++) { + spShortArray_dispose(self->convexPolygonsIndices->items[i]); + } + spArrayShortArray_dispose(self->convexPolygonsIndices); + + spShortArray_dispose(self->indicesArray); + spIntArray_dispose(self->isConcaveArray); + spShortArray_dispose(self->triangles); + + for (i = 0; i < self->polygonPool->size; i++) { + spFloatArray_dispose(self->polygonPool->items[i]); + } + spArrayFloatArray_dispose(self->polygonPool); + + for (i = 0; i < self->polygonIndicesPool->size; i++) { + spShortArray_dispose(self->polygonIndicesPool->items[i]); + } + spArrayShortArray_dispose(self->polygonIndicesPool); + + FREE(self); +} + +static spFloatArray* _obtainPolygon(spTriangulator* self) { + if (self->polygonPool->size == 0) return spFloatArray_create(16); + else return spArrayFloatArray_pop(self->polygonPool); +} + +static void _freePolygon(spTriangulator* self, spFloatArray* polygon) { + spArrayFloatArray_add(self->polygonPool, polygon); +} + +static void _freeAllPolygons(spTriangulator* self, spArrayFloatArray* polygons) { + int i; + for (i = 0; i < polygons->size; i++) { + _freePolygon(self, polygons->items[i]); + } +} + +static spShortArray* _obtainPolygonIndices(spTriangulator* self) { + if (self->polygonIndicesPool->size == 0) return spShortArray_create(16); + else return spArrayShortArray_pop(self->polygonIndicesPool); +} + +static void _freePolygonIndices(spTriangulator* self, spShortArray* indices) { + spArrayShortArray_add(self->polygonIndicesPool, indices); +} + +static void _freeAllPolygonIndices(spTriangulator* self, spArrayShortArray* polygonIndices) { + int i; + for (i = 0; i < polygonIndices->size; i++) { + _freePolygonIndices(self, polygonIndices->items[i]); + } +} + +static int _positiveArea(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; +} + +static int _isConcave(int index, int vertexCount, float* vertices, short* indices) { + int previous = indices[(vertexCount + index - 1) % vertexCount] << 1; + int current = indices[index] << 1; + int next = indices[(index + 1) % vertexCount] << 1; + return !_positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], + vertices[next], + vertices[next + 1]); +} + +static 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; +} + +spShortArray* spTriangulator_triangulate(spTriangulator* self, spFloatArray* verticesArray) { + float* vertices = verticesArray->items; + int vertexCount = verticesArray->size >> 1; + int i, n, ii; + + spShortArray* indicesArray = self->indicesArray; + short* indices; + spIntArray* isConcaveArray; + int* isConcave; + spShortArray* triangles; + + spShortArray_clear(indicesArray); + indices = spShortArray_setSize(indicesArray, vertexCount)->items; + for (i = 0; i < vertexCount; i++) + indices[i] = (short)i; + + isConcaveArray = self->isConcaveArray; + isConcave = spIntArray_setSize(isConcaveArray, vertexCount)->items; + for (i = 0, n = vertexCount; i < n; ++i) + isConcave[i] = _isConcave(i, vertexCount, vertices, indices); + + triangles = self->triangles; + spShortArray_clear(triangles); + spShortArray_ensureCapacity(triangles, MAX(0, vertexCount - 2) << 2); + + while (vertexCount > 3) { + int previous = vertexCount - 1, i = 0, next = 1; + int previousIndex, nextIndex; + while (1) { + outer: + if (!isConcave[i]) { + int p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + float p1x = vertices[p1], p1y = vertices[p1 + 1]; + float p2x = vertices[p2], p2y = vertices[p2 + 1]; + float p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) { + int v; + float vx, vy; + if (!isConcave[ii]) continue; + v = indices[ii] << 1; + 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)) goto outer; + } + } + } + break; + } + + if (next == 0) { + do { + if (!isConcave[i]) break; + i--; + } while (i > 0); + break; + } + + previous = i; + i = next; + next = (next + 1) % vertexCount; + } + + spShortArray_add(triangles, indices[(vertexCount + i - 1) % vertexCount]); + spShortArray_add(triangles, indices[i]); + spShortArray_add(triangles, indices[(i + 1) % vertexCount]); + spShortArray_removeAt(indicesArray, i); + spIntArray_removeAt(isConcaveArray, i); + vertexCount--; + + previousIndex = (vertexCount + i - 1) % vertexCount; + nextIndex = i == vertexCount ? 0 : i; + isConcave[previousIndex] = _isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = _isConcave(nextIndex, vertexCount, vertices, indices); + } + + if (vertexCount == 3) { + spShortArray_add(triangles, indices[2]); + spShortArray_add(triangles, indices[0]); + spShortArray_add(triangles, indices[1]); + } + + return triangles; +} + +spArrayFloatArray* spTriangulator_decompose(spTriangulator* self, spFloatArray* verticesArray, spShortArray* triangles) { + float* vertices = verticesArray->items; + + spArrayFloatArray* convexPolygons = self->convexPolygons; + spArrayShortArray* convexPolygonsIndices; + spShortArray* polygonIndices; + spFloatArray* polygon; + + int fanBaseIndex, lastWinding; + short* trianglesItems; + int i, n; + + _freeAllPolygons(self, convexPolygons); + spArrayFloatArray_clear(convexPolygons); + + convexPolygonsIndices = self->convexPolygonsIndices; + _freeAllPolygonIndices(self, convexPolygonsIndices); + spArrayShortArray_clear(convexPolygonsIndices); + + polygonIndices = _obtainPolygonIndices(self); + printf("Obtained indices 0x%x\n", polygonIndices); + spShortArray_clear(polygonIndices); + + polygon = _obtainPolygon(self); + printf("Obtained polygon 0x%x\n", polygon); + spFloatArray_clear(polygon); + + fanBaseIndex = -1; lastWinding = 0; + trianglesItems = triangles->items; + for (i = 0, n = triangles->size; i < n; i += 3) { + int t1 = trianglesItems[i] << 1, t2 = trianglesItems[i + 1] << 1, t3 = trianglesItems[i + 2] << 1; + float x1 = vertices[t1], y1 = vertices[t1 + 1]; + float x2 = vertices[t2], y2 = vertices[t2 + 1]; + float x3 = vertices[t3], y3 = vertices[t3 + 1]; + + int merged = 0; + if (fanBaseIndex == t1) { + int o = polygon->size - 4; + float* p = polygon->items; + int winding1 = _winding(p[o], p[o + 1], p[o + 2], p[o + 3], x3, y3); + int winding2 = _winding(x3, y3, p[0], p[1], p[2], p[3]); + if (winding1 == lastWinding && winding2 == lastWinding) { + spFloatArray_add(polygon, x3); + spFloatArray_add(polygon, y3); + spShortArray_add(polygonIndices, t3); + merged = 1; + } + } + + if (!merged) { + if (polygon->size > 0) { + spArrayFloatArray_add(convexPolygons, polygon); + spArrayShortArray_add(convexPolygonsIndices, polygonIndices); + } + polygon = _obtainPolygon(self); + printf("Obtained polygon #2 0x%x\n", polygon); + spFloatArray_clear(polygon); + spFloatArray_add(polygon, x1); + spFloatArray_add(polygon, y1); + spFloatArray_add(polygon, x2); + spFloatArray_add(polygon, y2); + spFloatArray_add(polygon, x3); + spFloatArray_add(polygon, y3); + polygonIndices = _obtainPolygonIndices(self); + printf("Obtained indices #2 0x%x\n", polygonIndices); + spShortArray_clear(polygonIndices); + spShortArray_add(polygonIndices, t1); + spShortArray_add(polygonIndices, t2); + spShortArray_add(polygonIndices, t3); + lastWinding = _winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + } + + if (polygon->size > 0) { + spArrayFloatArray_add(convexPolygons, polygon); + spArrayShortArray_add(convexPolygonsIndices, polygonIndices); + } + + for (i = 0, n = convexPolygons->size; i < n; i++) { + int firstIndex, lastIndex; + int o; + float* p; + float prevPrevX, prevPrevY, prevX, prevY, firstX, firstY, secondX, secondY; + int winding; + int ii; + + polygonIndices = convexPolygonsIndices->items[i]; + if (polygonIndices->size == 0) continue; + firstIndex = polygonIndices->items[0]; + lastIndex = polygonIndices->items[polygonIndices->size - 1]; + + polygon = convexPolygons->items[i]; + o = polygon->size - 4; + p = polygon->items; + prevPrevX = p[o]; prevPrevY = p[o + 1]; + prevX = p[o + 2]; prevY = p[o + 3]; + firstX = p[0]; firstY = p[1]; + secondX = p[2]; secondY = p[3]; + winding = _winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + + for (ii = 0; ii < n; ii++) { + spShortArray* otherIndices; + int otherFirstIndex, otherSecondIndex, otherLastIndex; + spFloatArray* otherPoly; + float x3, y3; + int winding1, winding2; + + if (ii == i) continue; + otherIndices = convexPolygonsIndices->items[ii]; + if (otherIndices->size != 3) continue; + otherFirstIndex = otherIndices->items[0]; + otherSecondIndex = otherIndices->items[1]; + otherLastIndex = otherIndices->items[2]; + + otherPoly = convexPolygons->items[ii]; + x3 = otherPoly->items[otherPoly->size - 2]; y3 = otherPoly->items[otherPoly->size - 1]; + + if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) continue; + winding1 = _winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3); + winding2 = _winding(x3, y3, firstX, firstY, secondX, secondY); + if (winding1 == winding && winding2 == winding) { + spFloatArray_clear(otherPoly); + spShortArray_clear(otherIndices); + spFloatArray_add(polygon, x3); + spFloatArray_add(polygon, y3); + spShortArray_add(polygonIndices, otherLastIndex); + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = 0; + } + } + } + + for (i = convexPolygons->size - 1; i >= 0; i--) { + polygon = convexPolygons->items[i]; + if (polygon->size == 0) { + spArrayFloatArray_removeAt(convexPolygons, i); + _freePolygon(self, polygon); + } + } + + return convexPolygons; +} diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/Triangulator.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/Triangulator.java index 3b97dee8c..f7ef28207 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/Triangulator.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/Triangulator.java @@ -277,4 +277,15 @@ class Triangulator { float px = p2x - p1x, py = p2y - p1y; return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1; } + + public static void main (String[] args) { + Triangulator triangulator = new Triangulator(); + FloatArray polygon = new FloatArray(); + polygon.addAll(0, 0, 100, 0, 100, 100, 0, 100); + ShortArray triangles = triangulator.triangulate(polygon); + System.out.println(triangles); + + Array polys = triangulator.decompose(polygon, triangles); + System.out.println(polys); + } }