diff --git a/assets/world/structures/human/blacksmith.vox b/assets/world/structure/human/blacksmith.vox similarity index 100% rename from assets/world/structures/human/blacksmith.vox rename to assets/world/structure/human/blacksmith.vox diff --git a/assets/world/structures/human/house_1.vox b/assets/world/structure/human/house_1.vox similarity index 100% rename from assets/world/structures/human/house_1.vox rename to assets/world/structure/human/house_1.vox diff --git a/assets/world/structures/human/house_2.vox b/assets/world/structure/human/house_2.vox similarity index 100% rename from assets/world/structures/human/house_2.vox rename to assets/world/structure/human/house_2.vox diff --git a/assets/world/structures/human/mage_tower.vox b/assets/world/structure/human/mage_tower.vox similarity index 100% rename from assets/world/structures/human/mage_tower.vox rename to assets/world/structure/human/mage_tower.vox diff --git a/assets/world/structures/human/stables_1.vox b/assets/world/structure/human/stables_1.vox similarity index 100% rename from assets/world/structures/human/stables_1.vox rename to assets/world/structure/human/stables_1.vox diff --git a/assets/world/structures/human/town_hall.vox b/assets/world/structure/human/town_hall.vox similarity index 100% rename from assets/world/structures/human/town_hall.vox rename to assets/world/structure/human/town_hall.vox diff --git a/assets/world/structures/human/town_hall_spire.vox b/assets/world/structure/human/town_hall_spire.vox similarity index 100% rename from assets/world/structures/human/town_hall_spire.vox rename to assets/world/structure/human/town_hall_spire.vox diff --git a/assets/world/structure/natural/Witch_Hut.vox b/assets/world/structure/natural/Witch_Hut.vox new file mode 100644 index 0000000000..f8e1306088 --- /dev/null +++ b/assets/world/structure/natural/Witch_Hut.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97f5726c4087bc79fda164c2d110aeb1e82f5e0c28d0d6e40cbc60cf821c7c53 +size 52573 diff --git a/assets/world/structure/natural/tower_ruin.vox b/assets/world/structure/natural/tower_ruin.vox new file mode 100644 index 0000000000..fa3b4880b4 --- /dev/null +++ b/assets/world/structure/natural/tower_ruin.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6135fec30e0b95d66e2105355f4c459912fd0665090a370ddf558871bdc74713 +size 87382 diff --git a/voxygen/shaders/include/sky.glsl b/voxygen/shaders/include/sky.glsl index 2cddb38394..566127ba40 100644 --- a/voxygen/shaders/include/sky.glsl +++ b/voxygen/shaders/include/sky.glsl @@ -31,7 +31,7 @@ float get_sun_brightness(vec3 sun_dir) { const float PERSISTENT_AMBIANCE = 0.008; vec3 get_sun_diffuse(vec3 norm, float time_of_day) { - const float SUN_AMBIANCE = 0.1; + const float SUN_AMBIANCE = 0.075; vec3 sun_dir = get_sun_dir(time_of_day); diff --git a/world/src/all.rs b/world/src/all.rs index 41f8eee75a..f687672ccb 100644 --- a/world/src/all.rs +++ b/world/src/all.rs @@ -1,6 +1,7 @@ #[derive(Copy, Clone)] pub enum ForestKind { Palm, + Savannah, Oak, Pine, SnowPine, diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 9484dbcfb5..f16aab6655 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -1,4 +1,4 @@ -mod tree; +mod natural; use crate::{ column::{ColumnGen, ColumnSample}, @@ -6,7 +6,7 @@ use crate::{ World, }; use common::{ - terrain::{structure::StructureBlock, Block}, + terrain::{structure::StructureBlock, Block, Structure}, vol::{ReadVol, Vox}, }; use noise::NoiseFn; @@ -86,19 +86,34 @@ impl<'a> BlockGen<'a> { let sample = Self::sample_column(column_gen, column_cache, wpos)?; // Tree samples - let mut tree_samples = [None, None, None, None, None, None, None, None, None]; - for i in 0..tree_samples.len() { - tree_samples[i] = Self::sample_column( + let mut structure_samples = [None, None, None, None, None, None, None, None, None]; + for i in 0..structure_samples.len() { + let st_sample = Self::sample_column( column_gen, column_cache, Vec2::from(sample.close_trees[i].0), ); + structure_samples[i] = st_sample; } - Some(ZCache { - sample, - tree_samples, - }) + let mut structures = [None, None, None, None, None, None, None, None, None]; + for i in 0..structures.len() { + let (st_pos, st_seed) = sample.close_trees[i]; + let st_info = natural::structure_gen( + column_gen, + column_cache, + i, + st_pos, + st_seed, + &structure_samples, + ); + + if let (Some(st_info), Some(st_sample)) = (st_info, structure_samples[i].clone()) { + structures[i] = Some((st_info, st_sample)); + } + } + + Some(ZCache { sample, structures }) } pub fn get_with_z_cache(&mut self, wpos: Vec3, z_cache: Option<&ZCache>) -> Option { @@ -128,9 +143,8 @@ impl<'a> BlockGen<'a> { .. } = &z_cache?.sample; - let tree_samples = &z_cache?.tree_samples; + let structures = &z_cache?.structures; - let wpos2d = Vec2::from(wpos); let wposf = wpos.map(|e| e as f64); let (definitely_underground, height, water_height) = @@ -193,7 +207,7 @@ impl<'a> BlockGen<'a> { // let warm_stone = Block::new(1, Rgb::new(165, 165, 130)); let water = Block::new(1, Rgb::new(100, 150, 255)); - let grass_depth = 2.0; + let grass_depth = 1.5 + 2.0 * chaos; let block = if (wposf.z as f32) < height - grass_depth { let col = Lerp::lerp( sub_surface_color.map(|e| (e * 255.0) as u8), @@ -307,55 +321,32 @@ impl<'a> BlockGen<'a> { let block = if definitely_underground { block.unwrap_or(Block::empty()) } else { - match block { - Some(block) => block, - None => (&close_trees).iter().enumerate().fold( - air, - |block, (tree_idx, (tree_pos, tree_seed))| { - if !block.is_empty() { - block - } else { - match &tree_samples[tree_idx] { - Some(tree_sample) - if wpos2d.distance_squared(*tree_pos) < 28 * 28 - && tree_sample.tree_density - > 0.5 + (*tree_seed as f32 / 1000.0).fract() * 0.2 - && tree_sample.alt > tree_sample.water_level - && tree_sample.spawn_rate > 0.5 => - { - let cliff_height = Self::get_cliff_height( - column_gen, - column_cache, - tree_pos.map(|e| e as f32), - &tree_sample.close_cliffs, - cliff_hill, - ); - let height = tree_sample.alt.max(cliff_height); - let tree_pos3d = - Vec3::new(tree_pos.x, tree_pos.y, height as i32); - let rpos = wpos - tree_pos3d; + block + .or_else(|| { + structures.iter().find_map(|st| { + let (st, st_sample) = st.as_ref()?; - let trees = tree::kinds(tree_sample.forest_kind); // Choose tree kind + let rpos = wpos - st.pos; + let block_pos = Vec3::unit_z() * rpos.z + + Vec3::from(st.units.0) * rpos.x + + Vec3::from(st.units.1) * rpos.y; - block.or(trees[*tree_seed as usize % trees.len()] - .get((rpos * 128) / 128) // Scaling - .map(|b| { - block_from_structure( - *b, - rpos, - *tree_pos, - *tree_seed, - &tree_sample, - ) - }) - .unwrap_or(Block::empty())) - } - _ => block, - } - } - }, - ), - } + st.volume + .get((block_pos * 128) / 128) // Scaling + .map(|b| { + block_from_structure( + *b, + block_pos, + st.pos.into(), + st.seed, + st_sample, + ) + }) + .ok() + .filter(|block| !block.is_empty()) + }) + }) + .unwrap_or(Block::empty()) }; Some(block) @@ -364,7 +355,14 @@ impl<'a> BlockGen<'a> { pub struct ZCache<'a> { sample: ColumnSample<'a>, - tree_samples: [Option>; 9], + structures: [Option<(StructureInfo, ColumnSample<'a>)>; 9], +} + +pub struct StructureInfo { + pos: Vec3, + seed: u32, + units: (Vec2, Vec2), + volume: &'static Structure, } impl<'a> SamplerMut for BlockGen<'a> { diff --git a/world/src/block/tree.rs b/world/src/block/natural.rs similarity index 87% rename from world/src/block/tree.rs rename to world/src/block/natural.rs index 2248e28a07..dc778a0f4c 100644 --- a/world/src/block/tree.rs +++ b/world/src/block/natural.rs @@ -1,16 +1,65 @@ -use crate::all::ForestKind; +use super::{BlockGen, StructureInfo, ZCache}; +use crate::{ + all::ForestKind, + column::{ColumnGen, ColumnSample}, + util::{HashCache, RandomPerm, Sampler}, +}; use common::{assets, terrain::Structure}; use lazy_static::lazy_static; use std::sync::Arc; use vek::*; -pub fn kinds(forest_kind: ForestKind) -> &'static [Arc] { - match forest_kind { +static VOLUME_RAND: RandomPerm = RandomPerm::new(0); +static UNIT_RAND: RandomPerm = RandomPerm::new(1); +static QUIRKY_RAND: RandomPerm = RandomPerm::new(2); + +pub fn structure_gen<'a>( + column_gen: &ColumnGen<'a>, + column_cache: &mut HashCache, Option>>, + idx: usize, + st_pos: Vec2, + st_seed: u32, + structure_samples: &[Option; 9], +) -> Option { + let st_sample = &structure_samples[idx].as_ref()?; + + // Assuming it's a tree... figure out when it SHOULDN'T spawn + if st_sample.tree_density < 0.5 + (st_seed as f32 / 1000.0).fract() * 0.2 + || st_sample.alt < st_sample.water_level + || st_sample.spawn_rate < 0.5 + { + return None; + } + + let cliff_height = BlockGen::get_cliff_height( + column_gen, + column_cache, + st_pos.map(|e| e as f32), + &st_sample.close_cliffs, + st_sample.cliff_hill, + ); + + let wheight = st_sample.alt.max(cliff_height); + let st_pos3d = Vec3::new(st_pos.x, st_pos.y, wheight as i32); + + let volumes: &'static [_] = match st_sample.forest_kind { ForestKind::Palm => &PALMS, + ForestKind::Savannah => &PALMS, + ForestKind::Oak if QUIRKY_RAND.get(st_seed) % 64 == 0 => &QUIRKY, + ForestKind::Oak if QUIRKY_RAND.get(st_seed) % 16 == 0 => &OAK_STUMPS, ForestKind::Oak => &OAKS, ForestKind::Pine => &PINES, ForestKind::SnowPine => &SNOW_PINES, - } + }; + + const UNIT_CHOICES: [(Vec2, Vec2); 1] = [(Vec2 { x: 1, y: 0 }, Vec2 { x: 0, y: 1 })]; + + Some(StructureInfo { + pos: st_pos3d, + seed: st_seed, + units: UNIT_CHOICES[UNIT_RAND.get(st_seed) as usize % UNIT_CHOICES.len()], + volume: &volumes[VOLUME_RAND.get(st_seed) as usize % volumes.len()], + }) } lazy_static! { @@ -43,6 +92,9 @@ lazy_static! { assets::load_map("world/tree/oak_green/9.vox", |s: Structure| s .with_center(Vec3::new(26, 26, 14))) .unwrap(), + ]; + + pub static ref OAK_STUMPS: Vec> = vec![ // oak stumps assets::load_map("world/tree/oak_stump/1.vox", |s: Structure| s .with_center(Vec3::new(15, 18, 10))) @@ -350,4 +402,10 @@ lazy_static! { .unwrap(), ]; */ + + pub static ref QUIRKY: Vec> = vec![ + assets::load_map("world/structure/natural/tower_ruin.vox", |s: Structure| s + .with_center(Vec3::new(11, 14, 7))) + .unwrap(), + ]; } diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index 3e2c818d5c..2f93eb3855 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -61,7 +61,7 @@ impl<'a> Sampler for ColumnGen<'a> { let riverless_alt = sim.get_interpolated(wpos, |chunk| chunk.alt)? + (sim.gen_ctx.small_nz.get((wposf.div(256.0)).into_array()) as f32) .abs() - .mul(chaos.max(0.2)) + .mul(chaos.max(0.15)) .mul(64.0); let cliffs = sim_chunk.cliffs; @@ -127,7 +127,7 @@ impl<'a> Sampler for ColumnGen<'a> { .mul(256.0), ), Rgb::lerp(tropical, sand, temp.sub(CONFIG.desert_temp).mul(32.0)), - temp.sub(CONFIG.tropical_temp).mul(128.0), + temp.sub(CONFIG.tropical_temp).mul(64.0), ); // Work out if we're on a path or near a town diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 61413d1fe5..28fcba56be 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -368,18 +368,18 @@ impl SimChunk { .into_array(), ) as f32; - let chaos = (gen_ctx.chaos_nz.get((wposf.div(4_000.0)).into_array()) as f32) + let chaos = (gen_ctx.chaos_nz.get((wposf.div(6_000.0)).into_array()) as f32) .add(1.0) .mul(0.5) .mul( - (gen_ctx.chaos_nz.get((wposf.div(6_000.0)).into_array()) as f32) + (gen_ctx.chaos_nz.get((wposf.div(4_000.0)).into_array()) as f32) .powf(2.0) .add(0.5) .min(1.0), ) - .mul(temp.mul(4.0).sub(1.0).neg().add(0.25).max(0.05).min(1.0)) - .powf(1.5) - .add(0.1 * hill); + .add(0.1 * hill) + .mul(temp.mul(4.0).sub(1.0).neg().add(1.25).max(0.15).min(1.0)) + .powf(1.5); let chaos = chaos + chaos.mul(16.0).sin().mul(0.02); @@ -397,14 +397,13 @@ impl SimChunk { + alt_base + (0.0 + alt_main - + gen_ctx.small_nz.get((wposf.div(300.0)).into_array()) as f32 - * alt_main.max(0.1) - * chaos - * 1.6) - .add(1.0) - .mul(0.5) - .mul(chaos) - .mul(CONFIG.mountain_scale); + + (gen_ctx.small_nz.get((wposf.div(300.0)).into_array()) as f32) + .mul(alt_main.max(0.1)) + .mul(1.6)) + .add(1.0) + .mul(0.5) + .mul(chaos) + .mul(CONFIG.mountain_scale); let cliff = gen_ctx.cliff_nz.get((wposf.div(2048.0)).into_array()) as f32 + chaos * 0.2; @@ -436,6 +435,8 @@ impl SimChunk { forest_kind: if temp > 0.0 { if temp > CONFIG.desert_temp { ForestKind::Palm + } else if temp > CONFIG.desert_temp { + ForestKind::Savannah } else { ForestKind::Oak } diff --git a/world/src/util/mod.rs b/world/src/util/mod.rs index a9c3cb8ae9..fd538e21ce 100644 --- a/world/src/util/mod.rs +++ b/world/src/util/mod.rs @@ -6,7 +6,7 @@ pub mod structure; // Reexports pub use self::{ hash_cache::HashCache, - random::RandomField, + random::{RandomField, RandomPerm}, sampler::{Sampler, SamplerMut}, structure::StructureGen2d, }; diff --git a/world/src/util/random.rs b/world/src/util/random.rs index 6e30b635bb..ece87a30ce 100644 --- a/world/src/util/random.rs +++ b/world/src/util/random.rs @@ -6,7 +6,7 @@ pub struct RandomField { } impl RandomField { - pub fn new(seed: u32) -> Self { + pub const fn new(seed: u32) -> Self { Self { seed } } } @@ -35,3 +35,28 @@ impl Sampler for RandomField { a } } + +pub struct RandomPerm { + seed: u32, +} + +impl RandomPerm { + pub const fn new(seed: u32) -> Self { + Self { seed } + } +} + +impl Sampler for RandomPerm { + type Index = u32; + type Sample = u32; + + fn get(&self, perm: Self::Index) -> Self::Sample { + let mut a = perm; + a = (a ^ 61) ^ (a >> 16); + a = a + (a << 3); + a = a ^ (a >> 4); + a = a * 0x27d4eb2d; + a = a ^ (a >> 15); + a + } +}