From bac001947b1c4ed5df8f98829a773aca6839ef2e Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 13 Mar 2024 14:00:56 -0500 Subject: [PATCH] interp tick ratio rather than time offset. set world tick timestamp at beginning of frame --- src/config.h | 7 +++++++ src/game.c | 12 +++++------- src/user.c | 22 +++++++++------------- src/world.h | 4 +++- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/config.h b/src/config.h index 85360799..d9b5430d 100644 --- a/src/config.h +++ b/src/config.h @@ -11,4 +11,11 @@ #define VSYNC_ENABLED 0 #define GAME_FPS 30 + #define USER_FRAME_LIMIT 300 + +/* How many ticks back in time should the user blend between? + * Delay ms = USER_INTERP_OFFSET_TICK_RATIO * Game tick rate + * E.g: At 1.5, the user thread will render 49.5ms back in time (if game thread runs at 30FPS) + */ +#define USER_INTERP_OFFSET_TICK_RATIO 1.5 diff --git a/src/game.c b/src/game.c index b0bdc403..761f2321 100644 --- a/src/game.c +++ b/src/game.c @@ -13,7 +13,6 @@ GLOBAL struct { b32 shutdown; struct sys_thread game_thread; - f64 timescale; struct world world; /* Game thread input */ @@ -66,9 +65,7 @@ INTERNAL struct game_cmd_array pop_cmds(struct arena *arena) INTERNAL void publish_game_tick(void) { __prof; - sys_mutex_lock(&L.published_tick_mutex); - L.world.tick_published_ts = sys_timestamp(); world_copy_replace(&L.published_tick, &L.world); sys_mutex_unlock(&L.published_tick_mutex); } @@ -211,7 +208,8 @@ INTERNAL void game_update(void) } ++L.world.tick_id; - L.world.dt = max_f64(0.0, (1.0 / GAME_FPS) * L.timescale); + L.world.tick_ts = sys_timestamp(); + L.world.dt = max_f64(0.0, (1.0 / GAME_FPS) * L.world.timescale); L.world.time += L.world.dt; struct entity_array entities_array = world_get_entities(&L.world); @@ -454,7 +452,7 @@ INTERNAL void game_update(void) if (entity_has_prop(ent, ENTITY_PROP_TEST_SOUND_EMITTER)) { struct mixer_desc desc = ent->sound_desc; - desc.speed = L.timescale; + desc.speed = L.world.timescale; desc.pos = ent->world_xform.og; struct sound *sound = sound_load_async(ent->sound_name, 0); b32 played = ent->sound_handle.gen != 0; @@ -486,7 +484,7 @@ INTERNAL void game_thread_entry_point(void *arg) { (UNUSED)arg; sys_timestamp_t last_frame_ts = 0; - f64 target_dt = GAME_FPS > 0 ? (1.0 / GAME_FPS) : 0; + f64 target_dt = GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0; while (!L.shutdown) { __profscope(game_update_w_sleep); sleep_frame(last_frame_ts, target_dt); @@ -509,7 +507,7 @@ void game_startup(void) L.published_tick_mutex = sys_mutex_alloc(); - L.timescale = 1.0; + L.world.timescale = 1.0; L.game_thread = sys_thread_init(&game_thread_entry_point, NULL, STR("[P2] Game thread")); } diff --git a/src/user.c b/src/user.c index eb211406..14aed7dd 100644 --- a/src/user.c +++ b/src/user.c @@ -19,10 +19,6 @@ #include "sound.h" #include "mixer.h" -/* How far back in time should the user blend between game ticks (in addition - * to the existing 1-tick delay) */ -#define USER_INTERP_DELAY 0.005 - struct view { f32 px_per_unit; @@ -213,13 +209,13 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time) struct world *from_tick = oldest_tick; struct world *to_tick = newest_tick; for (struct blend_tick *bt = L.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_seconds(bt->world.tick_published_ts); + f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); - if (bt_time < blend_time && bt_time > sys_timestamp_seconds(from_tick->tick_published_ts)) { + if (bt_time < blend_time && bt_time > sys_timestamp_seconds(from_tick->tick_ts)) { from_tick = &bt->world; } - if (bt_time > blend_time && bt_time < sys_timestamp_seconds(to_tick->tick_published_ts)) { + if (bt_time > blend_time && bt_time < sys_timestamp_seconds(to_tick->tick_ts)) { to_tick = &bt->world; } } @@ -231,8 +227,8 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time) u64 bts_to_free_count = 0; for (struct blend_tick *bt = L.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_seconds(bt->world.tick_published_ts); - if (bt_time < sys_timestamp_seconds(from_tick->tick_published_ts)) { + f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); + if (bt_time < sys_timestamp_seconds(from_tick->tick_ts)) { *arena_push(scratch.arena, struct blend_tick *) = bt; ++bts_to_free_count; } @@ -588,7 +584,7 @@ INTERNAL void user_update(void) /* Pull ticks */ /* FIXME: use real game DT */ - f64 blend_time_offset = USER_INTERP_DELAY + (1.0 / GAME_FPS); + f64 blend_time_offset = (1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO; f64 blend_time = L.time > blend_time_offset ? L.time - blend_time_offset : 0; struct interp_ticks interp_ticks = pull_ticks(blend_time); @@ -599,8 +595,8 @@ INTERNAL void user_update(void) { __profscope(produce_interpolated_tick); - f64 t0_time = sys_timestamp_seconds(t0->tick_published_ts); - f64 t1_time = sys_timestamp_seconds(t1->tick_published_ts); + f64 t0_time = sys_timestamp_seconds(t0->tick_ts); + f64 t1_time = sys_timestamp_seconds(t1->tick_ts); f32 tick_blend = 0; if (t1_time > t0_time) { @@ -939,7 +935,7 @@ INTERNAL void user_thread_entry_point(void *arg) (UNUSED)arg; sys_timestamp_t last_frame_ts = 0; - f64 target_dt = USER_FRAME_LIMIT > 0 ? (1.0 / USER_FRAME_LIMIT) : 0; + f64 target_dt = USER_FRAME_LIMIT > (0) ? (1.0 / USER_FRAME_LIMIT) : 0; while (!L.shutdown) { __profscope(user_update_w_sleep); diff --git a/src/world.h b/src/world.h index 0753a0f8..6920b248 100644 --- a/src/world.h +++ b/src/world.h @@ -5,8 +5,10 @@ struct world { u64 tick_id; /* Starts at 1 */ - u64 tick_published_ts; + u64 tick_ts; /* When was this tick simulated in program time */ + /* World time */ + f64 timescale; f64 dt; f64 time;