use std::array; use pumpkin_data::noise_router::{InterpolatedNoiseSamplerData, NoiseData, ShiftedNoiseData}; use pumpkin_util::{ math::{clamped_lerp, vector3::Vector3}, noise::perlin::OctavePerlinNoiseSampler, random::RandomGenerator, }; use crate::generation::{ noise::perlin::DoublePerlinNoiseSampler, noise::router::{ chunk_density_function::ChunkNoiseFunctionSampleOptions, chunk_noise_router::{ChunkNoiseFunctionComponent, StaticChunkNoiseFunctionComponentImpl}, }, }; use super::{NoiseFunctionComponentRange, StaticIndependentChunkNoiseFunctionComponentImpl}; pub struct Noise { sampler: DoublePerlinNoiseSampler, data: &'static NoiseData, } impl Noise { pub const fn new(sampler: DoublePerlinNoiseSampler, data: &'static NoiseData) -> Self { Self { sampler, data } } } impl NoiseFunctionComponentRange for Noise { #[inline] fn min(&self) -> f64 { -self.max() } #[inline] fn max(&self) -> f64 { self.sampler.max_value() } } impl StaticIndependentChunkNoiseFunctionComponentImpl for Noise { fn sample(&self, pos: &Vector3) -> f64 { self.sampler.sample( pos.x as f64 * self.data.xz_scale, pos.y as f64 * self.data.y_scale, pos.z as f64 * self.data.xz_scale, ) } } #[inline] fn shift_sample_3d(sampler: &DoublePerlinNoiseSampler, x: f64, y: f64, z: f64) -> f64 { sampler.sample(x * 0.25f64, y * 0.25f64, z * 0.25f64) * 4f64 } pub struct ShiftA { sampler: DoublePerlinNoiseSampler, } impl ShiftA { pub const fn new(sampler: DoublePerlinNoiseSampler) -> Self { Self { sampler } } } impl NoiseFunctionComponentRange for ShiftA { #[inline] fn min(&self) -> f64 { -self.max() } #[inline] fn max(&self) -> f64 { self.sampler.max_value() * 4.0 } } impl StaticIndependentChunkNoiseFunctionComponentImpl for ShiftA { fn sample(&self, pos: &Vector3) -> f64 { shift_sample_3d(&self.sampler, pos.x as f64, 0.0, pos.z as f64) } } pub struct ShiftB { sampler: DoublePerlinNoiseSampler, } impl ShiftB { pub const fn new(sampler: DoublePerlinNoiseSampler) -> Self { Self { sampler } } } impl NoiseFunctionComponentRange for ShiftB { #[inline] fn min(&self) -> f64 { -self.max() } #[inline] fn max(&self) -> f64 { self.sampler.max_value() * 4.0 } } impl StaticIndependentChunkNoiseFunctionComponentImpl for ShiftB { fn sample(&self, pos: &Vector3) -> f64 { shift_sample_3d(&self.sampler, pos.z as f64, pos.x as f64, 0.0) } } pub struct ShiftedNoise { input_x_index: usize, input_y_index: usize, input_z_index: usize, sampler: DoublePerlinNoiseSampler, data: &'static ShiftedNoiseData, } impl NoiseFunctionComponentRange for ShiftedNoise { #[inline] fn min(&self) -> f64 { -self.max() } #[inline] fn max(&self) -> f64 { self.sampler.max_value() } } impl StaticChunkNoiseFunctionComponentImpl for ShiftedNoise { fn sample( &self, component_stack: &mut [ChunkNoiseFunctionComponent], pos: &Vector3, sample_options: &ChunkNoiseFunctionSampleOptions, ) -> f64 { let translated_x = pos.x as f64 * self.data.xz_scale + ChunkNoiseFunctionComponent::sample_from_stack( &mut component_stack[..=self.input_x_index], pos, sample_options, ); let translated_y = pos.y as f64 * self.data.y_scale + ChunkNoiseFunctionComponent::sample_from_stack( &mut component_stack[..=self.input_y_index], pos, sample_options, ); let translated_z = pos.z as f64 * self.data.xz_scale + ChunkNoiseFunctionComponent::sample_from_stack( &mut component_stack[..=self.input_z_index], pos, sample_options, ); self.sampler .sample(translated_x, translated_y, translated_z) } } impl ShiftedNoise { pub const fn new( input_x_index: usize, input_y_index: usize, input_z_index: usize, sampler: DoublePerlinNoiseSampler, data: &'static ShiftedNoiseData, ) -> Self { Self { input_x_index, input_y_index, input_z_index, sampler, data, } } } pub struct InterpolatedNoiseSampler { lower_noise: OctavePerlinNoiseSampler, upper_noise: OctavePerlinNoiseSampler, noise: OctavePerlinNoiseSampler, data: &'static InterpolatedNoiseSamplerData, fractions: [f64; 16], max_value: f64, } impl InterpolatedNoiseSampler { pub fn new(data: &'static InterpolatedNoiseSamplerData, random: &mut RandomGenerator) -> Self { let big_start = -15; let big_amplitudes = [1.0; 16]; let little_start = -7; let little_amplitudes = [1.0; 8]; let lower_noise = OctavePerlinNoiseSampler::new(random, big_start, &big_amplitudes, true); let upper_noise = OctavePerlinNoiseSampler::new(random, big_start, &big_amplitudes, true); let noise = OctavePerlinNoiseSampler::new(random, little_start, &little_amplitudes, true); let max_value = lower_noise.get_total_amplitude(data.scaled_y_scale + 2.0); let fractions = array::from_fn(|index| { let mut o = 1.0; for _ in 0..index { o /= 2.0; } o }); Self { lower_noise, upper_noise, noise, data, fractions, max_value, } } } impl NoiseFunctionComponentRange for InterpolatedNoiseSampler { #[inline] fn min(&self) -> f64 { -self.max() } #[inline] fn max(&self) -> f64 { self.max_value } } impl StaticIndependentChunkNoiseFunctionComponentImpl for InterpolatedNoiseSampler { fn sample(&self, pos: &Vector3) -> f64 { let d = pos.x as f64 * self.data.scaled_xz_scale; let e = pos.y as f64 * self.data.scaled_y_scale; let f = pos.z as f64 * self.data.scaled_xz_scale; let g = d / self.data.xz_factor; let h = e / self.data.y_factor; let i = f / self.data.xz_factor; let j = self.data.scaled_y_scale * self.data.smear_scale_multiplier; let k = j / self.data.y_factor; // It's ok the the fractions are more than this; zip will cut it short let n: f64 = self .noise .samplers .iter() .rev() .zip(self.fractions) .map(|(data, fraction)| { let mapped_x = OctavePerlinNoiseSampler::maintain_precision(g * fraction); let mapped_y = OctavePerlinNoiseSampler::maintain_precision(h * fraction); let mapped_z = OctavePerlinNoiseSampler::maintain_precision(i * fraction); data.sampler.sample_no_fade( mapped_x, mapped_y, mapped_z, k * fraction, h * fraction, ) / fraction }) .sum(); let q = f64::midpoint(n / 10f64, 1f64); let bl2 = q >= 1f64; let bl3 = q <= 0f64; let l = if bl2 { 0.0 } else { self.lower_noise .samplers .iter() .rev() .zip(self.fractions) .map(|(data, fraction)| { let mapped_x = OctavePerlinNoiseSampler::maintain_precision(d * fraction); let mapped_y = OctavePerlinNoiseSampler::maintain_precision(e * fraction); let mapped_z = OctavePerlinNoiseSampler::maintain_precision(f * fraction); data.sampler.sample_no_fade( mapped_x, mapped_y, mapped_z, j * fraction, e * fraction, ) / fraction }) .sum() }; let m = if bl3 { 0.0 } else { self.upper_noise .samplers .iter() .rev() .zip(self.fractions) .map(|(data, fraction)| { let mapped_x = OctavePerlinNoiseSampler::maintain_precision(d * fraction); let mapped_y = OctavePerlinNoiseSampler::maintain_precision(e * fraction); let mapped_z = OctavePerlinNoiseSampler::maintain_precision(f * fraction); data.sampler.sample_no_fade( mapped_x, mapped_y, mapped_z, j * fraction, e * fraction, ) / fraction }) .sum() }; clamped_lerp(l / 512f64, m / 512f64, q) / 128f64 } }