Pumpkin/pumpkin-world/src/generation/noise/router/density_function/noise.rs
Alexander Medvedev 835262a85a chore: move chunk gen settings from runtime to compile time parsing
Bin size decreased, Startup time decreased by a lot in debug, lower memory usage
2026-02-03 23:35:31 +01:00

327 lines
9.0 KiB
Rust

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<i32>) -> 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<i32>) -> 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<i32>) -> 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<i32>,
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<i32>) -> 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
}
}