From 0754a128d7d8269a73f4b4518cccf278d5145a33 Mon Sep 17 00:00:00 2001 From: kralverde Date: Thu, 3 Oct 2024 16:29:39 -0400 Subject: [PATCH] rebase master --- pumpkin-core/src/math/mod.rs | 1 + pumpkin-core/src/math/voxel_shape.rs | 9 + pumpkin-world/src/biome.rs | 24 + pumpkin-world/src/block/block_state.rs | 1 + pumpkin-world/src/lib.rs | 1 - pumpkin-world/src/world_gen/blender/data.rs | 391 ------ pumpkin-world/src/world_gen/blender/mod.rs | 352 +----- pumpkin-world/src/world_gen/chunk.rs | 333 ----- .../{height.rs => world_gen/height_limit.rs} | 3 - pumpkin-world/src/world_gen/heightmap.rs | 1 - .../src/world_gen/implementation/aquifer.rs | 72 -- .../src/world_gen/implementation/mod.rs | 56 - .../world_gen/implementation/overworld/mod.rs | 1 - .../implementation/surface_builder.rs | 0 pumpkin-world/src/world_gen/mod.rs | 10 +- .../src/world_gen/noise/chunk_sampler.rs | 1119 ----------------- pumpkin-world/src/world_gen/noise/config.rs | 16 - .../src/world_gen/noise/density/blend.rs | 2 - .../src/world_gen/noise/density/mod.rs | 247 +++- .../src/world_gen/noise/density/spline.rs | 118 +- .../density/terrain_helpers.rs} | 106 +- pumpkin-world/src/world_gen/noise/mod.rs | 14 +- pumpkin-world/src/world_gen/positions.rs | 28 + pumpkin-world/src/world_gen/proto_chunk.rs | 29 + pumpkin-world/src/world_gen/supplier.rs | 26 - 25 files changed, 475 insertions(+), 2485 deletions(-) create mode 100644 pumpkin-core/src/math/voxel_shape.rs delete mode 100644 pumpkin-world/src/world_gen/blender/data.rs delete mode 100644 pumpkin-world/src/world_gen/chunk.rs rename pumpkin-world/src/{height.rs => world_gen/height_limit.rs} (96%) delete mode 100644 pumpkin-world/src/world_gen/heightmap.rs delete mode 100644 pumpkin-world/src/world_gen/implementation/aquifer.rs delete mode 100644 pumpkin-world/src/world_gen/implementation/surface_builder.rs delete mode 100644 pumpkin-world/src/world_gen/noise/chunk_sampler.rs delete mode 100644 pumpkin-world/src/world_gen/noise/config.rs rename pumpkin-world/src/world_gen/{implementation/overworld/terrain_params.rs => noise/density/terrain_helpers.rs} (84%) create mode 100644 pumpkin-world/src/world_gen/positions.rs create mode 100644 pumpkin-world/src/world_gen/proto_chunk.rs delete mode 100644 pumpkin-world/src/world_gen/supplier.rs diff --git a/pumpkin-core/src/math/mod.rs b/pumpkin-core/src/math/mod.rs index c568268af..29ac634d5 100644 --- a/pumpkin-core/src/math/mod.rs +++ b/pumpkin-core/src/math/mod.rs @@ -2,6 +2,7 @@ pub mod boundingbox; pub mod position; pub mod vector2; pub mod vector3; +pub mod voxel_shape; pub fn wrap_degrees(var: f32) -> f32 { let mut var1 = var % 360.0; diff --git a/pumpkin-core/src/math/voxel_shape.rs b/pumpkin-core/src/math/voxel_shape.rs new file mode 100644 index 000000000..ecf5a88d2 --- /dev/null +++ b/pumpkin-core/src/math/voxel_shape.rs @@ -0,0 +1,9 @@ +pub struct VoxelShape { + // TODO +} + +impl VoxelShape { + pub fn is_empty() -> bool { + unimplemented!() + } +} diff --git a/pumpkin-world/src/biome.rs b/pumpkin-world/src/biome.rs index 6af83f6e0..337a582ce 100644 --- a/pumpkin-world/src/biome.rs +++ b/pumpkin-world/src/biome.rs @@ -1,3 +1,4 @@ +use enum_dispatch::enum_dispatch; use serde::{Deserialize, Serialize}; // TODO make this work with the protocol @@ -9,3 +10,26 @@ pub enum Biome { SnowyTiga, // TODO list all Biomes } + +#[derive(Clone)] +#[enum_dispatch(BiomeSupplierImpl)] +pub enum BiomeSupplier { + Debug(DebugBiomeSupplier), +} + +#[enum_dispatch] +pub trait BiomeSupplierImpl { + fn biome(&self, x: i32, y: i32, z: i32, noise: &MultiNoiseSampler) -> Biome; +} + +#[derive(Clone)] +pub struct DebugBiomeSupplier {} + +impl BiomeSupplierImpl for DebugBiomeSupplier { + fn biome(&self, _x: i32, _y: i32, _z: i32, _noise: &MultiNoiseSampler) -> Biome { + Biome::Plains + } +} + +// TODO: Implement +pub struct MultiNoiseSampler {} diff --git a/pumpkin-world/src/block/block_state.rs b/pumpkin-world/src/block/block_state.rs index df79018c7..8e9a59e5d 100644 --- a/pumpkin-world/src/block/block_state.rs +++ b/pumpkin-world/src/block/block_state.rs @@ -1,3 +1,4 @@ +<<<<<<< HEAD use std::collections::HashMap; use thiserror::Error; diff --git a/pumpkin-world/src/lib.rs b/pumpkin-world/src/lib.rs index dd1fbafe5..dc1e73d1a 100644 --- a/pumpkin-world/src/lib.rs +++ b/pumpkin-world/src/lib.rs @@ -5,7 +5,6 @@ pub mod coordinates; pub mod cylindrical_chunk_iterator; pub mod dimension; pub mod global_registry; -mod height; pub mod item; pub mod level; mod world_gen; diff --git a/pumpkin-world/src/world_gen/blender/data.rs b/pumpkin-world/src/world_gen/blender/data.rs deleted file mode 100644 index d2559eb6f..000000000 --- a/pumpkin-world/src/world_gen/blender/data.rs +++ /dev/null @@ -1,391 +0,0 @@ -use crate::{ - self as pumpkin_world, - biome::Biome, - block::BlockId, - height::{HeightLimitView, HeightLimitViewImpl, StandardHeightLimitView}, - world_gen::{ - chunk::{BlockPos, Chunk, GenerationState, HeightMapType}, - Direction, - }, -}; -use num_traits::PrimInt; -use pumpkin_macros::block_id; - -pub const SURFACE_BLOCKS: [BlockId; 11] = [ - block_id!("minecraft:podzol"), - block_id!("minecraft:gravel"), - block_id!("minecraft:grass_block"), - block_id!("minecraft:stone"), - block_id!("minecraft:coarse_dirt"), - block_id!("minecraft:sand"), - block_id!("minecraft:red_sand"), - block_id!("minecraft:mycelium"), - block_id!("minecraft:snow_block"), - block_id!("minecraft:terracotta"), - block_id!("minecraft:dirt"), -]; - -const BIOMES_PER_CHUNK: usize = 16 >> 2; -const LAST_CHUNK_BIOME_INDEX: usize = BIOMES_PER_CHUNK - 1; -const CHUNK_BIOME_END_INDEX: usize = BIOMES_PER_CHUNK; -const NORTH_WEST_END_INDEX: usize = 2 * LAST_CHUNK_BIOME_INDEX + 1; -const SOUTH_EAST_END_INDEX_PART: usize = 2 * CHUNK_BIOME_END_INDEX + 1; -const HORIZONTAL_BIOME_COUNT: usize = NORTH_WEST_END_INDEX + SOUTH_EAST_END_INDEX_PART; - -pub struct BlendingData { - pub(crate) height_limit: HeightLimitView, - pub(crate) surface_heights: Box<[f64; HORIZONTAL_BIOME_COUNT]>, - pub(crate) biomes: Box<[Option>; HORIZONTAL_BIOME_COUNT]>, - pub(crate) collidable_block_densities: Box<[Option>; HORIZONTAL_BIOME_COUNT]>, - initialized: bool, -} - -impl BlendingData { - pub fn get_blending_data(chunk: &Chunk, _chunk_x: i32, _chunk_z: i32) -> Option { - // TODO: We currently assume all chunks have new noise. valid assumption? - if let Some(mut data) = chunk.blending_data() { - if chunk.status() >= GenerationState::Biome { - data.init_chunk_blending_data( - chunk, - &[ - Direction::North, - Direction::NorthWest, - Direction::West, - Direction::SouthWest, - Direction::South, - Direction::SouthEast, - Direction::East, - Direction::NorthEast, - ], - ); - Some(data) - } else { - None - } - } else { - None - } - } - - #[inline] - fn method_39355(i: usize) -> usize { - i & !(i.unsigned_shr(31)) - } - - pub(crate) fn x(index: usize) -> usize { - if index < NORTH_WEST_END_INDEX { - Self::method_39355(LAST_CHUNK_BIOME_INDEX - index) - } else { - let i = index - NORTH_WEST_END_INDEX; - CHUNK_BIOME_END_INDEX - Self::method_39355(CHUNK_BIOME_END_INDEX - i) - } - } - - pub(crate) fn z(index: usize) -> usize { - if index < NORTH_WEST_END_INDEX { - Self::method_39355(index - LAST_CHUNK_BIOME_INDEX) - } else { - let i = index - NORTH_WEST_END_INDEX; - CHUNK_BIOME_END_INDEX - Self::method_39355(i - CHUNK_BIOME_END_INDEX) - } - } - - pub fn height(&self, biome_x: usize, _biome_y: usize, biome_z: usize) -> f64 { - if biome_x == CHUNK_BIOME_END_INDEX || biome_z == CHUNK_BIOME_END_INDEX { - self.surface_heights[Self::south_east_index(biome_x, biome_z)] - } else if biome_x != 0 && biome_z != 0 { - f64::MAX - } else { - self.surface_heights[Self::north_west_index(biome_x, biome_z)] - } - } - - fn collidable_block_density_from_column( - &self, - column: Option<&[f64]>, - half_section_y: i32, - ) -> f64 { - if let Some(column) = column { - let i = self.half_section_height(half_section_y); - if (i >= 0) && ((i as usize) < column.len()) { - column[i as usize] * 0.1f64 - } else { - f64::MAX - } - } else { - f64::MAX - } - } - - pub fn collidable_block_density( - &self, - biome_x: usize, - half_section_y: i32, - biome_z: usize, - ) -> f64 { - if half_section_y == self.bottom_half_section_y() { - 0.1f64 - } else if biome_x == CHUNK_BIOME_END_INDEX || biome_z == CHUNK_BIOME_END_INDEX { - self.collidable_block_density_from_column( - self.collidable_block_densities[Self::south_east_index(biome_x, biome_z)] - .as_deref(), - half_section_y, - ) - } else if biome_x != 0 && biome_z != 0 { - f64::MAX - } else { - self.collidable_block_density_from_column( - self.collidable_block_densities[Self::north_west_index(biome_x, biome_z)] - .as_deref(), - half_section_y, - ) - } - } - - fn new(bottom_section_y: i32, top_section_y: i32, heights: Option<&[f64]>) -> Self { - let heights = match heights { - Some(heights) => { - let mut owned_heights = [0f64; HORIZONTAL_BIOME_COUNT]; - assert!( - heights.len() == HORIZONTAL_BIOME_COUNT, - "Heights needs to be the right length" - ); - owned_heights - .iter_mut() - .zip(heights) - .for_each(|(new, old)| { - *new = *old; - }); - owned_heights - } - None => [f64::MAX; HORIZONTAL_BIOME_COUNT], - }; - - let collidable_block_densities: [Option>; HORIZONTAL_BIOME_COUNT] = - [const { None }; HORIZONTAL_BIOME_COUNT]; - let biomes: [Option>; HORIZONTAL_BIOME_COUNT] = - [const { None }; HORIZONTAL_BIOME_COUNT]; - - let i = bottom_section_y << 4; - let j = (top_section_y << 4) - i; - let height_limit = HeightLimitView::Standard(StandardHeightLimitView::new(i, j)); - - Self { - height_limit, - surface_heights: Box::new(heights.clone()), - biomes: Box::new(biomes), - collidable_block_densities: Box::new(collidable_block_densities), - initialized: false, - } - } - - pub fn vertical_half_section_count(&self) -> i32 { - self.height_limit.vertical_section_count() * 2 - } - - fn collidable_and_not_tree(chunk: &Chunk, pos: &BlockPos) -> bool { - let state = chunk.get_block_state(pos); - if state.is_air() - || state.has_tag("leaves") - || state.has_tag("logs") - || state.is_block(block_id!("minecraft:brown_mushroom_block")) - || state.is_block(block_id!("minecraft:red_mushroom_block")) - { - false - } else { - state.collision_shape(chunk, pos).is_empty() - } - } - - fn above_collidable_block_value(chunk: &Chunk, pos: &BlockPos) -> (f64, BlockPos) { - let pos = pos.down(); - let val = if Self::collidable_and_not_tree(chunk, &pos) { - 1f64 - } else { - -1f64 - }; - (val, pos) - } - - fn north_west_index(biome_x: usize, biome_z: usize) -> usize { - LAST_CHUNK_BIOME_INDEX + biome_x + biome_z - } - - fn south_east_index(biome_x: usize, biome_z: usize) -> usize { - NORTH_WEST_END_INDEX + biome_x + CHUNK_BIOME_END_INDEX - biome_z - } - - fn init_chunk_blending_data(&mut self, chunk: &Chunk, directions: &[Direction]) { - if !self.initialized { - if directions.contains(&Direction::North) - || directions.contains(&Direction::West) - || directions.contains(&Direction::NorthWest) - { - self.init_block_column(Self::north_west_index(0, 0), chunk, 0, 0); - } - - if directions.contains(&Direction::North) { - for i in 1..BIOMES_PER_CHUNK { - self.init_block_column(Self::north_west_index(i, 0), chunk, (4 * i) as i32, 0); - } - } - - if directions.contains(&Direction::West) { - for i in 1..BIOMES_PER_CHUNK { - self.init_block_column(Self::north_west_index(0, i), chunk, 0, (4 * i) as i32); - } - } - - if directions.contains(&Direction::East) { - for i in 1..BIOMES_PER_CHUNK { - self.init_block_column( - Self::south_east_index(CHUNK_BIOME_END_INDEX, i), - chunk, - 15, - (4 * i) as i32, - ); - } - } - - if directions.contains(&Direction::South) { - for i in 1..BIOMES_PER_CHUNK { - self.init_block_column( - Self::south_east_index(i, CHUNK_BIOME_END_INDEX), - chunk, - (4 * i) as i32, - 15, - ); - } - } - - if directions.contains(&Direction::East) && directions.contains(&Direction::NorthEast) { - self.init_block_column( - Self::south_east_index(CHUNK_BIOME_END_INDEX, 0), - chunk, - 15, - 0, - ); - } - - if directions.contains(&Direction::East) - && directions.contains(&Direction::South) - && directions.contains(&Direction::SouthEast) - { - self.init_block_column( - Self::south_east_index(CHUNK_BIOME_END_INDEX, CHUNK_BIOME_END_INDEX), - chunk, - 15, - 15, - ); - } - - self.initialized = true; - } - } - - fn collidable_block_density_below(chunk: &Chunk, pos: &BlockPos) -> (f64, BlockPos) { - let (val, new_pos) = Self::above_collidable_block_value(chunk, &pos); - let mut d = val; - let mut pos = new_pos; - - for _ in 0..6 { - let (val, new_pos) = Self::above_collidable_block_value(chunk, &pos); - d += val; - pos = new_pos; - } - - (d, pos) - } - - pub fn bottom_half_section_y(&self) -> i32 { - self.height_limit.bottom_section_coord() * 2 - } - - fn half_section_height(&self, section_y: i32) -> i32 { - section_y - (self.bottom_half_section_y() + 1) - } - - fn init_block_column(&mut self, index: usize, chunk: &Chunk, chunk_x: i32, chunk_z: i32) { - if self.surface_heights[index] == f64::MAX { - self.surface_heights[index] = self.surface_block_y(chunk, chunk_x, chunk_z) as f64; - } - self.collidable_block_densities[index] = Some(self.collidable_block_density_column( - chunk, - chunk_x, - chunk_z, - self.surface_heights[index].floor() as i32, - )); - self.biomes[index] = Some(self.vertical_biome_sections(chunk, chunk_x, chunk_z)); - } - - fn vertical_biome_sections(&self, chunk: &Chunk, block_x: i32, block_z: i32) -> Vec { - (0..self.vertical_biome_count()) - .map(|i| { - let j = i + (self.height_limit.bottom_y() >> 2); - chunk.biome_for_noise_gen(block_x >> 2, j, block_z >> 2) - }) - .collect() - } - - fn vertical_biome_count(&self) -> i32 { - self.height_limit.vertical_section_count() << 2 - } - - fn collidable_block_density_column( - &self, - chunk: &Chunk, - chunk_x: i32, - chunk_z: i32, - height: i32, - ) -> Vec { - let mut ds: Vec = (0..self.vertical_half_section_count()) - .map(|_| -1f64) - .collect(); - - let pos = BlockPos::new(chunk_x, self.height_limit.top_y(), chunk_z); - let (mut d, mut pos) = Self::collidable_block_density_below(chunk, &pos); - - for i in (0..=(ds.len() - 2)).rev() { - let (e, local_pos) = Self::above_collidable_block_value(chunk, &pos); - let (f, local_pos) = Self::collidable_block_density_below(chunk, &local_pos); - ds[i] = (d + e + f) / 15f64; - d = f; - pos = local_pos; - } - - let i = self.half_section_height(height / 8); - if i >= 0 && (i as usize) < (ds.len() - 1) { - let e = (height as f64 + 0.5f64) % 8f64 / 8f64; - let f = (1f64 - e) / e; - let g = f.max(1f64) * 0.25f64; - ds[(i + 1) as usize] = -f / g; - ds[i as usize] = 1f64 / g; - } - - ds - } - - fn surface_block_y(&self, chunk: &Chunk, block_x: i32, block_z: i32) -> i32 { - let i = if let Some(value) = - chunk.sample_height_map(HeightMapType::WorldGenSurface, block_x, block_z) - { - value - } else { - self.height_limit.top_y() - }; - - let j = self.height_limit.bottom_y(); - - for height in (j..=i).rev() { - if SURFACE_BLOCKS.contains( - &chunk - .get_block_state(&BlockPos::new(block_x, height, block_z)) - .block(), - ) { - return height; - } - } - - j - } -} diff --git a/pumpkin-world/src/world_gen/blender/mod.rs b/pumpkin-world/src/world_gen/blender/mod.rs index b32efe658..eb1e0ec43 100644 --- a/pumpkin-world/src/world_gen/blender/mod.rs +++ b/pumpkin-world/src/world_gen/blender/mod.rs @@ -1,351 +1,11 @@ -use std::{ - collections::HashMap, - sync::{Arc, LazyLock}, -}; +use super::noise::density::NoisePos; -use data::BlendingData; -use enum_dispatch::enum_dispatch; -use pumpkin_core::{ - math::{hypot, magnitude}, - random::{xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl}, -}; - -use crate::{biome::Biome, height::HeightLimitViewImpl}; - -use super::{ - biome_coords, - chunk::{Chunk, ChunkPos}, - noise::{ - density::NoisePosImpl, - lerp, - perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler}, - }, - supplier::{BiomeSupplier, StaticBiomeSupplier}, -}; - -pub mod data; - -static OFFSET_NOISE: LazyLock = LazyLock::new(|| { - DoublePerlinNoiseSampler::new( - &mut RandomGenerator::Xoroshiro(Xoroshiro::from_seed(42)), - &DoublePerlinNoiseParameters::new(-3, &[1f64; 4]), - ) -}); -const BLENDING_BIOME_DISTANCE_THRESHOLD: i32 = (7 << 2) - 1; -const BLENDING_CHUNK_DISTANCE_THRESHOLD: i32 = (BLENDING_BIOME_DISTANCE_THRESHOLD + 3) >> 2; -const CLOSE_BLENDING_DISTANCE_THRESHOLD: i32 = 5 >> 2; - -#[derive(Clone)] -pub struct BlendResult { - alpha: f64, - offset: f64, +pub struct Blender { + // TODO } -impl BlendResult { - pub fn new(alpha: f64, offset: f64) -> Self { - Self { alpha, offset } - } - - pub fn alpha(&self) -> f64 { - self.alpha - } - - pub fn offset(&self) -> f64 { - self.offset - } -} - -#[enum_dispatch(BlenderImpl)] -#[derive(Clone)] -pub enum Blender { - None(NoBlendBlender), - Standard(StandardBlender), -} - -#[enum_dispatch] -pub trait BlenderImpl { - fn apply_blend_density(&self, pos: &impl NoisePosImpl, density: f64) -> f64; - fn calculate(&self, block_x: i32, block_z: i32) -> BlendResult; - fn biome_supplier(&self, supplier: &BiomeSupplier) -> BiomeSupplier; -} - -#[derive(Clone)] -pub struct NoBlendBlender {} -impl BlenderImpl for NoBlendBlender { - fn calculate(&self, _block_x: i32, _block_z: i32) -> BlendResult { - BlendResult { - alpha: 1f64, - offset: 0f64, - } - } - - fn apply_blend_density(&self, _pos: &impl NoisePosImpl, density: f64) -> f64 { - density - } - - fn biome_supplier(&self, supplier: &BiomeSupplier) -> BiomeSupplier { - supplier.clone() - } -} - -#[derive(Clone)] -struct StandardBlender { - blend_data: Arc>, - close_blend_data: Arc>, -} - -#[derive(Clone)] -enum BlendingSampleType { - Height, - Density, -} - -impl StandardBlender { - fn new( - blend_data: HashMap, - close_blend_data: HashMap, - ) -> Self { - Self { - blend_data: Arc::new(blend_data), - close_blend_data: Arc::new(close_blend_data), - } - } - - fn blend_offset(height: f64) -> f64 { - let e = height + 0.5f64; - let f = ((e % 8f64) + 8f64) % 8f64; - (32f64 * (e - 128f64) - 3f64 * (e - 128f64) * f + 3f64 * f * f) - / (128f64 * (32f64 - 3f64 * f)) - } - - fn sample_closest( - &self, - sample_type: BlendingSampleType, - biome_x: i32, - biome_y: i32, - biome_z: i32, - ) -> f64 { - let i = biome_coords::to_chunk(biome_x); - let j = biome_coords::to_chunk(biome_z); - - let bl = (biome_x & 3) == 0; - let bl2 = (biome_z & 3) == 0; - - let mut d = self.sample(sample_type.clone(), i, j, biome_x, biome_y, biome_z); - - if d == f64::MAX { - if bl && bl2 { - d = self.sample(sample_type.clone(), i - 1, j - 1, biome_x, biome_y, biome_z); - } - - if d == f64::MAX && bl { - d = self.sample(sample_type.clone(), i - 1, j, biome_x, biome_y, biome_z); - } - - if d == f64::MAX && bl2 { - d = self.sample(sample_type.clone(), i, j - 1, biome_x, biome_y, biome_z); - } - } - - d - } - - fn sample( - &self, - sample_type: BlendingSampleType, - chunk_x: i32, - chunk_z: i32, - biome_x: i32, - biome_y: i32, - biome_z: i32, - ) -> f64 { - if let Some(blending_data) = self - .blend_data - .get(&ChunkPos::new(chunk_x, chunk_z).to_long()) - { - match sample_type { - BlendingSampleType::Height => blending_data.height( - (biome_x - biome_coords::from_chunk(chunk_x)) as usize, - biome_y as usize, - (biome_z - biome_coords::from_chunk(chunk_z)) as usize, - ), - BlendingSampleType::Density => blending_data.collidable_block_density( - (biome_x - biome_coords::from_chunk(chunk_x)) as usize, - biome_y, - (biome_z - biome_coords::from_chunk(chunk_z)) as usize, - ), - } - } else { - f64::MAX - } - } - - fn blend_biome(&self, x: i32, y: i32, z: i32) -> Option { - for (k, v) in self.blend_data.iter() { - let biome_x = biome_coords::from_chunk(ChunkPos::packed_x(*k)); - let biome_z = biome_coords::from_chunk(ChunkPos::packed_z(*k)); - - if y >= biome_coords::from_block(v.height_limit.bottom_y()) - && y < biome_coords::from_block(v.height_limit.top_y()) - { - let mut val = f64::INFINITY; - let mut biome: Option = None; - - let i = biome_coords::from_block(v.height_limit.bottom_y()); - - for (j, biome_list) in v.biomes.iter().enumerate() { - if let Some(biome_list) = biome_list { - if let Some(internal_biome) = biome_list.get(i as usize) { - let biome_x = biome_x + BlendingData::x(j) as i32; - let biome_z = biome_z + BlendingData::z(j) as i32; - - let dx = hypot((x - biome_x) as f64, (z - biome_z) as f64); - if dx <= BLENDING_BIOME_DISTANCE_THRESHOLD as f64 && dx < val { - val = dx; - biome = Some(*internal_biome) - } - } - } - } - - if val < f64::MAX { - let d = OFFSET_NOISE.sample(x as f64, 0f64, z as f64) * 12f64; - let e = ((val + d) / (BLENDING_BIOME_DISTANCE_THRESHOLD + 1) as f64) - .clamp(0f64, 1f64); - if e <= 0.5f64 { - return Some(biome.unwrap()); - } - } - } - } - - None - } -} - -impl BlenderImpl for StandardBlender { - fn calculate(&self, block_x: i32, block_z: i32) -> BlendResult { - let i = biome_coords::from_block(block_x); - let j = biome_coords::from_block(block_z); - - let d = self.sample_closest(BlendingSampleType::Height, i, 0, j); - if d != f64::MAX { - BlendResult { - alpha: 0f64, - offset: Self::blend_offset(d), - } - } else { - let mut val1 = 0f64; - let mut val2 = 0f64; - let mut val3 = f64::INFINITY; - - for (chunk_pos, data) in self.blend_data.iter() { - let biome_x = biome_coords::from_chunk(ChunkPos::packed_x(*chunk_pos)); - let biome_z = biome_coords::from_chunk(ChunkPos::packed_z(*chunk_pos)); - - for (index, height) in data.surface_heights.iter().enumerate() { - if *height != f64::MAX { - let biome_x = biome_x + BlendingData::x(index) as i32; - let biome_z = biome_z + BlendingData::z(index) as i32; - - let dx = hypot((i - biome_x) as f64, (j - biome_z) as f64); - if dx <= BLENDING_BIOME_DISTANCE_THRESHOLD as f64 { - if dx < val3 { - val3 = dx; - } - let ex = 1f64 / (dx * dx * dx * dx); - val2 += *height * ex; - val1 += ex; - } - } - } - } - - if val3 == f64::INFINITY { - BlendResult { - alpha: 1f64, - offset: 0f64, - } - } else { - let e = val2 / val1; - let f = (val3 / (BLENDING_BIOME_DISTANCE_THRESHOLD + 1) as f64).clamp(0f64, 1f64); - let f = 3f64 * f * f - 2f64 * f * f * f; - BlendResult { - alpha: f, - offset: Self::blend_offset(e), - } - } - } - } - - fn apply_blend_density(&self, pos: &impl NoisePosImpl, density: f64) -> f64 { - let i = biome_coords::from_block(pos.x()); - let j = pos.y() / 8; - let k = biome_coords::from_block(pos.z()); - - let d = self.sample_closest(BlendingSampleType::Density, i, j, k); - - if d != f64::MAX { - d - } else { - let mut val1 = 0f64; - let mut val2 = 0f64; - let mut val3 = f64::INFINITY; - - for (chunk_pos, data) in self.close_blend_data.iter() { - let biome_x = biome_coords::from_chunk(ChunkPos::packed_z(*chunk_pos)); - let biome_y = biome_coords::from_chunk(ChunkPos::packed_z(*chunk_pos)); - let min_half_section_y = j - 1; - let max_half_section_y = j + 1; - - let one_above = data.bottom_half_section_y() + 1; - let j = 0.max(min_half_section_y - one_above); - let k = data - .vertical_half_section_count() - .min(max_half_section_y - one_above); - - for (index, density_vec) in data.collidable_block_densities.iter().enumerate() { - if let Some(density_vec) = density_vec { - let m = biome_x + BlendingData::x(index) as i32; - let n = biome_y + BlendingData::z(index) as i32; - - for o in j..k { - let biome_x = m; - let half_section_y = o + one_above; - let biome_z = n; - let density = density_vec[o as usize] * 0.1f64; - - let dx = magnitude( - (i - biome_x) as f64, - ((j - half_section_y) * 2) as f64, - (k - biome_z) as f64, - ); - - if dx <= 2f64 { - if dx < val3 { - val3 = dx; - } - - let ex = 1f64 / (dx * dx * dx * dx); - val2 += density * ex; - val1 += ex; - } - } - } - } - } - - if val3 == f64::INFINITY { - density - } else { - let e = val2 / val1; - let f = (val3 / 3f64).clamp(0f64, 1f64); - lerp(f, e, density) - } - } - } - - fn biome_supplier(&self, _supplier: &BiomeSupplier) -> BiomeSupplier { - BiomeSupplier::Static(StaticBiomeSupplier {}) +impl Blender { + pub fn apply_blend_density(&self, _pos: &NoisePos, _density: f64) -> f64 { + todo!() } } diff --git a/pumpkin-world/src/world_gen/chunk.rs b/pumpkin-world/src/world_gen/chunk.rs deleted file mode 100644 index 84c84a849..000000000 --- a/pumpkin-world/src/world_gen/chunk.rs +++ /dev/null @@ -1,333 +0,0 @@ -use std::{ops::Add, sync::Arc}; - -use num_traits::PrimInt; -use parking_lot::Mutex; - -use crate::{ - biome::Biome, block::BlockId, chunk::ChunkData, height::HeightLimitViewImpl, - world_gen::noise::chunk_sampler::ChunkNoiseSampler, -}; - -use super::{biome_coords, blender::data::BlendingData, heightmap::HeightMap}; - -#[derive(Clone, PartialEq, PartialOrd)] -pub enum GenerationState { - Empty, - StructureStart, - StructureRef, - Biome, - Noise, - Surface, - Carver, - Feature, - InitLight, - Light, - Spawn, - Full, -} - -pub struct BlockPos { - x: i32, - y: i32, - z: i32, -} - -impl BlockPos { - pub fn new(x: i32, y: i32, z: i32) -> Self { - Self { x, y, z } - } - - pub fn x(&self) -> i32 { - self.x - } - - pub fn y(&self) -> i32 { - self.y - } - - pub fn z(&self) -> i32 { - self.z - } - - pub fn down(&self) -> Self { - self.down_by(1) - } - - pub fn down_by(&self, count: i32) -> Self { - Self { - x: self.x, - y: self.y - count, - z: self.z, - } - } - - pub fn up(&self) -> Self { - self.up_by(1) - } - - pub fn up_by(&self, count: i32) -> Self { - Self { - x: self.x, - y: self.y + count, - z: self.z, - } - } - - pub fn north(&self) -> Self { - self.north_by(1) - } - - pub fn north_by(&self, count: i32) -> Self { - Self { - x: self.x, - y: self.y, - z: self.z - count, - } - } - - pub fn south(&self) -> Self { - self.south_by(1) - } - - pub fn south_by(&self, count: i32) -> Self { - Self { - x: self.x, - y: self.y, - z: self.z + count, - } - } - - pub fn west(&self) -> Self { - self.west_by(1) - } - - pub fn west_by(&self, count: i32) -> Self { - Self { - x: self.x - count, - y: self.y, - z: self.z, - } - } - - pub fn east(&self) -> Self { - self.east_by(1) - } - - pub fn east_by(&self, count: i32) -> Self { - Self { - x: self.x + count, - y: self.y, - z: self.z, - } - } -} - -impl Add for BlockPos { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, - z: self.z + rhs.z, - } - } -} - -pub enum HeightMapType { - WorldGenSurface, - WorldSurface, - WorldGenOceanFloor, - OceanFloor, - MotionBlocking, - MotionBlockingNoLeaves, -} - -pub struct VoxelShape {} - -impl VoxelShape { - pub fn is_empty(&self) -> bool { - unimplemented!() - } -} - -pub struct BlockState {} - -impl BlockState { - pub fn block(&self) -> BlockId { - unimplemented!() - } - - pub fn is_air(&self) -> bool { - unimplemented!() - } - - pub fn has_tag(&self, tag: &str) -> bool { - unimplemented!() - } - - pub fn is_block(&self, id: BlockId) -> bool { - unimplemented!() - } - - pub fn collision_shape(&self, chunk: &Chunk, pos: &BlockPos) -> VoxelShape { - unimplemented!() - } -} - -pub const CHUNK_MARKER: u64 = ChunkPos { - x: 1875066, - z: 1875066, -} -.to_long(); - -pub struct ChunkPos { - x: i32, - z: i32, -} - -impl ChunkPos { - pub const fn new(x: i32, z: i32) -> Self { - Self { x, z } - } - - pub const fn to_long(&self) -> u64 { - (self.x as u64 & 4294967295u64) | ((self.z as u64 & 4294967295u64) << 32) - } - - pub fn packed_x(pos: u64) -> i32 { - (pos & 4294967295u64) as i32 - } - - pub fn packed_z(pos: u64) -> i32 { - (pos.unsigned_shr(32) & 4294967295u64) as i32 - } - - pub fn get_start_x(&self) -> i32 { - self.x << 4 - } - - pub fn get_start_z(&self) -> i32 { - self.z << 4 - } -} - -pub struct Chunk { - pos: ChunkPos, - data: ChunkData, - state: GenerationState, -} - -impl Chunk { - pub fn get_block_state(&self, pos: &BlockPos) -> BlockState { - unimplemented!() - } - - pub fn sample_height_map(&self, map: HeightMapType, x: i32, y: i32) -> Option { - unimplemented!() - } - - pub fn biome_for_noise_gen(&self, biome_x: i32, biome_y: i32, biome_z: i32) -> Biome { - unimplemented!() - } - - pub fn blending_data(&self) -> Option { - unimplemented!() - } - - pub fn status(&self) -> GenerationState { - self.state.clone() - } - - pub fn get_or_create_noise_sampler(&self) -> Arc> { - unimplemented!() - } - - pub fn get_height_map(&self, map: HeightMapType) -> &HeightMap { - unimplemented!() - } - - pub fn pos(&self) -> &ChunkPos { - &self.pos - } -} - -impl HeightLimitViewImpl for Chunk { - fn bottom_y(&self) -> i32 { - unimplemented!() - } - - fn height(&self) -> i32 { - unimplemented!() - } -} - -#[derive(Clone)] -pub struct GenerationShapeConfig { - y_min: i32, - height: i32, - horizontal: i32, - vertical: i32, -} - -//Bits avaliable to encode y-pos -pub const SIZE_BITS_Y: i32 = 12; -pub const MAX_HEIGHT: i32 = (1 << SIZE_BITS_Y) - 32; -pub const MAX_COLUMN_HEIGHT: i32 = (MAX_HEIGHT >> 1) - 1; -pub const MIN_HEIGHT: i32 = MAX_COLUMN_HEIGHT - MAX_HEIGHT + 1; - -impl GenerationShapeConfig { - fn new(y_min: i32, height: i32, horizontal: i32, vertical: i32) -> Self { - if (y_min + height) > (MAX_COLUMN_HEIGHT + 1) { - panic!("Cannot be higher than max column height"); - } else if height % 16 != 0 { - panic!("Height must be a multiple of 16"); - } else if y_min % 16 != 0 { - panic!("Y min must be a multiple of 16"); - } - Self { - y_min, - height, - horizontal, - vertical, - } - } - - pub fn trim_height(&self, view: &impl HeightLimitViewImpl) -> Self { - let i = self.y_min.max(view.bottom_y()); - let j = (self.y_min + self.height).min(view.top_y()) - i; - Self { - y_min: i, - height: j, - horizontal: self.horizontal, - vertical: self.vertical, - } - } - - pub fn min_y(&self) -> i32 { - self.y_min - } - - pub fn height(&self) -> i32 { - self.height - } - - pub fn vertical_cell_block_count(&self) -> i32 { - biome_coords::to_block(self.vertical) - } - - pub fn horizontal_cell_block_count(&self) -> i32 { - biome_coords::to_block(self.horizontal) - } -} - -pub mod shape_configs { - use super::GenerationShapeConfig; - - pub const surface_config: GenerationShapeConfig = GenerationShapeConfig { - y_min: -64, - height: 384, - horizontal: 1, - vertical: 2, - }; -} diff --git a/pumpkin-world/src/height.rs b/pumpkin-world/src/world_gen/height_limit.rs similarity index 96% rename from pumpkin-world/src/height.rs rename to pumpkin-world/src/world_gen/height_limit.rs index 1effb518e..beb4dd043 100644 --- a/pumpkin-world/src/height.rs +++ b/pumpkin-world/src/world_gen/height_limit.rs @@ -1,11 +1,8 @@ use enum_dispatch::enum_dispatch; -use crate::world_gen::chunk::Chunk; - #[enum_dispatch] pub enum HeightLimitView { Standard(StandardHeightLimitView), - Chunk(Chunk), } #[enum_dispatch(HeightLimitView)] diff --git a/pumpkin-world/src/world_gen/heightmap.rs b/pumpkin-world/src/world_gen/heightmap.rs deleted file mode 100644 index 02e994ef5..000000000 --- a/pumpkin-world/src/world_gen/heightmap.rs +++ /dev/null @@ -1 +0,0 @@ -pub enum HeightMap {} diff --git a/pumpkin-world/src/world_gen/implementation/aquifer.rs b/pumpkin-world/src/world_gen/implementation/aquifer.rs deleted file mode 100644 index 84a0357ab..000000000 --- a/pumpkin-world/src/world_gen/implementation/aquifer.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::{self as pumpkin_world, world_gen::noise::density::NoisePosImpl}; -use enum_dispatch::enum_dispatch; -use pumpkin_macros::block_id; - -use crate::block::BlockId; - -#[derive(Clone)] -struct FluidLevel { - y: i32, - state: BlockId, -} - -impl FluidLevel { - fn get_block(&self, y: i32) -> BlockId { - if y < self.y { - self.state - } else { - block_id!("minecraft:air") - } - } -} - -#[derive(Clone)] -pub struct FluidLevelSampler { - sea_level: i32, - fluid_level_1: FluidLevel, - fluid_level_2: FluidLevel, -} - -impl FluidLevelSampler { - fn get_fluid_level(&self, _x: i32, y: i32, _z: i32) -> FluidLevel { - if y < (-51).min(self.sea_level) { - self.fluid_level_1.clone() - } else { - self.fluid_level_2.clone() - } - } -} - -#[enum_dispatch(AquiferSamplerImpl)] -pub enum AquifierSampler { - SeaLevel(AquiferSeaLevel), -} - -#[enum_dispatch] -pub trait AquiferSamplerImpl { - fn apply(&self, pos: &impl NoisePosImpl, density: f64) -> Option; -} - -pub struct AquiferSeaLevel { - level_sampler: FluidLevelSampler, -} - -impl AquiferSeaLevel { - pub fn new(level_sampler: FluidLevelSampler) -> Self { - Self { level_sampler } - } -} - -impl AquiferSamplerImpl for AquiferSeaLevel { - fn apply(&self, pos: &impl NoisePosImpl, density: f64) -> Option { - if density > 0f64 { - None - } else { - Some( - self.level_sampler - .get_fluid_level(pos.x(), pos.y(), pos.z()) - .get_block(pos.y()), - ) - } - } -} diff --git a/pumpkin-world/src/world_gen/implementation/mod.rs b/pumpkin-world/src/world_gen/implementation/mod.rs index 804b134ac..7aa11a83b 100644 --- a/pumpkin-world/src/world_gen/implementation/mod.rs +++ b/pumpkin-world/src/world_gen/implementation/mod.rs @@ -1,58 +1,2 @@ -use crate::height::HeightLimitViewImpl; - -use super::{ - blender::Blender, - chunk::{Chunk, GenerationShapeConfig, HeightMapType}, - noise::config::NoiseConfig, -}; - -pub mod aquifer; pub mod overworld; pub mod superflat; -mod surface_builder; - -pub fn populate_noise( - chunk: &mut Chunk, - blender: &Blender, - config: &NoiseConfig, - shape: &GenerationShapeConfig, -) { - let shape = shape.trim_height(chunk); - let i = shape.min_y(); - let j = i / shape.vertical_cell_block_count(); - let k = shape.height() / shape.vertical_cell_block_count(); - - internal_populate_noise(chunk, blender, config, j, k); -} - -fn internal_populate_noise( - chunk: &mut Chunk, - blender: &Blender, - config: &NoiseConfig, - min_cell_y: i32, - cell_height: i32, -) { - let sampler = chunk.get_or_create_noise_sampler(); - let height_map = chunk.get_height_map(HeightMapType::WorldGenOceanFloor); - let height_map2 = chunk.get_height_map(HeightMapType::WorldGenSurface); - let pos = chunk.pos(); - - let i = pos.get_start_x(); - let j = pos.get_start_z(); - - let mut sampler = sampler.lock(); - sampler.sample_start_density(); - - let k = sampler.horizontal_cell_block_count(); - let l = sampler.vertical_cell_block_count(); - let m = 16 / k; - let n = 16 / k; - - for o in 0..m { - sampler.sample_end_density(o); - - for p in 0..n { - let q = chunk.vertical_section_count() - 1; - } - } -} diff --git a/pumpkin-world/src/world_gen/implementation/overworld/mod.rs b/pumpkin-world/src/world_gen/implementation/overworld/mod.rs index f96d401f1..f1af41c40 100644 --- a/pumpkin-world/src/world_gen/implementation/overworld/mod.rs +++ b/pumpkin-world/src/world_gen/implementation/overworld/mod.rs @@ -1,2 +1 @@ pub mod biome; -pub mod terrain_params; diff --git a/pumpkin-world/src/world_gen/implementation/surface_builder.rs b/pumpkin-world/src/world_gen/implementation/surface_builder.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/pumpkin-world/src/world_gen/mod.rs b/pumpkin-world/src/world_gen/mod.rs index 5a0aca08a..fbf0490ac 100644 --- a/pumpkin-world/src/world_gen/mod.rs +++ b/pumpkin-world/src/world_gen/mod.rs @@ -1,13 +1,15 @@ +#![allow(dead_code)] + mod blender; -pub mod chunk; mod generator; mod generic_generator; -mod heightmap; +pub mod height_limit; mod implementation; mod noise; -pub mod sampler; +mod positions; +mod proto_chunk; +mod sampler; mod seed; -mod supplier; pub use generator::WorldGenerator; use implementation::overworld::biome::plains::PlainsGenerator; diff --git a/pumpkin-world/src/world_gen/noise/chunk_sampler.rs b/pumpkin-world/src/world_gen/noise/chunk_sampler.rs deleted file mode 100644 index 6c3ed9107..000000000 --- a/pumpkin-world/src/world_gen/noise/chunk_sampler.rs +++ /dev/null @@ -1,1119 +0,0 @@ -use core::panic; -use std::{ - borrow::{Borrow, BorrowMut}, - cell::{Cell, RefCell}, - collections::HashMap, - default, - ops::DerefMut, - rc::Rc, - sync::{Arc, LazyLock}, -}; - -use enum_dispatch::enum_dispatch; -use itertools::Itertools; -use parking_lot::Mutex; - -use crate::{ - block::BlockId, - world_gen::{ - biome_coords, - blender::{BlendResult, Blender, BlenderImpl}, - chunk::{Chunk, ChunkPos, GenerationShapeConfig, CHUNK_MARKER}, - implementation::aquifer::{ - self, AquiferSamplerImpl, AquiferSeaLevel, AquifierSampler, FluidLevelSampler, - }, - noise::lerp3, - sampler, - }, -}; - -use super::{ - config::NoiseConfig, - density::{ - blend::{BlendAlphaFunction, BlendOffsetFunction}, - Applier, ApplierImpl, BeardifyerFunction, DensityFunction, DensityFunctionImpl, NoisePos, - NoisePosImpl, UnblendedNoisePos, Visitor, VisitorImpl, WrapperFunction, WrapperType, - }, - lerp, - router::NoiseRouter, -}; - -pub(crate) struct InterpolationApplier<'a> { - parent_sampler: Arc>>, -} - -impl<'a> ApplierImpl<'a> for InterpolationApplier<'a> { - fn at(&self, index: usize) -> NoisePos<'a> { - let index = index as i32; - let mut sampler = self.parent_sampler.lock(); - sampler.start_block_y = - (index + sampler.minimum_cell_y) * sampler.vertical_cell_block_count; - sampler.sample_unique += 1; - sampler.cell_block_y = 0; - sampler.index = index; - - NoisePos::ChunkNoise(ChunkNoiseSamplerWrapper { - parent_sampler: self.parent_sampler.clone(), - }) - } - - fn fill(&self, densities: &mut [f64], function: &DensityFunction<'a>) { - let mut sampler = self.parent_sampler.lock(); - - for i in 0..=sampler.vertical_cell_count { - sampler.start_block_y = - (i + sampler.minimum_cell_y) * sampler.vertical_cell_block_count; - sampler.sample_unique += 1; - sampler.cell_block_y = 0; - sampler.index = i; - - drop(sampler); - let sample = function.sample(&NoisePos::ChunkNoise(ChunkNoiseSamplerWrapper { - parent_sampler: self.parent_sampler.clone(), - })); - sampler = self.parent_sampler.lock(); - densities[sampler.index as usize] = sample; - } - } -} - -#[derive(Clone)] -pub(crate) struct BlendOffsetDensityFunction<'a> { - parent_sampler: Arc>>, -} - -impl<'a> DensityFunctionImpl<'a> for BlendOffsetDensityFunction<'a> { - fn sample(&self, pos: &NoisePos) -> f64 { - let mut sampler = self.parent_sampler.lock(); - sampler.calculate_blend_result(pos.x(), pos.z()).offset() - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - applier.fill( - densities, - &DensityFunction::ChunkCacheBlendOffset(self.clone()), - ) - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - DensityFunction::BlendOffset(BlendOffsetFunction {}).apply(visitor) - } - - fn max(&self) -> f64 { - f64::INFINITY - } - - fn min(&self) -> f64 { - f64::NEG_INFINITY - } -} - -#[derive(Clone)] -pub(crate) struct BlendAlphaDensityFunction<'a> { - parent_sampler: Arc>>, -} - -impl<'a> DensityFunctionImpl<'a> for BlendAlphaDensityFunction<'a> { - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - DensityFunction::BlendAlpha(BlendAlphaFunction {}).apply(visitor) - } - - fn sample(&self, pos: &NoisePos) -> f64 { - let mut sampler = self.parent_sampler.lock(); - sampler.calculate_blend_result(pos.x(), pos.z()).alpha() - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - applier.fill( - densities, - &DensityFunction::ChunkCacheBlendAlpha(self.clone()), - ) - } - - fn min(&self) -> f64 { - 0f64 - } - - fn max(&self) -> f64 { - 1f64 - } -} - -#[derive(Clone)] -pub(crate) struct InterpolatorDensityFunctionWrapper<'a> { - wrapped: Arc>>, -} - -impl<'a> DensityFunctionImpl<'a> for InterpolatorDensityFunctionWrapper<'a> { - fn sample(&self, pos: &NoisePos) -> f64 { - self.wrapped.lock().sample(pos) - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - self.wrapped.lock().fill(densities, applier) - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - self.wrapped.lock().apply(visitor) - } - - fn min(&self) -> f64 { - self.wrapped.lock().min() - } - - fn max(&self) -> f64 { - self.wrapped.lock().max() - } -} - -#[derive(Clone)] -struct InterpolatorDensityFunction<'a> { - parent_sampler: Arc>>, - start_buffer: Vec>, - end_buffer: Vec>, - delegate: Arc>, - x0y0z0: f64, - x0y0z1: f64, - x1y0z0: f64, - x1y0z1: f64, - x0y1z0: f64, - x0y1z1: f64, - x1y1z0: f64, - x1y1z1: f64, - x0z0: f64, - x1z0: f64, - x0z1: f64, - x1z1: f64, - z0: f64, - z1: f64, - result: f64, -} - -impl<'a> InterpolatorDensityFunction<'a> { - fn new( - parent_sampler: Arc>>, - delegate: Arc>, - vertical_cell_count: i32, - horizontal_cell_count: i32, - ) -> InterpolatorDensityFunctionWrapper<'a> { - let result = Arc::new(Mutex::new(Self { - parent_sampler: parent_sampler.clone(), - start_buffer: Self::create_buffer(vertical_cell_count, horizontal_cell_count), - end_buffer: Self::create_buffer(vertical_cell_count, horizontal_cell_count), - delegate, - x0y0z0: 0f64, - x0y0z1: 0f64, - x1y0z0: 0f64, - x1y0z1: 0f64, - x0y1z0: 0f64, - x0y1z1: 0f64, - x1y1z0: 0f64, - x1y1z1: 0f64, - x0z0: 0f64, - x1z0: 0f64, - x0z1: 0f64, - x1z1: 0f64, - z0: 0f64, - z1: 0f64, - result: 0f64, - })); - let wrapper = InterpolatorDensityFunctionWrapper { wrapped: result }; - - let mut sampler = parent_sampler.lock(); - sampler.interpolators.push(wrapper.clone()); - wrapper - } - - fn on_sampled_cell_corners(&mut self, cell_y: usize, cell_z: usize) { - self.x0y0z0 = self.start_buffer[cell_z][cell_y]; - self.x0y0z1 = self.start_buffer[cell_z + 1][cell_y]; - self.x1y0z0 = self.end_buffer[cell_z][cell_y]; - self.x1y0z1 = self.end_buffer[cell_z + 1][cell_y]; - self.x0y1z0 = self.start_buffer[cell_z][cell_y + 1]; - self.x0y1z1 = self.start_buffer[cell_z + 1][cell_y + 1]; - self.x1y1z0 = self.end_buffer[cell_z][cell_y + 1]; - self.x1y1z1 = self.end_buffer[cell_z + 1][cell_y + 1]; - } - - fn interpolate_y(&mut self, delta: f64) { - self.x0z0 = lerp(delta, self.x0y0z0, self.x0y1z0); - self.x1z0 = lerp(delta, self.x1y0z0, self.x1y1z0); - self.x0z1 = lerp(delta, self.x0y0z1, self.x0y1z1); - self.x1z1 = lerp(delta, self.x1y0z1, self.x1y1z1); - } - - fn interpolate_x(&mut self, delta: f64) { - self.z0 = lerp(delta, self.x0z0, self.x1z0); - self.z1 = lerp(delta, self.x0z1, self.x1z1); - } - - fn interpolate_z(&mut self, delta: f64) { - self.result = lerp(delta, self.z0, self.z1); - } - - fn swap_buffers(&mut self) { - let ds = self.start_buffer.clone(); - self.start_buffer = self.end_buffer.clone(); - self.start_buffer = ds; - } - - fn create_buffer(size_z: i32, size_x: i32) -> Vec> { - let i = size_x + 1; - let j = size_z + 1; - - let mut result = Vec::>::new(); - for _ in 0..i { - result.push((0..j).map(|_| 0f64).collect()) - } - - result - } -} - -impl<'a> DensityFunctionImpl<'a> for InterpolatorDensityFunction<'a> { - fn sample(&self, pos: &super::density::NoisePos) -> f64 { - if let NoisePos::ChunkNoise(sampler) = pos { - let other_lock = { sampler.parent_sampler.lock().uuid }; - - let my_lock = { self.parent_sampler.lock().uuid }; - - if other_lock == my_lock { - return self.delegate.sample(pos); - } - } - - let sampler = self.parent_sampler.lock(); - assert!(sampler.interpolating, "Not interpolating"); - if sampler.sampling_for_caches { - lerp3( - sampler.cell_block_x as f64 / sampler.horizontal_cell_block_count as f64, - sampler.cell_block_y as f64 / sampler.vertical_cell_block_count as f64, - sampler.cell_block_z as f64 / sampler.horizontal_cell_block_count as f64, - self.x0y0z0, - self.x1y0z0, - self.x0y1z0, - self.x1y1z0, - self.x0y0z1, - self.x1y0z1, - self.x0y1z1, - self.x1y1z1, - ) - } else { - self.result - } - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - visitor.apply(Arc::new(DensityFunction::Wrapper(WrapperFunction::new( - self.delegate.clone(), - WrapperType::Interpolated, - )))) - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - let sampling = { self.parent_sampler.lock().sampling_for_caches }; - if sampling { - applier.fill( - densities, - &DensityFunction::ChunkCacheInterpolator(InterpolatorDensityFunctionWrapper { - wrapped: Arc::new(Mutex::new(self.clone())), - }), - ) - } else { - self.delegate.fill(densities, applier); - } - } - - fn min(&self) -> f64 { - self.delegate.min() - } - - fn max(&self) -> f64 { - self.delegate.max() - } -} - -#[derive(Clone)] -pub(crate) struct FlatCacheDensityFunction<'a> { - parent_sampler: Arc>>, - delegate: Arc>, - cache: Vec>, -} - -impl<'a> FlatCacheDensityFunction<'a> { - fn new( - parent_sampler: Arc>>, - delegate: Arc>, - biome_start_x: i32, - biome_start_z: i32, - horizontal_biome_end: usize, - sample: bool, - ) -> Self { - let mut cache: Vec> = Vec::new(); - for _ in 0..(horizontal_biome_end + 1) { - cache.push((0..(horizontal_biome_end + 1)).map(|_| 0f64).collect()) - } - - if sample { - for i in 0..=horizontal_biome_end { - let j = biome_start_x + i as i32; - let k = biome_coords::to_block(j); - - for l in 0..=horizontal_biome_end { - let m = biome_start_z + l as i32; - let n = biome_coords::to_block(m); - cache[i][l] = - delegate.sample(&NoisePos::Unblended(UnblendedNoisePos::new(k, 0, n))); - } - } - } - - Self { - parent_sampler, - delegate, - cache, - } - } -} - -impl<'a> DensityFunctionImpl<'a> for FlatCacheDensityFunction<'a> { - fn sample(&self, pos: &NoisePos) -> f64 { - let i = biome_coords::from_block(pos.x()); - let j = biome_coords::from_block(pos.z()); - let (start_biome_x, start_biome_z) = { - let sampler = self.parent_sampler.lock(); - (sampler.start_biome_x, sampler.start_biome_z) - }; - let k = i - start_biome_x; - let l = j - start_biome_z; - if k >= 0 && l >= 0 && (k as usize) < self.cache.len() && (l as usize) < self.cache.len() { - self.cache[k as usize][l as usize] - } else { - self.delegate.sample(pos) - } - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - applier.fill( - densities, - &DensityFunction::ChunkCacheFlatCache(self.clone()), - ); - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - visitor.apply(Arc::new(DensityFunction::Wrapper(WrapperFunction::new( - self.delegate.apply(visitor), - WrapperType::CacheFlat, - )))) - } - - fn min(&self) -> f64 { - self.delegate.min() - } - - fn max(&self) -> f64 { - self.delegate.max() - } -} - -#[derive(Clone)] -pub(crate) struct CellCacheDensityFunctionWrapper<'a> { - wrapped: Arc>, -} - -impl<'a> DensityFunctionImpl<'a> for CellCacheDensityFunctionWrapper<'a> { - fn sample(&self, pos: &NoisePos) -> f64 { - self.wrapped.sample(pos) - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - applier.fill( - densities, - &DensityFunction::ChunkCacheCellCache(self.clone()), - ); - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - self.wrapped.apply(visitor) - } - - fn min(&self) -> f64 { - self.wrapped.min() - } - - fn max(&self) -> f64 { - self.wrapped.max() - } -} - -#[derive(Clone)] -struct CellCacheDensityFunction<'a> { - parent_sampler: Arc>>, - delegate: Arc>, - cache: Vec, -} - -impl<'a> CellCacheDensityFunction<'a> { - fn new( - parent_sampler: Arc>>, - delegate: Arc>, - ) -> CellCacheDensityFunctionWrapper<'a> { - let cache_size = { - let sampler = parent_sampler.lock(); - sampler.horizontal_cell_block_count - * sampler.horizontal_cell_block_count - * sampler.vertical_cell_block_count - }; - let result = Arc::new(Self { - parent_sampler: parent_sampler.clone(), - delegate, - cache: (0..cache_size).map(|_| 0f64).collect(), - }); - - let wrapped = CellCacheDensityFunctionWrapper { wrapped: result }; - let mut sampler = parent_sampler.lock(); - sampler.caches.push(wrapped.clone()); - - wrapped - } -} - -impl<'a> DensityFunctionImpl<'a> for CellCacheDensityFunction<'a> { - fn sample(&self, pos: &NoisePos) -> f64 { - if let NoisePos::ChunkNoise(sampler) = pos { - let other_lock = { sampler.parent_sampler.lock().uuid }; - - let my_lock = { self.parent_sampler.lock().uuid }; - - if other_lock == my_lock { - return self.delegate.sample(pos); - } - } - - let sampler = self.parent_sampler.lock(); - assert!(sampler.interpolating); - let i = sampler.cell_block_x; - let j = sampler.cell_block_y; - let k = sampler.cell_block_z; - - if i >= 0 - && k >= 0 - && i < sampler.horizontal_cell_block_count - && j < sampler.vertical_cell_block_count - && k < sampler.horizontal_cell_block_count - { - self.cache[(((sampler.vertical_cell_block_count - 1 - j) - * sampler.horizontal_cell_block_count - + i) - * sampler.horizontal_cell_block_count - + k) as usize] - } else { - self.delegate.sample(pos) - } - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) {} - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - visitor.apply(Arc::new(DensityFunction::Wrapper(WrapperFunction::new( - self.delegate.apply(visitor), - WrapperType::CacheCell, - )))) - } - - fn min(&self) -> f64 { - self.delegate.min() - } - - fn max(&self) -> f64 { - self.delegate.max() - } -} - -struct CacheOnceDensityFunctionData { - sample_unique_index: u64, - cache_once_unique_index: u64, - last_sampling_result: f64, - cache: Option>, -} - -#[derive(Clone)] -pub(crate) struct CacheOnceDensityFunction<'a> { - parent_sampler: Arc>>, - delegate: Arc>, - data: Arc>, -} - -impl<'a> CacheOnceDensityFunction<'a> { - fn new( - parent_sampler: Arc>>, - delegate: Arc>, - ) -> Self { - Self { - parent_sampler, - delegate, - data: Arc::new(Mutex::new(CacheOnceDensityFunctionData { - sample_unique_index: 0, - cache_once_unique_index: 0, - last_sampling_result: 0f64, - cache: None, - })), - } - } -} - -impl<'a> DensityFunctionImpl<'a> for CacheOnceDensityFunction<'a> { - fn sample(&self, pos: &NoisePos) -> f64 { - let parent_sampler = self.parent_sampler.lock(); - let mut data = self.data.lock(); - - if let NoisePos::ChunkNoise(sampler) = pos { - let other_id = { sampler.parent_sampler.lock().uuid }; - let this_id = { self.parent_sampler.lock().uuid }; - if other_id != this_id { - return self.delegate.sample(pos); - } - } - - if let Some(cache) = &data.cache { - if data.cache_once_unique_index == parent_sampler.cache_unique { - return cache[parent_sampler.index as usize]; - } - } - - if data.sample_unique_index == parent_sampler.sample_unique { - data.last_sampling_result - } else { - data.sample_unique_index = parent_sampler.sample_unique; - let d = self.delegate.sample(pos); - data.last_sampling_result = d; - d - } - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - let parent_sampler = self.parent_sampler.lock(); - let mut data = self.data.lock(); - let cache_once_unique_index = data.cache_once_unique_index; - - if let Some(cache) = &mut data.cache { - if parent_sampler.cache_unique == cache_once_unique_index { - densities - .iter_mut() - .zip_eq(cache) - .for_each(|(val, temp)| *val = *temp); - return; - } - } - - self.delegate.fill(densities, applier); - data.cache_once_unique_index = parent_sampler.cache_unique; - if let Some(cache) = &mut data.cache { - if cache.len() == densities.len() { - cache - .iter_mut() - .zip_eq(densities) - .for_each(|(val, temp)| *val = *temp); - return; - } - } - data.cache = Some(Vec::from_iter(densities.iter().map(|x| *x))); - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - visitor.apply(Arc::new(DensityFunction::Wrapper(WrapperFunction::new( - self.delegate.apply(visitor), - WrapperType::CacheOnce, - )))) - } - - fn max(&self) -> f64 { - self.delegate.max() - } - - fn min(&self) -> f64 { - self.delegate.min() - } -} - -struct Cache2DDensityFunctionData { - last_sampling_column_pos: u64, - last_sampling_result: f64, -} - -#[derive(Clone)] -pub(crate) struct Cache2DDensityFunction<'a> { - delegate: Arc>, - data: Arc>, -} - -impl<'a> Cache2DDensityFunction<'a> { - fn new(delegate: Arc>) -> Self { - Self { - delegate, - data: Arc::new(Mutex::new(Cache2DDensityFunctionData { - last_sampling_column_pos: CHUNK_MARKER, - last_sampling_result: 0f64, - })), - } - } -} - -impl<'a> DensityFunctionImpl<'a> for Cache2DDensityFunction<'a> { - fn sample(&self, pos: &NoisePos) -> f64 { - let i = pos.x(); - let j = pos.z(); - let l = ChunkPos::new(i, j).to_long(); - let mut data = self.data.lock(); - if data.last_sampling_column_pos == l { - data.last_sampling_result - } else { - data.last_sampling_column_pos = l; - drop(data); - let d = self.delegate.sample(pos); - let mut data = self.data.lock(); - data.last_sampling_result = d; - d - } - } - - fn fill(&self, densities: &mut [f64], applier: &Applier<'a>) { - self.delegate.fill(densities, applier) - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - visitor.apply(Arc::new(DensityFunction::Wrapper(WrapperFunction::new( - self.delegate.clone(), - WrapperType::Cache2D, - )))) - } - - fn min(&self) -> f64 { - self.delegate.min() - } - - fn max(&self) -> f64 { - self.delegate.max() - } -} - -#[enum_dispatch(BlockStateSamplerImpl)] -enum BlockStateSampler<'a> { - Aquifer(AquiferBlockStateSampler<'a>), -} - -struct AquiferBlockStateSampler<'a> { - aquifier: Arc, - function: Arc>, -} - -impl<'a> BlockStateSamplerImpl for AquiferBlockStateSampler<'a> { - fn sample(&self, pos: &NoisePos) -> Option { - self.aquifier.apply(pos, self.function.sample(pos)) - } -} - -#[enum_dispatch] -trait BlockStateSamplerImpl { - fn sample(&self, pos: &NoisePos) -> Option; -} - -static SAMPLER_ID_COUNTER: LazyLock>> = LazyLock::new(|| Arc::new(Mutex::new(0u64))); - -pub(crate) struct ChunkSamplerDensityFunctionConverter<'a> { - parent_sampler: Arc>>, -} - -impl<'a> VisitorImpl<'a> for ChunkSamplerDensityFunctionConverter<'a> { - fn apply(&self, function: Arc>) -> Arc> { - let sampler = self.parent_sampler.lock(); - let vertical_cell_count = sampler.vertical_cell_count; - let horizontal_cell_count = sampler.horizontal_cell_count; - - let biome_start_x = sampler.start_biome_x; - let biome_start_z = sampler.start_biome_z; - let horizontal_biome_end = sampler.horizontal_biome_end as usize; - - let blender = sampler.blender; - - if let DensityFunction::Wrapper(wrapped) = function.as_ref() { - match wrapped.wrapper() { - WrapperType::Interpolated => Arc::new(DensityFunction::ChunkCacheInterpolator( - InterpolatorDensityFunction::new( - self.parent_sampler.clone(), - wrapped.wrapped(), - vertical_cell_count, - horizontal_cell_count, - ), - )), - WrapperType::Cache2D => Arc::new(DensityFunction::ChunkCache2DCache( - Cache2DDensityFunction::new(wrapped.wrapped()), - )), - WrapperType::CacheFlat => Arc::new(DensityFunction::ChunkCacheFlatCache( - FlatCacheDensityFunction::new( - self.parent_sampler.clone(), - wrapped.wrapped(), - biome_start_x, - biome_start_z, - horizontal_biome_end, - true, - ), - )), - WrapperType::CacheOnce => Arc::new(DensityFunction::ChunkCacheOnceCache( - CacheOnceDensityFunction::new(self.parent_sampler.clone(), wrapped.wrapped()), - )), - WrapperType::CacheCell => Arc::new(DensityFunction::ChunkCacheCellCache( - CellCacheDensityFunction::new(self.parent_sampler.clone(), wrapped.wrapped()), - )), - } - } else if let Blender::None(_) = blender { - if let DensityFunction::BlendAlpha(_) = function.as_ref() { - let alpha_cache = { - sampler - .self_referential - .as_ref() - .unwrap() - .cached_blend_alpha_density_function - .clone() - }; - Arc::new(DensityFunction::ChunkCacheFlatCache(alpha_cache)) - } else if let DensityFunction::BlendOffset(_) = function.as_ref() { - let offset_cache = { - sampler - .self_referential - .as_ref() - .unwrap() - .cached_blend_offset_density_function - .clone() - }; - Arc::new(DensityFunction::ChunkCacheFlatCache(offset_cache)) - } else { - function - } - } else { - function - } - } -} - -struct ChunkNoiseSamplerSelfReferential<'a> { - cached_blend_alpha_density_function: FlatCacheDensityFunction<'a>, - cached_blend_offset_density_function: FlatCacheDensityFunction<'a>, - block_state_sampler: BlockStateSampler<'a>, - initial_density: Arc>, - aquifer_sampler: Arc, - interpolation_applier: Applier<'a>, -} - -pub struct ChunkNoiseSampler<'a> { - shape_config: GenerationShapeConfig, - horizontal_cell_count: i32, - vertical_cell_count: i32, - minimum_cell_y: i32, - start_cell_x: i32, - start_cell_z: i32, - start_biome_x: i32, - start_biome_z: i32, - interpolators: Vec>, - caches: Vec>, - surface_height_estimate_cache: HashMap, - blender: &'a Blender, - last_blended_column_pos: u64, - last_blending_result: BlendResult, - horizontal_biome_end: i32, - horizontal_cell_block_count: i32, - vertical_cell_block_count: i32, - interpolating: bool, - sampling_for_caches: bool, - start_block_x: i32, - start_block_y: i32, - start_block_z: i32, - cell_block_x: i32, - cell_block_y: i32, - cell_block_z: i32, - sample_unique: u64, - cache_unique: u64, - index: i32, - uuid: u64, - visitor: Option>>, - self_referential: Option>, -} - -impl<'a> ChunkNoiseSampler<'a> { - pub fn horizontal_cell_block_count(&self) -> i32 { - self.horizontal_cell_block_count - } - - pub fn vertical_cell_block_count(&self) -> i32 { - self.vertical_cell_block_count - } - - pub fn sample_start_density(&mut self) { - if self.interpolating { - panic!("interpolating twice"); - } - - self.interpolating = true; - self.sample_unique = 0; - self.sample_density(true, self.start_cell_x); - } - - pub fn sample_end_density(&mut self, cell_x: i32) { - self.sample_density(false, self.start_cell_x + cell_x + 1); - self.start_block_x = (self.start_cell_x * cell_x) * self.horizontal_cell_block_count - } - - fn sample_density(&mut self, start: bool, cell_x: i32) { - self.start_block_x = cell_x * self.horizontal_cell_block_count; - self.cell_block_x = 0; - - for i in 0..=self.horizontal_cell_count { - let j = self.start_cell_z + i; - self.start_cell_z = j * self.horizontal_cell_block_count; - self.cell_block_z = 0; - self.cache_unique += 1; - - for interpolator in self.interpolators.iter() { - let mut wrapped = interpolator.wrapped.lock(); - let ds = &mut (if start { - &mut wrapped.start_buffer - } else { - &mut wrapped.end_buffer - })[i as usize]; - - interpolator.fill( - ds, - &self - .self_referential - .as_ref() - .expect("call .init()") - .interpolation_applier, - ); - } - } - - self.cache_unique += 1; - } - - fn init_visitor(me: Arc>>) { - let visitor = Visitor::ChunkSampler(ChunkSamplerDensityFunctionConverter { - parent_sampler: me.clone(), - }); - - let mut sampler = me.lock(); - sampler.visitor = Some(Arc::new(visitor)) - } - - fn init( - parent_sampler: Arc>>, - noise_router: &'a NoiseRouter<'a>, - fluid_level: FluidLevelSampler, - visitor: &Visitor<'a>, - ) { - let sampler = parent_sampler.lock(); - - let mut cached_blend_alpha_density_function = FlatCacheDensityFunction::new( - parent_sampler.clone(), - Arc::new(DensityFunction::ChunkCacheBlendAlpha( - BlendAlphaDensityFunction { - parent_sampler: parent_sampler.clone(), - }, - )), - sampler.start_biome_x, - sampler.start_biome_z, - sampler.horizontal_biome_end as usize, - false, - ); - - let mut cached_blend_offset_density_function = FlatCacheDensityFunction::new( - parent_sampler.clone(), - Arc::new(DensityFunction::ChunkCacheBlendOffset( - BlendOffsetDensityFunction { - parent_sampler: parent_sampler.clone(), - }, - )), - sampler.start_biome_x, - sampler.start_biome_z, - sampler.horizontal_biome_end as usize, - false, - ); - - for i in 0..=(sampler.horizontal_biome_end as usize) { - let j = sampler.start_biome_x + (i as i32); - let k = biome_coords::to_block(j); - for l in 0..=(sampler.horizontal_biome_end as usize) { - let m = sampler.start_biome_z + (l as i32); - let n = biome_coords::to_block(m); - let result = sampler.blender.calculate(k, n); - cached_blend_alpha_density_function.cache[i][l] = result.alpha(); - cached_blend_offset_density_function.cache[i][l] = result.offset(); - } - } - - let new_router = noise_router.apply(visitor); - let aquifer = Arc::new(AquifierSampler::SeaLevel(AquiferSeaLevel::new(fluid_level))); - let final_density = new_router - .final_densitiy - .add(Arc::new(DensityFunction::Beardifyer(BeardifyerFunction {}))); - - let function = DensityFunction::Wrapper(WrapperFunction::new( - Arc::new(final_density), - WrapperType::CacheCell, - )); - - let block_sampler = BlockStateSampler::Aquifer(AquiferBlockStateSampler { - aquifier: aquifer.clone(), - function: function.apply(visitor), - }); - - let self_referring = ChunkNoiseSamplerSelfReferential { - cached_blend_alpha_density_function, - cached_blend_offset_density_function, - aquifer_sampler: aquifer, - block_state_sampler: block_sampler, - initial_density: new_router.internal_density.clone(), - interpolation_applier: Applier::Interpolation(InterpolationApplier { - parent_sampler: parent_sampler.clone(), - }), - }; - let mut sampler = parent_sampler.lock(); - sampler.self_referential = Some(self_referring); - } - - fn new( - horizontal_cell_count: i32, - start_block_x: i32, - start_block_z: i32, - shape: &GenerationShapeConfig, - blender: &'a Blender, - ) -> Self { - let shape_config = shape.clone(); - let horizontal_cell_block_count = shape_config.horizontal_cell_block_count(); - let vertical_cell_block_count = shape_config.vertical_cell_block_count(); - let vertical_cell_count = shape_config.height() / vertical_cell_block_count; - let minimum_cell_y = shape_config.min_y() / vertical_cell_block_count; - let start_cell_x = start_block_x / horizontal_cell_block_count; - let start_cell_z = start_block_z / horizontal_cell_block_count; - let interpolators: Vec> = Vec::new(); - let caches: Vec> = Vec::new(); - let start_biome_x = biome_coords::from_block(start_block_x); - let start_biome_z = biome_coords::from_block(start_block_z); - let horizontal_biome_end = - biome_coords::from_block(horizontal_cell_count * horizontal_cell_block_count); - - let new_id = { - let mut id = SAMPLER_ID_COUNTER.lock(); - let new_id = *id; - *id += 1; - new_id - }; - - Self { - shape_config, - horizontal_cell_block_count, - vertical_cell_block_count, - horizontal_cell_count, - vertical_cell_count, - minimum_cell_y, - start_cell_x, - start_cell_z, - interpolators, - caches, - start_biome_x, - start_biome_z, - horizontal_biome_end, - blender, - surface_height_estimate_cache: HashMap::new(), - last_blending_result: BlendResult::new(1f64, 0f64), - last_blended_column_pos: CHUNK_MARKER, - interpolating: false, - sampling_for_caches: false, - start_block_z: 0, - start_block_x: 0, - start_block_y: 0, - cell_block_x: 0, - cell_block_y: 0, - cell_block_z: 0, - sample_unique: 0, - cache_unique: 0, - uuid: new_id, - index: 0, - visitor: None, - self_referential: None, - } - } - - fn calculate_blend_result(&mut self, block_x: i32, block_z: i32) -> BlendResult { - let l = ChunkPos::new(block_x, block_z).to_long(); - if l != self.last_blended_column_pos { - self.last_blended_column_pos = l; - let blend_result = self.blender.calculate(block_x, block_z); - self.last_blending_result = blend_result; - } - self.last_blending_result.clone() - } -} - -#[derive(Clone)] -pub(crate) struct ChunkNoiseSamplerWrapper<'a> { - parent_sampler: Arc>>, -} - -impl<'a> ApplierImpl<'a> for ChunkNoiseSamplerWrapper<'a> { - fn at(&self, index: usize) -> NoisePos<'a> { - let index = index as i32; - let mut sampler = self.parent_sampler.lock(); - let j = index % sampler.horizontal_cell_block_count; - let k = index % sampler.horizontal_cell_block_count; - let l = index % sampler.horizontal_cell_block_count; - let m = sampler.vertical_cell_block_count - 1 - (k / sampler.horizontal_cell_block_count); - - sampler.cell_block_x = l; - sampler.cell_block_y = m; - sampler.cell_block_z = j; - sampler.index = index; - - NoisePos::ChunkNoise(self.clone()) - } - - fn fill(&self, densities: &mut [f64], function: &DensityFunction<'a>) { - let mut sampler = self.parent_sampler.lock(); - sampler.index = 0; - for i in (0..=sampler.vertical_cell_block_count).rev() { - sampler.cell_block_y = i; - for j in 0..sampler.horizontal_cell_block_count { - sampler.cell_block_x = j; - for k in 0..sampler.horizontal_cell_block_count { - sampler.cell_block_z = k; - drop(sampler); - let sample = function.sample(&NoisePos::ChunkNoise(self.clone())); - sampler = self.parent_sampler.lock(); - densities[sampler.index as usize] = sample; - sampler.index += 1; - } - } - } - } -} - -impl<'a> NoisePosImpl for ChunkNoiseSamplerWrapper<'a> { - fn z(&self) -> i32 { - let sampler = self.parent_sampler.lock(); - sampler.start_block_z + sampler.cell_block_z - } - - fn y(&self) -> i32 { - let sampler = self.parent_sampler.lock(); - sampler.start_block_y + sampler.cell_block_y - } - - fn x(&self) -> i32 { - let sampler = self.parent_sampler.lock(); - sampler.start_block_x + sampler.cell_block_x - } - - fn get_blender(&self) -> Blender { - let sampler = self.parent_sampler.lock(); - sampler.blender.clone() - } -} diff --git a/pumpkin-world/src/world_gen/noise/config.rs b/pumpkin-world/src/world_gen/noise/config.rs deleted file mode 100644 index ab08dee04..000000000 --- a/pumpkin-world/src/world_gen/noise/config.rs +++ /dev/null @@ -1,16 +0,0 @@ -use pumpkin_core::random::RandomDeriver; - -use crate::world_gen::supplier::MultiNoiseSampler; - -use super::router::NoiseRouter; - -pub struct NoiseConfig<'a> { - random_deriver: RandomDeriver, - router: NoiseRouter<'a>, -} - -impl<'a> NoiseConfig<'a> { - pub fn noise_router(&self) -> NoiseRouter<'a> { - self.router.clone() - } -} diff --git a/pumpkin-world/src/world_gen/noise/density/blend.rs b/pumpkin-world/src/world_gen/noise/density/blend.rs index 33f17616a..952efc818 100644 --- a/pumpkin-world/src/world_gen/noise/density/blend.rs +++ b/pumpkin-world/src/world_gen/noise/density/blend.rs @@ -1,7 +1,5 @@ use std::sync::Arc; -use crate::world_gen::blender::BlenderImpl; - use super::{ Applier, ApplierImpl, DensityFunction, DensityFunctionImpl, NoisePos, NoisePosImpl, Visitor, VisitorImpl, diff --git a/pumpkin-world/src/world_gen/noise/density/mod.rs b/pumpkin-world/src/world_gen/noise/density/mod.rs index 9ea93436e..4f67aa582 100644 --- a/pumpkin-world/src/world_gen/noise/density/mod.rs +++ b/pumpkin-world/src/world_gen/noise/density/mod.rs @@ -8,28 +8,13 @@ use math::{BinaryFunction, BinaryType, LinearFunction}; use noise::{InternalNoise, InterpolatedNoiseSampler, NoiseFunction, ShiftedNoiseFunction}; use offset::{ShiftAFunction, ShiftBFunction}; use spline::SplineFunction; +use terrain_helpers::{create_factor_spline, create_jaggedness_spline, create_offset_spline}; use unary::{ClampFunction, UnaryFunction, UnaryType}; use weird::{RarityMapper, WierdScaledFunction}; -use crate::world_gen::{ - blender::{Blender, NoBlendBlender}, - chunk::{MAX_COLUMN_HEIGHT, MIN_HEIGHT}, - implementation::overworld::terrain_params::{ - create_factor_spline, create_jaggedness_spline, create_offset_spline, - }, -}; +use crate::world_gen::blender::Blender; -use super::{ - chunk_sampler::{ - BlendAlphaDensityFunction, BlendOffsetDensityFunction, Cache2DDensityFunction, - CacheOnceDensityFunction, CellCacheDensityFunctionWrapper, ChunkNoiseSamplerWrapper, - ChunkSamplerDensityFunctionConverter, FlatCacheDensityFunction, InterpolationApplier, - InterpolatorDensityFunctionWrapper, - }, - clamped_map, - perlin::DoublePerlinNoiseParameters, - BuiltInNoiseParams, -}; +use super::{clamped_map, perlin::DoublePerlinNoiseParameters, BuiltInNoiseParams}; pub mod blend; mod end; @@ -37,6 +22,7 @@ mod math; pub mod noise; mod offset; pub mod spline; +mod terrain_helpers; mod unary; mod weird; @@ -90,6 +76,12 @@ pub struct BuiltInNoiseFunctions<'a> { caves_pillars_overworld: Arc>, } +//Bits avaliable to encode y-pos +pub const SIZE_BITS_Y: i32 = 12; +pub const MAX_HEIGHT: i32 = (1 << SIZE_BITS_Y) - 32; +pub const MAX_COLUMN_HEIGHT: i32 = (MAX_HEIGHT >> 1) - 1; +pub const MIN_HEIGHT: i32 = MAX_COLUMN_HEIGHT - MAX_HEIGHT + 1; + impl<'a> BuiltInNoiseFunctions<'a> { pub fn new(built_in_noise_params: &BuiltInNoiseParams<'a>) -> Self { let blend_alpha = Arc::new(DensityFunction::BlendAlpha(BlendAlphaFunction {})); @@ -626,6 +618,7 @@ impl<'a> BuiltInNoiseFunctions<'a> { } } +#[allow(clippy::too_many_arguments)] fn sloped_cheese_function<'a>( jagged_noise: Arc>, continents: Arc>, @@ -640,13 +633,14 @@ fn sloped_cheese_function<'a>( ) -> SlopedCheeseResult<'a> { let offset = Arc::new(apply_blending( Arc::new( - DensityFunction::Spline(SplineFunction::new(Arc::new(create_offset_spline( - continents.clone(), - erosion.clone(), - ridges.clone(), - amplified, - )))) - .add_const(-0.50375f32 as f64), + DensityFunction::Constant(ConstantFunction::new(-0.50375f32 as f64)).add(Arc::new( + DensityFunction::Spline(SplineFunction::new(Arc::new(create_offset_spline( + continents.clone(), + erosion.clone(), + ridges_folded.clone(), + amplified, + )))), + )), ), blend_offset, )); @@ -734,7 +728,6 @@ fn apply_blending<'a>( function: Arc>, blend: Arc>, ) -> DensityFunction<'a> { - //let function = lerp_density(built_in_noises::BLEND_ALPHA.clone(), blend, function); let function = lerp_density( Arc::new(DensityFunction::BlendAlpha(BlendAlphaFunction {})), blend, @@ -799,14 +792,6 @@ pub enum DensityFunction<'a> { Wierd(WierdScaledFunction<'a>), Range(RangeFunction<'a>), Wrapper(WrapperFunction<'a>), - ChunkCacheFlatCache(FlatCacheDensityFunction<'a>), - ChunkCacheInterpolator(InterpolatorDensityFunctionWrapper<'a>), - ChunkCacheBlendAlpha(BlendAlphaDensityFunction<'a>), - ChunkCacheBlendOffset(BlendOffsetDensityFunction<'a>), - ChunkCacheCellCache(CellCacheDensityFunctionWrapper<'a>), - ChunkCache2DCache(Cache2DDensityFunction<'a>), - ChunkCacheOnceCache(CacheOnceDensityFunction<'a>), - Beardifyer(BeardifyerFunction), } impl<'a> DensityFunction<'a> { @@ -885,10 +870,44 @@ impl<'a> DensityFunction<'a> { } } +pub struct Unused<'a> { + _x: &'a str, +} + +impl<'a> NoisePosImpl for Unused<'a> { + fn x(&self) -> i32 { + todo!() + } + + fn y(&self) -> i32 { + todo!() + } + + fn z(&self) -> i32 { + todo!() + } +} + +impl<'a> ApplierImpl<'a> for Unused<'a> { + fn at(&self, _index: usize) -> NoisePos<'a> { + todo!() + } + + fn fill(&self, _densities: &mut [f64], _function: &DensityFunction<'a>) { + todo!() + } +} + +impl<'a> VisitorImpl<'a> for Unused<'a> { + fn apply(&self, _function: Arc>) -> Arc> { + todo!() + } +} + #[enum_dispatch(NoisePosImpl)] pub enum NoisePos<'a> { Unblended(UnblendedNoisePos), - ChunkNoise(ChunkNoiseSamplerWrapper<'a>), + Todo(Unused<'a>), } pub struct UnblendedNoisePos { @@ -924,14 +943,13 @@ pub trait NoisePosImpl { fn z(&self) -> i32; fn get_blender(&self) -> Blender { - Blender::None(NoBlendBlender {}) + unimplemented!() } } #[enum_dispatch(ApplierImpl)] pub enum Applier<'a> { - ChunkNoise(ChunkNoiseSamplerWrapper<'a>), - Interpolation(InterpolationApplier<'a>), + Todo(Unused<'a>), } #[enum_dispatch] @@ -944,7 +962,7 @@ pub trait ApplierImpl<'a> { #[enum_dispatch(VisitorImpl)] pub enum Visitor<'a> { Unwrap(UnwrapVisitor), - ChunkSampler(ChunkSamplerDensityFunctionConverter<'a>), + Todo(Unused<'a>), } pub struct UnwrapVisitor {} @@ -1134,31 +1152,6 @@ impl<'a> DensityFunctionImpl<'a> for RangeFunction<'a> { } } -#[derive(Clone)] -pub struct BeardifyerFunction {} - -impl<'a> DensityFunctionImpl<'a> for BeardifyerFunction { - fn sample(&self, _pos: &NoisePos) -> f64 { - 0f64 - } - - fn fill(&self, densities: &mut [f64], _applier: &Applier<'a>) { - densities.fill(0f64) - } - - fn min(&self) -> f64 { - 0f64 - } - - fn max(&self) -> f64 { - 0f64 - } - - fn apply(&self, visitor: &Visitor<'a>) -> Arc> { - visitor.apply(Arc::new(DensityFunction::Beardifyer(BeardifyerFunction {}))) - } -} - #[derive(Clone)] pub struct YClampedFunction { from: i32, @@ -1244,3 +1237,129 @@ pub fn lerp_density_static_start<'a>( ) -> DensityFunction<'a> { delta.mul(Arc::new(end.add_const(-start))).add_const(start) } + +#[cfg(test)] +mod test { + use crate::world_gen::noise::{density::DensityFunctionImpl, BuiltInNoiseParams}; + + use super::{BuiltInNoiseFunctions, NoisePos, UnblendedNoisePos}; + + #[test] + fn test_density_function_correctness() { + let noise_params = BuiltInNoiseParams::new(); + let noise_functions = BuiltInNoiseFunctions::new(&noise_params); + + let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 }); + + assert_eq!(noise_functions.blend_alpha.sample(&pos), 1f64); + assert_eq!(noise_functions.blend_alpha.min(), 1f64); + assert_eq!(noise_functions.blend_alpha.max(), 1f64); + + assert_eq!(noise_functions.blend_offset.sample(&pos), 0f64); + assert_eq!(noise_functions.blend_offset.min(), 0f64); + assert_eq!(noise_functions.blend_offset.max(), 0f64); + + assert_eq!(noise_functions.zero.sample(&pos), 0f64); + assert_eq!(noise_functions.zero.min(), 0f64); + assert_eq!(noise_functions.zero.max(), 0f64); + + assert_eq!(noise_functions.y.sample(&pos), 0f64); + assert_eq!(noise_functions.y.min(), -4064f64); + assert_eq!(noise_functions.y.max(), 4062f64); + + assert_eq!(noise_functions.shift_x.sample(&pos), 0f64); + assert_eq!(noise_functions.shift_x.min(), -8f64); + assert_eq!(noise_functions.shift_x.max(), 8f64); + + assert_eq!(noise_functions.shift_z.sample(&pos), 0f64); + assert_eq!(noise_functions.shift_z.min(), -8f64); + assert_eq!(noise_functions.shift_z.max(), 8f64); + + assert_eq!( + noise_functions.base_3d_noise_overworld.sample(&pos), + 0.05283727086562935f64 + ); + assert_eq!( + noise_functions.base_3d_noise_overworld.min(), + -87.55150000000002f64 + ); + assert_eq!( + noise_functions.base_3d_noise_overworld.max(), + 87.55150000000002f64 + ); + + assert_eq!( + noise_functions.base_3d_noise_nether.sample(&pos), + 0.05283727086562935f64 + ); + assert_eq!( + noise_functions.base_3d_noise_nether.min(), + -258.65450000000004f64 + ); + assert_eq!( + noise_functions.base_3d_noise_nether.max(), + 258.65450000000004f64 + ); + + assert_eq!( + noise_functions.base_3d_noise_end.sample(&pos), + 0.05283727086562935f64 + ); + assert_eq!( + noise_functions.base_3d_noise_end.min(), + -173.10299999999998f64 + ); + assert_eq!( + noise_functions.base_3d_noise_end.max(), + 173.10299999999998f64 + ); + + assert_eq!(noise_functions.continents_overworld.sample(&pos), 0f64); + assert_eq!(noise_functions.continents_overworld.min(), -2f64); + assert_eq!(noise_functions.continents_overworld.max(), 2f64); + + assert_eq!(noise_functions.erosion_overworld.sample(&pos), 0f64); + assert_eq!(noise_functions.erosion_overworld.min(), -2f64); + assert_eq!(noise_functions.erosion_overworld.max(), 2f64); + + assert_eq!(noise_functions.ridges_overworld.sample(&pos), 0f64); + assert_eq!(noise_functions.ridges_overworld.min(), -2f64); + assert_eq!(noise_functions.ridges_overworld.max(), 2f64); + + assert_eq!(noise_functions.ridges_folded_overworld.sample(&pos), -1f64); + assert_eq!( + noise_functions.ridges_folded_overworld.min(), + -3.000000000000001f64 + ); + assert_eq!(noise_functions.ridges_folded_overworld.max(), 1f64); + + assert_eq!( + noise_functions.offset_overworld.sample(&pos), + -0.6037500277161598f64 + ); + assert_eq!( + noise_functions.offset_overworld.min(), + -1.3752707839012146f64 + ); + assert_eq!( + noise_functions.offset_overworld.max(), + 0.9962499737739563f64 + ); + + assert_eq!(noise_functions.y.sample(&pos), 0f64); + assert_eq!(noise_functions.y.min(), -4064f64); + assert_eq!(noise_functions.y.max(), 4062f64); + + assert_eq!(noise_functions.y.sample(&pos), 0f64); + assert_eq!(noise_functions.y.min(), -4064f64); + assert_eq!(noise_functions.y.max(), 4062f64); + + assert_eq!(noise_functions.y.sample(&pos), 0f64); + assert_eq!(noise_functions.y.min(), -4064f64); + assert_eq!(noise_functions.y.max(), 4062f64); + + assert_eq!(noise_functions.y.sample(&pos), 0f64); + assert_eq!(noise_functions.y.min(), -4064f64); + assert_eq!(noise_functions.y.max(), 4062f64); + } +} diff --git a/pumpkin-world/src/world_gen/noise/density/spline.rs b/pumpkin-world/src/world_gen/noise/density/spline.rs index 04e543a6a..c2480d7cc 100644 --- a/pumpkin-world/src/world_gen/noise/density/spline.rs +++ b/pumpkin-world/src/world_gen/noise/density/spline.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::world_gen::noise::lerp_32; +use crate::world_gen::noise::lerp; use super::{ Applier, ApplierImpl, DensityFunction, DensityFunctionImpl, NoisePos, Visitor, VisitorImpl, @@ -56,6 +56,11 @@ pub struct Spline<'a> { max: f32, } +enum Range { + In(usize), + Below, +} + impl<'a> Spline<'a> { fn sample_outside_range(point: f32, value: f32, points: &[SplinePoint], i: usize) -> f32 { let f = points[i].derivative; @@ -66,8 +71,29 @@ impl<'a> Spline<'a> { } } - fn find_range_for_location(locations: &[f32], x: f32) -> i32 { - locations.partition_point(|val| x < *val) as i32 - 1 + fn binary_walk(min: usize, max: usize, pred: impl Fn(usize) -> bool) -> usize { + let mut i = max - min; + let mut min = min; + while i > 0 { + let j = i / 2; + let k = min + j; + if pred(k) { + i = j; + } else { + min = k + 1; + i -= j + 1; + } + } + min + } + + fn find_range_for_location(points: &[SplinePoint], x: f32) -> Range { + let index_greater_than_x = Self::binary_walk(0, points.len(), |i| x < points[i].location); + if index_greater_than_x == 0 { + Range::Below + } else { + Range::In(index_greater_than_x - 1) + } } pub fn new(function: Arc>, points: &[SplinePoint<'a>]) -> Self { @@ -143,31 +169,34 @@ impl<'a> Spline<'a> { pub fn apply(&self, pos: &NoisePos) -> f32 { let f = self.function.sample(pos) as f32; - let i = Self::find_range_for_location( - self.points - .iter() - .map(|p| p.location) - .collect::>() - .as_ref(), - f, - ); - let j = self.points.len() - 1; + let i = Self::find_range_for_location(&self.points, f); - if i < 0 { - Self::sample_outside_range(f, self.points[0].value.apply(pos), &self.points, 0) - } else if i == j as i32 { - Self::sample_outside_range(f, self.points[j].value.apply(pos), &self.points, j) - } else { - let point_1 = &self.points[i as usize]; - let point_2 = &self.points[i as usize + 1]; - let k = (f - point_1.location) / (point_2.location - point_1.location); + match i { + Range::In(index) => { + let last_index = self.points.len() - 1; + if index == last_index { + Self::sample_outside_range( + f, + self.points[last_index].value.apply(pos), + &self.points, + last_index, + ) + } else { + let point_1 = &self.points[index]; + let point_2 = &self.points[index + 1]; + let k = (f - point_1.location) / (point_2.location - point_1.location); - let n = point_1.value.apply(pos); - let o = point_2.value.apply(pos); + let n = point_1.value.apply(pos); + let o = point_2.value.apply(pos); - let p = point_1.derivative * (point_2.location - point_1.location) - (o - n); - let q = -point_2.derivative * (point_2.location - point_1.location) + (o - n); - lerp_32(k, n, o) + k * (1f32 - k) * lerp_32(k, p, q) + let p = point_1.derivative * (point_2.location - point_1.location) - (o - n); + let q = -point_2.derivative * (point_2.location - point_1.location) + (o - n); + lerp(k, n, o) + k * (1f32 - k) * lerp(k, p, q) + } + } + Range::Below => { + Self::sample_outside_range(f, self.points[0].value.apply(pos), &self.points, 0) + } } } @@ -225,7 +254,9 @@ impl<'a> DensityFunctionImpl<'a> for SplineFunction<'a> { #[derive(Clone)] pub enum FloatAmplifier { Identity, - Amplifier, + OffsetAmplifier, + FactorAmplifier, + JaggednessAmplifier, } impl FloatAmplifier { @@ -233,13 +264,15 @@ impl FloatAmplifier { pub fn apply(&self, f: f32) -> f32 { match self { Self::Identity => f, - Self::Amplifier => { + Self::OffsetAmplifier => { if f < 0f32 { f } else { f * 2f32 } } + Self::FactorAmplifier => 1.25f32 - 6.25f32 / (f + 5f32), + Self::JaggednessAmplifier => f * 2f32, } } } @@ -293,3 +326,34 @@ impl<'a> SplineBuilder<'a> { Spline::new(self.function.clone(), &self.points) } } + +#[cfg(test)] +mod test { + + use crate::world_gen::noise::{ + density::{BuiltInNoiseFunctions, NoisePos, UnblendedNoisePos}, + BuiltInNoiseParams, + }; + + use super::{FloatAmplifier, SplineBuilder}; + + #[test] + fn test_correctness() { + let noise_params = BuiltInNoiseParams::new(); + let noise_functions = BuiltInNoiseFunctions::new(&noise_params); + let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 }); + + let spline = SplineBuilder::new( + noise_functions.continents_overworld, + FloatAmplifier::Identity, + ) + .add_value(-1.1f32, 0.044f32, 0f32) + .add_value(-1.02f32, -0.2222f32, 0f32) + .add_value(-0.51f32, -0.2222f32, 0f32) + .add_value(-0.44f32, -0.12f32, 0f32) + .add_value(-0.18f32, -0.12f32, 0f32) + .build(); + + assert_eq!(spline.apply(&pos), -0.12f32); + } +} diff --git a/pumpkin-world/src/world_gen/implementation/overworld/terrain_params.rs b/pumpkin-world/src/world_gen/noise/density/terrain_helpers.rs similarity index 84% rename from pumpkin-world/src/world_gen/implementation/overworld/terrain_params.rs rename to pumpkin-world/src/world_gen/noise/density/terrain_helpers.rs index 31d5ffbae..432052cb6 100644 --- a/pumpkin-world/src/world_gen/implementation/overworld/terrain_params.rs +++ b/pumpkin-world/src/world_gen/noise/density/terrain_helpers.rs @@ -6,7 +6,7 @@ use crate::world_gen::noise::density::spline::{ FloatAmplifier, Spline, SplineBuilder, SplineValue, }; use crate::world_gen::noise::density::{peaks_valleys_noise, DensityFunction}; -use crate::world_gen::noise::lerp_32; +use crate::world_gen::noise::lerp; #[inline] fn get_offset_value(f: f32, g: f32, h: f32) -> f32 { @@ -69,7 +69,7 @@ fn meth_42050( let builder = if bl { builder .add_value(-1f32, 0.2f32.max(i), 0f32) - .add_value(0f32, lerp_32(0.5f32, i, k), n) + .add_value(0f32, lerp(0.5f32, i, k), n) } else { builder.add_value(-1f32, i, n) }; @@ -216,11 +216,8 @@ fn method_42052<'a>( builder.build() } -fn method_42049<'a>( - ridges: Arc>, - f: f32, - amplifier: FloatAmplifier, -) -> Spline<'a> { +#[inline] +fn method_42049(ridges: Arc, f: f32, amplifier: FloatAmplifier) -> Spline { let g = 0.63f32 * f; let h = 0.3f32 * f; SplineBuilder::new(ridges, amplifier) @@ -229,6 +226,8 @@ fn method_42049<'a>( .build() } +#[allow(clippy::too_many_arguments)] +#[inline] fn method_42053<'a>( erosion: Arc>, ridges: Arc>, @@ -257,7 +256,7 @@ fn method_42053<'a>( SplineBuilder::new(erosion, amplifier) .add_spline(-1f32, SplineValue::Spline(spline), 0f32) .add_spline(-0.78, SplineValue::Spline(spline2.clone()), 0f32) - .add_spline(-05775f32, SplineValue::Spline(spline2), 0f32) + .add_spline(-0.5775f32, SplineValue::Spline(spline2), 0f32) .add_value(-0.375f32, 0f32, 0f32) .build() } @@ -278,13 +277,13 @@ fn create_continental_offset_spline<'a>( ) -> Spline<'a> { let spline = meth_42050( ridges.clone(), - lerp_32(h, 0.6f32, 1.5f32), + lerp(h, 0.6f32, 1.5f32), bl2, amplifier.clone(), ); let spline2 = meth_42050( ridges.clone(), - lerp_32(h, 0.6f32, 1f32), + lerp(h, 0.6f32, 1f32), bl2, amplifier.clone(), ); @@ -293,7 +292,7 @@ fn create_continental_offset_spline<'a>( ridges.clone(), continental - 0.15f32, 0.5f32 * h, - lerp_32(0.5f32, 0.5f32, 0.5f32) * h, + lerp(0.5f32, 0.5f32, 0.5f32) * h, 0.5f32 * h, 0.6f32 * h, 0.5f32, @@ -378,7 +377,7 @@ pub fn create_offset_spline<'a>( amplified: bool, ) -> Spline<'a> { let amplification = if amplified { - FloatAmplifier::Amplifier + FloatAmplifier::OffsetAmplifier } else { FloatAmplifier::Identity }; @@ -458,7 +457,7 @@ pub fn create_factor_spline<'a>( amplified: bool, ) -> Spline<'a> { let amplification = if amplified { - FloatAmplifier::Amplifier + FloatAmplifier::FactorAmplifier } else { FloatAmplifier::Identity }; @@ -524,7 +523,7 @@ pub fn create_jaggedness_spline<'a>( amplified: bool, ) -> Spline<'a> { let amplification = if amplified { - FloatAmplifier::Amplifier + FloatAmplifier::JaggednessAmplifier } else { FloatAmplifier::Identity }; @@ -561,3 +560,82 @@ pub fn create_jaggedness_spline<'a>( ) .build() } + +#[cfg(test)] +mod test { + use crate::world_gen::noise::{ + density::{ + spline::FloatAmplifier, terrain_helpers::create_offset_spline, BuiltInNoiseFunctions, + NoisePos, UnblendedNoisePos, + }, + BuiltInNoiseParams, + }; + + use super::create_continental_offset_spline; + + #[test] + fn test_offset_correctness() { + let noise_params = BuiltInNoiseParams::new(); + let noise_functions = BuiltInNoiseFunctions::new(&noise_params); + + let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 }); + + let spline = create_continental_offset_spline( + noise_functions.erosion_overworld.clone(), + noise_functions.ridges_folded_overworld.clone(), + 1f32, + 1f32, + 1f32, + 1f32, + 1f32, + 1f32, + true, + true, + FloatAmplifier::Identity, + ); + + assert_eq!(spline.apply(&pos), 1f32); + + let pos = NoisePos::Unblended(UnblendedNoisePos { + x: 10, + y: 10, + z: 10, + }); + + let spline = create_continental_offset_spline( + noise_functions.erosion_overworld.clone(), + noise_functions.ridges_folded_overworld.clone(), + 2f32, + 2f32, + 2f32, + 2f32, + 2f32, + 2f32, + true, + true, + FloatAmplifier::Identity, + ); + + assert_eq!(spline.apply(&pos), 2f32); + + let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 }); + + let spline = create_offset_spline( + noise_functions.continents_overworld.clone(), + noise_functions.erosion_overworld.clone(), + noise_functions.ridges_folded_overworld.clone(), + true, + ); + + assert_eq!(spline.apply(&pos), -0.1f32); + + let spline = create_offset_spline( + noise_functions.continents_overworld, + noise_functions.erosion_overworld.clone(), + noise_functions.ridges_folded_overworld.clone(), + false, + ); + + assert_eq!(spline.apply(&pos), -0.1f32); + } +} diff --git a/pumpkin-world/src/world_gen/noise/mod.rs b/pumpkin-world/src/world_gen/noise/mod.rs index bf8d73c9b..0f9de83f1 100644 --- a/pumpkin-world/src/world_gen/noise/mod.rs +++ b/pumpkin-world/src/world_gen/noise/mod.rs @@ -1,9 +1,6 @@ -#![allow(dead_code)] - use derive_getters::Getters; +use num_traits::Float; use perlin::DoublePerlinNoiseParameters; -pub mod chunk_sampler; -pub mod config; pub mod density; pub mod perlin; mod router; @@ -188,11 +185,10 @@ impl<'a> BuiltInNoiseParams<'a> { } } -pub fn lerp_32(delta: f32, start: f32, end: f32) -> f32 { - start + delta * (end - start) -} - -pub fn lerp(delta: f64, start: f64, end: f64) -> f64 { +pub fn lerp(delta: T, start: T, end: T) -> T +where + T: Float, +{ start + delta * (end - start) } diff --git a/pumpkin-world/src/world_gen/positions.rs b/pumpkin-world/src/world_gen/positions.rs new file mode 100644 index 000000000..4420c96d0 --- /dev/null +++ b/pumpkin-world/src/world_gen/positions.rs @@ -0,0 +1,28 @@ +pub mod chunk_pos { + use noise::Vector2; + + const MARKER: u64 = packed(Vector2 { + x: 1875066, + y: 1875066, + }); + + pub const fn packed(vec: Vector2) -> u64 { + (vec.x as u64 & 4294967295u64) | ((vec.y as u64 & 4294967295u64) << 32) + } + + pub const fn unpack_x(packed: u64) -> i32 { + (packed & 4294967295u64) as i32 + } + + pub const fn unpack_z(packed: u64) -> i32 { + ((packed >> 32) & 4294967295u64) as i32 + } + + pub const fn start_x(vec: Vector2) -> i32 { + vec.x << 4 + } + + pub const fn start_y(vec: Vector2) -> i32 { + vec.y << 4 + } +} diff --git a/pumpkin-world/src/world_gen/proto_chunk.rs b/pumpkin-world/src/world_gen/proto_chunk.rs new file mode 100644 index 000000000..fadb30083 --- /dev/null +++ b/pumpkin-world/src/world_gen/proto_chunk.rs @@ -0,0 +1,29 @@ +use pumpkin_core::math::vector3::Vector3; + +use crate::block::block_state::BlockState; + +pub struct ProtoChunk { + state: GenerationState, +} + +impl ProtoChunk { + pub fn get_block_state(&self, _pos: &Vector3) -> BlockState { + unimplemented!() + } +} + +#[derive(Clone, PartialEq, PartialOrd)] +pub enum GenerationState { + Empty, + StructureStart, + StructureRef, + Biome, + Noise, + Surface, + Carver, + Feature, + InitLight, + Light, + Spawn, + Full, +} diff --git a/pumpkin-world/src/world_gen/supplier.rs b/pumpkin-world/src/world_gen/supplier.rs deleted file mode 100644 index b5514ed8c..000000000 --- a/pumpkin-world/src/world_gen/supplier.rs +++ /dev/null @@ -1,26 +0,0 @@ -use enum_dispatch::enum_dispatch; - -use crate::biome::Biome; - -#[derive(Clone)] -#[enum_dispatch] -pub enum BiomeSupplier { - Static(StaticBiomeSupplier), -} - -#[enum_dispatch(BiomeSupplier)] -pub trait BiomeSupplierImpl { - fn biome(&self, x: i32, y: i32, z: i32, noise: &MultiNoiseSampler) -> Biome; -} - -#[derive(Clone)] -pub struct StaticBiomeSupplier {} -impl BiomeSupplierImpl for StaticBiomeSupplier { - fn biome(&self, _x: i32, _y: i32, _z: i32, _noise: &MultiNoiseSampler) -> Biome { - Biome::Plains - } -} - -pub struct MultiNoiseSampler { - -}