From e1e19d6aca49fdc718b010e0a004aa6fffdf8f91 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 14 Mar 2026 18:58:32 -0500 Subject: [PATCH] blending wip --- src/pp/pp.c | 3 - src/pp/pp.h | 7 - src/pp/pp_vis/pp_vis_core.c | 379 +++++++++++++++++++++++++++++++++--- 3 files changed, 349 insertions(+), 40 deletions(-) diff --git a/src/pp/pp.c b/src/pp/pp.c index 98a601dd..7b7c3cf7 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -2070,9 +2070,6 @@ P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick) frame->tick = tick; frame->time_ns = src_frame->time_ns; frame->assembled_at_ns = src_frame->assembled_at_ns; - frame->base_time_ns = src_frame->base_time_ns; - frame->base_predict_from = src_frame->base_predict_from; - frame->base_predict_to = src_frame->base_predict_to; frame->first_ent = &P_NilEnt; frame->last_ent = &P_NilEnt; diff --git a/src/pp/pp.h b/src/pp/pp.h index 89f946ea..e615159b 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -372,13 +372,6 @@ Struct(P_Frame) u64 received_fragments_count; u64 received_fragment_bits[(P_MaxFrameSnapshotFragments + 63) / 64]; i64 assembled_at_ns; - - ////////////////////////////// - //- Prediction state - - i64 base_time_ns; - i64 base_predict_from; - i64 base_predict_to; }; Struct(P_FrameBin) diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 549cd502..8bab11e1 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -387,13 +387,41 @@ void V_TickForever(WaveLaneCtx *lane) P_World *sim_world = P_AcquireWorld(); - i64 cur_predict_world_seq = 0; - P_World *predict_worlds[V_MaxInterpRatio] = Zi; - for (i64 predict_world_idx = 0; predict_world_idx < countof(predict_worlds); ++predict_world_idx) + + + + + + + + + + // FIXME: Move this + + Struct(V_Prediction) { - predict_worlds[predict_world_idx] = P_AcquireWorld(); + i64 base_time_ns; + i64 predict_from; + i64 predict_to; + P_World *world; + }; + + i64 cur_prediction_seq = 0; + + V_Prediction predictions[V_MaxInterpRatio] = Zi; + for (i64 prediction_idx = 0; prediction_idx < countof(predictions); ++prediction_idx) + { + predictions[prediction_idx].world = P_AcquireWorld(); } + + + + + + + + i64 local_controls_cap = NextPow2U64(SIM_MAX_PING * SIM_TICKS_PER_SECOND); P_Control *local_controls = PushStructs(perm, P_Control, local_controls_cap); @@ -1316,7 +1344,6 @@ void V_TickForever(WaveLaneCtx *lane) } } } - } } } @@ -1433,8 +1460,8 @@ void V_TickForever(WaveLaneCtx *lane) // We cannot simulate backwards 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); + // 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); @@ -1631,21 +1658,32 @@ void V_TickForever(WaveLaneCtx *lane) // P_ClearFrames(sim_world, I64Min, ack - SIM_TICKS_PER_SECOND); // P_ClearFrames(sim_world, I64Min, sim_world->last_frame->tick - 1); + + + // Push prediction if new frame received from server + V_Prediction *cur_prediction = &predictions[cur_prediction_seq % countof(predictions)]; + V_Prediction *prev_prediction = &predictions[MaxI64(cur_prediction_seq - 1, 0) % countof(predictions)]; if (ack != prev_frame_ack) { - ack_frame->base_time_ns = ack_frame->time_ns; - ack_frame->base_predict_from = ack_frame->tick; - ack_frame->base_predict_to = predict_to; - cur_predict_world_seq += 1; + cur_prediction_seq += 1; + prev_prediction = cur_prediction; + cur_prediction = &predictions[cur_prediction_seq % countof(predictions)]; + + cur_prediction->base_time_ns = ack_frame->time_ns; + cur_prediction->predict_from = ack_frame->tick; + cur_prediction->predict_to = predict_to; if (ack != prev_frame_ack) { V_PushTimelineMarker(ack_frame->time_ns, Color_Green, 0); } } + + + + // Predict - P_World *predict_world = predict_worlds[cur_predict_world_seq % countof(predict_worlds)]; - P_World *prev_predict_world = predict_worlds[MaxI64(cur_predict_world_seq - 1, 0) % countof(predict_worlds)]; + P_World *predict_world = cur_prediction->world; P_Frame *predict_frame = predict_world->last_frame; { if (predict_world->tiles_hash != sim_world->tiles_hash) @@ -1717,11 +1755,6 @@ void V_TickForever(WaveLaneCtx *lane) - - - - - P_Frame *prev_local_frame = prev_frame->local_world->last_frame; P_Frame *local_frame = &P_NilFrame; { @@ -1740,6 +1773,7 @@ void V_TickForever(WaveLaneCtx *lane) // 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); f32 interp_ratio = TweakFloat("Interpolation ratio", 1.2, 0, V_MaxInterpRatio); // { @@ -1769,7 +1803,7 @@ void V_TickForever(WaveLaneCtx *lane) - V_PushTimelineMarker(target_blend_tick * SIM_TICK_INTERVAL_NS, Color_Cyan, 1); + // V_PushTimelineMarker(target_blend_tick * SIM_TICK_INTERVAL_NS, Color_Cyan, 1); V_PushTimelineMarker(frame->blend_tick * SIM_TICK_INTERVAL_NS, Color_Orange, 1); if (TweakBool("Interpolation enabled", 1)) @@ -1780,9 +1814,9 @@ void V_TickForever(WaveLaneCtx *lane) // Locate left & right frames { 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 prediction_seq = cur_prediction_seq; + prediction_seq >= MaxI64(cur_prediction_seq - countof(predictions), 0); + --prediction_seq ) { b32 should_search_right = P_IsFrameNil(right_predict_frame); @@ -1791,8 +1825,9 @@ void V_TickForever(WaveLaneCtx *lane) // Locate right frame if (should_search_right) { - i64 tmp_world_idx = predict_world_seq % countof(predict_worlds); - P_World *tmp_world = predict_worlds[tmp_world_idx]; + i64 tmp_prediction_idx = prediction_seq % countof(predictions); + V_Prediction *prediction = &predictions[tmp_prediction_idx]; + P_World *tmp_world = prediction->world; 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; @@ -1807,8 +1842,9 @@ void V_TickForever(WaveLaneCtx *lane) // Locate left frame if (should_search_left) { - i64 tmp_world_idx = (predict_world_seq - 1) % countof(predict_worlds); - P_World *tmp_world = predict_worlds[tmp_world_idx]; + i64 tmp_prediction_idx = MaxI64((prediction_seq - 1), 0) % countof(predictions); + V_Prediction *prediction = &predictions[tmp_prediction_idx]; + P_World *tmp_world = prediction->world; 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) @@ -1861,12 +1897,40 @@ void V_TickForever(WaveLaneCtx *lane) // P_Frame *right_sim_frame = P_FrameFromTick(sim_world, right_predict_frame->src_tick); // P_Frame *left_sim_frame = right_sim_frame->prev; + + + + + + + // P_Frame *left_sim_frame = P_FrameFromTick(prev_predict_world, left_predict_frame->base_predict_from); + // P_Frame *right_sim_frame = P_FrameFromTick(predict_world, right_predict_frame->base_predict_from); + + // P_Frame *left_sim_frame = P_FrameFromTick(prev_predict_world, left_predict_frame->base_predict_to); + // P_Frame *right_sim_frame = P_FrameFromTick(predict_world, right_predict_frame->base_predict_to); + + + + + // V_PushTimelineMarker(left_predict_frame->base_predict_from * SIM_TICK_INTERVAL_NS, Color_Yellow, 1); + // V_PushTimelineMarker(right_predict_frame->base_predict_from * SIM_TICK_INTERVAL_NS, Color_Yellow, 1); + + + + + + + + + + + + + // 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)(frame->blend_tick - left_predict_frame->tick) / (f64)(right_predict_frame->tick - left_predict_frame->tick); - - if (IsInf(blend_t)) { blend_t = 1; @@ -1881,7 +1945,7 @@ void V_TickForever(WaveLaneCtx *lane) // if (ent->sim) if (0) { - left = ent; + left = P_EntFromKey(left_predict_frame, ent->key); right = P_EntFromKey(right_predict_frame, ent->key); } else @@ -1927,6 +1991,261 @@ 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); + + // // Warm start + // 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); + // f32 interp_ratio = TweakFloat("Interpolation ratio", 1.2, 0, V_MaxInterpRatio); + + // // { + // // frame->blend_tick = frame->predict_tick_accum - interp_ratio; + // // } + + // f64 target_blend_tick = frame->predict_tick_accum - interp_ratio; + // { + // f64 lerp_rate = 5.0 * frame->dt; + // lerp_rate = SaturateF64(lerp_rate); + // frame->blend_tick = LerpF64(frame->blend_tick, target_blend_tick, lerp_rate); + // if ((prev_frame_ack == 0 && ack != 0) || AbsF64(frame->blend_tick - ack) > SIM_TICKS_PER_SECOND) + // { + // frame->blend_tick = target_blend_tick; + // LogDebugF("Blend reset"); + // } + // } + + + + + + + + + + + + + // // V_PushTimelineMarker(target_blend_tick * SIM_TICK_INTERVAL_NS, Color_Cyan, 1); + // V_PushTimelineMarker(frame->blend_tick * SIM_TICK_INTERVAL_NS, Color_Orange, 1); + + // if (TweakBool("Interpolation enabled", 1)) + // { + // P_Frame *left_predict_frame = &P_NilFrame; + // P_Frame *right_predict_frame = &P_NilFrame; + + // // Locate left & right frames + // { + // for ( + // i64 prediction_seq = cur_prediction_seq; + // prediction_seq >= MaxI64(cur_prediction_seq - countof(predict_worlds), 0); + // --prediction_seq + // ) + // { + // b32 should_search_right = P_IsFrameNil(right_predict_frame); + // b32 should_search_left = P_IsFrameNil(left_predict_frame); + + // // Locate right frame + // if (should_search_right) + // { + // i64 tmp_world_idx = prediction_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 (should_search_left) + // { + // i64 tmp_world_idx = MaxI64((prediction_seq - 1), 0) % 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 (!should_search_right && !should_search_left) + // { + // 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; + + // V_PushTimelineMarker(frame->blend_tick * SIM_TICK_INTERVAL_NS, Color_Red, 0); + // } + // } + + + // 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; + + + + + + + + // // P_Frame *left_sim_frame = P_FrameFromTick(prev_predict_world, left_predict_frame->base_predict_from); + // // P_Frame *right_sim_frame = P_FrameFromTick(predict_world, right_predict_frame->base_predict_from); + + // // P_Frame *left_sim_frame = P_FrameFromTick(prev_predict_world, left_predict_frame->base_predict_to); + // // P_Frame *right_sim_frame = P_FrameFromTick(predict_world, right_predict_frame->base_predict_to); + + + + + // V_PushTimelineMarker(left_predict_frame->base_predict_from * SIM_TICK_INTERVAL_NS, Color_Yellow, 1); + // V_PushTimelineMarker(right_predict_frame->base_predict_from * SIM_TICK_INTERVAL_NS, Color_Yellow, 1); + + + + + + + + + + + + + + // // 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)(frame->blend_tick - left_predict_frame->tick) / (f64)(right_predict_frame->tick - left_predict_frame->tick); + + // 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 = P_EntFromKey(left_predict_frame, ent->key); + // 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); + // } + + + + + + + + + + + + + + + + @@ -4333,7 +4652,7 @@ void V_TickForever(WaveLaneCtx *lane) } if (is_locked) { - V_PushTimelineMarker(current_marker_time_ns, Color_White, 1); + // V_PushTimelineMarker(current_marker_time_ns, Color_White, 1); } if (is_showing)