implementation progress

pull/1/head
cosmonaut 2022-07-18 21:29:30 -07:00
parent 534f61cbb0
commit bd8194afc4
4 changed files with 8265 additions and 1 deletions

View File

@ -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
) )

View File

@ -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 */

7897
lib/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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);
}