fp: Upgrade TELY and simplify build

This commit is contained in:
doyle 2023-10-29 14:59:53 +11:00
parent b7ae166e65
commit 989b0d30cc
11 changed files with 315 additions and 460 deletions

2
External/tely vendored

@ -1 +1 @@
Subproject commit a1e15e336b6d9eac5538392d2c473c7b740364d5 Subproject commit 77f354ae49aa6421c7d86d6f2254c926fceef9bc

View File

@ -38,7 +38,7 @@ static void FP_EmitParticle(FP_Game *game, FP_ParticleDescriptor descriptor, Dqn
} }
} }
static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform, TELY_Assets *assets, Dqn_Arena *arena, Dqn_Str8 sheet_name) static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_OS *os, TELY_Assets *assets, Dqn_Arena *arena, Dqn_Str8 sheet_name)
{ {
TELY_AssetSpriteSheet result = {}; TELY_AssetSpriteSheet result = {};
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(arena);
@ -47,7 +47,7 @@ static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform,
// NOTE: Load the sprite meta file ========================================================= // NOTE: Load the sprite meta file =========================================================
Dqn_Str8 sprite_spec_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.txt", DQN_STR_FMT(assets->textures_dir), DQN_STR_FMT(sheet_name)); Dqn_Str8 sprite_spec_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.txt", DQN_STR_FMT(assets->textures_dir), DQN_STR_FMT(sheet_name));
Dqn_Str8 sprite_spec_buffer = platform->func_load_file(scratch.arena, sprite_spec_path); Dqn_Str8 sprite_spec_buffer = os->funcs.load_file(scratch.arena, sprite_spec_path);
Dqn_Str8SplitAllocResult lines = Dqn_Str8_SplitAlloc(scratch.allocator, sprite_spec_buffer, DQN_STR8("\n")); Dqn_Str8SplitAllocResult lines = Dqn_Str8_SplitAlloc(scratch.allocator, sprite_spec_buffer, DQN_STR8("\n"));
Dqn_usize sprite_rect_index = 0; Dqn_usize sprite_rect_index = 0;
Dqn_usize sprite_anim_index = 0; Dqn_usize sprite_anim_index = 0;
@ -62,7 +62,7 @@ static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform,
// NOTE: Sprite sheet path // NOTE: Sprite sheet path
Dqn_Str8 sprite_sheet_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STR_FMT(assets->textures_dir), DQN_STR_FMT(line_splits.data[1])); Dqn_Str8 sprite_sheet_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STR_FMT(assets->textures_dir), DQN_STR_FMT(line_splits.data[1]));
result.tex_handle = platform->func_load_texture(assets, sheet_name, sprite_sheet_path); result.tex_handle = os->funcs.load_texture(assets, sheet_name, sprite_sheet_path);
DQN_ASSERTF(Dqn_Fs_Exists(sprite_sheet_path), "Required file does not exist '%.*s'", DQN_STR_FMT(sprite_sheet_path)); DQN_ASSERTF(Dqn_Fs_Exists(sprite_sheet_path), "Required file does not exist '%.*s'", DQN_STR_FMT(sprite_sheet_path));
// NOTE: Total sprite frame count // NOTE: Total sprite frame count
@ -127,18 +127,18 @@ static TELY_AssetSpriteSheet FP_LoadSpriteSheetFromSpec(TELY_Platform *platform,
static void FP_SetDefaultGamepadBindings(FP_GameControls *controls) static void FP_SetDefaultGamepadBindings(FP_GameControls *controls)
{ {
// NOTE: Note up/down/left/right uses analog sticks, non-negotiable. // NOTE: Note up/down/left/right uses analog sticks, non-negotiable.
controls->attack.gamepad_key = TELY_PlatformInputGamepadKey_X; controls->attack.gamepad_key = TELY_OSInputGamepadKey_X;
controls->range_attack.gamepad_key = TELY_PlatformInputGamepadKey_Y; controls->range_attack.gamepad_key = TELY_OSInputGamepadKey_Y;
controls->build_mode.gamepad_key = TELY_PlatformInputGamepadKey_L3; controls->build_mode.gamepad_key = TELY_OSInputGamepadKey_L3;
controls->strafe.gamepad_key = TELY_PlatformInputGamepadKey_B; controls->strafe.gamepad_key = TELY_OSInputGamepadKey_B;
controls->dash.gamepad_key = TELY_PlatformInputGamepadKey_A; controls->dash.gamepad_key = TELY_OSInputGamepadKey_A;
controls->buy_building.gamepad_key = TELY_PlatformInputGamepadKey_LeftBumper; controls->buy_building.gamepad_key = TELY_OSInputGamepadKey_LeftBumper;
controls->buy_upgrade.gamepad_key = TELY_PlatformInputGamepadKey_RightBumper; controls->buy_upgrade.gamepad_key = TELY_OSInputGamepadKey_RightBumper;
controls->move_building_ui_cursor_left.gamepad_key = TELY_PlatformInputGamepadKey_DLeft; controls->move_building_ui_cursor_left.gamepad_key = TELY_OSInputGamepadKey_DLeft;
controls->move_building_ui_cursor_right.gamepad_key = TELY_PlatformInputGamepadKey_DRight; controls->move_building_ui_cursor_right.gamepad_key = TELY_OSInputGamepadKey_DRight;
} }
static bool FP_ListenForNewPlayer(TELY_PlatformInput *input, FP_Game *game) static bool FP_ListenForNewPlayer(TELY_OSInput *input, FP_Game *game)
{ {
bool result = false; bool result = false;
if (game->play.players.size == 2) if (game->play.players.size == 2)
@ -159,8 +159,8 @@ static bool FP_ListenForNewPlayer(TELY_PlatformInput *input, FP_Game *game)
} }
} }
bool keyboard_pressed = !keyboard_already_allocated && TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_B); bool keyboard_pressed = !keyboard_already_allocated && TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_B);
bool gamepad_pressed = TELY_Platform_InputGamepadKeyIsPressed(input, gamepad_index, TELY_PlatformInputGamepadKey_Start); bool gamepad_pressed = TELY_OSInput_GamepadKeyIsPressed(input, gamepad_index, TELY_OSInputGamepadKey_Start);
if (keyboard_pressed || gamepad_pressed) { if (keyboard_pressed || gamepad_pressed) {
FP_GameEntityHandle terry_handle = {}; FP_GameEntityHandle terry_handle = {};
@ -178,19 +178,19 @@ static bool FP_ListenForNewPlayer(TELY_PlatformInput *input, FP_Game *game)
FP_GameControls *controls = &terry->controls; FP_GameControls *controls = &terry->controls;
if (keyboard_pressed) { if (keyboard_pressed) {
controls->mode = FP_GameControlMode_Keyboard; controls->mode = FP_GameControlMode_Keyboard;
controls->up.scan_code = TELY_PlatformInputScanCode_W; controls->up.scan_key = TELY_OSInputScanKey_W;
controls->down.scan_code = TELY_PlatformInputScanCode_S; controls->down.scan_key = TELY_OSInputScanKey_S;
controls->left.scan_code = TELY_PlatformInputScanCode_A; controls->left.scan_key = TELY_OSInputScanKey_A;
controls->right.scan_code = TELY_PlatformInputScanCode_D; controls->right.scan_key = TELY_OSInputScanKey_D;
controls->attack.scan_code = TELY_PlatformInputScanCode_J; controls->attack.scan_key = TELY_OSInputScanKey_J;
controls->range_attack.scan_code = TELY_PlatformInputScanCode_K; controls->range_attack.scan_key = TELY_OSInputScanKey_K;
controls->build_mode.scan_code = TELY_PlatformInputScanCode_H; controls->build_mode.scan_key = TELY_OSInputScanKey_H;
controls->strafe.scan_code = TELY_PlatformInputScanCode_L; controls->strafe.scan_key = TELY_OSInputScanKey_L;
controls->dash.scan_code = TELY_PlatformInputScanCode_N; controls->dash.scan_key = TELY_OSInputScanKey_N;
controls->buy_building.scan_code = TELY_PlatformInputScanCode_U; controls->buy_building.scan_key = TELY_OSInputScanKey_U;
controls->buy_upgrade.scan_code = TELY_PlatformInputScanCode_I; controls->buy_upgrade.scan_key = TELY_OSInputScanKey_I;
controls->move_building_ui_cursor_left.scan_code = TELY_PlatformInputScanCode_Q; controls->move_building_ui_cursor_left.scan_key = TELY_OSInputScanKey_Q;
controls->move_building_ui_cursor_right.scan_code = TELY_PlatformInputScanCode_E; controls->move_building_ui_cursor_right.scan_key = TELY_OSInputScanKey_E;
} else { } else {
controls->mode = FP_GameControlMode_Gamepad; controls->mode = FP_GameControlMode_Gamepad;
controls->gamepad_index = gamepad_index; controls->gamepad_index = gamepad_index;
@ -202,7 +202,7 @@ static bool FP_ListenForNewPlayer(TELY_PlatformInput *input, FP_Game *game)
return result; return result;
} }
static void FP_PlayReset(FP_Game *game, TELY_Platform *platform) static void FP_PlayReset(FP_Game *game, TELY_OS *os)
{ {
FP_GamePlay *play = &game->play; FP_GamePlay *play = &game->play;
if (game->play.root_entity) if (game->play.root_entity)
@ -211,7 +211,7 @@ static void FP_PlayReset(FP_Game *game, TELY_Platform *platform)
Dqn_VArray<FP_GameEntity> shallow_entities_copy = play->entities; Dqn_VArray<FP_GameEntity> shallow_entities_copy = play->entities;
DQN_MEMSET(play, 0, sizeof(*play)); DQN_MEMSET(play, 0, sizeof(*play));
play->chunk_pool = &platform->chunk_pool; play->chunk_pool = &os->chunk_pool;
play->meters_to_pixels = 65.416f; play->meters_to_pixels = 65.416f;
play->entities = shallow_entities_copy; play->entities = shallow_entities_copy;
@ -223,7 +223,7 @@ static void FP_PlayReset(FP_Game *game, TELY_Platform *platform)
play->root_entity = Dqn_VArray_Make(&play->entities, Dqn_ZeroMem_No); play->root_entity = Dqn_VArray_Make(&play->entities, Dqn_ZeroMem_No);
Dqn_FArray_Add(&play->parent_entity_stack, play->root_entity->handle); Dqn_FArray_Add(&play->parent_entity_stack, play->root_entity->handle);
Dqn_PCG32_Seed(&play->rng, platform->core.epoch_time); Dqn_PCG32_Seed(&play->rng, os->core.epoch_time);
// NOTE: Map =================================================================================== // NOTE: Map ===================================================================================
{ {
@ -393,61 +393,54 @@ static void FP_PlayReset(FP_Game *game, TELY_Platform *platform)
play->camera.size = FP_TARGET_VIEWPORT_SIZE; play->camera.size = FP_TARGET_VIEWPORT_SIZE;
} }
#if defined(DQN_OS_WIN32) TELY_OS_DLL_FUNCTION
#define FP_DLL_FUNCTION extern "C" __declspec(dllexport) void TELY_OS_DLLReload(TELY_OS *os)
#else
#define FP_DLL_FUNCTION
#endif
FP_DLL_FUNCTION
void TELY_DLL_Reload(void *user_data)
{ {
TELY_Platform *platform = DQN_CAST(TELY_Platform *)user_data; Dqn_Library_SetPointer(os->core.dqn_lib);
Dqn_Library_SetPointer(platform->core.dqn_lib); os->funcs.set_window_title(DQN_STR8("Terry Cherry"));
platform->func_set_window_title(DQN_STR8("Terry Cherry"));
} }
FP_DLL_FUNCTION TELY_OS_DLL_FUNCTION
void TELY_DLL_Init(void *user_data) void TELY_OS_DLLInit(TELY_OS *os)
{ {
TELY_Platform *platform = DQN_CAST(TELY_Platform *)user_data; TELY_OS_DLLReload(os);
TELY_DLL_Reload(user_data); FP_UnitTests(os);
FP_UnitTests(platform);
// NOTE: TELY Game ============================================================================= // NOTE: TELY Game =============================================================================
TELY_Assets *assets = &platform->assets; TELY_Assets *assets = &os->assets;
FP_Game *game = Dqn_Arena_New(&platform->arena, FP_Game, Dqn_ZeroMem_Yes); FP_Game *game = Dqn_Arena_New(&os->arena, FP_Game, Dqn_ZeroMem_Yes);
Dqn_f32 font_scalar = FP_TARGET_VIEWPORT_SIZE.w / DQN_CAST(Dqn_f32)platform->core.window_size.x; Dqn_f32 font_scalar = FP_TARGET_VIEWPORT_SIZE.w / DQN_CAST(Dqn_f32)os->core.window_size.x;
uint16_t font_size = DQN_CAST(uint16_t)(18 * font_scalar); game->font_size = DQN_CAST(uint16_t)(18 * font_scalar);
game->inter_regular_font_large = platform->func_load_font(assets, DQN_STR8("Inter (Regular)"), DQN_STR8("Data/Fonts/Inter-Regular.otf"), DQN_CAST(uint16_t)(font_size * 5.f)); game->large_font_size = DQN_CAST(uint16_t)(game->font_size * .5f);
game->inter_regular_font = platform->func_load_font(assets, DQN_STR8("Inter (Regular)"), DQN_STR8("Data/Fonts/Inter-Regular.otf"), DQN_CAST(uint16_t)(font_size)); game->large_talkco_font_size = DQN_CAST(uint16_t)(game->font_size * 1.5f);
game->inter_italic_font = platform->func_load_font(assets, DQN_STR8("Inter (Italic)"), DQN_STR8("Data/Fonts/Inter-Italic.otf"), font_size); game->xlarge_talkco_font_size = DQN_CAST(uint16_t)(game->font_size * 2.f);
game->jetbrains_mono_font = platform->func_load_font(assets, DQN_STR8("JetBrains Mono NL (Regular)"), DQN_STR8("Data/Fonts/JetBrainsMonoNL-Regular.ttf"), font_size);
game->talkco_font = platform->func_load_font(assets, DQN_STR8("Talkco"), DQN_STR8("Data/Fonts/Talkco.otf"), font_size); game->inter_regular_font = TELY_Asset_LoadFont(assets, DQN_STR8("Inter (Regular)"), DQN_STR8("Data/Fonts/Inter-Regular.otf"));
game->talkco_font_large = platform->func_load_font(assets, DQN_STR8("Talkco"), DQN_STR8("Data/Fonts/Talkco.otf"), DQN_CAST(uint16_t)(font_size * 1.5f)); game->inter_italic_font = TELY_Asset_LoadFont(assets, DQN_STR8("Inter (Italic)"), DQN_STR8("Data/Fonts/Inter-Italic.otf"));
game->talkco_font_xlarge = platform->func_load_font(assets, DQN_STR8("Talkco"), DQN_STR8("Data/Fonts/Talkco.otf"), DQN_CAST(uint16_t)(font_size * 2.f)); game->jetbrains_mono_font = TELY_Asset_LoadFont(assets, DQN_STR8("JetBrains Mono NL (Regular)"), DQN_STR8("Data/Fonts/JetBrainsMonoNL-Regular.ttf"));
game->audio[FP_GameAudio_TerryHit] = platform->func_load_audio(assets, DQN_STR8("Terry Hit"), DQN_STR8("Data/Audio/terry_hit.ogg")); game->talkco_font = TELY_Asset_LoadFont(assets, DQN_STR8("Talkco"), DQN_STR8("Data/Fonts/Talkco.otf"));
game->audio[FP_GameAudio_Ching] = platform->func_load_audio(assets, DQN_STR8("Ching"), DQN_STR8("Data/Audio/ching.ogg"));
game->audio[FP_GameAudio_Church] = platform->func_load_audio(assets, DQN_STR8("Church"), DQN_STR8("Data/Audio/church.ogg")); game->audio[FP_GameAudio_TerryHit] = os->funcs.load_audio(assets, DQN_STR8("Terry Hit"), DQN_STR8("Data/Audio/terry_hit.ogg"));
game->audio[FP_GameAudio_Club] = platform->func_load_audio(assets, DQN_STR8("Club"), DQN_STR8("Data/Audio/club_terry.ogg")); game->audio[FP_GameAudio_Ching] = os->funcs.load_audio(assets, DQN_STR8("Ching"), DQN_STR8("Data/Audio/ching.ogg"));
game->audio[FP_GameAudio_Dog] = platform->func_load_audio(assets, DQN_STR8("Dog"), DQN_STR8("Data/Audio/dog.ogg")); game->audio[FP_GameAudio_Church] = os->funcs.load_audio(assets, DQN_STR8("Church"), DQN_STR8("Data/Audio/church.ogg"));
game->audio[FP_GameAudio_MerchantGhost] = platform->func_load_audio(assets, DQN_STR8("Ghost"), DQN_STR8("Data/Audio/merchant_ghost.ogg")); game->audio[FP_GameAudio_Club] = os->funcs.load_audio(assets, DQN_STR8("Club"), DQN_STR8("Data/Audio/club_terry.ogg"));
game->audio[FP_GameAudio_MerchantGym] = platform->func_load_audio(assets, DQN_STR8("Gym"), DQN_STR8("Data/Audio/merchant_gym.ogg")); game->audio[FP_GameAudio_Dog] = os->funcs.load_audio(assets, DQN_STR8("Dog"), DQN_STR8("Data/Audio/dog.ogg"));
game->audio[FP_GameAudio_MerchantPhone] = platform->func_load_audio(assets, DQN_STR8("Phone"), DQN_STR8("Data/Audio/merchant_tech.ogg")); game->audio[FP_GameAudio_MerchantGhost] = os->funcs.load_audio(assets, DQN_STR8("Ghost"), DQN_STR8("Data/Audio/merchant_ghost.ogg"));
game->audio[FP_GameAudio_MerchantTerry] = platform->func_load_audio(assets, DQN_STR8("Door"), DQN_STR8("Data/Audio/merchant_terry.ogg")); game->audio[FP_GameAudio_MerchantGym] = os->funcs.load_audio(assets, DQN_STR8("Gym"), DQN_STR8("Data/Audio/merchant_gym.ogg"));
game->audio[FP_GameAudio_Message] = platform->func_load_audio(assets, DQN_STR8("Message"), DQN_STR8("Data/Audio/message.ogg")); game->audio[FP_GameAudio_MerchantPhone] = os->funcs.load_audio(assets, DQN_STR8("Phone"), DQN_STR8("Data/Audio/merchant_tech.ogg"));
game->audio[FP_GameAudio_Monkey] = platform->func_load_audio(assets, DQN_STR8("Monkey"), DQN_STR8("Data/Audio/monkey.ogg")); game->audio[FP_GameAudio_MerchantTerry] = os->funcs.load_audio(assets, DQN_STR8("Door"), DQN_STR8("Data/Audio/merchant_terry.ogg"));
game->audio[FP_GameAudio_Plane] = platform->func_load_audio(assets, DQN_STR8("Plane"), DQN_STR8("Data/Audio/airport.ogg")); game->audio[FP_GameAudio_Message] = os->funcs.load_audio(assets, DQN_STR8("Message"), DQN_STR8("Data/Audio/message.ogg"));
game->audio[FP_GameAudio_PortalDestroy] = platform->func_load_audio(assets, DQN_STR8("Portal Destroy"), DQN_STR8("Data/Audio/portal_destroy.ogg")); game->audio[FP_GameAudio_Monkey] = os->funcs.load_audio(assets, DQN_STR8("Monkey"), DQN_STR8("Data/Audio/monkey.ogg"));
game->audio[FP_GameAudio_Smooch] = platform->func_load_audio(assets, DQN_STR8("Smooch"), DQN_STR8("Data/Audio/smooch.ogg")); game->audio[FP_GameAudio_Plane] = os->funcs.load_audio(assets, DQN_STR8("Plane"), DQN_STR8("Data/Audio/airport.ogg"));
game->audio[FP_GameAudio_Woosh] = platform->func_load_audio(assets, DQN_STR8("Woosh"), DQN_STR8("Data/Audio/woosh.ogg")); game->audio[FP_GameAudio_PortalDestroy] = os->funcs.load_audio(assets, DQN_STR8("Portal Destroy"), DQN_STR8("Data/Audio/portal_destroy.ogg"));
game->audio[FP_GameAudio_Smooch] = os->funcs.load_audio(assets, DQN_STR8("Smooch"), DQN_STR8("Data/Audio/smooch.ogg"));
game->audio[FP_GameAudio_Woosh] = os->funcs.load_audio(assets, DQN_STR8("Woosh"), DQN_STR8("Data/Audio/woosh.ogg"));
// NOTE: Load sprite sheets ==================================================================== // NOTE: Load sprite sheets ====================================================================
platform->user_data = game; os->user_data = game;
game->atlas_sprite_sheet = FP_LoadSpriteSheetFromSpec(platform, assets, &platform->arena, DQN_STR8("atlas")); game->atlas_sprite_sheet = FP_LoadSpriteSheetFromSpec(os, assets, &os->arena, DQN_STR8("atlas"));
FP_PlayReset(game, platform); FP_PlayReset(game, os);
} }
@ -508,7 +501,7 @@ static void FP_AppendMobSpawnerWaypoints(FP_Game *game, FP_GameEntityHandle src_
} }
} }
static void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_PlatformInput *input, FP_GameEntity *entity, Dqn_V2 *acceleration_meters_per_s) static void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_OSInput *input, FP_GameEntity *entity, Dqn_V2 *acceleration_meters_per_s)
{ {
TELY_AssetSpriteSheet *sheet = &game->atlas_sprite_sheet; TELY_AssetSpriteSheet *sheet = &game->atlas_sprite_sheet;
FP_GameEntityAction *action = &entity->action; FP_GameEntityAction *action = &entity->action;
@ -1301,25 +1294,25 @@ static void FP_EntityActionStateMachine(FP_Game *game, TELY_Audio *audio, TELY_P
} }
} }
static void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput *input, TELY_Audio *audio) static void FP_Update(TELY_OS *os, FP_Game *game, TELY_OSInput *input, TELY_Audio *audio)
{ {
Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate); Dqn_Profiler_ZoneScopeWithIndex("FP_Update", FP_ProfileZone_FPUpdate);
game->play.update_counter++; game->play.update_counter++;
Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STR8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop); Dqn_ProfilerZone update_zone = Dqn_Profiler_BeginZoneWithIndex(DQN_STR8("FP_Update: Entity loop"), FP_ProfileZone_FPUpdate_EntityLoop);
if (game->play.state == FP_GameState_Play && game->play.perry_joined != FP_GamePerryJoins_Enters) { if (game->play.state == FP_GameState_Play && game->play.perry_joined != FP_GamePerryJoins_Enters) {
game->play.clock_ms = DQN_CAST(uint64_t)(platform->input.timer_s * 1000.f); game->play.clock_ms = DQN_CAST(uint64_t)(os->input.timer_s * 1000.f);
DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(4127) // Conditional expression is constant 'FP_DEVELOPER_MODE' DQN_MSVC_WARNING_DISABLE(4127) // Conditional expression is constant 'FP_DEVELOPER_MODE'
if (FP_DEVELOPER_MODE && TELY_Platform_InputKeyIsReleased(input->mouse_left)) if (FP_DEVELOPER_MODE && TELY_OSInput_KeyIsReleased(input->mouse_left))
game->play.clicked_entity = game->play.prev_active_entity; game->play.clicked_entity = game->play.prev_active_entity;
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Escape)) if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Escape))
game->play.state = FP_GameState_Pause; game->play.state = FP_GameState_Pause;
if (FP_DEVELOPER_MODE && game->play.clicked_entity.id) { if (FP_DEVELOPER_MODE && game->play.clicked_entity.id) {
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Delete)) if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Delete))
FP_Game_DeleteEntity(game, game->play.clicked_entity); FP_Game_DeleteEntity(game, game->play.clicked_entity);
} }
DQN_MSVC_WARNING_POP DQN_MSVC_WARNING_POP
@ -1347,8 +1340,8 @@ static void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput
// NOTE: Gamepad movement input // NOTE: Gamepad movement input
if (controls->mode == FP_GameControlMode_Gamepad) { if (controls->mode == FP_GameControlMode_Gamepad) {
dir_vector.x += input->left_stick[controls->gamepad_index].x; TELY_OSInputGamepad *gamepad = input->gamepads + controls->gamepad_index;
dir_vector.y += input->left_stick[controls->gamepad_index].y; dir_vector += gamepad->left_stick;
} }
// TODO(doyle): Some bug, diagonal is still faster // TODO(doyle): Some bug, diagonal is still faster
@ -1945,7 +1938,7 @@ static void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput
// NOTE: Tick the state machine // NOTE: Tick the state machine
// NOTE: This can delete the entity! Take caution // NOTE: This can delete the entity! Take caution
FP_GameEntityHandle entity_handle = entity->handle; FP_GameEntityHandle entity_handle = entity->handle;
FP_EntityActionStateMachine(game, &platform->audio, input, entity, &acceleration_meters_per_s); FP_EntityActionStateMachine(game, &os->audio, input, entity, &acceleration_meters_per_s);
// NOTE: Limit the entity to within bounds of the camera only in multiplayer =========== // NOTE: Limit the entity to within bounds of the camera only in multiplayer ===========
bool entity_is_oob_with_camera = false; bool entity_is_oob_with_camera = false;
@ -2304,7 +2297,7 @@ static void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput
// NOTE: Clamp camera to map bounds ============================================================ // NOTE: Clamp camera to map bounds ============================================================
{ {
Dqn_V2 window_size = Dqn_V2_InitV2I(platform->core.window_size); Dqn_V2 window_size = Dqn_V2_InitV2I(os->core.window_size);
camera->scale = window_size / camera->size; camera->scale = window_size / camera->size;
Dqn_V2 camera_size_screen = camera->size * camera->scale; Dqn_V2 camera_size_screen = camera->size * camera->scale;
@ -2323,27 +2316,27 @@ static void FP_Update(TELY_Platform *platform, FP_Game *game, TELY_PlatformInput
Dqn_Profiler_EndZone(update_zone); Dqn_Profiler_EndZone(update_zone);
} }
static Dqn_Str8 FP_ScanCodeToLabel(Dqn_Arena *arena, TELY_PlatformInputScanCode scan_code) static Dqn_Str8 FP_ScanKeyToLabel(Dqn_Arena *arena, TELY_OSInputScanKey scan_key)
{ {
Dqn_Str8 result = {}; Dqn_Str8 result = {};
Dqn_Allocator allocator = Dqn_Arena_Allocator(arena); Dqn_Allocator allocator = Dqn_Arena_Allocator(arena);
if (scan_code >= TELY_PlatformInputScanCode_A && scan_code <= TELY_PlatformInputScanCode_Z) { if (scan_key >= TELY_OSInputScanKey_A && scan_key <= TELY_OSInputScanKey_Z) {
char scan_code_ch = DQN_CAST(char)('A' + (scan_code - TELY_PlatformInputScanCode_A)); char scan_key_ch = DQN_CAST(char)('A' + (scan_key - TELY_OSInputScanKey_A));
result = Dqn_Str8_InitF(allocator, "[%c]", scan_code_ch); result = Dqn_Str8_InitF(allocator, "[%c]", scan_key_ch);
} else { } else {
if (scan_code == TELY_PlatformInputScanCode_Up) { if (scan_key == TELY_OSInputScanKey_Up) {
result = Dqn_Str8_InitF(allocator, "[Up]"); result = Dqn_Str8_InitF(allocator, "[Up]");
} else if (scan_code == TELY_PlatformInputScanCode_Down) { } else if (scan_key == TELY_OSInputScanKey_Down) {
result = Dqn_Str8_InitF(allocator, "[Down]"); result = Dqn_Str8_InitF(allocator, "[Down]");
} else if (scan_code == TELY_PlatformInputScanCode_Left) { } else if (scan_key == TELY_OSInputScanKey_Left) {
result = Dqn_Str8_InitF(allocator, "[Left]"); result = Dqn_Str8_InitF(allocator, "[Left]");
} else if (scan_code == TELY_PlatformInputScanCode_Right) { } else if (scan_key == TELY_OSInputScanKey_Right) {
result = Dqn_Str8_InitF(allocator, "[Right]"); result = Dqn_Str8_InitF(allocator, "[Right]");
} else if (scan_code == TELY_PlatformInputScanCode_Semicolon) { } else if (scan_key == TELY_OSInputScanKey_Semicolon) {
result = Dqn_Str8_InitF(allocator, "[;]"); result = Dqn_Str8_InitF(allocator, "[;]");
} else if (scan_code == TELY_PlatformInputScanCode_Apostrophe) { } else if (scan_key == TELY_OSInputScanKey_Apostrophe) {
result = Dqn_Str8_InitF(allocator, "[']"); result = Dqn_Str8_InitF(allocator, "[']");
} else if (scan_code == TELY_PlatformInputScanCode_Backslash) { } else if (scan_key == TELY_OSInputScanKey_Backslash) {
result = Dqn_Str8_InitF(allocator, "[/]"); result = Dqn_Str8_InitF(allocator, "[/]");
} }
} }
@ -2366,20 +2359,20 @@ static void FP_DrawBillboardKeyBindHint(TELY_Renderer *renderer,
if (mode == FP_GameControlMode_Gamepad) { if (mode == FP_GameControlMode_Gamepad) {
Dqn_Str8 tex_name = {}; Dqn_Str8 tex_name = {};
if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_A) if (key_bind.gamepad_key == TELY_OSInputGamepadKey_A)
tex_name = g_anim_names.merchant_button_a; tex_name = g_anim_names.merchant_button_a;
else if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_B) else if (key_bind.gamepad_key == TELY_OSInputGamepadKey_B)
tex_name = g_anim_names.merchant_button_b; tex_name = g_anim_names.merchant_button_b;
else if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_X) else if (key_bind.gamepad_key == TELY_OSInputGamepadKey_X)
tex_name = g_anim_names.merchant_button_x; tex_name = g_anim_names.merchant_button_x;
else if (key_bind.gamepad_key == TELY_PlatformInputGamepadKey_Y) else if (key_bind.gamepad_key == TELY_OSInputGamepadKey_Y)
tex_name = g_anim_names.merchant_button_y; tex_name = g_anim_names.merchant_button_y;
if (tex_name.size) { if (tex_name.size) {
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, tex_name); TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, tex_name);
Dqn_Rect button_rect = game->atlas_sprite_sheet.rects.data[anim->index]; Dqn_Rect button_rect = game->atlas_sprite_sheet.rects.data[anim->index];
Dqn_V2 text_size = TELY_Asset_MeasureText(TELY_Render_Font(renderer, assets), player_prefix); Dqn_V2 text_size = TELY_Asset_MeasureText(assets, TELY_Render_ActiveFont(renderer), player_prefix);
TELY_Render_Text(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), player_prefix); TELY_Render_Text(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), player_prefix);
Dqn_Rect gamepad_btn_rect = {}; Dqn_Rect gamepad_btn_rect = {};
@ -2395,22 +2388,22 @@ static void FP_DrawBillboardKeyBindHint(TELY_Renderer *renderer,
TELY_COLOUR_WHITE_V4); TELY_COLOUR_WHITE_V4);
} }
} else { } else {
Dqn_Str8 key_bind_label = FP_ScanCodeToLabel(scratch.arena, key_bind.scan_code); Dqn_Str8 key_bind_label = FP_ScanKeyToLabel(scratch.arena, key_bind.scan_key);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), "%.*s%.*s", DQN_STR_FMT(player_prefix), DQN_STR_FMT(key_bind_label)); TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0, +1.f), "%.*s%.*s", DQN_STR_FMT(player_prefix), DQN_STR_FMT(key_bind_label));
} }
} }
static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *renderer, TELY_Audio *audio) static void FP_Render(FP_Game *game, TELY_OS *os, TELY_Renderer *renderer, TELY_Audio *audio)
{ {
Dqn_Profiler_ZoneScopeWithIndex("FP_Render", FP_ProfileZone_FPRender); Dqn_Profiler_ZoneScopeWithIndex("FP_Render", FP_ProfileZone_FPRender);
TELY_PlatformInput *input = &platform->input; TELY_OSInput *input = &os->input;
TELY_RFui *rfui = &game->rfui; TELY_RFui *rfui = &game->rfui;
TELY_Assets *assets = &platform->assets; TELY_Assets *assets = &os->assets;
TELY_Render_ClearColourV3(renderer, TELY_COLOUR_BLACK_MIDNIGHT_V4.rgb); TELY_Render_ClearColourV3(renderer, TELY_COLOUR_BLACK_MIDNIGHT_V4.rgb);
TELY_Render_PushFont(renderer, game->jetbrains_mono_font); TELY_Render_PushFontSize(renderer, game->jetbrains_mono_font, game->font_size);
TELY_RFui_FrameSetup(rfui, &platform->frame_arena); TELY_RFui_FrameSetup(rfui, &os->frame_arena);
TELY_RFui_PushFont(rfui, game->jetbrains_mono_font); TELY_RFui_PushFontSize(rfui, game->jetbrains_mono_font, game->font_size);
FP_GameCamera shake_camera = game->play.camera; FP_GameCamera shake_camera = game->play.camera;
{ {
@ -2441,18 +2434,18 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(camera_xforms.view_model, input->mouse_p); Dqn_V2 world_mouse_p = Dqn_M2x3_MulV2(camera_xforms.view_model, input->mouse_p);
// NOTE: Draw tiles ============================================================================ // NOTE: Draw tiles ============================================================================
Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(platform->core.window_size.w / game->play.tile_size); Dqn_usize tile_count_x = DQN_CAST(Dqn_usize)(os->core.window_size.w / game->play.tile_size);
Dqn_usize tile_count_y = DQN_CAST(Dqn_usize)(platform->core.window_size.h / game->play.tile_size); Dqn_usize tile_count_y = DQN_CAST(Dqn_usize)(os->core.window_size.h / game->play.tile_size);
for (Dqn_usize x = 0; x < tile_count_x; x++) { for (Dqn_usize x = 0; x < tile_count_x; x++) {
Dqn_V2 start = Dqn_V2_InitNx2((x + 1) * game->play.tile_size, 0); Dqn_V2 start = Dqn_V2_InitNx2((x + 1) * game->play.tile_size, 0);
Dqn_V2 end = Dqn_V2_InitNx2(start.x, platform->core.window_size.h); Dqn_V2 end = Dqn_V2_InitNx2(start.x, os->core.window_size.h);
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f); TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f);
} }
for (Dqn_usize y = 0; y < tile_count_y; y++) { for (Dqn_usize y = 0; y < tile_count_y; y++) {
Dqn_V2 start = Dqn_V2_InitNx2(0, (y + 1) * game->play.tile_size); Dqn_V2 start = Dqn_V2_InitNx2(0, (y + 1) * game->play.tile_size);
Dqn_V2 end = Dqn_V2_InitNx2(platform->core.window_size.w, start.y); Dqn_V2 end = Dqn_V2_InitNx2(os->core.window_size.w, start.y);
TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f); TELY_Render_LineColourV4(renderer, start, end, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, .25f), 1.f);
} }
@ -2798,7 +2791,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
if (game->play.hot_entity == entity->handle) { if (game->play.hot_entity == entity->handle) {
if (entity->name.size) { if (entity->name.size) {
Dqn_V2I player_tile = Dqn_V2I_InitNx2(world_pos.x / game->play.tile_size, world_pos.y / game->play.tile_size); Dqn_V2I player_tile = Dqn_V2I_InitNx2(world_pos.x / game->play.tile_size, world_pos.y / game->play.tile_size);
Dqn_f32 line_height = TELY_Render_FontHeight(renderer, &platform->assets); Dqn_f32 line_height = TELY_Render_FontHeight(renderer);
Dqn_V2 draw_p = world_mouse_p; Dqn_V2 draw_p = world_mouse_p;
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "%.*s", DQN_STR_FMT(entity->name)); draw_p.y += line_height; TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "%.*s", DQN_STR_FMT(entity->name)); draw_p.y += line_height;
TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "World Pos: (%.1f, %.1f)", world_pos.x, world_pos.y); draw_p.y += line_height; TELY_Render_TextF(renderer, draw_p, Dqn_V2_InitNx2(0.f, 1), "World Pos: (%.1f, %.1f)", world_pos.x, world_pos.y); draw_p.y += line_height;
@ -2818,7 +2811,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
if (entity->type == FP_EntityType_Billboard) { if (entity->type == FP_EntityType_Billboard) {
TELY_Render_PushFont(renderer, game->talkco_font); TELY_Render_PushFontSize(renderer, game->talkco_font, game->font_size);
DQN_DEFER { TELY_Render_PopFont(renderer); }; DQN_DEFER { TELY_Render_PopFont(renderer); };
DQN_FOR_UINDEX (player_index, game->play.players.size) { DQN_FOR_UINDEX (player_index, game->play.players.size) {
FP_GameEntityHandle player_handle = game->play.players.data[player_index]; FP_GameEntityHandle player_handle = game->play.players.data[player_index];
@ -2828,7 +2821,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
switch (state) { switch (state) {
case FP_EntityBillboardState_Attack: { case FP_EntityBillboardState_Attack: {
Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.6f, 0.2f)); Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.6f, 0.2f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, colour_accent_yellow); TELY_Render_PushColourV4(renderer, colour_accent_yellow);
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->attack, draw_p, true /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->attack, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
@ -2836,7 +2829,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
case FP_EntityBillboardState_Dash: { case FP_EntityBillboardState_Dash: {
Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.505f, -0.08f)); Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.505f, -0.08f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFFE726)); TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFFE726));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->dash, draw_p, true /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->dash, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
@ -2847,7 +2840,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
case FP_EntityBillboardState_RangeAttack: { case FP_EntityBillboardState_RangeAttack: {
Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.20f, -0.13f)); Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.20f, -0.13f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0x364659)); TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0x364659));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->range_attack, draw_p, true /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->range_attack, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
@ -2855,7 +2848,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
case FP_EntityBillboardState_Strafe: { case FP_EntityBillboardState_Strafe: {
Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.36f, -0.15f)); Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.36f, -0.15f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8)); TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->strafe, draw_p, true /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->strafe, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
@ -2863,25 +2856,25 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
case FP_EntityBillboardState_Build: { case FP_EntityBillboardState_Build: {
Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.065f, 0.2f)); Dqn_V2 draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.065f, 0.2f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, colour_accent_yellow); TELY_Render_PushColourV4(renderer, colour_accent_yellow);
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->build_mode, draw_p, true /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->build_mode, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.35f, 0.2f)); draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.35f, 0.2f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8)); TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->move_building_ui_cursor_left, draw_p, true /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->move_building_ui_cursor_left, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.44f, 0.2f)); draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.44f, 0.2f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8)); TELY_Render_PushColourV4(renderer, TELY_Colour_V4InitRGBU32(0xFF68A8));
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->move_building_ui_cursor_right, draw_p, false /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->move_building_ui_cursor_right, draw_p, false /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.665f, 0.2f)); draw_p = Dqn_Rect_InterpolatedPoint(world_hit_box, Dqn_V2_InitNx2(0.665f, 0.2f));
draw_p.y += TELY_Render_FontHeight(renderer, assets) * player_index; draw_p.y += TELY_Render_FontHeight(renderer) * player_index;
TELY_Render_PushColourV4(renderer, TELY_COLOUR_BLACK_V4); TELY_Render_PushColourV4(renderer, TELY_COLOUR_BLACK_V4);
FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->attack, draw_p, true /*draw_player_prefix*/); FP_DrawBillboardKeyBindHint(renderer, assets, game, player_index, controls->mode, controls->attack, draw_p, true /*draw_player_prefix*/);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
@ -2899,7 +2892,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
// NOTE: Shake the world =================================================================== // NOTE: Shake the world ===================================================================
Dqn_Rect window_rect = {}; Dqn_Rect window_rect = {};
window_rect.size = Dqn_V2_InitV2I(platform->core.window_size); window_rect.size = Dqn_V2_InitV2I(os->core.window_size);
Dqn_f32 tex_scalar = {}; Dqn_f32 tex_scalar = {};
{ {
@ -3007,7 +3000,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
Dqn_V2 const player_avatar_base_pos[] = { Dqn_V2 const player_avatar_base_pos[] = {
Dqn_V2_InitNx1(32.f), Dqn_V2_InitNx1(32.f),
Dqn_V2_InitNx2(platform->core.window_size.x - 320.f, 32.f), Dqn_V2_InitNx2(os->core.window_size.x - 320.f, 32.f),
}; };
DQN_ASSERT(game->play.players.size <= DQN_ARRAY_UCOUNT(player_avatar_base_pos)); DQN_ASSERT(game->play.players.size <= DQN_ARRAY_UCOUNT(player_avatar_base_pos));
@ -3015,7 +3008,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
if (game->play.players.size == 1) { if (game->play.players.size == 1) {
// NOTE: We show the Press <BTN> to join for the remaining 2nd player // NOTE: We show the Press <BTN> to join for the remaining 2nd player
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity()); TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
TELY_Render_PushFont(renderer, game->talkco_font); TELY_Render_PushFontSize(renderer, game->talkco_font, game->font_size);
DQN_DEFER { DQN_DEFER {
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
TELY_Render_PopTransform(renderer); TELY_Render_PopTransform(renderer);
@ -3028,7 +3021,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
else else
join_game_key = DQN_STR8("<Gamepad: B>"); join_game_key = DQN_STR8("<Gamepad: B>");
Dqn_f32 font_height = TELY_Render_FontHeight(renderer, assets); Dqn_f32 font_height = TELY_Render_FontHeight(renderer);
Dqn_V2 base_p = player_avatar_base_pos[game->play.players.size]; Dqn_V2 base_p = player_avatar_base_pos[game->play.players.size];
TELY_Render_TextF(renderer, base_p, Dqn_V2_Zero, "Press %.*s", DQN_STR_FMT(join_game_key)); base_p.y += font_height; TELY_Render_TextF(renderer, base_p, Dqn_V2_Zero, "Press %.*s", DQN_STR_FMT(join_game_key)); base_p.y += font_height;
FP_ListenForNewPlayer(input, game); FP_ListenForNewPlayer(input, game);
@ -3144,7 +3137,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
TELY_Render_PushColourV4(renderer, TELY_COLOUR_BLACK_V4); TELY_Render_PushColourV4(renderer, TELY_COLOUR_BLACK_V4);
TELY_Render_PushFont(renderer, game->talkco_font_large); TELY_Render_PushFontSize(renderer, game->talkco_font, game->large_talkco_font_size);
DQN_DEFER { DQN_DEFER {
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
@ -3181,9 +3174,9 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
tex_mod_colour); tex_mod_colour);
} else { } else {
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
TELY_AssetFont const *font = TELY_Render_Font(renderer, assets); TELY_AssetFontSizeHandle font_size = TELY_Render_ActiveFont(renderer);
Dqn_Str8 key_bind_label = FP_ScanCodeToLabel(scratch.arena, key_bind.scan_code); Dqn_Str8 key_bind_label = FP_ScanKeyToLabel(scratch.arena, key_bind.scan_key);
interact_btn_rect.size = TELY_Asset_MeasureText(font, key_bind_label); interact_btn_rect.size = TELY_Asset_MeasureText(assets, font_size, key_bind_label);
Dqn_Rect key_bind_rect = interact_btn_rect; Dqn_Rect key_bind_rect = interact_btn_rect;
key_bind_rect.pos.y += interact_btn_rect.size.y * .3f; key_bind_rect.pos.y += interact_btn_rect.size.y * .3f;
@ -3204,13 +3197,13 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
bool trigger_buy_anim = false; bool trigger_buy_anim = false;
if (have_enough_coins) { if (have_enough_coins) {
if (TELY_Platform_InputScanCodeIsPressed(input, key_bind.scan_code)) { if (TELY_OSInput_ScanKeyIsPressed(input, key_bind.scan_key)) {
game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms + buy_duration_ms; game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms + buy_duration_ms;
} else if (TELY_Platform_InputScanCodeIsDown(input, key_bind.scan_code)) { } else if (TELY_OSInput_ScanKeyIsDown(input, key_bind.scan_key)) {
trigger_buy_anim = true; trigger_buy_anim = true;
if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp)
game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms; game->play.player_trigger_purchase_building_timestamp = game->play.clock_ms;
} else if (TELY_Platform_InputScanCodeIsReleased(input, key_bind.scan_code)) { } else if (TELY_OSInput_ScanKeyIsReleased(input, key_bind.scan_key)) {
if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) { if (game->play.clock_ms > game->play.player_trigger_purchase_building_timestamp) {
if (mapping.inventory_count) { if (mapping.inventory_count) {
player->coins -= *mapping.building_base_price; player->coins -= *mapping.building_base_price;
@ -3296,9 +3289,9 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
tex_mod_colour); tex_mod_colour);
} else { } else {
Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr);
TELY_AssetFont const *font = TELY_Render_Font(renderer, assets); TELY_AssetFontSizeHandle font_size = TELY_Render_ActiveFont(renderer);
Dqn_Str8 key_bind_label = FP_ScanCodeToLabel(scratch.arena, key_bind.scan_code); Dqn_Str8 key_bind_label = FP_ScanKeyToLabel(scratch.arena, key_bind.scan_key);
interact_btn_rect.size = TELY_Asset_MeasureText(font, key_bind_label); interact_btn_rect.size = TELY_Asset_MeasureText(assets, font_size, key_bind_label);
Dqn_Rect key_bind_rect = interact_btn_rect; Dqn_Rect key_bind_rect = interact_btn_rect;
key_bind_rect.pos.y += interact_btn_rect.size.y * .3f; key_bind_rect.pos.y += interact_btn_rect.size.y * .3f;
@ -3336,13 +3329,13 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
bool trigger_buy_anim = false; bool trigger_buy_anim = false;
if (have_enough_coins) { if (have_enough_coins) {
if (TELY_Platform_InputScanCodeIsPressed(input, key_bind.scan_code)) { if (TELY_OSInput_ScanKeyIsPressed(input, key_bind.scan_key)) {
game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms + buy_duration_ms; game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms + buy_duration_ms;
} else if (TELY_Platform_InputScanCodeIsDown(input, key_bind.scan_code)) { } else if (TELY_OSInput_ScanKeyIsDown(input, key_bind.scan_key)) {
trigger_buy_anim = true; trigger_buy_anim = true;
if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp)
game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms; game->play.player_trigger_purchase_upgrade_timestamp = game->play.clock_ms;
} else if (TELY_Platform_InputScanCodeIsReleased(input, key_bind.scan_code)) { } else if (TELY_OSInput_ScanKeyIsReleased(input, key_bind.scan_key)) {
if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) { if (game->play.clock_ms > game->play.player_trigger_purchase_upgrade_timestamp) {
player->coins -= *mapping.upgrade_base_price; player->coins -= *mapping.upgrade_base_price;
*mapping.upgrade_base_price *= 1; *mapping.upgrade_base_price *= 1;
@ -3411,11 +3404,11 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
0.f, 0.f,
TELY_COLOUR_WHITE_V4); TELY_COLOUR_WHITE_V4);
TELY_Render_PushFont(renderer, game->talkco_font); TELY_Render_PushFontSize(renderer, game->talkco_font, game->font_size);
DQN_DEFER { TELY_Render_PopFont(renderer); }; DQN_DEFER { TELY_Render_PopFont(renderer); };
next_pos = Dqn_Rect_InterpolatedPoint(player_avatar_rect, Dqn_V2_InitNx2(1.f, 0)); next_pos = Dqn_Rect_InterpolatedPoint(player_avatar_rect, Dqn_V2_InitNx2(1.f, 0));
Dqn_f32 font_height = TELY_Render_FontHeight(renderer, &platform->assets); Dqn_f32 font_height = TELY_Render_FontHeight(renderer);
// NOTE: Health bar ==================================================== // NOTE: Health bar ====================================================
Dqn_f32 bar_height = font_height * .75f; Dqn_f32 bar_height = font_height * .75f;
@ -3677,7 +3670,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
else if (building.type == FP_EntityType_ChurchTerry) else if (building.type == FP_EntityType_ChurchTerry)
building_count = player->inventory.churchs; building_count = player->inventory.churchs;
TELY_Render_PushFont(renderer, game->talkco_font); TELY_Render_PushFontSize(renderer, game->talkco_font, game->font_size);
DQN_DEFER { TELY_Render_PopFont(renderer); }; DQN_DEFER { TELY_Render_PopFont(renderer); };
Dqn_V2 label_p = Dqn_Rect_InterpolatedPoint(rect, Dqn_V2_InitNx2(0.5f, 1.25f)); Dqn_V2 label_p = Dqn_Rect_InterpolatedPoint(rect, Dqn_V2_InitNx2(0.5f, 1.25f));
@ -3694,7 +3687,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity()); TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
DQN_DEFER { TELY_Render_PopTransform(renderer); }; DQN_DEFER { TELY_Render_PopTransform(renderer); };
TELY_Render_PushFont(renderer, game->talkco_font_large); TELY_Render_PushFontSize(renderer, game->talkco_font, game->large_talkco_font_size);
DQN_DEFER { TELY_Render_PopFont(renderer); }; DQN_DEFER { TELY_Render_PopFont(renderer); };
uint64_t time_until_next_wave_ms = 0; uint64_t time_until_next_wave_ms = 0;
@ -3704,7 +3697,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
} }
Dqn_f32 mid_x = platform->core.window_size.x * .5f; Dqn_f32 mid_x = os->core.window_size.x * .5f;
if (time_until_next_wave_ms) { if (time_until_next_wave_ms) {
TELY_Render_TextF(renderer, TELY_Render_TextF(renderer,
Dqn_V2_InitNx2(mid_x, first_player_avatar_rect.pos.y), Dqn_V2_InitNx2(mid_x, first_player_avatar_rect.pos.y),
@ -3721,13 +3714,13 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity()); TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
DQN_DEFER { TELY_Render_PopTransform(renderer); }; DQN_DEFER { TELY_Render_PopTransform(renderer); };
Dqn_f32 font_height = TELY_Render_FontHeight(renderer, assets); Dqn_f32 font_height = TELY_Render_FontHeight(renderer);
Dqn_f32 bar_height = font_height * 1.25f; Dqn_f32 bar_height = font_height * 1.25f;
{ {
TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.heart); TELY_AssetSpriteAnimation *anim = TELY_Asset_GetSpriteAnimation(&game->atlas_sprite_sheet, g_anim_names.heart);
FP_GameEntity *heart = FP_Game_GetEntity(game, game->play.heart); FP_GameEntity *heart = FP_Game_GetEntity(game, game->play.heart);
Dqn_f32 max_width = platform->core.window_size.x * .5f; Dqn_f32 max_width = os->core.window_size.x * .5f;
Dqn_V2 draw_p = Dqn_V2_InitNx2(platform->core.window_size.x * .25f, first_player_avatar_rect.pos.y + bar_height); Dqn_V2 draw_p = Dqn_V2_InitNx2(os->core.window_size.x * .25f, first_player_avatar_rect.pos.y + bar_height);
Dqn_f32 health_t = heart->hp / DQN_CAST(Dqn_f32)heart->hp_cap; Dqn_f32 health_t = heart->hp / DQN_CAST(Dqn_f32)heart->hp_cap;
Dqn_Rect health_rect = Dqn_Rect_InitNx4(draw_p.x, draw_p.y, max_width, bar_height); Dqn_Rect health_rect = Dqn_Rect_InitNx4(draw_p.x, draw_p.y, max_width, bar_height);
Dqn_Rect curr_health_rect = Dqn_Rect_InitNx4(draw_p.x, draw_p.y, max_width * health_t, bar_height); Dqn_Rect curr_health_rect = Dqn_Rect_InitNx4(draw_p.x, draw_p.y, max_width * health_t, bar_height);
@ -3755,7 +3748,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
0.f /*rotation*/, 0.f /*rotation*/,
TELY_COLOUR_WHITE_V4); TELY_COLOUR_WHITE_V4);
TELY_Render_PushFont(renderer, game->talkco_font_large); TELY_Render_PushFontSize(renderer, game->talkco_font, game->large_talkco_font_size);
DQN_DEFER { TELY_Render_PopFont(renderer); }; DQN_DEFER { TELY_Render_PopFont(renderer); };
TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(heart_icon_rect, Dqn_V2_InitNx2(1.f, 0.65f)), Dqn_V2_Zero, "Terry's Heart"); TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(heart_icon_rect, Dqn_V2_InitNx2(1.f, 0.65f)), Dqn_V2_Zero, "Terry's Heart");
} }
@ -3772,7 +3765,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
// NOTE: Add scanlines into the game for A E S T H E T I C S =================================== // NOTE: Add scanlines into the game for A E S T H E T I C S ===================================
if (game->play.state == FP_GameState_Play) { if (game->play.state == FP_GameState_Play) {
Dqn_V2 screen_size = Dqn_V2_InitNx2(platform->core.window_size.w, platform->core.window_size.h); Dqn_V2 screen_size = Dqn_V2_InitNx2(os->core.window_size.w, os->core.window_size.h);
Dqn_f32 scanline_gap = 4.0f; Dqn_f32 scanline_gap = 4.0f;
Dqn_f32 scanline_thickness = 3.0f; Dqn_f32 scanline_thickness = 3.0f;
FP_GameRenderScanlines(renderer, scanline_gap, scanline_thickness, screen_size); FP_GameRenderScanlines(renderer, scanline_gap, scanline_thickness, screen_size);
@ -3784,7 +3777,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity()); TELY_Render_PushTransform(renderer, Dqn_M2x3_Identity());
DQN_DEFER { TELY_Render_PopTransform(renderer); }; DQN_DEFER { TELY_Render_PopTransform(renderer); };
Dqn_V2I inset = platform->core.window_size * .05f; Dqn_V2I inset = os->core.window_size * .05f;
Dqn_f32 min_inset = DQN_CAST(Dqn_f32)DQN_MIN(inset.x, inset.y); Dqn_f32 min_inset = DQN_CAST(Dqn_f32)DQN_MIN(inset.x, inset.y);
Dqn_V2 draw_p = Dqn_V2_InitNx2(min_inset, min_inset); Dqn_V2 draw_p = Dqn_V2_InitNx2(min_inset, min_inset);
@ -3793,11 +3786,11 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
Dqn_V4 bg_colour = TELY_Colour_V4InitRGBAU32(0x301010FF); // NOTE: Maroon Dqn_V4 bg_colour = TELY_Colour_V4InitRGBAU32(0x301010FF); // NOTE: Maroon
TELY_Render_RectColourV4( TELY_Render_RectColourV4(
renderer, renderer,
Dqn_Rect_InitNx4(0, 0, DQN_CAST(Dqn_f32)platform->core.window_size.x, DQN_CAST(Dqn_f32)platform->core.window_size.y), Dqn_Rect_InitNx4(0, 0, DQN_CAST(Dqn_f32)os->core.window_size.x, DQN_CAST(Dqn_f32)os->core.window_size.y),
TELY_RenderShapeMode_Fill, TELY_RenderShapeMode_Fill,
bg_colour); bg_colour);
Dqn_Rect window_rect = Dqn_Rect_InitNx4(0, 0, DQN_CAST(Dqn_f32)platform->core.window_size.w, DQN_CAST(Dqn_f32)platform->core.window_size.h); Dqn_Rect window_rect = Dqn_Rect_InitNx4(0, 0, DQN_CAST(Dqn_f32)os->core.window_size.w, DQN_CAST(Dqn_f32)os->core.window_size.h);
if (game->play.state == FP_GameState_IntroScreen || game->play.state == FP_GameState_LoseGame) { if (game->play.state == FP_GameState_IntroScreen || game->play.state == FP_GameState_LoseGame) {
Dqn_f32 tex_scalar = 0.f; Dqn_f32 tex_scalar = 0.f;
{ {
@ -3892,7 +3885,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
TELY_COLOUR_WHITE_V4); TELY_COLOUR_WHITE_V4);
} }
TELY_Render_PushFont(renderer, game->inter_regular_font); TELY_Render_PushFontSize(renderer, game->inter_regular_font, game->font_size);
Dqn_f32 t = (DQN_SINF(DQN_CAST(Dqn_f32)input->timer_s * 5.f) + 1.f) / 2.f; Dqn_f32 t = (DQN_SINF(DQN_CAST(Dqn_f32)input->timer_s * 5.f) + 1.f) / 2.f;
TELY_Render_PushColourV4(renderer, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, t)); TELY_Render_PushColourV4(renderer, TELY_Colour_V4Alpha(TELY_COLOUR_WHITE_V4, t));
TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(window_rect, Dqn_V2_InitNx2(0.5f, 0.925f)), Dqn_V2_InitNx1(0.5f), "Press <B> or <Gamepad: Start> to %s", game->play.state == FP_GameState_IntroScreen ? "start" : "restart"); TELY_Render_TextF(renderer, Dqn_Rect_InterpolatedPoint(window_rect, Dqn_V2_InitNx2(0.5f, 0.925f)), Dqn_V2_InitNx1(0.5f), "Press <B> or <Gamepad: Start> to %s", game->play.state == FP_GameState_IntroScreen ? "start" : "restart");
@ -3901,37 +3894,37 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
if (game->play.state == FP_GameState_LoseGame) if (game->play.state == FP_GameState_LoseGame)
FP_PlayReset(game, platform); FP_PlayReset(game, os);
if (FP_ListenForNewPlayer(input, game)) if (FP_ListenForNewPlayer(input, game))
game->play.state = FP_GameState_Play; game->play.state = FP_GameState_Play;
} else if (game->play.state == FP_GameState_Pause) { } else if (game->play.state == FP_GameState_Pause) {
TELY_Render_PushFont(renderer, game->inter_regular_font_large); TELY_Render_PushFontSize(renderer, game->inter_regular_font, game->large_font_size);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Paused"); draw_p.y += TELY_Render_FontHeight(renderer, assets); TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Paused"); draw_p.y += TELY_Render_FontHeight(renderer);
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
TELY_Render_PushFont(renderer, game->inter_regular_font); TELY_Render_PushFontSize(renderer, game->inter_regular_font, game->font_size);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Press enter to resume"); draw_p.y += TELY_Render_FontHeight(renderer, assets); TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Press enter to resume"); draw_p.y += TELY_Render_FontHeight(renderer);
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Return)) if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Return))
game->play.state = FP_GameState_Play; game->play.state = FP_GameState_Play;
} else { } else {
DQN_ASSERT(game->play.state == FP_GameState_WinGame); DQN_ASSERT(game->play.state == FP_GameState_WinGame);
TELY_Render_PushFont(renderer, game->inter_regular_font_large); TELY_Render_PushFontSize(renderer, game->inter_regular_font, game->large_font_size);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Terry has been saved"); draw_p.y += TELY_Render_FontHeight(renderer, assets); TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Terry has been saved"); draw_p.y += TELY_Render_FontHeight(renderer);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "from his terrible calamity"); draw_p.y += TELY_Render_FontHeight(renderer, assets); TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "from his terrible calamity"); draw_p.y += TELY_Render_FontHeight(renderer);
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
TELY_Render_PushFont(renderer, game->inter_regular_font); TELY_Render_PushFontSize(renderer, game->inter_regular_font, game->font_size);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "He lives for yet another day and another love"); draw_p.y += TELY_Render_FontHeight(renderer, assets); TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "He lives for yet another day and another love"); draw_p.y += TELY_Render_FontHeight(renderer);
TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Press enter to restart"); draw_p.y += TELY_Render_FontHeight(renderer, assets); TELY_Render_TextF(renderer, draw_p, Dqn_V2_Zero, "Press enter to restart"); draw_p.y += TELY_Render_FontHeight(renderer);
TELY_Render_PopFont(renderer); TELY_Render_PopFont(renderer);
TELY_Render_PopColourV4(renderer); TELY_Render_PopColourV4(renderer);
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_Return)) if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_Return))
FP_PlayReset(game, platform); FP_PlayReset(game, os);
} }
Dqn_f32 scanline_gap = 4.0f; Dqn_f32 scanline_gap = 4.0f;
@ -3978,7 +3971,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
// NOTE: Debug UI ============================================================================== // NOTE: Debug UI ==============================================================================
if (TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F1)) if (TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F1))
game->play.debug_ui = !game->play.debug_ui; game->play.debug_ui = !game->play.debug_ui;
DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_PUSH
@ -4009,7 +4002,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
info_column.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute; info_column.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute;
info_column.widget->semantic_position[TELY_RFuiAxis_X].value = next_y; info_column.widget->semantic_position[TELY_RFuiAxis_X].value = next_y;
info_column.widget->semantic_position[TELY_RFuiAxis_Y].kind = TELY_RFuiPositionKind_Absolute; info_column.widget->semantic_position[TELY_RFuiAxis_Y].kind = TELY_RFuiPositionKind_Absolute;
info_column.widget->semantic_position[TELY_RFuiAxis_Y].value = platform->core.window_size.h - TELY_Render_FontHeight(renderer, assets); info_column.widget->semantic_position[TELY_RFuiAxis_Y].value = os->core.window_size.h - TELY_Render_FontHeight(renderer);
{ {
TELY_RFuiResult row = TELY_RFui_Row(rfui, DQN_STR8("Info Bar")); TELY_RFuiResult row = TELY_RFui_Row(rfui, DQN_STR8("Info Bar"));
@ -4021,19 +4014,19 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
builder.allocator = scratch.allocator; builder.allocator = scratch.allocator;
Dqn_Str8Builder_AppendF(&builder, "TELY"); Dqn_Str8Builder_AppendF(&builder, "TELY");
if (Dqn_Str8_IsValid(platform->core.os_name)) { if (Dqn_Str8_IsValid(os->core.os_name)) {
Dqn_Str8Builder_AppendF(&builder, " | %.*s", DQN_STR_FMT(platform->core.os_name)); Dqn_Str8Builder_AppendF(&builder, " | %.*s", DQN_STR_FMT(os->core.os_name));
} }
Dqn_Str8Builder_AppendF(&builder, Dqn_Str8Builder_AppendF(&builder,
" | %dx%d %.1fHz | TSC %.1f GHz", " | %dx%d %.1fHz | TSC %.1f GHz",
platform->core.window_size.w, os->core.window_size.w,
platform->core.window_size.h, os->core.window_size.h,
platform->core.display.refresh_rate, os->core.display.refresh_rate,
platform->core.tsc_per_second / 1'000'000'000.0); os->core.tsc_per_second / 1'000'000'000.0);
if (platform->core.ram_mb) if (os->core.ram_mb)
Dqn_Str8Builder_AppendF(&builder, " | RAM %.1fGB", platform->core.ram_mb / 1024.0); Dqn_Str8Builder_AppendF(&builder, " | RAM %.1fGB", os->core.ram_mb / 1024.0);
DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(6272 6271) DQN_MSVC_WARNING_DISABLE(6272 6271)
@ -4059,23 +4052,23 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
if (TELY_RFui_ButtonF(rfui, "F1 Debug info").clicked) if (TELY_RFui_ButtonF(rfui, "F1 Debug info").clicked)
game->play.debug_ui = !game->play.debug_ui; game->play.debug_ui = !game->play.debug_ui;
if (TELY_RFui_ButtonF(rfui, "F2 Add coins x10,000").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F2)) { if (TELY_RFui_ButtonF(rfui, "F2 Add coins x10,000").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F2)) {
for (FP_GameEntityHandle player_handle : game->play.players) { for (FP_GameEntityHandle player_handle : game->play.players) {
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle); FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
player->coins += 10'000; player->coins += 10'000;
} }
} }
if (TELY_RFui_ButtonF(rfui, "F3 Win game").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F3)) if (TELY_RFui_ButtonF(rfui, "F3 Win game").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F3))
game->play.state = FP_GameState_WinGame; game->play.state = FP_GameState_WinGame;
if (TELY_RFui_ButtonF(rfui, "F4 Lose game").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F4)) if (TELY_RFui_ButtonF(rfui, "F4 Lose game").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F4))
game->play.state = FP_GameState_LoseGame; game->play.state = FP_GameState_LoseGame;
if (TELY_RFui_ButtonF(rfui, "F5 Reset game").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F5)) if (TELY_RFui_ButtonF(rfui, "F5 Reset game").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F5))
FP_PlayReset(game, platform); FP_PlayReset(game, os);
if (TELY_RFui_ButtonF(rfui, "F6 Increase health").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F6)) { if (TELY_RFui_ButtonF(rfui, "F6 Increase health").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F6)) {
for (FP_GameEntityHandle player_handle : game->play.players) { for (FP_GameEntityHandle player_handle : game->play.players) {
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle); FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
player->hp_cap += FP_DEFAULT_DAMAGE; player->hp_cap += FP_DEFAULT_DAMAGE;
@ -4083,7 +4076,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
} }
if (TELY_RFui_ButtonF(rfui, "F7 Increase stamina").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F7)) { if (TELY_RFui_ButtonF(rfui, "F7 Increase stamina").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F7)) {
for (FP_GameEntityHandle player_handle : game->play.players) { for (FP_GameEntityHandle player_handle : game->play.players) {
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle); FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
player->stamina_cap += DQN_CAST(uint16_t)(FP_TERRY_DASH_STAMINA_COST * .5f); player->stamina_cap += DQN_CAST(uint16_t)(FP_TERRY_DASH_STAMINA_COST * .5f);
@ -4091,7 +4084,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
} }
if (TELY_RFui_ButtonF(rfui, "F8 Increase mobile data").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F8)) { if (TELY_RFui_ButtonF(rfui, "F8 Increase mobile data").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F8)) {
for (FP_GameEntityHandle player_handle : game->play.players) { for (FP_GameEntityHandle player_handle : game->play.players) {
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle); FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
player->terry_mobile_data_plan_cap += DQN_KILOBYTES(1); player->terry_mobile_data_plan_cap += DQN_KILOBYTES(1);
@ -4099,10 +4092,10 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
} }
if (TELY_RFui_ButtonF(rfui, "F9 %s god mode", game->play.god_mode ? "Disable" : "Enable").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F9)) if (TELY_RFui_ButtonF(rfui, "F9 %s god mode", game->play.god_mode ? "Disable" : "Enable").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F9))
game->play.god_mode = !game->play.god_mode; game->play.god_mode = !game->play.god_mode;
if (TELY_RFui_ButtonF(rfui, "F11 Building inventory +1").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_F11)) { if (TELY_RFui_ButtonF(rfui, "F11 Building inventory +1").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_F11)) {
for (FP_GameEntityHandle player_handle : game->play.players) { for (FP_GameEntityHandle player_handle : game->play.players) {
FP_GameEntity *player = FP_Game_GetEntity(game, player_handle); FP_GameEntity *player = FP_Game_GetEntity(game, player_handle);
player->inventory.clubs += 1; player->inventory.clubs += 1;
@ -4112,7 +4105,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
} }
if (TELY_RFui_ButtonF(rfui, "1 %s HUD", game->play.debug_hide_hud ? "Show" : "Hide").clicked || TELY_Platform_InputScanCodeIsPressed(input, TELY_PlatformInputScanCode_1)) if (TELY_RFui_ButtonF(rfui, "1 %s HUD", game->play.debug_hide_hud ? "Show" : "Hide").clicked || TELY_OSInput_ScanKeyIsPressed(input, TELY_OSInputScanKey_1))
game->play.debug_hide_hud = !game->play.debug_hide_hud; game->play.debug_hide_hud = !game->play.debug_hide_hud;
if (TELY_RFui_ButtonF(rfui, "%s bounding rects", game->play.debug_hide_bounding_rectangles ? "Show" : "Hide").clicked) if (TELY_RFui_ButtonF(rfui, "%s bounding rects", game->play.debug_hide_bounding_rectangles ? "Show" : "Hide").clicked)
@ -4123,7 +4116,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
if (0) { if (0) {
next_y += TELY_Asset_GetFont(assets, TELY_RFui_ActiveFont(rfui))->pixel_height; next_y += TELY_RFui_ActiveFont(rfui).size;
TELY_RFuiResult bar = TELY_RFui_Column(rfui, DQN_STR8("Memory bar")); TELY_RFuiResult bar = TELY_RFui_Column(rfui, DQN_STR8("Memory bar"));
bar.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute; bar.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute;
bar.widget->semantic_position[TELY_RFuiAxis_X].value = 10.f; bar.widget->semantic_position[TELY_RFuiAxis_X].value = 10.f;
@ -4134,23 +4127,23 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
DQN_DEFER { TELY_RFui_PopParent(rfui); }; DQN_DEFER { TELY_RFui_PopParent(rfui); };
{ {
Dqn_ArenaInfo arena_info = Dqn_Arena_Info(&platform->arena); Dqn_ArenaInfo arena_info = Dqn_Arena_Info(&os->arena);
DQN_MSVC_WARNING_PUSH DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(6271) // warning C6271: Extra argument passed to 'TELY_RFui_TextF'. DQN_MSVC_WARNING_DISABLE(6271) // warning C6271: Extra argument passed to 'TELY_RFui_TextF'.
TELY_RFui_TextF(rfui, TELY_RFui_TextF(rfui,
"Platform Arena[%I64u]: %_$$d/%_$$d (HWM %_$$d, COMMIT %_$$d)", "Platform Arena[%I64u]: %_$$d/%_$$d (HWM %_$$d, COMMIT %_$$d)",
platform->arena.blocks, os->arena.blocks,
arena_info.used, arena_info.used,
arena_info.capacity, arena_info.capacity,
arena_info.used_hwm, arena_info.used_hwm,
arena_info.commit); arena_info.commit);
DQN_MSVC_WARNING_POP DQN_MSVC_WARNING_POP
next_y += TELY_Asset_GetFont(assets, TELY_RFui_ActiveFont(rfui))->pixel_height; next_y += TELY_RFui_ActiveFont(rfui).size;
} }
for (Dqn_ArenaCatalogItem *item = g_dqn_library->arena_catalog.sentinel.next; item != &g_dqn_library->arena_catalog.sentinel; item = item->next) { for (Dqn_ArenaCatalogItem *item = g_dqn_library->arena_catalog.sentinel.next; item != &g_dqn_library->arena_catalog.sentinel; item = item->next) {
if (item != g_dqn_library->arena_catalog.sentinel.next) if (item != g_dqn_library->arena_catalog.sentinel.next)
next_y += TELY_Asset_GetFont(assets, TELY_RFui_ActiveFont(rfui))->pixel_height; next_y += TELY_RFui_ActiveFont(rfui).size;
Dqn_Arena *arena = item->arena; Dqn_Arena *arena = item->arena;
Dqn_ArenaInfo arena_info = Dqn_Arena_Info(arena); Dqn_ArenaInfo arena_info = Dqn_Arena_Info(arena);
@ -4170,7 +4163,7 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
// NOTE: Profiler // NOTE: Profiler
if (0) { if (0) {
next_y += TELY_Asset_GetFont(assets, TELY_RFui_ActiveFont(rfui))->pixel_height; next_y += TELY_RFui_ActiveFont(rfui).size;
TELY_RFuiResult profiler_layout = TELY_RFui_Column(rfui, DQN_STR8("Profiler Bar")); TELY_RFuiResult profiler_layout = TELY_RFui_Column(rfui, DQN_STR8("Profiler Bar"));
profiler_layout.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute; profiler_layout.widget->semantic_position[TELY_RFuiAxis_X].kind = TELY_RFuiPositionKind_Absolute;
profiler_layout.widget->semantic_position[TELY_RFuiAxis_X].value = 10.f; profiler_layout.widget->semantic_position[TELY_RFuiAxis_X].value = 10.f;
@ -4181,9 +4174,9 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
DQN_DEFER { TELY_RFui_PopParent(rfui); }; DQN_DEFER { TELY_RFui_PopParent(rfui); };
// TODO(doyle): On emscripten we need to use Dqn_OS_PerfCounterNow() however those // TODO(doyle): On emscripten we need to use Dqn_OS_PerfCounterNow() however those
// require OS functions which need to be exposed into the platform layer. // require OS functions which need to be exposed into the os layer.
#if 0 #if 0
Dqn_f64 const tsc_frequency = DQN_CAST(Dqn_f64)TELY_Platform_PerfCounterFrequency(&platform->core); Dqn_f64 const tsc_frequency = DQN_CAST(Dqn_f64)TELY_OS_PerfCounterFrequency(&os->core);
Dqn_ProfilerAnchor *anchors = Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer_Back); Dqn_ProfilerAnchor *anchors = Dqn_Profiler_AnchorBuffer(Dqn_ProfilerAnchorBuffer_Back);
for (size_t anchor_index = 1; anchor_index < DQN_PROFILER_ANCHOR_BUFFER_SIZE; anchor_index++) { for (size_t anchor_index = 1; anchor_index < DQN_PROFILER_ANCHOR_BUFFER_SIZE; anchor_index++) {
Dqn_ProfilerAnchor const *anchor = anchors + anchor_index; Dqn_ProfilerAnchor const *anchor = anchors + anchor_index;
@ -4216,14 +4209,13 @@ static void FP_Render(FP_Game *game, TELY_Platform *platform, TELY_Renderer *ren
} }
} }
FP_DLL_FUNCTION TELY_OS_DLL_FUNCTION
void TELY_DLL_FrameUpdate(void *user_data) void TELY_OS_DLLFrameUpdate(TELY_OS *os)
{ {
TELY_Platform *platform = DQN_CAST(TELY_Platform *) user_data; TELY_OSInput *input = &os->input;
TELY_PlatformInput *input = &platform->input; TELY_Assets *assets = &os->assets;
TELY_Assets *assets = &platform->assets; TELY_Renderer *renderer = &os->renderer;
TELY_Renderer *renderer = &platform->renderer; FP_Game *game = DQN_CAST(FP_Game *) os->user_data;
FP_Game *game = DQN_CAST(FP_Game *) platform->user_data;
// ============================================================================================= // =============================================================================================
@ -4237,7 +4229,7 @@ void TELY_DLL_FrameUpdate(void *user_data)
// ============================================================================================= // =============================================================================================
TELY_Audio *audio = &platform->audio; TELY_Audio *audio = &os->audio;
#if 0 #if 0
if (audio->playback_size == 0) { if (audio->playback_size == 0) {
@ -4248,7 +4240,7 @@ void TELY_DLL_FrameUpdate(void *user_data)
// ============================================================================================= // =============================================================================================
if (game->play.state == FP_GameState_Play) { if (game->play.state == FP_GameState_Play) {
if (TELY_Platform_InputKeyWasDown(input->mouse_left) && TELY_Platform_InputKeyIsDown(input->mouse_left)) { if (TELY_OSInput_KeyWasDown(input->mouse_left) && TELY_OSInput_KeyIsDown(input->mouse_left)) {
if (game->play.prev_active_entity.id) if (game->play.prev_active_entity.id)
game->play.active_entity = game->play.prev_active_entity; game->play.active_entity = game->play.prev_active_entity;
} else { } else {
@ -4268,7 +4260,7 @@ void TELY_DLL_FrameUpdate(void *user_data)
continue; continue;
game->play.hot_entity = entity->handle; game->play.hot_entity = entity->handle;
if (TELY_Platform_InputKeyIsPressed(input->mouse_left)) { if (TELY_OSInput_KeyIsPressed(input->mouse_left)) {
game->play.active_entity = entity->handle; game->play.active_entity = entity->handle;
game->play.clicked_entity = entity->handle; game->play.clicked_entity = entity->handle;
} }
@ -4279,10 +4271,10 @@ void TELY_DLL_FrameUpdate(void *user_data)
for (game->play.delta_s_accumulator += DQN_CAST(Dqn_f32)input->delta_s; for (game->play.delta_s_accumulator += DQN_CAST(Dqn_f32)input->delta_s;
game->play.delta_s_accumulator > FP_GAME_PHYSICS_STEP; game->play.delta_s_accumulator > FP_GAME_PHYSICS_STEP;
game->play.delta_s_accumulator -= FP_GAME_PHYSICS_STEP) { game->play.delta_s_accumulator -= FP_GAME_PHYSICS_STEP) {
FP_Update(platform, game, input, audio); FP_Update(os, game, input, audio);
} }
FP_Render(game, platform, renderer, audio); FP_Render(game, os, renderer, audio);
TELY_Audio_MixPlaybackSamples(audio, assets); TELY_Audio_MixPlaybackSamples(audio, assets);
} }

View File

@ -97,7 +97,7 @@ int main(int argc, char const **argv)
dry_run = true; dry_run = true;
} else if (arg == DQN_STR8("--web")) { } else if (arg == DQN_STR8("--web")) {
target_web = true; target_web = true;
} else if (arg == DQN_STR8("--dev-fast-build")) { } else if (arg == DQN_STR8("--fast-dev-build")) {
dev_fast_build = true; dev_fast_build = true;
} else { } else {
PRINT_HELP; PRINT_HELP;
@ -302,14 +302,21 @@ int main(int argc, char const **argv)
DQN_DEFER { feely_pona_no_dll_timings[1] = Dqn_OS_PerfCounterNow(); }; DQN_DEFER { feely_pona_no_dll_timings[1] = Dqn_OS_PerfCounterNow(); };
Dqn_CPPBuildCompileFile build_file = {}; Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity_nodll.h", DQN_STR_FMT(code_dir)); build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.h", DQN_STR_FMT(code_dir));
build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "terry_cherry");
build_file.flags = Dqn_Slice_InitCArrayCopy(scratch.arena, {DQN_STR8("/Tp")}); build_file.flags = Dqn_Slice_InitCArrayCopy(scratch.arena, {DQN_STR8("/Tp")});
Dqn_List<Dqn_Str8> compile_flags = Dqn_List_InitSliceCopy(scratch.arena, 16, common_compile_flags);
Dqn_List_AddCArray(&compile_flags, {
DQN_STR8("/D TELY_WITH_PLATFORM"),
DQN_STR8("/D FEELY_PONA_IMPLEMENTATION"),
});
Dqn_CPPBuildContext feely_pona_no_dll_build_context = {}; Dqn_CPPBuildContext feely_pona_no_dll_build_context = {};
feely_pona_no_dll_build_context.compiler = Dqn_CPPBuildCompiler_MSVC; feely_pona_no_dll_build_context.compiler = Dqn_CPPBuildCompiler_MSVC;
feely_pona_no_dll_build_context.compile_files = Dqn_Slice_InitCArrayCopy(scratch.arena, {build_file}); feely_pona_no_dll_build_context.compile_files = Dqn_Slice_InitCArrayCopy(scratch.arena, {build_file});
feely_pona_no_dll_build_context.include_dirs = Dqn_Slice_InitCArrayCopy(scratch.arena, {raylib_dir}); feely_pona_no_dll_build_context.include_dirs = Dqn_Slice_InitCArrayCopy(scratch.arena, {raylib_dir});
feely_pona_no_dll_build_context.compile_flags = common_compile_flags; feely_pona_no_dll_build_context.compile_flags = Dqn_List_ToSliceCopy(&compile_flags, scratch.arena);
feely_pona_no_dll_build_context.build_dir = build_dir; feely_pona_no_dll_build_context.build_dir = build_dir;
feely_pona_no_dll_build_context.link_flags = feely_pona_platform_link_flags; feely_pona_no_dll_build_context.link_flags = feely_pona_platform_link_flags;
@ -329,12 +336,14 @@ int main(int argc, char const **argv)
Dqn_CPPBuildCompileFile build_file = {}; Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.h", DQN_STR_FMT(code_dir)); build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.h", DQN_STR_FMT(code_dir));
build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "tely_dll_msvc", DQN_STR_FMT(code_dir)); build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "terry_cherry_dev_dll");
build_file.flags = Dqn_Slice_InitCArrayCopy(scratch.arena, {DQN_STR8("/Tp")}); build_file.flags = Dqn_Slice_InitCArrayCopy(scratch.arena, {DQN_STR8("/Tp")});
Dqn_List<Dqn_Str8> compile_flags = Dqn_List_InitSliceCopy(scratch.arena, 128, common_compile_flags); Dqn_List<Dqn_Str8> compile_flags = Dqn_List_InitSliceCopy(scratch.arena, 16, common_compile_flags);
Dqn_List_Add(&compile_flags, DQN_STR8("/LD")); Dqn_List_AddCArray(&compile_flags, {
Dqn_List_Add(&compile_flags, DQN_STR8("/Fetely_dll_msvc")); DQN_STR8("/LD"),
DQN_STR8("/D FEELY_PONA_IMPLEMENTATION"),
});
if (!dev_fast_build) if (!dev_fast_build)
Dqn_List_Add(&compile_flags, DQN_STR8("/analyze")); Dqn_List_Add(&compile_flags, DQN_STR8("/analyze"));
@ -361,12 +370,15 @@ int main(int argc, char const **argv)
DQN_DEFER { feely_pona_platform_timings[1] = Dqn_OS_PerfCounterNow(); }; DQN_DEFER { feely_pona_platform_timings[1] = Dqn_OS_PerfCounterNow(); };
Dqn_CPPBuildCompileFile build_file = {}; Dqn_CPPBuildCompileFile build_file = {};
build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/tely_platform_raylib_unity.h", DQN_STR_FMT(tely_dir)); build_file.input_file_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.h", DQN_STR_FMT(code_dir));
build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "feely_pona_msvc", DQN_STR_FMT(code_dir)); build_file.output_file_path = Dqn_FsPath_ConvertF(scratch.arena, "terry_cherry_dev", DQN_STR_FMT(code_dir));
build_file.flags = Dqn_Slice_InitCArrayCopy(scratch.arena, {DQN_STR8("/Tp")}); build_file.flags = Dqn_Slice_InitCArrayCopy(scratch.arena, {DQN_STR8("/Tp")});
Dqn_List<Dqn_Str8> compile_flags = Dqn_List_InitSliceCopy(scratch.arena, 128, common_compile_flags); Dqn_List<Dqn_Str8> compile_flags = Dqn_List_InitSliceCopy(scratch.arena, 128, common_compile_flags);
Dqn_List_Add(&compile_flags, DQN_STR8("/Fefeely_pona_msvc")); Dqn_List_AddCArray(&compile_flags, {
DQN_STR8("/D TELY_WITH_PLATFORM"),
DQN_STR8("/D TELY_WITH_PLATFORM_DLL"),
});
Dqn_CPPBuildContext build_context = {}; Dqn_CPPBuildContext build_context = {};
build_context.compiler = Dqn_CPPBuildCompiler_MSVC; build_context.compiler = Dqn_CPPBuildCompiler_MSVC;
@ -380,7 +392,7 @@ int main(int argc, char const **argv)
Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLine(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.allocator); Dqn_Str8 cmd = Dqn_CPPBuild_ToCommandLine(build_context, Dqn_CPPBuildMode_AlwaysRebuild, scratch.allocator);
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "%.*s\n", DQN_STR_FMT(cmd)); Dqn_Print_StdLnF(Dqn_PrintStd_Out, "%.*s\n", DQN_STR_FMT(cmd));
} else { } else {
Dqn_Str8 exe_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_msvc.exe", DQN_STR_FMT(build_dir)); Dqn_Str8 exe_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/terry_cherry_dev_msvc.exe", DQN_STR_FMT(build_dir));
bool exe_is_locked = false; bool exe_is_locked = false;
if (Dqn_Fs_Exists(exe_path)) { if (Dqn_Fs_Exists(exe_path)) {
Dqn_FsFile exe_file = Dqn_Fs_OpenFile(exe_path, Dqn_FsFileOpen_OpenIfExist, Dqn_FsFileAccess_Read | Dqn_FsFileAccess_Write); Dqn_FsFile exe_file = Dqn_Fs_OpenFile(exe_path, Dqn_FsFileOpen_OpenIfExist, Dqn_FsFileAccess_Read | Dqn_FsFileAccess_Write);
@ -528,10 +540,10 @@ int main(int argc, char const **argv)
Dqn_CPPBuildContext build_context = {}; Dqn_CPPBuildContext build_context = {};
build_context.compile_file_obj_suffix = DQN_CPP_BUILD_OBJ_SUFFIX_O; build_context.compile_file_obj_suffix = DQN_CPP_BUILD_OBJ_SUFFIX_O;
build_context.compile_files = Dqn_Slice_InitCArrayCopy(scratch.arena, { build_context.compile_files = Dqn_Slice_InitCArrayCopy(scratch.arena, {
Dqn_CPPBuildCompileFile{{}, Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity_nodll.cpp", DQN_STR_FMT(code_dir)) }, Dqn_CPPBuildCompileFile{{}, Dqn_FsPath_ConvertF(scratch.arena, "%.*s/feely_pona_unity.cpp", DQN_STR_FMT(code_dir)) },
}); });
Dqn_Str8 output_name = DQN_STR8("Terry_Cherry"); Dqn_Str8 output_name = DQN_STR8("Terry_Cherry_Emscripten");
Dqn_List<Dqn_Str8> compile_flags = Dqn_List_InitCArrayCopy(scratch.arena, 32, { Dqn_List<Dqn_Str8> compile_flags = Dqn_List_InitCArrayCopy(scratch.arena, 32, {
DQN_STR8("cmd"), DQN_STR8("/C"), DQN_STR8("emcc.bat"), DQN_STR8("cmd"), DQN_STR8("/C"), DQN_STR8("emcc.bat"),
DQN_STR8("-o"), Dqn_Str8_InitF(scratch.allocator, "%.*s.html", DQN_STR_FMT(output_name)), DQN_STR8("-o"), Dqn_Str8_InitF(scratch.allocator, "%.*s.html", DQN_STR_FMT(output_name)),
@ -545,6 +557,8 @@ int main(int argc, char const **argv)
DQN_STR8("--preload-file"), DQN_STR8("Data"), DQN_STR8("--preload-file"), DQN_STR8("Data"),
DQN_STR8("-msimd128"), DQN_STR8("-msimd128"),
DQN_STR8("-msse2"), DQN_STR8("-msse2"),
DQN_STR8("-D"), DQN_STR8("TELY_WITH_PLATFORM"),
DQN_STR8("-D"), DQN_STR8("FEELY_PONA_IMPLEMENTATION"),
}); });
Dqn_List_AddList(&compile_flags, build_specific_compile_flags); Dqn_List_AddList(&compile_flags, build_specific_compile_flags);
@ -559,7 +573,7 @@ int main(int argc, char const **argv)
} }
// NOTE: Move the files to a directory // NOTE: Move the files to a directory
Dqn_Str8 folder_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s_Emscripten", DQN_STR_FMT(build_dir), DQN_STR_FMT(output_name)); Dqn_Str8 folder_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STR_FMT(build_dir), DQN_STR_FMT(output_name));
if (!Dqn_Fs_DirExists(folder_path)) { if (!Dqn_Fs_DirExists(folder_path)) {
Dqn_Str8 mkdir_cmd = Dqn_Str8_InitF(scratch.allocator, "mkdir %.*s", DQN_STR_FMT(folder_path)); Dqn_Str8 mkdir_cmd = Dqn_Str8_InitF(scratch.allocator, "mkdir %.*s", DQN_STR_FMT(folder_path));
Dqn_OS_ExecOrAbort(mkdir_cmd, {}); Dqn_OS_ExecOrAbort(mkdir_cmd, {});
@ -574,7 +588,7 @@ int main(int argc, char const **argv)
for (Dqn_Str8 file_ext : generated_file_extension) { for (Dqn_Str8 file_ext : generated_file_extension) {
Dqn_Str8 src_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.%.*s", DQN_STR_FMT(build_dir), DQN_STR_FMT(output_name), DQN_STR_FMT(file_ext)); Dqn_Str8 src_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.%.*s", DQN_STR_FMT(build_dir), DQN_STR_FMT(output_name), DQN_STR_FMT(file_ext));
Dqn_Str8 dest_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s.%.*s", DQN_STR_FMT(folder_path), DQN_STR_FMT(output_name), DQN_STR_FMT(file_ext)); Dqn_Str8 dest_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/Terry_Cherry.%.*s", DQN_STR_FMT(folder_path), DQN_STR_FMT(file_ext));
Dqn_Str8 cmd = Dqn_Str8_InitF(scratch.allocator, "cmd /C move /Y %.*s %.*s", DQN_STR_FMT(src_path), DQN_STR_FMT(dest_path)); Dqn_Str8 cmd = Dqn_Str8_InitF(scratch.allocator, "cmd /C move /Y %.*s %.*s", DQN_STR_FMT(src_path), DQN_STR_FMT(dest_path));
if (dry_run) { if (dry_run) {
Dqn_Print_StdLnF(Dqn_PrintStd_Out, "%.*s\n", DQN_STR_FMT(cmd)); Dqn_Print_StdLnF(Dqn_PrintStd_Out, "%.*s\n", DQN_STR_FMT(cmd));

View File

@ -3,24 +3,24 @@
#include "feely_pona_unity.h" #include "feely_pona_unity.h"
#endif #endif
static bool FP_Game_KeyBindIsPressed(TELY_PlatformInput const *input, FP_GameControls const *controls, FP_GameKeyBind key_bind) static bool FP_Game_KeyBindIsPressed(TELY_OSInput const *input, FP_GameControls const *controls, FP_GameKeyBind key_bind)
{ {
bool result = false; bool result = false;
if (controls->mode == FP_GameControlMode_Keyboard) { if (controls->mode == FP_GameControlMode_Keyboard) {
result = TELY_Platform_InputScanCodeIsPressed(input, key_bind.scan_code); result = TELY_OSInput_ScanKeyIsPressed(input, key_bind.scan_key);
} else { } else {
result = TELY_Platform_InputGamepadKeyIsPressed(input, controls->gamepad_index, key_bind.gamepad_key); result = TELY_OSInput_GamepadKeyIsPressed(input, controls->gamepad_index, key_bind.gamepad_key);
} }
return result; return result;
} }
static bool FP_Game_KeyBindIsDown(TELY_PlatformInput const *input, FP_GameControls const *controls, FP_GameKeyBind key_bind) static bool FP_Game_KeyBindIsDown(TELY_OSInput const *input, FP_GameControls const *controls, FP_GameKeyBind key_bind)
{ {
bool result = false; bool result = false;
if (controls->mode == FP_GameControlMode_Keyboard) { if (controls->mode == FP_GameControlMode_Keyboard) {
result = TELY_Platform_InputScanCodeIsDown(input, key_bind.scan_code); result = TELY_OSInput_ScanKeyIsDown(input, key_bind.scan_key);
} else { } else {
result = TELY_Platform_InputGamepadKeyIsDown(input, controls->gamepad_index, key_bind.gamepad_key); result = TELY_OSInput_GamepadKeyIsDown(input, controls->gamepad_index, key_bind.gamepad_key);
} }
return result; return result;
} }

View File

@ -168,8 +168,8 @@ enum FP_GameInGameMenu
struct FP_GameKeyBind struct FP_GameKeyBind
{ {
TELY_PlatformInputScanCode scan_code; TELY_OSInputScanKey scan_key;
TELY_PlatformInputGamepadKey gamepad_key; TELY_OSInputGamepadKey gamepad_key;
}; };
enum FP_GameControlMode enum FP_GameControlMode
@ -433,18 +433,20 @@ struct FP_GamePlay
struct FP_Game struct FP_Game
{ {
TELY_AssetFontHandle inter_regular_font_large;
TELY_AssetFontHandle inter_regular_font; TELY_AssetFontHandle inter_regular_font;
TELY_AssetFontHandle inter_italic_font; TELY_AssetFontHandle inter_italic_font;
TELY_AssetFontHandle jetbrains_mono_font; TELY_AssetFontHandle jetbrains_mono_font;
TELY_AssetFontHandle talkco_font; TELY_AssetFontHandle talkco_font;
TELY_AssetFontHandle talkco_font_large;
TELY_AssetFontHandle talkco_font_xlarge;
TELY_AssetAudioHandle audio[FP_GameAudio_Count]; TELY_AssetAudioHandle audio[FP_GameAudio_Count];
TELY_AssetSpriteSheet atlas_sprite_sheet; TELY_AssetSpriteSheet atlas_sprite_sheet;
TELY_RFui rfui; TELY_RFui rfui;
FP_GamePlay play; FP_GamePlay play;
Dqn_Arena *frame_arena; Dqn_Arena *frame_arena;
uint16_t font_size;
uint16_t large_font_size;
uint16_t large_talkco_font_size;
uint16_t xlarge_talkco_font_size;
}; };
struct FP_GameAStarNode struct FP_GameAStarNode

View File

@ -3,7 +3,7 @@
#include "feely_pona_unity.h" #include "feely_pona_unity.h"
#endif #endif
void FP_UnitTests(TELY_Platform *platform) void FP_UnitTests(TELY_OS *os)
{ {
{ {
uint32_t array[] = {1}; uint32_t array[] = {1};
@ -318,9 +318,9 @@ void FP_UnitTests(TELY_Platform *platform)
} }
{ {
Dqn_Arena_TempMemoryScope(&platform->arena); Dqn_Arena_TempMemoryScope(&os->arena);
TELY_ChunkPool pool = {}; TELY_ChunkPool pool = {};
pool.arena = &platform->arena; pool.arena = &os->arena;
void *bytes16 = TELY_ChunkPool_Alloc(&pool, 16); void *bytes16 = TELY_ChunkPool_Alloc(&pool, 16);
TELY_ChunkPool_Dealloc(&pool, bytes16); TELY_ChunkPool_Dealloc(&pool, bytes16);
@ -346,13 +346,13 @@ void FP_UnitTests(TELY_Platform *platform)
} }
// NOTE: Unit test DFS pre-order and post-order walk // NOTE: Unit test DFS pre-order and post-order walk
Dqn_Arena_TempMemoryScope(&platform->arena); Dqn_Arena_TempMemoryScope(&os->arena);
TELY_ChunkPool chunk_pool = {}; TELY_ChunkPool chunk_pool = {};
chunk_pool.arena = &platform->arena; chunk_pool.arena = &os->arena;
FP_Game *game = Dqn_Arena_New(&platform->arena, FP_Game, Dqn_ZeroMem_Yes); FP_Game *game = Dqn_Arena_New(&os->arena, FP_Game, Dqn_ZeroMem_Yes);
game->play.chunk_pool = &chunk_pool; game->play.chunk_pool = &chunk_pool;
game->play.entities = Dqn_VArray_Init<FP_GameEntity>(&platform->arena, 1024 * 8); game->play.entities = Dqn_VArray_Init<FP_GameEntity>(&os->arena, 1024 * 8);
game->play.root_entity = Dqn_VArray_Make(&game->play.entities, Dqn_ZeroMem_No); game->play.root_entity = Dqn_VArray_Make(&game->play.entities, Dqn_ZeroMem_No);
Dqn_FArray_Add(&game->play.parent_entity_stack, game->play.root_entity->handle); Dqn_FArray_Add(&game->play.parent_entity_stack, game->play.root_entity->handle);

View File

@ -37,17 +37,17 @@ struct SpriteSpecification
uint16_t frames_per_second; uint16_t frames_per_second;
}; };
static Dqn_String8 SpriteAnimNameFromFilePath(Dqn_String8 path) static Dqn_Str8 SpriteAnimNameFromFilePath(Dqn_Str8 path)
{ {
// NOTE: Enumerate the number of frames for this animation ================================= // NOTE: Enumerate the number of frames for this animation =================================
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(path); Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(path);
Dqn_String8 file_name_without_extension = Dqn_String8_BinarySplit(file_name, DQN_STRING8(".")).lhs; Dqn_Str8 file_name_without_extension = Dqn_Str8_BinarySplit(file_name, DQN_STR8(".")).lhs;
// NOTE: If the sprite is a standalone sprite without any frame suffix (e.g. "_1.png") then // NOTE: If the sprite is a standalone sprite without any frame suffix (e.g. "_1.png") then
// we accept the entry as the name of the sprite as is. // we accept the entry as the name of the sprite as is.
Dqn_String8 result = {}; Dqn_Str8 result = {};
if (Dqn_Char_IsDigit(file_name_without_extension.data[file_name_without_extension.size - 1])) { if (Dqn_Char_IsDigit(file_name_without_extension.data[file_name_without_extension.size - 1])) {
Dqn_String8BinarySplitResult split = Dqn_String8_BinarySplitReverse(file_name_without_extension, DQN_STRING8("_")); Dqn_Str8BinarySplitResult split = Dqn_Str8_BinarySplitReverse(file_name_without_extension, DQN_STR8("_"));
result = split.lhs; result = split.lhs;
} else { } else {
result = file_name_without_extension; result = file_name_without_extension;
@ -67,26 +67,26 @@ int main(int argc, char const *argv[])
} }
// NOTE: Verify some arguments ================================================================= // NOTE: Verify some arguments =================================================================
Dqn_String8 atlas_dimensions = Dqn_String8_InitCString8(argv[1]); Dqn_Str8 atlas_dimensions = Dqn_Str8_InitCStr8(argv[1]);
Dqn_String8 sprite_spec_path = Dqn_String8_InitCString8(argv[2]); Dqn_Str8 sprite_spec_path = Dqn_Str8_InitCStr8(argv[2]);
Dqn_String8 dir = Dqn_String8_InitCString8(argv[3]); Dqn_Str8 dir = Dqn_Str8_InitCStr8(argv[3]);
if (!Dqn_Fs_Exists(sprite_spec_path)) { 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)); Dqn_Log_ErrorF("Sprite specification file does not exist, we tried to find \"%.*s\" but it does not exist", DQN_STR_FMT(sprite_spec_path));
return -1; return -1;
} }
if (!Dqn_Fs_DirExists(dir)) { if (!Dqn_Fs_DirExists(dir)) {
Dqn_Log_ErrorF("Directory to load sprites from does not exist, we tried to find \"%.*s\" but it does not exist", DQN_STRING_FMT(dir)); Dqn_Log_ErrorF("Directory to load sprites from does not exist, we tried to find \"%.*s\" but it does not exist", DQN_STR_FMT(dir));
return -1; return -1;
} }
// NOTE: Parse the atlas size ================================================================== // NOTE: Parse the atlas size ==================================================================
Dqn_V2I atlas_size = {}; Dqn_V2I atlas_size = {};
{ {
Dqn_String8BinarySplitResult atlas_dimensions_split = Dqn_String8_BinarySplit(atlas_dimensions, DQN_STRING8("x")); Dqn_Str8BinarySplitResult atlas_dimensions_split = Dqn_Str8_BinarySplit(atlas_dimensions, DQN_STR8("x"));
Dqn_String8ToU64Result width = Dqn_String8_ToU64(atlas_dimensions_split.lhs, 0); Dqn_Str8ToU64Result width = Dqn_Str8_ToU64(atlas_dimensions_split.lhs, 0);
Dqn_String8ToU64Result height = Dqn_String8_ToU64(atlas_dimensions_split.rhs, 0); Dqn_Str8ToU64Result height = Dqn_Str8_ToU64(atlas_dimensions_split.rhs, 0);
if (!width.success || width.value == 0) { if (!width.success || width.value == 0) {
Dqn_Log_ErrorF("Width for the sprite atlas was not a number > 0"); Dqn_Log_ErrorF("Width for the sprite atlas was not a number > 0");
@ -106,51 +106,51 @@ int main(int argc, char const *argv[])
Dqn_DSMap<SpriteSpecification> sprite_spec_table = Dqn_DSMap_Init<SpriteSpecification>(1024); Dqn_DSMap<SpriteSpecification> sprite_spec_table = Dqn_DSMap_Init<SpriteSpecification>(1024);
{ {
Dqn_ThreadScratch inner_scratch = Dqn_Thread_GetScratch(scratch.arena); Dqn_ThreadScratch inner_scratch = Dqn_Thread_GetScratch(scratch.arena);
Dqn_String8 sprite_spec_buffer = Dqn_Fs_Read(sprite_spec_path, inner_scratch.allocator); Dqn_Str8 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_Str8SplitAllocResult sprite_spec_lines = Dqn_Str8_SplitAlloc(inner_scratch.allocator, sprite_spec_buffer, DQN_STR8("\n"));
DQN_FOR_UINDEX(line_index, sprite_spec_lines.size) { DQN_FOR_UINDEX(line_index, sprite_spec_lines.size) {
Dqn_String8 line = Dqn_String8_TrimWhitespaceAround(sprite_spec_lines.data[line_index]); Dqn_Str8 line = Dqn_Str8_TrimWhitespaceAround(sprite_spec_lines.data[line_index]);
if (line.size == 0) // NOTE: Support empty lines, just ignore them if (line.size == 0) // NOTE: Support empty lines, just ignore them
continue; continue;
Dqn_String8SplitAllocResult line_parts = Dqn_String8_SplitAlloc(inner_scratch.allocator, line, DQN_STRING8(";")); Dqn_Str8SplitAllocResult line_parts = Dqn_Str8_SplitAlloc(inner_scratch.allocator, line, DQN_STR8(";"));
DQN_ASSERTF(line_parts.size == 2, "Line must have 2 parts in the sprite specification\n" DQN_ASSERTF(line_parts.size == 2, "Line must have 2 parts in the sprite specification\n"
"\n" "\n"
"<animation name>;<frames per second>\\n\n" "<animation name>;<frames per second>\\n\n"
"\n" "\n"
"Line was '%.*s' loaded from '%.*s'", DQN_STRING_FMT(line), DQN_STRING_FMT(sprite_spec_path)); "Line was '%.*s' loaded from '%.*s'", DQN_STR_FMT(line), DQN_STR_FMT(sprite_spec_path));
Dqn_String8 anim_name = line_parts.data[0]; Dqn_Str8 anim_name = line_parts.data[0];
Dqn_String8ToU64Result frames_per_second = Dqn_String8_ToU64(line_parts.data[1], 0); Dqn_Str8ToU64Result frames_per_second = Dqn_Str8_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_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); Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_MakeKeyStr8Copy(&sprite_spec_table, scratch.allocator, anim_name);
slot.value->frames_per_second = DQN_CAST(uint16_t)frames_per_second.value; slot.value->frames_per_second = DQN_CAST(uint16_t)frames_per_second.value;
} }
} }
// NOTE: Get the list of files ================================================================= // NOTE: Get the list of files =================================================================
Dqn_List<Dqn_String8> file_list_raw = Dqn_List_Init<Dqn_String8>(scratch.arena, 128); Dqn_List<Dqn_Str8> file_list_raw = Dqn_List_Init<Dqn_Str8>(scratch.arena, 128);
for (Dqn_Win_FolderIterator it = {}; Dqn_Win_FolderIterate(dir, &it); ) { for (Dqn_Win_FolderIterator it = {}; Dqn_Win_FolderIterate(dir, &it); ) {
if (Dqn_String8_EndsWithInsensitive(it.file_name, DQN_STRING8(".png"))) { if (Dqn_Str8_EndsWithInsensitive(it.file_name, DQN_STR8(".png"))) {
Dqn_String8 *item = Dqn_List_Make(&file_list_raw, Dqn_ZeroMem_Yes); Dqn_Str8 *item = Dqn_List_Make(&file_list_raw, Dqn_ZeroMem_Yes);
*item = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STRING_FMT(dir), DQN_STRING_FMT(it.file_name)); *item = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/%.*s", DQN_STR_FMT(dir), DQN_STR_FMT(it.file_name));
} }
} }
// NOTE: Sort the list of files ================================================================ // NOTE: Sort the list of files ================================================================
if (file_list_raw.count == 0) { if (file_list_raw.count == 0) {
Dqn_Log_InfoF("There are no '.png' files in the directory '%.*s' to create an atlas from, exiting", DQN_STRING_FMT(dir)); Dqn_Log_InfoF("There are no '.png' files in the directory '%.*s' to create an atlas from, exiting", DQN_STR_FMT(dir));
return 0; return 0;
} }
// NOTE: Bubble sort the file list naturally =================================================== // NOTE: Bubble sort the file list naturally ===================================================
Dqn_Slice<Dqn_String8> file_list = Dqn_List_ToSliceCopy(&file_list_raw, scratch.arena); Dqn_Slice<Dqn_Str8> file_list = Dqn_List_ToSliceCopy(&file_list_raw, scratch.arena);
for (bool swapped = true; swapped; ) { for (bool swapped = true; swapped; ) {
swapped = false; swapped = false;
for (Dqn_usize list_index = 0; list_index < file_list.size - 1; list_index++) { for (Dqn_usize list_index = 0; list_index < file_list.size - 1; list_index++) {
Dqn_String8 left = file_list.data[list_index + 0]; Dqn_Str8 left = file_list.data[list_index + 0];
Dqn_String8 right = file_list.data[list_index + 1]; Dqn_Str8 right = file_list.data[list_index + 1];
if (strnatcmp(left.data, right.data) > 0) { if (strnatcmp(left.data, right.data) > 0) {
DQN_SWAP(file_list.data[list_index + 0], file_list.data[list_index + 1]); DQN_SWAP(file_list.data[list_index + 0], file_list.data[list_index + 1]);
swapped = true; swapped = true;
@ -165,7 +165,7 @@ int main(int argc, char const *argv[])
// 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.size, Dqn_ZeroMem_Yes); Dqn_SArray<stbrp_rect> rects = Dqn_SArray_Init<stbrp_rect>(scratch.arena, file_list.size, Dqn_ZeroMem_Yes);
for (Dqn_String8 it : file_list) { for (Dqn_Str8 it : file_list) {
int x = 0, y = 0, channels_in_file = 0; int x = 0, y = 0, channels_in_file = 0;
stbi_uc *pixels = stbi_load(it.data, &x, &y, &channels_in_file, 4 /*desired_channels*/); stbi_uc *pixels = stbi_load(it.data, &x, &y, &channels_in_file, 4 /*desired_channels*/);
DQN_ASSERT(pixels); DQN_ASSERT(pixels);
@ -177,16 +177,16 @@ int main(int argc, char const *argv[])
rect->h = y; rect->h = y;
// NOTE: Enumerate the number of frames for this animation ================================= // NOTE: Enumerate the number of frames for this animation =================================
Dqn_String8 anim_prefix = SpriteAnimNameFromFilePath(it); Dqn_Str8 anim_prefix = SpriteAnimNameFromFilePath(it);
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(it); Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(it);
DQN_ASSERTF(!Dqn_String8_HasChar(file_name, ';'), DQN_ASSERTF(!Dqn_Str8_HasChar(file_name, ';'),
"\n\nSprite frame loaded from file\n" "\n\nSprite frame loaded from file\n"
" '%.*s'\n" " '%.*s'\n"
"\n" "\n"
"however the file name has a semicolon which is not supported because we use a semicolon to delimit our sprite specification", "however the file name has a semicolon which is not supported because we use a semicolon to delimit our sprite specification",
DQN_STRING_FMT(file_name)); DQN_STR_FMT(file_name));
Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_FindKeyString8(&sprite_spec_table, anim_prefix); Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_FindKeyStr8(&sprite_spec_table, anim_prefix);
DQN_ASSERTF(slot.found, DQN_ASSERTF(slot.found,
"\n\nSprite frame loaded from file\n" "\n\nSprite frame loaded from file\n"
" '%.*s'\n" " '%.*s'\n"
@ -196,12 +196,12 @@ int main(int argc, char const *argv[])
"\n" "\n"
"Add a line in format of <animation name>;<frames_per_second> to the file, e.g.\n" "Add a line in format of <animation name>;<frames_per_second> to the file, e.g.\n"
" %.*s;8\n", " %.*s;8\n",
DQN_STRING_FMT(it), DQN_STR_FMT(it),
DQN_STRING_FMT(sprite_spec_path), DQN_STR_FMT(sprite_spec_path),
DQN_STRING_FMT(anim_prefix)); DQN_STR_FMT(anim_prefix));
slot.value->frame_count++; slot.value->frame_count++;
Dqn_Log_InfoF("Packing sprite: %.*s", DQN_STRING_FMT(it)); Dqn_Log_InfoF("Packing sprite: %.*s", DQN_STR_FMT(it));
} }
// NOTE: Pack the rects ======================================================================== // NOTE: Pack the rects ========================================================================
@ -217,7 +217,7 @@ int main(int argc, char const *argv[])
int final_bpp = 4; int final_bpp = 4;
int final_image_stride = atlas_size.w * final_bpp; int final_image_stride = atlas_size.w * final_bpp;
char *final_image = Dqn_Arena_NewArray(scratch.arena, char, atlas_size.h * final_image_stride, Dqn_ZeroMem_Yes); char *final_image = Dqn_Arena_NewArray(scratch.arena, char, atlas_size.h * final_image_stride, Dqn_ZeroMem_Yes);
Dqn_String8 atlas_path = Dqn_String8_InitF(scratch.allocator, "%.*s.png", DQN_STRING_FMT(dir)); Dqn_Str8 atlas_path = Dqn_Str8_InitF(scratch.allocator, "%.*s.png", DQN_STR_FMT(dir));
// NOTE: Generate the meta file ================================================================ // NOTE: Generate the meta file ================================================================
// NOTE: Count the number of animations we loaded frames fore // NOTE: Count the number of animations we loaded frames fore
@ -231,18 +231,18 @@ int main(int argc, char const *argv[])
} }
} }
Dqn_String8 meta_path = Dqn_String8_InitF(scratch.allocator, "%.*s.txt", DQN_STRING_FMT(dir)); Dqn_Str8 meta_path = Dqn_Str8_InitF(scratch.allocator, "%.*s.txt", DQN_STR_FMT(dir));
Dqn_FsFile meta_file = Dqn_Fs_OpenFile(meta_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_Write); Dqn_FsFile meta_file = Dqn_Fs_OpenFile(meta_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_Write);
Dqn_Fs_WriteFileF(&meta_file, Dqn_Fs_WriteFileF(&meta_file,
"@file;%.*s;%d;%d\n", "@file;%.*s;%d;%d\n",
DQN_STRING_FMT(Dqn_String8_FileNameFromPath(atlas_path)), DQN_STR_FMT(Dqn_Str8_FileNameFromPath(atlas_path)),
DQN_CAST(int) num_anim_rects, DQN_CAST(int) num_anim_rects,
DQN_CAST(int) num_anims); DQN_CAST(int) num_anims);
Dqn_Log_InfoF("Generating meta file: %.*s", DQN_STRING_FMT(meta_path)); Dqn_Log_InfoF("Generating meta file: %.*s", DQN_STR_FMT(meta_path));
Dqn_String8 active_anim_prefix = {}; Dqn_Str8 active_anim_prefix = {};
DQN_FOR_UINDEX (file_list_index, file_list.size) { DQN_FOR_UINDEX (file_list_index, file_list.size) {
Dqn_String8 it = file_list.data[file_list_index]; Dqn_Str8 it = file_list.data[file_list_index];
int w, h, channels_in_file; int w, h, channels_in_file;
stbi_uc *loaded_image = stbi_load(it.data, &w, &h, &channels_in_file, 4 /*desired_channels*/); stbi_uc *loaded_image = stbi_load(it.data, &w, &h, &channels_in_file, 4 /*desired_channels*/);
@ -263,22 +263,22 @@ int main(int argc, char const *argv[])
stbi_image_free(loaded_image); stbi_image_free(loaded_image);
// NOTE: Detect what animation we are currently processing ================================= // NOTE: Detect what animation we are currently processing =================================
Dqn_String8 anim_prefix = SpriteAnimNameFromFilePath(it); Dqn_Str8 anim_prefix = SpriteAnimNameFromFilePath(it);
if (active_anim_prefix.size == 0 || active_anim_prefix != anim_prefix) { if (active_anim_prefix.size == 0 || active_anim_prefix != anim_prefix) {
// NOTE: Anim prefix is different, we are starting a new animation- mark it accordingly // NOTE: Anim prefix is different, we are starting a new animation- mark it accordingly
active_anim_prefix = anim_prefix; active_anim_prefix = anim_prefix;
Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_FindKeyString8(&sprite_spec_table, active_anim_prefix); Dqn_DSMapResult<SpriteSpecification> slot = Dqn_DSMap_FindKeyStr8(&sprite_spec_table, active_anim_prefix);
Dqn_Fs_WriteFileF(&meta_file, "@anim;%.*s;%u;%u\n", DQN_STRING_FMT(active_anim_prefix), slot.value->frames_per_second, slot.value->frame_count); Dqn_Fs_WriteFileF(&meta_file, "@anim;%.*s;%u;%u\n", DQN_STR_FMT(active_anim_prefix), slot.value->frames_per_second, slot.value->frame_count);
} }
// NOTE: Write the sprite rectangles in ==================================================== // NOTE: Write the sprite rectangles in ====================================================
Dqn_String8 file_name = Dqn_String8_FileNameFromPath(it); Dqn_Str8 file_name = Dqn_Str8_FileNameFromPath(it);
Dqn_Fs_WriteFileF(&meta_file, "%d;%d;%d;%d;%.*s", packed_rect.x, packed_rect.y, packed_rect.w, packed_rect.h, DQN_STRING_FMT(file_name)); Dqn_Fs_WriteFileF(&meta_file, "%d;%d;%d;%d;%.*s", packed_rect.x, packed_rect.y, packed_rect.w, packed_rect.h, DQN_STR_FMT(file_name));
if (file_list_index != (file_list.size - 1)) if (file_list_index != (file_list.size - 1))
Dqn_Fs_WriteFileF(&meta_file, "\n"); Dqn_Fs_WriteFileF(&meta_file, "\n");
} }
Dqn_Log_InfoF("Generating atlas: %.*s", DQN_STRING_FMT(atlas_path)); Dqn_Log_InfoF("Generating atlas: %.*s", DQN_STR_FMT(atlas_path));
stbi_write_png(atlas_path.data, atlas_size.w, atlas_size.h, 4, final_image, final_image_stride); stbi_write_png(atlas_path.data, atlas_size.w, atlas_size.h, 4, final_image, final_image_stride);
return 0; return 0;
} }

1
feely_pona_unity.cpp Normal file
View File

@ -0,0 +1 @@
#include "feely_pona_unity.h"

View File

@ -1,65 +1,13 @@
// ================================================================================================= // NOTE: feely_pona ================================================================================
// Unity build header to compile the entire application as a single translation unit
// NOTE(doyle): Work-around for clangd to correctly resolve symbols in unity #define TELY_PLATFORM_DLL_FILE_NAME "terry_cherry_dev_dll_msvc"
// builds by providing symbol definition and prototypes by including this #include "External/tely/tely_os_raylib_unity.h"
// mega-header in all files and using the "#pragma once" directive to
// avoid multiple defined symbols when compiling the unity build itself.
//
// See: https://www.frogtoss.com/labs/clangd-with-unity-builds.html
#pragma once
// NOTE: DQN =======================================================================================
// NOTE: C-strings declared in a ternary cause global-buffer-overflow in
// MSVC2022.
// stb_sprintf assumes c-string literals are 4 byte aligned which is always
// true, however, reading past the end of a string whose size is not a multiple
// of 4 is UB causing ASAN to complain.
#if defined(_MSC_VER) && !defined(__clang__)
#define STBSP__ASAN __declspec(no_sanitize_address)
#endif
#define DQN_ASAN_POISON 0
#define DQN_ASAN_VET_POISON 1
#define DQN_ONLY_RECT
#define DQN_ONLY_V2
#define DQN_ONLY_V3
#define DQN_ONLY_V4
#define DQN_ONLY_WIN
#define DQN_ONLY_FARRAY
#define DQN_ONLY_PROFILER
#define DQN_ONLY_SLICE
#define DQN_ONLY_LIST
#define DQN_ONLY_VARRAY
#define DQN_ONLY_DSMAP
#define DQN_ONLY_FS
#define _CRT_SECURE_NO_WARNINGS
#define DQN_IMPLEMENTATION
#include "External/tely/External/dqn/dqn.h"
// NOTE: TELY ======================================================================================
DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with internal linkage has been removed
#include "External/tely/tely_profile.h"
#include "External/tely/tely_platform_input.h"
#include "External/tely/tely_tools.h"
#include "External/tely/tely_asset.h"
#include "External/tely/tely_colour.h"
#include "External/tely/tely_render.h"
#include "External/tely/tely_audio.h"
#include "External/tely/tely_platform.h"
#include "External/tely/tely_rfui.h"
#include "External/tely/tely_tools.cpp"
#include "External/tely/tely_asset.cpp"
#include "External/tely/tely_audio.cpp"
#include "External/tely/tely_render.cpp"
#include "External/tely/tely_platform_input.cpp"
#include "External/tely/tely_rfui.cpp"
// NOTE: feely_pona ================================================================================ // NOTE: feely_pona ================================================================================
#if defined(_CLANGD) || defined(FEELY_PONA_IMPLEMENTATION)
DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with internal linkage has been removed
#include "feely_pona.h" #include "feely_pona.h"
#include "feely_pona_stdlib.h" #include "feely_pona_stdlib.h"
#include "feely_pona_entity.h" #include "feely_pona_entity.h"
@ -71,3 +19,4 @@ DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with inte
#include "feely_pona_misc.cpp" #include "feely_pona_misc.cpp"
#include "feely_pona.cpp" #include "feely_pona.cpp"
DQN_MSVC_WARNING_POP DQN_MSVC_WARNING_POP
#endif

View File

@ -1 +0,0 @@
#include "feely_pona_unity_nodll.h"

View File

@ -1,102 +0,0 @@
// =================================================================================================
// NOTE(doyle): Work-around for clangd to correctly resolve symbols in unity
// builds by providing symbol definition and prototypes by including this
// mega-header in all files and using the "#pragma once" directive to
// avoid multiple defined symbols when compiling the unity build itself.
//
// See: https://www.frogtoss.com/labs/clangd-with-unity-builds.html
#pragma once
// NOTE: DQN =======================================================================================
// NOTE: C-strings declared in a ternary cause global-buffer-overflow in
// MSVC2022.
// stb_sprintf assumes c-string literals are 4 byte aligned which is always
// true, however, reading past the end of a string whose size is not a multiple
// of 4 is UB causing ASAN to complain.
#if defined(_MSC_VER) && !defined(__clang__)
#define STBSP__ASAN __declspec(no_sanitize_address)
#endif
#define DQN_ASAN_POISON 0
#define DQN_ASAN_VET_POISON 1
#define DQN_ONLY_RECT
#define DQN_ONLY_V2
#define DQN_ONLY_V3
#define DQN_ONLY_V4
#define DQN_ONLY_WIN
#define DQN_ONLY_FARRAY
#define DQN_ONLY_PROFILER
#define DQN_ONLY_SLICE
#define DQN_ONLY_LIST
#define DQN_ONLY_VARRAY
#define DQN_ONLY_DSMAP
#define DQN_ONLY_FS
#define _CRT_SECURE_NO_WARNINGS
#define DQN_IMPLEMENTATION
#include "External/tely/External/dqn/dqn.h"
// NOTE: STB Headers ===============================================================================
DQN_GCC_WARNING_PUSH
DQN_GCC_WARNING_DISABLE(-Wunused-function)
#include "External/tely/External/stb/stb_image.h"
DQN_GCC_WARNING_POP
// =================================================================================================
#include "External/tely/External/raylib/raylib.h"
#include "External/tely/External/raylib/rlgl.h"
#include "External/tely/External/raylib/external/glfw/include/GLFW/glfw3.h"
// NOTE: TELY ======================================================================================
DQN_MSVC_WARNING_PUSH
DQN_MSVC_WARNING_DISABLE(4505) // warning C4505: unreferenced function with internal linkage has been removed
DQN_GCC_WARNING_PUSH
DQN_GCC_WARNING_DISABLE(-Wunused-function)
#include "External/tely/tely_profile.h"
#include "External/tely/tely_platform_input.h"
#include "External/tely/tely_tools.h"
#include "External/tely/tely_asset.h"
#include "External/tely/tely_colour.h"
#include "External/tely/tely_render.h"
#include "External/tely/tely_audio.h"
#include "External/tely/tely_platform.h"
#include "External/tely/tely_rfui.h"
#include "External/tely/tely_tools.cpp"
#include "External/tely/tely_asset.cpp"
#include "External/tely/tely_audio.cpp"
#include "External/tely/tely_render.cpp"
#include "External/tely/tely_platform_input.cpp"
#include "External/tely/tely_rfui.cpp"
// NOTE: feely_pona ================================================================================
#include "feely_pona.h"
#include "feely_pona_stdlib.h"
#include "feely_pona_entity.h"
#include "feely_pona_game.h"
#include "feely_pona_entity.cpp"
#include "feely_pona_game.cpp"
#include "feely_pona_entity_create.cpp"
#include "feely_pona_misc.cpp"
#include "feely_pona.cpp"
DQN_MSVC_WARNING_POP
DQN_GCC_WARNING_POP
#if defined(DQN_PLATFORM_EMSCRIPTEN)
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#endif
// NOTE: TELY_Platform =============================================================================
#define TELY_PLATFORM_NO_DLL
#include "External/tely/tely_platform.cpp"
#include "External/tely/tely_platform_raylib.cpp"