noice/noise_fns/generators/
value.rs

1use crate::{
2    math::{self, interpolate},
3    noise_fns::{NoiseFn, Seedable},
4    permutationtable::PermutationTable,
5};
6
7/// Noise function that outputs 2/3/4-dimensional Value noise.
8#[derive(Clone, Copy, Debug)]
9pub struct Value {
10    seed: u32,
11    perm_table: PermutationTable,
12}
13
14impl Value {
15    pub const DEFAULT_SEED: u32 = 0;
16
17    pub fn new() -> Self {
18        Self {
19            seed: Self::DEFAULT_SEED,
20            perm_table: PermutationTable::new(Self::DEFAULT_SEED),
21        }
22    }
23}
24
25impl Default for Value {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31impl Seedable for Value {
32    /// Sets the seed value for Value noise
33    fn set_seed(self, seed: u32) -> Self {
34        // If the new seed is the same as the current seed, just return self.
35        if self.seed == seed {
36            return self;
37        }
38
39        // Otherwise, regenerate the permutation table based on the new seed.
40        Self {
41            seed,
42            perm_table: PermutationTable::new(seed),
43        }
44    }
45
46    fn seed(&self) -> u32 {
47        self.seed
48    }
49}
50
51/// 2-dimensional value noise
52impl NoiseFn<[f64; 2]> for Value {
53    fn get(&self, point: [f64; 2]) -> f64 {
54        fn get(perm_table: &PermutationTable, corner: [isize; 2]) -> f64 {
55            perm_table.get2(corner) as f64 / 255.0
56        }
57
58        let floored = math::map2(point, f64::floor);
59        let near_corner = math::to_isize2(floored);
60        let far_corner = math::add2(near_corner, math::one2());
61        let weight = math::map2(math::sub2(point, floored), interpolate::s_curve5);
62
63        let f00 = get(&self.perm_table, [near_corner[0], near_corner[1]]);
64        let f10 = get(&self.perm_table, [far_corner[0], near_corner[1]]);
65        let f01 = get(&self.perm_table, [near_corner[0], far_corner[1]]);
66        let f11 = get(&self.perm_table, [far_corner[0], far_corner[1]]);
67
68        let d0 = interpolate::linear(f00, f10, weight[0]);
69        let d1 = interpolate::linear(f01, f11, weight[0]);
70        let d = interpolate::linear(d0, d1, weight[1]);
71
72        d * 2.0 - 1.0
73    }
74}
75
76/// 3-dimensional value noise
77impl NoiseFn<[f64; 3]> for Value {
78    fn get(&self, point: [f64; 3]) -> f64 {
79        fn get(perm_table: &PermutationTable, corner: [isize; 3]) -> f64 {
80            perm_table.get3(corner) as f64 / 255.0
81        }
82
83        let floored = math::map3(point, f64::floor);
84        let near_corner = math::to_isize3(floored);
85        let far_corner = math::add3(near_corner, math::one3());
86        let weight = math::map3(math::sub3(point, floored), interpolate::s_curve5);
87
88        let f000 = get(
89            &self.perm_table,
90            [near_corner[0], near_corner[1], near_corner[2]],
91        );
92        let f100 = get(
93            &self.perm_table,
94            [far_corner[0], near_corner[1], near_corner[2]],
95        );
96        let f010 = get(
97            &self.perm_table,
98            [near_corner[0], far_corner[1], near_corner[2]],
99        );
100        let f110 = get(
101            &self.perm_table,
102            [far_corner[0], far_corner[1], near_corner[2]],
103        );
104        let f001 = get(
105            &self.perm_table,
106            [near_corner[0], near_corner[1], far_corner[2]],
107        );
108        let f101 = get(
109            &self.perm_table,
110            [far_corner[0], near_corner[1], far_corner[2]],
111        );
112        let f011 = get(
113            &self.perm_table,
114            [near_corner[0], far_corner[1], far_corner[2]],
115        );
116        let f111 = get(
117            &self.perm_table,
118            [far_corner[0], far_corner[1], far_corner[2]],
119        );
120
121        let d00 = interpolate::linear(f000, f100, weight[0]);
122        let d01 = interpolate::linear(f001, f101, weight[0]);
123        let d10 = interpolate::linear(f010, f110, weight[0]);
124        let d11 = interpolate::linear(f011, f111, weight[0]);
125        let d0 = interpolate::linear(d00, d10, weight[1]);
126        let d1 = interpolate::linear(d01, d11, weight[1]);
127        let d = interpolate::linear(d0, d1, weight[2]);
128
129        d * 2.0 - 1.0
130    }
131}
132
133/// 4-dimensional value noise
134impl NoiseFn<[f64; 4]> for Value {
135    fn get(&self, point: [f64; 4]) -> f64 {
136        fn get(perm_table: &PermutationTable, corner: [isize; 4]) -> f64 {
137            perm_table.get4(corner) as f64 / 255.0
138        }
139
140        let floored = math::map4(point, f64::floor);
141        let near_corner = math::to_isize4(floored);
142        let far_corner = math::add4(near_corner, math::one4());
143        let weight = math::map4(math::sub4(point, floored), interpolate::s_curve5);
144
145        let f0000 = get(
146            &self.perm_table,
147            [
148                near_corner[0],
149                near_corner[1],
150                near_corner[2],
151                near_corner[3],
152            ],
153        );
154        let f1000 = get(
155            &self.perm_table,
156            [
157                far_corner[0],
158                near_corner[1],
159                near_corner[2],
160                near_corner[3],
161            ],
162        );
163        let f0100 = get(
164            &self.perm_table,
165            [
166                near_corner[0],
167                far_corner[1],
168                near_corner[2],
169                near_corner[3],
170            ],
171        );
172        let f1100 = get(
173            &self.perm_table,
174            [far_corner[0], far_corner[1], near_corner[2], near_corner[3]],
175        );
176        let f0010 = get(
177            &self.perm_table,
178            [
179                near_corner[0],
180                near_corner[1],
181                far_corner[2],
182                near_corner[3],
183            ],
184        );
185        let f1010 = get(
186            &self.perm_table,
187            [far_corner[0], near_corner[1], far_corner[2], near_corner[3]],
188        );
189        let f0110 = get(
190            &self.perm_table,
191            [near_corner[0], far_corner[1], far_corner[2], near_corner[3]],
192        );
193        let f1110 = get(
194            &self.perm_table,
195            [far_corner[0], far_corner[1], far_corner[2], near_corner[3]],
196        );
197        let f0001 = get(
198            &self.perm_table,
199            [
200                near_corner[0],
201                near_corner[1],
202                near_corner[2],
203                far_corner[3],
204            ],
205        );
206        let f1001 = get(
207            &self.perm_table,
208            [far_corner[0], near_corner[1], near_corner[2], far_corner[3]],
209        );
210        let f0101 = get(
211            &self.perm_table,
212            [near_corner[0], far_corner[1], near_corner[2], far_corner[3]],
213        );
214        let f1101 = get(
215            &self.perm_table,
216            [far_corner[0], far_corner[1], near_corner[2], far_corner[3]],
217        );
218        let f0011 = get(
219            &self.perm_table,
220            [near_corner[0], near_corner[1], far_corner[2], far_corner[3]],
221        );
222        let f1011 = get(
223            &self.perm_table,
224            [far_corner[0], near_corner[1], far_corner[2], far_corner[3]],
225        );
226        let f0111 = get(
227            &self.perm_table,
228            [near_corner[0], far_corner[1], far_corner[2], far_corner[3]],
229        );
230        let f1111 = get(
231            &self.perm_table,
232            [far_corner[0], far_corner[1], far_corner[2], far_corner[3]],
233        );
234
235        let d000 = interpolate::linear(f0000, f1000, weight[0]);
236        let d010 = interpolate::linear(f0010, f1010, weight[0]);
237        let d100 = interpolate::linear(f0100, f1100, weight[0]);
238        let d110 = interpolate::linear(f0110, f1110, weight[0]);
239        let d001 = interpolate::linear(f0001, f1001, weight[0]);
240        let d011 = interpolate::linear(f0011, f1011, weight[0]);
241        let d101 = interpolate::linear(f0101, f1101, weight[0]);
242        let d111 = interpolate::linear(f0111, f1111, weight[0]);
243        let d00 = interpolate::linear(d000, d100, weight[1]);
244        let d10 = interpolate::linear(d010, d110, weight[1]);
245        let d01 = interpolate::linear(d001, d101, weight[1]);
246        let d11 = interpolate::linear(d011, d111, weight[1]);
247        let d0 = interpolate::linear(d00, d10, weight[2]);
248        let d1 = interpolate::linear(d01, d11, weight[2]);
249        let d = interpolate::linear(d0, d1, weight[3]);
250
251        d * 2.0 - 1.0
252    }
253}