packing and write implementation
parent
bd8194afc4
commit
02ddf8c5e1
|
@ -1,8 +1,8 @@
|
||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
project(Cram C)
|
project(Cram C)
|
||||||
|
|
||||||
|
option(BUILD_CLI "Build command line executable" ON)
|
||||||
option(BUILD_SHARED_LIBS "Build shared library" ON)
|
option(BUILD_SHARED_LIBS "Build shared library" ON)
|
||||||
option(USE_SDL2 "Use SDL2" ON)
|
|
||||||
|
|
||||||
SET(LIB_MAJOR_VERSION "0")
|
SET(LIB_MAJOR_VERSION "0")
|
||||||
SET(LIB_MINOR_VERSION "3")
|
SET(LIB_MINOR_VERSION "3")
|
||||||
|
@ -38,11 +38,7 @@ if(UNIX)
|
||||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
|
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(USE_SDL2)
|
file(GLOB SOURCE_FILES
|
||||||
add_definitions(-DUSE_SDL2)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(Cram
|
|
||||||
#Public header
|
#Public header
|
||||||
include/cram.h
|
include/cram.h
|
||||||
#Source
|
#Source
|
||||||
|
@ -51,6 +47,31 @@ add_library(Cram
|
||||||
src/cram.c
|
src/cram.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(LINKSTYLE PRIVATE)
|
||||||
|
if(BUILD_SHARED_LIBS)
|
||||||
|
set(LINKSTYLE PUBLIC)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_CLI)
|
||||||
|
add_executable(cramcli
|
||||||
|
tools/cli/dirent.h
|
||||||
|
tools/cli/stb_image_write.h
|
||||||
|
tools/cli/main.c
|
||||||
|
)
|
||||||
|
|
||||||
|
if(BUILD_SHARED_LIBS)
|
||||||
|
target_link_libraries(cramcli PUBLIC Cram)
|
||||||
|
else()
|
||||||
|
target_link_libraries(cramcli PRIVATE Cram)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(BUILD_SHARED_LIBS)
|
||||||
|
add_library(Cram SHARED ${SOURCE_FILES})
|
||||||
|
else()
|
||||||
|
add_library(Cram STATIC ${SOURCE_FILES})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Build flags
|
# Build flags
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
set_property(TARGET Cram PROPERTY COMPILE_FLAGS "-std=gnu99 -Wall -Wno-strict-aliasing -pedantic")
|
set_property(TARGET Cram PROPERTY COMPILE_FLAGS "-std=gnu99 -Wall -Wno-strict-aliasing -pedantic")
|
||||||
|
@ -68,26 +89,3 @@ set_target_properties(Cram PROPERTIES OUTPUT_NAME "Cram"
|
||||||
VERSION ${LIB_VERSION}
|
VERSION ${LIB_VERSION}
|
||||||
SOVERSION ${LIB_MAJOR_VERSION}
|
SOVERSION ${LIB_MAJOR_VERSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
# SDL2 Dependency
|
|
||||||
if(USE_SDL2)
|
|
||||||
if (DEFINED SDL2_INCLUDE_DIRS AND DEFINED SDL2_LIBRARIES)
|
|
||||||
message(STATUS "using pre-defined SDL2 variables SDL2_INCLUDE_DIRS and SDL2_LIBRARIES")
|
|
||||||
target_include_directories(Cram PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
|
|
||||||
target_link_libraries(Cram PUBLIC ${SDL2_LIBRARIES})
|
|
||||||
else()
|
|
||||||
# Only try to autodetect if both SDL2 variables aren't explicitly set
|
|
||||||
find_package(SDL2 CONFIG)
|
|
||||||
if (TARGET SDL2::SDL2)
|
|
||||||
message(STATUS "using TARGET SDL2::SDL2")
|
|
||||||
target_link_libraries(Cram PUBLIC SDL2::SDL2)
|
|
||||||
elseif (TARGET SDL2)
|
|
||||||
message(STATUS "using TARGET SDL2")
|
|
||||||
target_link_libraries(Cram PUBLIC SDL2)
|
|
||||||
else()
|
|
||||||
message(STATUS "no TARGET SDL2::SDL2, or SDL2, using variables")
|
|
||||||
target_include_directories(Cram PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
|
|
||||||
target_link_libraries(Cram PUBLIC ${SDL2_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
|
@ -35,9 +35,7 @@
|
||||||
#define CRAMCALL
|
#define CRAMCALL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SDL2
|
#include <stdint.h>
|
||||||
#include <SDL.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
|
@ -97,9 +95,8 @@ typedef struct Cram_AtlasData
|
||||||
CRAMAPI Cram_Context* Cram_Init(Cram_ContextCreateInfo *createInfo);
|
CRAMAPI Cram_Context* Cram_Init(Cram_ContextCreateInfo *createInfo);
|
||||||
|
|
||||||
CRAMAPI void Cram_AddFile(Cram_Context *context, const char *path);
|
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 int8_t Cram_Pack(Cram_Context *context);
|
||||||
|
|
||||||
CRAMAPI void Cram_GetPixelData(Cram_Context *context, uint8_t **pPixelData, uint32_t *pWidth, uint32_t *pHeight);
|
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_GetAtlasData(Cram_Context *context, Cram_AtlasData **pAtlasData);
|
||||||
|
|
315
src/cram.c
315
src/cram.c
|
@ -26,18 +26,6 @@
|
||||||
|
|
||||||
#include "cram.h"
|
#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
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -47,18 +35,19 @@
|
||||||
|
|
||||||
#endif /* _MSC_VER */
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
/* TODO: ifndefs here */
|
||||||
#define Cram_assert assert
|
#define Cram_assert assert
|
||||||
#define Cram_qsort qsort
|
#define Cram_qsort qsort
|
||||||
#define Cram_malloc malloc
|
#define Cram_malloc malloc
|
||||||
#define Cram_realloc realloc
|
#define Cram_realloc realloc
|
||||||
#define Cram_free free
|
#define Cram_free free
|
||||||
#define Cram_memcpy memcpy
|
#define Cram_memcpy memcpy
|
||||||
|
#define Cram_memset memset
|
||||||
#define Cram_strdup strdup
|
#define Cram_strdup strdup
|
||||||
|
#define Cram_max max
|
||||||
#endif /* USE_SDL2 */
|
|
||||||
|
|
||||||
#define STBRP_ASSERT Cram_assert
|
#define STBRP_ASSERT Cram_assert
|
||||||
#define STBRP_SORT Cram_sort
|
#define STBRP_SORT Cram_qsort
|
||||||
|
|
||||||
#define STBRP_STATIC
|
#define STBRP_STATIC
|
||||||
#define STB_RECT_PACK_IMPLEMENTATION
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
@ -69,6 +58,7 @@
|
||||||
#define STBI_REALLOC Cram_realloc
|
#define STBI_REALLOC Cram_realloc
|
||||||
#define STBI_FREE Cram_free
|
#define STBI_FREE Cram_free
|
||||||
|
|
||||||
|
#define STBI_ONLY_PNG
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
@ -76,15 +66,18 @@
|
||||||
|
|
||||||
/* Structures */
|
/* Structures */
|
||||||
|
|
||||||
typedef struct Cram_ImageRect
|
typedef struct Rect
|
||||||
|
{
|
||||||
|
int32_t x, y;
|
||||||
|
int32_t w, h;
|
||||||
|
} Rect;
|
||||||
|
|
||||||
|
typedef struct Cram_Image
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
uint32_t offsetX;
|
Rect rect;
|
||||||
uint32_t offsetY;
|
|
||||||
uint32_t width;
|
|
||||||
uint32_t height;
|
|
||||||
uint8_t *pixels;
|
uint8_t *pixels;
|
||||||
} Cram_ImageRect;
|
} Cram_Image;
|
||||||
|
|
||||||
typedef struct Cram_Internal_Context
|
typedef struct Cram_Internal_Context
|
||||||
{
|
{
|
||||||
|
@ -97,9 +90,9 @@ typedef struct Cram_Internal_Context
|
||||||
|
|
||||||
uint8_t *pixels;
|
uint8_t *pixels;
|
||||||
|
|
||||||
Cram_ImageRect *imageRects;
|
Cram_Image *images;
|
||||||
uint32_t imageRectCount;
|
uint32_t imageCount;
|
||||||
uint32_t imageRectCapacity;
|
uint32_t imageCapacity;
|
||||||
|
|
||||||
Cram_AtlasData *atlasData;
|
Cram_AtlasData *atlasData;
|
||||||
} Cram_Internal_Context;
|
} Cram_Internal_Context;
|
||||||
|
@ -123,9 +116,9 @@ Cram_Context* Cram_Init(Cram_ContextCreateInfo *createInfo)
|
||||||
context->padding = createInfo->padding;
|
context->padding = createInfo->padding;
|
||||||
context->trim = createInfo->trim;
|
context->trim = createInfo->trim;
|
||||||
|
|
||||||
context->imageRects = Cram_malloc(INITIAL_DATA_CAPACITY * sizeof(Cram_ImageRect));
|
context->images = Cram_malloc(INITIAL_DATA_CAPACITY * sizeof(Cram_Image));
|
||||||
context->imageRectCapacity = INITIAL_DATA_CAPACITY;
|
context->imageCapacity = INITIAL_DATA_CAPACITY;
|
||||||
context->imageRectCount = 0;
|
context->imageCount = 0;
|
||||||
|
|
||||||
context->atlasData = Cram_malloc(sizeof(Cram_AtlasData));
|
context->atlasData = Cram_malloc(sizeof(Cram_AtlasData));
|
||||||
|
|
||||||
|
@ -134,33 +127,91 @@ Cram_Context* Cram_Init(Cram_ContextCreateInfo *createInfo)
|
||||||
return (Cram_Context*) context;
|
return (Cram_Context*) context;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t GetPixelIndex(uint32_t i, uint32_t j, uint32_t width)
|
static inline uint32_t Cram_Internal_GetPixelIndex(uint32_t x, uint32_t y, uint32_t width)
|
||||||
{
|
{
|
||||||
return (i + j * width) * 4;
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t Cram_Internal_IsRowClear(uint32_t* pixels, uint32_t rowIndex, uint32_t width)
|
||||||
|
{
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < width; i += 1)
|
||||||
|
{
|
||||||
|
if ((pixels[Cram_Internal_GetPixelIndex(i, rowIndex, width)] & 0xFF) > 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t Cram_Internal_IsColumnClear(uint32_t* pixels, uint32_t columnIndex, uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < height; i += 1)
|
||||||
|
{
|
||||||
|
if ((pixels[Cram_Internal_GetPixelIndex(columnIndex, i, width)] & 0xFF) > 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cram_AddFile(Cram_Context *context, const char *path)
|
void Cram_AddFile(Cram_Context *context, const char *path)
|
||||||
{
|
{
|
||||||
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||||
Cram_ImageRect *imageRect;
|
Cram_Image *image;
|
||||||
uint8_t *pixels;
|
uint8_t *pixels;
|
||||||
int32_t leftTrim, topTrim, rightTrim, bottomTrim;
|
int32_t leftTrim, topTrim, rightTrim, bottomTrim;
|
||||||
int32_t width, height, numChannels;
|
int32_t width, height, numChannels;
|
||||||
uint32_t pixelIndex, pixelOffset;
|
|
||||||
uint8_t allClear;
|
|
||||||
int32_t i;
|
int32_t i;
|
||||||
|
|
||||||
if (internalContext->imageRectCapacity == internalContext->imageRectCount)
|
if (internalContext->imageCapacity == internalContext->imageCount)
|
||||||
{
|
{
|
||||||
internalContext->imageRectCapacity *= 2;
|
internalContext->imageCapacity *= 2;
|
||||||
internalContext->imageRects = Cram_realloc(internalContext->imageRects, internalContext->imageRectCapacity * sizeof(Cram_ImageRect));
|
internalContext->images = Cram_realloc(internalContext->images, internalContext->imageCapacity * sizeof(Cram_Image));
|
||||||
}
|
}
|
||||||
|
|
||||||
imageRect = &internalContext->imageRects[internalContext->imageRectCount];
|
image = &internalContext->images[internalContext->imageCount];
|
||||||
|
|
||||||
imageRect->name = Cram_Internal_GetTrimmedPath();
|
/* image->name = Cram_Internal_GetTrimmedPath(); */
|
||||||
|
|
||||||
pixels = stbi_load_from_file(
|
pixels = stbi_load(
|
||||||
path,
|
path,
|
||||||
&width,
|
&width,
|
||||||
&height,
|
&height,
|
||||||
|
@ -168,124 +219,152 @@ void Cram_AddFile(Cram_Context *context, const char *path)
|
||||||
STBI_rgb_alpha
|
STBI_rgb_alpha
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* Check for trim */
|
||||||
if (internalContext->trim)
|
if (internalContext->trim)
|
||||||
{
|
{
|
||||||
/* Check for trim */
|
topTrim = 0;
|
||||||
allClear = 1;
|
for (i = 0; i < height; i += 1)
|
||||||
topTrim = -1;
|
|
||||||
|
|
||||||
while (allClear)
|
|
||||||
{
|
{
|
||||||
topTrim += 1;
|
if (!Cram_Internal_IsRowClear(pixels, i, width))
|
||||||
|
|
||||||
for (i = 0; i < width; i += 1)
|
|
||||||
{
|
{
|
||||||
pixelIndex = GetPixelIndex(i, topTrim, width);
|
topTrim = i;
|
||||||
|
break;
|
||||||
/* alpha check */
|
|
||||||
if (pixels[pixelIndex + 3] > 0)
|
|
||||||
{
|
|
||||||
allClear = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allClear = 1;
|
leftTrim = 0;
|
||||||
leftTrim = -1;
|
for (i = 0; i < width; i += 1)
|
||||||
|
|
||||||
while (allClear)
|
|
||||||
{
|
{
|
||||||
leftTrim += 1;
|
if (!Cram_Internal_IsColumnClear(pixels, i, width, height))
|
||||||
|
|
||||||
for (i = topTrim; i < height; i += 1)
|
|
||||||
{
|
{
|
||||||
pixelIndex = GetPixelIndex(leftTrim, i, width);
|
leftTrim = i;
|
||||||
|
break;
|
||||||
if (pixels[pixelIndex + 3] > 0)
|
|
||||||
{
|
|
||||||
allClear = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allClear = 1;
|
bottomTrim = height;
|
||||||
bottomTrim = -1;
|
for (i = height - 1; i >= topTrim; i -= 1)
|
||||||
|
|
||||||
while (allClear)
|
|
||||||
{
|
{
|
||||||
bottomTrim += 1;
|
if (!Cram_Internal_IsRowClear(pixels, i, width))
|
||||||
|
|
||||||
for (i = width - 1; i >= leftTrim; i -= 1)
|
|
||||||
{
|
{
|
||||||
pixelIndex = GetPixelIndex(i, bottomTrim, width);
|
bottomTrim = i;
|
||||||
|
break;
|
||||||
if (pixels[pixelIndex + 3] > 0)
|
|
||||||
{
|
|
||||||
allClear = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allClear = 1;
|
rightTrim = width;
|
||||||
rightTrim = -1;
|
for (i = width - 1; i >= leftTrim; i -= 1)
|
||||||
|
|
||||||
while (allClear)
|
|
||||||
{
|
{
|
||||||
rightTrim += 1;
|
if (!Cram_Internal_IsColumnClear(pixels, i, width, height))
|
||||||
|
|
||||||
for (i = height - 1; i >= topTrim; i -= 1)
|
|
||||||
{
|
{
|
||||||
pixelIndex = GetPixelIndex(rightTrim, i, width);
|
rightTrim = i;
|
||||||
|
break;
|
||||||
if (pixels[pixelIndex + 3] > 0)
|
|
||||||
{
|
|
||||||
allClear = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imageRect->offsetX = leftTrim;
|
image->rect.x = leftTrim;
|
||||||
imageRect->offsetY = topTrim;
|
image->rect.y = topTrim;
|
||||||
imageRect->width = width - rightTrim;
|
image->rect.w = rightTrim - leftTrim;
|
||||||
imageRect->height = height - bottomTrim;
|
image->rect.h = bottomTrim - topTrim;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
imageRect->offsetX = 0;
|
image->rect.x = 0;
|
||||||
imageRect->offsetY = 0;
|
image->rect.y = 0;
|
||||||
imageRect->width = width;
|
image->rect.w = width;
|
||||||
imageRect->height = height;
|
image->rect.h = height;
|
||||||
}
|
}
|
||||||
/* copy */
|
|
||||||
imageRect->pixels = Cram_malloc(imageRect->width * imageRect->height * 4);
|
|
||||||
|
|
||||||
pixelOffset = GetPixelIndex(imageRect->offsetX, imageRect->offsetY, width);
|
/* copy */
|
||||||
Cram_memcpy(imageRect->pixels, pixels + pixelOffset, (width * height * 4) - pixelOffset);
|
image->pixels = Cram_malloc(image->rect.w * image->rect.h * 4);
|
||||||
|
|
||||||
|
Rect dstRect;
|
||||||
|
dstRect.x = 0;
|
||||||
|
dstRect.y = 0;
|
||||||
|
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);
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
internalContext->imageRectCount += 1;
|
internalContext->imageCount += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cram_AddFolder(Cram_Context *context, const char *path)
|
int8_t Cram_Pack(Cram_Context *context)
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cram_Pack(Cram_Context *context)
|
|
||||||
{
|
{
|
||||||
stbrp_context rectPackContext;
|
stbrp_context rectPackContext;
|
||||||
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
Cram_Internal_Context *internalContext = (Cram_Internal_Context*) context;
|
||||||
uint32_t numNodes = internalContext->width;
|
uint32_t numNodes = internalContext->width;
|
||||||
stbrp_node *nodes = Cram_malloc(sizeof(stbrp_node*) * numNodes);
|
stbrp_node *nodes = Cram_malloc(sizeof(stbrp_node) * numNodes);
|
||||||
|
stbrp_rect *rects = Cram_malloc(sizeof(stbrp_rect) * internalContext->imageCount);
|
||||||
|
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);
|
stbrp_init_target(&rectPackContext, internalContext->width, internalContext->height, nodes, numNodes);
|
||||||
|
|
||||||
/* TODO: pack rects */
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
stbrp_pack_rects(&rectPackContext, rects, internalContext->imageCount);
|
||||||
|
|
||||||
|
for (i = 0; i < internalContext->imageCount; i += 1)
|
||||||
|
{
|
||||||
|
rect = &rects[i];
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internalContext->width = maxWidth;
|
||||||
|
internalContext->height = maxHeight;
|
||||||
|
|
||||||
|
internalContext->pixels = Cram_realloc(internalContext->pixels, internalContext->width * internalContext->height * 4);
|
||||||
|
Cram_memset(internalContext->pixels, 0, internalContext->width * internalContext->height * 4);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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_free(nodes);
|
||||||
|
Cram_free(rects);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cram_GetPixelData(Cram_Context *context, uint8_t **pPixels, uint32_t *pWidth, uint32_t *pHeight)
|
void Cram_GetPixelData(Cram_Context *context, uint8_t **pPixels, uint32_t *pWidth, uint32_t *pHeight)
|
||||||
|
@ -310,7 +389,7 @@ void Cram_Destroy(Cram_Context *context)
|
||||||
Cram_free(internalContext);
|
Cram_free(internalContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cram_free(internalContext->imageRects);
|
Cram_free(internalContext->images);
|
||||||
Cram_free(internalContext->atlasData);
|
Cram_free(internalContext->atlasData);
|
||||||
Cram_free(internalContext);
|
Cram_free(internalContext);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,115 @@
|
||||||
|
#include "cram.h"
|
||||||
|
#include "dirent.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "stb_image_write.h"
|
||||||
|
|
||||||
|
#define MAX_DIR_LENGTH 2048
|
||||||
|
|
||||||
|
static Cram_Context *context;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#define SEPARATOR "\\"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __unix__
|
||||||
|
|
||||||
|
#define SEPARATOR "/"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const char* GetFilenameExtension(const char *filename)
|
||||||
|
{
|
||||||
|
const char *dot = strrchr(filename, '.');
|
||||||
|
if (!dot || dot == filename)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return dot + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mostly taken from K&R C 2nd edition page 182 */
|
||||||
|
static void dirwalk(char *dir)
|
||||||
|
{
|
||||||
|
dirent *dp;
|
||||||
|
DIR *dfd;
|
||||||
|
char subname[2048];
|
||||||
|
|
||||||
|
if ((dfd = opendir(dir)) == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Can't open %s\n", dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((dp = readdir(dfd)) != NULL)
|
||||||
|
{
|
||||||
|
if ( strcmp(dp->d_name, ".") == 0 ||
|
||||||
|
strcmp(dp->d_name, "..") == 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(subname, "%s%s%s", dir, SEPARATOR, dp->d_name);
|
||||||
|
|
||||||
|
if (dp->d_type == DT_DIR)
|
||||||
|
{
|
||||||
|
dirwalk(subname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strcmp(GetFilenameExtension(subname), "png") == 0)
|
||||||
|
{
|
||||||
|
Cram_AddFile(context, subname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stdout, "skipping %s\n", subname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
Cram_ContextCreateInfo createInfo;
|
||||||
|
uint8_t *pixelData;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Must provide directory!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
createInfo.padding = 0;
|
||||||
|
createInfo.trim = 1;
|
||||||
|
createInfo.maxDimension = 8192;
|
||||||
|
createInfo.name = "test";
|
||||||
|
|
||||||
|
context = Cram_Init(&createInfo);
|
||||||
|
|
||||||
|
dirwalk(argv[1]);
|
||||||
|
|
||||||
|
Cram_Pack(context);
|
||||||
|
|
||||||
|
Cram_GetPixelData(context, &pixelData, &width, &height);
|
||||||
|
|
||||||
|
stbi_write_png(
|
||||||
|
"output.png",
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
4,
|
||||||
|
pixelData,
|
||||||
|
width * 4
|
||||||
|
);
|
||||||
|
|
||||||
|
Cram_Destroy(context);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue