diff --git a/world/src/canvas.rs b/world/src/canvas.rs new file mode 100644 index 0000000000..e1c1b07862 --- /dev/null +++ b/world/src/canvas.rs @@ -0,0 +1,63 @@ +use vek::*; +use common::{ + terrain::{TerrainChunk, Block, TerrainChunkSize}, + vol::{ReadVol, WriteVol, RectVolSize}, +}; +use crate::{ + block::ZCache, + util::Grid, + column::ColumnSample, + index::IndexRef, +}; + +pub struct CanvasInfo<'a> { + pub(crate) wpos: Vec2, + pub(crate) column_grid: &'a Grid>>, + pub(crate) column_grid_border: i32, + pub(crate) index: IndexRef<'a>, +} + +impl<'a> CanvasInfo<'a> { + pub fn wpos(&self) -> Vec2 { + self.wpos + } + + pub fn area(&self) -> Aabr { + Rect::from((self.wpos(), Extent2::from(TerrainChunkSize::RECT_SIZE.map(|e| e as i32)))).into() + } + + pub fn col(&self, pos: Vec2) -> Option<&ColumnSample> { + self.column_grid + .get(self.column_grid_border + pos - self.wpos()) + .map(Option::as_ref) + .flatten() + .map(|zc| &zc.sample) + } + + pub fn index(&self) -> IndexRef { + self.index + } +} + +pub struct Canvas<'a> { + pub(crate) wpos: Vec2, + pub(crate) chunk: &'a mut TerrainChunk, +} + +impl<'a> Canvas<'a> { + pub fn wpos(&self) -> Vec2 { + self.wpos + } + + pub fn area(&self) -> Aabr { + Rect::from((self.wpos(), Extent2::from(TerrainChunkSize::RECT_SIZE.map(|e| e as i32)))).into() + } + + pub fn get(&mut self, pos: Vec3) -> Option { + self.chunk.get(pos - self.wpos()).ok().copied() + } + + pub fn set(&mut self, pos: Vec3, block: Block) { + let _ = self.chunk.set(pos - self.wpos(), block); + } +} diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs index 666664f49c..61dacb4efa 100644 --- a/world/src/layer/mod.rs +++ b/world/src/layer/mod.rs @@ -6,6 +6,8 @@ use crate::{ column::ColumnSample, util::{RandomField, Sampler}, IndexRef, + Canvas, + CanvasInfo, }; use common::{ assets::Asset, @@ -33,19 +35,17 @@ pub struct Colors { const EMPTY_AIR: Block = Block::air(SpriteKind::Empty); pub fn apply_paths_to<'a>( - wpos2d: Vec2, - mut get_column: impl FnMut(Vec2) -> Option<&'a ColumnSample<'a>>, - vol: &mut (impl BaseVol + RectSizedVol + ReadVol + WriteVol), - index: IndexRef, + canvas: &mut Canvas, + info: &CanvasInfo, ) { - for y in 0..vol.size_xy().y as i32 { - for x in 0..vol.size_xy().x as i32 { + for y in 0..canvas.area().size().h as i32 { + for x in 0..canvas.area().size().w as i32 { let offs = Vec2::new(x, y); - let wpos2d = wpos2d + offs; + let wpos2d = canvas.wpos() + offs; // Sample terrain - let col_sample = if let Some(col_sample) = get_column(offs) { + let col_sample = if let Some(col_sample) = info.col(wpos2d) { col_sample } else { continue; @@ -70,10 +70,10 @@ pub fn apply_paths_to<'a>( // Try to use the column at the centre of the path for sampling to make them // flatter let col_pos = (offs - wpos2d).map(|e| e as f32) + path_nearest; - let col00 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 0)); - let col10 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 0)); - let col01 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 1)); - let col11 = get_column(col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 1)); + let col00 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 0)); + let col10 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 0)); + let col01 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(0, 1)); + let col11 = info.col(info.wpos() + col_pos.map(|e| e.floor() as i32) + Vec2::new(1, 1)); let col_attr = |col: &ColumnSample| { Vec3::new(col.riverless_alt, col.alt, col.water_dist.unwrap_or(1000.0)) }; @@ -96,12 +96,12 @@ pub fn apply_paths_to<'a>( let surface_z = (riverless_alt + bridge_offset).floor() as i32; for z in inset - depth..inset { - let _ = vol.set( - Vec3::new(offs.x, offs.y, surface_z + z), + let _ = canvas.set( + Vec3::new(wpos2d.x, wpos2d.y, surface_z + z), if bridge_offset >= 2.0 && path_dist >= 3.0 || z < inset - 1 { Block::new( BlockKind::Rock, - noisy_color(index.colors.layer.bridge.into(), 8), + noisy_color(info.index().colors.layer.bridge.into(), 8), ) } else { let path_color = path.surface_color( @@ -113,9 +113,9 @@ pub fn apply_paths_to<'a>( } let head_space = path.head_space(path_dist); for z in inset..inset + head_space { - let pos = Vec3::new(offs.x, offs.y, surface_z + z); - if vol.get(pos).unwrap().kind() != BlockKind::Water { - let _ = vol.set(pos, EMPTY_AIR); + let pos = Vec3::new(wpos2d.x, wpos2d.y, surface_z + z); + if canvas.get(pos).unwrap().kind() != BlockKind::Water { + let _ = canvas.set(pos, EMPTY_AIR); } } } diff --git a/world/src/lib.rs b/world/src/lib.rs index 7aa02fb46c..d52a39c3c1 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -13,6 +13,7 @@ mod all; mod block; +pub mod canvas; pub mod civ; mod column; pub mod config; @@ -25,7 +26,10 @@ pub mod site; pub mod util; // Reexports -pub use crate::config::CONFIG; +pub use crate::{ + config::CONFIG, + canvas::{Canvas, CanvasInfo}, +}; pub use block::BlockGen; pub use column::ColumnSample; pub use index::{IndexOwned, IndexRef}; @@ -126,7 +130,6 @@ impl World { ); let water = Block::new(BlockKind::Water, Rgb::zero()); - let _chunk_size2d = TerrainChunkSize::RECT_SIZE; let (base_z, sim_chunk) = match self .sim /*.get_interpolated( @@ -203,7 +206,19 @@ impl World { // Apply layers (paths, caves, etc.) layer::apply_caves_to(chunk_wpos2d, sample_get, &mut chunk, index); layer::apply_scatter_to(chunk_wpos2d, sample_get, &mut chunk, index, sim_chunk); - layer::apply_paths_to(chunk_wpos2d, sample_get, &mut chunk, index); + + let canvas_info = CanvasInfo { + wpos: chunk_pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32), + column_grid: &zcache_grid, + column_grid_border: grid_border, + index, + }; + let mut canvas = Canvas { + wpos: chunk_pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32), + chunk: &mut chunk, + }; + + layer::apply_paths_to(&mut canvas, &canvas_info); // Apply site generation sim_chunk.sites.iter().for_each(|site| {