veloren_world/util/
structure.rs

1use super::{RandomField, Sampler};
2use vek::*;
3
4#[derive(Clone)]
5pub struct StructureGen2d {
6    freq: u32,
7    spread: u32,
8    x_field: RandomField,
9    y_field: RandomField,
10    seed_field: RandomField,
11}
12
13pub type StructureField = (Vec2<i32>, u32);
14
15impl StructureGen2d {
16    pub fn new(seed: u32, freq: u32, spread: u32) -> Self {
17        Self {
18            freq,
19            spread,
20            x_field: RandomField::new(seed + 0),
21            y_field: RandomField::new(seed + 1),
22            seed_field: RandomField::new(seed + 2),
23        }
24    }
25
26    #[inline]
27    fn sample_to_index_internal(freq: i32, pos: Vec2<i32>) -> Vec2<i32> {
28        pos.map(|e| e.div_euclid(freq))
29    }
30
31    #[inline]
32    pub fn sample_to_index(&self, pos: Vec2<i32>) -> Vec2<i32> {
33        Self::sample_to_index_internal(self.freq as i32, pos)
34    }
35
36    #[inline]
37    fn freq_offset(freq: i32) -> i32 { freq / 2 }
38
39    #[inline]
40    fn spread_mul(spread: u32) -> u32 { spread * 2 }
41
42    #[inline]
43    fn index_to_sample_internal(
44        freq: i32,
45        freq_offset: i32,
46        spread: i32,
47        spread_mul: u32,
48        x_field: RandomField,
49        y_field: RandomField,
50        seed_field: RandomField,
51        index: Vec2<i32>,
52    ) -> StructureField {
53        let center = index * freq + freq_offset;
54        let pos = Vec3::from(center);
55        (
56            center
57                + if spread_mul > 0 {
58                    Vec2::new(
59                        (x_field.get(pos) % spread_mul) as i32 - spread,
60                        (y_field.get(pos) % spread_mul) as i32 - spread,
61                    )
62                } else {
63                    Vec2::zero()
64                },
65            seed_field.get(pos),
66        )
67    }
68
69    /// Note: Generates all possible closest samples for elements in the range
70    /// of min to max, *exclusive.*
71    pub fn iter(
72        &self,
73        min: Vec2<i32>,
74        max: Vec2<i32>,
75    ) -> impl Iterator<Item = StructureField> + use<> {
76        let freq = self.freq;
77        let spread = self.spread;
78        let spread_mul = Self::spread_mul(spread);
79        assert!(spread * 2 == spread_mul);
80        assert!(spread_mul <= freq);
81        let spread = spread as i32;
82        let freq = freq as i32;
83        let freq_offset = Self::freq_offset(freq);
84        assert!(freq_offset * 2 == freq);
85
86        let min_index = Self::sample_to_index_internal(freq, min) - 1;
87        let max_index = Self::sample_to_index_internal(freq, max) + 1;
88        assert!(min_index.x < max_index.x);
89        // NOTE: xlen > 0
90        let xlen = (max_index.x - min_index.x) as u32;
91        assert!(min_index.y < max_index.y);
92        // NOTE: ylen > 0
93        let ylen = (max_index.y - min_index.y) as u32;
94        // NOTE: Cannot fail, since every product of u32s fits in a u64.
95        let len = ylen as u64 * xlen as u64;
96        // NOTE: since iteration is *exclusive* for the initial range, it's fine that we
97        // don't go up to the maximum value.
98        // NOTE: we convert to usize first, and then iterate, because we want to make
99        // sure we get a properly indexed parallel iterator that can deal with
100        // the whole range at once.
101        let x_field = self.x_field;
102        let y_field = self.y_field;
103        let seed_field = self.seed_field;
104        (0..len).map(move |xy| {
105            let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32);
106            Self::index_to_sample_internal(
107                freq,
108                freq_offset,
109                spread,
110                spread_mul,
111                x_field,
112                y_field,
113                seed_field,
114                index,
115            )
116        })
117    }
118}
119
120impl Sampler<'static> for StructureGen2d {
121    type Index = Vec2<i32>;
122    type Sample = [StructureField; 9];
123
124    fn get(&self, sample_pos: Self::Index) -> Self::Sample {
125        let mut samples = [(Vec2::zero(), 0); 9];
126
127        let freq = self.freq;
128        let spread = self.spread;
129        let spread_mul = Self::spread_mul(spread);
130        let spread = spread as i32;
131        let freq = freq as i32;
132        let freq_offset = Self::freq_offset(freq);
133
134        let sample_closest = Self::sample_to_index_internal(freq, sample_pos);
135
136        for i in 0..3 {
137            for j in 0..3 {
138                let index = sample_closest + Vec2::new(i as i32, j as i32) - 1;
139                let sample = Self::index_to_sample_internal(
140                    freq,
141                    freq_offset,
142                    spread,
143                    spread_mul,
144                    self.x_field,
145                    self.y_field,
146                    self.seed_field,
147                    index,
148                );
149                samples[i * 3 + j] = sample;
150            }
151        }
152
153        samples
154    }
155}