1struct Random {
4 seed: i32,
5 m: i32,
6 a: i32,
7 q: i32,
8 r: i32,
9}
10
11impl Random {
12 fn with_seed(seed: i32) -> Self {
13 let seed = Self::validate_seed(seed);
14 let m = i32::max_value();
15 let a = 16807; let q = 127773; let r = 2836; Self { seed, m, a, q, r }
19 }
20
21 fn validate_seed(seed: i32) -> i32 {
22 if seed <= 0 {
23 -(seed % (i32::max_value() - 1)) + 1
24 } else if seed > i32::max_value() - 1 {
25 i32::max_value() - 1
26 } else {
27 seed
28 }
29 }
30
31 fn next_long(&mut self) -> i32 {
32 let res = self.a * (self.seed % self.q) - self.r * (self.seed / self.q);
33 let res = if res <= 0 { res + self.m } else { res };
34 self.seed = res;
35 res
36 }
37
38 fn next(&mut self) -> f32 {
39 self.next_long() as f32 / self.m as f32
40 }
41}
42
43struct PerlinSampler {
44 width: usize,
45 height: usize,
46 gradients: Vec<f32>,
47}
48
49impl PerlinSampler {
50 pub fn new(width: usize, height: usize, seed: i32) -> Self {
51 let mut rng = Random::with_seed(seed);
52 let mut gradients = Vec::with_capacity(width * height * 2);
53 const TAU: f32 = std::f32::consts::PI * 2.;
54 for _i in (0..(width * height * 2)).step_by(2) {
55 let phi = rng.next() * TAU;
56 let (x, y) = phi.sin_cos();
57 gradients.push(x);
58 gradients.push(y);
59 }
60 Self {
61 width,
62 height,
63 gradients,
64 }
65 }
66
67 pub fn dot(&self, x_cell: usize, y_cell: usize, vx: f32, vy: f32) -> f32 {
68 let offset = (x_cell + y_cell * self.width) * 2;
69 let wx = self.gradients[offset];
70 let wy = self.gradients[offset + 1];
71 wx * vx + wy * vy
72 }
73
74 pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
75 a + t * (b - a)
76 }
77
78 pub fn s_curve(t: f32) -> f32 {
79 t * t * (3. - 2. * t)
80 }
81
82 pub fn get(&self, x: f32, y: f32) -> f32 {
83 let x_cell = x.trunc() as usize;
84 let y_cell = y.trunc() as usize;
85 let x_fract = x.fract();
86 let y_fract = y.fract();
87
88 let x0 = x_cell;
89 let y0 = y_cell;
90 let x1 = if x_cell == (self.width - 1) {
91 0
92 } else {
93 x_cell + 1
94 };
95 let y1 = if y_cell == (self.height - 1) {
96 0
97 } else {
98 y_cell + 1
99 };
100
101 let v00 = self.dot(x0, y0, x_fract, y_fract);
102 let v10 = self.dot(x1, y0, x_fract - 1., y_fract);
103 let v01 = self.dot(x0, y1, x_fract, y_fract - 1.);
104 let v11 = self.dot(x1, y1, x_fract - 1., y_fract - 1.);
105
106 let vx0 = Self::lerp(v00, v10, Self::s_curve(x_fract));
107 let vx1 = Self::lerp(v01, v11, Self::s_curve(x_fract));
108
109 return Self::lerp(vx0, vx1, Self::s_curve(y_fract));
110 }
111}
112
113#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Default)]
114pub struct PerlinTextureSettings {
115 pub seed: i32,
116 pub width: usize,
117 pub height: usize,
118 pub period: u32,
119 pub levels: u32,
120 pub attenuation: ordered_float::NotNan<f32>,
121 pub color: bool,
122}
123
124fn raster_to_bytes(raster: Vec<f32>) -> Vec<u8> {
125 let mut bytes = vec![0u8; raster.len()];
126 for (p, f) in bytes.iter_mut().zip(raster.into_iter()) {
127 *p = (((f + 1.) / 2.) * 255.).round() as u8;
128 }
129 bytes
130}
131
132fn bytes(settings: PerlinTextureSettings) -> Vec<u8> {
133 let PerlinTextureSettings {
134 seed,
135 width,
136 height,
137 period,
138 levels,
139 attenuation,
140 color,
141 } = settings;
142 let attenuation = attenuation.into_inner();
143 let num_channels = if color { 3 } else { 1 };
144 let mut raster = vec![0f32; width * height * num_channels];
145 for channel in 0..num_channels {
146 let mut local_period_inv = 1. / period as f32;
147 let mut freq_inv = 1f32;
148 let mut atten = 1.;
149 let mut weight = 0f32;
150
151 for level in 0..levels {
152 let sampler = PerlinSampler::new(
153 (width as f32 * local_period_inv).ceil() as usize,
154 (height as f32 * local_period_inv).ceil() as usize,
155 seed * 100 + channel as i32 * 10 + level as i32,
156 );
157 for y in 0..height {
158 for x in 0..width {
159 let val = sampler.get(x as f32 * local_period_inv, y as f32 * local_period_inv);
160 raster[(x + y * width) * num_channels + channel] += val * freq_inv.powf(atten);
161 }
162 }
163 weight += freq_inv.powf(atten);
164 freq_inv *= 0.5;
165 local_period_inv *= 2.;
166 atten *= attenuation;
167 }
168
169 let weight_inv = 1. / weight;
170 for y in 0..height {
171 for x in 0..width {
172 raster[(x + y * width) * num_channels + channel] *= weight_inv;
173 }
174 }
175 }
176
177 raster_to_bytes(raster)
178}
179
180pub fn create_perlin_texture(
181 gl: &mut solstice::Context,
182 settings: PerlinTextureSettings,
183) -> crate::ImageResult {
184 let width = settings.width;
185 let height = settings.height;
186 let format = if settings.color {
187 solstice::PixelFormat::RGB8
188 } else {
189 solstice::PixelFormat::LUMINANCE
190 };
191 let bytes = bytes(settings);
192
193 use solstice::image::*;
194 use solstice::texture::*;
195 Image::with_data(
196 gl,
197 TextureType::Tex2D,
198 format,
199 width as u32,
200 height as u32,
201 bytes.as_slice(),
202 Settings {
203 mipmaps: false,
204 filter: FilterMode::Linear,
205 wrap: WrapMode::Repeat,
206 ..Settings::default()
207 },
208 )
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 #[test]
216 fn random_test() {
217 let mut rng = Random::with_seed(1);
218 assert_eq!(rng.next_long(), 16807);
219 assert_eq!(rng.next_long(), 282475249);
220 assert_eq!(rng.next_long(), 1622650073);
221
222 assert_eq!(rng.next(), 0.4586501319234493);
223 assert_eq!(rng.next(), 0.5327672374121692);
224 assert_eq!(rng.next(), 0.21895918632809036);
225 }
226
227 #[test]
228 fn sampler_test() {
229 let sampler = PerlinSampler::new(2, 2, 0);
230
231 assert_eq!(CONTROL_GRADIENTS_4X4.len(), sampler.gradients.len());
232 for (a, b) in CONTROL_GRADIENTS_4X4.iter().zip(sampler.gradients.iter()) {
233 assert!((a - b).abs() <= 0.00001, "{} != {}", a, b);
235 }
236
237 assert_eq!(sampler.get(0., 0.), 0.);
238 assert_eq!(sampler.get(0.5, 0.0), -0.18387488976327257);
239 assert_eq!(sampler.get(1., 0.), 0.);
240 assert_eq!(sampler.get(1.5, 0.0), 0.18387488976327257);
241
242 assert!((sampler.get(0., 0.5) - 0.24119700031647284).abs() <= std::f32::EPSILON);
243 assert!((sampler.get(1.5, 1.0) - 0.31406892987757684).abs() <= std::f32::EPSILON);
244 }
245
246 #[test]
247 fn black_and_white_raster_test() {
248 fn dup_channel(bytes: Vec<u8>) -> Vec<u8> {
249 let mut new_bytes = Vec::with_capacity(bytes.len() * 4);
250 for byte in bytes {
251 new_bytes.push(byte);
252 new_bytes.push(byte);
253 new_bytes.push(byte);
254 new_bytes.push(255);
255 }
256 new_bytes
257 }
258
259 let settings = PerlinTextureSettings {
260 seed: 0,
261 width: 4,
262 height: 4,
263 period: 2,
264 levels: 1,
265 attenuation: std::convert::TryInto::try_into(0.0).unwrap(),
266 color: false,
267 };
268 let bytes = dup_channel(bytes(settings));
269 assert_eq!(&SEED0_CELL2_LEVEL1_4X4_BW[..], bytes.as_slice());
270 }
271
272 #[test]
273 fn color_raster_test() {
274 fn add_alpha(bytes: Vec<u8>) -> Vec<u8> {
275 let mut new_bytes = Vec::with_capacity(bytes.len() / 3);
276 for byte in bytes.chunks_exact(3) {
277 new_bytes.extend_from_slice(byte);
278 new_bytes.push(255);
279 }
280 new_bytes
281 }
282
283 let settings = PerlinTextureSettings {
284 seed: 0,
285 width: 4,
286 height: 4,
287 period: 2,
288 levels: 1,
289 attenuation: std::convert::TryInto::try_into(0.0).unwrap(),
290 color: true,
291 };
292 let bytes = add_alpha(bytes(settings));
293 assert_eq!(&SEED0_CELL2_LEVEL1_4X4_COLOR[..], bytes.as_slice());
294 }
295
296 const CONTROL_GRADIENTS_4X4: [f32; 8] = [
297 0.00004917452831956654,
298 0.9999999987909329,
299 0.7355487335814098,
300 0.6774718153006694,
301 -0.9993798653316448,
302 0.03521199752504148,
303 0.25689585417866245,
304 -0.9664390928071026,
305 ];
306
307 const SEED0_CELL2_LEVEL1_4X4_BW: [u8; 64] = [
308 128, 128, 128, 255, 104, 104, 104, 255, 128, 128, 128, 255, 151, 151, 151, 255, 158, 158,
309 158, 255, 137, 137, 137, 255, 180, 180, 180, 255, 201, 201, 201, 255, 128, 128, 128, 255,
310 87, 87, 87, 255, 128, 128, 128, 255, 168, 168, 168, 255, 97, 97, 97, 255, 54, 54, 54, 255,
311 75, 75, 75, 255, 118, 118, 118, 255,
312 ];
313
314 const SEED0_CELL2_LEVEL1_4X4_COLOR: [u8; 64] = [
315 128, 128, 128, 255, 104, 98, 151, 255, 128, 128, 128, 255, 151, 157, 104, 255, 158, 189,
316 135, 255, 137, 154, 121, 255, 180, 142, 91, 255, 201, 178, 105, 255, 128, 128, 128, 255,
317 87, 133, 120, 255, 128, 128, 128, 255, 168, 122, 135, 255, 97, 66, 120, 255, 54, 77, 150,
318 255, 75, 113, 164, 255, 118, 101, 134, 255,
319 ];
320}