From 692855198ecdd150831bceb82c787f176a54a4ba Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 27 Jan 2022 11:48:41 +0000 Subject: [PATCH] Improved terrain in sites --- world/src/column/mod.rs | 25 ++++++++++---------- world/src/site/mod.rs | 13 +++++++++++ world/src/site2/mod.rs | 51 +++++++++++++++++++++++------------------ world/src/site2/tile.rs | 2 ++ 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index 42f3871523..bace8d5d1d 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -1,6 +1,7 @@ use crate::{ all::ForestKind, sim::{local_cells, Cave, Path, RiverKind, SimChunk, WorldSim}, + site::SpawnRules, util::{RandomField, Sampler}, IndexRef, CONFIG, }; @@ -109,6 +110,11 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { let neighbor_chunk = sim.get(neighbor_pos)?; Some((neighbor_pos, neighbor_chunk, &neighbor_chunk.river)) }); + let spawn_rules = sim_chunk + .sites + .iter() + .map(|site| index.sites[*site].spawn_rules(wpos)) + .fold(SpawnRules::default(), |a, b| a.combine(b)); let gradient = sim.get_gradient_approx(chunk_pos); @@ -829,12 +835,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { // NOTE: To disable warp, uncomment this line. // let warp_factor = 0.0; - let warp_factor = warp_factor - * sim_chunk - .sites - .iter() - .map(|site| index.sites[*site].spawn_rules(wpos).max_warp) - .fold(1.0f32, |a, b| a.min(b)); + let warp_factor = warp_factor * spawn_rules.max_warp; let riverless_alt_delta = Lerp::lerp(0.0, riverless_alt_delta, warp_factor); let alt = alt + riverless_alt_delta; @@ -1120,7 +1121,11 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { // dirt let ground = Lerp::lerp(ground, sub_surface_color, marble_mid * tree_density); - let path = sim.get_nearest_path(wpos); + let path = if spawn_rules.paths { + sim.get_nearest_path(wpos) + } else { + None + }; let cave = sim.get_nearest_cave(wpos); let ice_depth = if snow_factor < -0.25 @@ -1168,11 +1173,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> { // No growing directly on bedrock. // And, no growing on sites that don't want them TODO: More precise than this when we // apply trees as a post-processing layer - tree_density: if sim_chunk - .sites - .iter() - .all(|site| index.sites[*site].spawn_rules(wpos).trees) - { + tree_density: if spawn_rules.trees { Lerp::lerp(0.0, tree_density, alt.sub(2.0).sub(basement).mul(0.5)) } else { 0.0 diff --git a/world/src/site/mod.rs b/world/src/site/mod.rs index d922944517..8019111c25 100644 --- a/world/src/site/mod.rs +++ b/world/src/site/mod.rs @@ -26,6 +26,18 @@ pub struct Colors { pub struct SpawnRules { pub trees: bool, pub max_warp: f32, + pub paths: bool, +} + +impl SpawnRules { + pub fn combine(self, other: Self) -> Self { + // Should be commutative + Self { + trees: self.trees && other.trees, + max_warp: self.max_warp.min(other.max_warp), + paths: self.paths && other.paths, + } + } } impl Default for SpawnRules { @@ -33,6 +45,7 @@ impl Default for SpawnRules { Self { trees: true, max_warp: 1.0, + paths: true, } } } diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs index ae1be53dc9..beb0b204da 100644 --- a/world/src/site2/mod.rs +++ b/world/src/site2/mod.rs @@ -60,13 +60,26 @@ impl Site { } pub fn spawn_rules(&self, wpos: Vec2) -> SpawnRules { - let not_near_things = SQUARE_9.iter().all(|&rpos| { - self.wpos_tile(wpos + rpos * tile::TILE_SIZE as i32) - .is_empty() - }); + let tile_pos = self.wpos_tile_pos(wpos); + let max_warp = SQUARE_9 + .iter() + .filter_map(|rpos| { + let tile_pos = tile_pos + rpos; + if self.tiles.get(tile_pos).is_natural() { + None + } else { + let clamped = + wpos.clamped(self.tile_wpos(tile_pos), self.tile_wpos(tile_pos + 1) - 1); + Some(clamped.distance_squared(wpos) as f32) + } + }) + .min_by_key(|d2| *d2 as i32) + .map(|d2| d2.sqrt() as f32 / TILE_SIZE as f32) + .unwrap_or(1.0); SpawnRules { - trees: not_near_things, - max_warp: if not_near_things { 1.0 } else { 0.0 }, + trees: max_warp == 1.0, + max_warp, + paths: max_warp > std::f32::EPSILON, } } @@ -698,14 +711,10 @@ impl Site { let alt = canvas.col(wpos2d).map_or(0, |col| col.alt as i32); (-8..6).for_each(|z| { canvas.map(Vec3::new(wpos2d.x, wpos2d.y, alt + z), |b| { - if z >= 0 { - if b.is_filled() { - Block::empty() - } else { - b.with_sprite(SpriteKind::Empty) - } - } else { + if b.is_filled() { Block::new(BlockKind::Earth, Rgb::new(0x6A, 0x47, 0x24)) + } else { + b.into_vacant() } }) }); @@ -761,21 +770,19 @@ impl Site { if min_dist.is_some() { let alt = /*avg_hard_alt.map(|(sum, weight)| sum / weight).unwrap_or_else(||*/ canvas.col(wpos2d).map_or(0.0, |col| col.alt)/*)*/ as i32; + let mut underground = true; (-6..4).for_each(|z| canvas.map( Vec3::new(wpos2d.x, wpos2d.y, alt + z), - |b| if z > 0 { - let sprite = if z == 1 && self.tile_wpos(tpos) == wpos2d && (tpos + tpos.yx() / 2) % 2 == Vec2::zero() { + |b| if b.is_filled() { + Block::new(BlockKind::Earth, Rgb::new(0x6A, 0x47, 0x24)) + } else { + let sprite = if underground && self.tile_wpos(tpos) == wpos2d && (tpos + tpos.yx() / 2) % 2 == Vec2::zero() { SpriteKind::StreetLamp } else { SpriteKind::Empty }; - if b.is_filled() { - Block::air(sprite) - } else { - b.with_sprite(sprite) - } - } else { - Block::new(BlockKind::Earth, Rgb::new(0x6A, 0x47, 0x24)) + underground = false; + b.with_sprite(sprite) }, )); } diff --git a/world/src/site2/tile.rs b/world/src/site2/tile.rs index 86019a2f4e..410a6be93b 100644 --- a/world/src/site2/tile.rs +++ b/world/src/site2/tile.rs @@ -216,6 +216,8 @@ impl Tile { pub fn is_empty(&self) -> bool { self.kind == TileKind::Empty } + pub fn is_natural(&self) -> bool { matches!(self.kind, TileKind::Empty | TileKind::Hazard(_)) } + pub fn is_road(&self) -> bool { matches!(self.kind, TileKind::Plaza | TileKind::Road { .. }) } pub fn is_obstacle(&self) -> bool {