noise/
permutationtable.rs1use core::fmt;
2use rand::{
3 distr::{Distribution, StandardUniform},
4 seq::SliceRandom,
5 Rng, SeedableRng,
6};
7use rand_xorshift::XorShiftRng;
8
9const TABLE_SIZE: usize = 256;
10
11pub trait NoiseHasher: Send + Sync {
12 fn hash(&self, to_hash: &[isize]) -> usize;
13}
14
15#[derive(Copy, Clone)]
20pub struct PermutationTable {
21 values: [u8; TABLE_SIZE],
22}
23
24impl Distribution<PermutationTable> for StandardUniform {
25 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> PermutationTable {
27 let mut perm_table = PermutationTable {
28 values: core::array::from_fn(|x| x as u8),
29 };
30 perm_table.values.shuffle(rng);
31
32 perm_table
33 }
34}
35
36impl PermutationTable {
37 pub fn new(seed: u32) -> Self {
42 let mut real = [0; 16];
43 real[0] = 1;
44 for i in 1..4 {
45 real[i * 4] = seed as u8;
46 real[(i * 4) + 1] = (seed >> 8) as u8;
47 real[(i * 4) + 2] = (seed >> 16) as u8;
48 real[(i * 4) + 3] = (seed >> 24) as u8;
49 }
50 let mut rng: XorShiftRng = SeedableRng::from_seed(real);
51 rng.random()
52 }
53}
54
55impl NoiseHasher for PermutationTable {
56 fn hash(&self, to_hash: &[isize]) -> usize {
57 let index = to_hash
58 .iter()
59 .map(|&a| (a & 0xff) as usize)
60 .reduce(|a, b| self.values[a] as usize ^ b)
61 .unwrap();
62 self.values[index] as usize
63 }
64}
65
66impl fmt::Debug for PermutationTable {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 write!(f, "PermutationTable {{ .. }}")
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use crate::{NoiseFn, Perlin, Seedable};
75 use rand::random;
76
77 #[test]
78 fn test_random_seed() {
79 let perlin = Perlin::default().set_seed(random());
80 let _ = perlin.get([1.0, 2.0, 3.0]);
81 }
82
83 #[test]
84 fn test_negative_params() {
85 let perlin = Perlin::default();
86 let _ = perlin.get([-1.0, 2.0, 3.0]);
87 }
88}