From 0b14ca2f3a1c261c789152653818dde764b66c04 Mon Sep 17 00:00:00 2001 From: Joshua Yanovski Date: Fri, 1 Jul 2022 15:23:27 -0700 Subject: [PATCH] Improved base_z => faster and smaller chunks! --- common/src/terrain/chonk.rs | 2 +- common/src/volumes/chunk.rs | 64 +++++++++++++++++++++--- world/benches/site2.rs | 8 +-- world/src/lib.rs | 99 ++++++++++++++++++++++++++----------- world/src/sim/mod.rs | 2 +- 5 files changed, 133 insertions(+), 42 deletions(-) diff --git a/common/src/terrain/chonk.rs b/common/src/terrain/chonk.rs index 9bf300d910..e943df42ca 100644 --- a/common/src/terrain/chonk.rs +++ b/common/src/terrain/chonk.rs @@ -146,7 +146,7 @@ impl>, S: RectVolSize, M: Clone> C // First, defragment all subchunks. self.sub_chunks.iter_mut().for_each(SubChunk::defragment); // For each homogeneous subchunk (i.e. those where all blocks are the same), - // find those which match `below` at the bottom of the cunk, or `above` + // find those which match `below` at the bottom of the chunk, or `above` // at the top, since these subchunks are redundant and can be removed. // Note that we find (and drain) the above chunks first, so that when we // remove the below chunks we have fewer remaining chunks to backshift. diff --git a/common/src/volumes/chunk.rs b/common/src/volumes/chunk.rs index 070e82e8f6..82763ad67c 100644 --- a/common/src/volumes/chunk.rs +++ b/common/src/volumes/chunk.rs @@ -247,17 +247,17 @@ impl> + VolSize, M> Chunk { #[inline(always)] fn grp_idx(pos: Vec3) -> u32 { let grp_pos = pos.map2(Self::GROUP_SIZE, |e, s| e as u32 / s); - (grp_pos.z * (Self::GROUP_COUNT.y * Self::GROUP_COUNT.x)) - + (grp_pos.y * Self::GROUP_COUNT.x) - + (grp_pos.x) + (grp_pos.x * (Self::GROUP_COUNT.y * Self::GROUP_COUNT.z)) + + (grp_pos.y * Self::GROUP_COUNT.z) + + (grp_pos.z) } #[inline(always)] fn rel_idx(pos: Vec3) -> u32 { let rel_pos = pos.map2(Self::GROUP_SIZE, |e, s| e as u32 % s); - (rel_pos.z * (Self::GROUP_SIZE.y * Self::GROUP_SIZE.x)) - + (rel_pos.y * Self::GROUP_SIZE.x) - + (rel_pos.x) + (rel_pos.x * (Self::GROUP_SIZE.y * Self::GROUP_SIZE.z)) + + (rel_pos.y * Self::GROUP_SIZE.z) + + (rel_pos.z) } #[inline(always)] @@ -386,6 +386,56 @@ impl, M> Iterator for ChunkPosIter { #[inline(always)] fn next(&mut self) -> Option { + if self.pos.x >= self.ub.x { + return None; + } + let res = Some(self.pos); + + self.pos.z += 1; + if self.pos.z != self.ub.z && self.pos.z % Chunk::::GROUP_SIZE.z as i32 != 0 { + return res; + } + self.pos.z = std::cmp::max( + self.lb.z, + (self.pos.z - 1) & !(Chunk::::GROUP_SIZE.z as i32 - 1), + ); + + self.pos.y += 1; + if self.pos.y != self.ub.y && self.pos.y % Chunk::::GROUP_SIZE.y as i32 != 0 { + return res; + } + self.pos.y = std::cmp::max( + self.lb.y, + (self.pos.y - 1) & !(Chunk::::GROUP_SIZE.y as i32 - 1), + ); + + self.pos.x += 1; + if self.pos.x != self.ub.x && self.pos.x % Chunk::::GROUP_SIZE.x as i32 != 0 { + return res; + } + self.pos.x = std::cmp::max( + self.lb.x, + (self.pos.x - 1) & !(Chunk::::GROUP_SIZE.x as i32 - 1), + ); + + self.pos.z = (self.pos.z | (Chunk::::GROUP_SIZE.z as i32 - 1)) + 1; + if self.pos.z < self.ub.z { + return res; + } + self.pos.z = self.lb.z; + + self.pos.y = (self.pos.y | (Chunk::::GROUP_SIZE.y as i32 - 1)) + 1; + if self.pos.y < self.ub.y { + return res; + } + self.pos.y = self.lb.y; + + self.pos.x = (self.pos.x | (Chunk::::GROUP_SIZE.x as i32 - 1)) + 1; + + res + } + + /* fn next(&mut self) -> Option { if self.pos.z >= self.ub.z { return None; } @@ -433,7 +483,7 @@ impl, M> Iterator for ChunkPosIter { self.pos.z = (self.pos.z | (Chunk::::GROUP_SIZE.z as i32 - 1)) + 1; res - } + } */ } pub struct ChunkVolIter<'a, V, S: VolSize, M> { diff --git a/world/benches/site2.rs b/world/benches/site2.rs index 23db0f1739..52a99225dc 100644 --- a/world/benches/site2.rs +++ b/world/benches/site2.rs @@ -299,10 +299,10 @@ fn dungeon(c: &mut Criterion) { bench_group("generate_citadel", "render_citadel", Site::generate_citadel); c.bench_function("generate_chunk", |b| { - // let chunk_pos = (world.sim().map_size_lg().chunks() >> 1).as_(); + let chunk_pos = (world.sim().map_size_lg().chunks() >> 1).as_(); // let chunk_pos = Vec2::new(9500 / 32, 29042 / 32); // let chunk_pos = Vec2::new(26944 / 32, 26848 / 32); - let chunk_pos = Vec2::new(842, 839); + // let chunk_pos = Vec2::new(842, 839); // let chunk_pos = Vec2::new(24507/32, 20682/32); // let chunk_pos = Vec2::new(19638/32, 19621/32); b.iter(|| { @@ -311,10 +311,10 @@ fn dungeon(c: &mut Criterion) { }); c.bench_function("deserialize_chunk", |b| { - // let chunk_pos = (world.sim().map_size_lg().chunks() >> 1).as_(); + let chunk_pos = (world.sim().map_size_lg().chunks() >> 1).as_(); // let chunk_pos = Vec2::new(9500 / 32, 29042 / 32); // let chunk_pos = Vec2::new(26944 / 32, 26848 / 32); - let chunk_pos = Vec2::new(842, 839); + // let chunk_pos = Vec2::new(842, 839); let chunk = world.generate_chunk(index.as_index_ref(), chunk_pos, || false, None).unwrap().0; /* println!("{:?}", chunk.sub_chunks_len()); let chunk = chunk.sub_chunks().next().unwrap(); */ diff --git a/world/src/lib.rs b/world/src/lib.rs index 55a127fbed..6bad1bfefb 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -239,12 +239,39 @@ impl World { let calendar = self.sim.calendar.as_ref(); // FIXME: Deal with this properly if it's not okay to exit early. - let mut sampler = self.sample_blocks(chunk_pos, index/*, calendar*/).ok_or(())?; + let sampler = self.sample_blocks(chunk_pos, index/*, calendar*/); // dbg!(&sampler.column_gen.chaos_spline); + let air = Block::air(SpriteKind::Empty); + let water = Block::new(BlockKind::Water, Rgb::zero()); + let (/*base_z, */sim_chunk, mut sampler) = match sampler/*.zip( + self.sim + /*.get_interpolated( + chunk_pos.map2(chunk_size2d, |e, sz: u32| e * sz as i32 + sz as i32 / 2), + |chunk| chunk.get_base_z(), + ) + .and_then(|base_z| self.sim.get(chunk_pos).map(|sim_chunk| (base_z, sim_chunk))) */ + .get_base_z(chunk_pos))*/ + { + /* Some((sampler, base_z)) => (base_z as i32, sampler.column_gen.sim_chunk, sampler),*/ + Some(sampler) => (/*base_z as i32, */sampler.column_gen.sim_chunk, sampler), + // Some((base_z, sim_chunk)) => (base_z as i32, sim_chunk), + None => { + return Ok(( + TerrainChunk::new( + CONFIG.sea_level as i32, + water, + air, + TerrainChunkMeta::void(), + ), + ChunkSupplement::default(), + )); + }, + }; + + let grid_border = /*4*/0; let chunk_wpos2d = chunk_pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32); let chunk_center_wpos2d = chunk_wpos2d + TerrainChunkSize::RECT_SIZE.map(|e| e as i32 / 2); - let grid_border = /*4*/0; let zcache_grid: Grid = Grid::populate_by_row::<_, _, {TerrainChunkSize::RECT_SIZE.x}, {TerrainChunkSize::RECT_SIZE.y}>( /* TerrainChunkSize::RECT_SIZE.map(|e| e as i32) + grid_border * 2, */ @@ -260,7 +287,12 @@ impl World { /* |offs| sampler.get_z_cache(chunk_wpos2d - grid_border + offs/*, index, calendar*/)/*None*/ */ ); - let air = Block::air(SpriteKind::Empty); + let base_z = ZCache { + sample: zcache_grid.get(grid_border + TerrainChunkSize::RECT_SIZE.map(|e| e as i32) / 2) .unwrap() + } + .get_z_limits() + .0 as i32 + 4; + let stone = Block::new( BlockKind::Rock, zcache_grid @@ -269,32 +301,6 @@ impl World { .map(|zcache| zcache/*.sample*/.stone_col) .unwrap_or_else(|| index.colors.deep_stone_color.into()), ); - let water = Block::new(BlockKind::Water, Rgb::zero()); - - let (base_z, sim_chunk) = match self - .sim - /*.get_interpolated( - chunk_pos.map2(chunk_size2d, |e, sz: u32| e * sz as i32 + sz as i32 / 2), - |chunk| chunk.get_base_z(), - ) - .and_then(|base_z| self.sim.get(chunk_pos).map(|sim_chunk| (base_z, sim_chunk))) */ - .get_base_z(chunk_pos) - { - Some(base_z) => (base_z as i32, self.sim.get(chunk_pos).unwrap()), - // Some((base_z, sim_chunk)) => (base_z as i32, sim_chunk), - None => { - return Ok(( - TerrainChunk::new( - CONFIG.sea_level as i32, - water, - air, - TerrainChunkMeta::void(), - ), - ChunkSupplement::default(), - )); - }, - }; - let meta = TerrainChunkMeta::new( sim_chunk .sites @@ -332,6 +338,11 @@ impl World { let mut chunk = TerrainChunk::new(base_z, stone, air, meta); let calendar = self.sim.calendar.as_ref(); + let mut delta0 = 0; + let mut delta1 = 0; + let mut delta2 = 0; + let mut delta3 = 0; + let mut delta4 = 0; for y in 0..TerrainChunkSize::RECT_SIZE.y as i32 { for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 { if should_continue() { @@ -351,10 +362,22 @@ impl World { let (min_z, max_z) = z_cache.get_z_limits(); /* let max_z = min_z + 1.0; let base_z = min_z as i32 - 1; */ + delta0 = delta0.max(min_z as i32 - base_z); + delta1 = delta1.max(base_z - min_z as i32); + delta2 += (min_z as i32 - base_z).max(0); + delta4 += (base_z - max_z as i32).max(0); + + /* if base_z as f32 > min_z { + dbg!(base_z, min_z, max_z, chunk_pos, sim_chunk); + panic!("base_z > min_z"); + } */ (base_z..min_z as i32).for_each(|z| { let _ = chunk.set(Vec3::new(x, y, z), stone); }); + (max_z as i32..base_z).for_each(|z| { + let _ = chunk.set(Vec3::new(x, y, z), air); + }); let mut block_ = None; (min_z as i32..max_z as i32).for_each(|z| { @@ -363,7 +386,11 @@ impl World { if let Some(block) = sampler.get_with_z_cache(wpos, /*Some(&*/z_cache/*)*/) { // block_ = Some(block); + // let _ = chunk.set(lpos, block); let _ = chunk.set(lpos, block); + }else if z < base_z { + let _ = chunk.set(lpos, air); + delta3 += 1; } }); if let Some(block_) = block_ { @@ -371,6 +398,20 @@ impl World { } } } + if /*delta1 > 0*/delta2 + delta3 + delta4 > 1024 { + let delta2 = delta2 as f32 / 1024.0; + let delta3 = delta3 as f32 / 1024.0; + let delta4 = delta4 as f32 / 1024.0; + /* dbg!( + sim_chunk, + base_z, + delta0, + delta1, + delta2, + delta3, + delta4, + ); */ + } let sample_get = |offs| { zcache_grid diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index c43c0d8fdc..a5c3741857 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -2480,7 +2480,7 @@ impl SimChunk { self.water_alt > self.alt || self.river.river_kind.is_some() } - pub fn get_base_z(&self) -> f32 { self.alt - self.chaos * 50.0 - 16.0 } + pub fn get_base_z(&self) -> f32 { self.alt/* - self.chaos * 16.0 - self.cliff_height.max(0.0) * /*3.125.powf(1.5)*/5.625 - 4.0/*/* * 50.0 - 16.0 */- 7.5*/*/ - 6.0 } pub fn get_biome(&self) -> BiomeKind { let savannah_hum_temp = [0.05..0.55, 0.3..1.6];