diff --git a/src/pp/pp.c b/src/pp/pp.c index 84ecd68f..6986cae4 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -322,9 +322,6 @@ P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent) if (wep->is_uzi) { result.wep_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("wep/uzi.ase"))); - } else if (wep->is_launcher) - { - result.wep_sheet = SPR_SheetKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("wep/launcher.ase"))); } result.frame_seq = animation_time_ns / animation_rate_ns; @@ -335,9 +332,9 @@ P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent) b32 P_IsEntRolling(P_Frame *frame, P_Ent *ent) { b32 result = ( - ent->last_roll_time_ns > 0 && - (frame->time_ns - ent->last_roll_time_ns) > 0 && - (frame->time_ns - ent->last_roll_time_ns) < P_RollTimeNs + ent->last_roll_ns > 0 && + (frame->time_ns - ent->last_roll_ns) > 0 && + (frame->time_ns - ent->last_roll_ns) < P_RollTimeNs ); return result; } @@ -2481,16 +2478,16 @@ void P_StepFrame(P_Frame *frame) if (guy->is_guy) { // if (guy->control.roll_presses && !IsVec2Zero(guy->control.move)) - if (guy->control.roll_presses) + if (guy->control.downs[P_Button_Roll]) { // TODO: Not like this i64 roll_timeout_ns = P_RollTimeoutNs; i64 roll_time_ns = P_RollTimeNs; - if (frame->time_ns - roll_timeout_ns - roll_time_ns > guy->last_roll_time_ns || guy->last_roll_time_ns == 0) + if (frame->time_ns - roll_timeout_ns - roll_time_ns > guy->last_roll_ns || guy->last_roll_ns == 0) { - guy->last_roll_time_ns = frame->time_ns; + guy->last_roll_ns = frame->time_ns; // guy->last_roll_dir = NormVec2(guy->control.move); guy->last_roll_dir = NormVec2(guy->control.look); } @@ -2552,7 +2549,7 @@ void P_StepFrame(P_Frame *frame) move_force *= roll_factor; max_speed *= roll_factor; - // if ((frame->time_ns - guy->last_roll_time_ns) > P_RollTurnTimeNs) + // if ((frame->time_ns - guy->last_roll_ns) > P_RollTurnTimeNs) { turn_rate = 0.1; } @@ -3133,40 +3130,57 @@ void P_StepFrame(P_Frame *frame) for (P_Ent *firer = P_FirstEnt(frame); !P_IsEntNil(firer); firer = P_NextEnt(firer)) { P_Ent *weapon = P_EntFromKey(frame, firer->weapon); - if (weapon->is_weapon && (firer->control.fire_held || firer->control.fire_presses)) - // if (weapon->is_weapon && firer->control.fire_presses) + if (weapon->is_weapon) { - f32 fire_rate = 50; - f32 bullets_per_fire = 1; - - b32 can_fire = (weapon->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= frame->time_ns; - - if (can_fire) + for (P_Button button = 0; button < P_Button_COUNT; ++button) { - i64 tick_bullets_count = bullets_per_fire; - if (tick_bullets_count > 0) + f32 fire_rate = 1; // In bullets per second + f32 bullets_per_fire = 1; + b32 firing = 0; + b32 is_bomb = 0; + if (button == P_Button_PrimaryFire && (firer->control.held[button] || firer->control.downs[button])) { - for (i64 bullet_idx = 0; bullet_idx < tick_bullets_count; ++bullet_idx) + // fire_rate = 100; + // bullets_per_fire = 4; + fire_rate = 10; + bullets_per_fire = 1; + firing = (weapon->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= frame->time_ns; + if (firing) { - P_Ent *bullet = P_PushTempEnt(scratch.arena, &bullets_to_spawn); - bullet->is_bullet = 1; - - // TDOO: More specific key with seed that only increments on player control (for less misprediction) - bullet->key = P_EntKeyFromU64(P_RandU64FromEnt(firer)); - - - - if (weapon->is_launcher) - { - bullet->is_bomb = 1; - } - - bullet->source = weapon->key; - bullet->damage_attribution = firer->source; - bullet->sim = weapon->sim; + weapon->last_fire_ns = frame->time_ns; + } + } + if (button == P_Button_AltFire && (firer->control.held[button] || firer->control.downs[button])) + { + fire_rate = 10; + bullets_per_fire = 4; + firing = (weapon->last_alt_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= frame->time_ns; + is_bomb = 1; + if (firing) + { + weapon->last_alt_fire_ns = frame->time_ns; + } + } + if (firing) + { + i64 tick_bullets_count = bullets_per_fire; + if (tick_bullets_count > 0) + { + for (i64 bullet_idx = 0; bullet_idx < tick_bullets_count; ++bullet_idx) + { + P_Ent *bullet = P_PushTempEnt(scratch.arena, &bullets_to_spawn); + bullet->is_bullet = 1; + + // TDOO: More specific key with seed that only increments on player control (for less chance of misprediction) + bullet->key = P_EntKeyFromU64(P_RandU64FromEnt(firer)); + bullet->is_bomb = is_bomb; + + bullet->source = weapon->key; + bullet->damage_attribution = firer->source; + bullet->sim = weapon->sim; + } } } - weapon->last_fire_ns = frame->time_ns; } } } @@ -3202,25 +3216,26 @@ void P_StepFrame(P_Frame *frame) ////////////////////////////// //- Bullet properties - f32 spread = Tau * 0.05; + // f32 spread = Tau * 0.05; + // f32 spread = Tau * 0.2; // f32 spread = Tau * 0.01; - // f32 spread = 0; + f32 spread = 0; b32 should_ricochet = 0; f32 initial_speed = 1; f32 speed_falloff = 0; - if (weapon->is_uzi) - { - initial_speed = TweakFloat("Bullet speed", 75, 1, 100); - } - else if (weapon->is_launcher) + if (bullet->is_bomb) { should_ricochet = 1; initial_speed = 50; // initial_speed = 100; speed_falloff = 5; } + else + { + initial_speed = TweakFloat("Bullet speed", 75, 1, 100); + } ////////////////////////////// //- Initialize @@ -3490,7 +3505,7 @@ void P_StepFrame(P_Frame *frame) { victim->damage_attribution = damager->key; } - // victim->health -= 0.25; + victim->health -= 0.25; } // Prune out of bounds bullet @@ -3696,17 +3711,19 @@ void P_StepFrame(P_Frame *frame) ////////////////////////////// //- Kill guys + { + P_EntList ents_to_spawn = Zi; for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy)) { - if (guy->is_guy) + if (guy->is_guy && guy->health <= 0) { - if (guy->health <= 0) + P_Ent *old_guy = P_EntFromKey(prev_frame, guy->key); + if (old_guy->health > 0) { - P_Ent *old_guy = P_EntFromKey(prev_frame, guy->key); - if (old_guy->health > 0) + P_Ent *player = P_EntFromKey(frame, guy->source); + P_Ent *killer = P_EntFromKey(frame, guy->damage_attribution); + // Update kill info { - P_Ent *player = P_EntFromKey(frame, guy->source); - P_Ent *killer = P_EntFromKey(frame, guy->damage_attribution); if (player->is_player) { player->deaths += 1; @@ -3717,10 +3734,23 @@ void P_StepFrame(P_Frame *frame) } guy->exists = 0; guy->continuity_gen += 1; + guy->health = 1; + } + // Push kill event + { + P_Ent *death = P_PushTempEnt(scratch.arena, &ents_to_spawn); + 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_killer = killer->key; + death->lifetime_seconds = P_ObservationDurationSeconds; } } } } + P_SpawnEntsFromList(frame, ents_to_spawn); + } ////////////////////////////// //- Debug draw diff --git a/src/pp/pp.h b/src/pp/pp.h index 2f4bec97..ff820c18 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -10,6 +10,7 @@ #define P_BulletSpreadBasis 0xc3b72fe38ca5a1d6ull #define P_BulletHitBasis 0xbc70fc783c1c507full #define P_BulletTrailBasis 0x27c011f891c571feull +#define P_DeathBasis 0x2e3c75a3286d872aull Struct(P_EntKey) { @@ -88,6 +89,15 @@ Struct(P_DebugDrawNode) #define P_RollTimeoutNs NsFromSeconds(0.5) #define P_ObservationDurationSeconds 1 +Enum(P_Button) +{ + P_Button_PrimaryFire, + P_Button_AltFire, + P_Button_Roll, + + P_Button_COUNT +}; + Struct(P_Control) { i64 tick; @@ -98,9 +108,8 @@ Struct(P_Control) Vec2 move; Vec2 look; - f32 fire_held; - f32 fire_presses; - f32 roll_presses; + f32 held[P_Button_COUNT]; + f32 downs[P_Button_COUNT]; }; Struct(P_Ent) @@ -159,6 +168,11 @@ Struct(P_Ent) Vec2 hit_entry_velocity; P_MaterialKind hit_material; + b32 is_death; + Vec2 death_pos; + P_EntKey death_player; + P_EntKey death_killer; + //- Bomb b32 is_bomb; @@ -189,8 +203,9 @@ Struct(P_Ent) P_EntKey guy; f32 ping; - f32 kills; - f32 deaths; + + u64 kills; + u64 deaths; u8 string_len; u8 string_text[P_MaxPlayerNameLen + 8]; @@ -198,18 +213,19 @@ Struct(P_Ent) //- Guy P_EntKey weapon; - i64 last_roll_time_ns; Vec2 last_roll_dir; i64 walk_time_accum_ns; + i64 last_fire_ns; + i64 last_alt_fire_ns; + i64 last_roll_ns; + //- Weapon b32 is_weapon; b32 is_uzi; b32 is_launcher; - i64 last_fire_ns; - //- Spawner b32 is_guy_spawn; diff --git a/src/pp/pp_res/wep/launcher.ase b/src/pp/pp_res/wep/launcher.ase deleted file mode 100644 index 26e215cf..00000000 --- a/src/pp/pp_res/wep/launcher.ase +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f7022bb2ec2a06d96bcdfe272a025e82a613727808ff5aa9981d084883e7fda8 -size 549 diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index c628d6a9..ae7963e6 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -425,7 +425,7 @@ void S_TickForever(WaveLaneCtx *lane) //- Apply bot controls { - f32 move_bias = TweakFloat("Bot movement bias", 1, -1, 1); + f32 move_bias = TweakFloat("Bot movement bias", 0, -1, 1); f32 move_frequency = TweakFloat("Bot movement frequency", 0, 0, 10); f32 turn_frequency = TweakFloat("Bot turn frequency", 0, 0, 10); // b32 bot_movement_enabled = TweakBool("Bot movement enabled", 1); diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 00f96d23..5b73d054 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -958,8 +958,6 @@ void V_TickForever(WaveLaneCtx *lane) frame->is_editing = prev_frame->is_editing; frame->ui_debug = prev_frame->ui_debug; frame->look = prev_frame->look; - frame->fire_presses = prev_frame->fire_presses; - frame->roll_presses = prev_frame->roll_presses; frame->show_consoles = prev_frame->show_consoles; frame->show_profilers = prev_frame->show_profilers; frame->edit_mode = prev_frame->edit_mode; @@ -1443,18 +1441,20 @@ void V_TickForever(WaveLaneCtx *lane) look = ClampVec2Len(look, min_look_radius, max_look_radius); } - f32 fire_held = frame->held_buttons[Button_M1]; - f32 roll_held = frame->held_buttons[Button_Space]; - - f32 fire_presses = fire_held && !prev_frame->held_buttons[Button_M1]; - f32 roll_presses = roll_held && !prev_frame->held_buttons[Button_Space]; - if (frame->is_looking) { frame->look = look; - frame->fire_held = fire_held; - frame->fire_presses += fire_presses; - frame->roll_presses += roll_presses; + + // Update game control + { + P_Control *control = &V.queued_pp_control; + control->held[P_Button_PrimaryFire] = frame->held_buttons[Button_M1]; + control->held[P_Button_AltFire] = frame->held_buttons[Button_M2]; + control->held[P_Button_Roll] = frame->held_buttons[Button_Space]; + control->downs[P_Button_PrimaryFire] += frame->held_buttons[Button_M1] && !prev_frame->held_buttons[Button_M1]; + control->downs[P_Button_AltFire] += frame->held_buttons[Button_M2] && !prev_frame->held_buttons[Button_M2]; + control->downs[P_Button_Roll] += frame->held_buttons[Button_Space] && !prev_frame->held_buttons[Button_Space]; + } } if (frame->is_moving) @@ -1462,13 +1462,10 @@ void V_TickForever(WaveLaneCtx *lane) frame->move = move; } - if (!frame->is_looking) + if (!frame->is_looking && !frame->is_panning) { - if (!frame->is_panning) - { - f32 edit_move_speed = 20.0 * MaxF32(frame->edit_camera_zoom, min_zoom); - frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, MulVec2(move, edit_move_speed * frame->dt)); - } + f32 edit_move_speed = 20.0 * MaxF32(frame->edit_camera_zoom, min_zoom); + frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, MulVec2(move, edit_move_speed * frame->dt)); } } @@ -1995,17 +1992,14 @@ void V_TickForever(WaveLaneCtx *lane) { i64 control_tick = predict_to; - P_Control control = Zi; - control.tick = control_tick; - control.orig_tick = control_tick; - control.move = frame->move; - control.look = frame->look; - control.fire_held = frame->fire_held; - control.fire_presses = frame->fire_presses; - control.roll_presses = frame->roll_presses; - - frame->fire_presses = 0; - frame->roll_presses = 0; + P_Control control = V.queued_pp_control; + { + control.tick = control_tick; + control.orig_tick = control_tick; + control.move = frame->move; + control.look = frame->look; + ZeroStruct(&V.queued_pp_control); + } //- Fill controls buffer backwards i64 max_fill_count = SIM_TICKS_PER_SECOND / 4; @@ -2936,7 +2930,7 @@ void V_TickForever(WaveLaneCtx *lane) { Affine wep_uv_to_world_af = ScaleAffine(wep_pix_to_world_af, DimsFromRng2(wep.tex_rect)); - V_Quad *quad = PushStruct(frame->quads_arena, V_Quad); + V_GpuQuad *quad = PushStruct(frame->quads_arena, V_GpuQuad); quad->quad_uv_to_world_af = wep_uv_to_world_af; quad->tex = wep.tex; quad->tex_slice_uv = DivRng2Vec2(wep.tex_rect, wep.tex_dims); @@ -2946,7 +2940,7 @@ void V_TickForever(WaveLaneCtx *lane) if (body.ready) { //- Legs quad - V_Quad legs_quad = Zi; + V_GpuQuad legs_quad = Zi; { Affine legs_uv_to_world_af = ScaleAffine(legs_pix_to_world_af, DimsFromRng2(legs.tex_rect)); legs_quad.quad_uv_to_world_af = legs_uv_to_world_af; @@ -2955,7 +2949,7 @@ void V_TickForever(WaveLaneCtx *lane) } //- Body quad - V_Quad body_quad = Zi; + V_GpuQuad body_quad = Zi; { Affine body_uv_to_world_af = ScaleAffine(body_pix_to_world_af, DimsFromRng2(body.tex_rect)); body_quad.quad_uv_to_world_af = body_uv_to_world_af; @@ -2968,7 +2962,7 @@ void V_TickForever(WaveLaneCtx *lane) } //- Weapon quad - V_Quad wep_quad = Zi; + V_GpuQuad wep_quad = Zi; { Affine wep_uv_to_world_af = ScaleAffine(wep_pix_to_world_af, DimsFromRng2(wep.tex_rect)); wep_quad.quad_uv_to_world_af = wep_uv_to_world_af; @@ -2982,21 +2976,21 @@ void V_TickForever(WaveLaneCtx *lane) { if (anim.weapon_over) { - *PushStructNoZero(frame->quads_arena, V_Quad) = legs_quad; - *PushStructNoZero(frame->quads_arena, V_Quad) = body_quad; - *PushStructNoZero(frame->quads_arena, V_Quad) = wep_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = legs_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = body_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = wep_quad; } else { - *PushStructNoZero(frame->quads_arena, V_Quad) = wep_quad; - *PushStructNoZero(frame->quads_arena, V_Quad) = legs_quad; - *PushStructNoZero(frame->quads_arena, V_Quad) = body_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = wep_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = legs_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = body_quad; } } else { - *PushStructNoZero(frame->quads_arena, V_Quad) = legs_quad; - *PushStructNoZero(frame->quads_arena, V_Quad) = body_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = legs_quad; + *PushStructNoZero(frame->quads_arena, V_GpuQuad) = body_quad; } } } @@ -3012,7 +3006,7 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// - //- Process event entities + //- Process world events for (P_Ent *event = P_FirstEnt(local_frame); !P_IsEntNil(event); event = P_NextEnt(event)) { @@ -3142,8 +3136,11 @@ void V_TickForever(WaveLaneCtx *lane) // } + // Bullet fired if (event->is_first_trail) { + // frame->camera_shake += 0.5; + //- Bullet particle { V_Emitter emitter = Zi; @@ -3182,7 +3179,7 @@ void V_TickForever(WaveLaneCtx *lane) emitter.kind = V_ParticleKind_MuzzleWide; // emitter.count = MaxF32(1000 * frame->dt, 1); // emitter.count = 128; - emitter.count = 8; + emitter.count = 2; f32 angle = AngleFromVec2(SubVec2(p1, p0)); @@ -3398,9 +3395,14 @@ void V_TickForever(WaveLaneCtx *lane) { P_MaterialKind material = event->hit_material; - Vec2 hit_entry = event->hit_entry; - Vec2 hit_entry_normal = event->hit_entry_normal; - Vec2 hit_entry_velocity = event->hit_entry_velocity; + Vec2 impact_pos = event->hit_entry; + Vec2 impact_velocity = event->hit_entry_velocity; + + f32 impact_dir_velocity_weight = 0; + Vec2 impact_dir = SlerpVec2(event->hit_entry_normal, NegVec2(impact_velocity), impact_dir_velocity_weight); + + f32 impact_offset_angle = rand_angle * (Tau * 0); + impact_dir = RotateVec2Angle(impact_dir, impact_offset_angle); //- Wall impact particles if (material != P_MaterialKind_Flesh) @@ -3425,7 +3427,7 @@ void V_TickForever(WaveLaneCtx *lane) // // emitter.velocity_falloff = 5; // // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; - // Vec2 dir = hit_entry_normal; + // Vec2 dir = impact_dir; // f32 angle = AngleFromVec2(dir); // f32 angle_spread = Tau * 0.5; @@ -3441,52 +3443,51 @@ void V_TickForever(WaveLaneCtx *lane) // V_PushParticles(emitter); // } - // Fire - // { - // V_Emitter emitter = Zi; - // emitter.kind = V_ParticleKind_Fire; - // // emitter.count = MaxF32(1000 * frame->dt, 1); - // emitter.count = 2; + // 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(SubVec2(p1, p0)); - // f32 angle = AngleFromVec2(hit_entry_normal); - // angle += rand_angle * (Tau * 0.05); + f32 angle = AngleFromVec2(impact_dir); - // f32 angle_particle_spread = Tau / 4; - // emitter.angle.min = angle - angle_particle_spread / 2; - // emitter.angle.max = angle + angle_particle_spread / 2; + f32 angle_particle_spread = Tau / 2.5; + emitter.angle.min = angle - angle_particle_spread / 2; + emitter.angle.max = angle + angle_particle_spread / 2; - // emitter.pos.p0 = - // emitter.pos.p1 = hit_entry; + emitter.pos.p0 = + emitter.pos.p1 = impact_pos; - // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); - // // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); - // emitter.speed.min = 0; - // emitter.speed.max = 25; + emitter.speed.min = 0; + emitter.speed.max = 30; - // // emitter.angle.min = angle - angle_spread / 2; - // // emitter.angle.max = angle + angle_spread / 2; + // emitter.angle.min = angle - angle_spread / 2; + // emitter.angle.max = angle + angle_spread / 2; - // // emitter.angle.min = - // // emitter.angle.max = angle; + // emitter.angle.min = + // emitter.angle.max = angle; - // // emitter.pos.p0 = - // // emitter.pos.p1 = p0; + // emitter.pos.p0 = + // emitter.pos.p1 = p0; - // // emitter.speed.min = - // // emitter.speed.max = + // emitter.speed.min = + // emitter.speed.max = - // // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1)); + // 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; + // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1)); + // emitter.speed.min = + // emitter.speed.max = Vec2Len(SubVec2(p1, p0)) / frame->dt; - // V_PushParticles(emitter); - // } + V_PushParticles(emitter); + } @@ -3494,32 +3495,32 @@ void V_TickForever(WaveLaneCtx *lane) // Wall dust - // { - // V_Emitter emitter = Zi; - // { - // emitter.kind = V_ParticleKind_Smoke; - // emitter.count = 128; + { + V_Emitter emitter = Zi; + { + emitter.kind = V_ParticleKind_WallDust; + emitter.count = 128; - // emitter.pos.p0 = emitter.pos.p1 = hit_entry; + emitter.pos.p0 = emitter.pos.p1 = impact_pos; - // // emitter.color_lin = LinearFromSrgb(VEC4(0.5, 0.5, 0.5, 0.75)); + // emitter.color_lin = LinearFromSrgb(VEC4(0.5, 0.5, 0.5, 0.75)); - // emitter.speed.min = 10; - // emitter.speed.max = 20; + emitter.speed.min = 1; + emitter.speed.max = 20; - // // emitter.velocity_falloff = 12; - // // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; + // emitter.velocity_falloff = 12; + // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; - // Vec2 dir = hit_entry_normal; - // f32 angle = AngleFromVec2(dir); - // f32 angle_spread = Tau * 0.1; + Vec2 dir = impact_dir; + f32 angle = AngleFromVec2(dir); + f32 angle_spread = Tau * 0.1; - // emitter.angle.min = angle - angle_spread / 2; - // emitter.angle.max = angle + angle_spread / 2; + emitter.angle.min = angle - angle_spread / 2; + emitter.angle.max = angle + angle_spread / 2; - // } - // V_PushParticles(emitter); - // } + } + V_PushParticles(emitter); + } } //- Flesh impact particles @@ -3530,7 +3531,7 @@ void V_TickForever(WaveLaneCtx *lane) emitter.kind = V_ParticleKind_BloodTrail; // emitter.kind = V_ParticleKind_BloodDebris; - Vec2 dir = NormVec2(NegVec2(hit_entry_velocity)); + Vec2 dir = NormVec2(NegVec2(impact_velocity)); f32 angle = AngleFromVec2(dir); // f32 angle = 0; @@ -3545,7 +3546,7 @@ void V_TickForever(WaveLaneCtx *lane) // f32 speed = 100; f32 speed_spread = speed * 2; - emitter.pos.p0 = emitter.pos.p1 = hit_entry; + emitter.pos.p0 = emitter.pos.p1 = impact_pos; emitter.speed.min = speed - speed_spread * 0.5; emitter.speed.max = speed + speed_spread * 0.5; emitter.angle.min = angle - angle_spread * 0.5; @@ -3557,6 +3558,49 @@ void V_TickForever(WaveLaneCtx *lane) // V_DrawPoint(victim_raycast.p, Color_Green); // V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White); } + + + + + ////////////////////////////// + //- Death + + if (event->is_death) + { + Vec2 death_pos = event->death_pos; + + //- Death particles + { + V_Emitter emitter = Zi; + + emitter.kind = V_ParticleKind_BloodTrail; + // emitter.kind = V_ParticleKind_BloodDebris; + + // f32 angle = AngleFromVec2(frame->look); + f32 angle = 0; + // f32 angle_spread = Tau * 0.25; + f32 angle_spread = Tau; + // f32 angle_spread = 0; + + // f32 speed = 5; + // f32 speed = 25; + f32 speed = 50; + // f32 speed = 100; + f32 speed_spread = speed * 2; + + emitter.pos.p0 = emitter.pos.p1 = death_pos; + emitter.speed.min = speed - speed_spread * 0.5; + emitter.speed.max = speed + speed_spread * 0.5; + emitter.angle.min = angle - angle_spread * 0.5; + emitter.angle.max = angle + angle_spread * 0.5; + + // emitter.count = Kibi(32) * frame->dt; + // emitter.count = Kibi(1); + emitter.count = Kibi(4); + + V_PushParticles(emitter); + } + } } } @@ -5486,20 +5530,6 @@ void V_TickForever(WaveLaneCtx *lane) } } - // //- Test profiler panel - // { - // V_Panel *parent = right_bottom_panel; - // V_Panel *panel = PushStruct(perm, V_Panel); - // panel->axis = Axis_X; - // DllQueuePush(panel->parent->first, panel->parent->last, panel); - // panel->box = UI_KeyF("test raah profiler panel"); - // panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); - // panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); - // panel->flags |= V_PanelFlag_Profiler; - // panel->flags |= V_PanelFlag_Ignore; - // panel->pct = 2; - // } - //- Test spawn panel { V_Panel *panel = PushStruct(perm, V_Panel); @@ -5539,6 +5569,20 @@ void V_TickForever(WaveLaneCtx *lane) panel->flags |= V_PanelFlag_Screen; panel->pct = 1; } + + // //- Test profiler panel + // { + // V_Panel *panel = PushStruct(perm, V_Panel); + // panel->parent = right_panel; + // panel->axis = Axis_X; + // DllQueuePush(panel->parent->first, panel->parent->last, panel); + // panel->box = UI_RandKey(); + // panel->contents_box = UI_KeyF("panel contents box %F", FmtUint(panel->box.v)); + // panel->resizer_box = UI_KeyF("panel resizer box %F", FmtUint(panel->box.v)); + // panel->flags |= V_PanelFlag_Profiler; + // panel->flags |= V_PanelFlag_Ignore; + // panel->pct = 2; + // } } @@ -8005,10 +8049,10 @@ void V_TickForever(WaveLaneCtx *lane) Rng2 shade_scissor = RNG2(VEC2(shade_viewport.p0.x, shade_viewport.p0.y), VEC2(shade_viewport.p1.x, shade_viewport.p1.y)); // Quad buffers - frame->quads_count = ArenaCount(frame->quads_arena, V_Quad); + frame->quads_count = ArenaCount(frame->quads_arena, V_GpuQuad); frame->quads = G_PushStructsFromCpu( cl, gpu_frame_arena, - ArenaFirst(frame->quads_arena, V_Quad), frame->quads_count, + ArenaFirst(frame->quads_arena, V_GpuQuad), frame->quads_count, .name = StringF(frame->arena, "quads [%F]", FmtSint(frame->tick)) ); @@ -8085,6 +8129,7 @@ void V_TickForever(WaveLaneCtx *lane) // Clear particles if (frame->should_clear_particles) { + LogDebugF("Clearing particles"); G_Compute(cl, V_ClearParticlesCS, V_ParticlesCap); V.particle_seq = 0; } diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index c69ecd21..055d5f67 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -418,8 +418,8 @@ Struct(V_Frame) f64 blend_sim_tick; f64 blend_predict_tick; - Button held_buttons[Button_COUNT]; // User input state captured for gameplay - Button real_held_buttons[Button_COUNT]; // Actual state of user input regardless of keyboard / mouse focus + b32 held_buttons[Button_COUNT]; // User input state captured for gameplay + b32 real_held_buttons[Button_COUNT]; // Actual state of user input regardless of keyboard / mouse focus V_Palette palette; UI_Key text_input_focus; @@ -460,6 +460,8 @@ Struct(V_Ctx) V_CmdNode *last_queued_cmd_node; V_CmdNode *first_free_cmd_node; + P_Control queued_pp_control; + diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 86128080..5fc68b11 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -17,6 +17,14 @@ f32 V_LifetimeFromParticleDesc(V_ParticleDesc desc, u32 particle_idx) return result; } +f32 V_FalloffFromParticleDesc(V_ParticleDesc desc, u32 particle_idx) +{ + u64 seed = MixU64(V_ParticleFalloffBasis ^ particle_idx); + f32 rand_falloff = Norm16(seed >> 16); + f32 result = lerp(desc.falloff_min, desc.falloff_max, rand_falloff); + return result; +} + Vec4 V_ColorFromParticleDesc(V_ParticleDesc desc, u32 particle_idx, f32 alive_seconds, u32 density) { Vec4 result = 0; @@ -36,7 +44,7 @@ Vec4 V_ColorFromParticleDesc(V_ParticleDesc desc, u32 particle_idx, f32 alive_se result.a += (1.0 - result.a) * (t); } - else if (desc.kind == V_ParticleKind_BloodTrail || desc.kind == V_ParticleKind_BloodDebris) + else if (desc.kind == V_ParticleKind_BloodTrail) { // f32 t = (f32)density / 5; // t = pow(t, 2); @@ -209,7 +217,8 @@ ComputeShader(V_PrepareCellsCS) } else { - f32 dry_rate = saturate(frame.dt * 0.1); + // f32 dry_rate = saturate(frame.dt * 0.1); + f32 dry_rate = saturate(frame.dt * 0.2); Vec4 before_stain = stains[cell_pos]; Vec4 before_dry_stain = dry_stains[cell_pos]; @@ -360,9 +369,9 @@ ComputeShader(V_BackdropUpCS) VertexShader(V_QuadVS, V_QuadPSInput) { V_SharedFrame frame = G_Deref(V_GpuReg_Frame, StructuredBuffer)[0]; - StructuredBuffer quads = G_Deref(frame.quads, StructuredBuffer); + StructuredBuffer quads = G_Deref(frame.quads, StructuredBuffer); - V_Quad quad = quads[SV_InstanceID]; + V_GpuQuad quad = quads[SV_InstanceID]; Vec2 rect_uv = RectUvFromIdx(SV_VertexID); Vec2 world_pos = mul(quad.quad_uv_to_world_af, Vec3(rect_uv, 1)); @@ -387,7 +396,7 @@ PixelShader(V_QuadPS, V_QuadPSOutput, V_QuadPSInput input) SamplerState sampler = G_Deref(frame.basic_samplers[G_BasicSamplerKind_PointClamp], SamplerState); RWTexture2D occluders = G_Deref(frame.occluders, RWTexture2D); - V_Quad quad = input.quad; + V_GpuQuad quad = input.quad; Texture2D tex = G_Deref(quad.tex, Texture2D); Vec2 world_pos = input.world_pos; @@ -465,7 +474,6 @@ ComputeShader(V_SimParticlesCS) f32 rand_offset = Norm16(seed0 >> 0); f32 rand_angle = Norm16(seed0 >> 16); f32 rand_speed = Norm16(seed0 >> 32); - f32 rand_falloff = Norm16(seed0 >> 48); ////////////////////////////// //- Init particle @@ -711,9 +719,13 @@ ComputeShader(V_SimParticlesCS) } } + f32 rand_falloff = Norm16(seed0 >> 48); // f32 falloff = saturate(lerp(1, 2, rand_falloff) * frame.dt); - // f32 falloff = saturate(lerp(10, 20, rand_falloff) * frame.dt); - f32 falloff = 0; + // f32 falloff = saturate(lerp(10, 20, rand_falloff * frame.dt)); + // f32 falloff = saturate(lerp(5, 10, rand_falloff * frame.dt)); + // f32 falloff = 20 * frame.dt; + + f32 falloff = V_FalloffFromParticleDesc(desc, particle_idx) * frame.dt; particle.velocity *= 1.0f - falloff; particle.pos = p0 + (p1 - p0) * t; @@ -1291,13 +1303,8 @@ ComputeShader(V_BloomDownCS) f32 knee_weight = 1; if (is_first_pass) { - // f32 luminance = LuminanceFromColor(src); - // f32 max_rgb = max(max(src.r, src.g), src.b); // So that we can get bloom on colors with high rgb, not just high luminance - f32 luminance = LuminanceFromColor(src); - f32 max_rgb = -1; // So that we can get bloom on colors with high rgb, not just high luminance - - + f32 max_rgb = max(max(src.r, src.g), src.b); // So that we can get bloom on colors with high rgb, not just high luminance f32 bright = max(luminance, (max_rgb - 1.0) * 0.5); if (bright > 0) { diff --git a/src/pp/pp_vis/pp_vis_gpu.gh b/src/pp/pp_vis/pp_vis_gpu.gh index 9275bb31..a4e334e4 100644 --- a/src/pp/pp_vis/pp_vis_gpu.gh +++ b/src/pp/pp_vis/pp_vis_gpu.gh @@ -6,7 +6,7 @@ Struct(V_QuadPSInput) Vec4 Semantic(sv_position); Vec2 Semantic(world_pos); Vec2 Semantic(samp_uv); - nointerpolation V_Quad Semantic(quad); + nointerpolation V_GpuQuad Semantic(quad); }; Struct(V_QuadPSOutput) @@ -46,6 +46,7 @@ Struct(V_DVertPSOutput) f32 V_RandFromPos(Vec3 pos); f32 V_LifetimeFromParticleDesc(V_ParticleDesc desc, u32 particle_idx); +f32 V_FalloffFromParticleDesc(V_ParticleDesc desc, u32 particle_idx); Vec4 V_ColorFromParticleDesc(V_ParticleDesc desc, u32 particle_idx, f32 alive_seconds, u32 density); //////////////////////////////////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_shared.cg b/src/pp/pp_vis/pp_vis_shared.cg index 83589632..1dccf839 100644 --- a/src/pp/pp_vis/pp_vis_shared.cg +++ b/src/pp/pp_vis/pp_vis_shared.cg @@ -4,18 +4,20 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind) { V_ParticleDesc descs[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, stain_rate, pen_rate, lifetime_min, lifetime_max, prune_speed_threshold, base_color, dry_factor) \ - { \ - V_ParticleKind_##name, \ - flags, \ - layer, \ - stain_rate, \ - pen_rate, \ - lifetime_min, \ - lifetime_max, \ - prune_speed_threshold, \ - LinearFromSrgb(base_color), \ - LinearFromSrgb(dry_factor) \ + #define X(name, flags, layer, stain_rate, pen_rate, lifetime_min, lifetime_max, falloff_min, falloff_max, prune_speed_threshold, base_color, dry_factor) \ + { \ + V_ParticleKind_##name, \ + flags, \ + layer, \ + stain_rate, \ + pen_rate, \ + lifetime_min, \ + lifetime_max, \ + falloff_min, \ + falloff_max, \ + prune_speed_threshold, \ + LinearFromSrgb(base_color), \ + LinearFromSrgb(dry_factor) \ }, V_ParticlesXList(X) #undef X diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index cc9e4257..d28a461a 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -25,6 +25,7 @@ G_DeclRegister(i32, V_GpuReg_MipIdx, 4); #define V_ParticleCellBasis 0xf60c0cff344b0c5dull #define V_ParticleStainBasis 0x3c64e8226d98d376ull #define V_ParticleLifetimeBasis 0x4969cf8f60816abfull +#define V_ParticleFalloffBasis 0xa475ffbeeeef3b9dull Enum(V_ParticleFlag) { @@ -46,7 +47,7 @@ Enum(V_ParticleLayer) V_ParticleLayer_COUNT }; -// NOTE: Higher particle enum values take priority over lower ones +// NOTE: Higher particle enum values take priority over lower within the same layer ones when drawing / staining #define V_ParticlesXList(X) \ X( \ /* Name */ None, \ @@ -54,6 +55,7 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Ground, \ /* Stain rate, pen chance */ 30, 0, \ /* Lifetime */ Inf, Inf, \ + /* Falloff */ 0, 0, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(0, 0, 0, 0), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -66,26 +68,18 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Ground, \ /* Stain rate, pen chance */ 100, 0.25, \ /* Lifetime */ Inf, Inf, \ + /* Falloff */ 10, 20, \ /* Prune speed threshold */ 0.5, \ /* Base color */ VEC4(0.6, 0.1, 0.1, 0.05), \ /* Dry color factor */ VEC4(0.4, 0.4, 0.4, 1) \ ) \ - X( \ - /* Name */ BloodDebris, \ - /* Flags */ V_ParticleFlag_StainWhenPruned, \ - /* Layer */ V_ParticleLayer_Mid, \ - /* Stain rate, pen chance */ 30, 0, \ - /* Lifetime */ Inf, Inf, \ - /* Prune speed threshold */ 0.01, \ - /* Base color */ VEC4(0.5, 0.1, 0.1, 0.8), \ - /* Dry color factor */ VEC4(1, 1, 1, 1) \ - ) \ X( \ /* Name */ Debris, \ /* Flags */ V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, Inf, \ + /* Falloff */ 10, 20, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(0.4, 0.3, 0.2, 1), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -96,38 +90,42 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, Inf, \ + /* Falloff */ 10, 20, \ /* Prune speed threshold */ 0.1, \ /* Base color */ VEC4(2, 0.5, 0, 1), \ /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ ) \ + X( \ + /* Name */ HotDebris, \ + /* Flags */ V_ParticleFlag_StainWhenPruned, \ + /* Layer */ V_ParticleLayer_Mid, \ + /* Stain rate, pen chance */ 0, 0, \ + /* Lifetime */ Inf, Inf, \ + /* Falloff */ 20, 30, \ + /* Prune speed threshold */ 0.1, \ + /* Base color */ VEC4(0.4, 0.3, 0.2, 1), \ + /* Dry color factor */ VEC4(0.2, 0.1, 0.1, 1) \ + ) \ X( \ /* Name */ Spark, \ /* Flags */ V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ 0.2, 0.3, \ + /* Falloff */ 10, 20, \ /* Prune speed threshold */ 0.1, \ /* Base color */ VEC4(2, 0.5, 0, 1), \ /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ ) \ \ /* Air particles */ \ - X( \ - /* Name */ Smoke, \ - /* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend | V_ParticleFlag_FadeLifetime, \ - /* Layer */ V_ParticleLayer_Air, \ - /* Stain rate, pen chance */ 0, 0, \ - /* Lifetime */ Inf, Inf, \ - /* Prune speed threshold */ 0.01, \ - /* Base color */ VEC4(0.25, 0.25, 0.25, 0.75), \ - /* Dry color factor */ VEC4(1, 1, 1, 1) \ - ) \ X( \ /* Name */ BulletSmoke, \ /* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend | V_ParticleFlag_FadeLifetime, \ /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ 0.075, 0.2, \ + /* Falloff */ 0, 0, \ /* Prune speed threshold */ 0.00, \ /* Base color */ VEC4(0.8, 0.6, 0.2, 0.005), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -138,6 +136,7 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Air, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ 0.0, .05, \ + /* Falloff */ 0, 0, \ /* Prune speed threshold */ 0, \ /* Base color */ VEC4(10, 3.5, 0, 1), \ /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ @@ -148,6 +147,7 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Air, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ 0.0, 0.05, \ + /* Falloff */ 0, 0, \ /* Prune speed threshold */ 0, \ /* Base color */ VEC4(10, 3.5, 0, 1), \ /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ @@ -158,6 +158,7 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Air, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ 0.075, 0.075, \ + /* Falloff */ 0, 0, \ /* Prune speed threshold */ 0, \ /* Base color */ VEC4(3, 1.5, 0, 1), \ /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ @@ -168,9 +169,21 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Air, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, Inf, \ + /* Falloff */ 0, 0, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(5, 1.75, 0.75, 1), \ /* Dry color factor */ VEC4(0.2, 0.1, 0.0, 1) \ + ) \ + X( \ + /* Name */ WallDust, \ + /* Flags */ V_ParticleFlag_OnlyCollideWithWalls | V_ParticleFlag_GasBlend | V_ParticleFlag_FadeLifetime, \ + /* Layer */ V_ParticleLayer_Air, \ + /* Stain rate, pen chance */ 0, 0, \ + /* Lifetime */ 0.1, 0.25, \ + /* Falloff */ 10, 20, \ + /* Prune speed threshold */ 0.01, \ + /* Base color */ VEC4(0.5, 0.5, 0.5, 0.35), \ + /* Dry color factor */ VEC4(1, 1, 1, 1) \ ) \ \ /* Test particles */ \ @@ -180,6 +193,7 @@ Enum(V_ParticleLayer) /* Layer */ V_ParticleLayer_Mid, \ /* Stain rate, pen chance */ 0, 0, \ /* Lifetime */ Inf, Inf, \ + /* Falloff */ 0, 0, \ /* Prune speed threshold */ 0.01, \ /* Base color */ VEC4(1, 1, 0, 1), \ /* Dry color factor */ VEC4(1, 1, 1, 1) \ @@ -228,6 +242,8 @@ Struct(V_ParticleDesc) f32 pen_rate; f32 lifetime_min; f32 lifetime_max; + f32 falloff_min; + f32 falloff_max; f32 prune_speed_threshold; Vec4 base_color; Vec4 dry_factor; @@ -244,14 +260,14 @@ Struct(V_ParticleDesc) //////////////////////////////////////////////////////////// //~ Quad types -Enum(V_QuadFlag) +Enum(V_GpuQuadFlag) { V_QuadFlag_None = 0, }; -Struct(V_Quad) +Struct(V_GpuQuad) { - V_QuadFlag flags; + V_GpuQuadFlag flags; u32 occluder_id; Affine quad_uv_to_world_af; G_TextureRef tex; @@ -433,9 +449,6 @@ Struct(V_SharedFrame) Vec2 move; Vec2 look; - f32 fire_held; - f32 fire_presses; - f32 roll_presses; //- Gpu data