noise_functions_config/
lib.rs

1//! Configurable noise generator struct for the [`noise-functions`](https://docs.rs/noise-functions) crate.
2//!
3//! Every `enum` of this crate implements `FromStr`, `to_str` and has a `VARIANTS` constant.
4//!
5//! ## Feature flags
6#![cfg_attr(
7    feature = "document-features",
8    cfg_attr(doc, doc = ::document_features::document_features!())
9)]
10#![cfg_attr(not(feature = "std"), no_std)]
11#![cfg_attr(feature = "nightly-simd", feature(portable_simd))]
12#![cfg_attr(docsrs, feature(doc_auto_cfg))]
13
14extern crate alloc;
15
16use alloc::boxed::Box;
17
18use noise_functions::{Noise as _, OpenSimplexNoise as _, *};
19
20#[cfg(feature = "nightly-simd")]
21use core::simd::*;
22
23pub use noise_functions;
24
25macro_rules! or_else {
26    ({ } else { $($else:tt)* }) => { $($else)* };
27    ({ $($tokens:tt)+ } else { $($else:tt)* }) => { $($tokens)* };
28}
29
30macro_rules! simple_enum {
31	(
32		enum $name:ident {
33			$(
34                $(#[$variant_attr:meta])*
35                $variant:ident $(= $variant_name:literal)?
36            ),* $(,)?
37		}
38	) => {
39		#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40		pub enum $name {
41			$(
42                $(#[$variant_attr])*
43                $variant,
44            )*
45		}
46
47		impl core::str::FromStr for $name {
48			type Err = noise_functions::errors::EnumFromStrError;
49
50			fn from_str(s: &str) -> Result<Self, Self::Err> {
51				Ok(match s {
52					$(or_else!({$($variant_name)?} else { stringify!($variant) }) => Self::$variant,)*
53					_ => return Err(noise_functions::errors::EnumFromStrError),
54				})
55			}
56		}
57
58		impl $name {
59			pub const VARIANTS: &'static [Self] = &[
60				$(Self::$variant,)*
61			];
62
63			pub fn to_str(self) -> &'static str {
64				[$(or_else!({$($variant_name)?} else { stringify!($variant) })),*][self as usize]
65			}
66		}
67
68		impl core::fmt::Debug for $name {
69			fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
70				f.write_str(self.to_str())
71			}
72		}
73
74		impl core::fmt::Display for $name {
75			fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
76				f.write_str(self.to_str())
77			}
78		}
79	};
80}
81
82simple_enum! {
83    enum Noise {
84        Value,
85        ValueCubic,
86        #[default]
87        Perlin,
88        Simplex,
89        OpenSimplex2,
90        OpenSimplex2s,
91        CellValue,
92        CellDistance,
93        CellDistanceSq,
94    }
95}
96
97simple_enum! {
98    enum Modifier {
99        #[default]
100        None,
101        Ridged,
102        TriangleWave,
103    }
104}
105
106simple_enum! {
107    enum Improve {
108        #[default]
109        None,
110        X = "2D X",
111        Xy = "3D Xy",
112        Xz = "3D Xz",
113        Xyz = "4D Xyz",
114        XyzXy = "4D XyzXy",
115        XyzXz = "4D XyzXz",
116        XyZw = "4D XyZw",
117    }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq)]
121pub struct Config {
122    pub noise: Noise,
123    pub seed: i32,
124    pub frequency: f32,
125
126    // modifiers
127    pub modifier: Modifier,
128    pub triangle_wave_frequency: f32,
129
130    // fractal
131    pub fractal: bool,
132    pub lacunarity: f32,
133    pub octaves: u32,
134    pub gain: f32,
135    pub weighted_strength: f32,
136
137    // open simplex 2
138    pub improve: Improve,
139
140    // cell
141    pub jitter: f32,
142
143    // tiling
144    pub tileable: bool,
145    pub tile_width: f32,
146    pub tile_height: f32,
147}
148
149impl Default for Config {
150    fn default() -> Self {
151        Self {
152            noise: Default::default(),
153            seed: Default::default(),
154            frequency: 1.0,
155
156            // modifiers
157            modifier: Modifier::default(),
158            triangle_wave_frequency: 2.0,
159
160            // fractal
161            fractal: false,
162            lacunarity: 2.0,
163            octaves: 3,
164            gain: 0.5,
165            weighted_strength: 0.0,
166
167            // open simplex 2
168            improve: Default::default(),
169
170            // cell
171            jitter: 1.0,
172
173            // tiling
174            tileable: false,
175            tile_width: 1.0,
176            tile_height: 1.0,
177        }
178    }
179}
180
181macro_rules! finish {
182    ($self:ident, $noise:expr) => {
183        Some(Box::new($noise.seed($self.seed).frequency($self.frequency)))
184    };
185}
186
187macro_rules! fractal {
188    ($self:ident, $noise:expr) => {
189        if $self.fractal {
190            finish!($self, $noise.fbm($self.octaves, $self.gain, $self.lacunarity).weighted($self.weighted_strength))
191        } else {
192            finish!($self, $noise)
193        }
194    };
195}
196
197macro_rules! modifier {
198    ($self:ident, $noise:expr) => {
199        match $self.modifier {
200            Modifier::None => fractal!($self, $noise),
201            Modifier::Ridged => fractal!($self, $noise.ridged()),
202            Modifier::TriangleWave => fractal!($self, $noise.triangle_wave($self.triangle_wave_frequency)),
203        }
204    };
205}
206
207macro_rules! apply_tileable {
208    ($self:ident, $noise:expr) => {
209        if $self.tileable {
210            modifier!($self, $noise.tileable($self.tile_width, $self.tile_height))
211        } else {
212            modifier!($self, $noise)
213        }
214    };
215}
216
217macro_rules! dont_apply_tileable {
218    ($self:ident, $noise:expr) => {
219        if $self.tileable {
220            None
221        } else {
222            modifier!($self, $noise)
223        }
224    };
225}
226
227macro_rules! if_supports_4d {
228    (Value { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
229    (ValueCubic { $($then:tt)* } else { $($else:tt)* }) => { $($else)* };
230    (Perlin { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
231    (Simplex { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
232    (OpenSimplex2 { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
233    (OpenSimplex2s { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
234    (CellValue { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
235    (CellDistance { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
236    (CellDistanceSq { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
237}
238
239macro_rules! tileable {
240    (2, $self:ident, $noise_name:ident $($noise_rest:tt)*) => {
241        if_supports_4d!($noise_name {
242            apply_tileable!($self, $noise_name $($noise_rest)*)
243        } else {
244            dont_apply_tileable!($self, $noise_name $($noise_rest)*)
245        })
246    };
247    (3, $self:ident, $noise_name:ident $($noise_rest:tt)*) => {
248        dont_apply_tileable!($self, $noise_name $($noise_rest)*)
249    };
250    (4, $self:ident, $noise_name:ident $($noise_rest:tt)*) => {
251        if_supports_4d!($noise_name {
252            dont_apply_tileable!($self, $noise_name $($noise_rest)*)
253        } else {
254            None
255        })
256    };
257}
258
259macro_rules! base {
260    ($dim:tt, $self:ident) => {
261        match $self.noise {
262            Noise::Value => tileable!($dim, $self, Value),
263            Noise::ValueCubic => tileable!($dim, $self, ValueCubic),
264            Noise::Perlin => tileable!($dim, $self, Perlin),
265            Noise::Simplex => tileable!($dim, $self, Simplex),
266            Noise::OpenSimplex2 => match $self.improve {
267                Improve::None => tileable!($dim, $self, OpenSimplex2),
268                Improve::X => tileable!($dim, $self, OpenSimplex2.improve2_x()),
269                Improve::Xy => tileable!($dim, $self, OpenSimplex2.improve3_xy()),
270                Improve::Xz => tileable!($dim, $self, OpenSimplex2.improve3_xz()),
271                Improve::Xyz => tileable!($dim, $self, OpenSimplex2.improve4_xyz()),
272                Improve::XyzXy => tileable!($dim, $self, OpenSimplex2.improve4_xyz_xy()),
273                Improve::XyzXz => tileable!($dim, $self, OpenSimplex2.improve4_xyz_xz()),
274                Improve::XyZw => tileable!($dim, $self, OpenSimplex2.improve4_xy_zw()),
275            },
276            Noise::OpenSimplex2s => match $self.improve {
277                Improve::None => tileable!($dim, $self, OpenSimplex2s),
278                Improve::X => tileable!($dim, $self, OpenSimplex2s.improve2_x()),
279                Improve::Xy => tileable!($dim, $self, OpenSimplex2s.improve3_xy()),
280                Improve::Xz => tileable!($dim, $self, OpenSimplex2s.improve3_xz()),
281                Improve::Xyz => tileable!($dim, $self, OpenSimplex2s.improve4_xyz()),
282                Improve::XyzXy => tileable!($dim, $self, OpenSimplex2s.improve4_xyz_xy()),
283                Improve::XyzXz => tileable!($dim, $self, OpenSimplex2s.improve4_xyz_xz()),
284                Improve::XyZw => tileable!($dim, $self, OpenSimplex2s.improve4_xy_zw()),
285            },
286            Noise::CellValue => tileable!($dim, $self, CellValue::default().jitter($self.jitter)),
287            Noise::CellDistance => tileable!($dim, $self, CellDistance::default().jitter($self.jitter)),
288            Noise::CellDistanceSq => tileable!($dim, $self, CellDistanceSq::default().jitter($self.jitter)),
289        }
290    };
291}
292
293macro_rules! sampler {
294    ($dim:tt, $self:ident) => {
295        base!($dim, $self)
296    };
297}
298
299impl Config {
300    pub fn sampler2(&self) -> Option<Box<dyn Sample<2>>> {
301        sampler!(2, self)
302    }
303
304    #[cfg(feature = "nightly-simd")]
305    pub fn sampler2a(&self) -> Option<Box<dyn Sample<2, f32x2>>> {
306        sampler!(2, self)
307    }
308
309    pub fn sampler3(&self) -> Option<Box<dyn Sample<3>>> {
310        sampler!(3, self)
311    }
312
313    #[cfg(feature = "nightly-simd")]
314    pub fn sampler3a(&self) -> Option<Box<dyn Sample<3, f32x4>>> {
315        sampler!(3, self)
316    }
317
318    pub fn sampler4(&self) -> Option<Box<dyn Sample<4>>> {
319        sampler!(4, self)
320    }
321
322    #[cfg(feature = "nightly-simd")]
323    pub fn sampler4a(&self) -> Option<Box<dyn Sample<4, f32x4>>> {
324        sampler!(4, self)
325    }
326}