timeline wip

This commit is contained in:
jacob 2026-03-13 10:03:45 -05:00
parent 0b808bffea
commit a19c2395ae
6 changed files with 172 additions and 28 deletions

View File

@ -267,7 +267,8 @@ P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent)
result.span = SPR_SpanKeyFromName(Lit("roll")); result.span = SPR_SpanKeyFromName(Lit("roll"));
result.weapon_over = 1; result.weapon_over = 1;
} }
else if (Vec2LenSq(ent->control.move) > (0.01 * 0.01)) // else if (Vec2LenSq(ent->control.move) > (0.01 * 0.01))
else if (0)
{ {
result.span = SPR_SpanKeyFromName(Lit("walk")); result.span = SPR_SpanKeyFromName(Lit("walk"));
if (ent->is_guy) if (ent->is_guy)
@ -1935,6 +1936,7 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
DllQueuePushNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, dst, next, prev); DllQueuePushNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, dst, next, prev);
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin); DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
} }
{
P_Ent *old_next = dst->next; P_Ent *old_next = dst->next;
P_Ent *old_prev = dst->prev; P_Ent *old_prev = dst->prev;
P_Ent *old_next_in_bin = dst->next_in_bin; P_Ent *old_next_in_bin = dst->next_in_bin;
@ -1947,10 +1949,10 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
dst->prev = old_prev; dst->prev = old_prev;
dst->next_in_bin = old_next_in_bin; dst->next_in_bin = old_next_in_bin;
dst->prev_in_bin = old_prev_in_bin; dst->prev_in_bin = old_prev_in_bin;
}
dst->created_at_ns = frame->time_ns; dst->created_at_ns = frame->time_ns;
dst->created_at_tick = frame->tick; dst->created_at_tick = frame->tick;
++frame->ents_count; ++frame->ents_count;
if (!P_tl.is_predicting) if (!P_tl.is_predicting)
{ {
dst->sim = 1; dst->sim = 1;

View File

@ -118,6 +118,8 @@ Struct(P_Ent)
//- Build data //- Build data
u64 continuity_gen;
f32 exists; f32 exists;
b32 sim; b32 sim;

View File

@ -580,6 +580,7 @@ void S_TickForever(WaveLaneCtx *lane)
if (!P_IsEntNil(ent)) if (!P_IsEntNil(ent))
{ {
ent->xf = msg->xf; ent->xf = msg->xf;
ent->continuity_gen += 1;
} }
} break; } break;
//- Prefab //- Prefab
@ -601,6 +602,7 @@ void S_TickForever(WaveLaneCtx *lane)
bot->is_bot = 1; bot->is_bot = 1;
P_SetEntString(bot, Lit("Bot")); P_SetEntString(bot, Lit("Bot"));
} }
bot->continuity_gen += 1;
P_Ent *guy = P_EntFromKey(world_frame, bot->guy); P_Ent *guy = P_EntFromKey(world_frame, bot->guy);
if (!guy->is_guy) if (!guy->is_guy)
{ {
@ -611,6 +613,7 @@ void S_TickForever(WaveLaneCtx *lane)
bot->guy = guy->key; bot->guy = guy->key;
} }
guy->xf = msg->xf; guy->xf = msg->xf;
guy->continuity_gen += 1;
} break; } break;
case P_PrefabKind_GuySpawn: case P_PrefabKind_GuySpawn:
@ -623,6 +626,7 @@ void S_TickForever(WaveLaneCtx *lane)
spawn->is_guy_spawn = 1; spawn->is_guy_spawn = 1;
} }
spawn->xf = msg->xf; spawn->xf = msg->xf;
spawn->continuity_gen += 1;
} break; } break;
} }
P_SpawnEntsFromList(world_frame, ents); P_SpawnEntsFromList(world_frame, ents);

View File

