implementation progress
parent
534f61cbb0
commit
bd8194afc4
|
@ -47,6 +47,7 @@ add_library(Cram
|
||||||
include/cram.h
|
include/cram.h
|
||||||
#Source
|
#Source
|
||||||
lib/stb_rect_pack.h
|
lib/stb_rect_pack.h
|
||||||
|
lib/stb_image.h
|
||||||
src/cram.c
|
src/cram.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Cram - A texture atlas system in C
|
/* Cram - A texture packing system in C
|
||||||
*
|
*
|
||||||
* Copyright (c) 2022 Evan Hemsley
|
* Copyright (c) 2022 Evan Hemsley
|
||||||
*
|
*
|
||||||
|
@ -56,6 +56,56 @@ extern "C"
|
||||||
|
|
||||||
CRAMAPI uint32_t Cram_LinkedVersion(void);
|
CRAMAPI uint32_t Cram_LinkedVersion(void);
|
||||||
|
|
||||||
|
/* Type definitions */
|
||||||
|
|
||||||
|
typedef struct Cram_Context Cram_Context;
|
||||||
|
|
||||||
|
typedef struct Cram_ContextCreateInfo
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
uint32_t maxDimension;
|
||||||
|
uint32_t padding;
|
||||||
|
uint8_t trim;
|
||||||
|
} Cram_ContextCreateInfo;
|
||||||
|
|
||||||
|
typedef struct Cram_ImageData
|
||||||
|
{
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
uint32_t offsetX;
|
||||||
|
uint32_t offsetY;
|
||||||
|
uint32_t trimmedWidth;
|
||||||
|
uint32_t trimmedHeight;
|
||||||
|
} Cram_ImageData;
|
||||||
|
|
||||||
|
typedef struct Cram_AtlasData
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
Cram_ImageData *imageDatas;
|
||||||
|
uint32_t imageDataCount;
|
||||||
|
} Cram_AtlasData;
|
||||||
|
|
||||||
|
/* API definition */
|
||||||
|
|
||||||
|
CRAMAPI Cram_Context* Cram_Init(Cram_ContextCreateInfo *createInfo);
|
||||||
|
|
||||||
|
CRAMAPI void Cram_AddFile(Cram_Context *context, const char *path);
|
||||||
|
CRAMAPI void Cram_AddFolder(Cram_Context *context, const char *path);
|
||||||
|
|
||||||
|
CRAMAPI void Cram_Pack(Cram_Context *context);
|
||||||
|
|
||||||
|
CRAMAPI void Cram_GetPixelData(Cram_Context *context, uint8_t **pPixelData, uint32_t *pWidth, uint32_t *pHeight);
|
||||||
|
CRAMAPI void Cram_GetAtlasData(Cram_Context *context, Cram_AtlasData **pAtlasData);
|
||||||
|
|
||||||
|
CRAMAPI void Cram_Destroy(Cram_Context *context);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
316
src/cram.c
316
src/cram.c
|
@ -0,0 +1,316 @@
|
||||||
|
/* Cram - A texture packing system in C
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 Evan Hemsley
|
||||||
|
*
|
||||||
|
* This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
* In no event will the authors be held liable for any damages arising from
|
||||||
|
* the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose,
|
||||||
|
* including commercial applications, and to alter it and redistribute it
|
||||||
|
* freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
* claim that you wrote the original software. If you use this software in a
|
||||||
|
* product, an acknowledgment in the product documentation would be
|
||||||
|
* appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
* misrepresented as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*
|
||||||
|
* Evan "cosmonaut" Hemsley <evan@moonside.games>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cram.h"
|
||||||
|
|
||||||
|
#ifdef USE_SDL2
|
||||||
|
|
||||||
|
#define Cram_assert SDL_assert
|
||||||
|
#define Cram_qsort SDL_qsort
|
||||||
|
#define Cram_malloc SDL_malloc
|
||||||
|
#define Cram_realloc SDL_realloc
|
||||||
|
#define Cram_free SDL_free
|
||||||
|
#define Cram_memcpy SDL_memcpy
|
||||||
|
#define Cram_strdup SDL_strdup
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <search.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
#define Cram_assert assert
|
||||||
|
#define Cram_qsort qsort
|
||||||
|
#define Cram_malloc malloc
|
||||||
|
#define Cram_realloc realloc
|
||||||
|
#define Cram_free free
|
||||||
|
#define Cram_memcpy memcpy
|
||||||
|
#define Cram_strdup strdup
|
||||||
|
|
||||||
|
#endif /* USE_SDL2 */
|
||||||
|
|
||||||
|
#define STBRP_ASSERT Cram_assert
|
||||||
|
#define STBRP_SORT Cram_sort
|
||||||
|
|
||||||
|
#define STBRP_STATIC
|
||||||
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
#include "stb_rect_pack.h"
|
||||||
|
|
||||||
|
#define STBI_ASSERT Cram_assert
|
||||||
|
#define STBI_MALLOC Cram_malloc
|
||||||
|
#define STBI_REALLOC Cram_realloc
|
||||||
|
#define STBI_FREE Cram_free
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
#define INITIAL_DATA_CAPACITY 8
|
||||||
|
|
||||||
|
/* Structures */
|
||||||
|
|
||||||
|
typedef struct Cram_ImageRect
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
uint32_t offsetX;
|
||||||
|
uint32_t offsetY;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint8_t *pixels;
|
||||||
|
} Cram_ImageRect;
|
||||||
|
|
||||||
|
typedef struct Cram_Internal_Context
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
uint32_t padding;
|
||||||
|
uint8_t trim;
|
||||||
|
|
||||||
|
uint8_t *pixels;
|
||||||
|
|
||||||
|
Cram_ImageRect *imageRects;
|
||||||
|
uint32_t imageRectCount;
|
||||||
|
uint32_t imageRectCapacity;
|
||||||
|
|
||||||
|
Cram_AtlasData *atlasData;
|
||||||
|
} Cram_Internal_Context;
|
||||||
|
|
||||||
|
/* API functions */
|
||||||
|
|
||||||
|
uint32_t Wellspring_LinkedVersion(void)
|
||||||
|
{
|
||||||
|
return WELLSPRING_COMPILED_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cram_Context* Cram_Init(Cram_ContextCreateInfo *createInfo)
|
||||||
|
{
|
||||||
|
Cram_Internal_Context *context = Cram_malloc(sizeof(Cram_Internal_Context));
|
||||||
|
|
||||||
|
context->name = Cram_strdup(createInfo->name);
|
||||||
|
|
||||||
|
context->width = createInfo->maxDimension;
|
||||||
|
context->height = createInfo->maxDimension;
|
||||||
|
|
||||||
|
context->padding = createInfo->padding;
|
||||||
|
context->trim = createInfo->trim;
|
||||||
|
|
||||||
|
context->imageRects = Cram_malloc(INITIAL_DATA_CAPACITY * sizeof(Cram_ImageRect));
|
||||||
|
context->imageRectCapacity = INITIAL_DATA_CAPACITY;
|
||||||
|
context->imageRectCount = 0;
|
||||||
|
|
||||||
|
context->atlasData = Cram_malloc(sizeof(Cram_AtlasData));
|
||||||
|
|
||||||
|
context->pixels = NULL;
|
||||||
|
|
||||||
|
return (Cram_Context*) context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t GetPixelIndex(uint32_t i, uint32_t j, uint32_t width)
|
||||||
|
{
|
||||||
|
return (i + j * width) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cram_AddFile(Cram_Context *context, const char *path)
|
||||||
|
{
|
||||||
|
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||||
|
Cram_ImageRect *imageRect;
|
||||||
|
uint8_t *pixels;
|
||||||
|
int32_t leftTrim, topTrim, rightTrim, bottomTrim;
|
||||||
|
int32_t width, height, numChannels;
|
||||||
|
uint32_t pixelIndex, pixelOffset;
|
||||||
|
uint8_t allClear;
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
|
if (internalContext->imageRectCapacity == internalContext->imageRectCount)
|
||||||
|
{
|
||||||
|
internalContext->imageRectCapacity *= 2;
|
||||||
|
internalContext->imageRects = Cram_realloc(internalContext->imageRects, internalContext->imageRectCapacity * sizeof(Cram_ImageRect));
|
||||||
|
}
|
||||||
|
|
||||||
|
imageRect = &internalContext->imageRects[internalContext->imageRectCount];
|
||||||
|
|
||||||
|
imageRect->name = Cram_Internal_GetTrimmedPath();
|
||||||
|
|
||||||
|
pixels = stbi_load_from_file(
|
||||||
|
path,
|
||||||
|
&width,
|
||||||
|
&height,
|
||||||
|
&numChannels,
|
||||||
|
STBI_rgb_alpha
|
||||||
|
);
|
||||||
|
|
||||||
|
if (internalContext->trim)
|
||||||
|
{
|
||||||
|
/* Check for trim */
|
||||||
|
allClear = 1;
|
||||||
|
topTrim = -1;
|
||||||
|
|
||||||
|
while (allClear)
|
||||||
|
{
|
||||||
|
topTrim += 1;
|
||||||
|
|
||||||
|
for (i = 0; i < width; i += 1)
|
||||||
|
{
|
||||||
|
pixelIndex = GetPixelIndex(i, topTrim, width);
|
||||||
|
|
||||||
|
/* alpha check */
|
||||||
|
if (pixels[pixelIndex + 3] > 0)
|
||||||
|
{
|
||||||
|
allClear = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allClear = 1;
|
||||||
|
leftTrim = -1;
|
||||||
|
|
||||||
|
while (allClear)
|
||||||
|
{
|
||||||
|
leftTrim += 1;
|
||||||
|
|
||||||
|
for (i = topTrim; i < height; i += 1)
|
||||||
|
{
|
||||||
|
pixelIndex = GetPixelIndex(leftTrim, i, width);
|
||||||
|
|
||||||
|
if (pixels[pixelIndex + 3] > 0)
|
||||||
|
{
|
||||||
|
allClear = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allClear = 1;
|
||||||
|
bottomTrim = -1;
|
||||||
|
|
||||||
|
while (allClear)
|
||||||
|
{
|
||||||
|
bottomTrim += 1;
|
||||||
|
|
||||||
|
for (i = width - 1; i >= leftTrim; i -= 1)
|
||||||
|
{
|
||||||
|
pixelIndex = GetPixelIndex(i, bottomTrim, width);
|
||||||
|
|
||||||
|
if (pixels[pixelIndex + 3] > 0)
|
||||||
|
{
|
||||||
|
allClear = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allClear = 1;
|
||||||
|
rightTrim = -1;
|
||||||
|
|
||||||
|
while (allClear)
|
||||||
|
{
|
||||||
|
rightTrim += 1;
|
||||||
|
|
||||||
|
for (i = height - 1; i >= topTrim; i -= 1)
|
||||||
|
{
|
||||||
|
pixelIndex = GetPixelIndex(rightTrim, i, width);
|
||||||
|
|
||||||
|
if (pixels[pixelIndex + 3] > 0)
|
||||||
|
{
|
||||||
|
allClear = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imageRect->offsetX = leftTrim;
|
||||||
|
imageRect->offsetY = topTrim;
|
||||||
|
imageRect->width = width - rightTrim;
|
||||||
|
imageRect->height = height - bottomTrim;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
imageRect->offsetX = 0;
|
||||||
|
imageRect->offsetY = 0;
|
||||||
|
imageRect->width = width;
|
||||||
|
imageRect->height = height;
|
||||||
|
}
|
||||||
|
/* copy */
|
||||||
|
imageRect->pixels = Cram_malloc(imageRect->width * imageRect->height * 4);
|
||||||
|
|
||||||
|
pixelOffset = GetPixelIndex(imageRect->offsetX, imageRect->offsetY, width);
|
||||||
|
Cram_memcpy(imageRect->pixels, pixels + pixelOffset, (width * height * 4) - pixelOffset);
|
||||||
|
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
|
internalContext->imageRectCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cram_AddFolder(Cram_Context *context, const char *path)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cram_Pack(Cram_Context *context)
|
||||||
|
{
|
||||||
|
stbrp_context rectPackContext;
|
||||||
|
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||||
|
uint32_t numNodes = internalContext->width;
|
||||||
|
stbrp_node *nodes = Cram_malloc(sizeof(stbrp_node*) * numNodes);
|
||||||
|
|
||||||
|
stbrp_init_target(&rectPackContext, internalContext->width, internalContext->height, nodes, numNodes);
|
||||||
|
|
||||||
|
/* TODO: pack rects */
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cram_GetPixelData(Cram_Context *context, uint8_t **pPixels, uint32_t *pWidth, uint32_t *pHeight)
|
||||||
|
{
|
||||||
|
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||||
|
*pPixels = internalContext->pixels;
|
||||||
|
*pWidth = internalContext->width;
|
||||||
|
*pHeight = internalContext->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cram_GetAtlasData(Cram_Context *context, Cram_AtlasData **pAtlasData)
|
||||||
|
{
|
||||||
|
*pAtlasData = ((Cram_Internal_Context*) context)->atlasData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cram_Destroy(Cram_Context *context)
|
||||||
|
{
|
||||||
|
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||||
|
|
||||||
|
if (internalContext->pixels != NULL)
|
||||||
|
{
|
||||||
|
Cram_free(internalContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cram_free(internalContext->imageRects);
|
||||||
|
Cram_free(internalContext->atlasData);
|
||||||
|
Cram_free(internalContext);
|
||||||
|
}
|
Loading…
Reference in New Issue