fire animation. colored guys.

This commit is contained in:
jacob 2026-04-04 16:30:30 -05:00
parent 0d2871d664
commit 92ed9a4c2d
14 changed files with 367 additions and 154 deletions

View File

@ -408,7 +408,6 @@ String LowerString(Arena *arena, String str)
String result = Zi; String result = Zi;
result.text = PushStructsNoZero(arena, u8, str.len); result.text = PushStructsNoZero(arena, u8, str.len);
result.len = str.len; result.len = str.len;
for (u64 i = 0; i < str.len; ++i) for (u64 i = 0; i < str.len; ++i)
{ {
u8 c = str.text[i]; u8 c = str.text[i];
@ -418,7 +417,23 @@ String LowerString(Arena *arena, String str)
} }
result.text[i] = c; 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; return result;
} }

View File

@ -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 ReplaceString(Arena *arena, String str, String old_pattern, String new_pattern);
String IndentString(Arena *arena, String str, u32 indent); String IndentString(Arena *arena, String str, u32 indent);
String LowerString(Arena *arena, String str); String LowerString(Arena *arena, String str);
String UpperString(Arena *arena, String str);
b32 MatchString(String str1, String str2); b32 MatchString(String str1, String str2);
b32 StringContains(String str, String substring); b32 StringContains(String str, String substring);
b32 StringBeginsWith(String str, String substring); b32 StringBeginsWith(String str, String substring);

View File

