Improved base_z => faster and smaller chunks!

This commit is contained in:
Joshua Yanovski 2022-07-01 15:23:27 -07:00
parent d1c06e619f
commit 0b14ca2f3a
5 changed files with 133 additions and 42 deletions

View File

@ -146,7 +146,7 @@ impl<V, Storage: core::ops::DerefMut<Target=Vec<V>>, S: RectVolSize, M: Clone> C
// First, defragment all subchunks. // First, defragment all subchunks.
self.sub_chunks.iter_mut().for_each(SubChunk::defragment); self.sub_chunks.iter_mut().for_each(SubChunk::defragment);
// For each homogeneous subchunk (i.e. those where all blocks are the same), // 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. // 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 // 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. // remove the below chunks we have fewer remaining chunks to backshift.

View File

@ -247,17 +247,17 @@ impl<V, S: core::ops::DerefMut<Target=Vec<V>> + VolSize<V>, M> Chunk<V, S, M> {
#[inline(always)] #[inline(always)]
fn grp_idx(pos: Vec3<i32>) -> u32 { fn grp_idx(pos: Vec3<i32>) -> u32 {
let grp_pos = pos.map2(Self::GROUP_SIZE, |e, s| e as u32 / s); 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.x * (Self::GROUP_COUNT.y * Self::GROUP_COUNT.z))
+ (grp_pos.y * Self::GROUP_COUNT.x) + (grp_pos.y * Self::GROUP_COUNT.z)
+ (grp_pos.x) + (grp_pos.z)
} }
#[inline(always)] #[inline(always)]
fn rel_idx(pos: Vec3<i32>) -> u32 { fn rel_idx(pos: Vec3<i32>) -> u32 {
let rel_pos = pos.map2(Self::GROUP_SIZE, |e, s| e as u32 % s); 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.x * (Self::GROUP_SIZE.y * Self::GROUP_SIZE.z))
+ (rel_pos.y * Self::GROUP_SIZE.x) + (rel_pos.y * Self::GROUP_SIZE.z)
+ (rel_pos.x) + (rel_pos.z)
} }
#[inline(always)] #[inline(always)]
@ -386,6 +386,56 @@ impl<V, S: VolSize<V>, M> Iterator for ChunkPosIter<V, S, M> {
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
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::<V, S, M>::GROUP_SIZE.z as i32 != 0 {
return res;
}
self.pos.z = std::cmp::max(
self.lb.z,
(self.pos.z - 1) & !(Chunk::<V, S, M>::GROUP_SIZE.z as i32 - 1),
);
self.pos.y += 1;
if self.pos.y != self.ub.y && self.pos.y % Chunk::<V, S, M>::GROUP_SIZE.y as i32 != 0 {
return res;
}
self.pos.y = std::cmp::max(
self.lb.y,
(self.pos.y - 1) & !(Chunk::<V, S, M>::GROUP_SIZE.y as i32 - 1),
);
self.pos.x += 1;
if self.pos.x != self.ub.x && self.pos.x % Chunk::<V, S, M>::GROUP_SIZE.x as i32 != 0 {
return res;
}
self.pos.x = std::cmp::max(
self.lb.x,
(self.pos.x - 1) & !(Chunk::<V, S, M>::GROUP_SIZE.x as i32 - 1),
);
self.pos.z = (self.pos.z | (Chunk::<V, S, M>::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::<V, S, M>::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::<V, S, M>::GROUP_SIZE.x as i32 - 1)) + 1;
res
}
/* fn next(&mut self) -> Option<Self::Item> {
if self.pos.z >= self.ub.z { if self.pos.z >= self.ub.z {
return None; return None;
} }
@ -433,7 +483,7 @@ impl<V, S: VolSize<V>, M> Iterator for ChunkPosIter<V, S, M> {
self.pos.z = (self.pos.z | (Chunk::<V, S, M>::GROUP_SIZE.z as i32 - 1)) + 1; self.pos.z = (self.pos.z | (Chunk::<V, S, M>::GROUP_SIZE.z as i32 - 1)) + 1;
res res
} } */
} }
pub struct ChunkVolIter<'a, V, S: VolSize<V>, M> { pub struct ChunkVolIter<'a, V, S: VolSize<V>, M> {

View File

@ -299,10 +299,10 @@ fn dungeon(c: &mut Criterion) {
bench_group("generate_citadel", "render_citadel", Site::generate_citadel); bench_group("generate_citadel", "render_citadel", Site::generate_citadel);
c.bench_function("generate_chunk", |b| { 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(9500 / 32, 29042 / 32);
// let chunk_pos = Vec2::new(26944 / 32, 26848 / 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(24507/32, 20682/32);
// let chunk_pos = Vec2::new(19638/32, 19621/32); // let chunk_pos = Vec2::new(19638/32, 19621/32);
b.iter(|| { b.iter(|| {
@ -311,10 +311,10 @@ fn dungeon(c: &mut Criterion) {
}); });
c.bench_function("deserialize_chunk", |b| { 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(9500 / 32, 29042 / 32);
// let chunk_pos = Vec2::new(26944 / 32, 26848 / 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; let chunk = world.generate_chunk(index.as_index_ref(), chunk_pos, || false, None).unwrap().0;
/* println!("{:?}", chunk.sub_chunks_len()); /* println!("{:?}", chunk.sub_chunks_len());
let chunk = chunk.sub_chunks().next().unwrap(); */ let chunk = chunk.sub_chunks().next().unwrap(); */

View File

@ -239,12 +239,39 @@ impl World {
let calendar = self.sim.calendar.as_ref(); let calendar = self.sim.calendar.as_ref();
// FIXME: Deal with this properly if it's not okay to exit early. // 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); // 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_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 chunk_center_wpos2d = chunk_wpos2d + TerrainChunkSize::RECT_SIZE.map(|e| e as i32 / 2);
let grid_border = /*4*/0;
let zcache_grid: Grid<ColumnSample> = let zcache_grid: Grid<ColumnSample> =
Grid::populate_by_row::<_, _, {TerrainChunkSize::RECT_SIZE.x}, {TerrainChunkSize::RECT_SIZE.y}>( Grid::populate_by_row::<_, _, {TerrainChunkSize::RECT_SIZE.x}, {TerrainChunkSize::RECT_SIZE.y}>(
/* TerrainChunkSize::RECT_SIZE.map(|e| e as i32) + grid_border * 2, */ /* 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*/ */ /* |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( let stone = Block::new(
BlockKind::Rock, BlockKind::Rock,
zcache_grid zcache_grid
@ -269,32 +301,6 @@ impl World {
.map(|zcache| zcache/*.sample*/.stone_col) .map(|zcache| zcache/*.sample*/.stone_col)
.unwrap_or_else(|| index.colors.deep_stone_color.into()), .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( let meta = TerrainChunkMeta::new(
sim_chunk sim_chunk
.sites .sites
@ -332,6 +338,11 @@ impl World {
let mut chunk = TerrainChunk::new(base_z, stone, air, meta); let mut chunk = TerrainChunk::new(base_z, stone, air, meta);
let calendar = self.sim.calendar.as_ref(); 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 y in 0..TerrainChunkSize::RECT_SIZE.y as i32 {
for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 { for x in 0..TerrainChunkSize::RECT_SIZE.x as i32 {
if should_continue() { if should_continue() {
@ -351,10 +362,22 @@ impl World {
let (min_z, max_z) = z_cache.get_z_limits(); let (min_z, max_z) = z_cache.get_z_limits();
/* let max_z = min_z + 1.0; /* let max_z = min_z + 1.0;
let base_z = min_z as i32 - 1; */ 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| { (base_z..min_z as i32).for_each(|z| {
let _ = chunk.set(Vec3::new(x, y, z), stone); 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; let mut block_ = None;
(min_z as i32..max_z as i32).for_each(|z| { (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/*)*/) { if let Some(block) = sampler.get_with_z_cache(wpos, /*Some(&*/z_cache/*)*/) {
// block_ = Some(block); // block_ = Some(block);
// let _ = chunk.set(lpos, 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_ { 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| { let sample_get = |offs| {
zcache_grid zcache_grid

View File

@ -2480,7 +2480,7 @@ impl SimChunk {
self.water_alt > self.alt || self.river.river_kind.is_some() 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 { pub fn get_biome(&self) -> BiomeKind {
let savannah_hum_temp = [0.05..0.55, 0.3..1.6]; let savannah_hum_temp = [0.05..0.55, 0.3..1.6];