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(&self, min: Vec2<i32>, max: Vec2<i32>) -> impl Iterator<Item = StructureField> {
72        let freq = self.freq;
73        let spread = self.spread;
74        let spread_mul = Self::spread_mul(spread);
75        assert!(spread * 2 == spread_mul);
76        assert!(spread_mul <= freq);
77        let spread = spread as i32;
78        let freq = freq as i32;
79        let freq_offset = Self::freq_offset(freq);
80        assert!(freq_offset * 2 == freq);
81
82        let min_index = Self::sample_to_index_internal(freq, min) - 1;
83        let max_index = Self::sample_to_index_internal(freq, max) + 1;
84        assert!(min_index.x < max_index.x);
85        // NOTE: xlen > 0
86        let xlen = (max_index.x - min_index.x) as u32;
87        assert!(min_index.y < max_index.y);
88        // NOTE: ylen > 0
89        let ylen = (max_index.y - min_index.y) as u32;
90        // NOTE: Cannot fail, since every product of u32s fits in a u64.
91        let len = ylen as u64 * xlen as u64;
92        // NOTE: since iteration is *exclusive* for the initial range, it's fine that we
93        // don't go up to the maximum value.
94        // NOTE: we convert to usize first, and then iterate, because we want to make
95        // sure we get a properly indexed parallel iterator that can deal with
96        // the whole range at once.
97        let x_field = self.x_field;
98        let y_field = self.y_field;
99        let seed_field = self.seed_field;
100        (0..len).map(move |xy| {
101            let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32);
102            Self::index_to_sample_internal(
103                freq,
104                freq_offset,
105                spread,
106                spread_mul,
107                x_field,
108                y_field,
109                seed_field,
110                index,
111            )
112        })
113    }
114}
115
116impl Sampler<'static> for StructureGen2d {
117    type Index = Vec2<i32>;
118    type Sample = [StructureField; 9];
119
120    fn get(&self, sample_pos: Self::Index) -> Self::Sample {
121        let mut samples = [(Vec2::zero(), 0); 9];
122
123        let freq = self.freq;
124        let spread = self.spread;
125        let spread_mul = Self::spread_mul(spread);
126        let spread = spread as i32;
127        let freq = freq as i32;
128        let freq_offset = Self::freq_offset(freq);
129
130        let sample_closest = Self::sample_to_index_internal(freq, sample_pos);
131
132        for i in 0..3 {
133            for j in 0..3 {
134                let index = sample_closest + Vec2::new(i as i32, j as i32) - 1;
135                let sample = Self::index_to_sample_internal(
136                    freq,
137                    freq_offset,
138                    spread,
139                    spread_mul,
140                    self.x_field,
141                    self.y_field,
142                    self.seed_field,
143                    index,
144                );
145                samples[i * 3 + j] = sample;
146            }
147        }
148
149        samples
150    }
151}