blending wip

This commit is contained in:
jacob 2026-03-14 18:58:32 -05:00
parent 065aedccc3
commit e1e19d6aca
3 changed files with 349 additions and 40 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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?
// <Delay> = <USER_INTERP_RATIO> * <Tick interval>
// 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?
// // <Delay> = <USER_INTERP_RATIO> * <Tick interval>
// // 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)