1#[inline]
9fn xorshift(mut x: u64) -> u64 {
10 x ^= x << 13;
11 x ^= x >> 7;
12 x ^= x << 17;
13 x.wrapping_mul(0x2545_F491_4F6C_DD1D)
14}
15
16#[inline]
17fn hash_u32(seed: u32) -> f32 {
18 let h = xorshift(seed as u64 | ((seed as u64) << 32));
19 ((h >> 40) as f32) / ((1u32 << 24) as f32) * 2.0 - 1.0
20}
21
22#[inline]
25pub fn value_noise(t: f32, freq: f32, seed: u32) -> f32 {
26 let idx = (t * freq).floor() as i32 as u32;
27 hash_u32(seed ^ idx)
28}
29
30pub fn perlin1d(t: f32, freq: f32, seed: u32) -> f32 {
33 let x = t * freq;
34 let i = x.floor();
35 let f = x - i;
36 let a = hash_u32(seed ^ (i as i32 as u32));
37 let b = hash_u32(seed ^ ((i as i32 + 1) as u32));
38 let s = f * f * (3.0 - 2.0 * f);
39 a + (b - a) * s
40}
41
42pub fn brown_walk(t: f32, step_hz: f32, scale: f32, seed: u32) -> f32 {
48 let mut sum = 0.0;
49 let mut amp = 1.0;
50 let mut freq = step_hz;
51 for octave in 0..4 {
52 sum += perlin1d(t, freq, seed.wrapping_add(octave * 131)) * amp;
53 amp *= 0.5;
54 freq *= 2.0;
55 }
56 sum * scale
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn deterministic() {
65 assert_eq!(value_noise(1.3, 2.0, 42), value_noise(1.3, 2.0, 42));
66 assert_eq!(perlin1d(0.7, 1.5, 7), perlin1d(0.7, 1.5, 7));
67 }
68
69 #[test]
70 fn perlin_in_range() {
71 for i in 0..1000 {
72 let v = perlin1d(i as f32 * 0.01, 3.7, 99);
73 assert!(v.abs() <= 1.01, "perlin out of range: {v}");
74 }
75 }
76}