diff --git a/assets/voxygen/shaders/include/sky.glsl b/assets/voxygen/shaders/include/sky.glsl index 7ac0dbc6c9..806d1bf140 100644 --- a/assets/voxygen/shaders/include/sky.glsl +++ b/assets/voxygen/shaders/include/sky.glsl @@ -4,8 +4,8 @@ const float PI = 3.141592; -const vec3 SKY_DAY_TOP = vec3(0.1, 0.2, 0.9); -const vec3 SKY_DAY_MID = vec3(0.02, 0.08, 0.8); +const vec3 SKY_DAY_TOP = vec3(0.1, 0.5, 0.9); +const vec3 SKY_DAY_MID = vec3(0.02, 0.28, 0.8); const vec3 SKY_DAY_BOT = vec3(0.1, 0.2, 0.3); const vec3 DAY_LIGHT = vec3(1.2, 1.0, 1.0); const vec3 SUN_HALO_DAY = vec3(0.35, 0.35, 0.0); diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index a4c4d25ce6..74a2f94852 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -10,7 +10,7 @@ use super::SceneData; use common::{ assets, figure::Segment, - spiral::Spiral2D, + spiral::Spiral2d, terrain::{Block, BlockKind, TerrainChunk}, vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, Vox}, volumes::vol_grid_2d::{VolGrid2d, VolGrid2dError}, diff --git a/world/examples/settlement_viewer.rs b/world/examples/settlement_viewer.rs index 903dba861f..2d963d07a9 100644 --- a/world/examples/settlement_viewer.rs +++ b/world/examples/settlement_viewer.rs @@ -9,7 +9,7 @@ fn main() { let mut win = minifb::Window::new("Settlement Viewer", W, H, minifb::WindowOptions::default()).unwrap(); - let settlement = Settlement::generate(&mut thread_rng()); + let settlement = Settlement::generate(Vec2::zero(), &mut thread_rng()); let mut focus = Vec2::::zero(); let mut zoom = 1.0; @@ -24,7 +24,7 @@ fn main() { for j in 0..H { let pos = focus + win_to_pos(Vec2::new(i, j)) * zoom; - let color = settlement.get_color(pos); + let color = settlement.get_color(pos).unwrap_or(Rgb::new(35, 50, 20)); buf[j * W + i] = u32::from_le_bytes([color.b, color.g, color.r, 255]); } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 8f60479481..fc923416aa 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -398,12 +398,14 @@ impl<'a> BlockGen<'a> { }; // Structures (like towns) + /* let block = chunk .structures .town .as_ref() .and_then(|town| TownGen.get((town, wpos, sample, height))) .or(block); + */ let block = structures .iter() @@ -472,6 +474,7 @@ impl<'a> ZCache<'a> { let max = (ground_max + structure_max).max(self.sample.water_level + 2.0); // Structures + /* let (min, max) = self .sample .chunk @@ -483,6 +486,7 @@ impl<'a> ZCache<'a> { (town_min.min(min), town_max.max(max)) }) .unwrap_or((min, max)); + */ let structures_only_min_z = ground_max.max(self.sample.water_level + 2.0); diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index c7a8f1babf..2a7f02976b 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -1000,6 +1000,13 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { humidity.sub(CONFIG.jungle_hum).mul(1.0), ); + let ground = sim_chunk.sites.iter().fold(ground, |ground, site| { + site.get_surface(wpos) + .and_then(|block| block.get_color()) + .map(|col| col.map(|e| e as f32 / 255.0)) + .unwrap_or(ground) + }); + // Snow covering let snow_cover = temp .sub(CONFIG.snow_temp) @@ -1095,6 +1102,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { stone_col, chunk: sim_chunk, + /* spawn_rules: sim_chunk .structures .town @@ -1105,6 +1113,11 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { cliffs: !in_water, trees: true, }), + */ + spawn_rules: SpawnRules { + cliffs: !in_water, + trees: true, + }, }) } } diff --git a/world/src/generator/mod.rs b/world/src/generator/mod.rs index 6ac7240b8d..2b92859af5 100644 --- a/world/src/generator/mod.rs +++ b/world/src/generator/mod.rs @@ -2,12 +2,33 @@ pub mod settlement; mod town; // Reexports -pub use self::town::{TownGen, TownState}; +pub use self::{ + settlement::Settlement, + town::{TownGen, TownState}, +}; use crate::{column::ColumnSample, util::Sampler}; use common::terrain::Block; +use std::sync::Arc; use vek::*; +#[derive(Clone)] +pub enum Site { + Settlement(Arc), +} + +impl Site { + pub fn get_surface(&self, wpos: Vec2) -> Option { + match self { + Site::Settlement(settlement) => settlement.get_surface(wpos), + } + } +} + +impl From for Site { + fn from(settlement: Settlement) -> Self { Site::Settlement(Arc::new(settlement)) } +} + #[derive(Copy, Clone, Debug)] pub struct SpawnRules { pub trees: bool, diff --git a/world/src/generator/settlement/mod.rs b/world/src/generator/settlement/mod.rs index 8e353bfd84..74d9929967 100644 --- a/world/src/generator/settlement/mod.rs +++ b/world/src/generator/settlement/mod.rs @@ -1,5 +1,10 @@ use crate::util::{Sampler, StructureGen2d}; -use common::{astar::Astar, path::Path, spiral::Spiral2d}; +use common::{ + astar::Astar, + path::Path, + spiral::Spiral2d, + terrain::{Block, BlockKind}, +}; use hashbrown::{HashMap, HashSet}; use rand::prelude::*; use std::{collections::VecDeque, f32, marker::PhantomData}; @@ -56,7 +61,7 @@ pub fn center_of(p: [Vec2; 3]) -> Vec2 { Vec2::new(x, y) } -const AREA_SIZE: u32 = 48; +const AREA_SIZE: u32 = 64; fn to_tile(e: i32) -> i32 { ((e as f32).div_euclid(AREA_SIZE as f32)).floor() as i32 } @@ -70,6 +75,7 @@ pub struct Structure { } pub struct Settlement { + origin: Vec2, land: Land, farms: Store, structures: Vec, @@ -85,15 +91,16 @@ pub struct Farm { } impl Settlement { - pub fn generate(rng: &mut impl Rng) -> Self { + pub fn generate(wpos: Vec2, rng: &mut impl Rng) -> Self { let mut this = Self { + origin: wpos, land: Land::new(rng), farms: Store::default(), structures: Vec::new(), town: None, }; - this.place_river(rng); + //this.place_river(rng); this.place_farms(rng); this.place_town(rng); @@ -296,7 +303,12 @@ impl Settlement { } } - pub fn get_color(&self, pos: Vec2) -> Rgb { + pub fn get_surface(&self, wpos: Vec2) -> Option { + self.get_color((wpos - self.origin).map(|e| e as f32)) + .map(|col| Block::new(BlockKind::Normal, col)) + } + + pub fn get_color(&self, pos: Vec2) -> Option> { let pos = pos.map(|e| e.floor() as i32); if let Some(structure) = self @@ -304,13 +316,13 @@ impl Settlement { .iter() .find(|s| s.bounds.contains_point(pos)) { - return match structure.kind { + return Some(match structure.kind { StructureKind::House => Rgb::new(200, 80, 50), - }; + }); } - match self.land.get_at_block(pos) { - Sample::Wilderness => Rgb::zero(), + Some(match self.land.get_at_block(pos) { + Sample::Wilderness => return None, Sample::Way(WayKind::Path) => Rgb::new(130, 100, 0), Sample::Way(WayKind::Hedge) => Rgb::new(0, 150, 0), Sample::Way(WayKind::Wall) => Rgb::new(60, 60, 60), @@ -336,7 +348,7 @@ impl Settlement { let furrow = (pos * furrow_dir).sum().rem_euclid(4) < 2; Rgb::new( if furrow { - 150 + 120 } else { 48 + seed.to_le_bytes()[0] % 64 }, @@ -344,7 +356,7 @@ impl Settlement { 16 + seed.to_le_bytes()[2] % 32, ) }, - } + }) } } @@ -374,9 +386,9 @@ pub enum WayKind { impl WayKind { pub fn width(&self) -> f32 { match self { - WayKind::Path => 2.5, + WayKind::Path => 4.0, WayKind::Hedge => 1.5, - WayKind::Wall => 2.5, + WayKind::Wall => 3.5, } } } @@ -386,6 +398,14 @@ pub enum Tower { Wall, } +impl Tower { + pub fn radius(&self) -> f32 { + match self { + Tower::Wall => 8.0, + } + } +} + pub struct Tile { plot: Id, ways: [Option; 4], @@ -414,7 +434,7 @@ impl Land { Self { tiles: HashMap::new(), plots: Store::default(), - sampler_warp: StructureGen2d::new(rng.gen(), AREA_SIZE, 16), + sampler_warp: StructureGen2d::new(rng.gen(), AREA_SIZE, AREA_SIZE * 2 / 5), } } @@ -428,8 +448,8 @@ impl Land { let center_tile = self.tile_at(neighbors[4].0.map(to_tile)); - if neighbors[4].0.distance_squared(pos) < 6i32.pow(2) { - if let Some(tower) = center_tile.and_then(|tile| tile.tower.as_ref()) { + if let Some(tower) = center_tile.and_then(|tile| tile.tower.as_ref()) { + if (neighbors[4].0.distance_squared(pos) as f32) < tower.radius().powf(2.0) { return Sample::Tower(tower); } } diff --git a/world/src/lib.rs b/world/src/lib.rs index acb9b94ca4..365c49adaa 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -16,7 +16,7 @@ pub use crate::config::CONFIG; use crate::{ block::BlockGen, column::{ColumnGen, ColumnSample}, - util::Sampler, + util::{Grid, Sampler}, }; use common::{ generation::{ChunkSupplement, EntityInfo, EntityKind}, @@ -95,7 +95,11 @@ impl World { let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome()); let mut sampler = self.sample_blocks(); - let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32); + let chunk_wpos2d = Vec2::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32); + let zcache_grid = + Grid::populate_from(TerrainChunkSize::RECT_SIZE.map(|e| e as i32), |offs| { + sampler.get_z_cache(chunk_wpos2d + offs) + }); let mut chunk = TerrainChunk::new(base_z, stone, air, meta); for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 { @@ -103,12 +107,13 @@ impl World { if should_continue() { return Err(()); }; - let wpos2d = Vec2::new(x, y) - + Vec2::from(chunk_pos) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32); - let z_cache = match sampler.get_z_cache(wpos2d) { - Some(z_cache) => z_cache, - None => continue, + let offs = Vec2::new(x, y); + let wpos2d = chunk_wpos2d + offs; + + let z_cache = match zcache_grid.get(offs) { + Some(Some(z_cache)) => z_cache, + _ => continue, }; let (min_z, only_structures_min_z, max_z) = z_cache.get_z_limits(&mut sampler); @@ -119,7 +124,7 @@ impl World { (min_z as i32..max_z as i32).for_each(|z| { let lpos = Vec3::new(x, y, z); - let wpos = chunk_block_pos + lpos; + let wpos = Vec3::from(chunk_wpos2d) + lpos; let only_structures = lpos.z >= only_structures_min_z as i32; if let Some(block) = @@ -140,7 +145,7 @@ impl World { lpos.z += 1; } - (chunk_block_pos + lpos).map(|e| e as f32) + 0.5 + (Vec3::from(chunk_wpos2d) + lpos).map(|e: i32| e as f32) + 0.5 }; const SPAWN_RATE: f32 = 0.1; diff --git a/world/src/sim/location.rs b/world/src/sim/location.rs index c337357afe..2eeb1c7a3d 100644 --- a/world/src/sim/location.rs +++ b/world/src/sim/location.rs @@ -1,4 +1,3 @@ -use super::Settlement; use hashbrown::HashSet; use rand::{seq::SliceRandom, Rng}; use vek::*; @@ -9,7 +8,6 @@ pub struct Location { pub(crate) center: Vec2, pub(crate) kingdom: Option, pub(crate) neighbours: HashSet, - pub(crate) settlement: Settlement, } impl Location { @@ -19,7 +17,6 @@ impl Location { center, kingdom: None, neighbours: HashSet::default(), - settlement: Settlement::generate(rng), } } diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 9b75fd9bb4..e21efd45a1 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -15,7 +15,6 @@ pub use self::{ }, location::Location, map::{MapConfig, MapDebug}, - settlement::Settlement, util::{ cdf_irwin_hall, downhill, get_oceans, local_cells, map_edge_factor, neighbors, uniform_idx_as_vec2, uniform_noise, uphill, vec2_as_uniform_idx, InverseCdf, ScaleBias, @@ -27,7 +26,7 @@ use crate::{ all::ForestKind, block::BlockGen, column::ColumnGen, - generator::TownState, + generator::{Settlement, Site}, util::{seed_expan, FastNoise, RandomField, Sampler, StructureGen2d}, CONFIG, }; @@ -1450,7 +1449,7 @@ impl WorldSim { e * sz as i32 + sz as i32 / 2 }) }; - let maybe_towns = self + let sites = self .gen_ctx .town_gen .par_iter( @@ -1462,11 +1461,12 @@ impl WorldSim { |mut block_gen, (pos, seed)| { let mut rng = ChaChaRng::from_seed(seed_expan::rng_state(seed)); // println!("Town: {:?}", town); - TownState::generate(pos, &mut block_gen, &mut rng).map(|t| (pos, Arc::new(t))) + //TownState::generate(pos, &mut block_gen, &mut rng).map(|t| (pos, + // Arc::new(t))) + (pos, Site::from(Settlement::generate(pos, &mut rng))) }, ) - .filter_map(|x| x) - .collect::>(); + .collect::>(); let gen_ctx = &self.gen_ctx; self.chunks @@ -1476,21 +1476,13 @@ impl WorldSim { let chunk_pos = uniform_idx_as_vec2(ij); let wpos = chunk_idx_center(chunk_pos); - let near_towns = gen_ctx.town_gen.get(wpos); - let town = near_towns + if let Some((pos, site)) = sites .iter() - .min_by_key(|(pos, _seed)| wpos.distance_squared(*pos)); - - let maybe_town = town - .and_then(|(pos, _seed)| maybe_towns.get(pos)) - // Only care if we're close to the town - .filter(|town| { - Vec2::from(town.center()).distance_squared(wpos) - < town.radius().add(64).pow(2) - }) - .cloned(); - - chunk.structures.town = maybe_town; + .filter(|(pos, _)| pos.distance_squared(wpos) < 1200i32.pow(2)) + .min_by_key(|(pos, _)| wpos.distance_squared(*pos)) + { + chunk.sites.push(site.clone()); + } }); // Create waypoints @@ -1771,7 +1763,7 @@ pub struct SimChunk { pub location: Option, pub river: RiverData, - pub structures: Structures, + pub sites: Vec, pub contains_waypoint: bool, } @@ -1789,11 +1781,6 @@ pub struct LocationInfo { pub near: Vec, } -#[derive(Clone)] -pub struct Structures { - pub town: Option>, -} - impl SimChunk { fn generate(posi: usize, gen_ctx: &GenCtx, gen_cdf: &GenCdf) -> Self { let pos = uniform_idx_as_vec2(posi); @@ -2015,7 +2002,7 @@ impl SimChunk { spawn_rate: 1.0, location: None, river, - structures: Structures { town: None }, + sites: Vec::new(), contains_waypoint: false, } } diff --git a/world/src/util/grid.rs b/world/src/util/grid.rs index b6a421ceb0..198679c8af 100644 --- a/world/src/util/grid.rs +++ b/world/src/util/grid.rs @@ -5,8 +5,22 @@ pub struct Grid { size: Vec2, } -impl Grid { - pub fn new(default_cell: T, size: Vec2) -> Self { +impl Grid { + pub fn populate_from(size: Vec2, mut f: impl FnMut(Vec2) -> T) -> Self { + Self { + cells: (0..size.y) + .map(|y| (0..size.x).map(move |x| Vec2::new(x, y))) + .flatten() + .map(&mut f) + .collect(), + size, + } + } + + pub fn new(default_cell: T, size: Vec2) -> Self + where + T: Clone, + { Self { cells: vec![default_cell; size.product() as usize], size,