@ -267,56 +267,97 @@ P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent)
// TODO: Determine animation dynamically // TODO: Determine animation dynamically
i64 animation_rate_ns = NsFromSeconds(0.050); 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.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; result.weapon_over = 1;
} }
else if (Vec2LenSq(ent->control.move) > (0.01 * 0.01)) else if (is_shooting)
{ {
result.span = SPR_SpanKeyFromName(Lit("walk")); result.body_span = SPR_SpanKeyFromName(Lit("shoot"));
if (ent->is_guy) // 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"))); 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)
else
{ {
result.span = SPR_SpanKeyFromName(Lit("idle")); 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));
}
} }
} }
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 // TODO: Use prefab lookup
if (ent->is_guy) 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) 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) 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) 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) 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) 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) 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.wep_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("wep/uzi.ase")));
} }
result.frame_seq = animation_time_ns / animation_rate_ns;
return result; 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)) for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy))
{ {
if (guy->is_guy) if (guy->is_guy)
{ {
// Roll
// if (guy->control.roll_presses && !IsVec2Zero(guy->control.move)) // if (guy->control.roll_presses && !IsVec2Zero(guy->control.move))
if (guy->control.downs[P_Button_Roll]) 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); guy->last_roll_dir = NormVec2(guy->control.look);
} }
} }
// Walk
if (!P_IsEntRolling(frame, guy))
{
b32 is_moving = Vec2LenSq(guy->control.move) > (0.001 * 0.001); 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; 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])) if (button == P_Button_PrimaryFire && (firer->control.held[button] || firer->control.downs[button]))
{ {
// fire_rate = 100; // fire_rate = 100;
// bullets_per_fire = 4; bullets_per_fire = 4;
fire_rate = 10; // fire_rate = 50;
fire_rate = 50;
bullets_per_fire = 1; bullets_per_fire = 1;
firing = (weapon->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= frame->time_ns; firing = (weapon->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= frame->time_ns;
if (firing) if (firing)
@ -3180,6 +3230,7 @@ void P_StepFrame(P_Frame *frame)
bullet->sim = weapon->sim; 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.05;
// f32 spread = Tau * 0.2; // f32 spread = Tau * 0.2;
// f32 spread = Tau * 0.01; f32 spread = Tau * 0.01;
f32 spread = 0; // f32 spread = 0;
b32 should_ricochet = 0; b32 should_ricochet = 0;
@ -3269,8 +3320,8 @@ void P_StepFrame(P_Frame *frame)
{ {
Vec2 look = firer->control.look; Vec2 look = firer->control.look;
P_Anim anim = P_AnimFromEnt(frame, firer); P_Anim anim = P_AnimFromEnt(frame, firer);
SPR_Sprite body = SPR_SpriteFromSheet(anim.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.span, anim.frame_seq); SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.wep_span, anim.wep_frame_seq);
//- Compute sprite transforms //- Compute sprite transforms
Affine ent_to_world_af = MulAffineXform(AffineIdentity, firer->xf); 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->key = P_EntKeyFromU64(MixU64s(guy->key.v, P_DeathBasis + (u64)player->deaths));
death->death_pos = guy->xf.t; death->death_pos = guy->xf.t;
death->is_death = 1; death->is_death = 1;
death->death_player = player->key; death->death_victim = player->key;
death->death_killer = killer->key; death->death_killer = killer->key;
death->lifetime_seconds = P_ObservationDurationSeconds; death->lifetime_seconds = P_ObservationDurationSeconds;
} }

View File

@ -11,6 +11,7 @@
#define P_BulletHitBasis 0xbc70fc783c1c507full #define P_BulletHitBasis 0xbc70fc783c1c507full
#define P_BulletTrailBasis 0x27c011f891c571feull #define P_BulletTrailBasis 0x27c011f891c571feull
#define P_DeathBasis 0x2e3c75a3286d872aull #define P_DeathBasis 0x2e3c75a3286d872aull
#define P_KillfeedBasis 0xd1f84bd6f7c3cf1eull
Struct(P_EntKey) Struct(P_EntKey)
{ {
@ -170,7 +171,7 @@ Struct(P_Ent)
b32 is_death; b32 is_death;
Vec2 death_pos; Vec2 death_pos;
P_EntKey death_player; P_EntKey death_victim;
P_EntKey death_killer; P_EntKey death_killer;
//- Bomb //- Bomb
@ -215,11 +216,14 @@ Struct(P_Ent)
P_EntKey weapon; P_EntKey weapon;
Vec2 last_roll_dir; Vec2 last_roll_dir;
i64 walk_time_accum_ns; i64 walk_time_accum_ns;
i64 fire_time_accum_ns;
i64 last_fire_ns; i64 last_fire_ns;
i64 last_alt_fire_ns; i64 last_alt_fire_ns;
i64 last_roll_ns; i64 last_roll_ns;
f32 last_fire_rate;
//- Weapon //- Weapon
b32 is_weapon; b32 is_weapon;
@ -264,11 +268,18 @@ Struct(P_EntBin)
Struct(P_Anim) Struct(P_Anim)
{ {
i64 frame_seq; i64 body_frame_seq;
SPR_SpanKey span; SPR_SpanKey body_span;
SPR_SheetKey sheet; SPR_SheetKey body_sheet;
i64 legs_frame_seq;
SPR_SpanKey legs_span;
SPR_SheetKey legs_sheet; SPR_SheetKey legs_sheet;
i64 wep_frame_seq;
SPR_SpanKey wep_span;
SPR_SheetKey wep_sheet; SPR_SheetKey wep_sheet;
b32 weapon_over; b32 weapon_over;
}; };

View File

@ -17,6 +17,7 @@
@IncludeC pp_shared.cgh @IncludeC pp_shared.cgh
@IncludeG pp_shared.cgh @IncludeG pp_shared.cgh
@IncludeC pp.h @IncludeC pp.h
@IncludeC pp_terms.h
@IncludeC pp_transcode.h @IncludeC pp_transcode.h
@Bootstrap P_Bootstrap @Bootstrap P_Bootstrap

BIN
src/pp/pp_res/guy/guy.ase (Stored with Git LFS)

Binary file not shown.

BIN
src/pp/pp_res/guy/legs.ase (Stored with Git LFS)

Binary file not shown.

BIN
src/pp/pp_res/wep/uzi.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -544,6 +544,7 @@ void S_TickForever(WaveLaneCtx *lane)
// FIXME: Only accept edits from privileged users // FIXME: Only accept edits from privileged users
{ {
u32 bots_count = 0;
b32 should_save = 0; b32 should_save = 0;
for (P_MsgNode *msg_node = in_msgs.first; msg_node; msg_node = msg_node->next) 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); P_Ent *bot = P_EntFromKey(world_frame, msg->key);
if (!bot->is_bot) 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 = P_PushTempEnt(frame_arena, &ents);
bot->key = msg->key; bot->key = msg->key;
bot->is_player = 1; bot->is_player = 1;
bot->is_bot = 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; bot->continuity_gen += 1;
P_Ent *guy = P_EntFromKey(world_frame, bot->guy); P_Ent *guy = P_EntFromKey(world_frame, bot->guy);

81
src/pp/pp_terms.h Normal file
View File

@ -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"),
};

View File

@ -1860,7 +1860,8 @@ void V_TickForever(WaveLaneCtx *lane)
// Rtt time // 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)); smoothed_rtt = LerpF64(smoothed_rtt, rtt, SaturateF64(lerp_rate));
if (rtt != 0 && prev_rtt == 0) if (rtt != 0 && prev_rtt == 0)
{ {
@ -1960,13 +1961,18 @@ void V_TickForever(WaveLaneCtx *lane)
// Compute prediction tick // 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 = 5.0 * frame->dt;
// f64 lerp_rate = 1.0 * frame->dt; // f64 lerp_rate = 1.0 * frame->dt;
f64 lerp_rate = 1; 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) 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 // 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->predict_tick_accum, Color_Red, 1);
// V_PushTimelineMarker(frame->target_predict_tick_accum, Color_Yellow, 1); // V_PushTimelineMarker(frame->target_predict_tick_accum, Color_Yellow, 1);
@ -2270,37 +2276,38 @@ void V_TickForever(WaveLaneCtx *lane)
// 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
// f64 interp_ratio = TweakFloat("Interpolation ratio", 1.5, 0, V_MaxInterpRatio);
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 //- Blended sim tick
f64 target_blend_sim_tick = (f64)ack - interp_ratio; f64 target_blend_sim_tick = (f64)ack - interp_ratio;
{ {
f64 lerp_rate = SaturateF64(5.0 * frame->dt); 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 = 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) 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; frame->blend_sim_tick = target_blend_sim_tick;
LogDebugF("Sim blend reset"); LogDebugF("Sim blend reset");
} }
} }
}
//- Blended prediction tick //- Blended prediction tick
f64 target_blend_predict_tick = frame->predict_tick_accum - interp_ratio; f64 target_blend_predict_tick = frame->predict_tick_accum - interp_ratio;
{ {
f64 lerp_rate = SaturateF64(2.0 * frame->dt); 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 = 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) 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; frame->blend_predict_tick = target_blend_predict_tick;
LogDebugF("Prediction blend reset"); LogDebugF("Prediction blend reset");
} }
} }
}
V_PushTimelineMarker(frame->blend_sim_tick, Color_Orange, 1); V_PushTimelineMarker(frame->blend_sim_tick, Color_Orange, 1);
V_PushTimelineMarker(frame->blend_predict_tick, Color_Red, 1); V_PushTimelineMarker(frame->blend_predict_tick, Color_Red, 1);
@ -2588,8 +2595,8 @@ void V_TickForever(WaveLaneCtx *lane)
P_Ent *ent = local_follow; P_Ent *ent = local_follow;
P_Anim anim = P_AnimFromEnt(local_frame, ent); P_Anim anim = P_AnimFromEnt(local_frame, ent);
SPR_Sprite body = SPR_SpriteFromSheet(anim.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.span, anim.frame_seq); SPR_Sprite wep = SPR_SpriteFromSheet(anim.wep_sheet, anim.wep_span, anim.wep_frame_seq);
Vec2 look = ent->control.look; Vec2 look = ent->control.look;
if (P_MatchEntKey(ent->key, local_guy->key)) if (P_MatchEntKey(ent->key, local_guy->key))
@ -2876,7 +2883,7 @@ void V_TickForever(WaveLaneCtx *lane)
SPR_Sprite body = Zi; SPR_Sprite body = Zi;
Affine body_pix_to_world_af = AffineIdentity; 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 = MulAffine(body_pix_to_world_af, ent_to_world_af);
body_pix_to_world_af = ScaleAffine(body_pix_to_world_af, pix_scale); 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; SPR_Sprite legs = Zi;
Affine legs_pix_to_world_af = AffineIdentity; 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 = TranslateAffine(legs_pix_to_world_af, ent_to_world_af.og);
legs_pix_to_world_af = ScaleAffine(legs_pix_to_world_af, pix_scale); legs_pix_to_world_af = ScaleAffine(legs_pix_to_world_af, pix_scale);
SPR_Ray anchor_ray = legs.rays[SPR_RayKind_Anchor]; 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, 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)); 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; Affine wep_pix_to_world_af = AffineIdentity;
if (ent->is_guy) 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 = MulAffine(wep_pix_to_world_af, ent_to_world_af);
wep_pix_to_world_af = ScaleAffine(wep_pix_to_world_af, pix_scale); 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)); 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 //- Push weapon quad
if (body.ready && wep.ready) 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.quad_uv_to_world_af = legs_uv_to_world_af;
legs_quad.tex = legs.tex; legs_quad.tex = legs.tex;
legs_quad.tex_slice_uv = DivRng2Vec2(legs.tex_rect, legs.tex_dims); legs_quad.tex_slice_uv = DivRng2Vec2(legs.tex_rect, legs.tex_dims);
legs_quad.mask_color_lin = legs_mask_color_lin;
} }
//- Body quad //- Body quad
@ -2957,6 +2990,7 @@ void V_TickForever(WaveLaneCtx *lane)
body_quad.tex_slice_uv = DivRng2Vec2(body.tex_rect, body.tex_dims); body_quad.tex_slice_uv = DivRng2Vec2(body.tex_rect, body.tex_dims);
if (ent->is_guy) if (ent->is_guy)
{ {
body_quad.mask_color_lin = body_mask_color_lin;
body_quad.occluder_id = ent->key.v & 0xFFFFFFFF; body_quad.occluder_id = ent->key.v & 0xFFFFFFFF;
} }
} }
@ -3407,51 +3441,12 @@ void V_TickForever(WaveLaneCtx *lane)
//- Wall impact particles //- Wall impact particles
if (material != P_MaterialKind_Flesh) 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 // Hot debris
{ {
V_Emitter emitter = Zi; V_Emitter emitter = Zi;
emitter.kind = V_ParticleKind_HotDebris; emitter.kind = V_ParticleKind_HotDebris;
// emitter.count = MaxF32(1000 * frame->dt, 1);
emitter.count = 32; emitter.count = 32;
// f32 angle = AngleFromVec2(SubVec2(p1, p0));
f32 angle = AngleFromVec2(impact_dir); f32 angle = AngleFromVec2(impact_dir);
f32 angle_particle_spread = Tau / 2.5; f32 angle_particle_spread = Tau / 2.5;
@ -3461,30 +3456,36 @@ void V_TickForever(WaveLaneCtx *lane)
emitter.pos.p0 = emitter.pos.p0 =
emitter.pos.p1 = impact_pos; 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.min = 0;
emitter.speed.max = 30; emitter.speed.max = 30;
// emitter.angle.min = angle - angle_spread / 2; V_PushParticles(emitter);
// emitter.angle.max = angle + angle_spread / 2; }
// 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)); //- Wall spark
// emitter.speed.min = {
// emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; 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); V_PushParticles(emitter);
} }
@ -3494,6 +3495,8 @@ void V_TickForever(WaveLaneCtx *lane)
// Wall dust // Wall dust
{ {
V_Emitter emitter = Zi; V_Emitter emitter = Zi;
@ -3503,14 +3506,10 @@ void V_TickForever(WaveLaneCtx *lane)
emitter.pos.p0 = emitter.pos.p1 = impact_pos; 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.min = 1;
emitter.speed.max = 20; emitter.speed.max = 20;
// emitter.velocity_falloff = 12;
// emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5;
Vec2 dir = impact_dir; Vec2 dir = impact_dir;
f32 angle = AngleFromVec2(dir); f32 angle = AngleFromVec2(dir);
f32 angle_spread = Tau * 0.1; f32 angle_spread = Tau * 0.1;
@ -3569,6 +3568,30 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
Vec2 death_pos = event->death_pos; 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 //- Death particles
{ {
V_Emitter emitter = Zi; V_Emitter emitter = Zi;
@ -3932,12 +3955,6 @@ void V_TickForever(WaveLaneCtx *lane)
// TODO: More efficient name processing // TODO: More efficient name processing
char *name_cstr = sample->name_cstr_lit; char *name_cstr = sample->name_cstr_lit;
zone->name = StringFromCstrNoLimit(name_cstr); 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; 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; b32 should_collapse_zone = (visual_zone_end_px - visual_zone_start_px) <= zone_collapse_threshold_px;
String zone_name = zone->name; String zone_name = zone->name;
u64 zone_id = zone->id; 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 = visual_zone_len_px <= zone_collapse_threshold_px;
// b32 should_collapse_zone = 0; // b32 should_collapse_zone = 0;
@ -5593,6 +5615,19 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Update panels from cmds //- 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); b32 show_editor_panels = (frame->is_editing && !hide_editor_ui) || TweakBool("Show panels when not editing", 0);
{ {
Struct(PanelBfs) { PanelBfs *next; V_Panel *panel; }; 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(Font, theme.player_name_font)
UI_PushDF(FontSize, 12) UI_PushDF(FontSize, 12)
UI_PushDF(Width, UI_Shrink(3, 1)) UI_PushDF(Width, UI_Shrink(4, 1))
UI_PushDF(Height, UI_Shrink(2, 1)) UI_PushDF(Height, UI_Shrink(1, 1))
UI_PushDF(BackgroundColor, Color_Black) // UI_PushDF(BackgroundColor, Color_Black)
UI_PushDF(ChildAlignment, UI_Region_Center) UI_PushDF(ChildAlignment, UI_Region_Center)
UI_PushDF(Opacity, 0.95) UI_PushDF(Opacity, 0.95)
UI_PushDF(Rounding, UI_Rgrow(0.25)) UI_PushDF(Rounding, UI_Rgrow(0.25))
// UI_PushDF(BackgroundColor, Color_Cyan) // 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, 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(Parent, vis_screen_overlay_box)
UI_PushDF(Anchor, UI_Region_Bottom) UI_PushDF(Anchor, UI_Region_Bottom)
UI_PushDF(Flags, UI_BoxFlag_Floating | UI_BoxFlag_DrawText | UI_BoxFlag_DontClampFloatingX | UI_BoxFlag_DontClampFloatingY) 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) if (guy->is_guy && name.len > 0)
{ {
Vec2 guy_world_pos = guy->xf.t; 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); 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.x = guy_screen_pos.x;
text_pos.y = guy_screen_pos.y; text_pos.y = guy_screen_pos.y;
UI_PushDF(Text, name) // UI_PushDF(Text, name)
{ {
// Name box // Name box
// UI_SetNext(TextColor, Color_Transparent); // UI_SetNext(TextColor, Color_Transparent);
UI_SetNext(FloatingPos, text_pos); UI_SetNext(FloatingPos, text_pos);
UI_PushDF(Text, name)
UI_PushDF(Parent, UI_BuildBox()) UI_PushDF(Parent, UI_BuildBox())
UI_PushDF(Text, name)
{ {
// // Drop-shadow // Drop-shadow
// UI_SetNext(TextColor, Color_Black); UI_SetNext(TextColor, Color_Black);
// UI_SetNext(FloatingPos, AddVec2(text_pos, VEC2(2, 2))); UI_SetNext(FloatingPos, VEC2(2, 2));
// UI_BuildBox(); UI_BuildBox();
// Name text // Name text
// UI_BuildBox(); UI_BuildBox();
} }
} }

View File

@ -258,10 +258,7 @@ Struct(V_Zone)
String name; String name;
u64 id; u64 id;
i64 depth; i64 depth;
Vec4 color;
i64 start_ns; i64 start_ns;
i64 end_ns; i64 end_ns;
}; };

View File

@ -406,6 +406,11 @@ PixelShader(V_QuadPS, V_QuadPSOutput, V_QuadPSInput input)
Vec4 albedo = tex.Sample(sampler, input.samp_uv); 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) if (is_in_world)
{ {
// TODO: Don't write occluders using screen space result. Do separate draw pass instead. // TODO: Don't write occluders using screen space result. Do separate draw pass instead.

View File

@ -272,6 +272,7 @@ Struct(V_GpuQuad)
Affine quad_uv_to_world_af; Affine quad_uv_to_world_af;
G_TextureRef tex; G_TextureRef tex;
Rng2 tex_slice_uv; Rng2 tex_slice_uv;
Vec4 mask_color_lin;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////