polydat_core/numeric/
noise.rs1pub struct PermTable {
12 pub perm: [u8; 512],
14}
15
16impl PermTable {
17 pub fn new(seed: u64) -> Self {
19 use xxhash_rust::xxh3::xxh3_64;
20 let mut p: Vec<u8> = (0..=255).collect();
21 let mut s = seed;
23 for i in (1..256).rev() {
24 s = xxh3_64(&s.to_le_bytes());
25 let j = (s as usize) % (i + 1);
26 p.swap(i, j);
27 }
28 let mut perm = [0u8; 512];
29 for i in 0..512 {
30 perm[i] = p[i & 255];
31 }
32 Self { perm }
33 }
34
35 #[inline]
36 pub fn hash(&self, i: i32) -> u8 {
38 self.perm[(i & 255) as usize]
39 }
40}
41
42#[inline]
47fn fade(t: f64) -> f64 {
48 t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
50}
51
52#[inline]
53fn lerp(t: f64, a: f64, b: f64) -> f64 {
54 a + t * (b - a)
55}
56
57#[inline]
58fn grad1d(hash: u8, x: f64) -> f64 {
59 if hash & 1 == 0 { x } else { -x }
60}
61
62#[inline]
63fn grad2d(hash: u8, x: f64, y: f64) -> f64 {
64 match hash & 3 {
65 0 => x + y,
66 1 => -x + y,
67 2 => x - y,
68 _ => -x - y,
69 }
70}
71
72pub fn perlin_1d_algo(perm: &PermTable, x: f64) -> f64 {
74 let xi = x.floor() as i32;
75 let xf = x - x.floor();
76 let u = fade(xf);
77
78 let a = perm.hash(xi);
79 let b = perm.hash(xi.wrapping_add(1));
80
81 lerp(u, grad1d(a, xf), grad1d(b, xf - 1.0))
82}
83
84pub fn perlin_2d_algo(perm: &PermTable, x: f64, y: f64) -> f64 {
86 let xi = x.floor() as i32;
87 let yi = y.floor() as i32;
88 let xf = x - x.floor();
89 let yf = y - y.floor();
90
91 let u = fade(xf);
92 let v = fade(yf);
93
94 let aa = perm.hash((perm.hash(xi) as i32).wrapping_add(yi));
95 let ab = perm.hash((perm.hash(xi) as i32).wrapping_add(yi).wrapping_add(1));
96 let ba = perm.hash((perm.hash(xi.wrapping_add(1)) as i32).wrapping_add(yi));
97 let bb = perm.hash(
98 (perm.hash(xi.wrapping_add(1)) as i32)
99 .wrapping_add(yi)
100 .wrapping_add(1),
101 );
102
103 lerp(
104 v,
105 lerp(u, grad2d(aa, xf, yf), grad2d(ba, xf - 1.0, yf)),
106 lerp(u, grad2d(ab, xf, yf - 1.0), grad2d(bb, xf - 1.0, yf - 1.0)),
107 )
108}
109
110const F2: f64 = 0.3660254037844386; const G2: f64 = 0.21132486540518713; pub fn simplex_2d_algo(perm: &PermTable, x: f64, y: f64) -> f64 {
119 let s = (x + y) * F2;
120 let i = (x + s).floor() as i32;
121 let j = (y + s).floor() as i32;
122
123 let t = (i + j) as f64 * G2;
124 let x0 = x - (i as f64 - t);
125 let y0 = y - (j as f64 - t);
126
127 let (i1, j1) = if x0 > y0 { (1, 0) } else { (0, 1) };
128
129 let x1 = x0 - i1 as f64 + G2;
130 let y1 = y0 - j1 as f64 + G2;
131 let x2 = x0 - 1.0 + 2.0 * G2;
132 let y2 = y0 - 1.0 + 2.0 * G2;
133
134 let gi0 = perm.hash(i.wrapping_add(perm.hash(j) as i32));
135 let gi1 = perm.hash(
136 i.wrapping_add(i1)
137 .wrapping_add(perm.hash(j.wrapping_add(j1)) as i32),
138 );
139 let gi2 = perm.hash(
140 i.wrapping_add(1)
141 .wrapping_add(perm.hash(j.wrapping_add(1)) as i32),
142 );
143
144 let mut n0 = 0.0;
145 let t0 = 0.5 - x0 * x0 - y0 * y0;
146 if t0 > 0.0 {
147 let t0 = t0 * t0;
148 n0 = t0 * t0 * grad2d(gi0, x0, y0);
149 }
150
151 let mut n1 = 0.0;
152 let t1 = 0.5 - x1 * x1 - y1 * y1;
153 if t1 > 0.0 {
154 let t1 = t1 * t1;
155 n1 = t1 * t1 * grad2d(gi1, x1, y1);
156 }
157
158 let mut n2 = 0.0;
159 let t2 = 0.5 - x2 * x2 - y2 * y2;
160 if t2 > 0.0 {
161 let t2 = t2 * t2;
162 n2 = t2 * t2 * grad2d(gi2, x2, y2);
163 }
164
165 70.0 * (n0 + n1 + n2)
167}
168
169impl crate::derive_support::PolydatSetup for PermTable {}
170
171const FBM_LACUNARITY: f64 = 2.0;
173const FBM_PERSISTENCE: f64 = 0.5;
175
176pub fn fbm_1d(perm: &PermTable, base_x: f64, frequency: f64, octaves: u32) -> f64 {
179 let mut total = 0.0;
180 let mut freq = frequency;
181 let mut amp = 1.0;
182 let mut max_amp = 0.0;
183
184 for _ in 0..octaves {
185 total += perlin_1d_algo(perm, base_x * freq) * amp;
186 max_amp += amp;
187 freq *= FBM_LACUNARITY;
188 amp *= FBM_PERSISTENCE;
189 }
190
191 total / max_amp
193}
194
195pub fn fbm_2d(perm: &PermTable, base_x: f64, base_y: f64, frequency: f64, octaves: u32) -> f64 {
197 let mut total = 0.0;
198 let mut freq = frequency;
199 let mut amp = 1.0;
200 let mut max_amp = 0.0;
201
202 for _ in 0..octaves {
203 total += perlin_2d_algo(perm, base_x * freq, base_y * freq) * amp;
204 max_amp += amp;
205 freq *= FBM_LACUNARITY;
206 amp *= FBM_PERSISTENCE;
207 }
208
209 total / max_amp
210}