diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index a850ca4294..664a50e223 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -75,6 +75,7 @@ const int TORNADO = 33; const int DEATH = 34; const int ENERGY_BUFFING = 35; const int WEB_STRAND = 36; +const int BLACK_SMOKE = 37; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -195,6 +196,17 @@ void main() { spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5) ); break; + case BLACK_SMOKE: + attr = Attr( + linear_motion( + vec3(0), + vec3(rand2 * 0.02, rand3 * 0.02, 0.9 + rand4 * 0.1) + ), + vec3(linear_scale(0.5)), + vec4(vec3(0, 0, 0), start_end(1.0, 0.0)), + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 0.5) + ); + break; case FIRE: f_reflect = 0.0; // Fire doesn't reflect light, it emits it attr = Attr( diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index c32a3e2503..91eef06251 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -87,6 +87,7 @@ pub enum ParticleMode { Death = 34, EnergyBuffing = 35, WebStrand = 36, + BlackSmoke = 37, } impl ParticleMode { diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index f6c4e8068a..96113ccb46 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -1181,14 +1181,6 @@ impl ParticleMgr { mode: ParticleMode::FireBowl, cond: |_| true, }, - BlockParticles { - blocks: |boi| &boi.smokers, - range: 8, - rate: 3.0, - lifetime: 40.0, - mode: ParticleMode::CampfireSmoke, - cond: |_| true, - }, BlockParticles { blocks: |boi| &boi.fireflies, range: 6, @@ -1255,6 +1247,53 @@ impl ParticleMgr { }); } } + // smoke is more complex as it comes with varying rate and color + { + let range = 8_usize; + let rate = 3.0 / 128.0; + let lifetime = 40.0; + + // mode: ParticleMode::CampfireSmoke, + for offset in Spiral2d::new().take((range * 2 + 1).pow(2)) { + let chunk_pos = player_chunk + offset; + + terrain.get(chunk_pos).map(|chunk_data| { + let blocks = &chunk_data.blocks_of_interest.smokers; + let sum = blocks + .iter() + .fold(0u32, |sum, smoker| sum + smoker.strength as u32); + let avg_particles = dt * sum as f32 * rate; + let block_pos = + Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32)); + + let particle_count = avg_particles.trunc() as usize + + (rng.gen::() < avg_particles.fract()) as usize; + let chosen = + blocks.choose_multiple_weighted(&mut rng, particle_count, |smoker| { + smoker.strength as u32 + }); + if let Ok(chosen) = chosen { + let mut smoke_particles: Vec = chosen + .map(|smoker| { + Particle::new( + Duration::from_secs_f32(lifetime), + time, + if rng.gen::() > smoker.dryness { + ParticleMode::BlackSmoke + } else { + ParticleMode::CampfireSmoke + }, + (block_pos + smoker.position) + .map(|e: i32| e as f32 + rng.gen::()), + ) + }) + .collect(); + + self.particles.append(&mut smoke_particles); + } + }); + } + } } fn maintain_shockwave_particles(&mut self, scene_data: &SceneData) { diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index 16a8060a75..40201660a4 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -12,6 +12,22 @@ pub enum Interaction { Mine, } +pub struct SmokeProperties { + pub position: Vec3, + pub dryness: u8, // 0 = black smoke, 255 = white + pub strength: u8, // 0 = thin, 128 = normal, 255 = very strong +} + +impl SmokeProperties { + fn new(position: Vec3, dryness: u8, strength: u8) -> Self { + Self { + position, + dryness, + strength, + } + } +} + #[derive(Default)] pub struct BlocksOfInterest { pub leaves: Vec>, @@ -20,7 +36,7 @@ pub struct BlocksOfInterest { pub slow_river: Vec>, pub fast_river: Vec>, pub fires: Vec>, - pub smokers: Vec>, + pub smokers: Vec, pub beehives: Vec>, pub reeds: Vec>, pub fireflies: Vec>, @@ -89,7 +105,7 @@ impl BlocksOfInterest { _ => match block.get_sprite() { Some(SpriteKind::Ember) => { fires.push(pos); - smokers.push(pos); + smokers.push(SmokeProperties::new(pos, 128, 128)); }, // Offset positions to account for block height. // TODO: Is this a good idea? @@ -117,7 +133,7 @@ impl BlocksOfInterest { interactables.push((pos, Interaction::Craft(CraftingTab::All))) }, Some(SpriteKind::SmokeDummy) => { - smokers.push(pos); + smokers.push(SmokeProperties::new(pos, 255, 128)); }, Some(SpriteKind::Forge) => interactables .push((pos, Interaction::Craft(CraftingTab::ProcessedMaterial))),