diff --git a/assets/voxygen/shaders/particle-frag.glsl b/assets/voxygen/shaders/particle-frag.glsl index 12a4ad2c3b..e0300606a6 100644 --- a/assets/voxygen/shaders/particle-frag.glsl +++ b/assets/voxygen/shaders/particle-frag.glsl @@ -71,6 +71,9 @@ void main() { max_light += lights_at(f_pos, f_norm, view_dir, k_a, k_d, k_s, alpha, emitted_light, reflected_light); + // TODO: Not this + emitted_light += max(f_col.rgb - 1.0, vec3(0)); + surf_color = illuminate(max_light, view_dir, surf_color * emitted_light, surf_color * reflected_light); #if (CLOUD_MODE == CLOUD_MODE_REGULAR) diff --git a/assets/voxygen/shaders/particle-vert.glsl b/assets/voxygen/shaders/particle-vert.glsl index d2dcb4dde7..08b54e54a8 100644 --- a/assets/voxygen/shaders/particle-vert.glsl +++ b/assets/voxygen/shaders/particle-vert.glsl @@ -45,6 +45,7 @@ const int FIREWORK_PURPLE = 6; const int FIREWORK_RED = 7; const int FIREWORK_YELLOW = 8; const int LEAF = 9; +const int FIREFLY = 10; // meters per second squared (acceleration) const float earth_gravity = 9.807; @@ -214,6 +215,18 @@ void main() { vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1), spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) ); + } else if (inst_mode == FIREFLY) { + float raise = pow(sin(3.1416 * lifetime / inst_lifespan), 0.2); + attr = Attr( + vec3(0, 0, raise * 5.0) + vec3( + sin(lifetime * 1.0 + rand0) + sin(lifetime * 7.0 + rand3) * 0.3, + sin(lifetime * 3.0 + rand1) + sin(lifetime * 8.0 + rand4) * 0.3, + sin(lifetime * 2.0 + rand2) + sin(lifetime * 9.0 + rand5) * 0.3 + ), + raise, + vec4(vec3(5, 5, 1.1), 1), + spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 5) + ); } else { attr = Attr( linear_motion( diff --git a/assets/voxygen/voxel/sprite/reed/reed-0.vox b/assets/voxygen/voxel/sprite/reed/reed-0.vox new file mode 100644 index 0000000000..71508195f0 Binary files /dev/null and b/assets/voxygen/voxel/sprite/reed/reed-0.vox differ diff --git a/assets/voxygen/voxel/sprite_manifest.ron b/assets/voxygen/voxel/sprite_manifest.ron index 5f74236719..55574a6b30 100644 --- a/assets/voxygen/voxel/sprite_manifest.ron +++ b/assets/voxygen/voxel/sprite_manifest.ron @@ -1947,4 +1947,16 @@ GrassSnow: Some(( ], wind_sway: 0.2, )), + +// Reed +Reed: Some(( + variations: [ + ( + model: "voxygen.voxel.sprite.reed.reed-0", + offset: (-6.5, -6.5, 0.0), + lod_axes: (0.0, 0.0, 0.5), + ), + ], + wind_sway: 0.65, +)), ) diff --git a/common/src/lib.rs b/common/src/lib.rs index 89abe44963..428383d4dc 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -42,6 +42,7 @@ pub mod store; pub mod sync; pub mod sys; pub mod terrain; +pub mod time; pub mod typed; pub mod util; pub mod vol; diff --git a/common/src/state.rs b/common/src/state.rs index 74919be12e..8598c4383e 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -5,6 +5,7 @@ use crate::{ sync::WorldSyncExt, sys, terrain::{Block, TerrainChunk, TerrainGrid}, + time::DayPeriod, vol::WriteVol, }; use hashbrown::{HashMap, HashSet}; @@ -230,6 +231,22 @@ impl State { /// localised timings. pub fn get_time_of_day(&self) -> f64 { self.ecs.read_resource::().0 } + /// Get the current in-game day period (period of the day/night cycle) + pub fn get_day_period(&self) -> DayPeriod { + let tod = self.get_time_of_day().rem_euclid(60.0 * 60.0 * 24.0); + if tod < 60.0 * 60.0 * 4.0 { + DayPeriod::Night + } else if tod < 60.0 * 60.0 * 10.0 { + DayPeriod::Morning + } else if tod < 60.0 * 60.0 * 16.0 { + DayPeriod::Noon + } else if tod < 60.0 * 60.0 * 20.0 { + DayPeriod::Evening + } else { + DayPeriod::Night + } + } + /// Get the current in-game time. /// /// Note that this does not correspond to the time of day. diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 790aa3ab81..6fe11fd434 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -93,6 +93,7 @@ make_case_elim!( DropGate = 0x50, DropGateBottom = 0x51, GrassSnow = 0x52, + Reed = 0x53, } ); @@ -200,6 +201,7 @@ impl BlockKind { BlockKind::DropGate => false, BlockKind::DropGateBottom => false, BlockKind::GrassSnow => true, + BlockKind::Reed => true, _ => false, } } @@ -296,6 +298,7 @@ impl BlockKind { BlockKind::DropGate => false, BlockKind::DropGateBottom => false, BlockKind::GrassSnow => false, + BlockKind::Reed => false, _ => true, } } @@ -373,6 +376,7 @@ impl BlockKind { BlockKind::DropGate => true, BlockKind::DropGateBottom => false, BlockKind::GrassSnow => false, + BlockKind::Reed => false, _ => true, } } diff --git a/common/src/time.rs b/common/src/time.rs new file mode 100644 index 0000000000..d47b98be05 --- /dev/null +++ b/common/src/time.rs @@ -0,0 +1,17 @@ +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum DayPeriod { + Night, + Morning, + Noon, + Evening, +} + +impl DayPeriod { + pub fn is_dark(&self) -> bool { + *self == DayPeriod::Night + } + + pub fn is_light(&self) -> bool { + !self.is_dark() + } +} diff --git a/voxygen/src/render/pipelines/particle.rs b/voxygen/src/render/pipelines/particle.rs index dd3b383548..63c99c339c 100644 --- a/voxygen/src/render/pipelines/particle.rs +++ b/voxygen/src/render/pipelines/particle.rs @@ -103,6 +103,7 @@ pub enum ParticleMode { FireworkRed = 7, FireworkYellow = 8, Leaf = 9, + Firefly = 10, } impl ParticleMode { diff --git a/voxygen/src/scene/particle.rs b/voxygen/src/scene/particle.rs index bec9b00fb2..1756d1ebed 100644 --- a/voxygen/src/scene/particle.rs +++ b/voxygen/src/scene/particle.rs @@ -14,6 +14,7 @@ use common::{ spiral::Spiral2d, state::DeltaTime, terrain::TerrainChunk, + time::DayPeriod, vol::{RectRasterableVol, SizedVol}, }; use dot_vox::DotVoxData; @@ -283,7 +284,7 @@ impl ParticleMgr { }); type BoiFn<'a> = fn(&'a BlocksOfInterest) -> &'a [Vec3]; - // blocks, chunk range, emission density, lifetime, particle mode + // blocks, chunk range, emission density, lifetime, particle mode, condition // // - blocks: the function to select the blocks of interest that we should emit // from @@ -293,14 +294,48 @@ impl ParticleMgr { // particles // - lifetime: the number of seconds that each particle should live for // - particle mode: the visual mode of the generated particle - let particles: &[(BoiFn, usize, f32, f32, ParticleMode)] = &[ - (|boi| &boi.leaves, 4, 0.001, 30.0, ParticleMode::Leaf), - (|boi| &boi.embers, 2, 20.0, 0.25, ParticleMode::CampfireFire), - (|boi| &boi.embers, 8, 3.0, 40.0, ParticleMode::CampfireSmoke), + // - Condition required for emissions + let particles: &[(BoiFn, usize, f32, f32, ParticleMode, fn(&SceneData) -> bool)] = &[ + ( + |boi| &boi.leaves, + 4, + 0.001, + 30.0, + ParticleMode::Leaf, + |_| true, + ), + ( + |boi| &boi.embers, + 2, + 20.0, + 0.25, + ParticleMode::CampfireFire, + |_| true, + ), + ( + |boi| &boi.embers, + 8, + 3.0, + 40.0, + ParticleMode::CampfireSmoke, + |_| true, + ), + ( + |boi| &boi.grass, + 5, + 0.001, + 40.0, + ParticleMode::Firefly, + |sd| sd.state.get_day_period().is_dark(), + ), ]; let mut rng = thread_rng(); - for (get_blocks, range, rate, dur, mode) in particles.iter() { + for (get_blocks, range, rate, dur, mode, cond) in particles.iter() { + if !cond(scene_data) { + continue; + } + for offset in Spiral2d::new().take((*range * 2 + 1).pow(2)) { let chunk_pos = player_chunk + offset; diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 04dccd9558..5587f4dfd0 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -91,6 +91,7 @@ struct SpriteModelConfig { lod_axes: (f32, f32, f32), } +<<<<<<< HEAD #[derive(Deserialize)] /// Configuration data for a group of sprites (currently associated with a /// particular BlockKind). diff --git a/voxygen/src/scene/terrain/watcher.rs b/voxygen/src/scene/terrain/watcher.rs index 439462f12a..57d672fd8a 100644 --- a/voxygen/src/scene/terrain/watcher.rs +++ b/voxygen/src/scene/terrain/watcher.rs @@ -7,12 +7,14 @@ use vek::*; pub struct BlocksOfInterest { pub leaves: Vec>, + pub grass: Vec>, pub embers: Vec>, } impl BlocksOfInterest { pub fn from_chunk(chunk: &TerrainChunk) -> Self { let mut leaves = Vec::new(); + let mut grass = Vec::new(); let mut embers = Vec::new(); chunk @@ -27,11 +29,17 @@ impl BlocksOfInterest { .for_each(|(pos, block)| { if block.kind() == BlockKind::Leaves && thread_rng().gen_range(0, 16) == 0 { leaves.push(pos); + } else if block.kind() == BlockKind::Grass && thread_rng().gen_range(0, 16) == 0 { + grass.push(pos); } else if block.kind() == BlockKind::Ember { embers.push(pos); } }); - Self { leaves, embers } + Self { + leaves, + grass, + embers, + } } } diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index 3fdbda950b..665b98fe86 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -774,6 +774,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { .div(100.0) .into_array(), ) as f32) + //.mul(water_dist.map(|wd| (wd / 2.0).clamped(0.0, 1.0).powf(0.5)).unwrap_or(1.0)) .mul(rockiness) .sub(0.4) .max(0.0) @@ -996,6 +997,11 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { (alt, ground, sub_surface_color) }; + // Make river banks not have grass + let ground = water_dist + .map(|wd| Lerp::lerp(sub_surface_color, ground, (wd / 3.0).clamped(0.0, 1.0))) + .unwrap_or(ground); + let near_ocean = max_river.and_then(|(_, _, river_data, _)| { if (river_data.is_lake() || river_data.river_kind == Some(RiverKind::Ocean)) && ((alt <= water_level.max(CONFIG.sea_level + 5.0) && !is_cliffs) || !near_cliffs) diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs index 6ca20116b2..1876bfe4ed 100644 --- a/world/src/layer/mod.rs +++ b/world/src/layer/mod.rs @@ -41,10 +41,14 @@ pub fn apply_scatter_to<'a>( use BlockKind::*; #[allow(clippy::type_complexity)] // TODO: Add back all sprites we had before - let scatter: &[(_, bool, fn(&SimChunk) -> (f32, Option<(f32, f32)>))] = &[ + let scatter: &[( + _, + bool, + fn(&SimChunk, &ColumnSample) -> (f32, Option<(f32, f32)>), + )] = &[ // (density, Option<(wavelen, threshold)>) // Flowers - (BlueFlower, false, |c| { + (BlueFlower, false, |c, col| { ( close(c.temp, 0.1, 0.2).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -52,7 +56,7 @@ pub fn apply_scatter_to<'a>( Some((48.0, 0.2)), ) }), - (PinkFlower, false, |c| { + (PinkFlower, false, |c, col| { ( close(c.temp, 0.2, 0.2).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -60,7 +64,7 @@ pub fn apply_scatter_to<'a>( Some((48.0, 0.2)), ) }), - (PurpleFlower, false, |c| { + (PurpleFlower, false, |c, col| { ( close(c.temp, 0.3, 0.2).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -68,7 +72,7 @@ pub fn apply_scatter_to<'a>( Some((48.0, 0.2)), ) }), - (RedFlower, false, |c| { + (RedFlower, false, |c, col| { ( close(c.temp, 0.5, 0.2).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -76,7 +80,7 @@ pub fn apply_scatter_to<'a>( Some((48.0, 0.2)), ) }), - (WhiteFlower, false, |c| { + (WhiteFlower, false, |c, col| { ( close(c.temp, 0.0, 0.3).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -84,7 +88,7 @@ pub fn apply_scatter_to<'a>( Some((48.0, 0.2)), ) }), - (YellowFlower, false, |c| { + (YellowFlower, false, |c, col| { ( close(c.temp, 0.3, 0.2).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -93,7 +97,7 @@ pub fn apply_scatter_to<'a>( ) }), // Herbs and Spices - (LingonBerry, false, |c| { + (LingonBerry, false, |c, col| { ( close(c.temp, 0.3, 0.4).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -101,7 +105,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - (LeafyPlant, false, |c| { + (LeafyPlant, false, |c, col| { ( close(c.temp, 0.3, 0.4).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -109,7 +113,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - (Fern, false, |c| { + (Fern, false, |c, col| { ( close(c.temp, 0.3, 0.4).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT @@ -117,7 +121,7 @@ pub fn apply_scatter_to<'a>( Some((48.0, 0.4)), ) }), - (Blueberry, false, |c| { + (Blueberry, false, |c, col| { ( close(c.temp, CONFIG.temperate_temp, 0.5).min(close( c.humidity, @@ -130,40 +134,40 @@ pub fn apply_scatter_to<'a>( }), // Collectable Objects // Only spawn twigs in temperate forests - (Twigs, false, |c| { + (Twigs, false, |c, col| { ((c.tree_density - 0.5).max(0.0) * 1.0e-3, None) }), - (Stones, false, |c| { + (Stones, false, |c, col| { ((c.rockiness - 0.5).max(0.0) * 1.0e-3, None) }), // Don't spawn Mushrooms in snowy regions - (Mushroom, false, |c| { + (Mushroom, false, |c, col| { ( close(c.temp, 0.3, 0.4).min(close(c.humidity, CONFIG.forest_hum, 0.35)) * MUSH_FACT, None, ) }), // Grass - (ShortGrass, false, |c| { + (ShortGrass, false, |c, col| { ( close(c.temp, 0.3, 0.4).min(close(c.humidity, 0.6, 0.35)) * 0.05, Some((48.0, 0.4)), ) }), - (MediumGrass, false, |c| { + (MediumGrass, false, |c, col| { ( close(c.temp, 0.0, 0.6).min(close(c.humidity, 0.6, 0.35)) * 0.05, Some((48.0, 0.2)), ) }), - (LongGrass, false, |c| { + (LongGrass, false, |c, col| { ( close(c.temp, 0.4, 0.4).min(close(c.humidity, 0.8, 0.2)) * 0.08, Some((48.0, 0.1)), ) }), // Jungle Sprites - (LongGrass, false, |c| { + (LongGrass, false, |c, col| { ( close(c.temp, CONFIG.tropical_temp, 0.4).min(close( c.humidity, @@ -173,7 +177,7 @@ pub fn apply_scatter_to<'a>( Some((60.0, 5.0)), ) }), - /*(WheatGreen, false, |c| { + /*(WheatGreen, false, |c, col| { ( close(c.temp, 0.4, 0.2).min(close(c.humidity, CONFIG.forest_hum, 0.1)) * MUSH_FACT @@ -181,7 +185,7 @@ pub fn apply_scatter_to<'a>( None, ) }),*/ - (GrassSnow, false, |c| { + (GrassSnow, false, |c, col| { ( close(c.temp, CONFIG.snow_temp - 0.2, 0.4).min(close( c.humidity, @@ -192,7 +196,7 @@ pub fn apply_scatter_to<'a>( ) }), // Desert Plants - (DeadBush, false, |c| { + (DeadBush, false, |c, col| { ( close(c.temp, CONFIG.desert_temp + 0.2, 0.3).min(close( c.humidity, @@ -203,7 +207,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - (LargeCactus, false, |c| { + (LargeCactus, false, |c, col| { ( close(c.temp, CONFIG.desert_temp + 0.2, 0.3).min(close( c.humidity, @@ -214,7 +218,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - /*(BarrelCactus, false, |c| { + /*(BarrelCactus, false, |c, col| { ( close(c.temp, CONFIG.desert_temp + 0.2, 0.3).min(close( c.humidity, @@ -225,7 +229,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - (RoundCactus, false, |c| { + (RoundCactus, false, |c, col| { ( close(c.temp, CONFIG.desert_temp + 0.2, 0.3).min(close( c.humidity, @@ -236,7 +240,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - (ShortCactus, false, |c| { + (ShortCactus, false, |c, col| { ( close(c.temp, CONFIG.desert_temp + 0.2, 0.3).min(close( c.humidity, @@ -247,7 +251,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - (MedFlatCactus, false, |c| { + (MedFlatCactus, false, |c, col| { ( close(c.temp, CONFIG.desert_temp + 0.2, 0.3).min(close( c.humidity, @@ -258,7 +262,7 @@ pub fn apply_scatter_to<'a>( None, ) }), - (ShortFlatCactus, false, |c| { + (ShortFlatCactus, false, |c, col| { ( close(c.temp, CONFIG.desert_temp + 0.2, 0.3).min(close( c.humidity, @@ -269,6 +273,16 @@ pub fn apply_scatter_to<'a>( None, ) }),*/ + (Reed, false, |c, col| { + ( + close(c.humidity, CONFIG.jungle_hum, 0.7) + * col + .water_dist + .map(|wd| Lerp::lerp(0.2, 0.0, (wd / 8.0).clamped(0.0, 1.0))) + .unwrap_or(0.0), + None, + ) + }), ]; for y in 0..vol.size_xy().y as i32 { @@ -290,7 +304,7 @@ pub fn apply_scatter_to<'a>( .iter() .enumerate() .find_map(|(i, (bk, is_underwater, f))| { - let (density, patch) = f(chunk); + let (density, patch) = f(chunk, col_sample); let is_patch = patch .map(|(wavelen, threshold)| { index.noise.scatter_nz.get( diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index cc9102ff69..58ec0de7ea 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -1657,7 +1657,7 @@ impl WorldSim { let new_chunk = this.get(downhill_pos)?; const SLIDE_THRESHOLD: f32 = 5.0; - if new_chunk.is_underwater() || new_chunk.alt + SLIDE_THRESHOLD < chunk.alt { + if new_chunk.river.near_water() || new_chunk.alt + SLIDE_THRESHOLD < chunk.alt { break; } else { chunk = new_chunk; @@ -2182,8 +2182,9 @@ impl SimChunk { downhill, temp, humidity, - rockiness: if true && !river.is_river() { + rockiness: if true { (gen_ctx.rock_nz.get((wposf.div(1024.0)).into_array()) as f32) + //.add(if river.near_river() { 20.0 } else { 0.0 }) .sub(0.1) .mul(1.3) .max(0.0)