diff --git a/spine-cpp/spine-cpp/include/spine/Skeleton.h b/spine-cpp/spine-cpp/include/spine/Skeleton.h index 18e0a6107..cf1df9f88 100644 --- a/spine-cpp/spine-cpp/include/spine/Skeleton.h +++ b/spine-cpp/spine-cpp/include/spine/Skeleton.h @@ -58,6 +58,8 @@ namespace spine { class Attachment; + class SkeletonClipping; + class SP_API Skeleton : public SpineObject { friend class AnimationState; @@ -187,7 +189,9 @@ namespace spine { /// @param outWidth The width of the AABB /// @param outHeight The height of the AABB. /// @param outVertexBuffer Reference to hold a Vector of floats. This method will assign it with new floats as needed. - void getBounds(float &outX, float &outY, float &outWidth, float &outHeight, Vector &outVertexBuffer); + // @param clipping Pointer to a SkeletonClipping instance or NULL. If a clipper is given, clipping attachments will be taken into account. + void getBounds(float &outX, float &outY, float &outWidth, float &outHeight, Vector &outVertexBuffer); + void getBounds(float &outX, float &outY, float &outWidth, float &outHeight, Vector &outVertexBuffer, SkeletonClipping *clipper); Bone *getRootBone(); diff --git a/spine-cpp/spine-cpp/include/spine/SkeletonClipping.h b/spine-cpp/spine-cpp/include/spine/SkeletonClipping.h index a5fbdc7ef..790bb01ee 100644 --- a/spine-cpp/spine-cpp/include/spine/SkeletonClipping.h +++ b/spine-cpp/spine-cpp/include/spine/SkeletonClipping.h @@ -48,6 +48,9 @@ namespace spine { void clipEnd(); + void + clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength); + void clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength, float *uvs, size_t stride); diff --git a/spine-cpp/spine-cpp/src/spine/Skeleton.cpp b/spine-cpp/spine-cpp/src/spine/Skeleton.cpp index 2ecf860a2..d50dfbd88 100644 --- a/spine-cpp/spine-cpp/src/spine/Skeleton.cpp +++ b/spine-cpp/spine-cpp/src/spine/Skeleton.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #include @@ -456,7 +458,14 @@ Skeleton::findPhysicsConstraint(const String &constraintName) { } void Skeleton::getBounds(float &outX, float &outY, float &outWidth, - float &outHeight, Vector &outVertexBuffer) { + float &outHeight, Vector &outVertexBuffer) { + getBounds(outX, outY, outWidth, outHeight, outVertexBuffer, NULL); +} + +static unsigned short quadIndices[] = {0, 1, 2, 2, 3, 0}; + +void Skeleton::getBounds(float &outX, float &outY, float &outWidth, + float &outHeight, Vector &outVertexBuffer, SkeletonClipping *clipper) { float minX = FLT_MAX; float minY = FLT_MAX; float maxX = -FLT_MAX; @@ -468,6 +477,8 @@ void Skeleton::getBounds(float &outX, float &outY, float &outWidth, continue; size_t verticesLength = 0; Attachment *attachment = slot->getAttachment(); + unsigned short *triangles = NULL; + size_t trianglesLength = 0; if (attachment != NULL && attachment->getRTTI().instanceOf(RegionAttachment::rtti)) { @@ -479,6 +490,8 @@ void Skeleton::getBounds(float &outX, float &outY, float &outWidth, outVertexBuffer.setSize(8, 0); } regionAttachment->computeWorldVertices(*slot, outVertexBuffer, 0); + triangles = quadIndices; + trianglesLength = 6; } else if (attachment != NULL && attachment->getRTTI().instanceOf(MeshAttachment::rtti)) { MeshAttachment *mesh = static_cast(attachment); @@ -490,18 +503,33 @@ void Skeleton::getBounds(float &outX, float &outY, float &outWidth, mesh->computeWorldVertices(*slot, 0, verticesLength, outVertexBuffer.buffer(), 0); - } + triangles = mesh->getTriangles().buffer(); + trianglesLength = mesh->getTriangles().size(); + } else if (attachment != NULL && + attachment->getRTTI().instanceOf(ClippingAttachment::rtti) && clipper != NULL) { + clipper->clipStart(*slot, static_cast(attachment)); + } - for (size_t ii = 0; ii < verticesLength; ii += 2) { - float vx = outVertexBuffer[ii]; - float vy = outVertexBuffer[ii + 1]; + if (verticesLength > 0) { + float *vertices = outVertexBuffer.buffer(); + if (clipper != NULL && clipper->isClipping()) { + clipper->clipTriangles(outVertexBuffer.buffer(), triangles, trianglesLength); + vertices = clipper->getClippedVertices().buffer(); + verticesLength = clipper->getClippedVertices().size(); + } + for (size_t ii = 0; ii < verticesLength; ii += 2) { + float vx = vertices[ii]; + float vy = vertices[ii + 1]; - minX = MathUtil::min(minX, vx); - minY = MathUtil::min(minY, vy); - maxX = MathUtil::max(maxX, vx); - maxY = MathUtil::max(maxY, vy); - } + minX = MathUtil::min(minX, vx); + minY = MathUtil::min(minY, vy); + maxX = MathUtil::max(maxX, vx); + maxY = MathUtil::max(maxY, vy); + } + } + if (clipper != NULL) clipper->clipEnd(*slot); } + if (clipper != NULL) clipper->clipEnd(); outX = minX; outY = minY; diff --git a/spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp b/spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp index b095547fd..77c1274ca 100644 --- a/spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp +++ b/spine-cpp/spine-cpp/src/spine/SkeletonClipping.cpp @@ -82,6 +82,79 @@ void SkeletonClipping::clipEnd() { _clippingPolygon.clear(); } +void SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles, + size_t trianglesLength) { + Vector &clipOutput = _clipOutput; + Vector &clippedVertices = _clippedVertices; + Vector &clippedTriangles = _clippedTriangles; + Vector *> &polygons = *_clippingPolygons; + size_t polygonsCount = (*_clippingPolygons).size(); + + size_t index = 0; + clippedVertices.clear(); + _clippedUVs.clear(); + clippedTriangles.clear(); + + int stride = 2; + size_t i = 0; + continue_outer: + for (; i < trianglesLength; i += 3) { + int vertexOffset = triangles[i] * stride; + float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + + vertexOffset = triangles[i + 1] * stride; + float x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + + vertexOffset = triangles[i + 2] * stride; + float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + + for (size_t p = 0; p < polygonsCount; p++) { + size_t s = clippedVertices.size(); + if (clip(x1, y1, x2, y2, x3, y3, &(*polygons[p]), &clipOutput)) { + size_t clipOutputLength = clipOutput.size(); + if (clipOutputLength == 0) continue; + + size_t clipOutputCount = clipOutputLength >> 1; + clippedVertices.setSize(s + clipOutputCount * 2, 0); + for (size_t ii = 0; ii < clipOutputLength; ii += 2) { + float x = clipOutput[ii], y = clipOutput[ii + 1]; + clippedVertices[s] = x; + clippedVertices[s + 1] = y; + s += 2; + } + + s = clippedTriangles.size(); + clippedTriangles.setSize(s + 3 * (clipOutputCount - 2), 0); + clipOutputCount--; + for (size_t ii = 1; ii < clipOutputCount; ii++) { + clippedTriangles[s] = (unsigned short) (index); + clippedTriangles[s + 1] = (unsigned short) (index + ii); + clippedTriangles[s + 2] = (unsigned short) (index + ii + 1); + s += 3; + } + index += clipOutputCount + 1; + } else { + clippedVertices.setSize(s + 3 * 2, 0); + clippedVertices[s] = x1; + clippedVertices[s + 1] = y1; + clippedVertices[s + 2] = x2; + clippedVertices[s + 3] = y2; + clippedVertices[s + 4] = x3; + clippedVertices[s + 5] = y3; + + s = clippedTriangles.size(); + clippedTriangles.setSize(s + 3, 0); + clippedTriangles[s] = (unsigned short) index; + clippedTriangles[s + 1] = (unsigned short) (index + 1); + clippedTriangles[s + 2] = (unsigned short) (index + 2); + index += 3; + i += 3; + goto continue_outer; + } + } + } +} + void SkeletonClipping::clipTriangles(Vector &vertices, Vector &triangles, Vector &uvs, size_t stride) { clipTriangles(vertices.buffer(), triangles.buffer(), triangles.size(), uvs.buffer(), stride); diff --git a/spine-sdl/example/main.cpp b/spine-sdl/example/main.cpp index 654b26e8a..8f8555bbc 100644 --- a/spine-sdl/example/main.cpp +++ b/spine-sdl/example/main.cpp @@ -58,9 +58,9 @@ int main(int argc, char **argv) { drawable.animationState->getData()->setDefaultMix(0.2f); drawable.skeleton->setPosition(400, 500); drawable.skeleton->setToSetupPose(); - drawable.update(0, spine::Physics_Update); drawable.animationState->setAnimation(0, "portal", true); drawable.animationState->addAnimation(0, "run", true, 0); + drawable.update(0, spine::Physics_Update); bool quit = false; uint64_t lastFrameTime = SDL_GetPerformanceCounter();