tely/asset: Fix sprite packer emitting wrong anim rect count
This commit is contained in:
parent
8af79b75d5
commit
481da3a6dd
BIN
Data/Textures/smoochie_resized_25%.txt
(Stored with Git LFS)
BIN
Data/Textures/smoochie_resized_25%.txt
(Stored with Git LFS)
Binary file not shown.
203
feely_pona.cpp
203
feely_pona.cpp
@ -3,6 +3,98 @@
|
||||
#include "feely_pona_unity.h"
|
||||
#endif
|
||||
|
||||
struct FP_LoadSpriteSheetFromSpecResult
|
||||
{
|
||||
TELY_AssetSpriteSheet sheet;
|
||||
Dqn_Slice<TELY_AssetSpriteAnimation> anims;
|
||||
};
|
||||
|
||||
FP_LoadSpriteSheetFromSpecResult FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_String8 sheet_name)
|
||||
{
|
||||
FP_LoadSpriteSheetFromSpecResult result = {};
|
||||
|
||||
TELY_AssetSpriteSheet *sheet = &result.sheet;
|
||||
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena);
|
||||
sheet->sprite_size = Dqn_V2I_InitNx2(185, 170);
|
||||
sheet->type = TELY_AssetSpriteSheetType_Rects;
|
||||
|
||||
// NOTE: Load the sprite meta file =========================================================
|
||||
Dqn_String8 sprite_spec_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.txt", DQN_STRING_FMT(assets->textures_dir), DQN_STRING_FMT(sheet_name));
|
||||
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_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(";"));
|
||||
|
||||
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));
|
||||
|
||||
// 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, sheet_name, sprite_sheet_path);
|
||||
DQN_ASSERTF(Dqn_Fs_Exists(sprite_sheet_path), "Required file does not exist '%.*s'", DQN_STRING_FMT(sprite_sheet_path));
|
||||
|
||||
// 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>(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);
|
||||
result.anims = Dqn_Slice_Alloc<TELY_AssetSpriteAnimation>(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);
|
||||
|
||||
Dqn_Allocator allocator = Dqn_Arena_Allocator(arena);
|
||||
TELY_AssetSpriteAnimation *anim = result.anims.data + sprite_anim_index++;
|
||||
anim->label = Dqn_String8_Copy(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);
|
||||
}
|
||||
}
|
||||
|
||||
DQN_ASSERT(sheet->rects.size == sprite_rect_index);
|
||||
DQN_ASSERT(result.anims.size == sprite_anim_index);
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport)
|
||||
void TELY_DLL_Reload(void *user_data)
|
||||
{
|
||||
@ -398,89 +490,19 @@ void TELY_DLL_Init(void *user_data)
|
||||
DQN_MEMCPY(game->hero_sprite_anims.data, &hero_anims, sizeof(hero_anims[0]) * DQN_ARRAY_UCOUNT(hero_anims));
|
||||
}
|
||||
|
||||
// NOTE: Load sprite sheets ====================================================================
|
||||
{
|
||||
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);
|
||||
sheet->sprite_size = Dqn_V2I_InitNx2(185, 170);
|
||||
sheet->type = TELY_AssetSpriteSheetType_Rects;
|
||||
|
||||
// NOTE: Load the sprite meta file =========================================================
|
||||
Dqn_String8 sheet_name = DQN_STRING8("terry_walk_resized_25%");
|
||||
|
||||
Dqn_String8 sprite_spec_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.txt", DQN_STRING_FMT(assets->textures_dir), DQN_STRING_FMT(sheet_name));
|
||||
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_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(";"));
|
||||
|
||||
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));
|
||||
|
||||
// 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, sheet_name, sprite_sheet_path);
|
||||
DQN_ASSERTF(Dqn_Fs_Exists(sprite_sheet_path), "Required file does not exist '%.*s'", DQN_STRING_FMT(sprite_sheet_path));
|
||||
|
||||
// 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);
|
||||
}
|
||||
{
|
||||
FP_LoadSpriteSheetFromSpecResult terry = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("terry_walk_resized_25%"));
|
||||
game->terry_sprite_sheet = terry.sheet;
|
||||
game->terry_sprite_anims = terry.anims;
|
||||
}
|
||||
|
||||
DQN_ASSERT(sheet->rects.size == sprite_rect_index);
|
||||
DQN_ASSERT(anims->size == sprite_anim_index);
|
||||
{
|
||||
FP_LoadSpriteSheetFromSpecResult smoochie = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STRING8("smoochie_resized_25%"));
|
||||
game->smoochie_sprite_sheet = smoochie.sheet;
|
||||
game->smoochie_sprite_anims = smoochie.anims;
|
||||
}
|
||||
}
|
||||
|
||||
game->entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8);
|
||||
@ -563,8 +585,8 @@ void TELY_DLL_Init(void *user_data)
|
||||
|
||||
// NOTE: Hero
|
||||
{
|
||||
TELY_AssetSpriteSheet *sheet = &game->protag_walk_sprite_sheet;
|
||||
Dqn_Slice<TELY_AssetSpriteAnimation> anims = game->protag_walk_sprite_anims;
|
||||
TELY_AssetSpriteSheet *sheet = &game->terry_sprite_sheet;
|
||||
Dqn_Slice<TELY_AssetSpriteAnimation> anims = game->terry_sprite_anims;
|
||||
|
||||
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Terry");
|
||||
entity->local_pos = Dqn_V2_InitNx2(1334, 396);
|
||||
@ -627,14 +649,15 @@ void TELY_DLL_Init(void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Mob spawner
|
||||
if (0) {
|
||||
// NOTE: Mob spawner ===========================================================================
|
||||
{
|
||||
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Mob spawner");
|
||||
entity->local_pos = Dqn_V2_InitNx2(0, platform->core.window_size.y * .5f);
|
||||
entity->flags |= FP_GameEntityFlag_Clickable;
|
||||
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
|
||||
entity->flags |= FP_GameEntityFlag_MoveByMouse;
|
||||
entity->flags |= FP_GameEntityFlag_MobSpawner;
|
||||
entity->spawn_cap = 1;
|
||||
}
|
||||
|
||||
uint16_t font_size = 18;
|
||||
@ -992,9 +1015,15 @@ void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_Renderer *renderer,
|
||||
}
|
||||
|
||||
// NOTE: Mob spawner =======================================================================
|
||||
if ((entity->flags & FP_GameEntityFlag_MobSpawner) && input->timer_s >= entity->next_spawn_timestamp_s) {
|
||||
entity->next_spawn_timestamp_s = DQN_CAST(uint64_t)(input->timer_s + 5.f);
|
||||
FP_Game_EntityAddMob(game, entity_world_pos);
|
||||
if (entity->flags & FP_GameEntityFlag_MobSpawner) {
|
||||
if (entity->spawn_count < entity->spawn_cap) {
|
||||
if (input->timer_s >= entity->next_spawn_timestamp_s) {
|
||||
entity->next_spawn_timestamp_s = DQN_CAST(uint64_t)(input->timer_s + 5.f);
|
||||
entity->spawn_count++;
|
||||
|
||||
FP_Game_EntityAddMob(game, entity_world_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Dqn_Profiler_EndZone(update_zone);
|
||||
|
@ -669,10 +669,10 @@ static FP_GameEntityHandle FP_Game_EntityAddMob(FP_Game *game, Dqn_V2 pos)
|
||||
{
|
||||
FP_GameEntity *entity = FP_Game_MakeEntityPointerF(game, "Mob");
|
||||
entity->local_pos = pos;
|
||||
entity->size_scale = Dqn_V2_InitNx1(4);
|
||||
entity->sprite_sheet = &game->hero_sprite_sheet;
|
||||
entity->sprite_anims = game->hero_sprite_anims;
|
||||
entity->local_hit_box_size = Dqn_V2_InitV2I(game->hero_sprite_sheet.sprite_size);
|
||||
entity->size_scale = Dqn_V2_InitNx1(.5f);
|
||||
entity->sprite_sheet = &game->smoochie_sprite_sheet;
|
||||
entity->sprite_anims = game->smoochie_sprite_anims;
|
||||
entity->local_hit_box_size = Dqn_V2_InitV2I(game->smoochie_sprite_sheet.sprite_size);
|
||||
entity->flags |= FP_GameEntityFlag_Clickable;
|
||||
entity->flags |= FP_GameEntityFlag_MoveByKeyboard;
|
||||
entity->flags |= FP_GameEntityFlag_MoveByMouse;
|
||||
|
@ -106,6 +106,8 @@ struct FP_GameEntity
|
||||
Dqn_V2 attack_box_offset;
|
||||
|
||||
uint64_t next_spawn_timestamp_s;
|
||||
uint64_t spawn_count;
|
||||
uint64_t spawn_cap;
|
||||
|
||||
uint64_t flags;
|
||||
bool facing_left;
|
||||
@ -148,8 +150,11 @@ struct FP_Game
|
||||
Dqn_FArray<FP_GameEntityHandle, 8> parent_entity_stack;
|
||||
Dqn_VArray<FP_GameEntity> entities;
|
||||
|
||||
TELY_AssetSpriteSheet protag_walk_sprite_sheet;
|
||||
Dqn_Slice<TELY_AssetSpriteAnimation> protag_walk_sprite_anims;
|
||||
TELY_AssetSpriteSheet terry_sprite_sheet;
|
||||
Dqn_Slice<TELY_AssetSpriteAnimation> terry_sprite_anims;
|
||||
|
||||
TELY_AssetSpriteSheet smoochie_sprite_sheet;
|
||||
Dqn_Slice<TELY_AssetSpriteAnimation> smoochie_sprite_anims;
|
||||
|
||||
FP_GameEntity *root_entity;
|
||||
FP_GameEntity *entity_free_list;
|
||||
|
@ -171,11 +171,13 @@ int main(int argc, char const *argv[])
|
||||
|
||||
// NOTE: Generate the meta file ================================================================
|
||||
// NOTE: Count the number of animations we loaded frames fore
|
||||
Dqn_usize num_animations = 0;
|
||||
Dqn_usize num_anims = 0;
|
||||
Dqn_usize num_anim_rects = 0;
|
||||
for (Dqn_usize index = 1 /*Sentinel*/; index < sprite_spec_table.occupied; index++) {
|
||||
Dqn_DSMapSlot<SpriteSpecification> *slot = sprite_spec_table.slots + index;
|
||||
if (slot->value.frame_count) {
|
||||
num_animations++;
|
||||
num_anims++;
|
||||
num_anim_rects += slot->value.frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,8 +186,8 @@ int main(int argc, char const *argv[])
|
||||
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) num_animations);
|
||||
DQN_CAST(int) num_anim_rects,
|
||||
DQN_CAST(int) num_anims);
|
||||
|
||||
Dqn_Log_InfoF("Generating meta file: %.*s", DQN_STRING_FMT(meta_path));
|
||||
Dqn_String8 anim_prefix = {};
|
||||
@ -210,15 +212,13 @@ 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_without_extension = Dqn_String8_BinarySplit(file_name, DQN_STRING8(".")).lhs;
|
||||
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(*it.data);
|
||||
Dqn_String8 file_name_to_anim_prefix = Dqn_String8_BinarySplitReverse(file_name, DQN_STRING8("_")).lhs;
|
||||
|
||||
// NOTE: Detect what animation we are currently processing =================================
|
||||
if (anim_prefix.size == 0 || !Dqn_String8_StartsWith(file_name_without_extension, anim_prefix)) {
|
||||
if (anim_prefix.size == 0 || file_name_to_anim_prefix != 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;
|
||||
|
||||
anim_prefix = file_name_to_anim_prefix;
|
||||
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);
|
||||
}
|
||||
|
BIN
project.rdbg
BIN
project.rdbg
Binary file not shown.
Loading…
Reference in New Issue
Block a user