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

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

View File

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

View File

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

View File

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

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
{
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);

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
{
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?
// <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
// 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();
}
}

View File

@ -258,10 +258,7 @@ Struct(V_Zone)
String name;
u64 id;
i64 depth;
Vec4 color;
i64 start_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);
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.

View File

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