doryen_extra/noise/algorithms/
perlin.rs

1/* BSD 3-Clause License
2 *
3 * Copyright © 2019, Alexander Krivács Schrøder <alexschrod@gmail.com>.
4 * Copyright © 2008-2019, Jice and the libtcod contributors.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 *    this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 *    this list of conditions and the following disclaimer in the documentation
15 *    and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 *    contributors may be used to endorse or promote products derived from
19 *    this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34use crate::noise::algorithms::AlgorithmInitializer;
35use crate::noise::{Algorithm, MAX_DIMENSIONS};
36use crate::random::algorithms::Algorithm as RandomAlgorithm;
37use derivative::Derivative;
38use ilyvion_util::multi_dimensional::Window2D;
39
40/// Perlin noise algorithm.
41#[derive(Clone, Copy, Derivative)]
42#[derivative(Debug)]
43pub struct Perlin {
44    dimensions: usize,
45    /** Randomized map of indexes into buffer */
46    #[derivative(Debug = "ignore")]
47    pub map: [u8; 256],
48    /** Random 256 x ndim buffer */
49    #[derivative(Debug = "ignore")]
50    pub buffer: [f32; MAX_DIMENSIONS * 256],
51}
52
53impl Perlin {
54    #[allow(clippy::too_many_arguments)]
55    fn lattice(
56        &self,
57        ix: i32,
58        fx: f32,
59        iy: i32,
60        fy: f32,
61        iz: i32,
62        fz: f32,
63        iw: i32,
64        fw: f32,
65    ) -> f32 {
66        let n: [i32; 4] = [ix, iy, iz, iw];
67        let f: [f32; 4] = [fx, fy, fz, fw];
68        let mut n_index = 0;
69        for &ni in n.iter().take(self.dimensions) {
70            n_index = i32::from(self.map[((n_index + ni) & 0xFF) as usize]);
71        }
72        let buffer_window = Window2D::new_ref_unchecked(&self.buffer, 256, MAX_DIMENSIONS);
73
74        Iterator::zip(buffer_window[n_index as usize].iter(), f.iter())
75            .take(self.dimensions)
76            .map(|(b, f)| b * f)
77            .sum()
78    }
79
80    fn perlin_1d(
81        &self,
82        n: [i32; MAX_DIMENSIONS],
83        r: [f32; MAX_DIMENSIONS],
84        w: [f32; MAX_DIMENSIONS],
85    ) -> f32 {
86        lerp!(
87            self.lattice(n[0], r[0], 0, 0.0, 0, 0.0, 0, 0.0),
88            self.lattice(n[0] + 1, r[0] - 1.0, 0, 0.0, 0, 0.0, 0, 0.0),
89            w[0]
90        )
91    }
92
93    fn perlin_2d(
94        &self,
95        n: [i32; MAX_DIMENSIONS],
96        r: [f32; MAX_DIMENSIONS],
97        w: [f32; MAX_DIMENSIONS],
98    ) -> f32 {
99        lerp!(
100            lerp!(
101                self.lattice(n[0], r[0], n[1], r[1], 0, 0.0, 0, 0.0),
102                self.lattice(n[0] + 1, r[0] - 1.0, n[1], r[1], 0, 0.0, 0, 0.0),
103                w[0]
104            ),
105            lerp!(
106                self.lattice(n[0], r[0], n[1] + 1, r[1] - 1.0, 0, 0.0, 0, 0.0),
107                self.lattice(n[0] + 1, r[0] - 1.0, n[1] + 1, r[1] - 1.0, 0, 0.0, 0, 0.0),
108                w[0]
109            ),
110            w[1]
111        )
112    }
113
114    fn perlin_3d(
115        &self,
116        n: [i32; MAX_DIMENSIONS],
117        r: [f32; MAX_DIMENSIONS],
118        w: [f32; MAX_DIMENSIONS],
119    ) -> f32 {
120        lerp!(
121            lerp!(
122                lerp!(
123                    self.lattice(n[0], r[0], n[1], r[1], n[2], r[2], 0, 0.0),
124                    self.lattice(n[0] + 1, r[0] - 1.0, n[1], r[1], n[2], r[2], 0, 0.0),
125                    w[0]
126                ),
127                lerp!(
128                    self.lattice(n[0], r[0], n[1] + 1, r[1] - 1.0, n[2], r[2], 0, 0.0),
129                    self.lattice(
130                        n[0] + 1,
131                        r[0] - 1.0,
132                        n[1] + 1,
133                        r[1] - 1.0,
134                        n[2],
135                        r[2],
136                        0,
137                        0.0
138                    ),
139                    w[0]
140                ),
141                w[1]
142            ),
143            lerp!(
144                lerp!(
145                    self.lattice(n[0], r[0], n[1], r[1], n[2] + 1, r[2] - 1.0, 0, 0.0),
146                    self.lattice(
147                        n[0] + 1,
148                        r[0] - 1.0,
149                        n[1],
150                        r[1],
151                        n[2] + 1,
152                        r[2] - 1.0,
153                        0,
154                        0.0
155                    ),
156                    w[0]
157                ),
158                lerp!(
159                    self.lattice(
160                        n[0],
161                        r[0],
162                        n[1] + 1,
163                        r[1] - 1.0,
164                        n[2] + 1,
165                        r[2] - 1.0,
166                        0,
167                        0.0
168                    ),
169                    self.lattice(
170                        n[0] + 1,
171                        r[0] - 1.0,
172                        n[1] + 1,
173                        r[1] - 1.0,
174                        n[2] + 1,
175                        r[2] - 1.0,
176                        0,
177                        0.0
178                    ),
179                    w[0]
180                ),
181                w[1]
182            ),
183            w[2]
184        )
185    }
186
187    #[allow(clippy::too_many_lines)]
188    fn perlin_4d(
189        &self,
190        n: [i32; MAX_DIMENSIONS],
191        r: [f32; MAX_DIMENSIONS],
192        w: [f32; MAX_DIMENSIONS],
193    ) -> f32 {
194        lerp!(
195            lerp!(
196                lerp!(
197                    lerp!(
198                        self.lattice(n[0], r[0], n[1], r[1], n[2], r[2], n[3], r[3]),
199                        self.lattice(n[0] + 1, r[0] - 1.0, n[1], r[1], n[2], r[2], n[3], r[3]),
200                        w[0]
201                    ),
202                    lerp!(
203                        self.lattice(n[0], r[0], n[1] + 1, r[1] - 1.0, n[2], r[2], n[3], r[3]),
204                        self.lattice(
205                            n[0] + 1,
206                            r[0] - 1.0,
207                            n[1] + 1,
208                            r[1] - 1.0,
209                            n[2],
210                            r[2],
211                            n[3],
212                            r[3]
213                        ),
214                        w[0]
215                    ),
216                    w[1]
217                ),
218                lerp!(
219                    lerp!(
220                        self.lattice(n[0], r[0], n[1], r[1], n[2] + 1, r[2] - 1.0, n[3], r[3]),
221                        self.lattice(
222                            n[0] + 1,
223                            r[0] - 1.0,
224                            n[1],
225                            r[1],
226                            n[2] + 1,
227                            r[2] - 1.0,
228                            n[3],
229                            r[3]
230                        ),
231                        w[0]
232                    ),
233                    lerp!(
234                        self.lattice(
235                            n[0],
236                            r[0],
237                            n[1] + 1,
238                            r[1] - 1.0,
239                            n[2] + 1,
240                            r[2] - 1.0,
241                            0,
242                            0.0
243                        ),
244                        self.lattice(
245                            n[0] + 1,
246                            r[0] - 1.0,
247                            n[1] + 1,
248                            r[1] - 1.0,
249                            n[2] + 1,
250                            r[2] - 1.0,
251                            n[3],
252                            r[3]
253                        ),
254                        w[0]
255                    ),
256                    w[1]
257                ),
258                w[2]
259            ),
260            lerp!(
261                lerp!(
262                    lerp!(
263                        self.lattice(n[0], r[0], n[1], r[1], n[2], r[2], n[3] + 1, r[3] - 1.0),
264                        self.lattice(
265                            n[0] + 1,
266                            r[0] - 1.0,
267                            n[1],
268                            r[1],
269                            n[2],
270                            r[2],
271                            n[3] + 1,
272                            r[3] - 1.0
273                        ),
274                        w[0]
275                    ),
276                    lerp!(
277                        self.lattice(
278                            n[0],
279                            r[0],
280                            n[1] + 1,
281                            r[1] - 1.0,
282                            n[2],
283                            r[2],
284                            n[3] + 1,
285                            r[3] - 1.0
286                        ),
287                        self.lattice(
288                            n[0] + 1,
289                            r[0] - 1.0,
290                            n[1] + 1,
291                            r[1] - 1.0,
292                            n[2],
293                            r[2],
294                            n[3] + 1,
295                            r[3] - 1.0
296                        ),
297                        w[0]
298                    ),
299                    w[1]
300                ),
301                lerp!(
302                    lerp!(
303                        self.lattice(
304                            n[0],
305                            r[0],
306                            n[1],
307                            r[1],
308                            n[2] + 1,
309                            r[2] - 1.0,
310                            n[3] + 1,
311                            r[3] - 1.0
312                        ),
313                        self.lattice(
314                            n[0] + 1,
315                            r[0] - 1.0,
316                            n[1],
317                            r[1],
318                            n[2] + 1,
319                            r[2] - 1.0,
320                            n[3] + 1,
321                            r[3] - 1.0
322                        ),
323                        w[0]
324                    ),
325                    lerp!(
326                        self.lattice(
327                            n[0],
328                            r[0],
329                            n[1] + 1,
330                            r[1] - 1.0,
331                            n[2] + 1,
332                            r[2] - 1.0,
333                            0,
334                            0.0
335                        ),
336                        self.lattice(
337                            n[0] + 1,
338                            r[0] - 1.0,
339                            n[1] + 1,
340                            r[1] - 1.0,
341                            n[2] + 1,
342                            r[2] - 1.0,
343                            n[3] + 1,
344                            r[3] - 1.0
345                        ),
346                        w[0]
347                    ),
348                    w[1]
349                ),
350                w[2]
351            ),
352            w[3]
353        )
354    }
355
356    fn cubic_f32(a: f32) -> f32 {
357        a * a * (3.0 - 2.0 * a)
358    }
359}
360
361impl Algorithm for Perlin {
362    fn new<R: RandomAlgorithm>(
363        dimensions: usize,
364        mut initializer: AlgorithmInitializer<R>,
365    ) -> Self {
366        Self {
367            dimensions,
368            map: initializer.map(),
369            buffer: initializer.buffer(dimensions),
370        }
371    }
372
373    fn generate(&self, f: &[f32]) -> f32 {
374        let mut n: [i32; MAX_DIMENSIONS] = [0; MAX_DIMENSIONS]; /* Indexes to pass to lattice function */
375        let mut r: [f32; MAX_DIMENSIONS] = [0.0; MAX_DIMENSIONS]; /* Remainders to pass to lattice function */
376        let mut w: [f32; MAX_DIMENSIONS] = [0.0; MAX_DIMENSIONS]; /* Cubic values to pass to interpolation function */
377        for i in 0..self.dimensions {
378            n[i] = f[i].floor() as i32;
379            r[i] = f[i] - n[i] as f32;
380            w[i] = Self::cubic_f32(r[i]);
381        }
382
383        let value = match self.dimensions {
384            1 => self.perlin_1d(n, r, w),
385            2 => self.perlin_2d(n, r, w),
386            3 => self.perlin_3d(n, r, w),
387            4 => self.perlin_4d(n, r, w),
388            _ => unreachable!(),
389        };
390
391        value.max(-0.99999).min(0.99999)
392    }
393}