interp tick ratio rather than time offset. set world tick timestamp at beginning of frame

This commit is contained in:
jacob 2024-03-13 14:00:56 -05:00
parent 8f33957bf9
commit bac001947b
4 changed files with 24 additions and 21 deletions

View File

@ -11,4 +11,11 @@
#define VSYNC_ENABLED 0 #define VSYNC_ENABLED 0
#define GAME_FPS 30 #define GAME_FPS 30
#define USER_FRAME_LIMIT 300 #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

View File

@ -13,7 +13,6 @@ GLOBAL struct {
b32 shutdown; b32 shutdown;
struct sys_thread game_thread; struct sys_thread game_thread;
f64 timescale;
struct world world; struct world world;
/* Game thread input */ /* Game thread input */
@ -66,9 +65,7 @@ INTERNAL struct game_cmd_array pop_cmds(struct arena *arena)
INTERNAL void publish_game_tick(void) INTERNAL void publish_game_tick(void)
{ {
__prof; __prof;
sys_mutex_lock(&L.published_tick_mutex); sys_mutex_lock(&L.published_tick_mutex);
L.world.tick_published_ts = sys_timestamp();
world_copy_replace(&L.published_tick, &L.world); world_copy_replace(&L.published_tick, &L.world);
sys_mutex_unlock(&L.published_tick_mutex); sys_mutex_unlock(&L.published_tick_mutex);
} }
@ -211,7 +208,8 @@ INTERNAL void game_update(void)
} }
++L.world.tick_id; ++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; L.world.time += L.world.dt;
struct entity_array entities_array = world_get_entities(&L.world); 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)) { if (entity_has_prop(ent, ENTITY_PROP_TEST_SOUND_EMITTER)) {
struct mixer_desc desc = ent->sound_desc; struct mixer_desc desc = ent->sound_desc;
desc.speed = L.timescale; desc.speed = L.world.timescale;
desc.pos = ent->world_xform.og; desc.pos = ent->world_xform.og;
struct sound *sound = sound_load_async(ent->sound_name, 0); struct sound *sound = sound_load_async(ent->sound_name, 0);
b32 played = ent->sound_handle.gen != 0; b32 played = ent->sound_handle.gen != 0;
@ -486,7 +484,7 @@ INTERNAL void game_thread_entry_point(void *arg)
{ {
(UNUSED)arg; (UNUSED)arg;
sys_timestamp_t last_frame_ts = 0; 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) { while (!L.shutdown) {
__profscope(game_update_w_sleep); __profscope(game_update_w_sleep);
sleep_frame(last_frame_ts, target_dt); sleep_frame(last_frame_ts, target_dt);
@ -509,7 +507,7 @@ void game_startup(void)
L.published_tick_mutex = sys_mutex_alloc(); 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")); L.game_thread = sys_thread_init(&game_thread_entry_point, NULL, STR("[P2] Game thread"));
} }

View File

@ -19,10 +19,6 @@
#include "sound.h" #include "sound.h"
#include "mixer.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 { struct view {
f32 px_per_unit; 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 *from_tick = oldest_tick;
struct world *to_tick = newest_tick; struct world *to_tick = newest_tick;
for (struct blend_tick *bt = L.head_blend_tick; bt; bt = bt->next) { 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; 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; to_tick = &bt->world;
} }
} }
@ -231,8 +227,8 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time)
u64 bts_to_free_count = 0; u64 bts_to_free_count = 0;
for (struct blend_tick *bt = L.head_blend_tick; bt; bt = bt->next) { 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 < sys_timestamp_seconds(from_tick->tick_published_ts)) { if (bt_time < sys_timestamp_seconds(from_tick->tick_ts)) {
*arena_push(scratch.arena, struct blend_tick *) = bt; *arena_push(scratch.arena, struct blend_tick *) = bt;
++bts_to_free_count; ++bts_to_free_count;
} }
@ -588,7 +584,7 @@ INTERNAL void user_update(void)
/* Pull ticks */ /* Pull ticks */
/* FIXME: use real game DT */ /* 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; f64 blend_time = L.time > blend_time_offset ? L.time - blend_time_offset : 0;
struct interp_ticks interp_ticks = pull_ticks(blend_time); struct interp_ticks interp_ticks = pull_ticks(blend_time);
@ -599,8 +595,8 @@ INTERNAL void user_update(void)
{ {
__profscope(produce_interpolated_tick); __profscope(produce_interpolated_tick);
f64 t0_time = sys_timestamp_seconds(t0->tick_published_ts); f64 t0_time = sys_timestamp_seconds(t0->tick_ts);
f64 t1_time = sys_timestamp_seconds(t1->tick_published_ts); f64 t1_time = sys_timestamp_seconds(t1->tick_ts);
f32 tick_blend = 0; f32 tick_blend = 0;
if (t1_time > t0_time) { if (t1_time > t0_time) {
@ -939,7 +935,7 @@ INTERNAL void user_thread_entry_point(void *arg)
(UNUSED)arg; (UNUSED)arg;
sys_timestamp_t last_frame_ts = 0; 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) { while (!L.shutdown) {
__profscope(user_update_w_sleep); __profscope(user_update_w_sleep);

View File

@ -5,8 +5,10 @@
struct world { struct world {
u64 tick_id; /* Starts at 1 */ 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 dt;
f64 time; f64 time;