From f0a25248c348f8aeb1eaddc70616af6d2b1515b2 Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 29 Jan 2025 11:29:31 -0600 Subject: [PATCH] remove sys_timestamp, refactor into generalized i64 holding nanoseconds --- src/common.h | 4 +++ src/font.c | 4 +-- src/game.c | 21 +++++++------- src/math.h | 18 +++++++++--- src/mixer.c | 10 +++---- src/sound.c | 4 +-- src/sprite.c | 8 +++--- src/sys.h | 34 ++-------------------- src/sys_win32.c | 46 +++++++++++------------------- src/user.c | 75 ++++++++++++++++++++++++------------------------- src/util.h | 13 +++++---- src/world.h | 6 ++-- 12 files changed, 109 insertions(+), 134 deletions(-) diff --git a/src/common.h b/src/common.h index 4cbfb6ed..f828dc66 100644 --- a/src/common.h +++ b/src/common.h @@ -231,6 +231,10 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #define GIGABYTE(n) (n*MEGABYTE(1024ULL)) #define TERABYTE(n) (n*GIGABYTE(1024ULL)) +/* Time */ +#define NS_FROM_SECONDS(s) ((i64)((s) * 1000000000.0)) +#define SECONDS_FROM_NS(ns) ((f64)(ns) / 1000000000.0) + /* typeof */ #if COMPILER_MSVC /* Typeof not supported in MSVC */ diff --git a/src/font.c b/src/font.c index bbc3ba9d..9f8f063f 100644 --- a/src/font.c +++ b/src/font.c @@ -102,7 +102,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) struct asset *asset = params->asset; logf_info("Loading font \"%F\" (point size %F)", FMT_STR(path), FMT_FLOAT((f64)point_size)); - struct sys_timestamp start_ts = sys_timestamp_prog(); + i64 start_ns = sys_time_ns(); ASSERT(string_ends_with(path, STR(".ttf"))); if (!resource_exists(path)) { @@ -157,7 +157,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) font_task_params_release(params); - f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); + f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); logf_info("Finished loading font \"%F\" (point size %F) in %F seconds", FMT_STR(path), FMT_FLOAT((f64)point_size), FMT_FLOAT(elapsed)); asset_cache_mark_ready(asset, font); diff --git a/src/game.c b/src/game.c index 5082cee5..a36f1e49 100644 --- a/src/game.c +++ b/src/game.c @@ -504,12 +504,13 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) * ========================== */ ++G.tick.tick_id; - G.tick.tick_ts = sys_timestamp_prog(); - G.tick.dt = max_f64(0.0, (1.0 / GAME_FPS) * G.tick.timescale); - G.tick.time += G.tick.dt; + G.tick.simtime_ns = sys_time_ns(); - f64 dt = G.tick.dt; - f64 time = G.tick.time; + G.tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / GAME_FPS) * G.tick.timescale)); + G.tick.time_ns += G.tick.dt_ns; + + f64 dt = SECONDS_FROM_NS(G.tick.dt_ns); + f64 time = SECONDS_FROM_NS(G.tick.time_ns); G.sprite_frame_scope = sprite_scope_begin(); G.root = entity_from_handle(G.tick.entity_store, G.tick.entity_store->root); @@ -1218,7 +1219,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) /* Lerp camera */ if (ent->camera_applied_lerp_continuity_gen_plus_one == ent->camera_lerp_continuity_gen + 1) { - f32 t = 1 - math_pow(2.f, -20.f * (f32)G.tick.dt); + f32 t = 1 - math_pow(2.f, -20.f * (f32)dt); xf = xform_lerp(xf, ent->camera_xform_target, t); } else { /* Skip lerp */ @@ -1347,13 +1348,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg) struct temp_arena scratch = scratch_begin_no_conflict(); (UNUSED)arg; - struct sys_timestamp last_frame_ts = ZI; - f64 target_dt = GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0; + i64 last_frame_ns = 0; + i64 target_dt_ns = NS_FROM_SECONDS(GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0); while (!atomic_i32_eval(&G.game_thread_shutdown)) { __profscope(game_update_w_sleep); struct temp_arena temp = arena_temp_begin(scratch.arena); - sleep_frame(last_frame_ts, target_dt); - last_frame_ts = sys_timestamp_prog(); + sleep_frame(last_frame_ns, target_dt_ns); + last_frame_ns = sys_time_ns(); { struct game_cmd_array game_cmds = pop_cmds(temp.arena); if (!G.paused) { diff --git a/src/math.h b/src/math.h index ec4fe452..8a195030 100644 --- a/src/math.h +++ b/src/math.h @@ -590,16 +590,26 @@ INLINE f32 math_unwind_angle(f32 a) * Lerp * ========================== */ -INLINE f32 math_lerp(f32 val0, f32 val1, f32 t) +INLINE f32 math_lerp_f32(f32 val0, f32 val1, f32 t) { return val0 + ((val1 - val0) * t); } -INLINE f64 math_lerp64(f64 val0, f64 val1, f64 t) +INLINE f64 math_lerp_f64(f64 val0, f64 val1, f64 t) { return val0 + ((val1 - val0) * t); } +INLINE i32 math_lerp_i32(i32 val0, i32 val1, f32 t) +{ + return val0 + math_round_to_int(((f32)(val1 - val0) * t)); +} + +INLINE i64 math_lerp_i64(i64 val0, i64 val1, f64 t) +{ + return val0 + math_round_to_int64(((f64)(val1 - val0) * t)); +} + INLINE f32 math_lerp_angle(f32 a, f32 b, f32 t) { f32 diff = math_unwind_angle(b - a); return a + diff * t; @@ -795,14 +805,14 @@ INLINE struct v2 v2_closest_point_ray(struct v2 ray_pos, struct v2 ray_dir_norm, /* Interpolate position vectors */ INLINE struct v2 v2_lerp(struct v2 val0, struct v2 val1, f32 t) { - return V2(math_lerp(val0.x, val1.x, t), math_lerp(val0.y, val1.y, t)); + return V2(math_lerp_f32(val0.x, val1.x, t), math_lerp_f32(val0.y, val1.y, t)); } /* Interpolate direction vectors (spherical lerp) */ INLINE struct v2 v2_slerp(struct v2 val0, struct v2 val1, f32 t) { f32 rot = math_lerp_angle(v2_angle(val0), v2_angle(val1), t); - f32 len = math_lerp(v2_len(val0), v2_len(val1), t); + f32 len = math_lerp_f32(v2_len(val0), v2_len(val1), t); return v2_mul(v2_from_angle(rot), len); } diff --git a/src/mixer.c b/src/mixer.c index b31d2af5..1b36b8d0 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -376,8 +376,8 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count) /* Lerp */ f32 t = in_frame_pos_exact - (f32)in_frame_pos_prev; - f32 sample1 = math_lerp(sample1_prev, sample1_next, t); - f32 sample2 = math_lerp(sample2_prev, sample2_next, t); + f32 sample1 = math_lerp_f32(sample1_prev, sample1_next, t); + f32 sample2 = math_lerp_f32(sample2_prev, sample2_next, t); out_samples[(out_frame_pos * 2) + 0] += sample1; out_samples[(out_frame_pos * 2) + 1] += sample2; @@ -395,7 +395,7 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count) /* Lerp */ f32 t = (f32)in_frame_pos_exact - in_frame_pos_prev; - f32 sample = math_lerp(sample_prev, sample_next, t); + f32 sample = math_lerp_f32(sample_prev, sample_next, t); out_samples[(out_frame_pos * 2) + 0] += sample; out_samples[(out_frame_pos * 2) + 1] += sample; @@ -446,8 +446,8 @@ struct mixed_pcm_f32 mixer_update(struct arena *arena, u64 frame_count) /* Spatialize samples */ for (u64 frame_pos = 0; frame_pos < frame_count; ++frame_pos) { f32 t = (f32)frame_pos / (f32)(frame_count - 1); - f32 volume = math_lerp(volume_start, volume_end, t); - f32 pan = math_lerp(pan_start, pan_end, t); + f32 volume = math_lerp_f32(volume_start, volume_end, t); + f32 pan = math_lerp_f32(pan_start, pan_end, t); u64 sample1_index = frame_pos * 2; u64 sample2_index = sample1_index + 1; diff --git a/src/sound.c b/src/sound.c index 99d2e058..06b5d50f 100644 --- a/src/sound.c +++ b/src/sound.c @@ -91,7 +91,7 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams) u32 flags = params->flags; logf_info("Loading sound \"%F\"", FMT_STR(path)); - struct sys_timestamp start_ts = sys_timestamp_prog(); + i64 start_ns = sys_time_ns(); b32 success = true; struct string error_msg = STR("Unknown error"); @@ -132,7 +132,7 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams) }; MEMCPY(sound->pcm.samples, decoded.pcm.samples, decoded.pcm.count * sizeof(*decoded.pcm.samples)); - f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); + f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); logf_info("Finished loading sound \"%F\" in %F seconds", FMT_STR(path), FMT_FLOAT(elapsed)); asset_cache_mark_ready(asset, sound); diff --git a/src/sprite.c b/src/sprite.c index bcbd22c0..7969a511 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -342,7 +342,7 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta struct string path = tag.path; logf_info("Loading sprite texture \"%F\"", FMT_STR(path)); - struct sys_timestamp start_ts = sys_timestamp_prog(); + i64 start_ns = sys_time_ns(); ASSERT(string_ends_with(path, STR(".ase"))); ASSERT(n->kind == CACHE_NODE_KIND_TEXTURE); @@ -383,7 +383,7 @@ INTERNAL void cache_node_load_texture(struct cache_node *n, struct sprite_tag ta n->memory_usage = n->arena.committed + memory_size; atomic_u64_eval_add(&G.cache.memory_usage, n->memory_usage); - f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); + f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); logf_info("Finished loading sprite texture \"%F\" in %F seconds (cache size: %F bytes).", FMT_STR(path), FMT_FLOAT(elapsed), @@ -648,7 +648,7 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag) struct string path = tag.path; logf_info("Loading sprite sheet \"%F\"", FMT_STR(path)); - struct sys_timestamp start_ts = sys_timestamp_prog(); + i64 start_ns = sys_time_ns(); //ASSERT(string_ends_with(path, STR(".ase"))); ASSERT(n->kind == CACHE_NODE_KIND_SHEET); @@ -683,7 +683,7 @@ INTERNAL void cache_node_load_sheet(struct cache_node *n, struct sprite_tag tag) n->memory_usage = n->arena.committed; atomic_u64_eval_add(&G.cache.memory_usage, n->memory_usage); - f64 elapsed = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), start_ts)); + f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); logf_info("Finished loading sprite sheet \"%F\" in %F seconds (cache size: %F bytes).", FMT_STR(path), FMT_FLOAT(elapsed), diff --git a/src/sys.h b/src/sys.h index 5217114c..9fa8c582 100644 --- a/src/sys.h +++ b/src/sys.h @@ -174,37 +174,7 @@ void sys_memory_set_committed_readonly(void *address, u64 size); void sys_memory_set_committed_readwrite(void *address, u64 size); /* ========================== * - * Timestamp - * ========================== */ - -struct sys_timestamp { - u64 v; -}; - -/* Returns timestamp representing time since program start */ -struct sys_timestamp sys_timestamp_prog(void); - -/* NOTE: Conversion between timestamp & seconds should only happen with small - * timestamp values (like relative timestamps) to avoid precision loss */ -struct sys_timestamp sys_timestamp_from_seconds(f64 s); -f64 sys_timestamp_to_seconds(struct sys_timestamp ts); - -INLINE struct sys_timestamp sys_timestamp_add(struct sys_timestamp a, struct sys_timestamp b) -{ - struct sys_timestamp res; - res.v = a.v + b.v; - return res; -} - -INLINE struct sys_timestamp sys_timestamp_sub(struct sys_timestamp a, struct sys_timestamp b) -{ - struct sys_timestamp res; - res.v = a.v - b.v; - return res; -} - -/* ========================== * - * Datetime + * Time * ========================== */ struct sys_datetime { @@ -220,6 +190,8 @@ struct sys_datetime { struct sys_datetime sys_local_time(void); +i64 sys_time_ns(void); + /* ========================== * * File system * diff --git a/src/sys_win32.c b/src/sys_win32.c index e0675725..c943f581 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -224,39 +224,19 @@ void sys_memory_set_committed_readwrite(void *address, u64 size) INTERNAL struct sys_datetime win32_time_to_sys_time(SYSTEMTIME st) { - return (struct sys_datetime) { + return (struct sys_datetime) + { .year = st.wYear, - .month = st.wMonth, - .day_of_week = st.wDayOfWeek, - .day = st.wDay, - .hour = st.wHour, - .minute = st.wMinute, - .second = st.wSecond, - .milliseconds = st.wMilliseconds + .month = st.wMonth, + .day_of_week = st.wDayOfWeek, + .day = st.wDay, + .hour = st.wHour, + .minute = st.wMinute, + .second = st.wSecond, + .milliseconds = st.wMilliseconds }; } -struct sys_timestamp sys_timestamp_prog(void) -{ - struct sys_timestamp ts; - LARGE_INTEGER qpc; - QueryPerformanceCounter(&qpc); - ts.v = (qpc.QuadPart * G.timer_frequency_ns) - G.timer_start_ns; - return ts; -} - -struct sys_timestamp sys_timestamp_from_seconds(f64 s) -{ - struct sys_timestamp ts; - ts.v = (u64)(s * 1000000000.0); - return ts; -} - -f64 sys_timestamp_to_seconds(struct sys_timestamp ts) -{ - return (f64)(ts.v) / 1000000000.0; -} - struct sys_datetime sys_local_time(void) { SYSTEMTIME lt; @@ -264,6 +244,14 @@ struct sys_datetime sys_local_time(void) return win32_time_to_sys_time(lt); } +i64 sys_time_ns(void) +{ + LARGE_INTEGER qpc; + QueryPerformanceCounter(&qpc); + i64 res = (qpc.QuadPart * G.timer_frequency_ns) - G.timer_start_ns; + return res; +} + /* ========================== * * File system * ========================== */ diff --git a/src/user.c b/src/user.c index ac01851e..1f154097 100644 --- a/src/user.c +++ b/src/user.c @@ -71,8 +71,8 @@ GLOBAL struct { struct arena sys_events_arena; /* Per-frame */ - f64 time; - f64 dt; + i64 time_ns; + i64 dt_ns; struct v2 screen_size; struct v2 screen_cursor; struct v2 ui_screen_offset; @@ -257,7 +257,7 @@ struct interp_ticks { struct world *to_tick; }; -INTERNAL struct interp_ticks pull_ticks(f64 blend_time) +INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) { __prof; @@ -291,13 +291,13 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time) from_tick = oldest_tick; to_tick = newest_tick; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_to_seconds(bt->world.tick_ts); + i64 bt_time_ns = bt->world.simtime_ns; - if (bt_time < blend_time && bt_time > sys_timestamp_to_seconds(from_tick->tick_ts)) { + if (bt_time_ns < blend_time_ns && bt_time_ns > from_tick->simtime_ns) { from_tick = &bt->world; } - if (bt_time > blend_time && bt_time < sys_timestamp_to_seconds(to_tick->tick_ts)) { + if (bt_time_ns > blend_time_ns && bt_time_ns < to_tick->simtime_ns) { to_tick = &bt->world; } } @@ -309,8 +309,8 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time) u64 bts_to_free_count = 0; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_to_seconds(bt->world.tick_ts); - if (bt_time < sys_timestamp_to_seconds(from_tick->tick_ts)) { + i64 bt_time_ns = bt->world.simtime_ns; + if (bt_time_ns < from_tick->simtime_ns) { *arena_push(scratch.arena, struct blend_tick *) = bt; ++bts_to_free_count; } @@ -490,9 +490,9 @@ INTERNAL void user_update(void) * Begin frame * ========================== */ - f64 cur_time = sys_timestamp_to_seconds(sys_timestamp_prog()); - G.dt = max_f64(0.0, cur_time - G.time); - G.time += G.dt; + i64 now_ns = sys_time_ns(); + G.dt_ns = max_f64(0.0, now_ns - G.time_ns); + G.time_ns += G.dt_ns; G.screen_size = sys_window_get_size(G.window); struct entity_store *store = G.world.entity_store; @@ -508,20 +508,22 @@ INTERNAL void user_update(void) #if USER_INTERP_ENABLED /* TODO: Use actual fps of game thread (will differ from GAME_FPS if game thread is lagging) to hide lag with slow-motion? */ - f64 blend_time_offset = (1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO; - f64 blend_time = G.time > blend_time_offset ? G.time - blend_time_offset : 0; + i64 blend_time_offset_ns = NS_FROM_SECONDS((1.0 / GAME_FPS) * USER_INTERP_OFFSET_TICK_RATIO); + i64 blend_time_ns = G.time_ns > blend_time_offset_ns ? G.time_ns - blend_time_offset_ns : 0; /* Pull ticks */ - struct interp_ticks interp_ticks = pull_ticks(blend_time); + struct interp_ticks interp_ticks = pull_ticks(blend_time_ns); struct world *t0 = interp_ticks.from_tick; struct world *t1 = interp_ticks.to_tick; f32 tick_blend = 0; { - f64 t0_time = sys_timestamp_to_seconds(t0->tick_ts); - f64 t1_time = sys_timestamp_to_seconds(t1->tick_ts); - if (t1_time > t0_time) { - tick_blend = (f32)((blend_time - t0_time) / (t1_time - t0_time)); + i64 t0_time_ns = t0->simtime_ns; + i64 t1_time_ns = t1->simtime_ns; + if (t1_time_ns > t0_time_ns) { + f64 t0_t1_elapsed = SECONDS_FROM_NS(t1_time_ns - t0_time_ns); + f64 t0_blend_elapsed = SECONDS_FROM_NS(blend_time_ns - t0_time_ns); + tick_blend = t0_blend_elapsed / t0_t1_elapsed; } tick_blend = clamp_f32(tick_blend, 0.0f, 1.0f); } @@ -529,8 +531,8 @@ INTERNAL void user_update(void) world_copy_replace(&G.world, t0); /* Blend world globals */ - G.world.time = math_lerp64(t0->time, t1->time, (f64)tick_blend); - G.world.dt = math_lerp64(t0->dt, t1->dt, (f64)tick_blend); + G.world.time_ns = math_lerp_i64(t0->time_ns, t1->time_ns, (f64)tick_blend); + G.world.dt_ns = math_lerp_i64(t0->dt_ns, t1->dt_ns, (f64)tick_blend); /* Blend entities */ u64 num_entities = min_u64(t0->entity_store->reserved, t1->entity_store->reserved); @@ -554,8 +556,8 @@ INTERNAL void user_update(void) entity_set_xform(e, xform_lerp(e0_xf, e1_xf, tick_blend)); } - e->control_force = math_lerp(e0->control_force, e1->control_force, tick_blend); - e->control_torque = math_lerp(e0->control_torque, e1->control_torque, tick_blend); + e->control_force = math_lerp_f32(e0->control_force, e1->control_force, tick_blend); + e->control_torque = math_lerp_f32(e0->control_torque, e1->control_torque, tick_blend); e->linear_velocity = v2_lerp(e0->linear_velocity, e1->linear_velocity, tick_blend); e->angular_velocity = math_lerp_angle(e0->angular_velocity, e1->angular_velocity, tick_blend); @@ -564,12 +566,12 @@ INTERNAL void user_update(void) e->control.focus = v2_lerp(e0->control.focus, e1->control.focus, tick_blend); e->sprite_local_xform = xform_lerp(e0->sprite_local_xform, e1->sprite_local_xform, tick_blend); - e->animation_time_in_frame = math_lerp64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend); - e->animation_frame = (u32)math_round_to_int(math_lerp(e0->animation_frame, e1->animation_frame, tick_blend)); + e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend); + e->animation_frame = (u32)math_round_to_int(math_lerp_f32(e0->animation_frame, e1->animation_frame, tick_blend)); e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, tick_blend); e->camera_xform_target = xform_lerp(e0->camera_xform_target, e1->camera_xform_target, tick_blend); - e->shake = math_lerp(e0->shake, e1->shake, tick_blend); + e->shake = math_lerp_f32(e0->shake, e1->shake, tick_blend); e->tracer_gradient_start = v2_lerp(e0->tracer_gradient_start, e1->tracer_gradient_start, tick_blend); e->tracer_gradient_end = v2_lerp(e0->tracer_gradient_end, e1->tracer_gradient_end, tick_blend); @@ -735,12 +737,12 @@ INTERNAL void user_update(void) if (!entity_is_valid_and_active(ent)) continue; /* How much time between camera shakes */ - const f32 frequency = 0.01f; + i64 frequency_ns = NS_FROM_SECONDS(0.01f); f32 shake = ent->shake; if (shake > 0) { u64 basis = hash_fnv64(HASH_FNV64_BASIS, BUFFER_FROM_STRUCT(&ent->handle)); - u32 angle_seed0 = basis + (u64)(G.world.time / frequency); - u32 angle_seed1 = angle_seed0 + 1; + u64 angle_seed0 = basis + (u64)(G.world.time_ns / frequency_ns); + u64 angle_seed1 = angle_seed0 + 1; f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU); f32 angle1 = rng_noise_f32(angle_seed1, 0, TAU); @@ -749,7 +751,7 @@ INTERNAL void user_update(void) struct v2 vec1 = v2_with_len(v2_from_angle(angle1), shake); /* TODO: Cubic interp? */ - f32 blend = math_fmod64(G.world.time, frequency) / frequency; + f32 blend = (f32)(G.world.time_ns % frequency_ns) / (f32)frequency_ns; struct v2 vec = v2_lerp(vec0, vec1, blend); struct xform xf = entity_get_xform(ent); @@ -1534,15 +1536,12 @@ INTERNAL void user_update(void) if (font) { struct temp_arena temp = arena_temp_begin(scratch.arena); - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT((f64)G.time))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.time_ns)))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT((f64)G.world.time))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("world time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.world.time_ns)))); pos.y += spacing; - //draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("time - world time: %F"), FMT_FLOAT((f64)G.time - (f64)G.world.time))); - //pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, STR("entities: %F/%F"), FMT_UINT(G.world.entity_store->allocated), FMT_UINT(G.world.entity_store->reserved))); pos.y += spacing; @@ -1717,13 +1716,13 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg) { (UNUSED)arg; - struct sys_timestamp last_frame_ts = ZI; - f64 target_dt = USER_FRAME_LIMIT > (0) ? (1.0 / USER_FRAME_LIMIT) : 0; + i64 last_frame_ns = 0; + i64 target_dt_ns = NS_FROM_SECONDS(USER_FRAME_LIMIT > (0) ? (1.0 / USER_FRAME_LIMIT) : 0); while (!atomic_i32_eval(&G.user_thread_shutdown)) { __profscope(user_update_w_sleep); - sleep_frame(last_frame_ts, target_dt); - last_frame_ts = sys_timestamp_prog(); + sleep_frame(last_frame_ns, target_dt_ns); + last_frame_ns = sys_time_ns(); user_update(); } } diff --git a/src/util.h b/src/util.h index 16717ff1..ec30a0d6 100644 --- a/src/util.h +++ b/src/util.h @@ -239,14 +239,15 @@ INLINE void sync_flag_wait(struct sync_flag *sf) * Sleep frame * ========================== */ -INLINE void sleep_frame(struct sys_timestamp last_frame_time, f64 target_dt) +INLINE void sleep_frame(i64 last_frame_time_ns, i64 target_dt_ns) { __prof; - if (last_frame_time.v != 0 && target_dt > 0) { - f64 last_frame_dt = sys_timestamp_to_seconds(sys_timestamp_sub(sys_timestamp_prog(), last_frame_time)); - f64 sleep_time = target_dt - last_frame_dt; - if (sleep_time > 0) { - sys_sleep_precise(sleep_time); + if (last_frame_time_ns != 0 && target_dt_ns > 0) { + i64 now_ns = sys_time_ns(); + i64 last_frame_dt_ns = now_ns - last_frame_time_ns; + i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns; + if (sleep_time_ns > 0) { + sys_sleep_precise(SECONDS_FROM_NS(sleep_time_ns)); } } } diff --git a/src/world.h b/src/world.h index d2f8e6c0..e18bc84d 100644 --- a/src/world.h +++ b/src/world.h @@ -6,12 +6,12 @@ struct world { u64 continuity_gen; /* Starts at 1 */ u64 tick_id; /* Starts at 1 */ - struct sys_timestamp tick_ts; /* When was this tick simulated in program time */ + i64 simtime_ns; /* When was this tick simulated in program time */ /* World time */ f64 timescale; - f64 dt; - f64 time; + i64 dt_ns; + i64 time_ns; struct entity_store *entity_store; };