tely/asset: Add new sprite packer spec file support
This commit is contained in:
1 parent
ebfcc899c1
commit
3f33b015ab
41 files changed
+168
-71
No files matched your search
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Vendored
+1
-1
Submodule External/tely updated: a3816ec63e...f7b7d4f505.
+78
-59
@@ -402,63 +402,83 @@ void TELY_DLL_Init(void *user_data)
|
||||
TELY_AssetSpriteSheet *sheet = &game->protag_walk_sprite_sheet;
|
||||
Dqn_Slice<TELY_AssetSpriteAnimation> *anims = &game->protag_walk_sprite_anims;
|
||||
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 sheet_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/terry_movement.png", DQN_STRING_FMT(assets->textures_dir));
|
||||
sheet->tex_handle = platform->func_load_texture(assets, DQN_STRING8("Terry Movement"), sheet_path);
|
||||
sheet->sprite_count = 28;
|
||||
sheet->sprites_per_row = 7;
|
||||
sheet->sprite_size = Dqn_V2I_InitNx2(185, 170);
|
||||
sheet->type = TELY_AssetSpriteSheetType_Rects;
|
||||
|
||||
struct LoadedSprite
|
||||
{
|
||||
Dqn_String8 name;
|
||||
Dqn_Rect rect;
|
||||
};
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
sheet->sprite_size = Dqn_V2I_InitNx2(185, 170);
|
||||
sheet->type = TELY_AssetSpriteSheetType_Rects;
|
||||
|
||||
// NOTE: Load the sprite meta file =========================================================
|
||||
{
|
||||
Dqn_List<LoadedSprite> raw_sprites = Dqn_List_Init<LoadedSprite>(scratch.arena, 32);
|
||||
Dqn_String8 sheet_meta_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/terry_movement.txt", DQN_STRING_FMT(assets->textures_dir));
|
||||
Dqn_String8 sheet_meta_file = Dqn_Fs_Read(sheet_meta_path, scratch.allocator);
|
||||
Dqn_String8 sprite_spec_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/terry_movement.txt", DQN_STRING_FMT(assets->textures_dir));
|
||||
Dqn_String8 sprite_spec_buffer = platform->func_load_file(scratch.arena, sprite_spec_path);
|
||||
Dqn_String8SplitAllocResult lines = Dqn_String8_SplitAlloc(scratch.allocator, sprite_spec_buffer, DQN_STRING8("\n"));
|
||||
Dqn_usize sprite_rect_index = 0;
|
||||
Dqn_usize sprite_anim_index = 0;
|
||||
|
||||
Dqn_String8BinarySplitResult split = {};
|
||||
Dqn_String8 first = sheet_meta_file;
|
||||
do {
|
||||
split = Dqn_String8_BinarySplit(first, DQN_STRING8("\n"));
|
||||
Dqn_String8BinarySplitResult name = Dqn_String8_BinarySplit(split.lhs, DQN_STRING8(";"));
|
||||
Dqn_String8BinarySplitResult x = Dqn_String8_BinarySplit(name.rhs, DQN_STRING8(";"));
|
||||
Dqn_String8BinarySplitResult y = Dqn_String8_BinarySplit(x.rhs, DQN_STRING8(";"));
|
||||
Dqn_String8BinarySplitResult width = Dqn_String8_BinarySplit(y.rhs, DQN_STRING8(";"));
|
||||
Dqn_String8BinarySplitResult height = Dqn_String8_BinarySplit(width.rhs, DQN_STRING8(";"));
|
||||
DQN_FOR_UINDEX(line_index, lines.size) {
|
||||
Dqn_String8 line = lines.data[line_index];
|
||||
Dqn_String8SplitAllocResult line_splits = Dqn_String8_SplitAlloc(scratch.allocator, line, DQN_STRING8(";"));
|
||||
|
||||
LoadedSprite *loaded_anim = Dqn_List_Make(&raw_sprites, 1);
|
||||
loaded_anim->name = name.lhs;
|
||||
loaded_anim->rect.pos.x = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(x.lhs, 0).value;
|
||||
loaded_anim->rect.pos.y = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(y.lhs, 0).value;
|
||||
loaded_anim->rect.size.w = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(width.lhs, 0).value;
|
||||
loaded_anim->rect.size.h = DQN_CAST(Dqn_f32)Dqn_String8_ToU64(height.lhs, 0).value;
|
||||
if (line_index == 0) {
|
||||
DQN_ASSERTF(line_splits.size == 4, "Expected 4 splits for @file lines");
|
||||
DQN_ASSERT(Dqn_String8_StartsWith(line_splits.data[0], DQN_STRING8("@file"), Dqn_String8EqCase_Sensitive));
|
||||
|
||||
first = split.rhs;
|
||||
} while (first.size);
|
||||
// NOTE: Sprite sheet path
|
||||
Dqn_String8 sprite_sheet_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STRING_FMT(assets->textures_dir), DQN_STRING_FMT(line_splits.data[1]));
|
||||
sheet->tex_handle = platform->func_load_texture(assets, DQN_STRING8("Terry Movement"), sprite_sheet_path);
|
||||
DQN_ASSERTF(Dqn_Fs_Exists(sprite_sheet_path), "Required file does not exist '%.*s'", DQN_STRING_FMT(sprite_sheet_path));
|
||||
|
||||
// NOTE: Populate the sheet ============================================================
|
||||
sheet->rects = Dqn_Slice_Alloc<Dqn_Rect>(&platform->arena, raw_sprites.count, Dqn_ZeroMem_No);
|
||||
for (Dqn_ListIterator<LoadedSprite> it = {}; Dqn_List_Iterate(&raw_sprites, &it, 0); ) {
|
||||
sheet->rects.data[it.index] = it.data->rect;
|
||||
// NOTE: Total sprite frame count
|
||||
Dqn_String8ToU64Result total_frame_count = Dqn_String8_ToU64(line_splits.data[2], 0);
|
||||
DQN_ASSERT(total_frame_count.success);
|
||||
sheet->rects = Dqn_Slice_Alloc<Dqn_Rect>(&platform->arena, total_frame_count.value, Dqn_ZeroMem_No);
|
||||
|
||||
// NOTE: Total animation count
|
||||
Dqn_String8ToU64Result total_anim_count = Dqn_String8_ToU64(line_splits.data[3], 0);
|
||||
DQN_ASSERT(total_anim_count.success);
|
||||
*anims = Dqn_Slice_Alloc<TELY_AssetSpriteAnimation>(&platform->arena, total_anim_count.value, Dqn_ZeroMem_No);
|
||||
|
||||
// TODO: Sprite size?
|
||||
|
||||
// TODO: Texture name?
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Dqn_String8_StartsWith(line, DQN_STRING8("@anim"))) {
|
||||
DQN_ASSERTF(line_splits.size == 4, "Expected 4 splits for @anim lines");
|
||||
Dqn_String8 anim_name = line_splits.data[1];
|
||||
Dqn_String8ToU64Result frames_per_second = Dqn_String8_ToU64(line_splits.data[2], 0);
|
||||
Dqn_String8ToU64Result frame_count = Dqn_String8_ToU64(line_splits.data[3], 0);
|
||||
|
||||
DQN_ASSERT(anim_name.size);
|
||||
DQN_ASSERT(frame_count.success);
|
||||
DQN_ASSERT(frames_per_second.success);
|
||||
|
||||
TELY_AssetSpriteAnimation *anim = anims->data + sprite_anim_index++;
|
||||
anim->label = Dqn_String8_Copy(platform->allocator, anim_name);
|
||||
anim->index = DQN_CAST(uint16_t)sprite_rect_index;
|
||||
anim->count = DQN_CAST(uint16_t)frame_count.value;
|
||||
anim->seconds_per_frame = 1.f / frames_per_second.value;
|
||||
} else {
|
||||
DQN_ASSERTF(line_splits.size == 4, "Expected 4 splits for sprite frame lines");
|
||||
Dqn_String8ToU64Result x = Dqn_String8_ToU64(line_splits.data[0], 0);
|
||||
Dqn_String8ToU64Result y = Dqn_String8_ToU64(line_splits.data[1], 0);
|
||||
Dqn_String8ToU64Result w = Dqn_String8_ToU64(line_splits.data[2], 0);
|
||||
Dqn_String8ToU64Result h = Dqn_String8_ToU64(line_splits.data[3], 0);
|
||||
|
||||
DQN_ASSERT(x.success);
|
||||
DQN_ASSERT(y.success);
|
||||
DQN_ASSERT(w.success);
|
||||
DQN_ASSERT(h.success);
|
||||
|
||||
sheet->rects.data[sprite_rect_index++] =
|
||||
Dqn_Rect_InitNx4(DQN_CAST(Dqn_f32) x.value,
|
||||
DQN_CAST(Dqn_f32) y.value,
|
||||
DQN_CAST(Dqn_f32) w.value,
|
||||
DQN_CAST(Dqn_f32) h.value);
|
||||
}
|
||||
}
|
||||
|
||||
TELY_AssetSpriteAnimation raw_anims[] = {
|
||||
{DQN_STRING8("Walk down"), /*index*/ 0, /*count*/ 7, /*seconds_per_frame*/ 1 / 8.f},
|
||||
{DQN_STRING8("Walk idle"), /*index*/ 7, /*count*/ 8, /*seconds_per_frame*/ 1 / 8.f},
|
||||
{DQN_STRING8("Walk left"), /*index*/ 15, /*count*/ 7, /*seconds_per_frame*/ 1 / 8.f},
|
||||
{DQN_STRING8("Walk right"), /*index*/ 22, /*count*/ 7, /*seconds_per_frame*/ 1 / 8.f},
|
||||
{DQN_STRING8("Walk up"), /*index*/ 29, /*count*/ 6, /*seconds_per_frame*/ 1 / 8.f},
|
||||
};
|
||||
|
||||
*anims = Dqn_Slice_Alloc<TELY_AssetSpriteAnimation>(&platform->arena, DQN_ARRAY_UCOUNT(raw_anims), Dqn_ZeroMem_No);
|
||||
DQN_MEMCPY(anims->data, &raw_anims, sizeof(raw_anims[0]) * DQN_ARRAY_UCOUNT(raw_anims));
|
||||
DQN_ASSERT(sheet->rects.size == sprite_rect_index);
|
||||
DQN_ASSERT(anims->size == sprite_anim_index);
|
||||
}
|
||||
|
||||
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
|
||||
@@ -851,7 +871,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
||||
|
||||
if (action->state == FP_GameEntityState_Idle) {
|
||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Walk idle")).index;
|
||||
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Walk_idle")).index;
|
||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, anim);
|
||||
} else if (we_are_clicked_entity) {
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J)) {
|
||||
@@ -907,7 +927,7 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
||||
|
||||
if (action->state == FP_GameEntityState_Run) {
|
||||
if (action->flags & FP_GameEntityActionFlag_StateTransition) {
|
||||
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Walk right")).index;
|
||||
TELY_AssetSpriteAnimation *anim = entity->sprite_anims.data + TELY_Asset_GetSpriteAnimation(entity->sprite_anims, DQN_STRING8("Walk_right")).index;
|
||||
FP_Game_EntityActionReset(action, FP_GAME_ENTITY_ACTION_INFINITE_TIMER, anim);
|
||||
} else if (we_are_clicked_entity) {
|
||||
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_J)) {
|
||||
@@ -1076,17 +1096,16 @@ void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer)
|
||||
TELY_AssetSpriteAnimation const *sprite_anim = action->anim;
|
||||
uint16_t anim_frame = DQN_CAST(uint16_t)(action->timer_s / sprite_anim->seconds_per_frame) % sprite_anim->count;
|
||||
|
||||
Dqn_usize sprite_index = sprite_anim->index + anim_frame;
|
||||
Dqn_usize sprite_sheet_row = sprite_index / sprite_sheet->sprites_per_row;
|
||||
Dqn_usize sprite_sheet_column = sprite_index % sprite_sheet->sprites_per_row;
|
||||
|
||||
Dqn_Rect src_rect = {};
|
||||
Dqn_usize sprite_index = sprite_anim->index + anim_frame;
|
||||
Dqn_Rect src_rect = {};
|
||||
switch (sprite_sheet->type) {
|
||||
case TELY_AssetSpriteSheetType_Uniform: {
|
||||
src_rect.pos.x = DQN_CAST(Dqn_f32)(sprite_sheet_column * sprite_sheet->sprite_size.w);
|
||||
src_rect.pos.y = DQN_CAST(Dqn_f32)(sprite_sheet_row * sprite_sheet->sprite_size.y);
|
||||
src_rect.size.w = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.w;
|
||||
src_rect.size.h = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.h;
|
||||
Dqn_usize sprite_sheet_row = sprite_index / sprite_sheet->sprites_per_row;
|
||||
Dqn_usize sprite_sheet_column = sprite_index % sprite_sheet->sprites_per_row;
|
||||
src_rect.pos.x = DQN_CAST(Dqn_f32)(sprite_sheet_column * sprite_sheet->sprite_size.w);
|
||||
src_rect.pos.y = DQN_CAST(Dqn_f32)(sprite_sheet_row * sprite_sheet->sprite_size.y);
|
||||
src_rect.size.w = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.w;
|
||||
src_rect.size.h = DQN_CAST(Dqn_f32)sprite_sheet->sprite_size.h;
|
||||
} break;
|
||||
|
||||
case TELY_AssetSpriteSheetType_Rects: {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define DQN_ONLY_V2
|
||||
#define DQN_ONLY_SLICE
|
||||
#define DQN_ONLY_SARRAY
|
||||
#define DQN_ONLY_DSMAP
|
||||
#define DQN_ONLY_LIST
|
||||
#define DQN_ONLY_FS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
@@ -23,16 +24,52 @@ DQN_MSVC_WARNING_DISABLE(4244) // warning C4244: 'argument': conversion from 'in
|
||||
#include "External/tely/external/stb/stb_image.h"
|
||||
DQN_MSVC_WARNING_POP
|
||||
|
||||
struct SpriteSpecification
|
||||
{
|
||||
uint16_t frame_count;
|
||||
uint16_t frames_per_second;
|
||||
};
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
Dqn_Log_InfoF("USAGE: feely_pona_sprite_packer \"<directory with sprites>\"");
|
||||
if (argc != 3) {
|
||||
Dqn_Log_InfoF("USAGE: feely_pona_sprite_packer <sprite_spec.txt> <sprite directory>");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Dqn_Library_Init();
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 dir = Dqn_String8_InitCString8(argv[1]);
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
|
||||
Dqn_String8 sprite_spec_path = Dqn_String8_InitCString8(argv[1]);
|
||||
Dqn_String8 dir = Dqn_String8_InitCString8(argv[2]);
|
||||
|
||||
// NOTE: Parse the sprite specifications =======================================================
|
||||
if (!Dqn_Fs_Exists(sprite_spec_path)) {
|
||||
Dqn_Log_ErrorF("Sprite specification file does not exist, we tried to find \"%.*s\" but it does not exist", DQN_STRING_FMT(sprite_spec_path));
|
||||
return -1;
|
||||
}
|
||||
|
||||
Dqn_DSMap<SpriteSpecification> sprite_spec_table = Dqn_DSMap_Init<SpriteSpecification>(1024);
|
||||
{
|
||||
Dqn_ThreadScratch inner_scratch = Dqn_Thread_GetScratch(scratch.arena);
|
||||
Dqn_String8 sprite_spec_buffer = Dqn_Fs_Read(sprite_spec_path, inner_scratch.allocator);
|
||||
Dqn_String8SplitAllocResult sprite_spec_lines = Dqn_String8_SplitAlloc(inner_scratch.allocator, sprite_spec_buffer, DQN_STRING8("\n"));
|
||||
DQN_FOR_UINDEX(line_index, sprite_spec_lines.size) {
|
||||
Dqn_String8 line = sprite_spec_lines.data[line_index];
|
||||
Dqn_String8SplitAllocResult line_parts = Dqn_String8_SplitAlloc(inner_scratch.allocator, line, DQN_STRING8(";"));
|
||||
DQN_ASSERTF(line_parts.size == 2, "Line must have 2 parts in the sprite specification\n"
|
||||
"\n"
|
||||
"<animation name>;<frames per second>\\n\n"
|
||||
"\n"
|
||||
"Line was '%.*s' loaded from '%.*s'", DQN_STRING_FMT(line), sprite_spec_path);
|
||||
|
||||
Dqn_String8 anim_name = line_parts.data[0];
|
||||
Dqn_String8ToU64Result frames_per_second = Dqn_String8_ToU64(line_parts.data[1], 0);
|
||||
DQN_ASSERTF(frames_per_second.success, "Frames per second was not a convertible number, line was '%.*s'", line);
|
||||
|
||||
Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_MakeKeyString8Copy(&sprite_spec_table, scratch.allocator, anim_name);
|
||||
slot.value->frames_per_second = DQN_CAST(uint16_t)frames_per_second.value;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Get the list of files =================================================================
|
||||
Dqn_List<Dqn_String8> file_list = Dqn_List_Init<Dqn_String8>(scratch.arena, 128);
|
||||
@@ -49,7 +86,7 @@ int main(int argc, char const *argv[])
|
||||
stbrp_context pack_context = {};
|
||||
stbrp_init_target(&pack_context, atlas_size, atlas_size, nodes, DQN_CAST(int)file_list.count);
|
||||
|
||||
// NOTE: Load the sprites to determine their dimensions for rect packing
|
||||
// NOTE: Load the sprites to determine their dimensions for rect packing =======================
|
||||
Dqn_SArray<stbrp_rect> rects = Dqn_SArray_Init<stbrp_rect>(scratch.arena, file_list.count, Dqn_ZeroMem_Yes);
|
||||
for (Dqn_ListIterator<Dqn_String8> it = {}; Dqn_List_Iterate<Dqn_String8>(&file_list, &it, 0);) {
|
||||
int x = 0, y = 0, channels_in_file = 0;
|
||||
@@ -57,11 +94,32 @@ int main(int argc, char const *argv[])
|
||||
DQN_ASSERT(pixels);
|
||||
stbi_image_free(pixels);
|
||||
|
||||
// NOTE: Add a rect to the packing context
|
||||
// NOTE: Add a rect to the packing context =================================================
|
||||
stbrp_rect *rect = Dqn_SArray_Make(&rects, Dqn_ZeroMem_Yes);
|
||||
rect->w = x;
|
||||
rect->h = y;
|
||||
|
||||
// NOTE: Enumerate the number of frames for this animation =================================
|
||||
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(*it.data);
|
||||
Dqn_String8 file_name_without_extension = Dqn_String8_BinarySplit(file_name, DQN_STRING8(".")).lhs;
|
||||
Dqn_String8BinarySplitResult split = Dqn_String8_BinarySplitReverse(file_name_without_extension, DQN_STRING8("_"));
|
||||
Dqn_String8 anim_prefix = split.lhs;
|
||||
|
||||
Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_FindKeyString8(&sprite_spec_table, anim_prefix);
|
||||
DQN_ASSERTF(slot.found,
|
||||
"\n\nSprite frame loaded from file\n"
|
||||
" '%.*s'\n"
|
||||
"\n"
|
||||
"however there's no corresponding entry in the specification file loaded at\n"
|
||||
" '%.*s'\n"
|
||||
"\n"
|
||||
"Add a line in format of <animation name>;<frames_per_second> to the file, e.g.\n"
|
||||
" %.*s;8\n",
|
||||
DQN_STRING_FMT(*it.data),
|
||||
DQN_STRING_FMT(sprite_spec_path),
|
||||
DQN_STRING_FMT(anim_prefix));
|
||||
|
||||
slot.value->frame_count++;
|
||||
Dqn_Log_InfoF("Packing sprite: %.*s", DQN_STRING_FMT(*it.data));
|
||||
}
|
||||
|
||||
@@ -78,12 +136,19 @@ int main(int argc, char const *argv[])
|
||||
int final_bpp = 4;
|
||||
int final_image_stride = atlas_size * final_bpp;
|
||||
char *final_image = Dqn_Arena_NewArray(scratch.arena, char, atlas_size * final_image_stride, Dqn_ZeroMem_Yes);
|
||||
Dqn_String8 atlas_path = Dqn_String8_InitF(scratch.allocator, "%.*s.png", DQN_STRING_FMT(dir));
|
||||
|
||||
// NOTE: Generate the meta file ================================================================
|
||||
Dqn_String8 meta_path = Dqn_String8_InitF(scratch.allocator, "%.*s.txt", DQN_STRING_FMT(dir));
|
||||
Dqn_FsFile meta_file = Dqn_Fs_OpenFile(meta_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_Write);
|
||||
Dqn_Fs_WriteFileF(&meta_file,
|
||||
"@file;%.*s;%d;%d\n",
|
||||
DQN_STRING_FMT(Dqn_String8_FileNameFromPath(atlas_path)),
|
||||
DQN_CAST(int) file_list.count,
|
||||
DQN_CAST(int) sprite_spec_table.occupied - 1);
|
||||
|
||||
Dqn_Log_InfoF("Generating meta file: %.*s", DQN_STRING_FMT(meta_path));
|
||||
Dqn_String8 anim_prefix = {};
|
||||
for (Dqn_ListIterator<Dqn_String8> it = {}; Dqn_List_Iterate<Dqn_String8>(&file_list, &it, 0);) {
|
||||
int w, h, channels_in_file;
|
||||
stbi_uc *loaded_image = stbi_load(it.data->data, &w, &h, &channels_in_file, 4 /*desired_channels*/);
|
||||
@@ -105,15 +170,25 @@ int main(int argc, char const *argv[])
|
||||
stbi_image_free(loaded_image);
|
||||
|
||||
// NOTE: Write the sprite and the rects to the sheet
|
||||
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(*it.data);
|
||||
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(*it.data);
|
||||
Dqn_String8 file_name_without_extension = Dqn_String8_BinarySplit(file_name, DQN_STRING8(".")).lhs;
|
||||
|
||||
Dqn_Fs_WriteFileF(&meta_file, "%.*s;%d;%d;%d;%d", DQN_STRING_FMT(file_name_without_extension), packed_rect.x, packed_rect.y, packed_rect.w, packed_rect.h);
|
||||
// NOTE: Detect what animation we are currently processing =================================
|
||||
if (anim_prefix.size == 0 || !Dqn_String8_StartsWith(file_name_without_extension, anim_prefix)) {
|
||||
// NOTE: Anim prefix is different, we are starting a new animation- mark it accordingly
|
||||
Dqn_String8BinarySplitResult split = Dqn_String8_BinarySplitReverse(file_name_without_extension, DQN_STRING8("_"));
|
||||
anim_prefix = split.lhs;
|
||||
|
||||
Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_FindKeyString8(&sprite_spec_table, anim_prefix);
|
||||
Dqn_Fs_WriteFileF(&meta_file, "@anim;%.*s;%u;%u\n", DQN_STRING_FMT(anim_prefix), slot.value->frames_per_second, slot.value->frame_count);
|
||||
}
|
||||
|
||||
// NOTE: Write the sprite rectangles in ====================================================
|
||||
Dqn_Fs_WriteFileF(&meta_file, "%d;%d;%d;%d", packed_rect.x, packed_rect.y, packed_rect.w, packed_rect.h);
|
||||
if (it.index != (file_list.count - 1))
|
||||
Dqn_Fs_WriteFileF(&meta_file, "\n");
|
||||
}
|
||||
|
||||
Dqn_String8 atlas_path = Dqn_String8_InitF(scratch.allocator, "%.*s.png", DQN_STRING_FMT(dir));
|
||||
Dqn_Log_InfoF("Generating atlas: %.*s", DQN_STRING_FMT(atlas_path));
|
||||
stbi_write_png(atlas_path.data, atlas_size, atlas_size, 4, final_image, final_image_stride);
|
||||
return 0;
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user