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 {
19 noise_levels: Vec<Option<SimplexNoise>>,
20 highest_freq_input_factor: f64,
21 highest_freq_value_factor: f32,
22}
23
24impl PerlinSimplexNoise {
25 #[must_use]
36 pub fn new(random: &mut RandomSource, octaves: &[i32]) -> Self {
37 let octave_set: BTreeSet<i32> = octaves.iter().copied().collect();
38 assert!(!octave_set.is_empty(), "Need some octaves");
39
40 let first_octave = *octave_set.first().expect("non-empty octave set");
42 let last_octave = *octave_set.last().expect("non-empty octave set");
43 let high_freq_octaves = last_octave;
44 let total = (last_octave - first_octave + 1) as usize;
45
46 let zero_octave = SimplexNoise::new(random);
49 let zero_index = high_freq_octaves; let mut noise_levels: Vec<Option<SimplexNoise>> = vec![None; total];
52
53 let hf_seed = if high_freq_octaves > 0 {
55 Some(
56 (f64::from(zero_octave.get_value_3d(
57 zero_octave.xo,
58 zero_octave.yo,
59 zero_octave.zo,
60 )) * 9.223_372_036_854_776e18) as i64,
61 )
62 } else {
63 None
64 };
65
66 if zero_index >= 0 && (zero_index as usize) < total && octave_set.contains(&0) {
68 noise_levels[zero_index as usize] = Some(zero_octave);
69 }
70
71 let start = (zero_index + 1).max(0) as usize;
73 for (i, level) in noise_levels.iter_mut().enumerate().skip(start) {
74 let octave_level = zero_index - i as i32;
75 if octave_set.contains(&octave_level) {
76 *level = Some(SimplexNoise::new(random));
77 } else {
78 random.consume_count(262);
79 }
80 }
81
82 if let Some(seed) = hf_seed {
85 let mut hf_random = RandomSource::Legacy(LegacyRandom::from_seed(seed as u64));
86
87 for ix in (0..zero_index as usize).rev() {
88 let octave_level = zero_index - ix as i32;
89 if octave_set.contains(&octave_level) {
90 noise_levels[ix] = Some(SimplexNoise::new(&mut hf_random));
91 } else {
92 hf_random.consume_count(262);
93 }
94 }
95 }
96
97 Self {
98 noise_levels,
99 highest_freq_input_factor: 2.0f64.powi(last_octave),
100 highest_freq_value_factor: (1.0 / (2.0f64.powi(total as i32) - 1.0)) as f32,
101 }
102 }
103
104 #[must_use]
108 pub fn get_value(&self, x: f64, z: f64) -> f32 {
109 let mut sum = 0.0_f32;
110 let mut factor = self.highest_freq_input_factor;
111 let mut amplitude = self.highest_freq_value_factor;
112
113 for noise in &self.noise_levels {
114 if let Some(n) = noise {
115 sum += amplitude * n.get_value_2d(x * factor, z * factor);
116 }
117 factor /= 2.0;
118 amplitude *= 2.0;
119 }
120
121 sum
122 }
123}