diff --git a/src/cram.c b/src/cram.c index 8774ceb..2c150f0 100644 --- a/src/cram.c +++ b/src/cram.c @@ -297,39 +297,86 @@ void Cram_Internal_PlaceRect(RectPackContext *context, Rect *rect, int32_t freeR context->freeRectangleCount -= 1; /* now we maybe have new free rectangles! */ + /* NOTE: free rectangles can overlap. */ - /* Left side */ - if (rect->x > freeRect.x && rect->x < freeRect.x + freeRect.w) + if (rect->y < freeRect.y + freeRect.h && rect->y + rect->h > freeRect.y) { - newRect = freeRect; - newRect.w = rect->x - freeRect.x; - Cram_Internal_AddFreeRect(context, newRect); + /* Left side */ + if (rect->x > freeRect.x && rect->x < freeRect.x + freeRect.w) + { + newRect = freeRect; + newRect.w = rect->x - freeRect.x; + Cram_Internal_AddFreeRect(context, newRect); + } + + /* Right side */ + if (rect->x + rect->w < freeRect.x + freeRect.w) + { + newRect = freeRect; + newRect.x = rect->x + rect->w; + newRect.w = freeRect.x + freeRect.w - (rect->x + rect->w); + Cram_Internal_AddFreeRect(context, newRect); + } } - /* Right side */ - if (rect->x + rect->w < freeRect.x + freeRect.w) + if (rect->x < freeRect.x + freeRect.w && rect->x + rect->w > freeRect.x) { - newRect = freeRect; - newRect.x = rect->x + rect->w; - newRect.w = freeRect.x + freeRect.w - (rect->x + rect->w); - Cram_Internal_AddFreeRect(context, newRect); - } + /* Top side */ + if (rect->y > freeRect.y && rect->y < freeRect.y + freeRect.h) + { + newRect = freeRect; + newRect.h = rect->y - freeRect.y; + Cram_Internal_AddFreeRect(context, newRect); + } - /* Top side */ - if (rect->y > freeRect.y && rect->y < freeRect.y + freeRect.h) - { - newRect = freeRect; - newRect.h = rect->y - freeRect.y; - Cram_Internal_AddFreeRect(context, newRect); + /* Bottom side */ + if (rect->y + rect->h < freeRect.y + freeRect.h) + { + newRect = freeRect; + newRect.y = rect->y + rect->h; + newRect.h = freeRect.y + freeRect.h - (rect->y + rect->h); + Cram_Internal_AddFreeRect(context, newRect); + } } +} - /* Bottom side */ - if (rect->y + rect->h < freeRect.y + freeRect.h) +static inline uint8_t Cram_Internal_Contains(Rect *a, Rect *b) +{ + return b->x >= a->x && + b->y >= a->y && + b->x + b->w <= a->x + a->w && + b->y + b->h <= a->y + a->h; +} + +void Cram_Internal_PruneRects(RectPackContext *context) +{ + int32_t i, j; + Rect *a; + Rect *b; + + for (i = context->freeRectangleCount - 1; i >= 0; i -= 1) { - newRect = freeRect; - newRect.y = rect->y + rect->h; - newRect.h = freeRect.y + freeRect.h - (rect->y + rect->h); - Cram_Internal_AddFreeRect(context, newRect); + a = &context->freeRectangles[i]; + + for (j = context->freeRectangleCount - 1; j > i; j -= 1) + { + b = &context->freeRectangles[j]; + + if (Cram_Internal_Contains(b, a)) + { + /* plug the hole */ + context->freeRectangles[j] = context->freeRectangles[context->freeRectangleCount - 1]; + context->freeRectangleCount -= 1; + break; + } + + if (Cram_Internal_Contains(a, b)) + { + /* plug the hole */ + context->freeRectangles[j] = context->freeRectangles[context->freeRectangleCount - 1]; + context->freeRectangleCount -= 1; + } + } } } @@ -385,6 +432,8 @@ int8_t Cram_Internal_PackRects(RectPackContext *context, Rect *rects, uint32_t n /* plug the hole */ rectsToPack[bestRectIndex] = rectsToPack[rectsToPackCount - 1]; rectsToPackCount -= 1; + + Cram_Internal_PruneRects(context); } Cram_free(rectsToPack);