From 92ed9a4c2d3c2d53e1ca553b799c0b49f995cee4 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 4 Apr 2026 16:30:30 -0500 Subject: [PATCH] fire animation. colored guys. --- src/base/base_string.c | 17 ++- src/base/base_string.h | 1 + src/pp/pp.c | 121 +++++++++++----- src/pp/pp.h | 19 ++- src/pp/pp.lay | 1 + src/pp/pp_res/guy/guy.ase | 4 +- src/pp/pp_res/guy/legs.ase | 4 +- src/pp/pp_res/wep/uzi.ase | 4 +- src/pp/pp_sim/pp_sim_core.c | 14 +- src/pp/pp_terms.h | 81 +++++++++++ src/pp/pp_vis/pp_vis_core.c | 246 ++++++++++++++++++-------------- src/pp/pp_vis/pp_vis_core.h | 3 - src/pp/pp_vis/pp_vis_gpu.g | 5 + src/pp/pp_vis/pp_vis_shared.cgh | 1 + 14 files changed, 367 insertions(+), 154 deletions(-) create mode 100644 src/pp/pp_terms.h diff --git a/src/base/base_string.c b/src/base/base_string.c index 0749b2a6..6a594f45 100644 --- a/src/base/base_string.c +++ b/src/base/base_string.c @@ -408,7 +408,6 @@ String LowerString(Arena *arena, String str) String result = Zi; result.text = PushStructsNoZero(arena, u8, str.len); result.len = str.len; - for (u64 i = 0; i < str.len; ++i) { u8 c = str.text[i]; @@ -418,7 +417,23 @@ String LowerString(Arena *arena, String str) } result.text[i] = c; } + return result; +} +String UpperString(Arena *arena, String str) +{ + String result = Zi; + result.text = PushStructsNoZero(arena, u8, str.len); + result.len = str.len; + for (u64 i = 0; i < str.len; ++i) + { + u8 c = str.text[i]; + if (97 <= c && c <= 122) + { + c -= 32; + } + result.text[i] = c; + } return result; } diff --git a/src/base/base_string.h b/src/base/base_string.h index e01c56d6..4e5bcdf9 100644 --- a/src/base/base_string.h +++ b/src/base/base_string.h @@ -100,6 +100,7 @@ StringArray SplitString(Arena *arena, String str, String delim); String ReplaceString(Arena *arena, String str, String old_pattern, String new_pattern); String IndentString(Arena *arena, String str, u32 indent); String LowerString(Arena *arena, String str); +String UpperString(Arena *arena, String str); b32 MatchString(String str1, String str2); b32 StringContains(String str, String substring); b32 StringBeginsWith(String str, String substring); diff --git a/src/pp/pp.c b/src/pp/pp.c index 6986cae4..ef27b1a4 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -267,56 +267,97 @@ P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent) // TODO: Determine animation dynamically i64 animation_rate_ns = NsFromSeconds(0.050); - i64 animation_time_ns = frame->time_ns; + i64 body_animation_time_ns = frame->time_ns; + i64 legs_animation_time_ns = frame->time_ns; + i64 wep_animation_time_ns = frame->time_ns; { - // result.span = SPR_SpanKeyFromName(Lit("test")); + b32 is_rolling = P_IsEntRolling(frame, ent); + // b32 is_shooting = ent->is_guy && ((frame->time_ns - MaxI64(wep->last_fire_ns, wep->last_alt_fire_ns)) < animation_rate_ns); + b32 is_shooting = ent->is_guy && ((frame->time_ns - MaxI64(wep->last_fire_ns, wep->last_alt_fire_ns)) < (animation_rate_ns * 2)); + b32 is_walking = !is_rolling && Vec2LenSq(ent->control.move) > (0.01 * 0.01); + + // is_shooting = 1; - if (P_IsEntRolling(frame, ent)) { - result.span = SPR_SpanKeyFromName(Lit("roll")); - result.weapon_over = 1; - } - else if (Vec2LenSq(ent->control.move) > (0.01 * 0.01)) - { - result.span = SPR_SpanKeyFromName(Lit("walk")); - if (ent->is_guy) + result.body_span = SPR_SpanKeyFromName(Lit("idle")); + result.legs_span = SPR_SpanKeyFromName(Lit("idle")); + result.wep_span = SPR_SpanKeyFromName(Lit("idle")); + + // if (is_shooting) + // { + // animation_rate_ns = NsFromSeconds(0.001); + // } + + + // Body + if (is_rolling) + { + result.body_span = SPR_SpanKeyFromName(Lit("roll")); + result.weapon_over = 1; + } + else if (is_shooting) + { + result.body_span = SPR_SpanKeyFromName(Lit("shoot")); + // body_animation_time_ns = SaturateF32(NsFromSeconds(1.0 / wep->last_fire_rate)); + } + else if (is_walking) + { + result.body_span = SPR_SpanKeyFromName(Lit("walk")); + body_animation_time_ns = ent->walk_time_accum_ns; + } + + // Legs + if (is_rolling) { result.legs_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("guy/legs.ase"))); - animation_time_ns = ent->walk_time_accum_ns; + result.legs_span = SPR_SpanKeyFromName(Lit("roll")); + // legs_animation_time_ns = ent->walk_time_accum_ns; + } + else if (is_walking) + { + result.legs_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("guy/legs.ase"))); + result.legs_span = SPR_SpanKeyFromName(Lit("walk")); + legs_animation_time_ns = ent->walk_time_accum_ns; + } + + // Weapon + if (is_shooting) + { + result.wep_span = SPR_SpanKeyFromName(Lit("shoot")); + // legs_animation_time_ns = SaturateF32(NsFromSeconds(1.0 / wep->last_fire_rate)); } - } - else - { - result.span = SPR_SpanKeyFromName(Lit("idle")); } } + result.body_frame_seq = body_animation_time_ns / animation_rate_ns; + result.legs_frame_seq = legs_animation_time_ns / animation_rate_ns; + result.wep_frame_seq = wep_animation_time_ns / animation_rate_ns; // TODO: Use prefab lookup if (ent->is_guy) { - result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("guy/guy.ase"))); + result.body_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("guy/guy.ase"))); } else if (ent->is_guy_spawn) { - result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("prefab/GuySpawn.ase"))); + result.body_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("prefab/GuySpawn.ase"))); } else if (ent->is_health_spawn) { - result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("prefab/HealthSpawn.ase"))); + result.body_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("prefab/HealthSpawn.ase"))); } else if (ent->is_bomb) { - result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("misc/bomb.ase"))); + result.body_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("misc/bomb.ase"))); } else if (ent->is_health) { - result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("misc/health.ase"))); + result.body_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("misc/health.ase"))); } else if (ent->is_health) { - result.sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("misc/health.ase"))); + result.body_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("misc/health.ase"))); } if (wep->is_uzi) @@ -324,8 +365,6 @@ P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent) result.wep_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("wep/uzi.ase"))); } - result.frame_seq = animation_time_ns / animation_rate_ns; - return result; } @@ -2471,12 +2510,13 @@ void P_StepFrame(P_Frame *frame) } ////////////////////////////// - //- Roll guys + //- Accumulate control times for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy)) { if (guy->is_guy) { + // Roll // if (guy->control.roll_presses && !IsVec2Zero(guy->control.move)) if (guy->control.downs[P_Button_Roll]) { @@ -2492,15 +2532,24 @@ void P_StepFrame(P_Frame *frame) guy->last_roll_dir = NormVec2(guy->control.look); } } - - if (!P_IsEntRolling(frame, guy)) - { + // Walk b32 is_moving = Vec2LenSq(guy->control.move) > (0.001 * 0.001); - if (is_moving) + if (is_moving) + { + if (!P_IsEntRolling(frame, guy)) { guy->walk_time_accum_ns += sim_dt_ns; } } + else + { + guy->walk_time_accum_ns = 0; + } + // Fire + if (guy->control.held[P_Button_PrimaryFire] || guy->control.held[P_Button_AltFire]) + { + guy->fire_time_accum_ns += sim_dt_ns; + } } } @@ -3141,8 +3190,9 @@ void P_StepFrame(P_Frame *frame) if (button == P_Button_PrimaryFire && (firer->control.held[button] || firer->control.downs[button])) { // fire_rate = 100; - // bullets_per_fire = 4; - fire_rate = 10; + bullets_per_fire = 4; + // fire_rate = 50; + fire_rate = 50; bullets_per_fire = 1; firing = (weapon->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= frame->time_ns; if (firing) @@ -3180,6 +3230,7 @@ void P_StepFrame(P_Frame *frame) bullet->sim = weapon->sim; } } + weapon->last_fire_rate = fire_rate; } } } @@ -3218,8 +3269,8 @@ void P_StepFrame(P_Frame *frame) // f32 spread = Tau * 0.05; // f32 spread = Tau * 0.2; - // f32 spread = Tau * 0.01; - f32 spread = 0; + f32 spread = Tau * 0.01; + // f32 spread = 0; b32 should_ricochet = 0; @@ -3269,8 +3320,8 @@ void P_StepFrame(P_Frame *frame) { Vec2 look = firer->control.look; P_Anim anim = P_AnimFromEnt(frame, firer); - SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); - SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); + SPR_Sprite body = SPR_SpriteFromSheet(anim.body_sheet, anim.body_span, anim.body_frame_seq); + SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.wep_span, anim.wep_frame_seq); //- Compute sprite transforms Affine ent_to_world_af = MulAffineXform(AffineIdentity, firer->xf); @@ -3742,7 +3793,7 @@ void P_StepFrame(P_Frame *frame) death->key = P_EntKeyFromU64(MixU64s(guy->key.v, P_DeathBasis + (u64)player->deaths)); death->death_pos = guy->xf.t; death->is_death = 1; - death->death_player = player->key; + death->death_victim = player->key; death->death_killer = killer->key; death->lifetime_seconds = P_ObservationDurationSeconds; } diff --git a/src/pp/pp.h b/src/pp/pp.h index ff820c18..69f7c8bd 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -11,6 +11,7 @@ #define P_BulletHitBasis 0xbc70fc783c1c507full #define P_BulletTrailBasis 0x27c011f891c571feull #define P_DeathBasis 0x2e3c75a3286d872aull +#define P_KillfeedBasis 0xd1f84bd6f7c3cf1eull Struct(P_EntKey) { @@ -170,7 +171,7 @@ Struct(P_Ent) b32 is_death; Vec2 death_pos; - P_EntKey death_player; + P_EntKey death_victim; P_EntKey death_killer; //- Bomb @@ -215,11 +216,14 @@ Struct(P_Ent) P_EntKey weapon; Vec2 last_roll_dir; i64 walk_time_accum_ns; + i64 fire_time_accum_ns; i64 last_fire_ns; i64 last_alt_fire_ns; i64 last_roll_ns; + f32 last_fire_rate; + //- Weapon b32 is_weapon; @@ -264,11 +268,18 @@ Struct(P_EntBin) Struct(P_Anim) { - i64 frame_seq; - SPR_SpanKey span; - SPR_SheetKey sheet; + i64 body_frame_seq; + SPR_SpanKey body_span; + SPR_SheetKey body_sheet; + + i64 legs_frame_seq; + SPR_SpanKey legs_span; SPR_SheetKey legs_sheet; + + i64 wep_frame_seq; + SPR_SpanKey wep_span; SPR_SheetKey wep_sheet; + b32 weapon_over; }; diff --git a/src/pp/pp.lay b/src/pp/pp.lay index 32243ab2..062361f8 100644 --- a/src/pp/pp.lay +++ b/src/pp/pp.lay @@ -17,6 +17,7 @@ @IncludeC pp_shared.cgh @IncludeG pp_shared.cgh @IncludeC pp.h +@IncludeC pp_terms.h @IncludeC pp_transcode.h @Bootstrap P_Bootstrap diff --git a/src/pp/pp_res/guy/guy.ase b/src/pp/pp_res/guy/guy.ase index eaf23112..92e20be2 100644 --- a/src/pp/pp_res/guy/guy.ase +++ b/src/pp/pp_res/guy/guy.ase @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:460192b81b4860758ce39630196e61006808cb8cb95508146cfd4e2fa1421e2a -size 9089 +oid sha256:604fc5012cc6dbad654f4e02449cbefeeda506f831c7accdb29b2dff8ecfe2f4 +size 12487 diff --git a/src/pp/pp_res/guy/legs.ase b/src/pp/pp_res/guy/legs.ase index d9f06e03..dc762b74 100644 --- a/src/pp/pp_res/guy/legs.ase +++ b/src/pp/pp_res/guy/legs.ase @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5ab70e7bccb51783818f3523b32b911d71ebedd9c711579084c9e4ef7540c174 -size 4716 +oid sha256:cc16b4e57700b47f4e9eab729e62c5e1a8c2fe038500e129f2e31f320e42f341 +size 5411 diff --git a/src/pp/pp_res/wep/uzi.ase b/src/pp/pp_res/wep/uzi.ase index 0bab1412..8a704ae0 100644 --- a/src/pp/pp_res/wep/uzi.ase +++ b/src/pp/pp_res/wep/uzi.ase @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a928f9225ff9a1d60b181f1ff331194f2da769b61cb43078f11bdd48fe96ad60 -size 549 +oid sha256:4b0f08e395186c694a7a2e7a0a35f021a9271f8192a4fcb6ef1d316b3f12559c +size 574 diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index ae7963e6..14bdf544 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -544,6 +544,7 @@ void S_TickForever(WaveLaneCtx *lane) // FIXME: Only accept edits from privileged users { + u32 bots_count = 0; b32 should_save = 0; for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next) { @@ -604,11 +605,22 @@ void S_TickForever(WaveLaneCtx *lane) P_Ent *bot = P_EntFromKey(world_frame, msg->key); if (!bot->is_bot) { + for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + { + if (ent->is_bot) + { + bots_count += 1; + } + } bot = P_PushTempEnt(frame_arena, &ents); bot->key = msg->key; bot->is_player = 1; bot->is_bot = 1; - P_SetEntString(bot, Lit("Bot")); + { + String bot_name = P_PresetPlayerNames[bots_count % countof(P_PresetPlayerNames)]; + P_SetEntString(bot, bot_name); + } + bots_count += 1; } bot->continuity_gen += 1; P_Ent *guy = P_EntFromKey(world_frame, bot->guy); diff --git a/src/pp/pp_terms.h b/src/pp/pp_terms.h new file mode 100644 index 00000000..78ce7ad2 --- /dev/null +++ b/src/pp/pp_terms.h @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////// +//~ Killfeed terms + +PERSIST Readonly String P_KillTerms[] = { + CompLit("fired"), + CompLit("reprimanded"), + CompLit("outsourced"), + CompLit("reassigned"), + CompLit("laminated"), + CompLit("downsized"), + CompLit("laid off"), + CompLit("terminated"), + CompLit("demoted"), + CompLit("restructured"), + CompLit("shredded"), + CompLit("decommissioned"), + CompLit("finalized"), + CompLit("offboarded"), +}; + +//////////////////////////////////////////////////////////// +//~ Names + +PERSIST Readonly String P_PresetHumanNames[] = { + CompLit("Harold"), + CompLit("Scruffy"), + CompLit("Rusty"), + CompLit("Carlile"), + CompLit("Frank"), + CompLit("Dick"), + CompLit("Rick"), + CompLit("Milton"), + CompLit("Bruce"), + CompLit("Leonard"), + CompLit("Stanley"), + CompLit("Randy"), + CompLit("Walter"), + CompLit("Eugene"), + CompLit("Ron"), + CompLit("Dale"), + CompLit("Keith"), + CompLit("Larry"), + CompLit("Terry"), + CompLit("Don"), + CompLit("Gary"), + CompLit("Greg"), + CompLit("Chester"), + CompLit("Russ"), + CompLit("Ed"), + CompLit("Buck"), +}; + +// Taken from a random GMOD server +PERSIST Readonly String P_PresetPlayerNames[] = { + CompLit("Kirep"), + CompLit("adoti"), + CompLit("TaurusJ3"), + CompLit("dub"), + CompLit("Tidunbly"), + CompLit("Siepter"), + CompLit("frezh"), + CompLit("lowayo"), + CompLit("Zunix"), + CompLit("_Runne_"), + CompLit("Fr0stie"), + CompLit("Mr. Bones"), + CompLit("Lumby"), + CompLit("Legs"), + CompLit("Talids"), + CompLit("yoyota"), + CompLit("Train"), + CompLit("lionberg"), + CompLit("Cyan Crayon"), + CompLit("Poy"), + CompLit("Kaitsedd"), + CompLit("Panda"), + CompLit("THE WIFE"), + CompLit("KARMA"), + CompLit("jiyu"), + CompLit("charlie main"), +}; diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 5b73d054..217e1efd 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -1860,7 +1860,8 @@ void V_TickForever(WaveLaneCtx *lane) // Rtt time { - f64 lerp_rate = 1.0 * frame->dt; + // f64 lerp_rate = 1.0 * frame->dt; + f64 lerp_rate = (1000.0 / 150.0) * frame->dt; smoothed_rtt = LerpF64(smoothed_rtt, rtt, SaturateF64(lerp_rate)); if (rtt != 0 && prev_rtt == 0) { @@ -1960,13 +1961,18 @@ void V_TickForever(WaveLaneCtx *lane) // Compute prediction tick { - frame->predict_tick_accum += frame->dt * SIM_TICKS_PER_SECOND; + // frame->predict_tick_accum += frame->dt * SIM_TICKS_PER_SECOND; + + f32 predict_dt = frame->dt + frame->dt * dilation_factor; + frame->predict_tick_accum += predict_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, SaturateF64(lerp_rate)); + // frame->predict_tick_accum = LerpF64(frame->predict_tick_accum, frame->target_predict_tick_accum, SaturateF64(lerp_rate)); + frame->predict_tick_accum = frame->target_predict_tick_accum; } if ((ack == 0 && prev_frame_ack != 0) || AbsF64(frame->predict_tick_accum - ack) > SIM_TICKS_PER_SECOND) @@ -1977,7 +1983,7 @@ void V_TickForever(WaveLaneCtx *lane) } // We cannot simulate backwards - frame->predict_tick_accum = MaxF64(prev_frame->predict_tick_accum, frame->predict_tick_accum); + // frame->predict_tick_accum = MaxF64(prev_frame->predict_tick_accum, frame->predict_tick_accum); // V_PushTimelineMarker(frame->predict_tick_accum, Color_Red, 1); // V_PushTimelineMarker(frame->target_predict_tick_accum, Color_Yellow, 1); @@ -2270,20 +2276,21 @@ 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 + // f64 interp_ratio = TweakFloat("Interpolation ratio", 1.5, 0, V_MaxInterpRatio); f64 interp_ratio = TweakFloat("Interpolation ratio", 1.5, 0, V_MaxInterpRatio); //- Blended sim tick f64 target_blend_sim_tick = (f64)ack - interp_ratio; { f64 lerp_rate = SaturateF64(5.0 * frame->dt); - frame->blend_sim_tick += frame->dt * SIM_TICKS_PER_SECOND; + // frame->blend_sim_tick += frame->dt * SIM_TICKS_PER_SECOND; + frame->blend_sim_tick += (frame->dt + frame->dt * dilation_factor) * SIM_TICKS_PER_SECOND; + frame->blend_sim_tick = LerpF64(frame->blend_sim_tick, target_blend_sim_tick, lerp_rate); + frame->blend_sim_tick = MaxF64(frame->blend_sim_tick, prev_frame->blend_sim_tick); + if ((prev_frame_ack == 0 && ack != 0) || AbsF64(frame->blend_sim_tick - ack) > SIM_TICKS_PER_SECOND) { - frame->blend_sim_tick = LerpF64(frame->blend_sim_tick, target_blend_sim_tick, lerp_rate); - if ((prev_frame_ack == 0 && ack != 0) || AbsF64(frame->blend_sim_tick - ack) > SIM_TICKS_PER_SECOND) - { - frame->blend_sim_tick = target_blend_sim_tick; - LogDebugF("Sim blend reset"); - } + frame->blend_sim_tick = target_blend_sim_tick; + LogDebugF("Sim blend reset"); } } @@ -2291,14 +2298,14 @@ void V_TickForever(WaveLaneCtx *lane) f64 target_blend_predict_tick = frame->predict_tick_accum - interp_ratio; { f64 lerp_rate = SaturateF64(2.0 * frame->dt); - frame->blend_predict_tick += frame->dt * SIM_TICKS_PER_SECOND; + // frame->blend_predict_tick += frame->dt * SIM_TICKS_PER_SECOND; + frame->blend_predict_tick += (frame->dt + frame->dt * dilation_factor) * SIM_TICKS_PER_SECOND; + frame->blend_predict_tick = LerpF64(frame->blend_predict_tick, target_blend_predict_tick, lerp_rate); + frame->blend_predict_tick = MaxF64(frame->blend_predict_tick, prev_frame->blend_predict_tick); + if ((prev_frame_ack == 0 && ack != 0) || AbsF64(frame->blend_predict_tick - ack) > SIM_TICKS_PER_SECOND) { - frame->blend_predict_tick = LerpF64(frame->blend_predict_tick, target_blend_predict_tick, lerp_rate); - if ((prev_frame_ack == 0 && ack != 0) || AbsF64(frame->blend_predict_tick - ack) > SIM_TICKS_PER_SECOND) - { - frame->blend_predict_tick = target_blend_predict_tick; - LogDebugF("Prediction blend reset"); - } + frame->blend_predict_tick = target_blend_predict_tick; + LogDebugF("Prediction blend reset"); } } @@ -2588,8 +2595,8 @@ void V_TickForever(WaveLaneCtx *lane) P_Ent *ent = local_follow; P_Anim anim = P_AnimFromEnt(local_frame, ent); - SPR_Sprite body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); - SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); + SPR_Sprite body = SPR_SpriteFromSheet(anim.body_sheet, anim.body_span, anim.body_frame_seq); + SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.wep_span, anim.wep_frame_seq); Vec2 look = ent->control.look; if (P_MatchEntKey(ent->key, local_guy->key)) @@ -2876,7 +2883,7 @@ void V_TickForever(WaveLaneCtx *lane) SPR_Sprite body = Zi; Affine body_pix_to_world_af = AffineIdentity; { - body = SPR_SpriteFromSheet(anim.sheet, anim.span, anim.frame_seq); + body = SPR_SpriteFromSheet(anim.body_sheet, anim.body_span, anim.body_frame_seq); body_pix_to_world_af = MulAffine(body_pix_to_world_af, ent_to_world_af); body_pix_to_world_af = ScaleAffine(body_pix_to_world_af, pix_scale); @@ -2890,16 +2897,20 @@ void V_TickForever(WaveLaneCtx *lane) SPR_Sprite legs = Zi; Affine legs_pix_to_world_af = AffineIdentity; { - Vec2 move_dir = NormVec2(ent->control.move); + Vec2 legs_dir = NormVec2(ent->control.move); + if (P_IsEntRolling(local_frame, ent)) + { + legs_dir = ent->xf.r; + } - legs = SPR_SpriteFromSheet(anim.legs_sheet, anim.span, anim.frame_seq); + legs = SPR_SpriteFromSheet(anim.legs_sheet, anim.legs_span, anim.legs_frame_seq); legs_pix_to_world_af = TranslateAffine(legs_pix_to_world_af, ent_to_world_af.og); legs_pix_to_world_af = ScaleAffine(legs_pix_to_world_af, pix_scale); SPR_Ray anchor_ray = legs.rays[SPR_RayKind_Anchor]; legs_pix_to_world_af = RotateAffine(legs_pix_to_world_af, InvertRot(anchor_ray.dir)); - legs_pix_to_world_af = RotateAffine(legs_pix_to_world_af, move_dir); + legs_pix_to_world_af = RotateAffine(legs_pix_to_world_af, legs_dir); legs_pix_to_world_af = TranslateAffine(legs_pix_to_world_af, NegVec2(anchor_ray.pos)); } @@ -2908,7 +2919,7 @@ void V_TickForever(WaveLaneCtx *lane) Affine wep_pix_to_world_af = AffineIdentity; if (ent->is_guy) { - wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.span, anim.frame_seq); + wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.wep_span, anim.wep_frame_seq); wep_pix_to_world_af = MulAffine(wep_pix_to_world_af, ent_to_world_af); wep_pix_to_world_af = ScaleAffine(wep_pix_to_world_af, pix_scale); @@ -2925,6 +2936,27 @@ void V_TickForever(WaveLaneCtx *lane) wep_pix_to_world_af = TranslateAffine(wep_pix_to_world_af, NegVec2(anchor_ray.pos)); } + //- Determine mask colors + Vec4 body_mask_color_lin = Zi; + Vec4 legs_mask_color_lin = Zi; + if (ent->is_guy) + { + f32 body_hue_offset = TweakFloat("Guy body hue offset", 135, 0, 360); + f32 body_s = TweakFloat("Guy body saturation", 0.7, 0, 1); + f32 body_v = TweakFloat("Guy body brightness", 1, 0, 1); + f32 legs_hue_offset = TweakFloat("Guy legs hue offset", 180, 0, 360); + f32 legs_s = TweakFloat("Guy legs saturation", 1, 0, 1); + f32 legs_v = TweakFloat("Guy legs brightness", 1, 0, 1); + { + P_Ent *player = P_EntFromKey(local_frame, ent->source); + u64 color_seed = HashString(P_StringFromEnt(player)); + f32 body_hue = (Norm16(color_seed >> 2) * 1) * 360 + body_hue_offset; + f32 legs_hue = ModF32(body_hue + legs_hue_offset, 360); + body_mask_color_lin = LinearFromSrgb(SrgbFromHsv(body_hue, body_s, body_v)); + legs_mask_color_lin = LinearFromSrgb(SrgbFromHsv(legs_hue, legs_s, legs_v)); + } + } + //- Push weapon quad if (body.ready && wep.ready) { @@ -2946,6 +2978,7 @@ void V_TickForever(WaveLaneCtx *lane) legs_quad.quad_uv_to_world_af = legs_uv_to_world_af; legs_quad.tex = legs.tex; legs_quad.tex_slice_uv = DivRng2Vec2(legs.tex_rect, legs.tex_dims); + legs_quad.mask_color_lin = legs_mask_color_lin; } //- Body quad @@ -2957,6 +2990,7 @@ void V_TickForever(WaveLaneCtx *lane) body_quad.tex_slice_uv = DivRng2Vec2(body.tex_rect, body.tex_dims); if (ent->is_guy) { + body_quad.mask_color_lin = body_mask_color_lin; body_quad.occluder_id = ent->key.v & 0xFFFFFFFF; } } @@ -3407,51 +3441,12 @@ void V_TickForever(WaveLaneCtx *lane) //- Wall impact particles if (material != P_MaterialKind_Flesh) { - // Debris - // { - // V_Emitter emitter = Zi; - // { - // // emitter.flags |= V_ParticleFlag_PruneWhenStill; - // // emitter.flags |= V_ParticleFlag_StainOnPrune; - - - // emitter.kind = V_ParticleKind_Debris; - // emitter.count = 4; - - // emitter.pos.p0 = - // emitter.pos.p1 = hit_entry; - - // emitter.speed.min = 0; - // emitter.speed.max = 20; - - // // emitter.velocity_falloff = 5; - // // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; - - // Vec2 dir = impact_dir; - - // f32 angle = AngleFromVec2(dir); - // f32 angle_spread = Tau * 0.5; - - // emitter.angle.min = angle - angle_spread / 2; - // emitter.angle.max = angle + angle_spread / 2; - - // // emitter.lifetime = 0.25; - // // emitter.lifetime = 0.05; - // // emitter.lifetime = 0.04; - // // emitter.lifetime_spread = emitter.lifetime * 2; - // } - // V_PushParticles(emitter); - // } - // Hot debris { V_Emitter emitter = Zi; emitter.kind = V_ParticleKind_HotDebris; - // emitter.count = MaxF32(1000 * frame->dt, 1); emitter.count = 32; - // f32 angle = AngleFromVec2(SubVec2(p1, p0)); - f32 angle = AngleFromVec2(impact_dir); f32 angle_particle_spread = Tau / 2.5; @@ -3461,30 +3456,36 @@ void V_TickForever(WaveLaneCtx *lane) emitter.pos.p0 = emitter.pos.p1 = impact_pos; - // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); - - // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); - emitter.speed.min = 0; emitter.speed.max = 30; - // emitter.angle.min = angle - angle_spread / 2; - // emitter.angle.max = angle + angle_spread / 2; + V_PushParticles(emitter); + } - // emitter.angle.min = - // emitter.angle.max = angle; - // emitter.pos.p0 = - // emitter.pos.p1 = p0; - // emitter.speed.min = - // emitter.speed.max = - // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); - // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); - // emitter.speed.min = - // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; + //- Wall spark + { + V_Emitter emitter = Zi; + emitter.kind = V_ParticleKind_Spark; + // emitter.count = MaxF32(1000 * frame->dt, 1); + // emitter.count = 128; + emitter.count = 1; + + f32 angle = AngleFromVec2(impact_dir); + + f32 angle_spread = Tau / 2; + emitter.angle.min = angle - angle_spread / 2; + emitter.angle.max = angle + angle_spread / 2; + + emitter.pos.p0 = + emitter.pos.p1 = impact_pos; + + emitter.speed.min = 20; + emitter.speed.max = 100; + V_PushParticles(emitter); } @@ -3494,6 +3495,8 @@ void V_TickForever(WaveLaneCtx *lane) + + // Wall dust { V_Emitter emitter = Zi; @@ -3503,14 +3506,10 @@ void V_TickForever(WaveLaneCtx *lane) emitter.pos.p0 = emitter.pos.p1 = impact_pos; - // emitter.color_lin = LinearFromSrgb(VEC4(0.5, 0.5, 0.5, 0.75)); emitter.speed.min = 1; emitter.speed.max = 20; - // emitter.velocity_falloff = 12; - // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; - Vec2 dir = impact_dir; f32 angle = AngleFromVec2(dir); f32 angle_spread = Tau * 0.1; @@ -3569,6 +3568,30 @@ void V_TickForever(WaveLaneCtx *lane) { Vec2 death_pos = event->death_pos; + //- Killfeed + { + P_Ent *victim = P_EntFromKey(local_frame, event->death_victim); + P_Ent *killer = P_EntFromKey(local_frame, event->death_killer); + String victim_name = P_StringFromEnt(victim); + String killer_name = P_StringFromEnt(killer); + + if (victim_name.len > 0) + { + u64 killfeed_term_seed = MixU64s(event->key.v, P_KillfeedBasis); + String killfeed_term = UpperString(frame->arena, P_KillTerms[killfeed_term_seed % countof(P_KillTerms)]); + String msg = Zi; + if (killer_name.len > 0) + { + msg = StringF(frame->arena, "%F %F %F", FmtString(killer_name), FmtString(killfeed_term), FmtString(victim_name)); + } + else + { + msg = StringF(frame->arena, "%F was %F", FmtString(killfeed_term), FmtString(victim_name)); + } + V_PushNotif(msg); + } + } + //- Death particles { V_Emitter emitter = Zi; @@ -3932,12 +3955,6 @@ void V_TickForever(WaveLaneCtx *lane) // TODO: More efficient name processing char *name_cstr = sample->name_cstr_lit; zone->name = StringFromCstrNoLimit(name_cstr); - - u64 color_seed = HashString(zone->name); - f32 h = (Norm16(color_seed >> 0) * 1) * 360; - f32 s = TweakFloat("Profiler zone saturation", 0.50, 0, 1); - f32 v = TweakFloat("Profiler zone brightness", 1.00, 0, 1); - zone->color = SrgbFromHsv(h, s, v); } zone_track->open_zone = zone; @@ -4724,7 +4741,12 @@ void V_TickForever(WaveLaneCtx *lane) b32 should_collapse_zone = (visual_zone_end_px - visual_zone_start_px) <= zone_collapse_threshold_px; String zone_name = zone->name; u64 zone_id = zone->id; - Vec4 zone_color = zone->color; + + u64 color_seed = HashString(zone->name); + f32 h = (Norm16(color_seed >> 0) * 1) * 360; + f32 s = TweakFloat("Profiler zone saturation", 0.50, 0, 1); + f32 v = TweakFloat("Profiler zone brightness", 1.00, 0, 1); + Vec4 zone_color = SrgbFromHsv(h, s, v); // b32 should_collapse_zone = visual_zone_len_px <= zone_collapse_threshold_px; // b32 should_collapse_zone = 0; @@ -5593,6 +5615,19 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Update panels from cmds + + + + // TODO: Remove this + if (frame->tick == 1) + { + frame->show_consoles = 1; + } + + + + + b32 show_editor_panels = (frame->is_editing && !hide_editor_ui) || TweakBool("Show panels when not editing", 0); { Struct(PanelBfs) { PanelBfs *next; V_Panel *panel; }; @@ -7682,16 +7717,18 @@ void V_TickForever(WaveLaneCtx *lane) { UI_PushDF(Font, theme.player_name_font) UI_PushDF(FontSize, 12) - UI_PushDF(Width, UI_Shrink(3, 1)) - UI_PushDF(Height, UI_Shrink(2, 1)) - UI_PushDF(BackgroundColor, Color_Black) + UI_PushDF(Width, UI_Shrink(4, 1)) + UI_PushDF(Height, UI_Shrink(1, 1)) + // UI_PushDF(BackgroundColor, Color_Black) UI_PushDF(ChildAlignment, UI_Region_Center) UI_PushDF(Opacity, 0.95) UI_PushDF(Rounding, UI_Rgrow(0.25)) // UI_PushDF(BackgroundColor, Color_Cyan) - UI_PushDF(FontSize, UI_Top(FontSize) * 1.5) + // UI_PushDF(FontSize, UI_Top(FontSize) * 1.5) + UI_PushDF(FontSize, 16) // UI_PushDF(TextColor, SrgbFromHsv(32, 1, 1)) - UI_PushDF(TextColor, SrgbFromHsv(32, 0.75, 1)) + // UI_PushDF(TextColor, SrgbFromHsv(32, 0.75, 1)) + UI_PushDF(TextColor, VEC4(0.95, 0.95, 0.95, 1)) UI_PushDF(Parent, vis_screen_overlay_box) UI_PushDF(Anchor, UI_Region_Bottom) UI_PushDF(Flags, UI_BoxFlag_Floating | UI_BoxFlag_DrawText | UI_BoxFlag_DontClampFloatingX | UI_BoxFlag_DontClampFloatingY) @@ -7705,7 +7742,8 @@ void V_TickForever(WaveLaneCtx *lane) if (guy->is_guy && name.len > 0) { Vec2 guy_world_pos = guy->xf.t; - guy_world_pos.y -= UI_Top(FontSize) * 0.01; + // guy_world_pos.y -= UI_Top(FontSize) * 0.01; + guy_world_pos.y -= 0.25; Vec2 guy_screen_pos = MulAffineVec2(frame->af.world_to_screen, guy_world_pos); @@ -7713,21 +7751,21 @@ void V_TickForever(WaveLaneCtx *lane) text_pos.x = guy_screen_pos.x; text_pos.y = guy_screen_pos.y; - UI_PushDF(Text, name) + // UI_PushDF(Text, name) { // Name box // UI_SetNext(TextColor, Color_Transparent); UI_SetNext(FloatingPos, text_pos); - UI_PushDF(Text, name) UI_PushDF(Parent, UI_BuildBox()) + UI_PushDF(Text, name) { - // // Drop-shadow - // UI_SetNext(TextColor, Color_Black); - // UI_SetNext(FloatingPos, AddVec2(text_pos, VEC2(2, 2))); - // UI_BuildBox(); + // Drop-shadow + UI_SetNext(TextColor, Color_Black); + UI_SetNext(FloatingPos, VEC2(2, 2)); + UI_BuildBox(); // Name text - // UI_BuildBox(); + UI_BuildBox(); } } diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 055d5f67..8343d68c 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -258,10 +258,7 @@ Struct(V_Zone) String name; u64 id; - i64 depth; - - Vec4 color; i64 start_ns; i64 end_ns; }; diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 5fc68b11..19235c3e 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -406,6 +406,11 @@ PixelShader(V_QuadPS, V_QuadPSOutput, V_QuadPSInput input) Vec4 albedo = tex.Sample(sampler, input.samp_uv); + if (quad.mask_color_lin.a != 0 && all(albedo == Color_White)) + { + albedo = quad.mask_color_lin; + } + if (is_in_world) { // TODO: Don't write occluders using screen space result. Do separate draw pass instead. diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index d28a461a..8ef9176f 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -272,6 +272,7 @@ Struct(V_GpuQuad) Affine quad_uv_to_world_af; G_TextureRef tex; Rng2 tex_slice_uv; + Vec4 mask_color_lin; }; ////////////////////////////////////////////////////////////