1#![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 pub modifier: Modifier,
128 pub triangle_wave_frequency: f32,
129
130 pub fractal: bool,
132 pub lacunarity: f32,
133 pub octaves: u32,
134 pub gain: f32,
135 pub weighted_strength: f32,
136
137 pub improve: Improve,
139
140 pub jitter: f32,
142
143 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 modifier: Modifier::default(),
158 triangle_wave_frequency: 2.0,
159
160 fractal: false,
162 lacunarity: 2.0,
163 octaves: 3,
164 gain: 0.5,
165 weighted_strength: 0.0,
166
167 improve: Default::default(),
169
170 jitter: 1.0,
172
173 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}