From a9ca71189276046f4061a67008c53eb840019384 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 16 Feb 2026 19:16:58 -0600 Subject: [PATCH] particle layer testing --- src/pp/pp_shared.cgh | 3 + src/pp/pp_vis/pp_vis_core.c | 146 +++----- src/pp/pp_vis/pp_vis_gpu.g | 575 +++++++++++++++++++++++--------- src/pp/pp_vis/pp_vis_gpu.gh | 2 +- src/pp/pp_vis/pp_vis_shared.cg | 25 +- src/pp/pp_vis/pp_vis_shared.cgh | 333 +++++++++--------- 6 files changed, 668 insertions(+), 416 deletions(-) diff --git a/src/pp/pp_shared.cgh b/src/pp/pp_shared.cgh index 1355852e..48b43851 100644 --- a/src/pp/pp_shared.cgh +++ b/src/pp/pp_shared.cgh @@ -11,6 +11,9 @@ #define P_TilesCount (P_TilesPitch * P_TilesPitch) #define P_CellsCount (P_CellsPitch * P_TilesPitch) +#define P_WorldTilesDims VEC2(P_TilesPitch, P_TilesPitch) +#define P_WorldCellsDims VEC2(P_CellsPitch, P_CellsPitch) + //////////////////////////////////////////////////////////// //~ Material types diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index c8f15763..e07158c5 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -389,32 +389,26 @@ void V_TickForever(WaveLaneCtx *lane) Vec2I32 tiles_dims = VEC2I32(P_TilesPitch, P_TilesPitch); Vec2I32 cells_dims = VEC2I32(P_CellsPitch, P_CellsPitch); - // Init gpu state + //- Init gpu state G_ResourceHandle gpu_tiles_res = Zi; G_ResourceHandle gpu_particles_res = Zi; - G_ResourceHandle gpu_stain_cells_res = Zi; - G_ResourceHandle gpu_ground_cells_res = Zi; - G_ResourceHandle gpu_air_cells_res = Zi; - G_ResourceHandle gpu_stain_densities_res = Zi; - G_ResourceHandle gpu_ground_densities_res = Zi; - G_ResourceHandle gpu_air_densities_res = Zi; + G_ResourceHandle gpu_particle_cell_resources[V_ParticleLayer_COUNT]; + G_ResourceHandle gpu_particle_density_resources[V_ParticleLayer_COUNT]; + G_ResourceHandle gpu_stains_res = Zi; G_ResourceHandle gpu_drynesses_res = Zi; G_ResourceHandle gpu_occluders_res = Zi; G_Texture2DRef gpu_tiles = Zi; G_RWStructuredBufferRef gpu_particles = Zi; - G_RWTexture2DRef gpu_stain_cells = Zi; - G_RWTexture2DRef gpu_ground_cells = Zi; - G_RWTexture2DRef gpu_air_cells = Zi; - G_RWTexture2DRef gpu_stain_densities = Zi; - G_RWTexture2DRef gpu_ground_densities = Zi; - G_RWTexture2DRef gpu_air_densities = Zi; + G_RWTexture2DRef gpu_particle_cells[V_ParticleLayer_COUNT]; + G_RWTexture2DRef gpu_particle_densities[V_ParticleLayer_COUNT]; + G_RWTexture2DRef gpu_stains = Zi; G_RWTexture2DRef gpu_drynesses = Zi; G_RWTexture2DRef gpu_occluders = Zi; { G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct); { - // Init tile map texture + //- Init tile map texture { gpu_tiles_res = G_PushTexture2D( gpu_perm, cl, @@ -426,7 +420,7 @@ void V_TickForever(WaveLaneCtx *lane) ); gpu_tiles = G_PushTexture2DRef(gpu_perm, gpu_tiles_res); } - // Init particle buffer + //- Init particle buffer { gpu_particles_res = G_PushBuffer( gpu_perm, cl, @@ -437,79 +431,49 @@ void V_TickForever(WaveLaneCtx *lane) ); gpu_particles = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles_res, V_Particle); } - // Init stain cells texture + //- Init particle textures + for (V_ParticleLayer layer = 0; layer < V_ParticleLayer_COUNT; ++layer) { - gpu_stain_cells_res = G_PushTexture2D( + { + G_ResourceHandle cells_res = G_PushTexture2D( + gpu_perm, cl, + G_Format_R32_Uint, + cells_dims, + G_Layout_DirectQueue_ShaderReadWrite, + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, + .name = StringF(perm, "Particle cells - layer %F", FmtSint(layer)) + ); + G_RWTexture2DRef cells = G_PushRWTexture2DRef(gpu_perm, cells_res); + gpu_particle_cell_resources[layer] = cells_res; + gpu_particle_cells[layer] = cells; + } + { + G_ResourceHandle densities_res = G_PushTexture2D( + gpu_perm, cl, + G_Format_R32_Uint, + cells_dims, + G_Layout_DirectQueue_ShaderReadWrite, + .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, + .name = StringF(perm, "Particle densities - layer %F", FmtSint(layer)) + ); + G_RWTexture2DRef densities = G_PushRWTexture2DRef(gpu_perm, densities_res); + gpu_particle_density_resources[layer] = densities_res; + gpu_particle_densities[layer] = densities; + } + } + //- Init stains texture + { + gpu_stains_res = G_PushTexture2D( gpu_perm, cl, - G_Format_R32_Uint, + G_Format_R16G16B16A16_Float, cells_dims, G_Layout_DirectQueue_ShaderReadWrite, .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Stain cells") + .name = Lit("Stains") ); - gpu_stain_cells = G_PushRWTexture2DRef(gpu_perm, gpu_stain_cells_res); + gpu_stains = G_PushRWTexture2DRef(gpu_perm, gpu_stains_res); } - // Init ground cells texture - { - gpu_ground_cells_res = G_PushTexture2D( - gpu_perm, cl, - G_Format_R32_Uint, - cells_dims, - G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Ground cells") - ); - gpu_ground_cells = G_PushRWTexture2DRef(gpu_perm, gpu_ground_cells_res); - } - // Init air cells texture - { - gpu_air_cells_res = G_PushTexture2D( - gpu_perm, cl, - G_Format_R32_Uint, - cells_dims, - G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Air cells") - ); - gpu_air_cells = G_PushRWTexture2DRef(gpu_perm, gpu_air_cells_res); - } - // Init stain densities texture - { - gpu_stain_densities_res = G_PushTexture2D( - gpu_perm, cl, - G_Format_R32_Uint, - cells_dims, - G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Stain densities") - ); - gpu_stain_densities = G_PushRWTexture2DRef(gpu_perm, gpu_stain_densities_res); - } - // Init ground densities texture - { - gpu_ground_densities_res = G_PushTexture2D( - gpu_perm, cl, - G_Format_R32_Uint, - cells_dims, - G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Ground densities") - ); - gpu_ground_densities = G_PushRWTexture2DRef(gpu_perm, gpu_ground_densities_res); - } - // Init air densities texture - { - gpu_air_densities_res = G_PushTexture2D( - gpu_perm, cl, - G_Format_R32_Uint, - cells_dims, - G_Layout_DirectQueue_ShaderReadWrite, - .flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite, - .name = Lit("Air densities") - ); - gpu_air_densities = G_PushRWTexture2DRef(gpu_perm, gpu_air_densities_res); - } - // Init drynesses texture + //- Init dryness texture { gpu_drynesses_res = G_PushTexture2D( gpu_perm, cl, @@ -521,7 +485,7 @@ void V_TickForever(WaveLaneCtx *lane) ); gpu_drynesses = G_PushRWTexture2DRef(gpu_perm, gpu_drynesses_res); } - // Init occluders texture + //- Init occluders texture { gpu_occluders_res = G_PushTexture2D( gpu_perm, cl, @@ -650,14 +614,14 @@ void V_TickForever(WaveLaneCtx *lane) { frame->basic_samplers[sampler_kind] = G_BasicSamplerFromKind(sampler_kind); } + for (V_ParticleLayer layer = 0; layer < V_ParticleLayer_COUNT; ++layer) + { + frame->particle_cells[layer] = gpu_particle_cells[layer]; + frame->particle_densities[layer] = gpu_particle_densities[layer]; + } frame->tiles = gpu_tiles; frame->particles = gpu_particles; - frame->stain_cells = gpu_stain_cells; - frame->ground_cells = gpu_ground_cells; - frame->air_cells = gpu_air_cells; - frame->stain_densities = gpu_stain_densities; - frame->ground_densities = gpu_ground_densities; - frame->air_densities = gpu_air_densities; + frame->stains = gpu_stains; frame->drynesses = gpu_drynesses; frame->occluders = gpu_occluders; } @@ -2562,8 +2526,8 @@ void V_TickForever(WaveLaneCtx *lane) ////////////////////////////// //- Push test emitter - // if (frame->held_buttons[Button_F]) - if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F]) + if (frame->held_buttons[Button_F]) + // if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F]) { { V_Emitter emitter = Zi; @@ -5045,8 +5009,6 @@ void V_TickForever(WaveLaneCtx *lane) { i32 mips_count = G_CountMips(bloom_target); - G_DumbMemoryLayoutSync(frame->cl, screen_target, G_Layout_DirectQueue_ShaderRead); - //- Downsample + blur passes for (i32 mip_idx = 0; mip_idx < mips_count; ++mip_idx) { diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 95d6c46c..9226f75c 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -10,10 +10,8 @@ f32 V_RandFromPos(Vec3 pos) return rand; } -Vec4 V_ColorFromParticle(V_ParticleKind particle_kind, u32 particle_idx, u32 density, f32 dryness) +Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density) { - V_ParticleDesc desc = V_DescFromParticleKind(particle_kind); - Vec4 result = 0; u64 seed = MixU64(V_ParticleColorBasis ^ particle_idx); f32 rand_color = Norm16(seed >> 0); @@ -21,30 +19,30 @@ Vec4 V_ColorFromParticle(V_ParticleKind particle_kind, u32 particle_idx, u32 den result = desc.color; // // FIXME: Base color on particle desc - // if (particle_kind == V_ParticleKind_Test) + // if (desc.kind == V_ParticleKind_Test) // { // // result.rgb = Vec3(0, 0, 0); // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 0.5)); // } - // else if (particle_kind == V_ParticleKind_Debris) + // else if (desc.kind == V_ParticleKind_Debris) // { // result = Color_Orange; // } - // else if (particle_kind == V_ParticleKind_Smoke) + // else if (desc.kind == V_ParticleKind_Smoke) // { // result = Vec4(0.15, 0.15, 0.15, 1); // } // Apply density { - if (particle_kind == V_ParticleKind_Smoke) + if (desc.kind == V_ParticleKind_Smoke) { // f32 t = saturate(density / 10.0); f32 t = smoothstep(-10, 32, density); // f32 t = smoothstep(0, 2, (f32)density); result.a = lerp(0, 0.85, t); } - else if (particle_kind == V_ParticleKind_BloodTrail || particle_kind == V_ParticleKind_BloodDebris) + else if (desc.kind == V_ParticleKind_BloodTrail || desc.kind == V_ParticleKind_BloodDebris) { // f32 t = (f32)density / 5; // t = pow(t, 2); @@ -67,7 +65,6 @@ Vec4 V_ColorFromParticle(V_ParticleKind particle_kind, u32 particle_idx, u32 den // result.a *= rand_alpha; // Apply dryness - result.rgb *= 1.0 - (dryness * 0.75); return result; } @@ -99,59 +96,69 @@ ComputeShader2D(V_PrepareCellsCS, 8, 8) { V_SharedFrame frame = G_Dereference(V_GpuConst_Frame)[0]; Texture2D tiles = G_Dereference(frame.tiles); - RWTexture2D stain_cells = G_Dereference(frame.stain_cells); - RWTexture2D ground_cells = G_Dereference(frame.ground_cells); - RWTexture2D air_cells = G_Dereference(frame.air_cells); - RWTexture2D stain_densities = G_Dereference(frame.stain_densities); - RWTexture2D ground_densities = G_Dereference(frame.ground_densities); - RWTexture2D air_densities = G_Dereference(frame.air_densities); + RWTexture2D stains = G_Dereference(frame.stains); RWTexture2D drynesses = G_Dereference(frame.drynesses); RWTexture2D occluders = G_Dereference(frame.occluders); Vec2 cell_pos = SV_DispatchThreadID + 0.5; - if (all(cell_pos < countof(air_cells))) + if (all(cell_pos < P_WorldCellsDims)) { Vec2 world_pos = mul(frame.af.cell_to_world, Vec3(cell_pos, 1)); Vec2 tile_pos = mul(frame.af.world_to_tile, Vec3(world_pos, 1)); P_TileKind tile = tiles[tile_pos]; - // Update stains + //- Reset occluders + + { + V_OccluderKind occluder = V_OccluderKind_None; + if (tile == P_TileKind_Wall) + { + occluder = V_OccluderKind_Wall; + } + occluders[cell_pos] = occluder; + } + + //- Reset particle layers + + Vec4 new_stain = 0; + for (V_ParticleLayer layer = (V_ParticleLayer)0; layer < V_ParticleLayer_COUNT; layer += (V_ParticleLayer)1) + { + RWTexture2D cells = G_Dereference(frame.particle_cells[layer]); + RWTexture2D densities = G_Dereference(frame.particle_densities[layer]); + u32 packed = cells[cell_pos]; + if (packed & (1 << 31)) + { + V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); + V_ParticleDesc desc = V_DescFromParticleKind(particle_kind); + u32 density = densities[cell_pos]; + u32 particle_idx = packed & ((1 << 24) - 1); + Vec4 particle_color = V_ColorFromParticle(desc, particle_idx, density); + particle_color.rgb *= particle_color.a; + new_stain = BlendPremul(particle_color, new_stain); + } + cells[cell_pos] = 0; + densities[cell_pos] = 0; + } + + //- Update stains + if (frame.should_clear_particles) { - stain_densities[cell_pos] = 0; - stain_cells[cell_pos] = 0; + stains[cell_pos] = 0; + drynesses[cell_pos] = 0; + } + else if (new_stain.a > 0) + { + Vec4 stain = stains[cell_pos]; + stain = BlendPremul(new_stain, stain); + stains[cell_pos] = stain; drynesses[cell_pos] = 0; } else { - u32 stain = stain_cells[cell_pos]; - { - stain &= ~(1 << 31); - } - f32 dryness = drynesses[cell_pos]; - { - f32 dry_rate = frame.dt * 0.1; - dryness = lerp(dryness, 1, dry_rate); - } - stain_cells[cell_pos] = stain; - drynesses[cell_pos] = dryness; + f32 dry_rate = frame.dt * 0.1; + drynesses[cell_pos] = lerp(drynesses[cell_pos], 1, dry_rate); } - - // Clear cells - ground_cells[cell_pos] = 0; - air_cells[cell_pos] = 0; - - // Clear densities - ground_densities[cell_pos] = 0; - air_densities[cell_pos] = 0; - - // Reset occluders - V_OccluderKind occluder = V_OccluderKind_None; - if (tile == P_TileKind_Wall) - { - occluder = V_OccluderKind_Wall; - } - occluders[cell_pos] = occluder; } } @@ -210,7 +217,7 @@ PixelShader(V_QuadPS, V_QuadPSOutput, V_QuadPSInput input) Vec2 world_pos = input.world_pos; Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(world_pos, 1)); - b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(occluders)); + b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < P_WorldCellsDims); Vec4 albedo = tex.Sample(sampler, input.samp_uv); @@ -270,13 +277,6 @@ ComputeShader(V_SimParticlesCS, 64) V_SharedFrame frame = G_Dereference(V_GpuConst_Frame)[0]; Texture2D tiles = G_Dereference(frame.tiles); RWStructuredBuffer particles = G_Dereference(frame.particles); - RWTexture2D stain_cells = G_Dereference(frame.stain_cells); - RWTexture2D ground_cells = G_Dereference(frame.ground_cells); - RWTexture2D air_cells = G_Dereference(frame.air_cells); - RWTexture2D stain_densities = G_Dereference(frame.stain_densities); - RWTexture2D ground_densities = G_Dereference(frame.ground_densities); - RWTexture2D air_densities = G_Dereference(frame.air_densities); - RWTexture2D drynesses = G_Dereference(frame.drynesses); RWTexture2D occluders = G_Dereference(frame.occluders); u32 particle_idx = SV_DispatchThreadID; @@ -317,17 +317,29 @@ ComputeShader(V_SimParticlesCS, 64) particle.velocity = Vec2(cos(initial_angle), sin(initial_angle)) * initial_speed; } + + + + + + if (particle.kind > V_ParticleKind_None && particle.kind < V_ParticleKind_COUNT) { V_ParticleDesc desc = V_DescFromParticleKind((V_ParticleKind)particle.kind); + RWTexture2D cells = G_Dereference(frame.particle_cells[desc.layer]); + RWTexture2D densities = G_Dereference(frame.particle_densities[desc.layer]); u32 packed = 0; packed |= (particle_idx & ((1 >> 24) - 1)) << 0; packed |= (particle.kind & 0xFF) << 24; - packed |= 1 << 31; StaticAssert(V_ParticlesCap <= (1 << 24)); // particle idx must fit in 24 bits StaticAssert(V_ParticleKind_COUNT <= 0x7F); // particle kind must fit in 7 bits + if (AnyBit(desc.flags, V_ParticleFlag_StainTrail)) + { + packed |= 1 << 31; + } + ////////////////////////////// //- Move @@ -397,13 +409,13 @@ ComputeShader(V_SimParticlesCS, 64) Vec2 cell_screen_pos_p1 = mul(frame.af.world_to_screen, Vec3(mul(frame.af.cell_to_world, Vec3(ceil(cell_pos), 1)), 1)); cell_screen_pos_p1 = max(cell_screen_pos_p1, cell_screen_pos_p0 + 1); - b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(air_cells)); + b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < P_WorldCellsDims); b32 is_visible = all(cell_screen_pos_p1 >= 0) && all(cell_screen_pos_p0 < frame.screen_dims); if (is_in_world) { - f32 stain_delta = abs(t_diff) * desc.stain_rate * frame.dt; - particle.stain_accum += stain_delta; + f32 commit_delta = abs(t_diff) * desc.commit_rate * frame.dt; + particle.commit_accum += commit_delta; //- Handle collision V_OccluderKind occluder = (V_OccluderKind)occluders[cell_pos]; @@ -450,49 +462,31 @@ ComputeShader(V_SimParticlesCS, 64) } - if (AnyBit(desc.flags, V_ParticleFlag_PruneWhenStill)) + if (!AnyBit(desc.flags, V_ParticleFlag_NoPruneWhenStill) && dot(particle.velocity, particle.velocity) < 0.0001) { - if (dot(particle.velocity, particle.velocity) < 0.0001) - { - prune = 1; - } + prune = 1; } - if (prune && AnyBit(desc.flags, V_ParticleFlag_StainWhenPruned)) + if (prune) { - particle.stain_accum += 1; + done = 1; + if (AnyBit(desc.flags, V_ParticleFlag_StainWhenPruned)) + { + // particle.commit_accum = max(particle.commit_accum, 1); + particle.commit_accum += 1; + packed |= 1 << 31; + } } if (!collision) { - //- Stain - u32 stains_count = floor(particle.stain_accum); - if (stains_count > 0) + u32 commit_count = floor(particle.commit_accum); + u32 density = commit_count; + { - // TODO: Fixed point - u32 density = round(stains_count * rand_density); - InterlockedMax(stain_cells[cell_pos], packed); - InterlockedAdd(stain_densities[cell_pos], density); - drynesses[cell_pos] = 0; - particle.stain_accum -= stains_count; - } - - //- Draw - { - b32 should_draw_ground = is_visible && AnyBit(desc.flags, V_ParticleFlag_Ground); - b32 should_draw_air = is_visible && AnyBit(desc.flags, V_ParticleFlag_Air); - - if (should_draw_ground) - { - InterlockedMax(ground_cells[cell_pos], packed); - InterlockedAdd(ground_densities[cell_pos], 1); - } - - if (should_draw_air) - { - InterlockedMax(air_cells[cell_pos], packed); - InterlockedAdd(air_densities[cell_pos], 1); - } + InterlockedMax(cells[cell_pos], packed); + InterlockedAdd(densities[cell_pos], density); + particle.commit_accum -= commit_count; } } } @@ -514,10 +508,234 @@ ComputeShader(V_SimParticlesCS, 64) particle.pos = p0 + (p1 - p0) * t; } - // Increment life - particle.life += frame.dt; + // Increment life + particle.life += frame.dt; } + + + + + + + + + + + + + // if (particle.kind > V_ParticleKind_None && particle.kind < V_ParticleKind_COUNT) + // { + // V_ParticleDesc desc = V_DescFromParticleKind((V_ParticleKind)particle.kind); + + // u32 packed = 0; + // packed |= (particle_idx & ((1 >> 24) - 1)) << 0; + // packed |= (particle.kind & 0xFF) << 24; + // packed |= 1 << 31; + // StaticAssert(V_ParticlesCap <= (1 << 24)); // particle idx must fit in 24 bits + // StaticAssert(V_ParticleKind_COUNT <= 0x7F); // particle kind must fit in 6 bits + + // ////////////////////////////// + // //- Move + + // b32 collision = 0; + + // // TODO: Clip to avoid unnecessary iterations outside of world bounds + // { + // Vec2 p0 = particle.pos; + // Vec2 p1 = particle.pos + particle.velocity * frame.dt; + // f32 t = 1; + // { + // Vec2 occluder_p0 = mul(frame.af.world_to_cell, Vec3(p0, 1)); + // Vec2 occluder_p1 = mul(frame.af.world_to_cell, Vec3(p1, 1)); + // Vec2I32 cell_p0 = floor(occluder_p0); + // Vec2I32 cell_p1 = floor(occluder_p1); + + // Vec2 delta = occluder_p1 - occluder_p0; + // Vec2 inv_delta = 1.0 / delta; + // Vec2 dda_step_dir = Vec2((delta.x > 0) - (delta.x < 0), (delta.y > 0) - (delta.y < 0)); + // Vec2 t_delta = abs(inv_delta); + // Vec2 t_max = cell_p0 - occluder_p0; + // t_max.x += dda_step_dir.x > 0; + // t_max.y += dda_step_dir.y > 0; + // t_max *= inv_delta; + // t_max = abs(t_max); + + // Vec2 t_hit = 0; + + // Vec2I32 cell_pos = cell_p0; + + // b32 stepped_x = 0; + // b32 stepped_y = 0; + + // // TODO: Tune this + // u32 max_iterations = 128; + + // b32 done = 0; + // f32 t_diff = 0; + // for (u32 iteration_idx = 0; iteration_idx < max_iterations && !done; ++iteration_idx) + // { + // if (cell_pos.x == cell_p1.x && cell_pos.y == cell_p1.y) + // { + // done = 1; + // } + // else if (t_max.x < t_max.y) + // { + // cell_pos.x += dda_step_dir.x; + // f32 old = t_hit.x; + // t_hit.x = t_max.x - t_delta.x; + // t_diff = t_hit.x - old; + // t_max.x += t_delta.x; + // stepped_x = 1; + // stepped_y = 0; + // } + // else + // { + // cell_pos.y += dda_step_dir.y; + // f32 old = t_hit.y; + // t_hit.y = t_max.y - t_delta.y; + // t_diff = t_hit.y - old; + // t_max.y += t_delta.y; + // stepped_x = 0; + // stepped_y = 1; + // } + + // Vec2 cell_screen_pos_p0 = mul(frame.af.world_to_screen, Vec3(mul(frame.af.cell_to_world, Vec3(floor(cell_pos), 1)), 1)); + // Vec2 cell_screen_pos_p1 = mul(frame.af.world_to_screen, Vec3(mul(frame.af.cell_to_world, Vec3(ceil(cell_pos), 1)), 1)); + // cell_screen_pos_p1 = max(cell_screen_pos_p1, cell_screen_pos_p0 + 1); + + // b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < P_WorldCellsDims); + // b32 is_visible = all(cell_screen_pos_p1 >= 0) && all(cell_screen_pos_p0 < frame.screen_dims); + + // if (is_in_world) + // { + // f32 commit_delta = abs(t_diff) * desc.commit_rate * frame.dt; + // particle.commit_accum += commit_delta; + + // //- Handle collision + // V_OccluderKind occluder = (V_OccluderKind)occluders[cell_pos]; + // if (occluder != V_OccluderKind_None) + // { + // u64 collision_seed = MixU64(V_ParticleCellBasis ^ seed0 ^ particle.cells_count); + // f32 rand_collision_angle = Norm16(collision_seed >> 0); + // f32 rand_collision_velocity = Norm16(collision_seed >> 16); + // f32 rand_collision_penetration = Norm16(collision_seed >> 32); + // if (rand_collision_penetration >= desc.pen_rate) + // { + // collision = 1; + // done = 1; + // { + // if (stepped_x) + // { + // if (!AnyBit(desc.flags, V_ParticleFlag_NoReflect)) + // { + // particle.velocity.x *= -1; + // } + // t = saturate(t_hit.x); + // } + // else if (stepped_y) + // { + // if (!AnyBit(desc.flags, V_ParticleFlag_NoReflect)) + // { + // particle.velocity.y *= -1; + // } + // t = saturate(t_hit.y); + // } + // { + // f32 collision_angle = lerp(-0.05 * Tau, 0.05 * Tau, rand_collision_angle); + + // f32 collision_velocity_falloff = lerp(50, 100, rand_collision_velocity); + // // f32 collision_velocity_falloff = lerp(5000, 10000, rand_collision_velocity); + // // f32 collision_velocity_falloff = lerp(500, 10000, rand_collision_velocity); + // // f32 collision_velocity_falloff = 0; + + // particle.velocity = RotateVec2Angle(particle.velocity, collision_angle); + // particle.velocity *= 1.0f - saturate(collision_velocity_falloff * frame.dt); + // } + // } + // } + + // } + + // if (AnyBit(desc.flags, V_ParticleFlag_PruneWhenStill)) + // { + // if (dot(particle.velocity, particle.velocity) < 0.0001) + // { + // prune = 1; + // } + // } + + // if (prune && AnyBit(desc.flags, V_ParticleFlag_StainWhenPruned)) + // { + // particle.commit_accum += 1; + // } + + // if (!collision) + // { + // //- Stain + // u32 stains_count = floor(particle.commit_accum); + // if (stains_count > 0) + // { + // // TODO: Fixed point + // u32 density = round(stains_count * rand_density); + // InterlockedMax(stain_cells[cell_pos], packed); + // InterlockedAdd(stain_densities[cell_pos], density); + // drynesses[cell_pos] = 0; + // particle.commit_accum -= stains_count; + // } + + // //- Draw + // { + // b32 should_draw_ground = is_visible && AnyBit(desc.flags, V_ParticleFlag_Ground); + // b32 should_draw_air = is_visible && AnyBit(desc.flags, V_ParticleFlag_Air); + + // if (should_draw_ground) + // { + // InterlockedMax(ground_cells[cell_pos], packed); + // InterlockedAdd(ground_densities[cell_pos], 1); + // } + + // if (should_draw_air) + // { + // InterlockedMax(air_cells[cell_pos], packed); + // InterlockedAdd(air_densities[cell_pos], 1); + // } + // } + // } + // } + // else + // { + // done = 1; + // prune = 1; + // } + + // particle.cells_count += 1; + // iteration_idx += 1; + // } + // } + + // f32 falloff = saturate(lerp(10, 20, rand_falloff) * frame.dt); + // // f32 falloff = saturate(lerp(1, 2, rand_falloff) * frame.dt); + // particle.velocity *= 1.0f - falloff; + + // particle.pos = p0 + (p1 - p0) * t; + // } + + // // Increment life + // particle.life += frame.dt; + // } + + + + + + + + + + + + if (prune) { particle.kind = V_ParticleKind_None; @@ -540,7 +758,6 @@ ComputeShader2D(V_ShadeCS, 8, 8) Texture2D tiles = G_Dereference(frame.tiles); Texture2D albedo_tex = G_Dereference(frame.albedo_ro); RWTexture2D shade_tex = G_Dereference(frame.shade_rw); - RWTexture2D stain_cells = G_Dereference(frame.stain_cells); RWTexture2D drynesses = G_Dereference(frame.drynesses); Vec2 shade_pos = SV_DispatchThreadID + 0.5; @@ -551,7 +768,7 @@ ComputeShader2D(V_ShadeCS, 8, 8) P_TileKind tile = tiles[tile_pos]; Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5; - b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(stain_cells)); + b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < P_WorldCellsDims); ////////////////////////////// //- Compute result @@ -577,12 +794,7 @@ ComputeShader2D(V_CompositeCS, 8, 8) SamplerState sampler = G_Dereference(frame.basic_samplers[G_BasicSamplerKind_PointClamp]); Texture2D albedo_tex = G_Dereference(frame.albedo_ro); RWTexture2D screen_tex = G_Dereference(frame.screen_rw); - RWTexture2D stain_cells = G_Dereference(frame.stain_cells); - RWTexture2D ground_cells = G_Dereference(frame.ground_cells); - RWTexture2D stain_densities = G_Dereference(frame.stain_densities); - RWTexture2D air_cells = G_Dereference(frame.air_cells); - RWTexture2D ground_densities = G_Dereference(frame.ground_densities); - RWTexture2D air_densities = G_Dereference(frame.air_densities); + RWTexture2D stains = G_Dereference(frame.stains); RWTexture2D drynesses = G_Dereference(frame.drynesses); Texture2D tiles = G_Dereference(frame.tiles); RWStructuredBuffer particles = G_Dereference(frame.particles); @@ -596,7 +808,7 @@ ComputeShader2D(V_CompositeCS, 8, 8) Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5; Vec2 world_bounds_screen_p0 = mul(frame.af.world_to_screen, Vec3(-half_world_dims.xy, 1)); Vec2 world_bounds_screen_p1 = mul(frame.af.world_to_screen, Vec3(half_world_dims.xy, 1)); - b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(ground_cells)); + b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < P_WorldCellsDims); b32 is_in_screen = all(screen_pos >= 0) && all(screen_pos < countof(screen_tex)); P_TileKind tile = tiles[tile_pos]; @@ -698,76 +910,129 @@ ComputeShader2D(V_CompositeCS, 8, 8) ////////////////////////////// //- Particles - Vec4 stain_particle_color = 0; - Vec4 ground_particle_color = 0; - Vec4 air_particle_color = 0; + // FIXME: Stain + Vec4 stain_color = 0; { - //- Stain + Vec4 orig_stain = stains[cell_pos]; + + // FIXME: Dryness + // f32 dryness = drynesses[cell_pos]; + stain_color = orig_stain; + } + + + Vec4 particle_color = 0; + + + for (V_ParticleLayer layer = (V_ParticleLayer)0; layer < V_ParticleLayer_COUNT; layer += (V_ParticleLayer)1) + { + RWTexture2D cells = G_Dereference(frame.particle_cells[layer]); + RWTexture2D densities = G_Dereference(frame.particle_densities[layer]); + u32 packed = cells[cell_pos]; + V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); + if (particle_kind != V_ParticleKind_None) { - { - u32 packed = stain_cells[cell_pos]; - V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); - if (particle_kind != V_ParticleKind_None) - { - u32 particle_idx = packed & ((1 << 24) - 1); - u32 density = stain_densities[cell_pos]; - f32 dryness = drynesses[cell_pos]; - stain_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, dryness); - } - } - stain_particle_color.rgb *= 1.0 - (0.30 * tile_is_wall); // Darken wall stains - stain_particle_color.rgb *= stain_particle_color.a; - } - //- Ground - { - { - u32 packed = ground_cells[cell_pos]; - V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); - if (particle_kind != V_ParticleKind_None) - { - u32 particle_idx = packed & ((1 << 24) - 1); - u32 density = ground_densities[cell_pos]; - ground_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, 0); - } - } - ground_particle_color.rgb *= ground_particle_color.a; - } - //- Air - { - { - u32 packed = air_cells[cell_pos]; - V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); - if (particle_kind != V_ParticleKind_None) - { - u32 particle_idx = packed & ((1 << 24) - 1); - u32 density = air_densities[cell_pos]; - air_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, 0); - } - } - air_particle_color.rgb *= air_particle_color.a; + u32 density = densities[cell_pos]; + V_ParticleDesc desc = V_DescFromParticleKind(particle_kind); + u32 particle_idx = packed & ((1 << 24) - 1); + Vec4 cell_color = V_ColorFromParticle(desc, particle_idx, density); + cell_color.rgb *= cell_color.a; + particle_color = BlendPremul(cell_color, particle_color); } } + + + + // Vec4 stain_particle_color = 0; + // Vec4 ground_particle_color = 0; + // Vec4 air_particle_color = 0; + // { + // //- Stain + // { + // { + // u32 packed = stain_cells[cell_pos]; + // V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); + // if (particle_kind != V_ParticleKind_None) + // { + // u32 particle_idx = packed & ((1 << 24) - 1); + // u32 density = stain_densities[cell_pos]; + // f32 dryness = drynesses[cell_pos]; + // stain_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, dryness); + // } + // } + // stain_particle_color.rgb *= 1.0 - (0.30 * tile_is_wall); // Darken wall stains + // stain_particle_color.rgb *= stain_particle_color.a; + // } + // //- Ground + // { + // { + // u32 packed = ground_cells[cell_pos]; + // V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); + // if (particle_kind != V_ParticleKind_None) + // { + // u32 particle_idx = packed & ((1 << 24) - 1); + // u32 density = ground_densities[cell_pos]; + // ground_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, 0); + // } + // } + // ground_particle_color.rgb *= ground_particle_color.a; + // } + // //- Air + // { + // { + // u32 packed = air_cells[cell_pos]; + // V_ParticleKind particle_kind = (V_ParticleKind)((packed >> 24) & 0x7F); + // if (particle_kind != V_ParticleKind_None) + // { + // u32 particle_idx = packed & ((1 << 24) - 1); + // u32 density = air_densities[cell_pos]; + // air_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, 0); + // } + // } + // air_particle_color.rgb *= air_particle_color.a; + // } + // } + ////////////////////////////// //- Compose world + + // world_color = BlendPremul(shade_color, world_color); - world_color = BlendPremul(stain_particle_color, world_color); - world_color = BlendPremul(ground_particle_color, world_color); if (!tile_is_wall) { world_color = BlendPremul(tile_color, world_color); // Blend ground tile - world_color = BlendPremul(stain_particle_color, world_color); // Blend ground stain - world_color = BlendPremul(ground_particle_color, world_color); // Blend ground particle + world_color = BlendPremul(stain_color, world_color); // Blend ground stain + world_color = BlendPremul(particle_color, world_color); // Blend ground particle } world_color = BlendPremul(albedo_tex_color, world_color); if (tile_is_wall) { world_color = BlendPremul(tile_color, world_color); // Blend wall tile - world_color = BlendPremul(stain_particle_color, world_color); // Blend wall stain - world_color = BlendPremul(ground_particle_color, world_color); // Blend wall particle + world_color = BlendPremul(stain_color, world_color); // Blend wall stain + world_color = BlendPremul(particle_color, world_color); // Blend wall particle } - world_color = BlendPremul(air_particle_color, world_color); + + + + // // world_color = BlendPremul(shade_color, world_color); + // world_color = BlendPremul(stain_particle_color, world_color); + // world_color = BlendPremul(ground_particle_color, world_color); + // if (!tile_is_wall) + // { + // world_color = BlendPremul(tile_color, world_color); // Blend ground tile + // world_color = BlendPremul(stain_particle_color, world_color); // Blend ground stain + // world_color = BlendPremul(ground_particle_color, world_color); // Blend ground particle + // } + // world_color = BlendPremul(albedo_tex_color, world_color); + // if (tile_is_wall) + // { + // world_color = BlendPremul(tile_color, world_color); // Blend wall tile + // world_color = BlendPremul(stain_particle_color, world_color); // Blend wall stain + // world_color = BlendPremul(ground_particle_color, world_color); // Blend wall particle + // } + // world_color = BlendPremul(air_particle_color, world_color); } ////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_gpu.gh b/src/pp/pp_vis/pp_vis_gpu.gh index feb4f08e..a47a2335 100644 --- a/src/pp/pp_vis/pp_vis_gpu.gh +++ b/src/pp/pp_vis/pp_vis_gpu.gh @@ -45,7 +45,7 @@ Struct(V_DVertPSOutput) //~ Helpers f32 V_RandFromPos(Vec3 pos); -Vec4 V_ColorFromParticle(V_ParticleKind particle_kind, u32 particle_idx, u32 density, f32 dryness); +Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density); Vec3 V_ToneMap(Vec3 v); //////////////////////////////////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_shared.cg b/src/pp/pp_vis/pp_vis_shared.cg index fd96b32c..b7fd4b9f 100644 --- a/src/pp/pp_vis/pp_vis_shared.cg +++ b/src/pp/pp_vis/pp_vis_shared.cg @@ -11,42 +11,49 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind) V_ParticleDesc result; { PERSIST Readonly V_ParticleFlag flags[V_ParticleKind_COUNT] = { - #define X(name, flags, stain_rate, pen_rate, r, g, b, a) flags, + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) flags, V_ParticlesXList(X) #undef X }; - PERSIST Readonly f32 stain_rates[V_ParticleKind_COUNT] = { - #define X(name, flags, stain_rate, pen_rate, r, g, b, a) stain_rate, + PERSIST Readonly V_ParticleLayer layers[V_ParticleKind_COUNT] = { + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) layer, + V_ParticlesXList(X) + #undef X + }; + PERSIST Readonly f32 commit_rates[V_ParticleKind_COUNT] = { + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) commit_rate, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 pen_rates[V_ParticleKind_COUNT] = { - #define X(name, flags, stain_rate, pen_rate, r, g, b, a) pen_rate, + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) pen_rate, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 r[V_ParticleKind_COUNT] = { - #define X(name, flags, stain_rate, pen_rate, r, g, b, a) r, + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) r, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 g[V_ParticleKind_COUNT] = { - #define X(name, flags, stain_rate, pen_rate, r, g, b, a) g, + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) g, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 b[V_ParticleKind_COUNT] = { - #define X(name, flags, stain_rate, pen_rate, r, g, b, a) b, + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) b, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 a[V_ParticleKind_COUNT] = { - #define X(name, flags, stain_rate, pen_rate, r, g, b, a) a, + #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) a, V_ParticlesXList(X) #undef X }; + result.kind = kind; result.flags = flags[kind]; - result.stain_rate = stain_rates[kind]; + result.layer = layers[kind]; + result.commit_rate = commit_rates[kind]; result.pen_rate = pen_rates[kind]; result.color = LinearFromSrgb(VEC4(r[kind], g[kind], b[kind], a[kind])); } diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 873cf43a..8ee8e6ce 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -18,6 +18,176 @@ G_DeclConstant(G_Texture3DRef, V_GpuConst_NoiseTex, 2); G_DeclConstant(G_Texture2DRef, V_GpuConst_BloomRead, 3); G_DeclConstant(G_RWTexture2DRef, V_GpuConst_BloomWrite, 4); +//////////////////////////////////////////////////////////// +//~ Occluder types + +Enum(V_OccluderKind) +{ + V_OccluderKind_None, + V_OccluderKind_Guy, + V_OccluderKind_Wall, +}; + +//////////////////////////////////////////////////////////// +//~ Particle types + +#define V_ParticleSimBasis 0xb49f2d9e406873b9ull +#define V_ParticleColorBasis 0x569aa8341ecc0ea3ull +#define V_ParticleCellBasis 0xf60c0cff344b0c5dull +#define V_ParticleStainBasis 0x3c64e8226d98d376ull + +Enum(V_ParticleFlag) +{ + V_ParticleFlag_None = 0, + V_ParticleFlag_NoPruneWhenStill = (1 << 0), + V_ParticleFlag_StainWhenPruned = (1 << 1), + V_ParticleFlag_NoReflect = (1 << 2), + V_ParticleFlag_StainTrail = (1 << 3), +}; + +Enum(V_ParticleLayer) +{ + V_ParticleLayer_Ground, + V_ParticleLayer_Mid, + V_ParticleLayer_Air, + + V_ParticleLayer_COUNT +}; + +// NOTE: Higher particle enum values take priority over lower ones +#define V_ParticlesXList(X) \ + X( \ + /* Name */ None, \ + /* Flags */ V_ParticleFlag_None, \ + /* Layer */ V_ParticleLayer_Ground, \ + /* Commit rate, pen chance */ 30, 0, \ + /* Base color */ 0, 0, 0, 0 \ + ) \ + \ + /* Ground particles */ \ + X( \ + /* Name */ BloodTrail, \ + /* Flags */ V_ParticleFlag_NoReflect | V_ParticleFlag_StainTrail, \ + /* Layer */ V_ParticleLayer_Ground, \ + /* Commit rate, pen chance */ 500, 0.25, \ + /* Base color */ 0.5, 0.1, 0.1, 0.1 \ + ) \ + X( \ + /* Name */ BloodDebris, \ + /* Flags */ V_ParticleFlag_StainWhenPruned, \ + /* Layer */ V_ParticleLayer_Mid, \ + /* Commit rate, pen chance */ 30, 0, \ + /* Base color */ 0.5, 0.1, 0.1, 0.8 \ + ) \ + X( \ + /* Name */ Debris, \ + /* Flags */ V_ParticleFlag_StainWhenPruned, \ + /* Layer */ V_ParticleLayer_Mid, \ + /* Commit rate, pen chance */ 10000, 0, \ + /* Base color */ 2, 0.5, 0, 1 \ + ) \ + \ + /* Air particles */ \ + X( \ + /* Name */ Smoke, \ + /* Flags */ V_ParticleFlag_None, \ + /* Layer */ V_ParticleLayer_Air, \ + /* Commit rate, pen chance */ 30, 0, \ + /* Base color */ 0.15, 0.15, 0.15, 0.5 \ + ) \ + X( \ + /* Name */ BulletTrail, \ + /* Flags */ V_ParticleFlag_None, \ + /* Layer */ V_ParticleLayer_Air, \ + /* Commit rate, pen chance */ 30, 0, \ + /* Base color */ 1, 0, 1, 1 \ + ) \ + \ + /* Test particles */ \ + X( \ + /* Name */ Test, \ + /* Flags */ V_ParticleFlag_None, \ + /* Layer */ V_ParticleLayer_Mid, \ + /* Commit rate, pen chance */ 30, 0, \ + /* Base color */ 1, 1, 0, 1 \ + ) \ +/* ----------------------------------------------------------------------------------------------------------------------------------- */ + +Enum(V_ParticleKind) +{ + #define X(name, ...) V_ParticleKind_##name, + V_ParticlesXList(X) + #undef X + V_ParticleKind_COUNT, +}; + +Struct(V_Emitter) +{ + V_ParticleKind kind; + + u32 first_particle_seq; + u32 count; + + Rng2 pos; + Rng speed; + Rng angle; +}; + +// TODO: Pack this efficiently +Struct(V_Particle) +{ + i32 kind; // If >= 0, then map to V_ParticleKind. Otherwize initialize particle using emitter at index [abs(kind) - 1] + f32 life; + f32 commit_accum; + u32 cells_count; + Vec2 pos; + Vec2 velocity; +}; + +Struct(V_ParticleDesc) +{ + V_ParticleKind kind; + V_ParticleFlag flags; + V_ParticleLayer layer; + f32 commit_rate; + f32 pen_rate; + Vec4 color; +}; + +#if IsCpu + Struct(V_EmitterNode) + { + V_EmitterNode *next; + V_Emitter emitter; + }; +#endif + +//////////////////////////////////////////////////////////// +//~ Quad types + +Enum(V_QuadFlag) +{ + V_QuadFlag_None = 0, +}; + +Struct(V_Quad) +{ + V_QuadFlag flags; + V_OccluderKind occluder; + Affine quad_uv_to_world_af; + G_Texture2DRef tex; + Rng2 tex_slice_uv; +}; + +//////////////////////////////////////////////////////////// +//~ Debug vert types + +Struct(V_DVert) +{ + Vec2 pos; + Vec4 color_lin; +}; + //////////////////////////////////////////////////////////// //~ State types @@ -161,172 +331,17 @@ Struct(V_SharedFrame) G_StructuredBufferRef emitters; G_RWStructuredBufferRef particles; - G_RWTexture2DRef stain_cells; - G_RWTexture2DRef ground_cells; - G_RWTexture2DRef air_cells; - G_RWTexture2DRef stain_densities; - G_RWTexture2DRef ground_densities; - G_RWTexture2DRef air_densities; + G_RWTexture2DRef stains; G_RWTexture2DRef drynesses; G_RWTexture2DRef occluders; + G_RWTexture2DRef particle_cells[V_ParticleLayer_COUNT]; + G_RWTexture2DRef particle_densities[V_ParticleLayer_COUNT]; + G_StructuredBufferRef dverts; G_StructuredBufferRef quads; }; -//////////////////////////////////////////////////////////// -//~ Occluder types - -Enum(V_OccluderKind) -{ - V_OccluderKind_None, - V_OccluderKind_Guy, - V_OccluderKind_Wall, -}; - -//////////////////////////////////////////////////////////// -//~ Particle types - -#define V_ParticleSimBasis 0xb49f2d9e406873b9ull -#define V_ParticleColorBasis 0x569aa8341ecc0ea3ull -#define V_ParticleCellBasis 0xf60c0cff344b0c5dull -#define V_ParticleStainBasis 0x3c64e8226d98d376ull - -Enum(V_ParticleFlag) -{ - V_ParticleFlag_None = 0, - V_ParticleFlag_Ground = (1 << 0), - V_ParticleFlag_Air = (1 << 1), - V_ParticleFlag_PruneWhenStill = (1 << 2), - V_ParticleFlag_StainWhenPruned = (1 << 3), - V_ParticleFlag_NoReflect = (1 << 4), -}; - -// NOTE: Higher particle enum values take priority over lower ones -#define V_ParticlesXList(X) \ - X( \ - /* Name */ None, \ - /* Flags */ V_ParticleFlag_None, \ - /* Stain rate, pen chance */ 0, 0, \ - /* Base color */ 0, 0, 0, 0 \ - ) \ - \ - /* Ground particles */ \ - X( \ - /* Name */ BloodTrail, \ - /* Flags */ V_ParticleFlag_NoReflect, \ - /* Stain rate, pen chance */ 500, 0.25, \ - /* Base color */ 0.5, 0.1, 0.1, 0.1 \ - ) \ - X( \ - /* Name */ BloodDebris, \ - /* Flags */ V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill | V_ParticleFlag_StainWhenPruned, \ - /* Stain rate, pen chance */ 1, 0, \ - /* Base color */ 0.5, 0.1, 0.1, 0.8 \ - ) \ - X( \ - /* Name */ Debris, \ - /* Flags */ V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill | V_ParticleFlag_StainWhenPruned, \ - /* Stain rate, pen chance */ 0, 0, \ - /* Base color */ 2, 0.5, 0, 1 \ - ) \ - \ - /* Air particles */ \ - X( \ - /* Name */ Smoke, \ - /* Flags */ V_ParticleFlag_Air, \ - /* Stain rate, pen chance */ 0, 0, \ - /* Base color */ 0.15, 0.15, 0.15, 0.5 \ - ) \ - X( \ - /* Name */ BulletTrail, \ - /* Flags */ V_ParticleFlag_Air, \ - /* Stain rate, pen chance */ 0, 0, \ - /* Base color */ 1, 0, 1, 1 \ - ) \ - \ - /* Test particles */ \ - X( \ - /* Name */ Test, \ - /* Flags */ V_ParticleFlag_PruneWhenStill, \ - /* Stain rate, pen chance */ 0, 0, \ - /* Base color */ 1, 1, 0, 1 \ - ) \ -/* ----------------------------------------------------------------------------------------------------------------------------------- */ - -Enum(V_ParticleKind) -{ - #define X(name, ...) V_ParticleKind_##name, - V_ParticlesXList(X) - #undef X - V_ParticleKind_COUNT, -}; - -Struct(V_Emitter) -{ - V_ParticleKind kind; - - u32 first_particle_seq; - u32 count; - - Rng2 pos; - Rng speed; - Rng angle; -}; - -// TODO: Pack this efficiently -Struct(V_Particle) -{ - i32 kind; // If >= 0, then map to V_ParticleKind. Otherwize initialize particle using emitter at index [abs(kind) - 1] - f32 life; - f32 stain_accum; - u32 cells_count; - Vec2 pos; - Vec2 velocity; -}; - -Struct(V_ParticleDesc) -{ - V_ParticleFlag flags; - f32 stain_rate; - f32 pen_rate; - Vec4 color; -}; - -#if IsCpu - Struct(V_EmitterNode) - { - V_EmitterNode *next; - V_Emitter emitter; - }; -#endif - -//////////////////////////////////////////////////////////// -//~ Quad types - -Enum(V_QuadFlag) -{ - V_QuadFlag_None = 0, -}; - -Struct(V_Quad) -{ - V_QuadFlag flags; - V_OccluderKind occluder; - Affine quad_uv_to_world_af; - G_Texture2DRef tex; - Rng2 tex_slice_uv; -}; - -//////////////////////////////////////////////////////////// -//~ Debug vert types - -Struct(V_DVert) -{ - Vec2 pos; - Vec4 color_lin; -}; - //////////////////////////////////////////////////////////// //~ Helpers