new free rectangle system
parent
2b9a708ceb
commit
651bdf7685
94
src/cram.c
94
src/cram.c
|
@ -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,46 +295,64 @@ 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 = context->freeRectangleCount + context->newFreeRectangleCount;
|
||||||
{
|
|
||||||
context->freeRectangleCapacity *= 2;
|
|
||||||
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->freeRectangles[context->freeRectangleCount] = context->newFreeRectangles[i];
|
||||||
context->freeRectangleCount += 1;
|
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. */
|
||||||
|
|
Loading…
Reference in New Issue