1use crate::material::{NoiseKind, NoiseLayer, PARAMS};
2
3#[derive(Clone, Copy, Debug, PartialEq, Default)]
4pub struct Fibre {
5 pub across: f32,
6 pub along: f32,
7 pub fine: f32,
8 pub mottle: f32,
9 pub ripple: f32,
10 pub swell: f32,
11 pub fibre_gain: f32,
12 pub mottle_gain: f32,
13 pub ripple_gain: f32,
14 pub swell_gain: f32,
15}
16
17impl Fibre {
18 pub const SAMPLE: Self = Self {
19 across: 2400.0,
20 along: 800.0,
21 fine: 6000.0,
22 mottle: 120.0,
23 ripple: 4800.0,
24 swell: 80.0,
25 fibre_gain: 0.06,
26 mottle_gain: 0.04,
27 ripple_gain: 0.07,
28 swell_gain: 0.01,
29 };
30
31 pub fn layer(self, amplitude: f32, seed: u32) -> NoiseLayer {
32 layer(NoiseKind::Fibre, self.params(), amplitude, seed)
33 }
34
35 pub fn params(self) -> [f32; PARAMS] {
36 fill(&[
37 self.across,
38 self.along,
39 self.fine,
40 self.mottle,
41 self.ripple,
42 self.swell,
43 self.fibre_gain,
44 self.mottle_gain,
45 self.ripple_gain,
46 self.swell_gain,
47 ])
48 }
49
50 pub fn from_params(p: &[f32; PARAMS]) -> Self {
51 Self {
52 across: p[0],
53 along: p[1],
54 fine: p[2],
55 mottle: p[3],
56 ripple: p[4],
57 swell: p[5],
58 fibre_gain: p[6],
59 mottle_gain: p[7],
60 ripple_gain: p[8],
61 swell_gain: p[9],
62 }
63 }
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Default)]
67pub struct Crinkle {
68 pub frequencies: [f32; 2],
69 pub gains: [f32; 2],
70}
71
72impl Crinkle {
73 pub const SAMPLE: Self = Self {
74 frequencies: [300.0, 650.0],
75 gains: [0.15, 0.06],
76 };
77
78 pub fn layer(self, amplitude: f32, seed: u32) -> NoiseLayer {
79 layer(NoiseKind::Crinkle, self.params(), amplitude, seed)
80 }
81
82 pub fn params(self) -> [f32; PARAMS] {
83 fill(&[
84 self.frequencies[0],
85 self.frequencies[1],
86 self.gains[0],
87 self.gains[1],
88 ])
89 }
90
91 pub fn from_params(p: &[f32; PARAMS]) -> Self {
92 Self {
93 frequencies: [p[0], p[1]],
94 gains: [p[2], p[3]],
95 }
96 }
97}
98
99#[derive(Clone, Copy, Debug, PartialEq, Default)]
100pub struct PlankWood {
101 pub width: f32,
102 pub rings: f32,
103 pub warp: f32,
104 pub figure: [f32; 2],
105 pub tone: f32,
106 pub figure_depth: f32,
107 pub seam_floor: f32,
108 pub roughness: f32,
109 pub jitter: f32,
110}
111
112impl PlankWood {
113 pub const SAMPLE: Self = Self {
114 width: 0.15,
115 rings: 60.0,
116 warp: 0.03,
117 figure: [80.0, 600.0],
118 tone: 0.3,
119 figure_depth: 0.4,
120 seam_floor: 0.4,
121 roughness: 0.45,
122 jitter: 2.5,
123 };
124
125 pub fn layer(self, amplitude: f32, seed: u32) -> NoiseLayer {
126 layer(NoiseKind::PlankWood, self.params(), amplitude, seed)
127 }
128
129 pub fn params(self) -> [f32; PARAMS] {
130 fill(&[
131 self.width,
132 self.rings,
133 self.warp,
134 self.figure[0],
135 self.figure[1],
136 self.tone,
137 self.figure_depth,
138 self.seam_floor,
139 self.roughness,
140 self.jitter,
141 ])
142 }
143
144 pub fn from_params(p: &[f32; PARAMS]) -> Self {
145 Self {
146 width: p[0],
147 rings: p[1],
148 warp: p[2],
149 figure: [p[3], p[4]],
150 tone: p[5],
151 figure_depth: p[6],
152 seam_floor: p[7],
153 roughness: p[8],
154 jitter: p[9],
155 }
156 }
157}
158
159#[derive(Clone, Copy, Debug, PartialEq, Default)]
160pub struct WallMottle {
161 pub broad: [f32; 2],
162 pub fine: [f32; 2],
163 pub swell: [f32; 2],
164 pub broad_gain: f32,
165 pub fine_gain: f32,
166 pub swell_gains: [f32; 2],
167}
168
169impl WallMottle {
170 pub const SAMPLE: Self = Self {
171 broad: [2.5, 7.0],
172 fine: [400.0, 1400.0],
173 swell: [250.0, 36.0],
174 broad_gain: 0.12,
175 fine_gain: 0.05,
176 swell_gains: [0.016, 0.006],
177 };
178
179 pub fn layer(self, amplitude: f32, seed: u32) -> NoiseLayer {
180 layer(NoiseKind::WallMottle, self.params(), amplitude, seed)
181 }
182
183 pub fn params(self) -> [f32; PARAMS] {
184 fill(&[
185 self.broad[0],
186 self.broad[1],
187 self.fine[0],
188 self.fine[1],
189 self.swell[0],
190 self.swell[1],
191 self.broad_gain,
192 self.fine_gain,
193 self.swell_gains[0],
194 self.swell_gains[1],
195 ])
196 }
197
198 pub fn from_params(p: &[f32; PARAMS]) -> Self {
199 Self {
200 broad: [p[0], p[1]],
201 fine: [p[2], p[3]],
202 swell: [p[4], p[5]],
203 broad_gain: p[6],
204 fine_gain: p[7],
205 swell_gains: [p[8], p[9]],
206 }
207 }
208}
209
210#[derive(Clone, Copy, Debug, PartialEq, Default)]
211pub struct Grime {
212 pub frequencies: [f32; 2],
213 pub dirty: [f32; 3],
214 pub clean: [f32; 3],
215 pub roughness: [f32; 2],
216}
217
218impl Grime {
219 pub const SAMPLE: Self = Self {
220 frequencies: [160.0, 800.0],
221 dirty: [0.9, 0.84, 0.76],
222 clean: [1.03, 1.02, 1.0],
223 roughness: [1.2, 0.65],
224 };
225
226 pub fn layer(self, amplitude: f32, seed: u32) -> NoiseLayer {
227 layer(NoiseKind::Grime, self.params(), amplitude, seed)
228 }
229
230 pub fn params(self) -> [f32; PARAMS] {
231 fill(&[
232 self.frequencies[0],
233 self.frequencies[1],
234 self.dirty[0],
235 self.dirty[1],
236 self.dirty[2],
237 self.clean[0],
238 self.clean[1],
239 self.clean[2],
240 self.roughness[0],
241 self.roughness[1],
242 ])
243 }
244
245 pub fn from_params(p: &[f32; PARAMS]) -> Self {
246 Self {
247 frequencies: [p[0], p[1]],
248 dirty: [p[2], p[3], p[4]],
249 clean: [p[5], p[6], p[7]],
250 roughness: [p[8], p[9]],
251 }
252 }
253}
254
255#[derive(Clone, Copy, Debug, PartialEq, Default)]
256pub struct Scratch {
257 pub line: f32,
258 pub smudge: [f32; 2],
259 pub speck: f32,
260}
261
262impl Scratch {
263 pub const SAMPLE: Self = Self {
264 line: 800.0,
265 smudge: [20.0, 55.0],
266 speck: 2400.0,
267 };
268
269 pub fn layer(self, amplitude: f32, seed: u32) -> NoiseLayer {
270 layer(NoiseKind::Scratch, self.params(), amplitude, seed)
271 }
272
273 pub fn params(self) -> [f32; PARAMS] {
274 fill(&[self.line, self.smudge[0], self.smudge[1], self.speck])
275 }
276
277 pub fn from_params(p: &[f32; PARAMS]) -> Self {
278 Self {
279 line: p[0],
280 smudge: [p[1], p[2]],
281 speck: p[3],
282 }
283 }
284}
285
286#[derive(Clone, Copy, Debug, PartialEq, Default)]
287pub struct CoatWobble {
288 pub frequencies: [f32; 3],
289 pub weights: [f32; 2],
290}
291
292impl CoatWobble {
293 pub const SAMPLE: Self = Self {
294 frequencies: [800.0, 48.0, 20.0],
295 weights: [0.5, 1.0],
296 };
297
298 pub fn layer(self, amplitude: f32, seed: u32) -> NoiseLayer {
299 layer(NoiseKind::CoatWobble, self.params(), amplitude, seed)
300 }
301
302 pub fn params(self) -> [f32; PARAMS] {
303 fill(&[
304 self.frequencies[0],
305 self.frequencies[1],
306 self.frequencies[2],
307 self.weights[0],
308 self.weights[1],
309 ])
310 }
311
312 pub fn from_params(p: &[f32; PARAMS]) -> Self {
313 Self {
314 frequencies: [p[0], p[1], p[2]],
315 weights: [p[3], p[4]],
316 }
317 }
318}
319
320fn layer(kind: NoiseKind, params: [f32; PARAMS], amplitude: f32, seed: u32) -> NoiseLayer {
321 NoiseLayer::new(kind, 1.0, amplitude, seed).with_params(params)
322}
323
324fn fill(values: &[f32]) -> [f32; PARAMS] {
325 let mut out = [0.0; PARAMS];
326 out[..values.len()].copy_from_slice(values);
327 out
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 fn counted(values: usize) -> [f32; PARAMS] {
335 std::array::from_fn(|k| if k < values { k as f32 + 1.5 } else { 0.0 })
336 }
337
338 #[test]
339 fn every_kind_reads_back_the_params_it_writes() {
340 assert_eq!(Fibre::from_params(&counted(10)).params(), counted(10));
341 assert_eq!(Crinkle::from_params(&counted(4)).params(), counted(4));
342 assert_eq!(PlankWood::from_params(&counted(10)).params(), counted(10));
343 assert_eq!(WallMottle::from_params(&counted(10)).params(), counted(10));
344 assert_eq!(Grime::from_params(&counted(10)).params(), counted(10));
345 assert_eq!(Scratch::from_params(&counted(4)).params(), counted(4));
346 assert_eq!(CoatWobble::from_params(&counted(5)).params(), counted(5));
347 }
348
349 #[test]
350 fn a_kind_builds_its_own_layer() {
351 let coat = CoatWobble {
352 frequencies: [400.0, 30.0, 8.0],
353 weights: [0.5, 0.25],
354 };
355 let layer = coat.layer(0.02, 4);
356 assert_eq!(layer.kind, NoiseKind::CoatWobble);
357 assert_eq!(layer.amplitude, 0.02);
358 assert_eq!(layer.seed, 4);
359 assert_eq!(CoatWobble::from_params(&layer.params), coat);
360 assert!(!PlankWood::default().layer(1.0, 0).active());
361 let wood = PlankWood {
362 width: 0.2,
363 ..PlankWood::default()
364 };
365 assert!(wood.layer(1.0, 0).active());
366 }
367}