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
											
										
									
								
							
							
								
								
									
										213
									
								
								src/cram.c
								
								
								
								
							
							
						
						
									
										213
									
								
								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; | ||||
| } | ||||
| 
 | ||||
| /* 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) | ||||
| 	int32_t i; | ||||
| 	if (a->hash == b->hash && a->rect.w == b->rect.w && a->rect.h == b->rect.h) | ||||
| 	{ | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < dstRect->w; i += 1) | ||||
| 	{ | ||||
| 		for (j = 0; j < dstRect->h; j += 1) | ||||
| 		for (i = 0; i < a->rect.w * a->rect.h * 4; i += 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]; | ||||
| 			if (a->pixels[i] != b->pixels[i]) | ||||
| 			{ | ||||
| 				return 0; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		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,40 +343,64 @@ 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]; | ||||
| 
 | ||||
| 		rect->w = internalContext->images[i].rect.w + internalContext->padding; | ||||
| 		rect->h = internalContext->images[i].rect.h + internalContext->padding; | ||||
| 		if (!internalContext->images[i].duplicate) | ||||
| 		{ | ||||
| 			numRects += 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	stbrp_pack_rects(&rectPackContext, rects, internalContext->imageCount); | ||||
| 	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) | ||||
| 	{ | ||||
| 		rect = &rects[i]; | ||||
| 
 | ||||
| 		if (rect->was_packed) | ||||
| 		if (!internalContext->images[i].duplicate) | ||||
| 		{ | ||||
| 			internalContext->images[i].rect.x = rect->x; | ||||
| 			internalContext->images[i].rect.y = rect->y; | ||||
| 			rect = &rects[numRects]; | ||||
| 
 | ||||
| 			maxWidth = Cram_max(maxWidth, rect->x + rect->w); | ||||
| 			maxHeight = Cram_max(maxHeight, rect->y + rect->h); | ||||
| 			rect->w = internalContext->images[i].rect.w + internalContext->padding; | ||||
| 			rect->h = internalContext->images[i].rect.h + internalContext->padding; | ||||
| 
 | ||||
| 			numRects += 1; | ||||
| 		} | ||||
| 		else | ||||
| 	} | ||||
| 
 | ||||
| 	stbrp_pack_rects(&rectPackContext, rects, numRects); | ||||
| 
 | ||||
| 	numRects = 0; | ||||
| 	for (i = 0; i < internalContext->imageCount; i += 1) | ||||
| 	{ | ||||
| 		if (!internalContext->images[i].duplicate) | ||||
| 		{ | ||||
| 			return -1; | ||||
| 			rect = &rects[numRects]; | ||||
| 
 | ||||
| 			if (rect->was_packed) | ||||
| 			{ | ||||
| 				internalContext->images[i].rect.x = rect->x; | ||||
| 				internalContext->images[i].rect.y = rect->y; | ||||
| 
 | ||||
| 				maxWidth = Cram_max(maxWidth, rect->x + rect->w); | ||||
| 				maxHeight = Cram_max(maxHeight, rect->y + rect->h); | ||||
| 
 | ||||
| 				numRects += 1; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -341,24 +412,27 @@ int8_t Cram_Pack(Cram_Context *context) | |||
| 
 | ||||
| 	for (i = 0; i < internalContext->imageCount; i += 1) | ||||
| 	{ | ||||
| 		dstRect.x = internalContext->images[i].rect.x; | ||||
| 		dstRect.y = internalContext->images[i].rect.y; | ||||
| 		dstRect.w = internalContext->images[i].rect.w; | ||||
| 		dstRect.h = internalContext->images[i].rect.h; | ||||
| 		if (!internalContext->images[i].duplicate) | ||||
| 		{ | ||||
| 			dstRect.x = internalContext->images[i].rect.x; | ||||
| 			dstRect.y = internalContext->images[i].rect.y; | ||||
| 			dstRect.w = internalContext->images[i].rect.w; | ||||
| 			dstRect.h = internalContext->images[i].rect.h; | ||||
| 
 | ||||
| 		srcRect.x = 0; | ||||
| 		srcRect.y = 0; | ||||
| 		srcRect.w = internalContext->images[i].rect.w; | ||||
| 		srcRect.h = internalContext->images[i].rect.h; | ||||
| 			srcRect.x = 0; | ||||
| 			srcRect.y = 0; | ||||
| 			srcRect.w = internalContext->images[i].rect.w; | ||||
| 			srcRect.h = internalContext->images[i].rect.h; | ||||
| 
 | ||||
| 		Cram_Internal_CopyPixels( | ||||
| 			(uint32_t*) internalContext->pixels, | ||||
| 			internalContext->width, | ||||
| 			(uint32_t*) internalContext->images[i].pixels, | ||||
| 			internalContext->images[i].rect.w, | ||||
| 			&dstRect, | ||||
| 			&srcRect | ||||
| 		); | ||||
| 			Cram_Internal_CopyPixels( | ||||
| 				(uint32_t*) internalContext->pixels, | ||||
| 				internalContext->width, | ||||
| 				(uint32_t*) internalContext->images[i].pixels, | ||||
| 				internalContext->images[i].rect.w, | ||||
| 				&dstRect, | ||||
| 				&srcRect | ||||
| 			); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	Cram_free(nodes); | ||||
|  | @ -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