From d0e119c476aa8f823f3029b828638e07253390b9 Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 7 Jan 2026 01:22:20 -0600 Subject: [PATCH] track emitter particle sequence on cpu --- src/pp/pp_vis/pp_vis_core.c | 35 +++++++++++++++++++++++++-------- src/pp/pp_vis/pp_vis_core.h | 3 +++ src/pp/pp_vis/pp_vis_gpu.g | 18 +++++++---------- src/pp/pp_vis/pp_vis_shared.cgh | 15 ++++++++------ 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 0df2ac3b..46b6d372 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -2633,25 +2633,37 @@ void V_TickForever(WaveLaneCtx *lane) frame->emitters_count += 1; emitter = &en->emitter; } - V_ParticleFlag flags = V_ParticleFlag_StainOnPrune; + V_ParticleFlag flags = 0; + flags |= V_ParticleFlag_StainOnPrune; + if (TweakBool("Emitter stain trail", 0)) + { + flags |= V_ParticleFlag_StainTrail; + } + emitter->flags = flags; Vec2 dir = victim_raycast.normal; emitter->pos = victim_raycast.p; - emitter->count = 50; + f32 count = TweakFloat("Emitter count", 50, 0, 10000); + f32 speed = TweakFloat("Emitter speed", 10, 0, 100); + f32 falloff = TweakFloat("Emitter falloff", 30, 0, 100); + // f32 angle_spread = TweakFloat("Emitter spread", Tau / 20, 0, Tau); + f32 angle_spread = TweakFloat("Emitter spread", 0.1, 0, 1) * Tau; + + emitter->count = count; // emitter->count = 100; // emitter->count = 500; - emitter->speed = 10; - emitter->speed_spread = 20; + emitter->speed = speed; + emitter->speed_spread = speed * 2; - emitter->velocity_falloff = 30; - emitter->velocity_falloff_spread = 60; + emitter->velocity_falloff = falloff; + emitter->velocity_falloff_spread = falloff * 2; emitter->angle = AngleFromVec2(dir); // emitter->angle_spread = Tau / 4; - emitter->angle_spread = Tau / 20; + emitter->angle_spread = angle_spread; // emitter->angle_spread = Tau / 32; emitter->color_lin = LinearFromSrgb(VEC4(0.5, 0.1, 0.1, 1)); @@ -2666,6 +2678,9 @@ 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); + + emitter->first_particle_seq = V.particle_seq; + V.particle_seq += emitter->count; } @@ -2778,7 +2793,8 @@ void V_TickForever(WaveLaneCtx *lane) case S_DebugDrawKind_Shape: { S_Shape ui_shape = S_MulXformShape(frame->xf.world_to_ui, desc->shape); - V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); + // V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line); + V_DrawShape(ui_shape, color, detail, V_DrawFlag_None); } break; } } @@ -2814,6 +2830,9 @@ void V_TickForever(WaveLaneCtx *lane) // emitter->angle_spread = 0.5; emitter->angle_spread = Tau / 4; // emitter->angle_spread = Tau; + + emitter->first_particle_seq = V.particle_seq; + V.particle_seq += emitter->count; } ////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 65d27cb1..e31bc7f9 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -289,6 +289,9 @@ Struct(V_Ctx) V_Panel *root_panel; V_Window *dragging_window; + // Atomic monotonically increasing allocation counter sequence for GPU particle ring buffer + u32 particle_seq; + Atomic32 shutdown; Fence shutdown_complete; diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 499e092d..0f835056 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -259,18 +259,13 @@ ComputeShader(V_EmitParticlesCS, 64) { V_Emitter emitter = emitters[emitter_idx]; - u32 first_particle_seq; - InterlockedAdd(state_buff[0].particle_seq, emitter.count, first_particle_seq); - u32 last_particle_seq = first_particle_seq + emitter.count; - - u32 particles_created_count = 0; - for (u32 particle_seq = first_particle_seq; particle_seq < last_particle_seq; ++particle_seq) + for (u32 i = 0; i < emitter.count; ++i) { + u32 particle_seq = emitter.first_particle_seq + i; u32 particle_idx = particle_seq % params.max_particles; particles[particle_idx].exists = 1; particles[particle_idx].emitter_init_num = emitter_idx + 1; - particles[particle_idx].idx_in_emitter = particles_created_count; - particles_created_count += 1; + particles[particle_idx].seq = particle_seq; } } } @@ -296,7 +291,7 @@ ComputeShader(V_SimParticlesCS, 64) { V_Emitter emitter = G_Dereference(params.emitters)[particle.emitter_init_num - 1]; - u64 seed = MixU64(emitter.seed + particle.idx_in_emitter); + u64 seed = MixU64(emitter.seed + particle.seq); // u32 speed_noise = (u32)((seed >> 0) & 0xFF); // u32 angle_noise = (u32)((seed >> 8) & 0xFF); @@ -321,6 +316,7 @@ ComputeShader(V_SimParticlesCS, 64) f32 velocity_falloff = emitter.velocity_falloff + rand_falloff * emitter.velocity_falloff; Vec3 color = emitter.color_lin.rgb + Vec3(rand_r, rand_g, rand_b) * emitter.color_spread; + particle.flags = emitter.flags; particle.pos = emitter.pos; particle.velocity = Vec2(cos(angle), sin(angle)) * speed; particle.velocity_falloff = velocity_falloff; @@ -333,7 +329,7 @@ ComputeShader(V_SimParticlesCS, 64) { particle.pos += particle.velocity * params.dt; particle.velocity = lerp(particle.velocity, 0, particle.velocity_falloff * params.dt); - if (particle.exists < 0.0001) + if (particle.exists < 0.001 || dot(particle.velocity, particle.velocity) < (0.001 * 0.001)) { particle.exists = 0; } @@ -346,7 +342,7 @@ ComputeShader(V_SimParticlesCS, 64) if (cell_pos.x >= 0 && cell_pos.y >= 0 && cell_pos.x < countof(stains).x && cell_pos.y < countof(stains).y) { b32 should_stain = 0; - if (particle.flags & V_ParticleFlag_StainOnPrune && particle.exists == 0) + if (particle.flags & V_ParticleFlag_StainTrail || ((particle.flags & V_ParticleFlag_StainOnPrune) && particle.exists == 0)) { should_stain = 1; } diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 53072a7c..d9ab5693 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -35,7 +35,8 @@ Struct(V_Xforms) Struct(V_GpuState) { - u32 particle_seq; // Atomic monotonically increasing allocation counter sequence for particle ring buffer + // u32 particle_seq; // Atomic monotonically increasing allocation counter sequence for particle ring buffer + i32 _; }; Struct(V_GpuParams) @@ -87,16 +88,19 @@ Enum(V_ParticleFlag) { V_ParticleFlag_None = 0, V_ParticleFlag_StainOnPrune = (1 << 0), + V_ParticleFlag_StainTrail = (1 << 1), }; Struct(V_Emitter) { V_ParticleFlag flags; - Vec2 pos; + u32 first_particle_seq; u32 count; u64 seed; + Vec2 pos; + f32 speed; f32 speed_spread; @@ -113,11 +117,10 @@ Struct(V_Emitter) // TODO: Pack this efficiently Struct(V_Particle) { - V_ParticleFlag flags; - - u32 emitter_init_num; // if != 0, then initialize using emitter at index (emitter_init_num - 1) + u32 emitter_init_num; // if != 0, then initialize using emitter at index [emitter_init_num - 1] u32 seq; - u32 idx_in_emitter; + + V_ParticleFlag flags; Vec2 pos; Vec2 velocity;