noise_functions/base/
cell_value.rs

1use crate::base::{impl_noise, CustomCellValue};
2
3#[cfg(feature = "nightly-simd")]
4use core::simd::{f32x2, f32x4};
5
6/// 2/3/4 dimensional noise of the random value of the closest cell.
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct CellValue {
9    pub jitter: f32,
10}
11
12impl CellValue {
13    pub const fn jitter(mut self, jitter: f32) -> Self {
14        self.jitter = jitter;
15        self
16    }
17}
18
19impl_noise!(234 CellValue);
20
21impl Default for CellValue {
22    fn default() -> Self {
23        Self { jitter: 1.0 }
24    }
25}
26
27impl CellValue {
28    #[inline]
29    fn gen2(self, [x, y]: [f32; 2], seed: i32) -> f32 {
30        // implementation from FastNoiseLite
31        use crate::from_fast_noise_lite::{cell_neighbours, hash2, round_to_int, JITTER_2D, PRIME_X, PRIME_Y, RAND_VECS_2D};
32
33        let jitter = self.jitter * JITTER_2D;
34
35        let xr: i32 = round_to_int(x);
36        let yr: i32 = round_to_int(y);
37
38        let mut distance0: f32 = 1e10;
39        let mut closest_hash: i32 = 0;
40
41        let mut x_primed: i32 = xr.wrapping_sub(1).wrapping_mul(PRIME_X);
42        let y_primed_base: i32 = yr.wrapping_sub(1).wrapping_mul(PRIME_Y);
43
44        for xi in cell_neighbours(xr) {
45            let mut y_primed: i32 = y_primed_base;
46
47            for yi in cell_neighbours(yr) {
48                let hash: i32 = hash2(seed, x_primed, y_primed);
49                let [rand_x, rand_y] = *RAND_VECS_2D[hash].as_array();
50
51                let vec_x: f32 = (xi as f32 - x) + rand_x * jitter;
52                let vec_y: f32 = (yi as f32 - y) + rand_y * jitter;
53
54                let new_distance: f32 = vec_x * vec_x + vec_y * vec_y;
55
56                if new_distance < distance0 {
57                    distance0 = new_distance;
58                    closest_hash = hash;
59                }
60
61                y_primed = y_primed.wrapping_add(PRIME_Y);
62            }
63            x_primed = x_primed.wrapping_add(PRIME_X);
64        }
65
66        closest_hash as f32 * (1.0 / 2147483648.0)
67    }
68
69    #[inline]
70    fn gen3(self, [x, y, z]: [f32; 3], seed: i32) -> f32 {
71        // implementation from FastNoiseLite
72        use crate::from_fast_noise_lite::{cell_neighbours, hash3, round_to_int, JITTER_3D, PRIME_X, PRIME_Y, PRIME_Z, RAND_VECS_3D};
73
74        let jitter = self.jitter * JITTER_3D;
75
76        let xr: i32 = round_to_int(x);
77        let yr: i32 = round_to_int(y);
78        let zr: i32 = round_to_int(z);
79
80        let mut distance0: f32 = 1e10;
81        let mut closest_hash: i32 = 0;
82
83        let mut x_primed: i32 = xr.wrapping_sub(1).wrapping_mul(PRIME_X);
84        let y_primed_base: i32 = yr.wrapping_sub(1).wrapping_mul(PRIME_Y);
85        let z_primed_base: i32 = zr.wrapping_sub(1).wrapping_mul(PRIME_Z);
86
87        for xi in cell_neighbours(xr) {
88            let mut y_primed: i32 = y_primed_base;
89
90            for yi in cell_neighbours(yr) {
91                let mut z_primed: i32 = z_primed_base;
92
93                for zi in cell_neighbours(zr) {
94                    let hash: i32 = hash3(seed, x_primed, y_primed, z_primed);
95                    let [rand_x, rand_y, rand_z, _] = *RAND_VECS_3D[hash].as_array();
96
97                    let vec_x: f32 = (xi as f32 - x) + rand_x * jitter;
98                    let vec_y: f32 = (yi as f32 - y) + rand_y * jitter;
99                    let vec_z: f32 = (zi as f32 - z) + rand_z * jitter;
100
101                    let new_distance: f32 = vec_x * vec_x + vec_y * vec_y + vec_z * vec_z;
102
103                    if new_distance < distance0 {
104                        distance0 = new_distance;
105                        closest_hash = hash;
106                    }
107
108                    z_primed = z_primed.wrapping_add(PRIME_Z);
109                }
110                y_primed = y_primed.wrapping_add(PRIME_Y);
111            }
112            x_primed = x_primed.wrapping_add(PRIME_X);
113        }
114
115        closest_hash as f32 * (1.0 / 2147483648.0)
116    }
117
118    #[inline]
119    fn gen4(self, point: [f32; 4], seed: i32) -> f32 {
120        CustomCellValue::default().jitter(self.jitter).gen4(point, seed)
121    }
122
123    #[inline]
124    #[cfg(feature = "nightly-simd")]
125    fn gen2a(self, point: f32x2, seed: i32) -> f32 {
126        // based on the implementation from FastNoiseLite
127        use crate::from_fast_noise_lite::{cell_neighbours, hash2, length_squared, round_to_int, splat, JITTER_2D, PRIME_X, PRIME_Y, RAND_VECS_2D};
128
129        let jitter = self.jitter * JITTER_2D;
130
131        let rounded = round_to_int(point);
132        let mut distance: f32 = 1e10;
133        let mut closest_hash: i32 = 0;
134
135        let mut x_primed = rounded[0].wrapping_sub(1).wrapping_mul(PRIME_X);
136        let y_primed_base = rounded[1].wrapping_sub(1).wrapping_mul(PRIME_Y);
137
138        for xi in cell_neighbours(rounded[0]) {
139            let mut y_primed = y_primed_base;
140
141            for yi in cell_neighbours(rounded[1]) {
142                let hash = hash2(seed, x_primed, y_primed);
143                let rand = RAND_VECS_2D[hash].0;
144                let coor = f32x2::from_array([xi as f32, yi as f32]);
145                let vec = (coor - point) + rand * splat(jitter);
146                let new_distance = length_squared(vec);
147
148                if new_distance < distance {
149                    distance = new_distance;
150                    closest_hash = hash;
151                }
152
153                y_primed = y_primed.wrapping_add(PRIME_Y);
154            }
155            x_primed = x_primed.wrapping_add(PRIME_X);
156        }
157
158        closest_hash as f32 * (1.0 / 2147483648.0)
159    }
160
161    #[inline]
162    #[cfg(feature = "nightly-simd")]
163    fn gen3a(self, point: f32x4, seed: i32) -> f32 {
164        // based on the implementation from FastNoiseLite
165        use crate::from_fast_noise_lite::{cell_neighbours, hash3, length_squared, round_to_int, splat, JITTER_3D, PRIME_X, PRIME_Y, PRIME_Z, RAND_VECS_3D};
166
167        let jitter = self.jitter * JITTER_3D;
168
169        let rounded = round_to_int(point);
170
171        let mut distance: f32 = 1e10;
172        let mut closest_hash: i32 = 0;
173
174        let mut x_primed = rounded[0].wrapping_sub(1).wrapping_mul(PRIME_X);
175        let y_primed_base = rounded[1].wrapping_sub(1).wrapping_mul(PRIME_Y);
176        let z_primed_base = rounded[2].wrapping_sub(1).wrapping_mul(PRIME_Z);
177
178        for xi in cell_neighbours(rounded[0]) {
179            let mut y_primed = y_primed_base;
180
181            for yi in cell_neighbours(rounded[1]) {
182                let mut z_primed = z_primed_base;
183
184                for zi in cell_neighbours(rounded[2]) {
185                    let hash = hash3(seed, x_primed, y_primed, z_primed);
186                    let rand = RAND_VECS_3D[hash].0;
187                    let coor = f32x4::from_array([xi as f32, yi as f32, zi as f32, zi as f32]);
188                    let vec = (coor - point) + rand * splat(jitter);
189                    let new_distance = length_squared(vec);
190
191                    if new_distance < distance {
192                        distance = new_distance;
193                        closest_hash = hash;
194                    }
195
196                    z_primed = z_primed.wrapping_add(PRIME_Z);
197                }
198                y_primed = y_primed.wrapping_add(PRIME_Y);
199            }
200            x_primed = x_primed.wrapping_add(PRIME_X);
201        }
202
203        closest_hash as f32 * (1.0 / 2147483648.0)
204    }
205
206    #[inline]
207    #[cfg(feature = "nightly-simd")]
208    fn gen4a(self, point: f32x4, seed: i32) -> f32 {
209        CustomCellValue::default().jitter(self.jitter).gen4a(point, seed)
210    }
211}