diff --git a/pumpkin-core/src/random/gaussian.rs b/pumpkin-core/src/random/gaussian.rs index 8364cb91..35d4095c 100644 --- a/pumpkin-core/src/random/gaussian.rs +++ b/pumpkin-core/src/random/gaussian.rs @@ -1,18 +1,14 @@ -use super::Random; +use super::RandomImpl; -pub trait GaussianGenerator: Random { - fn has_next_gaussian(&self) -> bool; +pub trait GaussianGenerator: RandomImpl { + fn stored_next_gaussian(&self) -> Option; - fn set_has_next_gaussian(&mut self, value: bool); - - fn stored_next_gaussian(&self) -> f64; - - fn set_stored_next_gaussian(&mut self, value: f64); + fn set_stored_next_gaussian(&mut self, value: Option); fn calculate_gaussian(&mut self) -> f64 { - if self.has_next_gaussian() { - self.set_has_next_gaussian(false); - self.stored_next_gaussian() + if let Some(gaussian) = self.stored_next_gaussian() { + self.set_stored_next_gaussian(None); + gaussian } else { loop { let d = 2f64 * self.next_f64() - 1f64; @@ -21,8 +17,7 @@ pub trait GaussianGenerator: Random { if f < 1f64 && f != 0f64 { let g = (-2f64 * f.ln() / f).sqrt(); - self.set_stored_next_gaussian(e * g); - self.set_has_next_gaussian(true); + self.set_stored_next_gaussian(Some(e * g)); return d * g; } } diff --git a/pumpkin-core/src/random/legacy_rand.rs b/pumpkin-core/src/random/legacy_rand.rs index f7f60ff4..4a2cb1b9 100644 --- a/pumpkin-core/src/random/legacy_rand.rs +++ b/pumpkin-core/src/random/legacy_rand.rs @@ -1,11 +1,10 @@ use super::{ - gaussian::GaussianGenerator, hash_block_pos, java_string_hash, Random, RandomSplitter, + gaussian::GaussianGenerator, hash_block_pos, java_string_hash, RandomDeriverImpl, RandomImpl, }; -struct LegacyRand { +pub struct LegacyRand { seed: u64, - internal_next_gaussian: f64, - internal_has_next_gaussian: bool, + internal_next_gaussian: Option, } impl LegacyRand { @@ -18,29 +17,20 @@ impl LegacyRand { } impl GaussianGenerator for LegacyRand { - fn has_next_gaussian(&self) -> bool { - self.internal_has_next_gaussian - } - - fn stored_next_gaussian(&self) -> f64 { + fn stored_next_gaussian(&self) -> Option { self.internal_next_gaussian } - fn set_has_next_gaussian(&mut self, value: bool) { - self.internal_has_next_gaussian = value; - } - - fn set_stored_next_gaussian(&mut self, value: f64) { + fn set_stored_next_gaussian(&mut self, value: Option) { self.internal_next_gaussian = value; } } -impl Random for LegacyRand { +impl RandomImpl for LegacyRand { fn from_seed(seed: u64) -> Self { LegacyRand { seed: (seed ^ 0x5DEECE66D) & 0xFFFFFFFFFFFF, - internal_has_next_gaussian: false, - internal_next_gaussian: 0f64, + internal_next_gaussian: None, } } @@ -77,7 +67,8 @@ impl Random for LegacyRand { self.next(1) != 0 } - fn next_splitter(&mut self) -> impl RandomSplitter { + #[allow(refining_impl_trait)] + fn next_splitter(&mut self) -> LegacySplitter { LegacySplitter::new(self.next_i64() as u64) } @@ -86,13 +77,13 @@ impl Random for LegacyRand { } fn next_bounded_i32(&mut self, bound: i32) -> i32 { - if bound & (bound - 1) == 0 { - (bound as u64).wrapping_mul(self.next(31) >> 31) as i32 + if (bound & bound.wrapping_sub(1)) == 0 { + ((bound as u64).wrapping_mul(self.next(31)) >> 31) as i32 } else { loop { let i = self.next(31) as i32; let j = i % bound; - if (i - j + (bound - 1)) > 0 { + if (i.wrapping_sub(j).wrapping_add(bound.wrapping_sub(1))) >= 0 { return j; } } @@ -100,7 +91,7 @@ impl Random for LegacyRand { } } -struct LegacySplitter { +pub struct LegacySplitter { seed: u64, } @@ -110,17 +101,18 @@ impl LegacySplitter { } } -impl RandomSplitter for LegacySplitter { - fn split_u64(&self, seed: u64) -> impl Random { +#[allow(refining_impl_trait)] +impl RandomDeriverImpl for LegacySplitter { + fn split_u64(&self, seed: u64) -> LegacyRand { LegacyRand::from_seed(seed) } - fn split_string(&self, seed: &str) -> impl Random { + fn split_string(&self, seed: &str) -> LegacyRand { let string_hash = java_string_hash(seed); LegacyRand::from_seed((string_hash as u64) ^ self.seed) } - fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random { + fn split_pos(&self, x: i32, y: i32, z: i32) -> LegacyRand { let pos_hash = hash_block_pos(x, y, z); LegacyRand::from_seed((pos_hash as u64) ^ self.seed) } @@ -128,7 +120,7 @@ impl RandomSplitter for LegacySplitter { #[cfg(test)] mod test { - use crate::random::{Random, RandomSplitter}; + use crate::random::{RandomDeriverImpl, RandomImpl}; use super::LegacyRand; @@ -163,6 +155,17 @@ mod test { for value in values { assert_eq!(rand.next_bounded_i32(0xf), value); } + + let mut rand = LegacyRand::from_seed(0); + for _ in 0..10 { + assert_eq!(rand.next_bounded_i32(1), 0); + } + + let mut rand = LegacyRand::from_seed(0); + let values = [1, 1, 0, 1, 1, 0, 1, 0, 1, 1]; + for value in values { + assert_eq!(rand.next_bounded_i32(2), value); + } } #[test] diff --git a/pumpkin-core/src/random/mod.rs b/pumpkin-core/src/random/mod.rs index b5389aa4..d0200ebc 100644 --- a/pumpkin-core/src/random/mod.rs +++ b/pumpkin-core/src/random/mod.rs @@ -1,13 +1,156 @@ +use legacy_rand::{LegacyRand, LegacySplitter}; +use xoroshiro128::{Xoroshiro, XoroshiroSplitter}; + mod gaussian; pub mod legacy_rand; pub mod xoroshiro128; -pub trait Random { +pub enum RandomGenerator { + Xoroshiro(Xoroshiro), + Legacy(LegacyRand), +} + +impl RandomGenerator { + #[inline] + pub fn split(&mut self) -> Self { + match self { + Self::Xoroshiro(rand) => Self::Xoroshiro(rand.split()), + Self::Legacy(rand) => Self::Legacy(rand.split()), + } + } + + #[inline] + pub fn next_splitter(&mut self) -> RandomDeriver { + match self { + Self::Xoroshiro(rand) => RandomDeriver::Xoroshiro(rand.next_splitter()), + Self::Legacy(rand) => RandomDeriver::Legacy(rand.next_splitter()), + } + } + + #[inline] + pub fn next(&mut self, bits: u64) -> u64 { + match self { + Self::Xoroshiro(rand) => rand.next(bits), + Self::Legacy(rand) => rand.next(bits), + } + } + + #[inline] + pub fn next_i32(&mut self) -> i32 { + match self { + Self::Xoroshiro(rand) => rand.next_i32(), + Self::Legacy(rand) => rand.next_i32(), + } + } + + #[inline] + pub fn next_bounded_i32(&mut self, bound: i32) -> i32 { + match self { + Self::Xoroshiro(rand) => rand.next_bounded_i32(bound), + Self::Legacy(rand) => rand.next_bounded_i32(bound), + } + } + + #[inline] + pub fn next_inbetween_i32(&mut self, min: i32, max: i32) -> i32 { + self.next_bounded_i32(max - min + 1) + min + } + + #[inline] + pub fn next_i64(&mut self) -> i64 { + match self { + Self::Xoroshiro(rand) => rand.next_i64(), + Self::Legacy(rand) => rand.next_i64(), + } + } + + #[inline] + pub fn next_bool(&mut self) -> bool { + match self { + Self::Xoroshiro(rand) => rand.next_bool(), + Self::Legacy(rand) => rand.next_bool(), + } + } + + #[inline] + pub fn next_f32(&mut self) -> f32 { + match self { + Self::Xoroshiro(rand) => rand.next_f32(), + Self::Legacy(rand) => rand.next_f32(), + } + } + + #[inline] + pub fn next_f64(&mut self) -> f64 { + match self { + Self::Xoroshiro(rand) => rand.next_f64(), + Self::Legacy(rand) => rand.next_f64(), + } + } + + #[inline] + pub fn next_gaussian(&mut self) -> f64 { + match self { + Self::Xoroshiro(rand) => rand.next_gaussian(), + Self::Legacy(rand) => rand.next_gaussian(), + } + } + + #[inline] + pub fn next_triangular(&mut self, mode: f64, deviation: f64) -> f64 { + mode + deviation * (self.next_f64() - self.next_f64()) + } + + #[inline] + pub fn skip(&mut self, count: i32) { + for _ in 0..count { + self.next_i64(); + } + } + + #[inline] + pub fn next_inbetween_i32_exclusive(&mut self, min: i32, max: i32) -> i32 { + min + self.next_bounded_i32(max - min) + } +} + +pub enum RandomDeriver { + Xoroshiro(XoroshiroSplitter), + Legacy(LegacySplitter), +} + +impl RandomDeriver { + #[inline] + pub fn split_string(&self, seed: &str) -> RandomGenerator { + match self { + Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_string(seed)), + Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_string(seed)), + } + } + + #[inline] + pub fn split_u64(&self, seed: u64) -> RandomGenerator { + match self { + Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_u64(seed)), + Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_u64(seed)), + } + } + + #[inline] + pub fn split_pos(&self, x: i32, y: i32, z: i32) -> RandomGenerator { + match self { + Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_pos(x, y, z)), + Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_pos(x, y, z)), + } + } +} + +pub trait RandomImpl { fn from_seed(seed: u64) -> Self; fn split(&mut self) -> Self; - fn next_splitter(&mut self) -> impl RandomSplitter; + fn next_splitter(&mut self) -> impl RandomDeriverImpl; fn next(&mut self, bits: u64) -> u64; @@ -44,12 +187,12 @@ pub trait Random { } } -pub trait RandomSplitter { - fn split_string(&self, seed: &str) -> impl Random; +pub trait RandomDeriverImpl { + fn split_string(&self, seed: &str) -> impl RandomImpl; - fn split_u64(&self, seed: u64) -> impl Random; + fn split_u64(&self, seed: u64) -> impl RandomImpl; - fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random; + fn split_pos(&self, x: i32, y: i32, z: i32) -> impl RandomImpl; } fn hash_block_pos(x: i32, y: i32, z: i32) -> i64 { diff --git a/pumpkin-core/src/random/xoroshiro128.rs b/pumpkin-core/src/random/xoroshiro128.rs index e8d7e4f1..a82fcf75 100644 --- a/pumpkin-core/src/random/xoroshiro128.rs +++ b/pumpkin-core/src/random/xoroshiro128.rs @@ -1,10 +1,9 @@ -use super::{gaussian::GaussianGenerator, hash_block_pos, Random, RandomSplitter}; +use super::{gaussian::GaussianGenerator, hash_block_pos, RandomDeriverImpl, RandomImpl}; pub struct Xoroshiro { lo: u64, hi: u64, - internal_next_gaussian: f64, - internal_has_next_gaussian: bool, + internal_next_gaussian: Option, } impl Xoroshiro { @@ -17,8 +16,7 @@ impl Xoroshiro { Self { lo, hi, - internal_next_gaussian: 0f64, - internal_has_next_gaussian: false, + internal_next_gaussian: None, } } @@ -45,21 +43,13 @@ impl Xoroshiro { } impl GaussianGenerator for Xoroshiro { - fn stored_next_gaussian(&self) -> f64 { + fn stored_next_gaussian(&self) -> Option { self.internal_next_gaussian } - fn has_next_gaussian(&self) -> bool { - self.internal_has_next_gaussian - } - - fn set_stored_next_gaussian(&mut self, value: f64) { + fn set_stored_next_gaussian(&mut self, value: Option) { self.internal_next_gaussian = value; } - - fn set_has_next_gaussian(&mut self, value: bool) { - self.internal_has_next_gaussian = value; - } } fn mix_stafford_13(z: u64) -> u64 { @@ -68,7 +58,7 @@ fn mix_stafford_13(z: u64) -> u64 { z ^ (z >> 31) } -impl Random for Xoroshiro { +impl RandomImpl for Xoroshiro { fn from_seed(seed: u64) -> Self { let (lo, hi) = Self::mix_u64(seed); let lo = mix_stafford_13(lo); @@ -84,7 +74,8 @@ impl Random for Xoroshiro { self.next_random() >> (64 - bits) } - fn next_splitter(&mut self) -> impl RandomSplitter { + #[allow(refining_impl_trait)] + fn next_splitter(&mut self) -> XoroshiroSplitter { XoroshiroSplitter { lo: self.next_random(), hi: self.next_random(), @@ -137,18 +128,19 @@ pub struct XoroshiroSplitter { hi: u64, } -impl RandomSplitter for XoroshiroSplitter { - fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random { +#[allow(refining_impl_trait)] +impl RandomDeriverImpl for XoroshiroSplitter { + fn split_pos(&self, x: i32, y: i32, z: i32) -> Xoroshiro { let l = hash_block_pos(x, y, z) as u64; let m = l ^ self.lo; Xoroshiro::new(m, self.hi) } - fn split_u64(&self, seed: u64) -> impl Random { + fn split_u64(&self, seed: u64) -> Xoroshiro { Xoroshiro::new(seed ^ self.lo, seed ^ self.hi) } - fn split_string(&self, seed: &str) -> impl Random { + fn split_string(&self, seed: &str) -> Xoroshiro { let bytes = md5::compute(seed.as_bytes()); let l = u64::from_be_bytes(bytes[0..8].try_into().expect("incorrect length")); let m = u64::from_be_bytes(bytes[8..16].try_into().expect("incorrect length")); @@ -159,7 +151,7 @@ impl RandomSplitter for XoroshiroSplitter { #[cfg(test)] mod tests { - use crate::random::{Random, RandomSplitter}; + use crate::random::{RandomDeriverImpl, RandomImpl}; use super::{mix_stafford_13, Xoroshiro}; diff --git a/pumpkin-world/src/world_gen/mod.rs b/pumpkin-world/src/world_gen/mod.rs index ddb1bbb9..4712a36f 100644 --- a/pumpkin-world/src/world_gen/mod.rs +++ b/pumpkin-world/src/world_gen/mod.rs @@ -1,6 +1,7 @@ mod generator; mod generic_generator; mod implementation; +mod noise; mod seed; pub use generator::WorldGenerator; diff --git a/pumpkin-world/src/world_gen/noise/mod.rs b/pumpkin-world/src/world_gen/noise/mod.rs new file mode 100644 index 00000000..ea5d5119 --- /dev/null +++ b/pumpkin-world/src/world_gen/noise/mod.rs @@ -0,0 +1,65 @@ +#![allow(dead_code)] +mod perlin; +mod simplex; + +pub fn lerp(delta: f64, start: f64, end: f64) -> f64 { + start + delta * (end - start) +} + +pub fn lerp2(delta_x: f64, delta_y: f64, x0y0: f64, x1y0: f64, x0y1: f64, x1y1: f64) -> f64 { + lerp( + delta_y, + lerp(delta_x, x0y0, x1y0), + lerp(delta_x, x0y1, x1y1), + ) +} + +#[allow(clippy::too_many_arguments)] +pub fn lerp3( + delta_x: f64, + delta_y: f64, + delta_z: f64, + x0y0z0: f64, + x1y0z0: f64, + x0y1z0: f64, + x1y1z0: f64, + x0y0z1: f64, + x1y0z1: f64, + x0y1z1: f64, + x1y1z1: f64, +) -> f64 { + lerp( + delta_z, + lerp2(delta_x, delta_y, x0y0z0, x1y0z0, x0y1z0, x1y1z0), + lerp2(delta_x, delta_y, x0y0z1, x1y0z1, x0y1z1, x1y1z1), + ) +} + +struct Gradient { + x: i32, + y: i32, + z: i32, +} + +const GRADIENTS: [Gradient; 16] = [ + Gradient { x: 1, y: 1, z: 0 }, + Gradient { x: -1, y: 1, z: 0 }, + Gradient { x: 1, y: -1, z: 0 }, + Gradient { x: -1, y: -1, z: 0 }, + Gradient { x: 1, y: 0, z: 1 }, + Gradient { x: -1, y: 0, z: 1 }, + Gradient { x: 1, y: 0, z: -1 }, + Gradient { x: -1, y: 0, z: -1 }, + Gradient { x: 0, y: 1, z: 1 }, + Gradient { x: 0, y: -1, z: 1 }, + Gradient { x: 0, y: 1, z: -1 }, + Gradient { x: 0, y: -1, z: -1 }, + Gradient { x: 1, y: 1, z: 0 }, + Gradient { x: 0, y: -1, z: 1 }, + Gradient { x: -1, y: 1, z: 0 }, + Gradient { x: 0, y: -1, z: -1 }, +]; + +fn dot(gradient: &Gradient, x: f64, y: f64, z: f64) -> f64 { + gradient.x as f64 * x + gradient.y as f64 * y + gradient.z as f64 * z +} diff --git a/pumpkin-world/src/world_gen/noise/perlin.rs b/pumpkin-world/src/world_gen/noise/perlin.rs new file mode 100644 index 00000000..a96b1fc6 --- /dev/null +++ b/pumpkin-world/src/world_gen/noise/perlin.rs @@ -0,0 +1,1125 @@ +use itertools::Itertools; +use num_traits::{Pow, Zero}; +use pumpkin_core::random::{RandomDeriverImpl, RandomGenerator, RandomImpl}; + +use super::{dot, lerp3, GRADIENTS}; + +pub struct PerlinNoiseSampler { + permutation: Box<[u8]>, + x_origin: f64, + y_origin: f64, + z_origin: f64, +} + +impl PerlinNoiseSampler { + pub fn new(random: &mut impl RandomImpl) -> Self { + let x_origin = random.next_f64() * 256f64; + let y_origin = random.next_f64() * 256f64; + let z_origin = random.next_f64() * 256f64; + + let mut permutation = [0u8; 256]; + + permutation + .iter_mut() + .enumerate() + .for_each(|(i, x)| *x = i as u8); + + for i in 0..256 { + let j = random.next_bounded_i32((256 - i) as i32) as usize; + permutation.swap(i, i + j); + } + + Self { + permutation: Box::new(permutation), + x_origin, + y_origin, + z_origin, + } + } + + pub fn sample_flat_y(&self, x: f64, y: f64, z: f64) -> f64 { + self.sample_no_fade(x, y, z, 0f64, 0f64) + } + + pub fn sample_no_fade(&self, x: f64, y: f64, z: f64, y_scale: f64, y_max: f64) -> f64 { + let trans_x = x + self.x_origin; + let trans_y = y + self.y_origin; + let trans_z = z + self.z_origin; + + let x_int = trans_x.floor() as i32; + let y_int = trans_y.floor() as i32; + let z_int = trans_z.floor() as i32; + + let x_dec = trans_x - x_int as f64; + let y_dec = trans_y - y_int as f64; + let z_dec = trans_z - z_int as f64; + + let y_noise = if y_scale != 0f64 { + let raw_y_dec = if y_max >= 0f64 && y_max < y_dec { + y_max + } else { + y_dec + }; + (raw_y_dec / y_scale + 1.0E-7f32 as f64).floor() * y_scale + } else { + 0f64 + }; + + self.sample(x_int, y_int, z_int, x_dec, y_dec - y_noise, z_dec, y_dec) + } + + fn grad(hash: i32, x: f64, y: f64, z: f64) -> f64 { + dot(&GRADIENTS[(hash & 15) as usize], x, y, z) + } + + fn perlin_fade(value: f64) -> f64 { + value * value * value * (value * (value * 6f64 - 15f64) + 10f64) + } + + fn map(&self, input: i32) -> i32 { + self.permutation[(input & 0xFF) as usize] as i32 + } + + #[allow(clippy::too_many_arguments)] + fn sample( + &self, + x: i32, + y: i32, + z: i32, + local_x: f64, + local_y: f64, + local_z: f64, + fade_local_y: f64, + ) -> f64 { + let i = self.map(x); + let j = self.map(x.wrapping_add(1)); + let k = self.map(i.wrapping_add(y)); + + let l = self.map(i.wrapping_add(y).wrapping_add(1)); + let m = self.map(j.wrapping_add(y)); + let n = self.map(j.wrapping_add(y).wrapping_add(1)); + + let d = Self::grad(self.map(k.wrapping_add(z)), local_x, local_y, local_z); + let e = Self::grad( + self.map(m.wrapping_add(z)), + local_x - 1f64, + local_y, + local_z, + ); + let f = Self::grad( + self.map(l.wrapping_add(z)), + local_x, + local_y - 1f64, + local_z, + ); + let g = Self::grad( + self.map(n.wrapping_add(z)), + local_x - 1f64, + local_y - 1f64, + local_z, + ); + let h = Self::grad( + self.map(k.wrapping_add(z).wrapping_add(1)), + local_x, + local_y, + local_z - 1f64, + ); + let o = Self::grad( + self.map(m.wrapping_add(z).wrapping_add(1)), + local_x - 1f64, + local_y, + local_z - 1f64, + ); + let p = Self::grad( + self.map(l.wrapping_add(z).wrapping_add(1)), + local_x, + local_y - 1f64, + local_z - 1f64, + ); + let q = Self::grad( + self.map(n.wrapping_add(z).wrapping_add(1)), + local_x - 1f64, + local_y - 1f64, + local_z - 1f64, + ); + let r = Self::perlin_fade(local_x); + let s = Self::perlin_fade(fade_local_y); + let t = Self::perlin_fade(local_z); + + lerp3(r, s, t, d, e, f, g, h, o, p, q) + } +} + +pub struct OctavePerlinNoiseSampler { + octave_samplers: Vec>, + amplitudes: Vec, + first_octave: i32, + persistence: f64, + lacunarity: f64, + max_value: f64, +} + +impl OctavePerlinNoiseSampler { + fn get_total_amplitude(scale: f64, persistence: f64, amplitudes: &[f64]) -> f64 { + let mut d = 0f64; + let mut e = persistence; + + for amplitude in amplitudes.iter() { + d += amplitude * scale * e; + e /= 2f64; + } + + d + } + + fn maintain_precision(value: f64) -> f64 { + value - (value / 3.3554432E7f64 + 0.5f64).floor() * 3.3554432E7f64 + } + + pub fn calculate_amplitudes(octaves: &[i32]) -> (i32, Vec) { + let mut octaves = Vec::from_iter(octaves); + octaves.sort(); + + let i = -**octaves.first().expect("we should have some octaves"); + let j = **octaves.last().expect("we should have some octaves"); + let k = i + j + 1; + + let mut double_list: Vec = Vec::with_capacity(k as usize); + for _ in 0..k { + double_list.push(0f64) + } + + for l in octaves { + double_list[(l + i) as usize] = 1f64; + } + + (-i, double_list) + } + + pub fn new(random: &mut RandomGenerator, first_octave: i32, amplitudes: &[f64]) -> Self { + let i = amplitudes.len(); + let j = -first_octave; + + let mut samplers: Vec> = Vec::with_capacity(i); + for _ in 0..i { + samplers.push(None); + } + + match random { + RandomGenerator::Xoroshiro(random) => { + let splitter = random.next_splitter(); + for k in 0..i { + if amplitudes[k] != 0f64 { + let l = first_octave + k as i32; + samplers[k] = Some(PerlinNoiseSampler::new( + &mut splitter.split_string(&format!("octave_{}", l)), + )); + } + } + } + RandomGenerator::Legacy(random) => { + let sampler = PerlinNoiseSampler::new(random); + if j >= 0 && j < i as i32 { + let d = amplitudes[j as usize]; + if d != 0f64 { + samplers[j as usize] = Some(sampler); + } + } + + for kx in (0..j as usize).rev() { + if kx < i { + let e = amplitudes[kx]; + if e != 0f64 { + samplers[kx] = Some(PerlinNoiseSampler::new(random)); + } else { + random.skip(262); + } + } else { + random.skip(262); + } + } + + if let Ok(length1) = samplers.iter().filter(|x| x.is_some()).try_len() { + if let Ok(length2) = amplitudes.iter().filter(|x| !x.is_zero()).try_len() { + assert_eq!(length1, length2); + } + } + assert!(j >= i as i32 - 1); + } + } + + let persistence = 2f64.pow((i as i32).wrapping_sub(1) as f64) / (2f64.pow(i as f64) - 1f64); + let max_value = Self::get_total_amplitude(2f64, persistence, amplitudes); + Self { + octave_samplers: samplers, + amplitudes: amplitudes.to_vec(), + first_octave, + persistence, + lacunarity: 2f64.pow((-j) as f64), + max_value, + } + } + + pub fn sample(&self, x: f64, y: f64, z: f64) -> f64 { + let mut d = 0f64; + let mut e = self.lacunarity; + let mut f = self.persistence; + + for (sampler, amplitude) in self.octave_samplers.iter().zip(self.amplitudes.iter()) { + if let Some(sampler) = sampler { + let g = sampler.sample_no_fade( + Self::maintain_precision(x * e), + Self::maintain_precision(y * e), + Self::maintain_precision(z * e), + 0f64, + 0f64, + ); + + d += amplitude * g * f; + } + + e *= 2f64; + f /= 2f64; + } + + d + } +} + +pub struct DoublePerlinNoiseSampler { + first_sampler: OctavePerlinNoiseSampler, + second_sampler: OctavePerlinNoiseSampler, + amplitude: f64, + max_value: f64, +} + +impl DoublePerlinNoiseSampler { + fn create_amplitude(octaves: i32) -> f64 { + 0.1f64 * (1f64 + 1f64 / (octaves + 1) as f64) + } + + pub fn new(rand: &mut RandomGenerator, first_octave: i32, amplitudes: &[f64]) -> Self { + let first_sampler = OctavePerlinNoiseSampler::new(rand, first_octave, amplitudes); + let second_sampler = OctavePerlinNoiseSampler::new(rand, first_octave, amplitudes); + + let mut j = i32::MAX; + let mut k = i32::MIN; + + for (index, amplitude) in amplitudes.iter().enumerate() { + if *amplitude != 0f64 { + j = i32::min(j, index as i32); + k = i32::max(k, index as i32); + } + } + + let amplitude = 0.16666666666666666f64 / Self::create_amplitude(k - j); + let max_value = (first_sampler.max_value + second_sampler.max_value) * amplitude; + + Self { + first_sampler, + second_sampler, + amplitude, + max_value, + } + } + + pub fn sample(&self, x: f64, y: f64, z: f64) -> f64 { + let d = x * 1.0181268882175227f64; + let e = y * 1.0181268882175227f64; + let f = z * 1.0181268882175227f64; + + (self.first_sampler.sample(x, y, z) + self.second_sampler.sample(d, e, f)) * self.amplitude + } +} + +#[cfg(test)] +mod double_perlin_noise_sampler_test { + use pumpkin_core::random::{legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomImpl}; + + use crate::world_gen::noise::perlin::{DoublePerlinNoiseSampler, RandomGenerator}; + + #[test] + fn sample_legacy() { + let mut rand = LegacyRand::from_seed(513513513); + assert_eq!(rand.next_i32(), -1302745855); + + let mut rand_gen = RandomGenerator::Legacy(rand); + let sampler = DoublePerlinNoiseSampler::new(&mut rand_gen, 0, &[4f64]); + + let values = [ + ( + ( + 3.7329617139221236E7, + 2.847228022372606E8, + -1.8244299064688918E8, + ), + -0.5044027150385925, + ), + ( + ( + 8.936597679535551E7, + 1.491954533221004E8, + 3.457494216166344E8, + ), + -1.0004671438756043, + ), + ( + ( + -2.2479845046034336E8, + -4.085449163378981E7, + 1.343082907470065E8, + ), + 2.1781128778536973, + ), + ( + ( + -1.9094944979652843E8, + 3.695081561625232E8, + 2.1566424798360935E8, + ), + -1.2571847948126453, + ), + ( + ( + 1.8486356004931596E8, + -4.148713734284534E8, + 4.8687219454012525E8, + ), + -0.550285244015363, + ), + ( + ( + 1.7115351141710258E8, + -1.8835885697652313E8, + 1.7031060329927653E8, + ), + -0.6953327750604766, + ), + ( + ( + 8.952317194270046E7, + -5.420942524023042E7, + -2.5987559023045145E7, + ), + 2.7361630914824393, + ), + ( + ( + -8.36195975247282E8, + -1.2167090318484206E8, + 2.1237199673286602E8, + ), + -1.5518675789351004, + ), + ( + ( + 3.333103540906928E8, + 5.088236187007203E8, + -3.521137809477999E8, + ), + 0.6928720433082317, + ), + ( + ( + 7.82760234776598E7, + -2.5204361464037597E7, + -1.6615974590937865E8, + ), + -0.5102124930620466, + ), + ]; + + for ((x, y, z), sample) in values { + assert_eq!(sampler.sample(x, y, z), sample) + } + } + + #[test] + fn sample_xoroshiro() { + let mut rand = Xoroshiro::from_seed(5); + assert_eq!(rand.next_i32(), -1678727252); + + let mut rand_gen = RandomGenerator::Xoroshiro(rand); + let sampler = DoublePerlinNoiseSampler::new(&mut rand_gen, 1, &[2f64, 4f64]); + + let values = [ + ( + ( + -2.4823401687190732E8, + 1.6909869132832196E8, + 1.0510057123823991E8, + ), + -0.09627881756376819, + ), + ( + ( + 1.2971355215791291E8, + -3.614855223614046E8, + 1.9997149869463342E8, + ), + 0.4412466810560897, + ), + ( + ( + -1.9858224577678584E7, + 2.5103843334053648E8, + 2.253841390457064E8, + ), + -1.3086196098510068, + ), + ( + ( + 1.4243878295159304E8, + -1.9185612600051942E8, + 4.7736284830701286E8, + ), + 1.727683424808049, + ), + ( + ( + -9.411241394159131E7, + 4.4052130232611096E8, + 5.1042225596740514E8, + ), + -0.4651812519989636, + ), + ( + ( + 3.007670445405074E8, + 1.4630490674448165E8, + -1.681994537227527E8, + ), + -0.8607587886441551, + ), + ( + ( + -2.290369962944646E8, + -4.9627750061129004E8, + 9.751744069476394E7, + ), + -0.3592693708849225, + ), + ( + ( + -5.380825223911383E7, + 6.317706682942032E7, + -3.0105795661690116E8, + ), + 0.7372424991843702, + ), + ( + ( + -1.4261684559190175E8, + 9.987839104129419E7, + 3.3290027416415906E8, + ), + 0.27706980571082485, + ), + ( + ( + -8.881637146904664E7, + 1.1033687270820947E8, + -1.0014482192140123E8, + ), + -0.4602443245357103, + ), + ]; + + for ((x, y, z), sample) in values { + assert_eq!(sampler.sample(x, y, z), sample) + } + } +} + +#[cfg(test)] +mod octave_perline_noise_sampler_test { + use pumpkin_core::random::{legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomImpl}; + + use crate::world_gen::noise::perlin::RandomGenerator; + + use super::OctavePerlinNoiseSampler; + + #[test] + fn test_create_xoroshiro() { + let mut rand = Xoroshiro::from_seed(513513513); + assert_eq!(rand.next_i32(), 404174895); + + let (start, amplitudes) = OctavePerlinNoiseSampler::calculate_amplitudes(&[1, 2, 3]); + assert_eq!(start, 1); + assert_eq!(amplitudes, [1f64, 1f64, 1f64]); + + let mut rand_gen = RandomGenerator::Xoroshiro(rand); + let sampler = OctavePerlinNoiseSampler::new(&mut rand_gen, start, &litudes); + + assert_eq!(sampler.first_octave, 1); + assert_eq!(sampler.persistence, 0.5714285714285714f64); + assert_eq!(sampler.lacunarity, 2f64); + assert_eq!(sampler.max_value, 2f64); + + let coords = [ + (210.19539348148294, 203.08258445596215, 45.29925114984684), + (24.841250686920773, 181.62678157390076, 69.49871248131629), + (21.65886467061867, 97.80131502331685, 225.9273676334467), + ]; + + for (sampler, (x, y, z)) in sampler.octave_samplers.iter().zip(coords) { + match sampler { + Some(sampler) => { + assert_eq!(sampler.x_origin, x); + assert_eq!(sampler.y_origin, y); + assert_eq!(sampler.z_origin, z); + } + None => panic!(), + } + } + } + + #[test] + fn test_create_legacy() { + let mut rand = LegacyRand::from_seed(513513513); + assert_eq!(rand.next_i32(), -1302745855); + + let (start, amplitudes) = OctavePerlinNoiseSampler::calculate_amplitudes(&[0]); + assert_eq!(start, 0); + assert_eq!(amplitudes, [1f64]); + + let mut rand_gen = RandomGenerator::Legacy(rand); + let sampler = OctavePerlinNoiseSampler::new(&mut rand_gen, start, &litudes); + assert_eq!(sampler.first_octave, 0); + assert_eq!(sampler.persistence, 1f64); + assert_eq!(sampler.lacunarity, 1f64); + assert_eq!(sampler.max_value, 2f64); + + let coords = [(226.220117499588, 32.67924779023767, 202.84067325597647)]; + + for (sampler, (x, y, z)) in sampler.octave_samplers.iter().zip(coords) { + match sampler { + Some(sampler) => { + assert_eq!(sampler.x_origin, x); + assert_eq!(sampler.y_origin, y); + assert_eq!(sampler.z_origin, z); + } + None => panic!(), + } + } + } + + #[test] + fn test_sample() { + let mut rand = Xoroshiro::from_seed(513513513); + assert_eq!(rand.next_i32(), 404174895); + + let (start, amplitudes) = OctavePerlinNoiseSampler::calculate_amplitudes(&[1, 2, 3]); + let mut rand_gen = RandomGenerator::Xoroshiro(rand); + let sampler = OctavePerlinNoiseSampler::new(&mut rand_gen, start, &litudes); + + let values = [ + ( + ( + 1.4633897801218182E8, + 3.360929121402108E8, + -1.7376184515043163E8, + ), + -0.16510137639683028, + ), + ( + ( + -3.952093942501234E8, + -8.149682915016855E7, + 2.0761709535397574E8, + ), + -0.19865227457826365, + ), + ( + ( + 1.0603518812861493E8, + -1.6028050039630303E8, + 9.621510690305333E7, + ), + -0.16157548492944798, + ), + ( + ( + -2.2789281609860754E8, + 1.2416505757723756E8, + -3.047619296454517E8, + ), + -0.05762575118540847, + ), + ( + ( + -1.6361322604690066E8, + -1.862652364900794E8, + 9.03458926538596E7, + ), + 0.21589404036742288, + ), + ( + ( + -1.6074718857061076E8, + -4.816551924254624E8, + -9.930236785759543E7, + ), + 0.1888188057014473, + ), + ( + ( + -1.6848478115907547E8, + 1.9495247771890038E8, + 1.3780564333313772E8, + ), + 0.23114508298896774, + ), + ( + ( + 2.5355640846261957E8, + -2.5973376726076955E8, + 3.7834594620459855E7, + ), + -0.23703473310230702, + ), + ( + ( + -8.636649828254433E7, + 1.7017680431584623E8, + 2.941033134334743E8, + ), + -0.14050102207739693, + ), + ( + ( + -4.573784466442647E8, + 1.789046617664721E8, + -5.515223967099891E8, + ), + -0.1422470544720957, + ), + ]; + + for ((x, y, z), sample) in values { + assert_eq!(sampler.sample(x, y, z), sample); + } + } +} + +#[cfg(test)] +mod perlin_noise_sampler_test { + use std::ops::Deref; + + use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; + + use crate::world_gen::noise::perlin::PerlinNoiseSampler; + + #[test] + fn test_create() { + let mut rand = Xoroshiro::from_seed(111); + assert_eq!(rand.next_i32(), -1467508761); + + let sampler = PerlinNoiseSampler::new(&mut rand); + assert_eq!(sampler.x_origin, 48.58072036717974); + assert_eq!(sampler.y_origin, 110.73235882678037); + assert_eq!(sampler.z_origin, 65.26438852860176); + + let permutation: [u8; 256] = [ + 159, 113, 41, 143, 203, 123, 95, 177, 25, 79, 229, 219, 194, 60, 130, 14, 83, 99, 24, + 202, 207, 232, 167, 152, 220, 201, 29, 235, 87, 147, 74, 160, 155, 97, 111, 31, 85, + 205, 115, 50, 13, 171, 77, 237, 149, 116, 209, 174, 169, 109, 221, 9, 166, 84, 54, 216, + 121, 106, 211, 16, 69, 244, 65, 192, 183, 146, 124, 37, 56, 45, 193, 158, 126, 217, 36, + 255, 162, 163, 230, 103, 63, 90, 191, 214, 20, 138, 32, 39, 238, 67, 64, 105, 250, 140, + 148, 114, 68, 75, 200, 161, 239, 125, 227, 199, 101, 61, 175, 107, 129, 240, 170, 51, + 139, 86, 186, 145, 212, 178, 30, 251, 89, 226, 120, 153, 47, 141, 233, 2, 179, 236, 1, + 19, 98, 21, 164, 108, 11, 23, 91, 204, 119, 88, 165, 195, 168, 26, 48, 206, 128, 6, 52, + 118, 110, 180, 197, 231, 117, 7, 3, 135, 224, 58, 82, 78, 4, 59, 222, 18, 72, 57, 150, + 43, 246, 100, 122, 112, 53, 133, 93, 17, 27, 210, 142, 234, 245, 80, 22, 46, 185, 172, + 71, 248, 33, 173, 76, 35, 40, 92, 228, 127, 254, 70, 42, 208, 73, 104, 187, 62, 154, + 243, 189, 241, 34, 66, 249, 94, 8, 12, 134, 132, 102, 242, 196, 218, 181, 28, 38, 15, + 151, 157, 247, 223, 198, 55, 188, 96, 0, 182, 49, 190, 156, 10, 215, 252, 131, 137, + 184, 176, 136, 81, 44, 213, 253, 144, 225, 5, + ]; + assert_eq!(sampler.permutation.deref(), permutation); + } + + #[test] + fn test_no_y() { + let mut rand = Xoroshiro::from_seed(111); + assert_eq!(rand.next_i32(), -1467508761); + let sampler = PerlinNoiseSampler::new(&mut rand); + + let values = [ + ( + ( + -3.134738528791615E8, + 5.676610095659718E7, + 2.011711832498507E8, + ), + 0.38582139614602945, + ), + ( + (-1369026.560586418, 3.957311252810864E8, 6.797037355570006E8), + 0.15777501333157193, + ), + ( + ( + 6.439373693833767E8, + -3.36218773041759E8, + -3.265494249695775E8, + ), + -0.2806135912409497, + ), + ( + ( + 1.353820060118252E8, + -3.204701624793043E8, + -4.612474746056331E8, + ), + -0.15052865500837787, + ), + ( + ( + -6906850.625560562, + 1.0153663948838013E8, + 2.4923185478305575E8, + ), + -0.3079300694558318, + ), + ( + ( + -7.108376621385525E7, + -2.029413580824217E8, + 2.5164602748045415E8, + ), + 0.03051312670440398, + ), + ( + ( + 1.0591429119126628E8, + -4.7911044364543396E8, + -2918719.2277242197, + ), + -0.11775123159138573, + ), + ( + ( + 4.04615501401398E7, + -3.074409286586152E8, + 5.089118769334092E7, + ), + 0.08763639340713025, + ), + ( + ( + -4.8645283544246924E8, + -3.922570151180015E8, + 2.3741632952563038E8, + ), + 0.08857245482456311, + ), + ( + ( + 2.861710031285905E8, + -1.8973201372718483E8, + -3.2653143323982143E8, + ), + -0.2378339698793312, + ), + ( + ( + 2.885407603819252E8, + -3.358708100884505E7, + -1.4480399660676318E8, + ), + -0.46661747461279457, + ), + ( + ( + 3.6548491156354237E8, + 7.995429702025633E7, + 2.509991661702412E8, + ), + 0.1671543972176835, + ), + ( + ( + 1.3298684552869435E8, + 3.6743804723880893E8, + 5.791092458225288E7, + ), + -0.2704070746642889, + ), + ( + ( + -1.3123184148036437E8, + -2.722300890805201E8, + 2.1601883778132245E7, + ), + 0.05049887915906969, + ), + ( + ( + -5.56047682304707E8, + 3.554803693060646E8, + 3.1647392358159083E8, + ), + -0.21178547899422662, + ), + ( + ( + 5.638216625134594E8, + -2.236907346192737E8, + -5.0562852022285646E8, + ), + 0.03351245780858128, + ), + ( + ( + -5.436956979127073E7, + -1.129261611506945E8, + -1.7909512156895646E8, + ), + 0.31670010349494726, + ), + ( + ( + 1.0915760091641709E8, + 1.932642099859593E7, + -3.405060533753616E8, + ), + -0.13987439655026918, + ), + ( + ( + -6.73911758014991E8, + -2.2147483413687566E8, + -4.531457195005102E7, + ), + 0.07824440437151846, + ), + ( + ( + -2.4827386778136212E8, + -2.6640208832089204E8, + -3.354675096522197E8, + ), + -0.2989735599541437, + ), + ]; + + for ((x, y, z), sample) in values { + assert_eq!(sampler.sample_flat_y(x, y, z), sample); + } + } + + #[test] + fn test_no_fade() { + let mut rand = Xoroshiro::from_seed(111); + assert_eq!(rand.next_i32(), -1467508761); + let sampler = PerlinNoiseSampler::new(&mut rand); + + let values = [ + ( + ( + -3.134738528791615E8, + 5.676610095659718E7, + 2.011711832498507E8, + -1369026.560586418, + 3.957311252810864E8, + ), + 23234.47859421248, + ), + ( + ( + 6.797037355570006E8, + 6.439373693833767E8, + -3.36218773041759E8, + -3.265494249695775E8, + 1.353820060118252E8, + ), + -0.016403984198221984, + ), + ( + ( + -3.204701624793043E8, + -4.612474746056331E8, + -6906850.625560562, + 1.0153663948838013E8, + 2.4923185478305575E8, + ), + 0.3444286491766397, + ), + ( + ( + -7.108376621385525E7, + -2.029413580824217E8, + 2.5164602748045415E8, + 1.0591429119126628E8, + -4.7911044364543396E8, + ), + 0.03051312670440398, + ), + ( + ( + -2918719.2277242197, + 4.04615501401398E7, + -3.074409286586152E8, + 5.089118769334092E7, + -4.8645283544246924E8, + ), + 0.3434020232968479, + ), + ( + ( + -3.922570151180015E8, + 2.3741632952563038E8, + 2.861710031285905E8, + -1.8973201372718483E8, + -3.2653143323982143E8, + ), + -0.07935517045771859, + ), + ( + ( + 2.885407603819252E8, + -3.358708100884505E7, + -1.4480399660676318E8, + 3.6548491156354237E8, + 7.995429702025633E7, + ), + -0.46661747461279457, + ), + ( + ( + 2.509991661702412E8, + 1.3298684552869435E8, + 3.6743804723880893E8, + 5.791092458225288E7, + -1.3123184148036437E8, + ), + 0.0723439870279631, + ), + ( + ( + -2.722300890805201E8, + 2.1601883778132245E7, + -5.56047682304707E8, + 3.554803693060646E8, + 3.1647392358159083E8, + ), + -0.656560662515624, + ), + ( + ( + 5.638216625134594E8, + -2.236907346192737E8, + -5.0562852022285646E8, + -5.436956979127073E7, + -1.129261611506945E8, + ), + 0.03351245780858128, + ), + ( + ( + -1.7909512156895646E8, + 1.0915760091641709E8, + 1.932642099859593E7, + -3.405060533753616E8, + -6.73911758014991E8, + ), + -0.2089142558681482, + ), + ( + ( + -2.2147483413687566E8, + -4.531457195005102E7, + -2.4827386778136212E8, + -2.6640208832089204E8, + -3.354675096522197E8, + ), + 0.38250837565598395, + ), + ( + ( + 3.618095500266467E8, + -1.785261966631494E8, + 8.855575989580283E7, + -1.3702508894700047E8, + -3.564818414428105E8, + ), + 0.00883370523171791, + ), + ( + ( + 3.585592594479808E7, + 1.8822208340571395E8, + -386327.524558296, + -2.613548000006699E8, + 1995562.4304017993, + ), + -0.27653878487738676, + ), + ( + ( + 3.0800276873619422E7, + 1.166750302259058E7, + 8.502636255675305E7, + 4.347409652503064E8, + 1.0678086363325526E8, + ), + -0.13800758751097497, + ), + ( + ( + -2.797805968820768E8, + 9.446376468140173E7, + 2.2821543438325477E8, + -4.8176550369786626E8, + 7.316871126959312E7, + ), + 0.05505478945301634, + ), + ( + ( + -2.236596113898912E7, + 1.5296478602495643E8, + 3.903966235164034E8, + 9.40479475527148E7, + 1.0948229366673347E8, + ), + 0.1158678618158655, + ), + ( + ( + 3.5342596632385695E8, + 3.1584773170834744E8, + -2.1860087172846535E8, + -1.8126626716239208E8, + -2.5263456116162892E7, + ), + -0.354953975313882, + ), + ( + ( + -1.2711958434031656E8, + -4.541988855460623E7, + -1.375878074907788E8, + 6.72693784001799E7, + 6815739.665531283, + ), + -0.23849179316215247, + ), + ( + ( + 1.2660906027019228E8, + -3.3769609799741164E7, + -3.4331505330046E8, + -6.663866659430536E7, + -1.6603843763414428E8, + ), + 0.07974650858448407, + ), + ]; + + for ((x, y, z, y_scale, y_max), sample) in values { + assert_eq!(sampler.sample_no_fade(x, y, z, y_scale, y_max), sample); + } + } +} diff --git a/pumpkin-world/src/world_gen/noise/simplex.rs b/pumpkin-world/src/world_gen/noise/simplex.rs new file mode 100644 index 00000000..8d6fba7f --- /dev/null +++ b/pumpkin-world/src/world_gen/noise/simplex.rs @@ -0,0 +1,702 @@ +use num_traits::Pow; +use pumpkin_core::random::{legacy_rand::LegacyRand, RandomImpl}; + +use super::{dot, GRADIENTS}; + +pub struct SimplexNoiseSampler { + permutation: Box<[u8]>, + x_origin: f64, + y_origin: f64, + z_origin: f64, +} + +impl SimplexNoiseSampler { + const SQRT_3: f64 = 1.7320508075688772f64; + const SKEW_FACTOR_2D: f64 = 0.5f64 * (Self::SQRT_3 - 1f64); + const UNSKEW_FACTOR_2D: f64 = (3f64 - Self::SQRT_3) / 6f64; + + pub fn new(random: &mut impl RandomImpl) -> Self { + let x_origin = random.next_f64() * 256f64; + let y_origin = random.next_f64() * 256f64; + let z_origin = random.next_f64() * 256f64; + + let mut permutation = [0u8; 256]; + + permutation + .iter_mut() + .enumerate() + .for_each(|(i, x)| *x = i as u8); + + for i in 0..256 { + let j = random.next_bounded_i32(256 - i) as usize; + permutation.swap(i as usize, i as usize + j); + } + + Self { + permutation: Box::new(permutation), + x_origin, + y_origin, + z_origin, + } + } + + fn map(&self, input: i32) -> i32 { + self.permutation[(input & 0xFF) as usize] as i32 + } + + fn grad(gradient_index: usize, x: f64, y: f64, z: f64, distance: f64) -> f64 { + let d = distance - x * x - y * y - z * z; + if d < 0f64 { + 0f64 + } else { + let d = d * d; + d * d * dot(&GRADIENTS[gradient_index], x, y, z) + } + } + + pub fn sample_2d(&self, x: f64, y: f64) -> f64 { + let d = (x + y) * Self::SKEW_FACTOR_2D; + let i = (x + d).floor() as i32; + let j = (y + d).floor() as i32; + + let e = (i.wrapping_add(j)) as f64 * Self::UNSKEW_FACTOR_2D; + let f = i as f64 - e; + let g = j as f64 - e; + + let h = x - f; + let k = y - g; + + let (l, m) = if h > k { (1, 0) } else { (0, 1) }; + + let n = h - l as f64 + Self::UNSKEW_FACTOR_2D; + let o = k - m as f64 + Self::UNSKEW_FACTOR_2D; + let p = h - 1f64 + 2f64 * Self::UNSKEW_FACTOR_2D; + let q = k - 1f64 + 2f64 * Self::UNSKEW_FACTOR_2D; + + let r = i & 0xFF; + let s = j & 0xFF; + + let t = self.map(r.wrapping_add(self.map(s))) % 12; + let u = self.map(r.wrapping_add(l).wrapping_add(self.map(s.wrapping_add(m)))) % 12; + let v = self.map(r.wrapping_add(1).wrapping_add(self.map(s.wrapping_add(1)))) % 12; + + let w = Self::grad(t as usize, h, k, 0f64, 0.5f64); + let z = Self::grad(u as usize, n, o, 0f64, 0.5f64); + let aa = Self::grad(v as usize, p, q, 0f64, 0.5f64); + + 70f64 * (w + z + aa) + } + + pub fn sample_3d(&self, x: f64, y: f64, z: f64) -> f64 { + let e = (x + y + z) * 0.3333333333333333f64; + + let i = (x + e).floor() as i32; + let j = (y + e).floor() as i32; + let k = (z + e).floor() as i32; + + let g = (i.wrapping_add(j).wrapping_add(k)) as f64 * 0.16666666666666666f64; + let h = i as f64 - g; + let l = j as f64 - g; + let m = k as f64 - g; + + let n = x - h; + let o = y - l; + let p = z - m; + + let (q, r, s, t, u, v) = if n >= o { + if o >= p { + (1, 0, 0, 1, 1, 0) + } else if n >= p { + (1, 0, 0, 1, 0, 1) + } else { + (0, 0, 1, 1, 0, 1) + } + } else if o < p { + (0, 0, 1, 0, 1, 1) + } else if n < p { + (0, 1, 0, 0, 1, 1) + } else { + (0, 1, 0, 1, 1, 0) + }; + + let w = n - q as f64 + 0.16666666666666666f64; + let aa = o - r as f64 + 0.16666666666666666f64; + let ab = p - s as f64 + 0.16666666666666666f64; + + let ac = n - t as f64 + 0.3333333333333333f64; + let ad = o - u as f64 + 0.3333333333333333f64; + let ae = p - v as f64 + 0.3333333333333333f64; + + let af = n - 1f64 + 0.5f64; + let ag = o - 1f64 + 0.5f64; + let ah = p - 1f64 + 0.5f64; + + let ai = i & 0xFF; + let aj = j & 0xFF; + let ak = k & 0xFF; + + let al = self.map(ai.wrapping_add(self.map(aj.wrapping_add(self.map(ak))))) % 12; + let am = self.map( + ai.wrapping_add(q).wrapping_add( + self.map( + aj.wrapping_add(r) + .wrapping_add(self.map(ak.wrapping_add(s))), + ), + ), + ) % 12; + let an = self.map( + ai.wrapping_add(t).wrapping_add( + self.map( + aj.wrapping_add(u) + .wrapping_add(self.map(ak.wrapping_add(v))), + ), + ), + ) % 12; + let ao = self.map( + ai.wrapping_add(1).wrapping_add( + self.map( + aj.wrapping_add(1) + .wrapping_add(self.map(ak.wrapping_add(1))), + ), + ), + ) % 12; + + let ap = Self::grad(al as usize, n, o, p, 0.6f64); + let aq = Self::grad(am as usize, w, aa, ab, 0.6f64); + let ar = Self::grad(an as usize, ac, ad, ae, 0.6f64); + let az = Self::grad(ao as usize, af, ag, ah, 0.6f64); + + 32f64 * (ap + aq + ar + az) + } +} + +pub struct OctaveSimplexNoiseSampler { + octave_samplers: Vec>, + persistence: f64, + lacunarity: f64, +} + +impl OctaveSimplexNoiseSampler { + pub fn new(random: &mut impl RandomImpl, octaves: &[i32]) -> Self { + let mut octaves = Vec::from_iter(octaves); + octaves.sort(); + + let i = -**octaves.first().expect("Should have some octaves"); + let j = **octaves.last().expect("Should have some octaves"); + let k = i.wrapping_add(j).wrapping_add(1); + + let sampler = SimplexNoiseSampler::new(random); + let l = j; + let mut samplers: Vec> = Vec::with_capacity(k as usize); + for _ in 0..k { + samplers.push(None); + } + + for m in (j + 1)..k { + if m >= 0 && octaves.contains(&&(l - m)) { + let sampler = SimplexNoiseSampler::new(random); + samplers[m as usize] = Some(sampler); + } else { + random.skip(262); + } + } + + if j > 0 { + let sample = sampler.sample_3d(sampler.x_origin, sampler.y_origin, sampler.z_origin); + let n = (sample * 9.223372E18f32 as f64) as i64; + let mut random = LegacyRand::from_seed(n as u64); + + for o in (0..=(l - 1)).rev() { + if o < k && octaves.contains(&&(l - o)) { + let sampler = SimplexNoiseSampler::new(&mut random); + samplers[o as usize] = Some(sampler); + } else { + random.skip(262); + } + } + } + + if j >= 0 && j < k && octaves.contains(&&0) { + samplers[j as usize] = Some(sampler); + } + + Self { + octave_samplers: samplers, + persistence: 1f64 / (2f64.pow(k) - 1f64), + lacunarity: 2f64.pow(j), + } + } + + pub fn sample(&self, x: f64, y: f64, use_origin: bool) -> f64 { + let mut d = 0f64; + let mut e = self.lacunarity; + let mut f = self.persistence; + + for sampler in self.octave_samplers.iter() { + if let Some(sampler) = sampler { + d += sampler.sample_2d( + x * e + if use_origin { sampler.x_origin } else { 0f64 }, + y * e + if use_origin { sampler.y_origin } else { 0f64 }, + ) * f; + } + + e /= 2f64; + f *= 2f64; + } + + d + } +} + +#[cfg(test)] +mod octave_simplex_noise_sampler_test { + use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; + + use crate::world_gen::noise::simplex::OctaveSimplexNoiseSampler; + + #[test] + fn test_new() { + let mut rand = Xoroshiro::from_seed(450); + assert_eq!(rand.next_i32(), 1394613419); + let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]); + + assert_eq!(sampler.lacunarity, 2f64); + assert_eq!(sampler.persistence, 0.14285714285714285); + + let values = [ + (33.48154133535127, 200.15584029786743, 239.82697852863149), + (115.65071632913913, 5.88805286077266, 184.4887403898897), + (64.69791492580848, 19.256055216755044, 97.01795462351956), + ]; + + assert_eq!(values.len(), sampler.octave_samplers.len()); + for (sampler, (x, y, z)) in sampler.octave_samplers.iter().zip(values) { + match sampler { + Some(sampler) => { + assert_eq!(sampler.x_origin, x); + assert_eq!(sampler.y_origin, y); + assert_eq!(sampler.z_origin, z); + } + None => panic!(), + } + } + } + + #[test] + fn test_sample() { + let mut rand = Xoroshiro::from_seed(450); + assert_eq!(rand.next_i32(), 1394613419); + let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]); + + let values_1 = [ + ( + (-1.3127900550351206E7, 792897.4979227383), + -0.4321152413690901, + ), + ( + (-1.6920637874404985E7, -2.7155569346339065E8), + -0.5262902093081003, + ), + ( + (4.3144247722741723E8, 5.681942883881191E8), + 0.11591369897395602, + ), + ( + (1.4302738270336467E8, -1.4548998886244193E8), + -0.3879951077548365, + ), + ( + (-3.9028350711219925E8, -5.213995559811158E7), + -0.7540785159288218, + ), + ( + (-1.3442750163759476E8, -6.725465365393716E8), + 0.31442035977402105, + ), + ( + (-1.1937282161424601E8, 3.2134650034986335E8), + 0.28218849676360336, + ), + ( + (-3.128475507865152E8, -3.014112871163455E8), + 0.593770404657594, + ), + ( + (1.2027011883589141E8, -5.045175636913682E8), + -0.2893240282016911, + ), + ( + (-9.065155753781198E7, 6106991.342893547), + -0.3402301205344082, + ), + ]; + + for ((x, y), sample) in values_1 { + assert_eq!(sampler.sample(x, y, false), sample); + } + + let values_2 = [ + ( + (-1.3127900550351206E7, 792897.4979227383), + 0.21834818545873672, + ), + ( + (-1.6920637874404985E7, -2.7155569346339065E8), + 0.025042742676442978, + ), + ( + (4.3144247722741723E8, 5.681942883881191E8), + 0.3738693783591451, + ), + ( + (1.4302738270336467E8, -1.4548998886244193E8), + -0.023113657524218345, + ), + ( + (-3.9028350711219925E8, -5.213995559811158E7), + 0.5195582376240916, + ), + ( + (-1.3442750163759476E8, -6.725465365393716E8), + 0.020366186088347903, + ), + ( + (-1.1937282161424601E8, 3.2134650034986335E8), + -0.10921072611129382, + ), + ( + (-3.128475507865152E8, -3.014112871163455E8), + 0.18066933648141983, + ), + ( + (1.2027011883589141E8, -5.045175636913682E8), + -0.36788084946294336, + ), + ( + (-9.065155753781198E7, 6106991.342893547), + -0.5677921377363926, + ), + ]; + + for ((x, y), sample) in values_2 { + assert_eq!(sampler.sample(x, y, true), sample); + } + } +} +#[cfg(test)] +mod simplex_noise_sampler_test { + use std::ops::Deref; + + use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; + + use crate::world_gen::noise::simplex::SimplexNoiseSampler; + + #[test] + fn test_create() { + let mut rand = Xoroshiro::from_seed(111); + assert_eq!(rand.next_i32(), -1467508761); + let sampler = SimplexNoiseSampler::new(&mut rand); + assert_eq!(sampler.x_origin, 48.58072036717974f64); + assert_eq!(sampler.y_origin, 110.73235882678037f64); + assert_eq!(sampler.z_origin, 65.26438852860176f64); + + let permutation: [u8; 256] = [ + 159, 113, 41, 143, 203, 123, 95, 177, 25, 79, 229, 219, 194, 60, 130, 14, 83, 99, 24, + 202, 207, 232, 167, 152, 220, 201, 29, 235, 87, 147, 74, 160, 155, 97, 111, 31, 85, + 205, 115, 50, 13, 171, 77, 237, 149, 116, 209, 174, 169, 109, 221, 9, 166, 84, 54, 216, + 121, 106, 211, 16, 69, 244, 65, 192, 183, 146, 124, 37, 56, 45, 193, 158, 126, 217, 36, + 255, 162, 163, 230, 103, 63, 90, 191, 214, 20, 138, 32, 39, 238, 67, 64, 105, 250, 140, + 148, 114, 68, 75, 200, 161, 239, 125, 227, 199, 101, 61, 175, 107, 129, 240, 170, 51, + 139, 86, 186, 145, 212, 178, 30, 251, 89, 226, 120, 153, 47, 141, 233, 2, 179, 236, 1, + 19, 98, 21, 164, 108, 11, 23, 91, 204, 119, 88, 165, 195, 168, 26, 48, 206, 128, 6, 52, + 118, 110, 180, 197, 231, 117, 7, 3, 135, 224, 58, 82, 78, 4, 59, 222, 18, 72, 57, 150, + 43, 246, 100, 122, 112, 53, 133, 93, 17, 27, 210, 142, 234, 245, 80, 22, 46, 185, 172, + 71, 248, 33, 173, 76, 35, 40, 92, 228, 127, 254, 70, 42, 208, 73, 104, 187, 62, 154, + 243, 189, 241, 34, 66, 249, 94, 8, 12, 134, 132, 102, 242, 196, 218, 181, 28, 38, 15, + 151, 157, 247, 223, 198, 55, 188, 96, 0, 182, 49, 190, 156, 10, 215, 252, 131, 137, + 184, 176, 136, 81, 44, 213, 253, 144, 225, 5, + ]; + assert_eq!(sampler.permutation.deref(), permutation); + } + + #[test] + fn test_sample_2d() { + let data1 = [ + ((-50000, 0), -0.013008608535752102), + ((-49999, 1000), 0.0), + ((-49998, 2000), -0.03787856584046271), + ((-49997, 3000), 0.0), + ((-49996, 4000), 0.5015373706471664), + ((-49995, 5000), -0.032797908620906514), + ((-49994, 6000), -0.19158655563621785), + ((-49993, 7000), 0.49893473629544977), + ((-49992, 8000), 0.31585737840402556), + ((-49991, 9000), 0.43909577227435836), + ]; + + let data2 = [ + ( + (-3.134738528791615E8, 5.676610095659718E7), + 0.018940199193618792, + ), + ( + (-1369026.560586418, 3.957311252810864E8), + -0.1417598930091471, + ), + ( + (6.439373693833767E8, -3.36218773041759E8), + 0.07129176668335062, + ), + ( + (1.353820060118252E8, -3.204701624793043E8), + 0.330648835988156, + ), + ( + (-6906850.625560562, 1.0153663948838013E8), + 0.46826928755778685, + ), + ( + (-7.108376621385525E7, -2.029413580824217E8), + -0.515950097501492, + ), + ( + (1.0591429119126628E8, -4.7911044364543396E8), + -0.5467822192664874, + ), + ( + (4.04615501401398E7, -3.074409286586152E8), + 0.7470460844090322, + ), + ( + (-4.8645283544246924E8, -3.922570151180015E8), + 0.8521699147242563, + ), + ( + (2.861710031285905E8, -1.8973201372718483E8), + 0.1889297962671115, + ), + ( + (2.885407603819252E8, -3.358708100884505E7), + 0.24006029504945695, + ), + ( + (3.6548491156354237E8, 7.995429702025633E7), + -0.8114171447379924, + ), + ( + (1.3298684552869435E8, 3.6743804723880893E8), + 0.07042306408164949, + ), + ( + (-1.3123184148036437E8, -2.722300890805201E8), + 0.5093850689193259, + ), + ( + (-5.56047682304707E8, 3.554803693060646E8), + -0.6343788467687929, + ), + ( + (5.638216625134594E8, -2.236907346192737E8), + 0.5848746152449286, + ), + ( + (-5.436956979127073E7, -1.129261611506945E8), + -0.05456282199582522, + ), + ( + (1.0915760091641709E8, 1.932642099859593E7), + -0.273739377096594, + ), + ( + (-6.73911758014991E8, -2.2147483413687566E8), + 0.05464681163741797, + ), + ( + (-2.4827386778136212E8, -2.6640208832089204E8), + -0.0902449424742273, + ), + ]; + + let mut rand = Xoroshiro::from_seed(111); + assert_eq!(rand.next_i32(), -1467508761); + + let sampler = SimplexNoiseSampler::new(&mut rand); + for ((x, y), sample) in data1 { + assert_eq!(sampler.sample_2d(x as f64, y as f64), sample); + } + + for ((x, y), sample) in data2 { + assert_eq!(sampler.sample_2d(x, y), sample); + } + } + + #[test] + fn test_sample_3d() { + let data = [ + ( + ( + -3.134738528791615E8, + 5.676610095659718E7, + 2.011711832498507E8, + ), + -0.07626353895981935, + ), + ( + (-1369026.560586418, 3.957311252810864E8, 6.797037355570006E8), + 0.0, + ), + ( + ( + 6.439373693833767E8, + -3.36218773041759E8, + -3.265494249695775E8, + ), + -0.5919400355725402, + ), + ( + ( + 1.353820060118252E8, + -3.204701624793043E8, + -4.612474746056331E8, + ), + -0.5220477236433517, + ), + ( + ( + -6906850.625560562, + 1.0153663948838013E8, + 2.4923185478305575E8, + ), + -0.39146687767898636, + ), + ( + ( + -7.108376621385525E7, + -2.029413580824217E8, + 2.5164602748045415E8, + ), + -0.629386846329711, + ), + ( + ( + 1.0591429119126628E8, + -4.7911044364543396E8, + -2918719.2277242197, + ), + 0.5427502531663232, + ), + ( + ( + 4.04615501401398E7, + -3.074409286586152E8, + 5.089118769334092E7, + ), + -0.4273080639878097, + ), + ( + ( + -4.8645283544246924E8, + -3.922570151180015E8, + 2.3741632952563038E8, + ), + 0.32129944093252394, + ), + ( + ( + 2.861710031285905E8, + -1.8973201372718483E8, + -3.2653143323982143E8, + ), + 0.35839032946039706, + ), + ( + ( + 2.885407603819252E8, + -3.358708100884505E7, + -1.4480399660676318E8, + ), + -0.02451312935907038, + ), + ( + ( + 3.6548491156354237E8, + 7.995429702025633E7, + 2.509991661702412E8, + ), + -0.36830526266318003, + ), + ( + ( + 1.3298684552869435E8, + 3.6743804723880893E8, + 5.791092458225288E7, + ), + -0.023683302916542803, + ), + ( + ( + -1.3123184148036437E8, + -2.722300890805201E8, + 2.1601883778132245E7, + ), + -0.261629562325043, + ), + ( + ( + -5.56047682304707E8, + 3.554803693060646E8, + 3.1647392358159083E8, + ), + -0.4959372930161496, + ), + ( + ( + 5.638216625134594E8, + -2.236907346192737E8, + -5.0562852022285646E8, + ), + -0.06079315675880484, + ), + ( + ( + -5.436956979127073E7, + -1.129261611506945E8, + -1.7909512156895646E8, + ), + -0.37726907424345196, + ), + ( + ( + 1.0915760091641709E8, + 1.932642099859593E7, + -3.405060533753616E8, + ), + 0.37747828159811136, + ), + ( + ( + -6.73911758014991E8, + -2.2147483413687566E8, + -4.531457195005102E7, + ), + -0.32929020207000603, + ), + ( + ( + -2.4827386778136212E8, + -2.6640208832089204E8, + -3.354675096522197E8, + ), + -0.3046390200444667, + ), + ]; + + let mut rand = Xoroshiro::from_seed(111); + assert_eq!(rand.next_i32(), -1467508761); + + let sampler = SimplexNoiseSampler::new(&mut rand); + for ((x, y, z), sample) in data { + assert_eq!(sampler.sample_3d(x, y, z), sample); + } + } +}