[cocos2dx] SkeletonRenderer:getBoundingBox() recalculates the bounds on each call instead of relying on draw() having calculated it. Closes #1483.

This commit is contained in:
badlogic 2019-09-23 16:03:37 +02:00
parent 3034d93178
commit fba357ed74

View File

@ -254,13 +254,12 @@ namespace spine {
void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) {
// Early exit if the skeleton is invisible // Early exit if the skeleton is invisible
if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0){ if (getDisplayedOpacity() == 0 || _skeleton->getColor().a == 0) {
return; return;
} }
const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex); const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex);
if (coordCount == 0) if (coordCount == 0) {
{
return; return;
} }
assert(coordCount % 2 == 0); assert(coordCount % 2 == 0);
@ -273,8 +272,7 @@ namespace spine {
const cocos2d::Rect brect = computeBoundingRect(worldCoords, coordCount / 2); const cocos2d::Rect brect = computeBoundingRect(worldCoords, coordCount / 2);
_boundingRect = brect; _boundingRect = brect;
if (camera && cullRectangle(transform, brect, *camera)) if (camera && cullRectangle(transform, brect, *camera)) {
{
VLA_FREE(worldCoords); VLA_FREE(worldCoords);
return; return;
} }
@ -726,7 +724,13 @@ namespace spine {
} }
cocos2d::Rect SkeletonRenderer::getBoundingBox () const { cocos2d::Rect SkeletonRenderer::getBoundingBox () const {
return _boundingRect; const int coordCount = computeTotalCoordCount(*_skeleton, _startSlotIndex, _endSlotIndex);
if (coordCount == 0) return { 0, 0, 0, 0 };
VLA(float, worldCoords, coordCount);
transformWorldVertices(worldCoords, coordCount, *_skeleton, _startSlotIndex, _endSlotIndex);
const cocos2d::Rect bb = computeBoundingRect(worldCoords, coordCount / 2);
VLA_FREE(worldCoords);
return bb;
} }
// --- Convenience methods for Skeleton_* functions. // --- Convenience methods for Skeleton_* functions.
@ -862,8 +866,7 @@ namespace spine {
} }
namespace { namespace {
cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount) cocos2d::Rect computeBoundingRect(const float* coords, int vertexCount) {
{
assert(coords); assert(coords);
assert(vertexCount > 0); assert(vertexCount > 0);
@ -872,8 +875,7 @@ namespace spine {
float minY = v[1]; float minY = v[1];
float maxX = minX; float maxX = minX;
float maxY = minY; float maxY = minY;
for (int i = 1; i < vertexCount; ++i) for (int i = 1; i < vertexCount; ++i) {
{
v += 2; v += 2;
float x = v[0]; float x = v[0];
float y = v[1]; float y = v[1];
@ -885,37 +887,30 @@ namespace spine {
return { minX, minY, maxX - minX, maxY - minY }; return { minX, minY, maxX - minX, maxY - minY };
} }
bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex) bool slotIsOutRange(Slot& slot, int startSlotIndex, int endSlotIndex) {
{
const int index = slot.getData().getIndex(); const int index = slot.getData().getIndex();
return startSlotIndex > index || endSlotIndex < index; return startSlotIndex > index || endSlotIndex < index;
} }
int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex) int computeTotalCoordCount(Skeleton& skeleton, int startSlotIndex, int endSlotIndex) {
{
int coordCount = 0; int coordCount = 0;
for (size_t i = 0; i < skeleton.getSlots().size(); ++i) for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
{
Slot& slot = *skeleton.getSlots()[i]; Slot& slot = *skeleton.getSlots()[i];
Attachment* const attachment = slot.getAttachment(); Attachment* const attachment = slot.getAttachment();
if (!attachment) if (!attachment) {
{
continue; continue;
} }
if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) {
{
continue; continue;
} }
// Early exit if slot is invisible // Early exit if slot is invisible
if (slot.getColor().a == 0) { if (slot.getColor().a == 0) {
continue; continue;
} }
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
{
coordCount += 8; coordCount += 8;
} }
else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
{
MeshAttachment* const mesh = static_cast<MeshAttachment*>(attachment); MeshAttachment* const mesh = static_cast<MeshAttachment*>(attachment);
coordCount += mesh->getWorldVerticesLength(); coordCount += mesh->getWorldVerticesLength();
} }
@ -924,36 +919,29 @@ namespace spine {
} }
void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex) void transformWorldVertices(float* dstCoord, int coordCount, Skeleton& skeleton, int startSlotIndex, int endSlotIndex) {
{
float* dstPtr = dstCoord; float* dstPtr = dstCoord;
#ifndef NDEBUG #ifndef NDEBUG
float* const dstEnd = dstCoord + coordCount; float* const dstEnd = dstCoord + coordCount;
#endif #endif
for (size_t i = 0; i < skeleton.getSlots().size(); ++i) for (size_t i = 0; i < skeleton.getSlots().size(); ++i) {
{
/*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw /*const*/ Slot& slot = *skeleton.getDrawOrder()[i]; // match the draw order of SkeletonRenderer::Draw
Attachment* const attachment = slot.getAttachment(); Attachment* const attachment = slot.getAttachment();
if (!attachment) if (!attachment) {
{
continue; continue;
} }
if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) if (slotIsOutRange(slot, startSlotIndex, endSlotIndex)) {
{
continue; continue;
} }
if (slot.getColor().a == 0) { if (slot.getColor().a == 0) {
continue; continue;
} }
if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) {
{
RegionAttachment* const regionAttachment = static_cast<RegionAttachment*>(attachment); RegionAttachment* const regionAttachment = static_cast<RegionAttachment*>(attachment);
assert(dstPtr + 8 <= dstEnd); assert(dstPtr + 8 <= dstEnd);
regionAttachment->computeWorldVertices(slot.getBone(), dstPtr, 0, 2); regionAttachment->computeWorldVertices(slot.getBone(), dstPtr, 0, 2);
dstPtr += 8; dstPtr += 8;
} } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) {
else if (attachment->getRTTI().isExactly(MeshAttachment::rtti))
{
MeshAttachment* const mesh = static_cast<MeshAttachment*>(attachment); MeshAttachment* const mesh = static_cast<MeshAttachment*>(attachment);
assert(dstPtr + mesh->getWorldVerticesLength() <= dstEnd); assert(dstPtr + mesh->getWorldVerticesLength() <= dstEnd);
mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), dstPtr, 0, 2); mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), dstPtr, 0, 2);
@ -963,16 +951,11 @@ namespace spine {
assert(dstPtr == dstEnd); assert(dstPtr == dstEnd);
} }
void interleaveCoordinates(float* dst, const float* src, int count, int dstStride) void interleaveCoordinates(float* dst, const float* src, int count, int dstStride) {
{ if (dstStride == 2) {
if (dstStride == 2)
{
memcpy(dst, src, sizeof(float) * count * 2); memcpy(dst, src, sizeof(float) * count * 2);
} } else {
else for (int i = 0; i < count; ++i) {
{
for (int i = 0; i < count; ++i)
{
dst[0] = src[0]; dst[0] = src[0];
dst[1] = src[1]; dst[1] = src[1];
dst += dstStride; dst += dstStride;
@ -982,8 +965,7 @@ namespace spine {
} }
BlendFunc makeBlendFunc(int blendMode, bool premultipliedAlpha) BlendFunc makeBlendFunc(int blendMode, bool premultipliedAlpha) {
{
BlendFunc blendFunc; BlendFunc blendFunc;
switch (blendMode) { switch (blendMode) {
case BlendMode_Additive: case BlendMode_Additive:
@ -1007,8 +989,7 @@ namespace spine {
} }
bool cullRectangle(const Mat4& transform, const cocos2d::Rect& rect, const Camera& camera) bool cullRectangle(const Mat4& transform, const cocos2d::Rect& rect, const Camera& camera) {
{
// Compute rectangle center and half extents in local space // Compute rectangle center and half extents in local space
// TODO: Pass the bounding rectangle with this representation directly // TODO: Pass the bounding rectangle with this representation directly
const float halfRectWidth = rect.size.width * 0.5f; const float halfRectWidth = rect.size.width * 0.5f;
@ -1042,26 +1023,22 @@ namespace spine {
// e.g. left culling <==> (c_cx + c_ex) / cw < -1 <==> (c_cx + c_ex) < -cw // e.g. left culling <==> (c_cx + c_ex) / cw < -1 <==> (c_cx + c_ex) < -cw
// Left // Left
if (c_cx + c_ex < -c_w) if (c_cx + c_ex < -c_w) {
{
return true; return true;
} }
// Right // Right
if (c_cx - c_ex > c_w) if (c_cx - c_ex > c_w) {
{
return true; return true;
} }
// Bottom // Bottom
if (c_cy + c_ey < -c_w) if (c_cy + c_ey < -c_w) {
{
return true; return true;
} }
// Top // Top
if (c_cy - c_ey > c_w) if (c_cy - c_ey > c_w) {
{
return true; return true;
} }
@ -1069,8 +1046,7 @@ namespace spine {
} }
Color4B ColorToColor4B(const Color& color) Color4B ColorToColor4B(const Color& color) {
{
return { (GLubyte)(color.r * 255.f), (GLubyte)(color.g * 255.f), (GLubyte)(color.b * 255.f), (GLubyte)(color.a * 255.f) }; return { (GLubyte)(color.r * 255.f), (GLubyte)(color.g * 255.f), (GLubyte)(color.b * 255.f), (GLubyte)(color.a * 255.f) };
} }
} }