From 4c8fa33b23e3dc0fad51bee79083c1a41b128b9e Mon Sep 17 00:00:00 2001 From: kralverde Date: Tue, 10 Sep 2024 18:55:53 -0400 Subject: [PATCH 1/9] start work on noise for chunk generation --- pumpkin-world/src/world_gen/mod.rs | 6 + pumpkin-world/src/world_gen/noise.rs | 1158 ++++++++++++++++++++++++++ 2 files changed, 1164 insertions(+) create mode 100644 pumpkin-world/src/world_gen/noise.rs diff --git a/pumpkin-world/src/world_gen/mod.rs b/pumpkin-world/src/world_gen/mod.rs index ddb1bbb9e..db5470680 100644 --- a/pumpkin-world/src/world_gen/mod.rs +++ b/pumpkin-world/src/world_gen/mod.rs @@ -1,10 +1,12 @@ mod generator; mod generic_generator; mod implementation; +mod noise; mod seed; pub use generator::WorldGenerator; use implementation::overworld::biome::plains::PlainsGenerator; +use pumpkin_core::random::Random; pub use seed::Seed; use generator::GeneratorInit; @@ -13,3 +15,7 @@ pub fn get_world_gen(seed: Seed) -> Box { // TODO decide which WorldGenerator to pick based on config. Box::new(PlainsGenerator::new(seed)) } + +pub struct ChunkRandom { + sample_count: i32, +} diff --git a/pumpkin-world/src/world_gen/noise.rs b/pumpkin-world/src/world_gen/noise.rs new file mode 100644 index 000000000..647f4462d --- /dev/null +++ b/pumpkin-world/src/world_gen/noise.rs @@ -0,0 +1,1158 @@ +use pumpkin_core::random::Random; + +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), + ) +} + +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, +} + +pub struct SimplexNoiseSampler { + permutation: Box<[u8]>, + x_origin: f64, + y_origin: f64, + z_origin: f64, +} + +impl SimplexNoiseSampler { + 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 }, + ]; + + const SQRT_3: f64 = 1.732050807568877293527446341505872367f64; + 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 Random) -> 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, + } + } + + fn map(&self, input: i32) -> i32 { + self.permutation[(input & 0xFF) as usize] as i32 + } + + 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 + } + + 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 * Self::dot(&Self::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 + 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 PerlinNoiseSampler { + permutation: Box<[u8]>, + x_origin: f64, + y_origin: f64, + z_origin: f64, +} + +impl PerlinNoiseSampler { + pub fn new(random: &mut impl Random) -> 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 { + SimplexNoiseSampler::dot( + &SimplexNoiseSampler::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] & 0xFF) 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) + } +} + +struct OctavePerlinNoiseSampler { + octave_samplers: Box<[SimplexNoiseSampler]>, + persistence: f64, + lacunarity: f64, +} + +impl OctavePerlinNoiseSampler { + pub fn new(random: &mut impl Random, 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![]; + + if j >= 0 && j < k && octaves.contains(&&0) { + samplers[0] = sampler; + } + + for m in (j + 1)..k { + if m >= 0 && octaves.contains(&&(l - m)) { + samplers[m as usize] = SimplexNoiseSampler::new(random); + } else { + random.skip(262); + } + } + + if j > 0 { + let n = (sampler.sample_3d(sampler.x_origin, sampler.y_origin, sampler.z_origin) + * 9.223372E18f32 as f64) as i64; + } + } +} + +#[cfg(test)] +mod simplex_noise_sampler_test { + use std::ops::Deref; + + use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + + use crate::world_gen::noise::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); + } + } +} + +#[cfg(test)] +mod perlin_noise_sampler_test { + use std::ops::Deref; + + use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + + use crate::world_gen::noise::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); + } + } +} From 987d2cf87e5dd439ef253b8613e3654c2807020f Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 11 Sep 2024 13:44:28 -0400 Subject: [PATCH 2/9] continue implementation of noise --- pumpkin-core/src/random/legacy_rand.rs | 19 ++- pumpkin-world/src/world_gen/mod.rs | 1 - pumpkin-world/src/world_gen/noise.rs | 203 +++++++++++++++++++++++-- 3 files changed, 205 insertions(+), 18 deletions(-) diff --git a/pumpkin-core/src/random/legacy_rand.rs b/pumpkin-core/src/random/legacy_rand.rs index f7f60ff41..2360ab5ca 100644 --- a/pumpkin-core/src/random/legacy_rand.rs +++ b/pumpkin-core/src/random/legacy_rand.rs @@ -2,7 +2,7 @@ use super::{ gaussian::GaussianGenerator, hash_block_pos, java_string_hash, Random, RandomSplitter, }; -struct LegacyRand { +pub struct LegacyRand { seed: u64, internal_next_gaussian: f64, internal_has_next_gaussian: bool, @@ -86,13 +86,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; } } @@ -163,6 +163,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-world/src/world_gen/mod.rs b/pumpkin-world/src/world_gen/mod.rs index db5470680..693132f5c 100644 --- a/pumpkin-world/src/world_gen/mod.rs +++ b/pumpkin-world/src/world_gen/mod.rs @@ -6,7 +6,6 @@ mod seed; pub use generator::WorldGenerator; use implementation::overworld::biome::plains::PlainsGenerator; -use pumpkin_core::random::Random; pub use seed::Seed; use generator::GeneratorInit; diff --git a/pumpkin-world/src/world_gen/noise.rs b/pumpkin-world/src/world_gen/noise.rs index 647f4462d..0f9fc0f33 100644 --- a/pumpkin-world/src/world_gen/noise.rs +++ b/pumpkin-world/src/world_gen/noise.rs @@ -1,4 +1,5 @@ -use pumpkin_core::random::Random; +use num_traits::Pow; +use pumpkin_core::random::{legacy_rand::LegacyRand, Random}; pub fn lerp(delta: f64, start: f64, end: f64) -> f64 { start + delta * (end - start) @@ -65,7 +66,7 @@ impl SimplexNoiseSampler { Gradient { x: 0, y: -1, z: -1 }, ]; - const SQRT_3: f64 = 1.732050807568877293527446341505872367f64; + 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; @@ -82,8 +83,8 @@ impl SimplexNoiseSampler { .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); + let j = random.next_bounded_i32(256 - i) as usize; + permutation.swap(i as usize, i as usize + j); } Self { @@ -134,7 +135,7 @@ impl SimplexNoiseSampler { let r = i & 0xFF; let s = j & 0xFF; - let t = self.map(r + self.map(s)) % 12; + 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; @@ -380,7 +381,7 @@ impl PerlinNoiseSampler { } struct OctavePerlinNoiseSampler { - octave_samplers: Box<[SimplexNoiseSampler]>, + octave_samplers: Vec>, persistence: f64, lacunarity: f64, } @@ -396,23 +397,199 @@ impl OctavePerlinNoiseSampler { let sampler = SimplexNoiseSampler::new(random); let l = j; - let mut samplers: Vec = vec![]; - - if j >= 0 && j < k && octaves.contains(&&0) { - samplers[0] = sampler; + 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)) { - samplers[m as usize] = SimplexNoiseSampler::new(random); + let sampler = SimplexNoiseSampler::new(random); + samplers[m as usize] = Some(sampler); } else { random.skip(262); } } if j > 0 { - let n = (sampler.sample_3d(sampler.x_origin, sampler.y_origin, sampler.z_origin) - * 9.223372E18f32 as f64) as i64; + 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_perlin_noise_sampler_test { + use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + + use crate::world_gen::noise::OctavePerlinNoiseSampler; + + #[test] + fn test_new() { + let mut rand = Xoroshiro::from_seed(450); + assert_eq!(rand.next_i32(), 1394613419); + let sampler = OctavePerlinNoiseSampler::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 = OctavePerlinNoiseSampler::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); } } } From e49c46df322195c306fa232fe7befc8ebd192b3d Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 11 Sep 2024 17:37:12 -0400 Subject: [PATCH 3/9] split code up --- pumpkin-world/src/world_gen/mod.rs | 4 - pumpkin-world/src/world_gen/noise/mod.rs | 63 ++ pumpkin-world/src/world_gen/noise/perlin.rs | 571 +++++++++++++++ .../world_gen/{noise.rs => noise/simplex.rs} | 651 +----------------- 4 files changed, 643 insertions(+), 646 deletions(-) create mode 100644 pumpkin-world/src/world_gen/noise/mod.rs create mode 100644 pumpkin-world/src/world_gen/noise/perlin.rs rename pumpkin-world/src/world_gen/{noise.rs => noise/simplex.rs} (52%) diff --git a/pumpkin-world/src/world_gen/mod.rs b/pumpkin-world/src/world_gen/mod.rs index 693132f5c..4712a36f3 100644 --- a/pumpkin-world/src/world_gen/mod.rs +++ b/pumpkin-world/src/world_gen/mod.rs @@ -14,7 +14,3 @@ pub fn get_world_gen(seed: Seed) -> Box { // TODO decide which WorldGenerator to pick based on config. Box::new(PlainsGenerator::new(seed)) } - -pub struct ChunkRandom { - sample_count: i32, -} 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 000000000..206a47a30 --- /dev/null +++ b/pumpkin-world/src/world_gen/noise/mod.rs @@ -0,0 +1,63 @@ +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), + ) +} + +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 000000000..a39caa6bc --- /dev/null +++ b/pumpkin-world/src/world_gen/noise/perlin.rs @@ -0,0 +1,571 @@ +use pumpkin_core::random::Random; + +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 Random) -> 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] & 0xFF) 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) + } +} + +#[cfg(test)] +mod perlin_noise_sampler_test { + use std::ops::Deref; + + use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + + 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.rs b/pumpkin-world/src/world_gen/noise/simplex.rs similarity index 52% rename from pumpkin-world/src/world_gen/noise.rs rename to pumpkin-world/src/world_gen/noise/simplex.rs index 0f9fc0f33..6c4567007 100644 --- a/pumpkin-world/src/world_gen/noise.rs +++ b/pumpkin-world/src/world_gen/noise/simplex.rs @@ -1,43 +1,7 @@ use num_traits::Pow; use pumpkin_core::random::{legacy_rand::LegacyRand, Random}; -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), - ) -} - -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, -} +use super::{dot, GRADIENTS}; pub struct SimplexNoiseSampler { permutation: Box<[u8]>, @@ -47,25 +11,6 @@ pub struct SimplexNoiseSampler { } impl SimplexNoiseSampler { - 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 }, - ]; - 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; @@ -99,17 +44,13 @@ impl SimplexNoiseSampler { self.permutation[(input & 0xFF) as usize] as i32 } - 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 - } - 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 * Self::dot(&Self::GRADIENTS[gradient_index], x, y, z) + d * d * dot(&GRADIENTS[gradient_index], x, y, z) } } @@ -229,164 +170,13 @@ impl SimplexNoiseSampler { } } -pub struct PerlinNoiseSampler { - permutation: Box<[u8]>, - x_origin: f64, - y_origin: f64, - z_origin: f64, -} - -impl PerlinNoiseSampler { - pub fn new(random: &mut impl Random) -> 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 { - SimplexNoiseSampler::dot( - &SimplexNoiseSampler::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] & 0xFF) 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) - } -} - -struct OctavePerlinNoiseSampler { +pub struct OctaveSimplexNoiseSampler { octave_samplers: Vec>, persistence: f64, lacunarity: f64, } -impl OctavePerlinNoiseSampler { +impl OctaveSimplexNoiseSampler { pub fn new(random: &mut impl Random, octaves: &[i32]) -> Self { let mut octaves = Vec::from_iter(octaves); octaves.sort(); @@ -459,16 +249,16 @@ impl OctavePerlinNoiseSampler { } #[cfg(test)] -mod octave_perlin_noise_sampler_test { +mod octave_simplex_noise_sampler_test { use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; - use crate::world_gen::noise::OctavePerlinNoiseSampler; + 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 = OctavePerlinNoiseSampler::new(&mut rand, &[-1, 1, 0]); + let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]); assert_eq!(sampler.lacunarity, 2f64); assert_eq!(sampler.persistence, 0.14285714285714285); @@ -496,7 +286,7 @@ mod octave_perlin_noise_sampler_test { fn test_sample() { let mut rand = Xoroshiro::from_seed(450); assert_eq!(rand.next_i32(), 1394613419); - let sampler = OctavePerlinNoiseSampler::new(&mut rand, &[-1, 1, 0]); + let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]); let values_1 = [ ( @@ -593,14 +383,13 @@ mod octave_perlin_noise_sampler_test { } } } - #[cfg(test)] mod simplex_noise_sampler_test { use std::ops::Deref; use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; - use crate::world_gen::noise::SimplexNoiseSampler; + use crate::world_gen::noise::simplex::SimplexNoiseSampler; #[test] fn test_create() { @@ -911,425 +700,3 @@ mod simplex_noise_sampler_test { } } } - -#[cfg(test)] -mod perlin_noise_sampler_test { - use std::ops::Deref; - - use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; - - use crate::world_gen::noise::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); - } - } -} From a9031e48f9d1a8c5410e38f0d89f766e3ff49d69 Mon Sep 17 00:00:00 2001 From: kralverde Date: Wed, 11 Sep 2024 23:22:00 -0400 Subject: [PATCH 4/9] implement octave perlin noise sampler --- pumpkin-world/src/world_gen/noise/perlin.rs | 246 +++++++++++++++++++- 1 file changed, 245 insertions(+), 1 deletion(-) diff --git a/pumpkin-world/src/world_gen/noise/perlin.rs b/pumpkin-world/src/world_gen/noise/perlin.rs index a39caa6bc..7cfd2cb96 100644 --- a/pumpkin-world/src/world_gen/noise/perlin.rs +++ b/pumpkin-world/src/world_gen/noise/perlin.rs @@ -1,4 +1,5 @@ -use pumpkin_core::random::Random; +use num_traits::{Pow, WrappingSub}; +use pumpkin_core::random::{Random, RandomSplitter}; use super::{dot, lerp3, GRADIENTS}; @@ -148,6 +149,249 @@ impl PerlinNoiseSampler { } } +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: &Vec) -> f64 { + let mut d = 0f64; + let mut e = persistence; + + for amplitude in amplitudes.iter() { + if *amplitude != 0f64 { + 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 impl Random, first_octave: i32, amplitudes: Vec) -> Self { + let i = amplitudes.len(); + let j = -first_octave; + + let mut samplers: Vec> = Vec::with_capacity(i); + for _ in 0..i { + samplers.push(None); + } + + 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)), + )); + } + } + + 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, &litudes); + Self { + octave_samplers: samplers, + amplitudes, + 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 + } +} + +#[cfg(test)] +mod octave_perline_noise_sampler_test { + use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + + 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 sampler = OctavePerlinNoiseSampler::new(&mut rand, start, amplitudes); + + 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_sample() { + let mut rand = Xoroshiro::from_seed(513513513); + assert_eq!(rand.next_i32(), 404174895); + + let (start, amplitudes) = OctavePerlinNoiseSampler::calculate_amplitudes(&[1, 2, 3]); + let sampler = OctavePerlinNoiseSampler::new(&mut rand, start, amplitudes); + + 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; From c34b5db03adc8421125f92f2942e2b3f5959c18b Mon Sep 17 00:00:00 2001 From: kralverde Date: Thu, 12 Sep 2024 21:50:48 -0400 Subject: [PATCH 5/9] add double noise generator and clean up code --- pumpkin-world/src/world_gen/noise/mod.rs | 2 + pumpkin-world/src/world_gen/noise/perlin.rs | 361 ++++++++++++++++++- pumpkin-world/src/world_gen/noise/simplex.rs | 3 + 3 files changed, 349 insertions(+), 17 deletions(-) diff --git a/pumpkin-world/src/world_gen/noise/mod.rs b/pumpkin-world/src/world_gen/noise/mod.rs index 206a47a30..106a38f3b 100644 --- a/pumpkin-world/src/world_gen/noise/mod.rs +++ b/pumpkin-world/src/world_gen/noise/mod.rs @@ -13,6 +13,8 @@ pub fn lerp2(delta_x: f64, delta_y: f64, x0y0: f64, x1y0: f64, x0y1: f64, x1y1: ) } +#[allow(dead_code)] +#[allow(clippy::too_many_arguments)] pub fn lerp3( delta_x: f64, delta_y: f64, diff --git a/pumpkin-world/src/world_gen/noise/perlin.rs b/pumpkin-world/src/world_gen/noise/perlin.rs index 7cfd2cb96..e1c92bf88 100644 --- a/pumpkin-world/src/world_gen/noise/perlin.rs +++ b/pumpkin-world/src/world_gen/noise/perlin.rs @@ -1,5 +1,8 @@ -use num_traits::{Pow, WrappingSub}; -use pumpkin_core::random::{Random, RandomSplitter}; +use itertools::Itertools; +use num_traits::{Pow, Zero}; +use pumpkin_core::random::{ + legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, Random, RandomSplitter, +}; use super::{dot, lerp3, GRADIENTS}; @@ -36,6 +39,7 @@ impl PerlinNoiseSampler { } } + #[allow(dead_code)] pub fn sample_flat_y(&self, x: f64, y: f64, z: f64) -> f64 { self.sample_no_fade(x, y, z, 0f64, 0f64) } @@ -76,7 +80,7 @@ impl PerlinNoiseSampler { } fn map(&self, input: i32) -> i32 { - (self.permutation[(input & 0xFF) as usize] & 0xFF) as i32 + self.permutation[(input & 0xFF) as usize] as i32 } #[allow(clippy::too_many_arguments)] @@ -149,9 +153,16 @@ impl PerlinNoiseSampler { } } +#[allow(dead_code)] +pub enum RandomGenerator<'a> { + Xoroshiro(&'a mut Xoroshiro), + Legacy(&'a mut LegacyRand), +} + pub struct OctavePerlinNoiseSampler { octave_samplers: Vec>, amplitudes: Vec, + #[allow(dead_code)] first_octave: i32, persistence: f64, lacunarity: f64, @@ -159,7 +170,7 @@ pub struct OctavePerlinNoiseSampler { } impl OctavePerlinNoiseSampler { - fn get_total_amplitude(scale: f64, persistence: f64, amplitudes: &Vec) -> f64 { + fn get_total_amplitude(scale: f64, persistence: f64, amplitudes: &[f64]) -> f64 { let mut d = 0f64; let mut e = persistence; @@ -178,6 +189,7 @@ impl OctavePerlinNoiseSampler { value - (value / 3.3554432E7f64 + 0.5f64).floor() * 3.3554432E7f64 } + #[allow(dead_code)] pub fn calculate_amplitudes(octaves: &[i32]) -> (i32, Vec) { let mut octaves = Vec::from_iter(octaves); octaves.sort(); @@ -198,7 +210,7 @@ impl OctavePerlinNoiseSampler { (-i, double_list) } - pub fn new(random: &mut impl Random, first_octave: i32, amplitudes: Vec) -> Self { + pub fn new(random: &mut RandomGenerator, first_octave: i32, amplitudes: &[f64]) -> Self { let i = amplitudes.len(); let j = -first_octave; @@ -207,21 +219,54 @@ impl OctavePerlinNoiseSampler { samplers.push(None); } - 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)), - )); + 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, &litudes); + let max_value = Self::get_total_amplitude(2f64, persistence, amplitudes); Self { octave_samplers: samplers, - amplitudes, + amplitudes: amplitudes.to_vec(), first_octave, persistence, lacunarity: 2f64.pow((-j) as f64), @@ -255,9 +300,259 @@ impl OctavePerlinNoiseSampler { } } +pub struct DoublePerlinNoiseSampler { + first_sampler: OctavePerlinNoiseSampler, + second_sampler: OctavePerlinNoiseSampler, + amplitude: f64, + #[allow(dead_code)] + max_value: f64, +} + +impl DoublePerlinNoiseSampler { + fn create_amplitude(octaves: i32) -> f64 { + 0.1f64 * (1f64 + 1f64 / (octaves + 1) as f64) + } + + #[allow(dead_code)] + 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, + } + } + + #[allow(dead_code)] + 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, Random}; + + 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(&mut 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(&mut 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::{xoroshiro128::Xoroshiro, Random}; + use pumpkin_core::random::{legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, Random}; + + use crate::world_gen::noise::perlin::RandomGenerator; use super::OctavePerlinNoiseSampler; @@ -270,7 +565,8 @@ mod octave_perline_noise_sampler_test { assert_eq!(start, 1); assert_eq!(amplitudes, [1f64, 1f64, 1f64]); - let sampler = OctavePerlinNoiseSampler::new(&mut rand, start, amplitudes); + let mut rand_gen = RandomGenerator::Xoroshiro(&mut rand); + let sampler = OctavePerlinNoiseSampler::new(&mut rand_gen, start, &litudes); assert_eq!(sampler.first_octave, 1); assert_eq!(sampler.persistence, 0.5714285714285714f64); @@ -295,13 +591,44 @@ mod octave_perline_noise_sampler_test { } } + #[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(&mut 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 sampler = OctavePerlinNoiseSampler::new(&mut rand, start, amplitudes); + let mut rand_gen = RandomGenerator::Xoroshiro(&mut rand); + let sampler = OctavePerlinNoiseSampler::new(&mut rand_gen, start, &litudes); let values = [ ( diff --git a/pumpkin-world/src/world_gen/noise/simplex.rs b/pumpkin-world/src/world_gen/noise/simplex.rs index 6c4567007..a84ab460f 100644 --- a/pumpkin-world/src/world_gen/noise/simplex.rs +++ b/pumpkin-world/src/world_gen/noise/simplex.rs @@ -15,6 +15,7 @@ impl SimplexNoiseSampler { const SKEW_FACTOR_2D: f64 = 0.5f64 * (Self::SQRT_3 - 1f64); const UNSKEW_FACTOR_2D: f64 = (3f64 - Self::SQRT_3) / 6f64; + #[allow(dead_code)] pub fn new(random: &mut impl Random) -> Self { let x_origin = random.next_f64() * 256f64; let y_origin = random.next_f64() * 256f64; @@ -177,6 +178,7 @@ pub struct OctaveSimplexNoiseSampler { } impl OctaveSimplexNoiseSampler { + #[allow(dead_code)] pub fn new(random: &mut impl Random, octaves: &[i32]) -> Self { let mut octaves = Vec::from_iter(octaves); octaves.sort(); @@ -227,6 +229,7 @@ impl OctaveSimplexNoiseSampler { } } + #[allow(dead_code)] pub fn sample(&self, x: f64, y: f64, use_origin: bool) -> f64 { let mut d = 0f64; let mut e = self.lacunarity; From 41b9e90112375218030a0f309b40e4618d858f2e Mon Sep 17 00:00:00 2001 From: kralverde Date: Fri, 13 Sep 2024 13:08:51 -0400 Subject: [PATCH 6/9] add enum wrapper around random implementations --- pumpkin-core/src/random/gaussian.rs | 21 ++- pumpkin-core/src/random/legacy_rand.rs | 38 ++--- pumpkin-core/src/random/mod.rs | 138 ++++++++++++++++++- pumpkin-core/src/random/xoroshiro128.rs | 36 ++--- pumpkin-world/src/world_gen/noise/perlin.rs | 32 ++--- pumpkin-world/src/world_gen/noise/simplex.rs | 10 +- 6 files changed, 186 insertions(+), 89 deletions(-) diff --git a/pumpkin-core/src/random/gaussian.rs b/pumpkin-core/src/random/gaussian.rs index 8364cb910..35d4095cd 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 2360ab5ca..4a2cb1b98 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, }; 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) } @@ -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; diff --git a/pumpkin-core/src/random/mod.rs b/pumpkin-core/src/random/mod.rs index b5389aa49..2bb937de2 100644 --- a/pumpkin-core/src/random/mod.rs +++ b/pumpkin-core/src/random/mod.rs @@ -1,13 +1,139 @@ +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 { + pub fn split(&mut self) -> Self { + match self { + Self::Xoroshiro(rand) => Self::Xoroshiro(rand.split()), + Self::Legacy(rand) => Self::Legacy(rand.split()), + } + } + + 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()), + } + } + + pub fn next(&mut self, bits: u64) -> u64 { + match self { + Self::Xoroshiro(rand) => rand.next(bits), + Self::Legacy(rand) => rand.next(bits), + } + } + + pub fn next_i32(&mut self) -> i32 { + match self { + Self::Xoroshiro(rand) => rand.next_i32(), + Self::Legacy(rand) => rand.next_i32(), + } + } + + 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), + } + } + + pub fn next_inbetween_i32(&mut self, min: i32, max: i32) -> i32 { + self.next_bounded_i32(max - min + 1) + min + } + + pub fn next_i64(&mut self) -> i64 { + match self { + Self::Xoroshiro(rand) => rand.next_i64(), + Self::Legacy(rand) => rand.next_i64(), + } + } + + pub fn next_bool(&mut self) -> bool { + match self { + Self::Xoroshiro(rand) => rand.next_bool(), + Self::Legacy(rand) => rand.next_bool(), + } + } + + pub fn next_f32(&mut self) -> f32 { + match self { + Self::Xoroshiro(rand) => rand.next_f32(), + Self::Legacy(rand) => rand.next_f32(), + } + } + + pub fn next_f64(&mut self) -> f64 { + match self { + Self::Xoroshiro(rand) => rand.next_f64(), + Self::Legacy(rand) => rand.next_f64(), + } + } + + pub fn next_gaussian(&mut self) -> f64 { + match self { + Self::Xoroshiro(rand) => rand.next_gaussian(), + Self::Legacy(rand) => rand.next_gaussian(), + } + } + + pub fn next_triangular(&mut self, mode: f64, deviation: f64) -> f64 { + mode + deviation * (self.next_f64() - self.next_f64()) + } + + pub fn skip(&mut self, count: i32) { + for _ in 0..count { + self.next_i64(); + } + } + + 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 { + 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)), + } + } + + 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)), + } + } + + 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 +170,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 e8d7e4f12..a82fcf75c 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/noise/perlin.rs b/pumpkin-world/src/world_gen/noise/perlin.rs index e1c92bf88..71ebcf188 100644 --- a/pumpkin-world/src/world_gen/noise/perlin.rs +++ b/pumpkin-world/src/world_gen/noise/perlin.rs @@ -1,8 +1,6 @@ use itertools::Itertools; use num_traits::{Pow, Zero}; -use pumpkin_core::random::{ - legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, Random, RandomSplitter, -}; +use pumpkin_core::random::{RandomDeriverImpl, RandomGenerator, RandomImpl}; use super::{dot, lerp3, GRADIENTS}; @@ -14,7 +12,7 @@ pub struct PerlinNoiseSampler { } impl PerlinNoiseSampler { - pub fn new(random: &mut impl Random) -> Self { + 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; @@ -153,12 +151,6 @@ impl PerlinNoiseSampler { } } -#[allow(dead_code)] -pub enum RandomGenerator<'a> { - Xoroshiro(&'a mut Xoroshiro), - Legacy(&'a mut LegacyRand), -} - pub struct OctavePerlinNoiseSampler { octave_samplers: Vec>, amplitudes: Vec, @@ -232,7 +224,7 @@ impl OctavePerlinNoiseSampler { } } RandomGenerator::Legacy(random) => { - let sampler = PerlinNoiseSampler::new(*random); + let sampler = PerlinNoiseSampler::new(random); if j >= 0 && j < i as i32 { let d = amplitudes[j as usize]; if d != 0f64 { @@ -244,7 +236,7 @@ impl OctavePerlinNoiseSampler { if kx < i { let e = amplitudes[kx]; if e != 0f64 { - samplers[kx] = Some(PerlinNoiseSampler::new(*random)); + samplers[kx] = Some(PerlinNoiseSampler::new(random)); } else { random.skip(262); } @@ -351,7 +343,7 @@ impl DoublePerlinNoiseSampler { #[cfg(test)] mod double_perlin_noise_sampler_test { - use pumpkin_core::random::{legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, Random}; + use pumpkin_core::random::{legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomImpl}; use crate::world_gen::noise::perlin::{DoublePerlinNoiseSampler, RandomGenerator}; @@ -360,7 +352,7 @@ mod double_perlin_noise_sampler_test { let mut rand = LegacyRand::from_seed(513513513); assert_eq!(rand.next_i32(), -1302745855); - let mut rand_gen = RandomGenerator::Legacy(&mut rand); + let mut rand_gen = RandomGenerator::Legacy(rand); let sampler = DoublePerlinNoiseSampler::new(&mut rand_gen, 0, &[4f64]); let values = [ @@ -456,7 +448,7 @@ mod double_perlin_noise_sampler_test { let mut rand = Xoroshiro::from_seed(5); assert_eq!(rand.next_i32(), -1678727252); - let mut rand_gen = RandomGenerator::Xoroshiro(&mut rand); + let mut rand_gen = RandomGenerator::Xoroshiro(rand); let sampler = DoublePerlinNoiseSampler::new(&mut rand_gen, 1, &[2f64, 4f64]); let values = [ @@ -550,7 +542,7 @@ mod double_perlin_noise_sampler_test { #[cfg(test)] mod octave_perline_noise_sampler_test { - use pumpkin_core::random::{legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, Random}; + use pumpkin_core::random::{legacy_rand::LegacyRand, xoroshiro128::Xoroshiro, RandomImpl}; use crate::world_gen::noise::perlin::RandomGenerator; @@ -565,7 +557,7 @@ mod octave_perline_noise_sampler_test { assert_eq!(start, 1); assert_eq!(amplitudes, [1f64, 1f64, 1f64]); - let mut rand_gen = RandomGenerator::Xoroshiro(&mut rand); + let mut rand_gen = RandomGenerator::Xoroshiro(rand); let sampler = OctavePerlinNoiseSampler::new(&mut rand_gen, start, &litudes); assert_eq!(sampler.first_octave, 1); @@ -600,7 +592,7 @@ mod octave_perline_noise_sampler_test { assert_eq!(start, 0); assert_eq!(amplitudes, [1f64]); - let mut rand_gen = RandomGenerator::Legacy(&mut rand); + 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); @@ -627,7 +619,7 @@ mod octave_perline_noise_sampler_test { assert_eq!(rand.next_i32(), 404174895); let (start, amplitudes) = OctavePerlinNoiseSampler::calculate_amplitudes(&[1, 2, 3]); - let mut rand_gen = RandomGenerator::Xoroshiro(&mut rand); + let mut rand_gen = RandomGenerator::Xoroshiro(rand); let sampler = OctavePerlinNoiseSampler::new(&mut rand_gen, start, &litudes); let values = [ @@ -723,7 +715,7 @@ mod octave_perline_noise_sampler_test { mod perlin_noise_sampler_test { use std::ops::Deref; - use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; use crate::world_gen::noise::perlin::PerlinNoiseSampler; diff --git a/pumpkin-world/src/world_gen/noise/simplex.rs b/pumpkin-world/src/world_gen/noise/simplex.rs index a84ab460f..f15d787e0 100644 --- a/pumpkin-world/src/world_gen/noise/simplex.rs +++ b/pumpkin-world/src/world_gen/noise/simplex.rs @@ -1,5 +1,5 @@ use num_traits::Pow; -use pumpkin_core::random::{legacy_rand::LegacyRand, Random}; +use pumpkin_core::random::{legacy_rand::LegacyRand, RandomImpl}; use super::{dot, GRADIENTS}; @@ -16,7 +16,7 @@ impl SimplexNoiseSampler { const UNSKEW_FACTOR_2D: f64 = (3f64 - Self::SQRT_3) / 6f64; #[allow(dead_code)] - pub fn new(random: &mut impl Random) -> Self { + 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; @@ -179,7 +179,7 @@ pub struct OctaveSimplexNoiseSampler { impl OctaveSimplexNoiseSampler { #[allow(dead_code)] - pub fn new(random: &mut impl Random, octaves: &[i32]) -> Self { + pub fn new(random: &mut impl RandomImpl, octaves: &[i32]) -> Self { let mut octaves = Vec::from_iter(octaves); octaves.sort(); @@ -253,7 +253,7 @@ impl OctaveSimplexNoiseSampler { #[cfg(test)] mod octave_simplex_noise_sampler_test { - use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; use crate::world_gen::noise::simplex::OctaveSimplexNoiseSampler; @@ -390,7 +390,7 @@ mod octave_simplex_noise_sampler_test { mod simplex_noise_sampler_test { use std::ops::Deref; - use pumpkin_core::random::{xoroshiro128::Xoroshiro, Random}; + use pumpkin_core::random::{xoroshiro128::Xoroshiro, RandomImpl}; use crate::world_gen::noise::simplex::SimplexNoiseSampler; From f57ff1ab78f3d1e259d3258bbac2b49af9505e1a Mon Sep 17 00:00:00 2001 From: kralverde Date: Fri, 13 Sep 2024 13:21:03 -0400 Subject: [PATCH 7/9] add inline(always) --- pumpkin-core/src/random/mod.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pumpkin-core/src/random/mod.rs b/pumpkin-core/src/random/mod.rs index 2bb937de2..9b238ce3e 100644 --- a/pumpkin-core/src/random/mod.rs +++ b/pumpkin-core/src/random/mod.rs @@ -11,6 +11,7 @@ pub enum RandomGenerator { } impl RandomGenerator { + #[inline(always)] pub fn split(&mut self) -> Self { match self { Self::Xoroshiro(rand) => Self::Xoroshiro(rand.split()), @@ -18,6 +19,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_splitter(&mut self) -> RandomDeriver { match self { Self::Xoroshiro(rand) => RandomDeriver::Xoroshiro(rand.next_splitter()), @@ -25,6 +27,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next(&mut self, bits: u64) -> u64 { match self { Self::Xoroshiro(rand) => rand.next(bits), @@ -32,6 +35,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_i32(&mut self) -> i32 { match self { Self::Xoroshiro(rand) => rand.next_i32(), @@ -39,6 +43,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_bounded_i32(&mut self, bound: i32) -> i32 { match self { Self::Xoroshiro(rand) => rand.next_bounded_i32(bound), @@ -46,10 +51,12 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_inbetween_i32(&mut self, min: i32, max: i32) -> i32 { self.next_bounded_i32(max - min + 1) + min } + #[inline(always)] pub fn next_i64(&mut self) -> i64 { match self { Self::Xoroshiro(rand) => rand.next_i64(), @@ -57,6 +64,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_bool(&mut self) -> bool { match self { Self::Xoroshiro(rand) => rand.next_bool(), @@ -64,6 +72,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_f32(&mut self) -> f32 { match self { Self::Xoroshiro(rand) => rand.next_f32(), @@ -71,6 +80,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_f64(&mut self) -> f64 { match self { Self::Xoroshiro(rand) => rand.next_f64(), @@ -78,6 +88,7 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_gaussian(&mut self) -> f64 { match self { Self::Xoroshiro(rand) => rand.next_gaussian(), @@ -85,16 +96,19 @@ impl RandomGenerator { } } + #[inline(always)] pub fn next_triangular(&mut self, mode: f64, deviation: f64) -> f64 { mode + deviation * (self.next_f64() - self.next_f64()) } + #[inline(always)] pub fn skip(&mut self, count: i32) { for _ in 0..count { self.next_i64(); } } + #[inline(always)] pub fn next_inbetween_i32_exclusive(&mut self, min: i32, max: i32) -> i32 { min + self.next_bounded_i32(max - min) } @@ -106,6 +120,7 @@ pub enum RandomDeriver { } impl RandomDeriver { + #[inline(always)] pub fn split_string(&self, seed: &str) -> RandomGenerator { match self { Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_string(seed)), @@ -113,6 +128,7 @@ impl RandomDeriver { } } + #[inline(always)] pub fn split_u64(&self, seed: u64) -> RandomGenerator { match self { Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_u64(seed)), @@ -120,6 +136,7 @@ impl RandomDeriver { } } + #[inline(always)] 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)), From 642e3ee9f4b37148956e95ffc7c8d0c25b42b919 Mon Sep 17 00:00:00 2001 From: kralverde Date: Fri, 13 Sep 2024 18:51:04 -0400 Subject: [PATCH 8/9] implement some changes --- pumpkin-core/src/random/mod.rs | 34 ++++++++++----------- pumpkin-world/src/world_gen/noise/perlin.rs | 5 +-- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/pumpkin-core/src/random/mod.rs b/pumpkin-core/src/random/mod.rs index 9b238ce3e..d0200ebc4 100644 --- a/pumpkin-core/src/random/mod.rs +++ b/pumpkin-core/src/random/mod.rs @@ -11,7 +11,7 @@ pub enum RandomGenerator { } impl RandomGenerator { - #[inline(always)] + #[inline] pub fn split(&mut self) -> Self { match self { Self::Xoroshiro(rand) => Self::Xoroshiro(rand.split()), @@ -19,7 +19,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_splitter(&mut self) -> RandomDeriver { match self { Self::Xoroshiro(rand) => RandomDeriver::Xoroshiro(rand.next_splitter()), @@ -27,7 +27,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next(&mut self, bits: u64) -> u64 { match self { Self::Xoroshiro(rand) => rand.next(bits), @@ -35,7 +35,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_i32(&mut self) -> i32 { match self { Self::Xoroshiro(rand) => rand.next_i32(), @@ -43,7 +43,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_bounded_i32(&mut self, bound: i32) -> i32 { match self { Self::Xoroshiro(rand) => rand.next_bounded_i32(bound), @@ -51,12 +51,12 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_inbetween_i32(&mut self, min: i32, max: i32) -> i32 { self.next_bounded_i32(max - min + 1) + min } - #[inline(always)] + #[inline] pub fn next_i64(&mut self) -> i64 { match self { Self::Xoroshiro(rand) => rand.next_i64(), @@ -64,7 +64,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_bool(&mut self) -> bool { match self { Self::Xoroshiro(rand) => rand.next_bool(), @@ -72,7 +72,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_f32(&mut self) -> f32 { match self { Self::Xoroshiro(rand) => rand.next_f32(), @@ -80,7 +80,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_f64(&mut self) -> f64 { match self { Self::Xoroshiro(rand) => rand.next_f64(), @@ -88,7 +88,7 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_gaussian(&mut self) -> f64 { match self { Self::Xoroshiro(rand) => rand.next_gaussian(), @@ -96,19 +96,19 @@ impl RandomGenerator { } } - #[inline(always)] + #[inline] pub fn next_triangular(&mut self, mode: f64, deviation: f64) -> f64 { mode + deviation * (self.next_f64() - self.next_f64()) } - #[inline(always)] + #[inline] pub fn skip(&mut self, count: i32) { for _ in 0..count { self.next_i64(); } } - #[inline(always)] + #[inline] pub fn next_inbetween_i32_exclusive(&mut self, min: i32, max: i32) -> i32 { min + self.next_bounded_i32(max - min) } @@ -120,7 +120,7 @@ pub enum RandomDeriver { } impl RandomDeriver { - #[inline(always)] + #[inline] pub fn split_string(&self, seed: &str) -> RandomGenerator { match self { Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_string(seed)), @@ -128,7 +128,7 @@ impl RandomDeriver { } } - #[inline(always)] + #[inline] pub fn split_u64(&self, seed: u64) -> RandomGenerator { match self { Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_u64(seed)), @@ -136,7 +136,7 @@ impl RandomDeriver { } } - #[inline(always)] + #[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)), diff --git a/pumpkin-world/src/world_gen/noise/perlin.rs b/pumpkin-world/src/world_gen/noise/perlin.rs index 71ebcf188..2674ded78 100644 --- a/pumpkin-world/src/world_gen/noise/perlin.rs +++ b/pumpkin-world/src/world_gen/noise/perlin.rs @@ -167,10 +167,7 @@ impl OctavePerlinNoiseSampler { let mut e = persistence; for amplitude in amplitudes.iter() { - if *amplitude != 0f64 { - d += amplitude * scale * e; - } - + d += amplitude * scale * e; e /= 2f64; } From 56b5d85324c1fdfb66381acbaead46f0425863cf Mon Sep 17 00:00:00 2001 From: kralverde Date: Fri, 13 Sep 2024 20:28:39 -0400 Subject: [PATCH 9/9] change allow dead code --- pumpkin-world/src/world_gen/noise/mod.rs | 2 +- pumpkin-world/src/world_gen/noise/perlin.rs | 6 ------ pumpkin-world/src/world_gen/noise/simplex.rs | 3 --- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/pumpkin-world/src/world_gen/noise/mod.rs b/pumpkin-world/src/world_gen/noise/mod.rs index 106a38f3b..ea5d51196 100644 --- a/pumpkin-world/src/world_gen/noise/mod.rs +++ b/pumpkin-world/src/world_gen/noise/mod.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] mod perlin; mod simplex; @@ -13,7 +14,6 @@ pub fn lerp2(delta_x: f64, delta_y: f64, x0y0: f64, x1y0: f64, x0y1: f64, x1y1: ) } -#[allow(dead_code)] #[allow(clippy::too_many_arguments)] pub fn lerp3( delta_x: f64, diff --git a/pumpkin-world/src/world_gen/noise/perlin.rs b/pumpkin-world/src/world_gen/noise/perlin.rs index 2674ded78..a96b1fc6c 100644 --- a/pumpkin-world/src/world_gen/noise/perlin.rs +++ b/pumpkin-world/src/world_gen/noise/perlin.rs @@ -37,7 +37,6 @@ impl PerlinNoiseSampler { } } - #[allow(dead_code)] pub fn sample_flat_y(&self, x: f64, y: f64, z: f64) -> f64 { self.sample_no_fade(x, y, z, 0f64, 0f64) } @@ -154,7 +153,6 @@ impl PerlinNoiseSampler { pub struct OctavePerlinNoiseSampler { octave_samplers: Vec>, amplitudes: Vec, - #[allow(dead_code)] first_octave: i32, persistence: f64, lacunarity: f64, @@ -178,7 +176,6 @@ impl OctavePerlinNoiseSampler { value - (value / 3.3554432E7f64 + 0.5f64).floor() * 3.3554432E7f64 } - #[allow(dead_code)] pub fn calculate_amplitudes(octaves: &[i32]) -> (i32, Vec) { let mut octaves = Vec::from_iter(octaves); octaves.sort(); @@ -293,7 +290,6 @@ pub struct DoublePerlinNoiseSampler { first_sampler: OctavePerlinNoiseSampler, second_sampler: OctavePerlinNoiseSampler, amplitude: f64, - #[allow(dead_code)] max_value: f64, } @@ -302,7 +298,6 @@ impl DoublePerlinNoiseSampler { 0.1f64 * (1f64 + 1f64 / (octaves + 1) as f64) } - #[allow(dead_code)] 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); @@ -328,7 +323,6 @@ impl DoublePerlinNoiseSampler { } } - #[allow(dead_code)] pub fn sample(&self, x: f64, y: f64, z: f64) -> f64 { let d = x * 1.0181268882175227f64; let e = y * 1.0181268882175227f64; diff --git a/pumpkin-world/src/world_gen/noise/simplex.rs b/pumpkin-world/src/world_gen/noise/simplex.rs index f15d787e0..8d6fba7fa 100644 --- a/pumpkin-world/src/world_gen/noise/simplex.rs +++ b/pumpkin-world/src/world_gen/noise/simplex.rs @@ -15,7 +15,6 @@ impl SimplexNoiseSampler { const SKEW_FACTOR_2D: f64 = 0.5f64 * (Self::SQRT_3 - 1f64); const UNSKEW_FACTOR_2D: f64 = (3f64 - Self::SQRT_3) / 6f64; - #[allow(dead_code)] pub fn new(random: &mut impl RandomImpl) -> Self { let x_origin = random.next_f64() * 256f64; let y_origin = random.next_f64() * 256f64; @@ -178,7 +177,6 @@ pub struct OctaveSimplexNoiseSampler { } impl OctaveSimplexNoiseSampler { - #[allow(dead_code)] pub fn new(random: &mut impl RandomImpl, octaves: &[i32]) -> Self { let mut octaves = Vec::from_iter(octaves); octaves.sort(); @@ -229,7 +227,6 @@ impl OctaveSimplexNoiseSampler { } } - #[allow(dead_code)] pub fn sample(&self, x: f64, y: f64, use_origin: bool) -> f64 { let mut d = 0f64; let mut e = self.lacunarity;