[cpp] Skeleton.getBounds() optionally applies clipping, see #2515

This commit is contained in:
Mario Zechner 2024-05-21 12:29:42 +02:00
parent cb3aa4ec7c
commit b8f0aaaacc
5 changed files with 120 additions and 12 deletions

View File

@ -58,6 +58,8 @@ namespace spine {
class Attachment; class Attachment;
class SkeletonClipping;
class SP_API Skeleton : public SpineObject { class SP_API Skeleton : public SpineObject {
friend class AnimationState; friend class AnimationState;
@ -187,7 +189,9 @@ namespace spine {
/// @param outWidth The width of the AABB /// @param outWidth The width of the AABB
/// @param outHeight The height 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. /// @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<float> &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<float> &outVertexBuffer);
void getBounds(float &outX, float &outY, float &outWidth, float &outHeight, Vector<float> &outVertexBuffer, SkeletonClipping *clipper);
Bone *getRootBone(); Bone *getRootBone();

View File

@ -48,6 +48,9 @@ namespace spine {
void clipEnd(); void clipEnd();
void
clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength);
void void
clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength, float *uvs, size_t stride); clipTriangles(float *vertices, unsigned short *triangles, size_t trianglesLength, float *uvs, size_t stride);

View File

@ -41,6 +41,7 @@
#include <spine/BoneData.h> #include <spine/BoneData.h>
#include <spine/IkConstraintData.h> #include <spine/IkConstraintData.h>
#include <spine/ClippingAttachment.h>
#include <spine/MeshAttachment.h> #include <spine/MeshAttachment.h>
#include <spine/PathAttachment.h> #include <spine/PathAttachment.h>
#include <spine/PathConstraintData.h> #include <spine/PathConstraintData.h>
@ -48,6 +49,7 @@
#include <spine/RegionAttachment.h> #include <spine/RegionAttachment.h>
#include <spine/SlotData.h> #include <spine/SlotData.h>
#include <spine/TransformConstraintData.h> #include <spine/TransformConstraintData.h>
#include <spine/SkeletonClipping.h>
#include <spine/ContainerUtil.h> #include <spine/ContainerUtil.h>
@ -456,7 +458,14 @@ Skeleton::findPhysicsConstraint(const String &constraintName) {
} }
void Skeleton::getBounds(float &outX, float &outY, float &outWidth, void Skeleton::getBounds(float &outX, float &outY, float &outWidth,
float &outHeight, Vector<float> &outVertexBuffer) { float &outHeight, Vector<float> &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<float> &outVertexBuffer, SkeletonClipping *clipper) {
float minX = FLT_MAX; float minX = FLT_MAX;
float minY = FLT_MAX; float minY = FLT_MAX;
float maxX = -FLT_MAX; float maxX = -FLT_MAX;
@ -468,6 +477,8 @@ void Skeleton::getBounds(float &outX, float &outY, float &outWidth,
continue; continue;
size_t verticesLength = 0; size_t verticesLength = 0;
Attachment *attachment = slot->getAttachment(); Attachment *attachment = slot->getAttachment();
unsigned short *triangles = NULL;
size_t trianglesLength = 0;
if (attachment != NULL && if (attachment != NULL &&
attachment->getRTTI().instanceOf(RegionAttachment::rtti)) { attachment->getRTTI().instanceOf(RegionAttachment::rtti)) {
@ -479,6 +490,8 @@ void Skeleton::getBounds(float &outX, float &outY, float &outWidth,
outVertexBuffer.setSize(8, 0); outVertexBuffer.setSize(8, 0);
} }
regionAttachment->computeWorldVertices(*slot, outVertexBuffer, 0); regionAttachment->computeWorldVertices(*slot, outVertexBuffer, 0);
triangles = quadIndices;
trianglesLength = 6;
} else if (attachment != NULL && } else if (attachment != NULL &&
attachment->getRTTI().instanceOf(MeshAttachment::rtti)) { attachment->getRTTI().instanceOf(MeshAttachment::rtti)) {
MeshAttachment *mesh = static_cast<MeshAttachment *>(attachment); MeshAttachment *mesh = static_cast<MeshAttachment *>(attachment);
@ -490,18 +503,33 @@ void Skeleton::getBounds(float &outX, float &outY, float &outWidth,
mesh->computeWorldVertices(*slot, 0, verticesLength, mesh->computeWorldVertices(*slot, 0, verticesLength,
outVertexBuffer.buffer(), 0); 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<ClippingAttachment *>(attachment));
}
for (size_t ii = 0; ii < verticesLength; ii += 2) { if (verticesLength > 0) {
float vx = outVertexBuffer[ii]; float *vertices = outVertexBuffer.buffer();
float vy = outVertexBuffer[ii + 1]; 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); minX = MathUtil::min(minX, vx);
minY = MathUtil::min(minY, vy); minY = MathUtil::min(minY, vy);
maxX = MathUtil::max(maxX, vx); maxX = MathUtil::max(maxX, vx);
maxY = MathUtil::max(maxY, vy); maxY = MathUtil::max(maxY, vy);
} }
}
if (clipper != NULL) clipper->clipEnd(*slot);
} }
if (clipper != NULL) clipper->clipEnd();
outX = minX; outX = minX;
outY = minY; outY = minY;

View File

@ -82,6 +82,79 @@ void SkeletonClipping::clipEnd() {
_clippingPolygon.clear(); _clippingPolygon.clear();
} }
void SkeletonClipping::clipTriangles(float *vertices, unsigned short *triangles,
size_t trianglesLength) {
Vector<float> &clipOutput = _clipOutput;
Vector<float> &clippedVertices = _clippedVertices;
Vector<unsigned short> &clippedTriangles = _clippedTriangles;
Vector<Vector<float> *> &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<float> &vertices, Vector<unsigned short> &triangles, Vector<float> &uvs, void SkeletonClipping::clipTriangles(Vector<float> &vertices, Vector<unsigned short> &triangles, Vector<float> &uvs,
size_t stride) { size_t stride) {
clipTriangles(vertices.buffer(), triangles.buffer(), triangles.size(), uvs.buffer(), stride); clipTriangles(vertices.buffer(), triangles.buffer(), triangles.size(), uvs.buffer(), stride);

View File

@ -58,9 +58,9 @@ int main(int argc, char **argv) {
drawable.animationState->getData()->setDefaultMix(0.2f); drawable.animationState->getData()->setDefaultMix(0.2f);
drawable.skeleton->setPosition(400, 500); drawable.skeleton->setPosition(400, 500);
drawable.skeleton->setToSetupPose(); drawable.skeleton->setToSetupPose();
drawable.update(0, spine::Physics_Update);
drawable.animationState->setAnimation(0, "portal", true); drawable.animationState->setAnimation(0, "portal", true);
drawable.animationState->addAnimation(0, "run", true, 0); drawable.animationState->addAnimation(0, "run", true, 0);
drawable.update(0, spine::Physics_Update);
bool quit = false; bool quit = false;
uint64_t lastFrameTime = SDL_GetPerformanceCounter(); uint64_t lastFrameTime = SDL_GetPerformanceCounter();