correctly implement placement
parent
d86e094933
commit
2b9a708ceb
190
src/cram.c
190
src/cram.c
|
@ -118,7 +118,6 @@ typedef struct PackScoreInfo
|
||||||
int32_t secondaryScore;
|
int32_t secondaryScore;
|
||||||
int32_t x;
|
int32_t x;
|
||||||
int32_t y;
|
int32_t y;
|
||||||
int32_t freeRectIndex;
|
|
||||||
} PackScoreInfo;
|
} PackScoreInfo;
|
||||||
|
|
||||||
/* Pixel data functions */
|
/* Pixel data functions */
|
||||||
|
@ -250,7 +249,8 @@ void Cram_Internal_Score(
|
||||||
PackScoreInfo *scoreInfo
|
PackScoreInfo *scoreInfo
|
||||||
) {
|
) {
|
||||||
Rect *freeRect;
|
Rect *freeRect;
|
||||||
int32_t topSideY;
|
int32_t areaFit;
|
||||||
|
int32_t shortestSide;
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
|
||||||
scoreInfo->score = INT32_MAX;
|
scoreInfo->score = INT32_MAX;
|
||||||
|
@ -262,12 +262,13 @@ void Cram_Internal_Score(
|
||||||
|
|
||||||
if (freeRect->w >= width && freeRect->h >= height)
|
if (freeRect->w >= width && freeRect->h >= height)
|
||||||
{
|
{
|
||||||
topSideY = freeRect->y + height;
|
areaFit = freeRect->w * freeRect->h - width * height;
|
||||||
if (topSideY < scoreInfo->score || (topSideY == scoreInfo->score && freeRect->x < scoreInfo->secondaryScore))
|
shortestSide = Cram_min(freeRect->w - width, freeRect->h - height);
|
||||||
|
|
||||||
|
if (areaFit < scoreInfo->score || (areaFit == scoreInfo->score && shortestSide < scoreInfo->secondaryScore))
|
||||||
{
|
{
|
||||||
scoreInfo->score = topSideY;
|
scoreInfo->score = areaFit;
|
||||||
scoreInfo->secondaryScore = freeRect->x;
|
scoreInfo->secondaryScore = shortestSide;
|
||||||
scoreInfo->freeRectIndex = i;
|
|
||||||
scoreInfo->x = freeRect->x;
|
scoreInfo->x = freeRect->x;
|
||||||
scoreInfo->y = freeRect->y;
|
scoreInfo->y = freeRect->y;
|
||||||
}
|
}
|
||||||
|
@ -275,72 +276,7 @@ void Cram_Internal_Score(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Cram_Internal_AddFreeRect(RectPackContext *context, Rect rect)
|
static inline uint8_t Cram_Internal_Contains(Rect* a, Rect* b)
|
||||||
{
|
|
||||||
if (context->freeRectangleCount == context->freeRectangleCapacity)
|
|
||||||
{
|
|
||||||
context->freeRectangleCapacity *= 2;
|
|
||||||
context->freeRectangles = Cram_realloc(context->freeRectangles, sizeof(Rect) * context->freeRectangleCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
context->freeRectangles[context->freeRectangleCount] = rect;
|
|
||||||
context->freeRectangleCount += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cram_Internal_PlaceRect(RectPackContext *context, Rect *rect, int32_t freeRectIndex)
|
|
||||||
{
|
|
||||||
Rect freeRect = context->freeRectangles[freeRectIndex];
|
|
||||||
Rect newRect;
|
|
||||||
|
|
||||||
/* plug the hole */
|
|
||||||
context->freeRectangles[freeRectIndex] = context->freeRectangles[context->freeRectangleCount - 1];
|
|
||||||
context->freeRectangleCount -= 1;
|
|
||||||
|
|
||||||
/* now we maybe have new free rectangles! */
|
|
||||||
/* NOTE: free rectangles can overlap. */
|
|
||||||
|
|
||||||
if (rect->y < freeRect.y + freeRect.h && rect->y + rect->h > freeRect.y)
|
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rect->x < freeRect.x + freeRect.w && rect->x + rect->w > freeRect.x)
|
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint8_t Cram_Internal_Contains(Rect *a, Rect *b)
|
|
||||||
{
|
{
|
||||||
return b->x >= a->x &&
|
return b->x >= a->x &&
|
||||||
b->y >= a->y &&
|
b->y >= a->y &&
|
||||||
|
@ -348,11 +284,11 @@ static inline uint8_t Cram_Internal_Contains(Rect *a, Rect *b)
|
||||||
b->y + b->h <= a->y + a->h;
|
b->y + b->h <= a->y + a->h;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cram_Internal_PruneRects(RectPackContext *context)
|
void Cram_Internal_PruneRects(RectPackContext* context)
|
||||||
{
|
{
|
||||||
int32_t i, j;
|
int32_t i, j;
|
||||||
Rect *a;
|
Rect* a;
|
||||||
Rect *b;
|
Rect* b;
|
||||||
|
|
||||||
for (i = context->freeRectangleCount - 1; i >= 0; i -= 1)
|
for (i = context->freeRectangleCount - 1; i >= 0; i -= 1)
|
||||||
{
|
{
|
||||||
|
@ -380,6 +316,101 @@ void Cram_Internal_PruneRects(RectPackContext *context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void Cram_Internal_AddFreeRect(RectPackContext *context, Rect rect)
|
||||||
|
{
|
||||||
|
if (context->freeRectangleCount == context->freeRectangleCapacity)
|
||||||
|
{
|
||||||
|
context->freeRectangleCapacity *= 2;
|
||||||
|
context->freeRectangles = Cram_realloc(context->freeRectangles, sizeof(Rect) * context->freeRectangleCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
context->freeRectangles[context->freeRectangleCount] = rect;
|
||||||
|
context->freeRectangleCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Cram_Internal_SplitRect(RectPackContext *context, Rect *rect, Rect *freeRect)
|
||||||
|
{
|
||||||
|
Rect newRect;
|
||||||
|
|
||||||
|
/* Test intersection */
|
||||||
|
if ( rect->x >= freeRect->x + freeRect->w ||
|
||||||
|
rect->y >= freeRect->y + freeRect->h ||
|
||||||
|
rect->x + rect->w <= freeRect->x ||
|
||||||
|
rect->y + rect->h <= freeRect->y )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now we have new free rectangles! */
|
||||||
|
/* NOTE: free rectangles can overlap. */
|
||||||
|
|
||||||
|
if (rect->y < freeRect->y + freeRect->h && rect->y + rect->h > freeRect->y)
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rect->x < freeRect->x + freeRect->w && rect->x + rect->w > freeRect->x)
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cram_Internal_PlaceRect(RectPackContext *context, Rect *rect)
|
||||||
|
{
|
||||||
|
Rect *freeRect;
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < context->freeRectangleCount;)
|
||||||
|
{
|
||||||
|
freeRect = &context->freeRectangles[i];
|
||||||
|
|
||||||
|
if (Cram_Internal_SplitRect(context, rect, freeRect))
|
||||||
|
{
|
||||||
|
/* plug the hole */
|
||||||
|
context->freeRectangles[i] = context->freeRectangles[context->freeRectangleCount - 1];
|
||||||
|
context->freeRectangleCount -= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cram_Internal_PruneRects(context);
|
||||||
|
}
|
||||||
|
|
||||||
/* 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. */
|
||||||
int8_t Cram_Internal_PackRects(RectPackContext *context, Rect *rects, uint32_t numRects)
|
int8_t Cram_Internal_PackRects(RectPackContext *context, Rect *rects, uint32_t numRects)
|
||||||
{
|
{
|
||||||
|
@ -389,7 +420,7 @@ int8_t Cram_Internal_PackRects(RectPackContext *context, Rect *rects, uint32_t n
|
||||||
int32_t bestScore = INT32_MAX;
|
int32_t bestScore = INT32_MAX;
|
||||||
int32_t bestSecondaryScore = INT32_MAX;
|
int32_t bestSecondaryScore = INT32_MAX;
|
||||||
PackScoreInfo scoreInfo;
|
PackScoreInfo scoreInfo;
|
||||||
int32_t bestRectIndex, bestX, bestY, bestFreeRectIndex;
|
int32_t bestRectIndex, bestX, bestY;
|
||||||
int32_t i, repeat;
|
int32_t i, repeat;
|
||||||
|
|
||||||
for (i = 0; i < numRects; i += 1)
|
for (i = 0; i < numRects; i += 1)
|
||||||
|
@ -412,7 +443,6 @@ int8_t Cram_Internal_PackRects(RectPackContext *context, Rect *rects, uint32_t n
|
||||||
bestScore = scoreInfo.score;
|
bestScore = scoreInfo.score;
|
||||||
bestSecondaryScore = scoreInfo.secondaryScore;
|
bestSecondaryScore = scoreInfo.secondaryScore;
|
||||||
bestRectIndex = i;
|
bestRectIndex = i;
|
||||||
bestFreeRectIndex = scoreInfo.freeRectIndex;
|
|
||||||
bestX = scoreInfo.x;
|
bestX = scoreInfo.x;
|
||||||
bestY = scoreInfo.y;
|
bestY = scoreInfo.y;
|
||||||
}
|
}
|
||||||
|
@ -427,13 +457,11 @@ int8_t Cram_Internal_PackRects(RectPackContext *context, Rect *rects, uint32_t n
|
||||||
rectPtr = rectsToPack[bestRectIndex];
|
rectPtr = rectsToPack[bestRectIndex];
|
||||||
rectPtr->x = bestX;
|
rectPtr->x = bestX;
|
||||||
rectPtr->y = bestY;
|
rectPtr->y = bestY;
|
||||||
Cram_Internal_PlaceRect(context, rectPtr, bestFreeRectIndex);
|
Cram_Internal_PlaceRect(context, rectPtr);
|
||||||
|
|
||||||
/* plug the hole */
|
/* plug the hole */
|
||||||
rectsToPack[bestRectIndex] = rectsToPack[rectsToPackCount - 1];
|
rectsToPack[bestRectIndex] = rectsToPack[rectsToPackCount - 1];
|
||||||
rectsToPackCount -= 1;
|
rectsToPackCount -= 1;
|
||||||
|
|
||||||
Cram_Internal_PruneRects(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cram_free(rectsToPack);
|
Cram_free(rectsToPack);
|
||||||
|
|
Loading…
Reference in New Issue