tely/asset: Add new sprite packer spec file support
This commit is contained in:
+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: {
|
||||
|
||||
Reference in New Issue
Block a user