From 19687d9957fd5869ca3661cdd2f698e6a7f58b35 Mon Sep 17 00:00:00 2001 From: Stephen Gowen Date: Sat, 25 Nov 2017 15:09:37 -0500 Subject: [PATCH] wip, forgot about SkeletonBounds and SkeletonClipping --- .../include/spine/ClippingAttachment.h | 2 + .../spine-cpp/include/spine/EventTimeline.h | 2 +- .../spine-cpp/include/spine/SkeletonBounds.h | 112 +++++++ .../include/spine/SkeletonClipping.h | 76 +++++ spine-cpp/spine-cpp/include/spine/Slot.h | 1 + spine-cpp/spine-cpp/include/spine/Vector.h | 13 + .../spine-cpp/src/spine/SkeletonBounds.cpp | 267 ++++++++++++++++ .../spine-cpp/src/spine/SkeletonClipping.cpp | 293 ++++++++++++++++++ 8 files changed, 765 insertions(+), 1 deletion(-) create mode 100644 spine-cpp/spine-cpp/include/spine/SkeletonBounds.h create mode 100644 spine-cpp/spine-cpp/include/spine/SkeletonClipping.h create mode 100644 spine-cpp/spine-cpp/src/spine/SkeletonBounds.cpp create mode 100644 spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp diff --git a/spine-cpp/spine-cpp/include/spine/ClippingAttachment.h b/spine-cpp/spine-cpp/include/spine/ClippingAttachment.h index 6ee27813d..6b117c374 100644 --- a/spine-cpp/spine-cpp/include/spine/ClippingAttachment.h +++ b/spine-cpp/spine-cpp/include/spine/ClippingAttachment.h @@ -41,6 +41,8 @@ namespace Spine { SPINE_RTTI_DECL; + friend class SkeletonClipping; + public: ClippingAttachment(std::string name); diff --git a/spine-cpp/spine-cpp/include/spine/EventTimeline.h b/spine-cpp/spine-cpp/include/spine/EventTimeline.h index 1013a26e7..4a844cbd7 100644 --- a/spine-cpp/spine-cpp/include/spine/EventTimeline.h +++ b/spine-cpp/spine-cpp/include/spine/EventTimeline.h @@ -87,7 +87,7 @@ namespace Spine // } // } // for (; frame < frameCount && time >= frames[frame]; frame++) -// firedEvents.Add(events[frame]); +// firedEvents.push_back(events[frame]); // } }; } diff --git a/spine-cpp/spine-cpp/include/spine/SkeletonBounds.h b/spine-cpp/spine-cpp/include/spine/SkeletonBounds.h new file mode 100644 index 000000000..432342a1f --- /dev/null +++ b/spine-cpp/spine-cpp/include/spine/SkeletonBounds.h @@ -0,0 +1,112 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#ifndef Spine_SkeletonBounds_h +#define Spine_SkeletonBounds_h + +#include + +namespace Spine +{ + class Skeleton; + class BoundingBoxAttachment; + + class Polygon; + + /// + /// Collects each BoundingBoxAttachment that is visible and computes the world vertices for its polygon. + /// The polygon vertices are provided along with convenience methods for doing hit detection. + /// + class SkeletonBounds + { + public: + SkeletonBounds(); + + /// + /// Clears any previous polygons, finds all visible bounding box attachments, + /// and computes the world vertices for each bounding box's polygon. + /// @param skeleton The skeleton. + /// @param updateAabb + /// If true, the axis aligned bounding box containing all the polygons is computed. + /// If false, the SkeletonBounds AABB methods will always return true. + /// + void update(Skeleton& skeleton, bool updateAabb); + + /// Returns true if the axis aligned bounding box contains the point. + bool aabbcontainsPoint(float x, float y); + + /// Returns true if the axis aligned bounding box intersects the line segment. + bool aabbintersectsSegment(float x1, float y1, float x2, float y2); + + /// Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. + bool aabbIntersectsSkeleton(SkeletonBounds bounds); + + /// Returns true if the polygon contains the point. + bool containsPoint(Polygon polygon, float x, float y); + + /// Returns the first bounding box attachment that contains the point, or NULL. When doing many checks, it is usually more + /// efficient to only call this method if {@link #aabbcontainsPoint(float, float)} returns true. + BoundingBoxAttachment* containsPoint(float x, float y); + + /// Returns the first bounding box attachment that contains the line segment, or NULL. When doing many checks, it is usually + /// more efficient to only call this method if {@link #aabbintersectsSegment(float, float, float, float)} returns true. + BoundingBoxAttachment* intersectsSegment(float x1, float y1, float x2, float y2); + + /// Returns true if the polygon contains the line segment. + bool intersectsSegment(Polygon* polygon, float x1, float y1, float x2, float y2); + + Polygon* getPolygon(BoundingBoxAttachment* attachment); + + float getWidth(); + float getHeight(); + + private: + Vector _polygonPool; + Vector _boundingBoxes; + Vector _polygons; + float _minX, _minY, _maxX, _maxY; + + void aabbCompute(); + }; + + class Polygon + { + public: + Vector _vertices; + int _count; + + Polygon() : _count(0) + { + _vertices.reserve(16); + } + }; +} + +#endif /* Spine_SkeletonBounds_h */ diff --git a/spine-cpp/spine-cpp/include/spine/SkeletonClipping.h b/spine-cpp/spine-cpp/include/spine/SkeletonClipping.h new file mode 100644 index 000000000..4effd5ede --- /dev/null +++ b/spine-cpp/spine-cpp/include/spine/SkeletonClipping.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * 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. + *****************************************************************************/ + +#ifndef Spine_SkeletonClipping_h +#define Spine_SkeletonClipping_h + +#include +#include + +namespace Spine +{ + class Slot; + class ClippingAttachment; + + class SkeletonClipping + { + public: + SkeletonClipping(); + + int clipStart(Slot& slot, ClippingAttachment* clip); + + void clipEnd(Slot& slot); + + void clipEnd(); + + void clipTriangles(Vector& vertices, int verticesLength, Vector& triangles, int trianglesLength, Vector& uvs); + + bool isClipping(); + + private: + Triangulator _triangulator; + Vector _clippingPolygon; + Vector _clipOutput; + Vector _clippedVertices; + Vector _clippedTriangles; + Vector _clippedUVs; + Vector _scratch; + ClippingAttachment* _clipAttachment; + Vector< Vector > _clippingPolygons; + + /** Clips the input triangle against the convex, clockwise clipping area. 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. */ + bool clip(float x1, float y1, float x2, float y2, float x3, float y3, Vector& clippingArea, Vector& output); + + static void makeClockwise(Vector& polygon); + }; +} + +#endif /* Spine_SkeletonClipping_h */ diff --git a/spine-cpp/spine-cpp/include/spine/Slot.h b/spine-cpp/spine-cpp/include/spine/Slot.h index 26fd37f9a..dc55390e2 100644 --- a/spine-cpp/spine-cpp/include/spine/Slot.h +++ b/spine-cpp/spine-cpp/include/spine/Slot.h @@ -46,6 +46,7 @@ namespace Spine { friend class VertexAttachment; friend class Skeleton; + friend class SkeletonClipping; friend class AttachmentTimeline; friend class ColorTimeline; diff --git a/spine-cpp/spine-cpp/include/spine/Vector.h b/spine-cpp/spine-cpp/include/spine/Vector.h index ec25ecb84..8fc87c490 100644 --- a/spine-cpp/spine-cpp/include/spine/Vector.h +++ b/spine-cpp/spine-cpp/include/spine/Vector.h @@ -79,6 +79,19 @@ namespace Spine return false; } + int indexOf(const T& inValue) + { + for (size_t i = 0; i < _size; ++i) + { + if (_buffer[i] == inValue) + { + return static_cast(i); + } + } + + return -1; + } + void push_back(const T& inValue) { if (_size == _capacity) diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonBounds.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonBounds.cpp new file mode 100644 index 000000000..f4b1a4ce3 --- /dev/null +++ b/spine-cpp/spine-cpp/src/spine/SkeletonBounds.cpp @@ -0,0 +1,267 @@ +/****************************************************************************** +* 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 + +namespace Spine +{ + SkeletonBounds::SkeletonBounds() : _minX(0), _minY(0), _maxX(0), _maxY(0) + { + // Empty + } + + void SkeletonBounds::update(Skeleton& skeleton, bool updateAabb) + { +// Vector slots = skeleton._slots; +// int slotCount = slots.Count; +// +// _boundingBoxes.clear(); +// for (int i = 0, n = _polygons.size(); i < n; ++i) +// { +// _polygonPool.push_back(_polygons[i]); +// } +// +// _polygons.clear(); +// +// for (int i = 0; i < slotCount; i++) +// { +// Slot slot = slots.Items[i]; +// BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment; +// if (boundingBox == NULL) +// { +// continue; +// } +// _boundingBoxes.push_back(boundingBox); +// +// Polygon* polygonP = NULL; +// int poolCount = _polygonPool.size(); +// if (poolCount > 0) +// { +// polygonP = _polygonPool[poolCount - 1]; +// _polygonPool.erase(poolCount - 1); +// } +// else +// { +// polygonP = new Polygon(); +// } +// +// _polygons.push_back(polygonP); +// +// Polygon& polygon = *polygonP; +// +// int count = boundingBox.worldVerticesLength; +// polygon._count = count; +// if (polygon._vertices.size() < count) +// { +// polygon._vertices.reserve(count); +// } +// boundingBox.computeWorldVertices(slot, polygon._vertices); +// } +// +// if (updateAabb) +// { +// aabbCompute(); +// } +// else +// { +// minX = int.MinValue; +// minY = int.MinValue; +// maxX = int.MaxValue; +// maxY = int.MaxValue; +// } + } + + bool SkeletonBounds::aabbcontainsPoint(float x, float y) + { + return x >= _minX && x <= _maxX && y >= _minY && y <= _maxY; + } + + bool SkeletonBounds::aabbintersectsSegment(float x1, float y1, float x2, float y2) + { + float minX = _minX; + float minY = _minY; + float maxX = _maxX; + float maxY = _maxY; + + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + { + return false; + } + + float m = (y2 - y1) / (x2 - x1); + float y = m * (minX - x1) + y1; + if (y > minY && y < maxY) + { + return true; + } + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) + { + return true; + } + float x = (minY - y1) / m + x1; + if (x > minX && x < maxX) + { + return true; + } + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) + { + return true; + } + return false; + } + + bool SkeletonBounds::aabbIntersectsSkeleton(SkeletonBounds bounds) + { + return _minX < bounds._maxX && _maxX > bounds._minX && _minY < bounds._maxY && _maxY > bounds._minY; + } + + bool SkeletonBounds::containsPoint(Polygon polygon, float x, float y) + { +// float[] vertices = polygon.Vertices; +// int nn = polygon.Count; +// +// int prevIndex = nn - 2; + bool inside = false; +// for (int ii = 0; ii < nn; ii += 2) +// { +// float vertexY = vertices[ii + 1]; +// float prevY = vertices[prevIndex + 1]; +// if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) +// { +// float vertexX = vertices[ii]; +// if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) +// { +// inside = !inside; +// } +// } +// prevIndex = ii; +// } + return inside; + } + + BoundingBoxAttachment* SkeletonBounds::containsPoint(float x, float y) + { +// for (int i = 0, n = _polygons.size(); i < n; ++i) +// { +// if (containsPoint(_polygons[i], x, y)) +// { +// return _boundingBoxes[i]; +// } +// } + return NULL; + } + + BoundingBoxAttachment* SkeletonBounds::intersectsSegment(float x1, float y1, float x2, float y2) + { +// for (int i = 0, n = _polygons.size(); i < n; ++i) +// { +// if (intersectsSegment(_polygons[i], x1, y1, x2, y2)) +// { +// return _boundingBoxes[i]; +// } +// } + return NULL; + } + + bool SkeletonBounds::intersectsSegment(Polygon* polygon, float x1, float y1, float x2, float y2) + { +// Vector& vertices = polygon->_vertices; +// int nn = polygon.Count; +// +// float width12 = x1 - x2, height12 = y1 - y2; +// float det1 = x1 * y2 - y1 * x2; +// float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; +// for (int ii = 0; ii < nn; ii += 2) +// { +// float x4 = vertices[ii], y4 = vertices[ii + 1]; +// float det2 = x3 * y4 - y3 * x4; +// float width34 = x3 - x4, height34 = y3 - y4; +// float det3 = width12 * height34 - height12 * width34; +// float x = (det1 * width34 - width12 * det2) / det3; +// if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) +// { +// float y = (det1 * height34 - height12 * det2) / det3; +// if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) +// { +// return true; +// } +// } +// x3 = x4; +// y3 = y4; +// } + return false; + } + + Polygon* SkeletonBounds::getPolygon(BoundingBoxAttachment* attachment) + { + int index = _boundingBoxes.indexOf(attachment); + + return index == -1 ? NULL : _polygons[index]; + } + + float SkeletonBounds::getWidth() + { + return _maxX - _minX; + } + + float SkeletonBounds::getHeight() + { + return _maxY - _minY; + } + + void SkeletonBounds::aabbCompute() + { +// float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; +// for (int i = 0, n = _polygons.size(); i < n; i++) +// { +// Polygon* polygon = _polygons[i]; +// Vector& vertices = polygon->_vertices; +// for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) +// { +// float x = vertices[ii]; +// float y = vertices[ii + 1]; +// minX = Math.Min(minX, x); +// minY = Math.Min(minY, y); +// maxX = Math.Max(maxX, x); +// maxY = Math.Max(maxY, y); +// } +// } +// _minX = minX; +// _minY = minY; +// _maxX = maxX; +// _maxY = maxY; + } +} + diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp new file mode 100644 index 000000000..c3684bfb3 --- /dev/null +++ b/spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp @@ -0,0 +1,293 @@ +/****************************************************************************** +* 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 + +namespace Spine +{ + SkeletonClipping::SkeletonClipping() + { + _clipOutput.reserve(128); + _clippedVertices.reserve(128); + _clippedTriangles.reserve(128); + _clippedUVs.reserve(128); + } + + int SkeletonClipping::clipStart(Slot& slot, ClippingAttachment* clip) + { +// if (clipAttachment != NULL) return 0; +// clipAttachment = clip; +// +// int n = clip.worldVerticesLength; +// float[] vertices = clippingPolygon.Resize(n).Items; +// clip.ComputeWorldVertices(slot, 0, n, vertices, 0, 2); +// makeClockwise(clippingPolygon); +// clippingPolygons = triangulator.Decompose(clippingPolygon, triangulator.Triangulate(clippingPolygon)); +// foreach (var polygon in clippingPolygons) { +// makeClockwise(polygon); +// polygon.push_back(polygon.Items[0]); +// polygon.push_back(polygon.Items[1]); +// } + return static_cast(_clippingPolygons.size()); + } + + void SkeletonClipping::clipEnd(Slot& slot) + { + if (_clipAttachment != NULL && _clipAttachment->_endSlot == &slot._data) + { + clipEnd(); + } + } + + void SkeletonClipping::clipEnd() + { + if (_clipAttachment == NULL) + { + return; + } + + _clipAttachment = NULL; + _clippingPolygons.clear(); + _clippedVertices.clear(); + _clippedTriangles.clear(); + _clippingPolygon.clear(); + } + + void SkeletonClipping::clipTriangles(Vector& vertices, int verticesLength, Vector& triangles, int trianglesLength, Vector& uvs) + { +// Vector clipOutput = _clipOutput, clippedVertices = _clippedVertices; +// var clippedTriangles = _clippedTriangles; +// var polygons = clippingPolygons.Items; +// int polygonsCount = clippingPolygons.Count; +// +// int index = 0; +// clippedVertices.Clear(); +// clippedUVs.Clear(); +// clippedTriangles.Clear(); +// //outer: +// for (int i = 0; i < trianglesLength; i += 3) { +// int vertexOffset = triangles[i] << 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], y2 = vertices[vertexOffset + 1]; +// float u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; +// +// vertexOffset = triangles[i + 2] << 1; +// float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; +// float u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; +// +// for (int p = 0; p < polygonsCount; p++) { +// int s = clippedVertices.Count; +// if (clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { +// int clipOutputLength = clipOutput.Count; +// if (clipOutputLength == 0) continue; +// float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; +// float d = 1 / (d0 * d2 + d1 * (y1 - y3)); +// +// int clipOutputCount = clipOutputLength >> 1; +// float[] clipOutputItems = clipOutput.Items; +// float[] clippedVerticesItems = clippedVertices.Resize(s + clipOutputCount * 2).Items; +// float[] clippedUVsItems = clippedUVs.Resize(s + clipOutputCount * 2).Items; +// for (int ii = 0; ii < clipOutputLength; ii += 2) { +// float x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; +// clippedVerticesItems[s] = x; +// clippedVerticesItems[s + 1] = y; +// 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; +// clippedUVsItems[s] = u1 * a + u2 * b + u3 * c; +// clippedUVsItems[s + 1] = v1 * a + v2 * b + v3 * c; +// s += 2; +// } +// +// s = clippedTriangles.Count; +// int[] clippedTrianglesItems = clippedTriangles.Resize(s + 3 * (clipOutputCount - 2)).Items; +// clipOutputCount--; +// for (int ii = 1; ii < clipOutputCount; ii++) { +// clippedTrianglesItems[s] = index; +// clippedTrianglesItems[s + 1] = index + ii; +// clippedTrianglesItems[s + 2] = index + ii + 1; +// s += 3; +// } +// index += clipOutputCount + 1; +// } +// else { +// float[] clippedVerticesItems = clippedVertices.Resize(s + 3 * 2).Items; +// float[] clippedUVsItems = clippedUVs.Resize(s + 3 * 2).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.Count; +// int[] clippedTrianglesItems = clippedTriangles.Resize(s + 3).Items; +// clippedTrianglesItems[s] = index; +// clippedTrianglesItems[s + 1] = index + 1; +// clippedTrianglesItems[s + 2] = index + 2; +// index += 3; +// break; //continue outer; +// } +// } +// } + } + + bool SkeletonClipping::isClipping() + { + return _clipAttachment != NULL; + } + + bool SkeletonClipping::clip(float x1, float y1, float x2, float y2, float x3, float y3, Vector& clippingArea, Vector& output) + { +// var originalOutput = output; + bool clipped = false; +// +// // Avoid copy at the end. +// Vector input = NULL; +// if (clippingArea.Count % 4 >= 2) { +// input = output; +// output = scratch; +// } else { +// input = scratch; +// } +// +// input.Clear(); +// input.push_back(x1); +// input.push_back(y1); +// input.push_back(x2); +// input.push_back(y2); +// input.push_back(x3); +// input.push_back(y3); +// input.push_back(x1); +// input.push_back(y1); +// output.Clear(); +// +// Vector clippingVertices = clippingArea.Items; +// int clippingVerticesLast = clippingArea.Count - 4; +// for (int i = 0; ; i += 2) { +// float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1]; +// float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3]; +// float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2; +// +// Vector inputVertices = input.Items; +// int inputVerticesLength = input.Count - 2, outputStart = output.Count; +// 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]; +// bool side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0; +// if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) { +// if (side2) { // v1 inside, v2 inside +// output.push_back(inputX2); +// output.push_back(inputY2); +// continue; +// } +// // v1 inside, v2 outside +// float c0 = inputY2 - inputY, c2 = inputX2 - inputX; +// float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY)); +// output.push_back(edgeX + (edgeX2 - edgeX) * ua); +// output.push_back(edgeY + (edgeY2 - edgeY) * ua); +// } +// else if (side2) { // v1 outside, v2 inside +// float c0 = inputY2 - inputY, c2 = inputX2 - inputX; +// float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY)); +// output.push_back(edgeX + (edgeX2 - edgeX) * ua); +// output.push_back(edgeY + (edgeY2 - edgeY) * ua); +// output.push_back(inputX2); +// output.push_back(inputY2); +// } +// clipped = true; +// } +// +// if (outputStart == output.Count) { // All edges outside. +// originalOutput.Clear(); +// return true; +// } +// +// output.push_back(output.Items[0]); +// output.push_back(output.Items[1]); +// +// if (i == clippingVerticesLast) break; +// var temp = output; +// output = input; +// output.Clear(); +// input = temp; +// } +// +// if (originalOutput != output) { +// originalOutput.Clear(); +// for (int i = 0, n = output.Count - 2; i < n; i++) { +// originalOutput.push_back(output.Items[i]); +// } +// } else { +// originalOutput.Resize(originalOutput.Count - 2); +// } + + return clipped; + } + + void SkeletonClipping::makeClockwise(Vector& polygon) + { +// Vector vertices = polygon.Items; +// int verticeslength = polygon.Count; +// +// float area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], 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 < 0) return; +// +// for (int 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; +// } + } +}