diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 646b0f25..549cd502 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -403,6 +403,7 @@ void V_TickForever(WaveLaneCtx *lane) i64 prev_snapshot_sent_at_ns = 0; i64 known_sim_tick = 0; i64 remote_buffered_controls_count = 0; + f64 smoothed_remote_buffered_controls_count = 0; // Which tick snapshots we have received and finished assembling from the server i64 ack = 0; @@ -410,7 +411,8 @@ void V_TickForever(WaveLaneCtx *lane) i64 ack_received_at_ns = 0; i64 ack_dt_ns = 0; - f64 most_recent_rtt = 0; + f64 rtt = 0; + f64 prev_rtt = 0; // i64 smoothed_rtt_ns = 0; f64 smoothed_rtt = 0.0; // f64 smoothed_rtt = 0.300; @@ -1058,7 +1060,7 @@ void V_TickForever(WaveLaneCtx *lane) { frame->camera_lerp_rate = 15.0 * frame->dt; } - frame->camera_lerp_rate = ClampF32(frame->camera_lerp_rate, 0, 1); + frame->camera_lerp_rate = SaturateF32(frame->camera_lerp_rate); frame->camera_pos = LerpVec2(prev_frame->camera_pos, target_camera_pos, frame->camera_lerp_rate); frame->camera_zoom = LerpF32(prev_frame->camera_zoom, target_camera_zoom, frame->camera_lerp_rate); } @@ -1246,7 +1248,8 @@ void V_TickForever(WaveLaneCtx *lane) P_Control *acked_control = &local_controls[remote_ack % local_controls_cap]; if (acked_control->tick == remote_ack) { - most_recent_rtt = SecondsFromNs(frame->time_ns - acked_control->produced_at_ns); + prev_rtt = rtt; + rtt = SecondsFromNs(frame->time_ns - acked_control->produced_at_ns); } } @@ -1319,11 +1322,23 @@ void V_TickForever(WaveLaneCtx *lane) } ////////////////////////////// - //- Compute smoothed rtt + //- Compute smoothed rtt info + // Rtt time { - f64 change_rate = 1.0 * frame->dt; - smoothed_rtt = LerpF64(smoothed_rtt, most_recent_rtt, change_rate); + f64 lerp_rate = 1.0 * frame->dt; + smoothed_rtt = LerpF64(smoothed_rtt, rtt, SaturateF64(lerp_rate)); + if (rtt != 0 && prev_rtt == 0) + { + smoothed_rtt = prev_rtt; + } + } + + // Buffered controls + { + f64 rtt_bias_factor = 1; + f64 lerp_rate = frame->dt / (smoothed_rtt * rtt_bias_factor); + smoothed_remote_buffered_controls_count = LerpF64(smoothed_remote_buffered_controls_count, remote_buffered_controls_count, SaturateF64(lerp_rate)); } ////////////////////////////// @@ -1369,13 +1384,6 @@ void V_TickForever(WaveLaneCtx *lane) } } - - - - - - - ////////////////////////////// //- Determine local simulation bounds // @@ -1390,138 +1398,47 @@ 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 on hand + i64 target_buffered_controls_count = 2; - // 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; + // Compute target prediction tick + { + dilation_factor = SmoothstepF64( + -SIM_TICKS_PER_SECOND, + SIM_TICKS_PER_SECOND, + target_buffered_controls_count - smoothed_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; + } - 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; + // Compute prediction tick + { + frame->predict_tick_accum += frame->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; + // f64 lerp_rate = 5.0 * frame->dt; + // f64 lerp_rate = 1.0 * frame->dt; + f64 lerp_rate = 1; - // Warm start - frame->predict_tick_accum += frame->dt * SIM_TICKS_PER_SECOND; + frame->predict_tick_accum = LerpF64(frame->predict_tick_accum, frame->target_predict_tick_accum, SaturateF64(lerp_rate)); + } - 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) + if ((ack == 0 && prev_frame_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("Prediction 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) - // ); - + // 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); } 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 @@ -1682,39 +1599,11 @@ void V_TickForever(WaveLaneCtx *lane) } P_Frame *ack_frame = P_FrameFromTick(sim_world, ack); + V_PushTimelineMarker(ack_frame->time_ns, Color_Green, 1); ////////////////////////////// //- Predict - - // TODO: Only predict when new sim snapshot is received - - - - - // P_Frame *predict_frame = &P_NilFrame; - // { - // if (predict_world->tiles_hash != sim_world->tiles_hash) - // { - // predict_world->tiles_hash = sim_world->tiles_hash; - // CopyStructs(predict_world->tiles, sim_world->tiles, P_TilesCount); - // } - // predict_world->seed = sim_world->seed; - - // P_ClearFrames(predict_world, I64Min, I64Max); - // predict_frame = P_PushFrame(predict_world, sim_world->last_frame, sim_world->last_frame->tick); - // P_DebugDrawFrame(predict_frame); - - // predict_frame = predict_world->last_frame; - // } - - - - - - - - i64 first_predict_tick = 0; i64 last_predict_tick = 0; { @@ -1725,8 +1614,6 @@ void V_TickForever(WaveLaneCtx *lane) // first_predict_tick = MaxI64(first_predict_tick, last_predict_tick - max_predict_ticks); } - - // TODO: Remove this // TODO: Delete all frames except for prediction base & remote ack // TODO: Limit max sim frames stored @@ -1744,8 +1631,6 @@ 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); - - if (ack != prev_frame_ack) { ack_frame->base_time_ns = ack_frame->time_ns; @@ -1758,16 +1643,9 @@ void V_TickForever(WaveLaneCtx *lane) } } - - - - - // 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_Frame *predict_frame = predict_world->last_frame; { if (predict_world->tiles_hash != sim_world->tiles_hash) @@ -1827,166 +1705,6 @@ void V_TickForever(WaveLaneCtx *lane) V_PushTimelineMarker(predict_frame->time_ns, Color_Purple, 1); } - - - - - - - - - - - // // Predict - // P_Frame *predict_frame = &P_NilFrame; - // { - // if (predict_world->tiles_hash != sim_world->tiles_hash) - // { - // predict_world->tiles_hash = sim_world->tiles_hash; - // CopyStructs(predict_world->tiles, sim_world->tiles, P_TilesCount); - // } - // predict_world->seed = sim_world->seed; - - - - // // P_ClearFrames(predict_world, I64Min, I64Max); - // // predict_frame = P_PushFrame(predict_world, sim_world->last_frame, sim_world->last_frame->tick); - - // // FIXME: Not like this - // i64 max_predict_ticks = SIM_TICKS_PER_SECOND; - - // i64 last_predict_tick = frame->predict_to; - // i64 first_predict_tick = sim_world->last_frame->tick; - // first_predict_tick = MaxI64(first_predict_tick, last_predict_tick - max_predict_ticks); - - // P_ClearFrames(predict_world, I64Min, first_predict_tick - 1); - // predict_frame = P_PushFrame(predict_world, sim_world->last_frame, first_predict_tick); - - // for (i64 predict_tick = first_predict_tick + 1; predict_tick <= last_predict_tick; ++predict_tick) - // { - // predict_frame = P_PushFrame(predict_world, predict_world->last_frame, predict_tick); - - // P_Ent *predict_player = P_EntFromKey(predict_frame, local_player->key); - // if (!P_IsEntNil(predict_player)) - // { - // P_Control *predict_control = &local_controls[predict_tick % local_controls_cap]; - // if (predict_control->tick == predict_tick) - // { - // predict_player->control = *predict_control; - // } - // } - - // P_StepFrame(predict_frame); - // } - - // predict_frame = predict_world->last_frame; - // P_DebugDrawFrame(predict_frame); - - // // TODO: Extract information that occurred between first & last prediction, like bullet hits etc? - // } - - - - - - - - // ////////////////////////////// - // //- Update corrected world - - - - // P_Frame *correct_frame = &P_NilFrame; - // { - // if (correct_world->tiles_hash != predict_world->tiles_hash) - // { - // correct_world->tiles_hash = predict_world->tiles_hash; - // CopyStructs(correct_world->tiles, predict_world->tiles, P_TilesCount); - // tiles_dirty = 1; - // } - // correct_world->seed = predict_world->seed; - - // P_ClearFrames(correct_world, I64Min, I64Max); - // correct_frame = P_PushFrame(correct_world, predict_world->last_frame, predict_world->last_frame->tick); - // } - - - - - - // // P_Frame *correct_frame = correct_world->last_frame; - // // { - // // if (correct_world->tiles_hash != predict_world->tiles_hash) - // // { - // // correct_world->tiles_hash = predict_world->tiles_hash; - // // CopyStructs(correct_world->tiles, predict_world->tiles, P_TilesCount); - // // } - // // correct_world->seed = predict_world->seed; - - // // if (correct_world->last_frame->tick != predict_frame->tick) - // // { - // // correct_frame = P_PushFrame(correct_world, correct_world->last_frame, predict_frame->tick); - // // } - - // // // P_ClearFrames(correct_world, I64Min, correct_world->last_frame->tick - 1); - // // // P_Frame *prev_correct_frame = correct_world->last_frame; - - // // { - // // f32 correction_rate = 1; - // // // f32 correction_rate = 30 * frame->dt; - // // P_EntList spawn_ents = Zi; - // // for (P_Ent *predict_ent = P_FirstEnt(predict_frame); !P_IsEntNil(predict_ent); predict_ent = P_NextEnt(predict_ent)) - // // { - // // P_Ent *correct_ent = P_EntFromKey(correct_frame, predict_ent->key); - // // if (P_IsEntNil(correct_ent)) - // // { - // // correct_ent = P_PushTempEnt(frame->arena, &spawn_ents); - // // *correct_ent = *predict_ent; - // // } - // // else - // // { - // // // TODO: Unified blend logic between local world & correct world - // // correct_ent->af = LerpAffine(correct_ent->af, predict_ent->af, correction_rate); - // // correct_ent->solved_v = LerpVec2(correct_ent->solved_v, predict_ent->solved_v, correction_rate); - // // correct_ent->solved_w = LerpF32(correct_ent->solved_w, predict_ent->solved_w, correction_rate); - // // } - // // } - // // P_SpawnEntsFromList(correct_frame, spawn_ents); - // // } - - // // // Prune ents - // // { - // // i64 ents_to_prune_count = 0; - // // P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, correct_frame->ents_count); - // // for (P_Ent *ent = P_FirstEnt(correct_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) - // // { - // // if (ent->exists <= 0 || P_IsEntNil(P_EntFromKey(predict_frame, ent->key))) - // // { - // // ents_to_prune[ents_to_prune_count] = ent; - // // ents_to_prune_count += 1; - // // } - // // } - // // for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx) - // // { - // // P_Ent *ent = ents_to_prune[prune_idx]; - // // P_EntBin *bin = &correct_frame->ent_bins[ent->key.v % correct_frame->ent_bins_count]; - // // DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin); - // // DllQueueRemoveNPZ(&P_NilEnt, correct_frame->first_ent, correct_frame->last_ent, ent, next, prev); - // // correct_frame->ents_count -= 1; - // // SllStackPush(correct_world->first_free_ent, ent); - // // } - // // } - - - // // // P_Frame *prev_correct_frame = P_PushFrame(correct_world, predict_world->last_frame, predict_world->last_frame->tick); - - // // P_DebugDrawFrame(correct_frame); - // // } - - - - - ////////////////////////////// //- Update local world @@ -2016,6 +1734,7 @@ void V_TickForever(WaveLaneCtx *lane) 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? @@ -2023,14 +1742,42 @@ void V_TickForever(WaveLaneCtx *lane) // 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); - frame->blend_tick = frame->predict_tick_accum - interp_ratio; + // { + // 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 right & left frames + // Locate left & right frames { for ( i64 predict_world_seq = cur_predict_world_seq; @@ -2038,11 +1785,11 @@ void V_TickForever(WaveLaneCtx *lane) --predict_world_seq ) { - b32 search_right = P_IsFrameNil(right_predict_frame); - b32 search_left = P_IsFrameNil(left_predict_frame); + b32 should_search_right = P_IsFrameNil(right_predict_frame); + b32 should_search_left = P_IsFrameNil(left_predict_frame); // Locate right frame - if (search_right) + if (should_search_right) { i64 tmp_world_idx = predict_world_seq % countof(predict_worlds); P_World *tmp_world = predict_worlds[tmp_world_idx]; @@ -2058,7 +1805,7 @@ void V_TickForever(WaveLaneCtx *lane) } // Locate left frame - if (search_left) + if (should_search_left) { i64 tmp_world_idx = (predict_world_seq - 1) % countof(predict_worlds); P_World *tmp_world = predict_worlds[tmp_world_idx]; @@ -2075,7 +1822,7 @@ void V_TickForever(WaveLaneCtx *lane) // V_PushTimelineMarker(left_time_ns, Color_Cyan, 1); // V_PushTimelineMarker(right_time_ns, Color_Orange, 1); - if (!search_right && !search_left) + if (!should_search_right && !should_search_left) { break; } @@ -2085,13 +1832,9 @@ void V_TickForever(WaveLaneCtx *lane) { 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); } } @@ -2188,412 +1931,6 @@ 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); - // } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // 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 blend_dt_ns = frame->dt_ns; - - // 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, 5); - // if (predict_to != prev_frame_predict_to) - // { - // i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; - // V.target_blend_time_ns = predict_world->last_frame->time_ns - delay_ns; - // } - - // f64 blend_to_target_lerp_rate = 0.05; - // 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; - // } - - // 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; - // } - // } - - // if (P_IsFrameNil(left_predict_frame) || P_IsFrameNil(right_predict_frame)) - // { - // right_predict_frame = predict_world->last_frame; - // left_predict_frame = right_predict_frame->prev; - // } - - // 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); - // { - // f64 blend_t = (f64)(V.blend_time_ns - left_predict_frame->time_ns) / (f64)(right_predict_frame->time_ns - left_predict_frame->time_ns); - - // // 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(sim_world, ack); - // P_Frame *left_sim_frame = right_sim_frame->prev; - - // 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)) - // { - // 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); - // } @@ -4978,27 +4315,28 @@ void V_TickForever(WaveLaneCtx *lane) PERSIST i64 timeline_start_ns = 0; PERSIST i64 current_marker_time_ns = 0; - 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; + b32 is_locked = prev_frame->timeline.locked; + b32 is_paused = prev_frame->timeline.paused; + b32 is_showing = prev_frame->timeline.show; + + f64 unlocked_timeline_span_seconds = 2; + f64 locked_timeline_span_seconds = 1; + i64 timeline_span_ns = NsFromSeconds(is_locked ? locked_timeline_span_seconds : unlocked_timeline_span_seconds); // Current frame time marker if (!was_paused) { current_marker_time_ns = frame->time_ns - last_timeline_matchup_ns + timeline_start_ns; } - if (locked) + if (is_locked) { V_PushTimelineMarker(current_marker_time_ns, Color_White, 1); } - if (showing) + if (is_showing) { UI_Key timeline_key = UI_KeyF("Timeline box"); @@ -5041,7 +4379,7 @@ void V_TickForever(WaveLaneCtx *lane) Vec2 marker_offset = Zi; marker_offset.x = timeline_width.v * 0.5; - if (locked) + if (is_locked) { i64 offset_ns = current_marker_time_ns; marker_offset.x += -((f64)(offset_ns - timeline_start_ns) / (f64)timeline_span_ns) * timeline_width.v; @@ -5109,15 +4447,15 @@ void V_TickForever(WaveLaneCtx *lane) i64 reset_span_ns = timeline_span_ns * 0.5; b32 is_first_ack = prev_frame_ack == 0 && ack != 0; b32 should_reset = ( - !paused && ( + !is_paused && ( (frame->time_ns - last_timeline_reset_ns > reset_span_ns) || - locked != was_locked || - paused != was_paused || - showing != was_showing || + is_locked != was_locked || + is_paused != was_paused || + is_showing != was_showing || is_first_ack ) ); - if (!locked && should_reset || is_first_ack || showing != was_showing) + if (!is_locked && should_reset || is_first_ack || is_showing != was_showing) { last_timeline_matchup_ns = frame->time_ns; timeline_start_ns = frame->predict_tick_accum * SIM_TICK_INTERVAL_NS; @@ -5127,7 +4465,7 @@ void V_TickForever(WaveLaneCtx *lane) last_timeline_reset_ns = frame->time_ns; ResetArena(V.persistent_markers_arena); } - if (!paused) + if (!is_paused) { ResetArena(V.transient_markers_arena); }