deduplication
parent
02ddf8c5e1
commit
aeb8ed39f7
|
@ -44,6 +44,7 @@ file(GLOB SOURCE_FILES
|
|||
#Source
|
||||
lib/stb_rect_pack.h
|
||||
lib/stb_image.h
|
||||
lib/stb_ds.h
|
||||
src/cram.c
|
||||
)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
161
src/cram.c
161
src/cram.c
|
@ -62,8 +62,15 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
#define STB_DS_IMPLEMENTATION
|
||||
#include "stb_ds.h"
|
||||
|
||||
#define INITIAL_DATA_CAPACITY 8
|
||||
|
||||
#define STBDS_SIZE_T_BITS ((sizeof (size_t)) * 8)
|
||||
#define STBDS_ROTATE_LEFT(val, n) (((val) << (n)) | ((val) >> (STBDS_SIZE_T_BITS - (n))))
|
||||
#define STBDS_ROTATE_RIGHT(val, n) (((val) >> (n)) | ((val) << (STBDS_SIZE_T_BITS - (n))))
|
||||
|
||||
/* Structures */
|
||||
|
||||
typedef struct Rect
|
||||
|
@ -76,7 +83,9 @@ typedef struct Cram_Image
|
|||
{
|
||||
const char *name;
|
||||
Rect rect;
|
||||
uint8_t *pixels;
|
||||
uint8_t duplicate;
|
||||
uint8_t *pixels; // will be NULL if duplicate!
|
||||
size_t hash;
|
||||
} Cram_Image;
|
||||
|
||||
typedef struct Cram_Internal_Context
|
||||
|
@ -127,41 +136,30 @@ Cram_Context* Cram_Init(Cram_ContextCreateInfo *createInfo)
|
|||
return (Cram_Context*) context;
|
||||
}
|
||||
|
||||
static inline uint32_t Cram_Internal_GetPixelIndex(uint32_t x, uint32_t y, uint32_t width)
|
||||
static uint8_t Cram_Internal_IsImageEqual(Cram_Image *a, Cram_Image *b)
|
||||
{
|
||||
return x + y * width;
|
||||
int32_t i;
|
||||
if (a->hash == b->hash && a->rect.w == b->rect.w && a->rect.h == b->rect.h)
|
||||
{
|
||||
for (i = 0; i < a->rect.w * a->rect.h * 4; i += 1)
|
||||
{
|
||||
if (a->pixels[i] != b->pixels[i])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* width and height of source and destination rects must be the same! */
|
||||
static int8_t Cram_Internal_CopyPixels(
|
||||
uint32_t *dstPixels,
|
||||
uint32_t dstPixelWidth,
|
||||
uint32_t *srcPixels,
|
||||
uint32_t srcPixelWidth,
|
||||
Rect *dstRect,
|
||||
Rect *srcRect
|
||||
) {
|
||||
int32_t i, j;
|
||||
int32_t dstPixelIndex, srcPixelIndex;
|
||||
|
||||
if (dstRect->w != srcRect->w || dstRect->h != srcRect->h)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < dstRect->w; i += 1)
|
||||
{
|
||||
for (j = 0; j < dstRect->h; j += 1)
|
||||
{
|
||||
dstPixelIndex = Cram_Internal_GetPixelIndex(i + dstRect->x, j + dstRect->y, dstPixelWidth);
|
||||
srcPixelIndex = Cram_Internal_GetPixelIndex(i + srcRect->x, j + srcRect->y, srcPixelWidth);
|
||||
dstPixels[dstPixelIndex] = srcPixels[srcPixelIndex];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32_t Cram_Internal_GetPixelIndex(uint32_t x, uint32_t y, uint32_t width)
|
||||
{
|
||||
return x + y * width;
|
||||
}
|
||||
|
||||
static uint8_t Cram_Internal_IsRowClear(uint32_t* pixels, uint32_t rowIndex, uint32_t width)
|
||||
{
|
||||
int32_t i;
|
||||
|
@ -192,6 +190,36 @@ static uint8_t Cram_Internal_IsColumnClear(uint32_t* pixels, uint32_t columnInde
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* width and height of source and destination rects must be the same! */
|
||||
static int8_t Cram_Internal_CopyPixels(
|
||||
uint32_t *dstPixels,
|
||||
uint32_t dstPixelWidth,
|
||||
uint32_t *srcPixels,
|
||||
uint32_t srcPixelWidth,
|
||||
Rect *dstRect,
|
||||
Rect *srcRect
|
||||
) {
|
||||
int32_t i, j;
|
||||
int32_t dstPixelIndex, srcPixelIndex;
|
||||
|
||||
if (dstRect->w != srcRect->w || dstRect->h != srcRect->h)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < dstRect->w; i += 1)
|
||||
{
|
||||
for (j = 0; j < dstRect->h; j += 1)
|
||||
{
|
||||
dstPixelIndex = Cram_Internal_GetPixelIndex(i + dstRect->x, j + dstRect->y, dstPixelWidth);
|
||||
srcPixelIndex = Cram_Internal_GetPixelIndex(i + srcRect->x, j + srcRect->y, srcPixelWidth);
|
||||
dstPixels[dstPixelIndex] = srcPixels[srcPixelIndex];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Cram_AddFile(Cram_Context *context, const char *path)
|
||||
{
|
||||
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||
|
@ -247,7 +275,7 @@ void Cram_AddFile(Cram_Context *context, const char *path)
|
|||
{
|
||||
if (!Cram_Internal_IsRowClear(pixels, i, width))
|
||||
{
|
||||
bottomTrim = i;
|
||||
bottomTrim = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +285,7 @@ void Cram_AddFile(Cram_Context *context, const char *path)
|
|||
{
|
||||
if (!Cram_Internal_IsColumnClear(pixels, i, width, height))
|
||||
{
|
||||
rightTrim = i;
|
||||
rightTrim = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +303,7 @@ void Cram_AddFile(Cram_Context *context, const char *path)
|
|||
image->rect.h = height;
|
||||
}
|
||||
|
||||
/* copy */
|
||||
/* copy and free source pixels */
|
||||
image->pixels = Cram_malloc(image->rect.w * image->rect.h * 4);
|
||||
|
||||
Rect dstRect;
|
||||
|
@ -284,9 +312,28 @@ void Cram_AddFile(Cram_Context *context, const char *path)
|
|||
dstRect.w = image->rect.w;
|
||||
dstRect.h = image->rect.h;
|
||||
Cram_Internal_CopyPixels((uint32_t*) image->pixels, image->rect.w, (uint32_t*) pixels, width, &dstRect, &image->rect);
|
||||
|
||||
stbi_image_free(pixels);
|
||||
|
||||
/* hash */
|
||||
image->hash = stbds_hash_bytes(image->pixels, image->rect.w * image->rect.h * 4, 0);
|
||||
|
||||
/* check if this is a duplicate */
|
||||
image->duplicate = 0;
|
||||
for (i = 0; i < internalContext->imageCount; i += 1)
|
||||
{
|
||||
if (!internalContext->images[i].duplicate)
|
||||
{
|
||||
if (Cram_Internal_IsImageEqual(image, &internalContext->images[i]))
|
||||
{
|
||||
/* this is duplicate data! */
|
||||
image->duplicate = 1;
|
||||
Cram_free(image->pixels);
|
||||
image->pixels = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internalContext->imageCount += 1;
|
||||
}
|
||||
|
||||
|
@ -296,28 +343,49 @@ int8_t Cram_Pack(Cram_Context *context)
|
|||
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||
uint32_t numNodes = internalContext->width;
|
||||
stbrp_node *nodes = Cram_malloc(sizeof(stbrp_node) * numNodes);
|
||||
stbrp_rect *rects = Cram_malloc(sizeof(stbrp_rect) * internalContext->imageCount);
|
||||
stbrp_rect *rects;
|
||||
uint32_t numRects = 0;
|
||||
stbrp_rect *rect;
|
||||
Rect dstRect, srcRect;
|
||||
int32_t i;
|
||||
uint32_t maxWidth = 0;
|
||||
uint32_t maxHeight = 0;
|
||||
|
||||
stbrp_init_target(&rectPackContext, internalContext->width, internalContext->height, nodes, numNodes);
|
||||
|
||||
/* FIXME: this numRects repetition sucks */
|
||||
for (i = 0; i < internalContext->imageCount; i += 1)
|
||||
{
|
||||
rect = &rects[i];
|
||||
if (!internalContext->images[i].duplicate)
|
||||
{
|
||||
numRects += 1;
|
||||
}
|
||||
}
|
||||
|
||||
rects = Cram_malloc(sizeof(stbrp_rect) * numRects);
|
||||
|
||||
stbrp_init_target(&rectPackContext, internalContext->width, internalContext->height, nodes, numNodes);
|
||||
|
||||
numRects = 0;
|
||||
for (i = 0; i < internalContext->imageCount; i += 1)
|
||||
{
|
||||
if (!internalContext->images[i].duplicate)
|
||||
{
|
||||
rect = &rects[numRects];
|
||||
|
||||
rect->w = internalContext->images[i].rect.w + internalContext->padding;
|
||||
rect->h = internalContext->images[i].rect.h + internalContext->padding;
|
||||
|
||||
numRects += 1;
|
||||
}
|
||||
}
|
||||
|
||||
stbrp_pack_rects(&rectPackContext, rects, internalContext->imageCount);
|
||||
stbrp_pack_rects(&rectPackContext, rects, numRects);
|
||||
|
||||
numRects = 0;
|
||||
for (i = 0; i < internalContext->imageCount; i += 1)
|
||||
{
|
||||
rect = &rects[i];
|
||||
if (!internalContext->images[i].duplicate)
|
||||
{
|
||||
rect = &rects[numRects];
|
||||
|
||||
if (rect->was_packed)
|
||||
{
|
||||
|
@ -326,12 +394,15 @@ int8_t Cram_Pack(Cram_Context *context)
|
|||
|
||||
maxWidth = Cram_max(maxWidth, rect->x + rect->w);
|
||||
maxHeight = Cram_max(maxHeight, rect->y + rect->h);
|
||||
|
||||
numRects += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internalContext->width = maxWidth;
|
||||
internalContext->height = maxHeight;
|
||||
|
@ -340,6 +411,8 @@ int8_t Cram_Pack(Cram_Context *context)
|
|||
Cram_memset(internalContext->pixels, 0, internalContext->width * internalContext->height * 4);
|
||||
|
||||
for (i = 0; i < internalContext->imageCount; i += 1)
|
||||
{
|
||||
if (!internalContext->images[i].duplicate)
|
||||
{
|
||||
dstRect.x = internalContext->images[i].rect.x;
|
||||
dstRect.y = internalContext->images[i].rect.y;
|
||||
|
@ -360,6 +433,7 @@ int8_t Cram_Pack(Cram_Context *context)
|
|||
&srcRect
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Cram_free(nodes);
|
||||
Cram_free(rects);
|
||||
|
@ -383,10 +457,19 @@ void Cram_GetAtlasData(Cram_Context *context, Cram_AtlasData **pAtlasData)
|
|||
void Cram_Destroy(Cram_Context *context)
|
||||
{
|
||||
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||
int32_t i;
|
||||
|
||||
if (internalContext->pixels != NULL)
|
||||
{
|
||||
Cram_free(internalContext);
|
||||
Cram_free(internalContext->pixels);
|
||||
}
|
||||
|
||||
for (i = 0; i < internalContext->imageCount; i += 1)
|
||||
{
|
||||
if (!internalContext->images[i].duplicate)
|
||||
{
|
||||
Cram_free(internalContext->images[i].pixels);
|
||||
}
|
||||
}
|
||||
|
||||
Cram_free(internalContext->images);
|
||||
|
|
Loading…
Reference in New Issue