@ -571,6 +571,7 @@ void V_TickForever(WaveLaneCtx *lane)
frame->is_editing = prev_frame->is_editing; frame->is_editing = prev_frame->is_editing;
frame->ui_debug = prev_frame->ui_debug; frame->ui_debug = prev_frame->ui_debug;
frame->show_console = prev_frame->show_console; frame->show_console = prev_frame->show_console;
frame->show_timeline = prev_frame->show_timeline;
frame->look = prev_frame->look; frame->look = prev_frame->look;
frame->fire_presses = prev_frame->fire_presses; frame->fire_presses = prev_frame->fire_presses;
frame->roll_presses = prev_frame->roll_presses; frame->roll_presses = prev_frame->roll_presses;
@ -1619,6 +1620,7 @@ void V_TickForever(WaveLaneCtx *lane)
P_World *predict_world = predict_worlds[cur_predict_world_seq % countof(predict_worlds)]; 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 *prev_predict_world = predict_worlds[MaxI64(cur_predict_world_seq - 1, 0) % countof(predict_worlds)];
P_Frame *predict_frame = predict_world->last_frame; P_Frame *predict_frame = predict_world->last_frame;
{ {
if (predict_world->tiles_hash != sim_world->tiles_hash) if (predict_world->tiles_hash != sim_world->tiles_hash)
@ -1854,22 +1856,35 @@ void V_TickForever(WaveLaneCtx *lane)
// i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor; // i64 target_blend_dt_ns = frame->dt_ns + frame->dt_ns * dilation_factor;
i64 target_blend_dt_ns = frame->dt_ns; i64 target_blend_dt_ns = frame->dt_ns;
i64 blend_dt_ns = frame->dt_ns; i64 blend_dt_ns = frame->dt_ns;
// i64 blend_dt_ns = target_blend_dt_ns;
V.target_blend_time_ns += target_blend_dt_ns; // V.target_blend_time_ns += target_blend_dt_ns;
V.blend_time_ns += blend_dt_ns; V.blend_time_ns += blend_dt_ns;
// How many ticks back in time should the user thread blend between? // How many ticks back in time should the user thread blend between?
// <Delay> = <USER_INTERP_RATIO> * <Tick interval> // <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 // 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);
// 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 (ack != prev_frame_ack) if (ack != prev_frame_ack)
{ {
i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio; i64 delay_ns = SIM_TICK_INTERVAL_NS * interp_ratio;
V.target_blend_time_ns = ack_frame->time_ns - delay_ns; V.target_blend_time_ns = predict_frame->time_ns - delay_ns;
} }
// 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 = 0.0;
// f64 blend_to_target_lerp_rate = 0.05; // f64 blend_to_target_lerp_rate = 0.05;
f64 blend_to_target_lerp_rate = 1;
// f64 blend_to_target_lerp_rate = 1; // 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); 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)) if (AbsI64(V.blend_time_ns - V.target_blend_time_ns) > (SIM_TICK_INTERVAL_NS * interp_ratio * 2))
@ -1878,7 +1893,7 @@ void V_TickForever(WaveLaneCtx *lane)
V.blend_time_ns = V.target_blend_time_ns; V.blend_time_ns = V.target_blend_time_ns;
} }
if (TweakBool("Interpolation enabled", 0)) if (TweakBool("Interpolation enabled", 1))
{ {
P_Frame *left_predict_frame = &P_NilFrame; P_Frame *left_predict_frame = &P_NilFrame;
P_Frame *right_predict_frame = &P_NilFrame; P_Frame *right_predict_frame = &P_NilFrame;
@ -1911,19 +1926,28 @@ void V_TickForever(WaveLaneCtx *lane)
P_World *tmp_right_world = predict_worlds[tmp_right_predict_world_idx]; 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_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_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_right = tmp_right_world->last_frame;
// P_Frame *tmp_left = tmp_left_world->last_frame; // P_Frame *tmp_left = tmp_left_world->last_frame;
// 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 = P_FrameFromTick(tmp_right_world, tmp_right_world->last_frame->base_predict_from); 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); P_Frame *tmp_left = P_FrameFromTick(tmp_left_world, tmp_left_world->last_frame->base_predict_from);
// P_Frame *tmp_right = tmp_right_world->last_frame;
// P_Frame *tmp_left = tmp_left_world->last_frame;
if (tmp_right->base_time_ns >= V.blend_time_ns && tmp_left->base_time_ns <= V.blend_time_ns)
// i64 right_time_ns = tmp_right->base_time_ns;
// i64 left_time_ns = tmp_left->base_time_ns;
i64 right_time_ns = tmp_right->time_ns;
i64 left_time_ns = tmp_left->time_ns;
if (right_time_ns >= V.blend_time_ns && left_time_ns <= V.blend_time_ns)
{ {
right_predict_frame = tmp_right; right_predict_frame = tmp_right;
left_predict_frame = tmp_left; left_predict_frame = tmp_left;
@ -2004,6 +2028,9 @@ void V_TickForever(WaveLaneCtx *lane)
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->base_time_ns) / (f64)(right_predict_frame->base_time_ns - left_predict_frame->base_time_ns);
if (IsInf(blend_t)) if (IsInf(blend_t))
{ {
blend_t = 1; blend_t = 1;
@ -2028,7 +2055,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
ent->exists = LerpF32(left->exists, right->exists, blend_t); ent->exists = LerpF32(left->exists, right->exists, blend_t);
if (!P_IsEntNil(right)) if (!P_IsEntNil(right) && right->continuity_gen == left->continuity_gen)
{ {
ent->health = LerpF32(left->health, right->health, blend_t); ent->health = LerpF32(left->health, right->health, blend_t);
ent->xf.t = LerpVec2(left->xf.t, right->xf.t, blend_t); ent->xf.t = LerpVec2(left->xf.t, right->xf.t, blend_t);
@ -2037,7 +2064,6 @@ void V_TickForever(WaveLaneCtx *lane)
ent->v = LerpVec2(left->v, right->v, blend_t); ent->v = LerpVec2(left->v, right->v, blend_t);
ent->w = LerpF32(left->w, right->w, blend_t); ent->w = LerpF32(left->w, right->w, blend_t);
} }
} }
} }
} }
@ -2814,9 +2840,9 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push test emitter //- Push test emitter
if (frame->held_buttons[Button_F]) // if (frame->held_buttons[Button_F])
// if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F]) // if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F])
// if (0) if (0)
{ {
{ {
V_Emitter emitter = Zi; V_Emitter emitter = Zi;
@ -2876,9 +2902,9 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push test explosion //- Push test explosion
if (frame->held_buttons[Button_G]) // if (frame->held_buttons[Button_G])
// if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G]) // if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G])
// if (0) if (0)
{ {
// Fire // Fire
{ {
@ -4542,6 +4568,108 @@ void V_TickForever(WaveLaneCtx *lane)
UI_PopCP(UI_TopCP()); UI_PopCP(UI_TopCP());
} }
//////////////////////////////
//- Build timeline debug UI
if (frame->show_timeline)
{
UI_Key timeline_key = UI_KeyF("Timeline box");
// FIXME: Remove this
i64 timeline_span_ns = NsFromSeconds(10);
PERSIST i64 last_timeline_switch_ns = 0;
PERSIST i64 timeline_start_ns = 0;
if (frame->time_ns - last_timeline_switch_ns > timeline_span_ns)
{
last_timeline_switch_ns = frame->time_ns;
timeline_start_ns = ack_frame->time_ns;
}
UI_Size timeline_width = UI_FNT(80, 1);
UI_Size timeline_height = UI_FNT(2.5, 1);
Vec4 tmld_bg = Color_Black;
f32 timeline_opacity = 0.75;
Vec2 timeline_pos = VEC2(frame->screen_dims.x * 0.5, frame->screen_dims.y * 0.25);
//- Push markers
Struct(TimelineMarker)
{
TimelineMarker *next;
i64 time_ns;
Vec4 color;
};
TimelineMarker *first_marker = 0;
TimelineMarker *last_marker = 0;
{
// Now frame time
// {
// TimelineMarker *marker = PushStruct(frame->arena, TimelineMarker);
// SllQueuePush(first_marker, last_marker, marker);
// marker->color = Color_White;
// marker->time_ns = frame->time_ns;
// }
// Ack frame time
{
TimelineMarker *marker = PushStruct(frame->arena, TimelineMarker);
SllQueuePush(first_marker, last_marker, marker);
marker->color = Color_Yellow;
marker->time_ns = ack_frame->time_ns;
}
}
// i64 timeline_span_ns = NsFromSeconds(10);
i64 timeline_span_ns = NsFromSeconds(1);
i64 timeline_start_ns = (frame->time_ns / timeline_span_ns) * timeline_span_ns;
i64 timeline_end_ns = timeline_start_ns + timeline_span_ns;
UI_Size marker_width = UI_FNT(0.5, 1);
UI_Size marker_height = timeline_height;
UI_PushCP(UI_NilKey);
{
UI_Push(Tint, VEC4(1, 1, 1, timeline_opacity));
//- Build timeline
{
UI_SetNext(Anchor, UI_Region_Top);
UI_SetNext(Width, timeline_width);
UI_SetNext(Height, timeline_height);
UI_SetNext(Anchor, UI_Region_Center);
UI_SetNext(FloatingPos, timeline_pos);
UI_SetNext(BackgroundColor, tmld_bg);
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_PushCP(UI_BuildRowEx(timeline_key));
{
}
UI_PopCP(UI_TopCP());
}
//- Build markers
for (TimelineMarker *marker = first_marker; marker; marker = marker->next)
{
f64 marker_ratio = (f64)(marker->time_ns - timeline_start_ns) / (f64)(timeline_end_ns - timeline_start_ns);
Vec2 marker_pos = timeline_pos;
marker_pos.x += marker_ratio * timeline_width.v;
UI_SetNext(Flags, UI_BoxFlag_Floating);
UI_SetNext(BackgroundColor, marker->color);
UI_SetNext(Anchor, UI_Region_Center);
UI_SetNext(Width, marker_width);
UI_SetNext(Height, marker_height);
UI_SetNext(FloatingPos, marker_pos);
UI_BuildBox();
}
}
UI_PopCP(UI_TopCP());
}
////////////////////////////// //////////////////////////////
//- Build scoreboard UI //- Build scoreboard UI
@ -4948,6 +5076,12 @@ void V_TickForever(WaveLaneCtx *lane)
frame->show_console = new; frame->show_console = new;
} break; } break;
case V_CmdKind_toggle_timeline:
{
b32 new = !frame->show_timeline;
frame->show_timeline = new;
} break;
case V_CmdKind_toggle_fullscreen: case V_CmdKind_toggle_fullscreen:
{ {
b32 new = !window_frame.fullscreen; b32 new = !window_frame.fullscreen;

View File

@ -11,6 +11,7 @@
X(save_level, Save level, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \ X(save_level, Save level, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \ 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_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(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \ 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(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 ), ) \ X(tp_player, Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_Q ), ) \

View File

@ -283,6 +283,7 @@ Struct(V_SharedFrame)
b32 is_editing; b32 is_editing;
b32 ui_debug; b32 ui_debug;
b32 show_console; b32 show_console;
b32 show_timeline;
b32 is_selecting; b32 is_selecting;
b32 is_panning; b32 is_panning;
b32 has_mouse_focus; b32 has_mouse_focus;