From 63c3b4d427541f4c33f9d836acec2b0a3de8d27b Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 13 Mar 2026 17:13:12 -0500 Subject: [PATCH] base blend time off of accumulated prediction tick --- src/pp/pp_vis/pp_vis_core.c | 743 +++++++++++++++++++++++--------- src/pp/pp_vis/pp_vis_core.h | 17 +- src/pp/pp_vis/pp_vis_shared.cgh | 12 + 3 files changed, 560 insertions(+), 212 deletions(-) diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 48579b95..646b0f25 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -5,9 +5,8 @@ V_Ctx V = Zi; void V_Bootstrap(void) { - V.timeline.transient_markers_arena = AcquireArena(Gibi(64)); - V.timeline.persistent_markers_arena = AcquireArena(Gibi(64)); - V.timeline.show = 1; + V.transient_markers_arena = AcquireArena(Gibi(64)); + V.persistent_markers_arena = AcquireArena(Gibi(64)); DispatchWave(Lit("Vis"), 1, V_TickForever, 0); OnExit(V_Shutdown); } @@ -260,16 +259,17 @@ void V_DrawPoint(Vec2 p, Vec4 srgb) void V_PushTimelineMarker(i64 time_ns, Vec4 color, b32 transient) { - if (!V.timeline.paused) + V_Frame *prev_frame = V_PrevFrame(); + if (!prev_frame->prev_timeline.paused) { V_TimelineMarker *marker = 0; if (transient) { - marker = PushStruct(V.timeline.transient_markers_arena, V_TimelineMarker); + marker = PushStruct(V.transient_markers_arena, V_TimelineMarker); } else { - marker = PushStruct(V.timeline.persistent_markers_arena, V_TimelineMarker); + marker = PushStruct(V.persistent_markers_arena, V_TimelineMarker); } marker->time_ns = time_ns; marker->color = color; @@ -603,9 +603,13 @@ void V_TickForever(WaveLaneCtx *lane) frame->equipped_prefab = prev_frame->equipped_prefab ; frame->edit_camera_pos = prev_frame->edit_camera_pos; frame->edit_camera_zoom = prev_frame->edit_camera_zoom; + frame->prev_timeline = prev_frame->timeline; + frame->timeline = prev_frame->timeline; frame->sim_key = prev_frame->sim_key; frame->desired_sim_key = prev_frame->desired_sim_key; + frame->target_predict_tick_accum = prev_frame->target_predict_tick_accum; frame->predict_tick_accum = prev_frame->predict_tick_accum; + frame->blend_tick = prev_frame->blend_tick; frame->af = prev_frame->af; frame->tick = V.cur_frame_tick; @@ -621,6 +625,12 @@ void V_TickForever(WaveLaneCtx *lane) TrueRand(StringFromStruct(&V.player_key)); } + if (frame->tick == 1) + { + frame->timeline.show = 1; + frame->timeline.locked = 1; + } + ////////////////////////////// //- Initialize persistent gpu resources @@ -1359,6 +1369,13 @@ void V_TickForever(WaveLaneCtx *lane) } } + + + + + + + ////////////////////////////// //- Determine local simulation bounds // @@ -1373,6 +1390,8 @@ void V_TickForever(WaveLaneCtx *lane) f64 dilation_factor = 0; { + // TODO: Warm start + // How many buffered commands of ours we'd like the server to have i64 target_buffered_controls_count = 1; f64 rtt_bias_factor = 10.0; @@ -1383,12 +1402,21 @@ void V_TickForever(WaveLaneCtx *lane) target_buffered_controls_count - remote_buffered_controls_count ) * 2 - 1; - f64 predict_dt = frame->dt + frame->dt * dilation_factor; - frame->predict_tick_accum += predict_dt * SIM_TICKS_PER_SECOND; + f64 target_predict_dt = frame->dt + frame->dt * dilation_factor; + frame->target_predict_tick_accum += target_predict_dt * SIM_TICKS_PER_SECOND; + + // Warm start + frame->predict_tick_accum += frame->dt * SIM_TICKS_PER_SECOND; + + f64 lerp_rate = 5.0 * frame->dt; + // f64 lerp_rate = 1.0 * frame->dt; + // f64 lerp_rate = 1; + frame->predict_tick_accum = LerpF64(frame->predict_tick_accum, frame->target_predict_tick_accum, lerp_rate); if (ack == 0 || AbsF64(frame->predict_tick_accum - ack) > SIM_TICKS_PER_SECOND) { - frame->predict_tick_accum = ack + (SIM_TICKS_PER_SECOND * smoothed_rtt * 0.5); + frame->target_predict_tick_accum = ack + (SIM_TICKS_PER_SECOND * smoothed_rtt * 0.5); + frame->predict_tick_accum = frame->target_predict_tick_accum; LogDebugF("RESET"); } @@ -1402,10 +1430,98 @@ void V_TickForever(WaveLaneCtx *lane) // ); frame->predict_tick_accum = MaxF64(prev_frame->predict_tick_accum, frame->predict_tick_accum); + + + + + + V_PushTimelineMarker(frame->predict_tick_accum * SIM_TICK_INTERVAL_NS, Color_Red, 1); + V_PushTimelineMarker(frame->target_predict_tick_accum * SIM_TICK_INTERVAL_NS, Color_Yellow, 1); } i64 prev_frame_predict_to = FloorF64(prev_frame->predict_tick_accum); i64 predict_to = FloorF64(frame->predict_tick_accum); + + + + + + + + + // ////////////////////////////// + // //- Determine local simulation bounds + // // + // // Prediction rate will increase based on how many commands of ours we know + // // that the server has buffered up or is missing. + // // + // // If the server is missing commands, we increase the rate of prediction + // // until the server reports it has enough of our commands buffered up. + // // + // // If the server reports it has too many of our commands buffered up, we + // // slow the rate of prediction. + + // f64 dilation_factor = 0; + // { + // // TODO: Warm start + + // // How many buffered commands of ours we'd like the server to have + // i64 target_buffered_controls_count = 1; + // f64 rtt_bias_factor = 10.0; + + // dilation_factor = SmoothstepF64( + // -(SIM_TICKS_PER_SECOND * smoothed_rtt * rtt_bias_factor), + // (SIM_TICKS_PER_SECOND * smoothed_rtt * rtt_bias_factor), + // target_buffered_controls_count - remote_buffered_controls_count + // ) * 2 - 1; + + // f64 target_predict_dt = frame->dt + frame->dt * dilation_factor; + // frame->target_predict_tick_accum += target_predict_dt * SIM_TICKS_PER_SECOND; + + // frame->predict_tick_accum += frame->dt * SIM_TICKS_PER_SECOND; + + // // f64 lerp_rate = 5.0 * frame->dt; + // f64 lerp_rate = 1.0 * frame->dt; + // // f64 lerp_rate = 1; + // frame->predict_tick_accum = LerpF64(frame->predict_tick_accum, frame->target_predict_tick_accum, lerp_rate); + + // if (ack == 0 || AbsF64(frame->predict_tick_accum - ack) > SIM_TICKS_PER_SECOND) + // { + // frame->target_predict_tick_accum = ack + (SIM_TICKS_PER_SECOND * smoothed_rtt * 0.5); + // frame->predict_tick_accum = frame->target_predict_tick_accum; + // LogDebugF("RESET"); + // } + + // // LogDebugF( + // // "Buffered count: %F. Ack: %F, Predict tick accum: %F, Predict dt: %F, Dilation factor: %F", + // // FmtSint(remote_buffered_controls_count), + // // FmtFloat(ack), + // // FmtFloat(frame->predict_tick_accum), + // // FmtFloat(predict_dt), + // // FmtFloat(dilation_factor) + // // ); + + // frame->predict_tick_accum = MaxF64(prev_frame->predict_tick_accum, frame->predict_tick_accum); + + + + + + // V_PushTimelineMarker(frame->predict_tick_accum * SIM_TICK_INTERVAL_NS, Color_Red, 1); + // V_PushTimelineMarker(frame->target_predict_tick_accum * SIM_TICK_INTERVAL_NS, Color_Yellow, 1); + // } + // i64 prev_frame_predict_to = FloorF64(prev_frame->predict_tick_accum); + // i64 predict_to = FloorF64(frame->predict_tick_accum); + + + + + + + + + + ////////////////////////////// //- Create player control @@ -1636,6 +1752,10 @@ void V_TickForever(WaveLaneCtx *lane) ack_frame->base_predict_from = ack_frame->tick; ack_frame->base_predict_to = predict_to; cur_predict_world_seq += 1; + if (ack != prev_frame_ack) + { + V_PushTimelineMarker(ack_frame->time_ns, Color_Green, 0); + } } @@ -1875,6 +1995,15 @@ void V_TickForever(WaveLaneCtx *lane) + + + + + + + + + P_Frame *prev_local_frame = prev_frame->local_world->last_frame; P_Frame *local_frame = &P_NilFrame; { @@ -1887,89 +2016,21 @@ void V_TickForever(WaveLaneCtx *lane) frame->local_world->seed = predict_world->seed; P_ClearFrames(frame->local_world, I64Min, I64Max); - // i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor; - // i64 target_blend_dt_ns = frame->dt_ns; - - i64 blend_dt_ns = frame->dt_ns; - // i64 blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor; - - // V.target_blend_time_ns += target_blend_dt_ns; - V.blend_time_ns += blend_dt_ns; + frame->blend_tick += frame->dt * SIM_TICKS_PER_SECOND; // How many ticks back in time should the user thread blend between? // = * // E.g: At 1.5, the world will render 75ms back in time if the sim runs at 50tps f32 interp_ratio = TweakFloat("Interpolation ratio", 1.2, 0, V_MaxInterpRatio); - // if (ack != prev_frame_ack) - // { - // i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; - // V.target_blend_time_ns = ack_frame->time_ns - delay_ns; - // } - - // if (predict_to != prev_frame_predict_to) - // { - // i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; - // V.target_blend_time_ns = predict_frame->time_ns - delay_ns; - // } - - { - P_Frame *target_blend_frame = P_FrameFromTick(predict_world, predict_world->last_frame->base_predict_to); - - i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; - V.target_blend_time_ns = target_blend_frame->time_ns - delay_ns; - } - - - - if (ack != prev_frame_ack) - { - V_PushTimelineMarker(ack_frame->time_ns, Color_Green, 0); - } - - - // f64 blend_to_target_lerp_rate = 0.01 * frame->dt; - - f64 blend_to_target_lerp_rate = 1 * frame->dt; - // f64 blend_to_target_lerp_rate = 1 * frame->dt; - // f64 blend_to_target_lerp_rate = 0.0 * frame->dt; - - // f64 blend_to_target_lerp_rate = 0.0; - // f64 blend_to_target_lerp_rate = 0.05; - // f64 blend_to_target_lerp_rate = 1; - V.blend_time_ns = LerpI64(V.blend_time_ns, V.target_blend_time_ns, blend_to_target_lerp_rate); - if (AbsI64(V.blend_time_ns - V.target_blend_time_ns) > (SIM_TICK_INTERVAL_NS * interp_ratio * 2)) - { - LogDebugF("Blend reset"); - V.blend_time_ns = V.target_blend_time_ns; - - V_PushTimelineMarker(V.blend_time_ns, Color_Red, 0); - } + frame->blend_tick = frame->predict_tick_accum - interp_ratio; if (TweakBool("Interpolation enabled", 1)) { P_Frame *left_predict_frame = &P_NilFrame; P_Frame *right_predict_frame = &P_NilFrame; - // for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) - // { - // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) - // { - // right_predict_frame = tmp; - // left_predict_frame = tmp->prev; - // break; - // } - // } - - - - V_PushTimelineMarker(V.blend_time_ns, Color_Red, 1); - V_PushTimelineMarker(V.target_blend_time_ns, Color_Yellow, 1); - - - - - + // Locate right & left frames { for ( i64 predict_world_seq = cur_predict_world_seq; @@ -1977,97 +2038,65 @@ void V_TickForever(WaveLaneCtx *lane) --predict_world_seq ) { - i64 tmp_right_predict_world_idx = predict_world_seq % countof(predict_worlds); - i64 tmp_left_predict_world_idx = (predict_world_seq - 1) % countof(predict_worlds); - P_World *tmp_right_world = predict_worlds[tmp_right_predict_world_idx]; - P_World *tmp_left_world = predict_worlds[tmp_left_predict_world_idx]; + b32 search_right = P_IsFrameNil(right_predict_frame); + b32 search_left = P_IsFrameNil(left_predict_frame); - // P_Frame *tmp_right = P_FrameFromTick(tmp_right_world, tmp_right_world->last_frame->base_predict_from); - // P_Frame *tmp_left = P_FrameFromTick(tmp_left_world, tmp_left_world->last_frame->base_predict_from); - // i64 right_time_ns = tmp_right->base_time_ns; - // i64 left_time_ns = tmp_left->base_time_ns; - - - - - - P_Frame *tmp_right = P_FrameFromTick(tmp_right_world, tmp_right_world->last_frame->base_predict_to); - P_Frame *tmp_left = P_FrameFromTick(tmp_left_world, tmp_left_world->last_frame->base_predict_to); - - // P_Frame *tmp_right = tmp_right_world->last_frame; - // P_Frame *tmp_left = tmp_left_world->last_frame; - - i64 right_time_ns = tmp_right->time_ns; - i64 left_time_ns = tmp_left->time_ns; - - - - - V_PushTimelineMarker(left_time_ns, Color_Cyan, 1); - V_PushTimelineMarker(right_time_ns, Color_Orange, 1); - - - - if (right_time_ns >= V.blend_time_ns && left_time_ns <= V.blend_time_ns) + // Locate right frame + if (search_right) + { + i64 tmp_world_idx = predict_world_seq % countof(predict_worlds); + P_World *tmp_world = predict_worlds[tmp_world_idx]; + for (P_Frame *tmp_right_frame = tmp_world->last_frame; !P_IsFrameNil(tmp_right_frame); tmp_right_frame = tmp_right_frame->prev) + { + P_Frame *tmp_left_frame = tmp_right_frame->prev; + if (tmp_right_frame->tick >= frame->blend_tick && tmp_left_frame->tick <= frame->blend_tick) + { + right_predict_frame = tmp_right_frame; + break; + } + } + } + + // Locate left frame + if (search_left) + { + i64 tmp_world_idx = (predict_world_seq - 1) % countof(predict_worlds); + P_World *tmp_world = predict_worlds[tmp_world_idx]; + for (P_Frame *tmp_frame = tmp_world->last_frame; !P_IsFrameNil(tmp_frame); tmp_frame = tmp_frame->prev) + { + if (tmp_frame->tick <= frame->blend_tick) + { + left_predict_frame = tmp_frame; + break; + } + } + } + + // V_PushTimelineMarker(left_time_ns, Color_Cyan, 1); + // V_PushTimelineMarker(right_time_ns, Color_Orange, 1); + + if (!search_right && !search_left) { - right_predict_frame = tmp_right; - left_predict_frame = tmp_left; break; } } - // for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) - // { - // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) - // { - // right_predict_frame = tmp; - // break; - // } - // } - // for (P_Frame *tmp = prev_predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) - // { - // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) - // { - // left_predict_frame = tmp->prev; - // break; - // } - // } + if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame)) + { + LogDebugF("Missing blend"); + + + right_predict_frame = predict_world->last_frame; + left_predict_frame = right_predict_frame; + + DEBUGBREAKABLE; + + + V_PushTimelineMarker(frame->blend_tick * SIM_TICK_INTERVAL_NS, Color_Red, 0); + } } - - - // for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) - // { - // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) - // { - // right_predict_frame = tmp; - // break; - // } - // } - // for (P_Frame *tmp = prev_predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) - // { - // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) - // { - // left_predict_frame = tmp->prev; - // break; - // } - // } - - - - - - if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame)) - { - LogDebugF("Missing blend"); - right_predict_frame = predict_world->last_frame; - // left_predict_frame = right_predict_frame->prev; - left_predict_frame = right_predict_frame; - - DEBUGBREAKABLE; - } - frame->blend_from_tick = left_predict_frame->tick; frame->blend_to_tick = right_predict_frame->tick; @@ -2090,7 +2119,8 @@ void V_TickForever(WaveLaneCtx *lane) // P_Frame *left_sim_frame = right_sim_frame->prev; // f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->base_time_ns) / (f64)(right_predict_frame->base_time_ns - left_predict_frame->base_time_ns); - f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->time_ns) / (f64)(right_predict_frame->time_ns - left_predict_frame->time_ns); + // f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->time_ns) / (f64)(right_predict_frame->time_ns - left_predict_frame->time_ns); + f64 blend_t = (f64)(frame->blend_tick - left_predict_frame->tick) / (f64)(right_predict_frame->tick - left_predict_frame->tick); @@ -2143,6 +2173,312 @@ void V_TickForever(WaveLaneCtx *lane) + + + + + + + + + + + + + + + + + + + + + + // P_Frame *prev_local_frame = prev_frame->local_world->last_frame; + // P_Frame *local_frame = &P_NilFrame; + // { + // if (frame->local_world->tiles_hash != predict_world->tiles_hash) + // { + // frame->local_world->tiles_hash = predict_world->tiles_hash; + // CopyStructs(frame->local_world->tiles, predict_world->tiles, P_TilesCount); + // frame->tiles_dirty = 1; + // } + // frame->local_world->seed = predict_world->seed; + // P_ClearFrames(frame->local_world, I64Min, I64Max); + + // // i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor; + // // i64 target_blend_dt_ns = frame->dt_ns; + + // i64 blend_dt_ns = frame->dt_ns; + // // i64 blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor; + + // // V.target_blend_time_ns += target_blend_dt_ns; + // V.blend_time_ns += blend_dt_ns; + + // // How many ticks back in time should the user thread blend between? + // // = * + // // E.g: At 1.5, the world will render 75ms back in time if the sim runs at 50tps + // f32 interp_ratio = TweakFloat("Interpolation ratio", 1.2, 0, V_MaxInterpRatio); + + // // if (ack != prev_frame_ack) + // // { + // // i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; + // // V.target_blend_time_ns = ack_frame->time_ns - delay_ns; + // // } + + // // if (predict_to != prev_frame_predict_to) + // // { + // // i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; + // // V.target_blend_time_ns = predict_frame->time_ns - delay_ns; + // // } + + // { + // P_Frame *target_blend_frame = P_FrameFromTick(predict_world, predict_world->last_frame->base_predict_to); + + // i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; + // V.target_blend_time_ns = target_blend_frame->time_ns - delay_ns; + // } + + + + // if (ack != prev_frame_ack) + // { + // V_PushTimelineMarker(ack_frame->time_ns, Color_Green, 0); + // } + + + // // f64 blend_to_target_lerp_rate = 0.01 * frame->dt; + + // f64 blend_to_target_lerp_rate = 1 * frame->dt; + // // f64 blend_to_target_lerp_rate = 1 * frame->dt; + // // f64 blend_to_target_lerp_rate = 0.0 * frame->dt; + + // // f64 blend_to_target_lerp_rate = 0.0; + // // f64 blend_to_target_lerp_rate = 0.05; + // // f64 blend_to_target_lerp_rate = 1; + // V.blend_time_ns = LerpI64(V.blend_time_ns, V.target_blend_time_ns, blend_to_target_lerp_rate); + // if (AbsI64(V.blend_time_ns - V.target_blend_time_ns) > (SIM_TICK_INTERVAL_NS * interp_ratio * 2)) + // { + // LogDebugF("Blend reset"); + // V.blend_time_ns = V.target_blend_time_ns; + + // V_PushTimelineMarker(V.blend_time_ns, Color_Red, 0); + // } + + // if (TweakBool("Interpolation enabled", 1)) + // { + // P_Frame *left_predict_frame = &P_NilFrame; + // P_Frame *right_predict_frame = &P_NilFrame; + + // // for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) + // // { + // // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) + // // { + // // right_predict_frame = tmp; + // // left_predict_frame = tmp->prev; + // // break; + // // } + // // } + + + + // V_PushTimelineMarker(V.blend_time_ns, Color_Red, 1); + // V_PushTimelineMarker(V.target_blend_time_ns, Color_Yellow, 1); + + + + + + // { + // for ( + // i64 predict_world_seq = cur_predict_world_seq; + // predict_world_seq > MaxI64(0, cur_predict_world_seq - countof(predict_worlds)); + // --predict_world_seq + // ) + // { + // i64 tmp_right_predict_world_idx = predict_world_seq % countof(predict_worlds); + // i64 tmp_left_predict_world_idx = (predict_world_seq - 1) % countof(predict_worlds); + // P_World *tmp_right_world = predict_worlds[tmp_right_predict_world_idx]; + // P_World *tmp_left_world = predict_worlds[tmp_left_predict_world_idx]; + + // // P_Frame *tmp_right = P_FrameFromTick(tmp_right_world, tmp_right_world->last_frame->base_predict_from); + // // P_Frame *tmp_left = P_FrameFromTick(tmp_left_world, tmp_left_world->last_frame->base_predict_from); + // // i64 right_time_ns = tmp_right->base_time_ns; + // // i64 left_time_ns = tmp_left->base_time_ns; + + + + + + // P_Frame *tmp_right = P_FrameFromTick(tmp_right_world, tmp_right_world->last_frame->base_predict_to); + // P_Frame *tmp_left = P_FrameFromTick(tmp_left_world, tmp_left_world->last_frame->base_predict_to); + + // // P_Frame *tmp_right = tmp_right_world->last_frame; + // // P_Frame *tmp_left = tmp_left_world->last_frame; + + // i64 right_time_ns = tmp_right->time_ns; + // i64 left_time_ns = tmp_left->time_ns; + + + + + // V_PushTimelineMarker(left_time_ns, Color_Cyan, 1); + // V_PushTimelineMarker(right_time_ns, Color_Orange, 1); + + + + // if (right_time_ns >= V.blend_time_ns && left_time_ns <= V.blend_time_ns) + // { + // right_predict_frame = tmp_right; + // left_predict_frame = tmp_left; + // break; + // } + // } + + // // for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) + // // { + // // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) + // // { + // // right_predict_frame = tmp; + // // break; + // // } + // // } + // // for (P_Frame *tmp = prev_predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) + // // { + // // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) + // // { + // // left_predict_frame = tmp->prev; + // // break; + // // } + // // } + // } + + + + + // // for (P_Frame *tmp = predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) + // // { + // // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) + // // { + // // right_predict_frame = tmp; + // // break; + // // } + // // } + // // for (P_Frame *tmp = prev_predict_world->last_frame; !P_IsFrameNil(tmp); tmp = tmp->prev) + // // { + // // if (tmp->time_ns >= V.blend_time_ns && tmp->prev->time_ns <= V.blend_time_ns) + // // { + // // left_predict_frame = tmp->prev; + // // break; + // // } + // // } + + + + + + // if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame)) + // { + // LogDebugF("Missing blend"); + // right_predict_frame = predict_world->last_frame; + // // left_predict_frame = right_predict_frame->prev; + // left_predict_frame = right_predict_frame; + + // DEBUGBREAKABLE; + // } + + // frame->blend_from_tick = left_predict_frame->tick; + // frame->blend_to_tick = right_predict_frame->tick; + + // local_frame = P_PushFrame(frame->local_world, left_predict_frame, left_predict_frame->tick); + // { + // P_Frame *left_sim_frame = left_predict_frame; + // P_Frame *right_sim_frame = right_predict_frame; + + // // P_Frame *left_sim_frame = predict_world->first_frame; + // // P_Frame *right_sim_frame = left_sim_frame->next; + + // // P_Frame *right_sim_frame = P_FrameFromTick(predict_world, first_predict_tick); + // // P_Frame *left_sim_frame = right_sim_frame->prev; + + + // // P_Frame *right_sim_frame = P_FrameFromTick(sim_world, ack - 1); + // // P_Frame *left_sim_frame = right_sim_frame->prev; + + // // P_Frame *right_sim_frame = P_FrameFromTick(sim_world, right_predict_frame->src_tick); + // // P_Frame *left_sim_frame = right_sim_frame->prev; + + // // f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->base_time_ns) / (f64)(right_predict_frame->base_time_ns - left_predict_frame->base_time_ns); + // f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->time_ns) / (f64)(right_predict_frame->time_ns - left_predict_frame->time_ns); + + + + // if (IsInf(blend_t)) + // { + // blend_t = 1; + // } + + + + // for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + // { + // P_Ent *left = ent; + // P_Ent *right = ent; + // // if (ent->sim) + // if (0) + // { + // left = ent; + // right = P_EntFromKey(right_predict_frame, ent->key); + // } + // else + // { + // left = P_EntFromKey(left_sim_frame, ent->key); + // right = P_EntFromKey(right_sim_frame, ent->key); + // } + + // ent->exists = LerpF32(left->exists, right->exists, blend_t); + // if (!P_IsEntNil(right) && right->continuity_gen == left->continuity_gen) + // { + // ent->health = LerpF32(left->health, right->health, blend_t); + // ent->xf.t = LerpVec2(left->xf.t, right->xf.t, blend_t); + // ent->xf.r = SlerpVec2(left->xf.r, right->xf.r, blend_t); + // ent->walk_time_accum_ns = LerpI64(left->walk_time_accum_ns, right->walk_time_accum_ns, blend_t); + // ent->v = LerpVec2(left->v, right->v, blend_t); + // ent->w = LerpF32(left->w, right->w, blend_t); + // } + // } + // } + // } + // else + // { + // local_frame = P_PushFrame(frame->local_world, predict_world->last_frame, predict_world->last_frame->tick); + // } + + + // P_DebugDrawFrame(local_frame); + // } + + + + + + + + + + + + + + + + + + + + + + @@ -4645,30 +4981,31 @@ void V_TickForever(WaveLaneCtx *lane) f64 timeline_span_seconds = TweakFloat("Timeline span", 1, 0.01, 5); i64 timeline_span_ns = NsFromSeconds(timeline_span_seconds); + b32 was_locked = prev_frame->prev_timeline.locked; + b32 was_paused = prev_frame->prev_timeline.paused; + b32 was_showing = prev_frame->prev_timeline.show; + b32 locked = prev_frame->timeline.locked; + b32 paused = prev_frame->timeline.paused; + b32 showing = prev_frame->timeline.show; + // Current frame time marker - if (!V.timeline.paused) + if (!was_paused) { current_marker_time_ns = frame->time_ns - last_timeline_matchup_ns + timeline_start_ns; } - if (V.timeline.locked) + if (locked) { V_PushTimelineMarker(current_marker_time_ns, Color_White, 1); } - b32 was_locked = V.timeline.locked; - b32 locked = frame->held_buttons[Button_R]; - b32 paused = frame->held_buttons[Button_E]; - V.timeline.locked = locked; - V.timeline.paused = paused; - - if (V.timeline.show) + if (showing) { UI_Key timeline_key = UI_KeyF("Timeline box"); UI_Size timeline_width = UI_FNT(120, 1); UI_Size timeline_height = UI_FNT(2, 1); Vec4 tmld_bg = Color_Black; - Vec2 timeline_pos = VEC2(frame->screen_dims.x * 0.5, frame->screen_dims.y * 0.25); + Vec2 timeline_pos = VEC2(frame->screen_dims.x * 0.5, frame->screen_dims.y * 0.75); f32 timeline_opacity = 0.75; f32 marker_opacity = 0.75; @@ -4703,22 +5040,23 @@ void V_TickForever(WaveLaneCtx *lane) } Vec2 marker_offset = Zi; + marker_offset.x = timeline_width.v * 0.5; if (locked) { i64 offset_ns = current_marker_time_ns; - marker_offset.x = -((f64)(offset_ns - timeline_start_ns) / (f64)timeline_span_ns) * timeline_width.v + timeline_width.v * 0.5; + marker_offset.x += -((f64)(offset_ns - timeline_start_ns) / (f64)timeline_span_ns) * timeline_width.v; } //- Build markers Arena *marker_arenas[] = { - V.timeline.transient_markers_arena, - V.timeline.persistent_markers_arena, + V.transient_markers_arena, + V.persistent_markers_arena, }; for (u64 marker_arena_idx = 0; marker_arena_idx < countof(marker_arenas); ++marker_arena_idx) { Arena *marker_arena = marker_arenas[marker_arena_idx]; u64 markers_count = ArenaCount(marker_arena, V_TimelineMarker); - b32 is_transient = marker_arena == V.timeline.transient_markers_arena; + b32 is_transient = marker_arena == V.transient_markers_arena; V_TimelineMarker *markers = ArenaFirst(marker_arena, V_TimelineMarker); for (u64 marker_idx = 0; marker_idx < markers_count; ++marker_idx) { @@ -4768,35 +5106,30 @@ void V_TickForever(WaveLaneCtx *lane) UI_PopCP(UI_TopCP()); } - - i64 reset_span_ns = timeline_span_ns; - if (locked) - { - reset_span_ns = timeline_span_ns * 0.5; - } - - // reset_span_ns = NsFromSeconds(10); - - b32 should_reset = 0; - if (!paused) - { - b32 is_first_ack = prev_frame_ack == 0 && ack != 0; - should_reset = (frame->time_ns - last_timeline_reset_ns > reset_span_ns) || is_first_ack || (locked != was_locked); - } - if (!locked && should_reset) + i64 reset_span_ns = timeline_span_ns * 0.5; + b32 is_first_ack = prev_frame_ack == 0 && ack != 0; + b32 should_reset = ( + !paused && ( + (frame->time_ns - last_timeline_reset_ns > reset_span_ns) || + locked != was_locked || + paused != was_paused || + showing != was_showing || + is_first_ack + ) + ); + if (!locked && should_reset || is_first_ack || showing != was_showing) { last_timeline_matchup_ns = frame->time_ns; - timeline_start_ns = ack_frame->time_ns; + timeline_start_ns = frame->predict_tick_accum * SIM_TICK_INTERVAL_NS; } - if (should_reset) { last_timeline_reset_ns = frame->time_ns; - ResetArena(V.timeline.persistent_markers_arena); + ResetArena(V.persistent_markers_arena); } if (!paused) { - ResetArena(V.timeline.transient_markers_arena); + ResetArena(V.transient_markers_arena); } } @@ -5203,14 +5536,22 @@ void V_TickForever(WaveLaneCtx *lane) case V_CmdKind_toggle_console: { - b32 new = !frame->show_console; - frame->show_console = new; + frame->show_console = !frame->show_console; } break; case V_CmdKind_toggle_timeline: { - b32 new = !V.timeline.show; - V.timeline.show = new; + frame->timeline.show = !frame->timeline.show; + } break; + + case V_CmdKind_pause_timeline: + { + frame->timeline.paused = !frame->timeline.paused; + } break; + + case V_CmdKind_lock_timeline: + { + frame->timeline.locked = !frame->timeline.locked; } break; case V_CmdKind_toggle_fullscreen: diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 9a5e5430..0f541a76 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -12,6 +12,8 @@ X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \ X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \ X(toggle_timeline, Toggle Debug Timeline, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent, .alt = 1 ), ) \ + X(pause_timeline, Pause Debug Timeline, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_E ), ) \ + X(lock_timeline, Lock Debug Timeline, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_R ), ) \ X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ X(toggle_window_topmost, Toggle Window Topmost, V_CmdDescFlag_None, V_HOTKEY( Button_F4 ), ) \ X(tp_player, Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_Q ), ) \ @@ -245,7 +247,9 @@ Struct(V_Frame) NET_Key sim_key; NET_Key desired_sim_key; + f64 target_predict_tick_accum; f64 predict_tick_accum; + f64 blend_tick; i64 blend_from_tick; i64 blend_to_tick; @@ -270,14 +274,8 @@ Struct(V_Ctx) P_EntKey player_key; P_EntKey follow_key; - struct - { - b32 show; - b32 paused; - b32 locked; - Arena *transient_markers_arena; - Arena *persistent_markers_arena; - } timeline; + Arena *transient_markers_arena; + Arena *persistent_markers_arena; i64 panels_count; i64 windows_count; @@ -286,9 +284,6 @@ Struct(V_Ctx) i64 connect_try_ns; - i64 target_blend_time_ns; - i64 blend_time_ns; - // Notifications V_Notif *first_notif; V_Notif *last_notif; diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 1ad7e583..842dd965 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -233,6 +233,13 @@ Enum(V_EditMode) V_EditMode_Tile, }; +Struct(V_Timeline) +{ + b32 show; + b32 paused; + b32 locked; +}; + Struct(V_Affines) { // World <-> screen (raw) @@ -288,6 +295,11 @@ Struct(V_SharedFrame) b32 has_mouse_focus; b32 has_keyboard_focus; + //- Timeline + + V_Timeline prev_timeline; + V_Timeline timeline; + //- Editor state V_EditMode edit_mode;