new free rectangle system

pull/1/head
cosmonaut 2022-07-21 17:34:33 -07:00
parent 2b9a708ceb
commit 651bdf7685
1 changed files with 62 additions and 34 deletions

View File

@ -110,6 +110,10 @@ typedef struct RectPackContext
Rect *freeRectangles; Rect *freeRectangles;
int32_t freeRectangleCount; int32_t freeRectangleCount;
int32_t freeRectangleCapacity; int32_t freeRectangleCapacity;
Rect *newFreeRectangles;
int32_t newFreeRectangleCount;
int32_t newFreeRectangleCapacity;
} RectPackContext; } RectPackContext;
typedef struct PackScoreInfo typedef struct PackScoreInfo
@ -237,10 +241,14 @@ RectPackContext* Cram_Internal_InitRectPacker(uint32_t width, uint32_t height)
context->freeRectangles[0].h = height; context->freeRectangles[0].h = height;
context->freeRectangleCount = 1; context->freeRectangleCount = 1;
context->newFreeRectangleCapacity = INITIAL_FREE_RECTANGLE_CAPACITY;
context->newFreeRectangles = Cram_malloc(sizeof(Rect) * context->freeRectangleCapacity);
context->newFreeRectangleCount = 0;
return context; return context;
} }
/* Uses the bottom left (Tetris) heuristic. */ /* Uses the short side fit heuristic. */
/* TODO: make the heuristic configurable? */ /* TODO: make the heuristic configurable? */
void Cram_Internal_Score( void Cram_Internal_Score(
RectPackContext *context, RectPackContext *context,
@ -249,8 +257,8 @@ void Cram_Internal_Score(
PackScoreInfo *scoreInfo PackScoreInfo *scoreInfo
) { ) {
Rect *freeRect; Rect *freeRect;
int32_t areaFit;
int32_t shortestSide; int32_t shortestSide;
int32_t longestSide;
int32_t i; int32_t i;
scoreInfo->score = INT32_MAX; scoreInfo->score = INT32_MAX;
@ -262,13 +270,13 @@ void Cram_Internal_Score(
if (freeRect->w >= width && freeRect->h >= height) if (freeRect->w >= width && freeRect->h >= height)
{ {
areaFit = freeRect->w * freeRect->h - width * height;
shortestSide = Cram_min(freeRect->w - width, freeRect->h - height); shortestSide = Cram_min(freeRect->w - width, freeRect->h - height);
longestSide = Cram_max(freeRect->w - width, freeRect->h - height);
if (areaFit < scoreInfo->score || (areaFit == scoreInfo->score && shortestSide < scoreInfo->secondaryScore)) if (shortestSide < scoreInfo->score || (shortestSide == scoreInfo->score && longestSide < scoreInfo->secondaryScore))
{ {
scoreInfo->score = areaFit; scoreInfo->score = shortestSide;
scoreInfo->secondaryScore = shortestSide; scoreInfo->secondaryScore = longestSide;
scoreInfo->x = freeRect->x; scoreInfo->x = freeRect->x;
scoreInfo->y = freeRect->y; scoreInfo->y = freeRect->y;
} }
@ -287,45 +295,63 @@ static inline uint8_t Cram_Internal_Contains(Rect* a, Rect* b)
void Cram_Internal_PruneRects(RectPackContext* context) void Cram_Internal_PruneRects(RectPackContext* context)
{ {
int32_t i, j; int32_t i, j;
Rect* a;
Rect* b;
for (i = context->freeRectangleCount - 1; i >= 0; i -= 1) for (i = 0; i < context->freeRectangleCount; i += 1)
{ {
a = &context->freeRectangles[i]; for (j = 0; j < context->newFreeRectangleCount;)
for (j = context->freeRectangleCount - 1; j > i; j -= 1)
{ {
b = &context->freeRectangles[j]; if (Cram_Internal_Contains(&context->freeRectangles[i], &context->newFreeRectangles[j]))
if (Cram_Internal_Contains(b, a))
{ {
/* plug the hole */ /* plug the hole */
context->freeRectangles[j] = context->freeRectangles[context->freeRectangleCount - 1]; context->newFreeRectangles[j] = context->newFreeRectangles[context->newFreeRectangleCount - 1];
context->freeRectangleCount -= 1; context->newFreeRectangleCount -= 1;
break;
} }
else
if (Cram_Internal_Contains(a, b))
{ {
/* plug the hole */ j += 1;
context->freeRectangles[j] = context->freeRectangles[context->freeRectangleCount - 1];
context->freeRectangleCount -= 1;
} }
} }
} }
}
static inline void Cram_Internal_AddFreeRect(RectPackContext *context, Rect rect) if (context->freeRectangleCapacity < context->freeRectangleCount + context->newFreeRectangleCount)
{
if (context->freeRectangleCount == context->freeRectangleCapacity)
{ {
context->freeRectangleCapacity *= 2; context->freeRectangleCapacity = context->freeRectangleCount + context->newFreeRectangleCount;
context->freeRectangles = Cram_realloc(context->freeRectangles, sizeof(Rect) * context->freeRectangleCapacity); context->freeRectangles = Cram_realloc(context->freeRectangles, sizeof(Rect) * context->freeRectangleCapacity);
} }
context->freeRectangles[context->freeRectangleCount] = rect; for (i = 0; i < context->newFreeRectangleCount; i += 1)
context->freeRectangleCount += 1; {
context->freeRectangles[context->freeRectangleCount] = context->newFreeRectangles[i];
context->freeRectangleCount += 1;
}
}
static inline void Cram_Internal_AddNewFreeRect(RectPackContext *context, Rect rect)
{
int32_t i;
for (i = context->newFreeRectangleCount - 1; i >= 0; i -= 1)
{
if (Cram_Internal_Contains(&context->newFreeRectangles[i], &rect))
{
return;
}
if (Cram_Internal_Contains(&rect, &context->newFreeRectangles[i]))
{
context->newFreeRectangles[i] = context->newFreeRectangles[context->newFreeRectangleCount - 1];
context->newFreeRectangleCount -= 1;
}
}
if (context->newFreeRectangleCount == context->newFreeRectangleCapacity)
{
context->newFreeRectangleCapacity *= 2;
context->newFreeRectangles = Cram_realloc(context->newFreeRectangles, sizeof(Rect) * context->newFreeRectangleCapacity);
}
context->newFreeRectangles[context->newFreeRectangleCount] = rect;
context->newFreeRectangleCount += 1;
} }
uint8_t Cram_Internal_SplitRect(RectPackContext *context, Rect *rect, Rect *freeRect) uint8_t Cram_Internal_SplitRect(RectPackContext *context, Rect *rect, Rect *freeRect)
@ -351,7 +377,7 @@ uint8_t Cram_Internal_SplitRect(RectPackContext *context, Rect *rect, Rect *free
{ {
newRect = *freeRect; newRect = *freeRect;
newRect.w = rect->x - freeRect->x; newRect.w = rect->x - freeRect->x;
Cram_Internal_AddFreeRect(context, newRect); Cram_Internal_AddNewFreeRect(context, newRect);
} }
/* Right side */ /* Right side */
@ -360,7 +386,7 @@ uint8_t Cram_Internal_SplitRect(RectPackContext *context, Rect *rect, Rect *free
newRect = *freeRect; newRect = *freeRect;
newRect.x = rect->x + rect->w; newRect.x = rect->x + rect->w;
newRect.w = freeRect->x + freeRect->w - (rect->x + rect->w); newRect.w = freeRect->x + freeRect->w - (rect->x + rect->w);
Cram_Internal_AddFreeRect(context, newRect); Cram_Internal_AddNewFreeRect(context, newRect);
} }
} }
@ -371,7 +397,7 @@ uint8_t Cram_Internal_SplitRect(RectPackContext *context, Rect *rect, Rect *free
{ {
newRect = *freeRect; newRect = *freeRect;
newRect.h = rect->y - freeRect->y; newRect.h = rect->y - freeRect->y;
Cram_Internal_AddFreeRect(context, newRect); Cram_Internal_AddNewFreeRect(context, newRect);
} }
/* Bottom side */ /* Bottom side */
@ -380,7 +406,7 @@ uint8_t Cram_Internal_SplitRect(RectPackContext *context, Rect *rect, Rect *free
newRect = *freeRect; newRect = *freeRect;
newRect.y = rect->y + rect->h; newRect.y = rect->y + rect->h;
newRect.h = freeRect->y + freeRect->h - (rect->y + rect->h); newRect.h = freeRect->y + freeRect->h - (rect->y + rect->h);
Cram_Internal_AddFreeRect(context, newRect); Cram_Internal_AddNewFreeRect(context, newRect);
} }
} }
@ -409,6 +435,8 @@ void Cram_Internal_PlaceRect(RectPackContext *context, Rect *rect)
} }
Cram_Internal_PruneRects(context); Cram_Internal_PruneRects(context);
context->newFreeRectangleCount = 0;
} }
/* Given rects with width and height, modifies rects with packed x and y positions. */ /* Given rects with width and height, modifies rects with packed x and y positions. */