steel_worldgen/noise/
perlin_simplex_noise.rs1use std::collections::BTreeSet;
7
8use crate::noise::SimplexNoise;
9use crate::random::legacy_random::LegacyRandom;
10use crate::random::{Random, RandomSource};
11
12pub struct PerlinSimplexNoise {
20 noise_levels: Vec<Option<SimplexNoise>>,
21 highest_freq_input_factor: f64,
22 highest_freq_value_factor: f64,
23}
24
25impl PerlinSimplexNoise {
26 #[must_use]
37 pub fn new(random: &mut RandomSource, octaves: &[i32]) -> Self {
38 let octave_set: BTreeSet<i32> = octaves.iter().copied().collect();
39 assert!(!octave_set.is_empty(), "Need some octaves");
40
41 let first_octave = *octave_set.first().expect("non-empty octave set");
43 let last_octave = *octave_set.last().expect("non-empty octave set");
44 let high_freq_octaves = last_octave;
45 let total = (last_octave - first_octave + 1) as usize;
46
47 let zero_octave = SimplexNoise::new(random);
50 let zero_index = high_freq_octaves; let mut noise_levels: Vec<Option<SimplexNoise>> = vec![None; total];
53
54 let hf_seed = if high_freq_octaves > 0 {
56 Some(
57 (zero_octave.get_value_3d(zero_octave.xo, zero_octave.yo, zero_octave.zo)
58 * 9.223_372_036_854_776e18) as i64,
59 )
60 } else {
61 None
62 };
63
64 if zero_index >= 0 && (zero_index as usize) < total && octave_set.contains(&0) {
66 noise_levels[zero_index as usize] = Some(zero_octave);
67 }
68
69 let start = (zero_index + 1).max(0) as usize;
71 for (i, level) in noise_levels.iter_mut().enumerate().skip(start) {
72 let octave_level = zero_index - i as i32;
73 if octave_set.contains(&octave_level) {
74 *level = Some(SimplexNoise::new(random));
75 } else {
76 random.consume_count(262);
77 }
78 }
79
80 if let Some(seed) = hf_seed {
83 let mut hf_random = RandomSource::Legacy(LegacyRandom::from_seed(seed as u64));
84
85 for ix in (0..zero_index as usize).rev() {
86 let octave_level = zero_index - ix as i32;
87 if octave_set.contains(&octave_level) {
88 noise_levels[ix] = Some(SimplexNoise::new(&mut hf_random));
89 } else {
90 hf_random.consume_count(262);
91 }
92 }
93 }
94
95 Self {
96 noise_levels,
97 highest_freq_input_factor: 2.0f64.powi(last_octave),
98 highest_freq_value_factor: 1.0 / (2.0f64.powi(total as i32) - 1.0),
99 }
100 }
101
102 #[must_use]
106 pub fn get_value(&self, x: f64, z: f64) -> f64 {
107 let mut sum = 0.0;
108 let mut factor = self.highest_freq_input_factor;
109 let mut amplitude = self.highest_freq_value_factor;
110
111 for noise in &self.noise_levels {
112 if let Some(n) = noise {
113 sum += n.get_value_2d(x * factor, z * factor) * amplitude;
114 }
115 factor /= 2.0;
116 amplitude *= 2.0;
117 }
118
119 sum
120 }
121}