terrain_forge/noise/
modifiers.rs1use super::NoiseSource;
2
3pub struct Scale<S: NoiseSource> {
5 pub(crate) source: S,
6 pub(crate) factor: f64,
7}
8
9impl<S: NoiseSource> NoiseSource for Scale<S> {
10 fn sample(&self, x: f64, y: f64) -> f64 {
11 self.source.sample(x, y) * self.factor
12 }
13}
14
15pub struct Offset<S: NoiseSource> {
17 pub(crate) source: S,
18 pub(crate) amount: f64,
19}
20
21impl<S: NoiseSource> NoiseSource for Offset<S> {
22 fn sample(&self, x: f64, y: f64) -> f64 {
23 self.source.sample(x, y) + self.amount
24 }
25}
26
27pub struct Clamp<S: NoiseSource> {
29 pub(crate) source: S,
30 pub(crate) min: f64,
31 pub(crate) max: f64,
32}
33
34impl<S: NoiseSource> NoiseSource for Clamp<S> {
35 fn sample(&self, x: f64, y: f64) -> f64 {
36 self.source.sample(x, y).clamp(self.min, self.max)
37 }
38}
39
40pub struct Abs<S: NoiseSource> {
42 pub(crate) source: S,
43}
44
45impl<S: NoiseSource> NoiseSource for Abs<S> {
46 fn sample(&self, x: f64, y: f64) -> f64 {
47 self.source.sample(x, y).abs()
48 }
49}
50
51pub struct Blend<A: NoiseSource, B: NoiseSource, C: NoiseSource> {
53 pub source_a: A,
54 pub source_b: B,
55 pub control: C,
56}
57
58impl<A: NoiseSource, B: NoiseSource, C: NoiseSource> Blend<A, B, C> {
59 pub fn new(source_a: A, source_b: B, control: C) -> Self {
60 Self { source_a, source_b, control }
61 }
62}
63
64impl<A: NoiseSource, B: NoiseSource, C: NoiseSource> NoiseSource for Blend<A, B, C> {
65 fn sample(&self, x: f64, y: f64) -> f64 {
66 let a = self.source_a.sample(x, y);
67 let b = self.source_b.sample(x, y);
68 let t = (self.control.sample(x, y) + 1.0) * 0.5; a + t * (b - a)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::noise::{Perlin, NoiseExt};
77
78 #[test]
79 fn scale_modifier() {
80 let noise = Perlin::new(42).scale(2.0);
81 let base = Perlin::new(42);
82 let v1 = noise.sample(1.0, 1.0);
83 let v2 = base.sample(1.0, 1.0) * 2.0;
84 assert!((v1 - v2).abs() < 1e-10);
85 }
86
87 #[test]
88 fn offset_modifier() {
89 let noise = Perlin::new(42).offset(0.5);
90 let base = Perlin::new(42);
91 let v1 = noise.sample(1.0, 1.0);
92 let v2 = base.sample(1.0, 1.0) + 0.5;
93 assert!((v1 - v2).abs() < 1e-10);
94 }
95
96 #[test]
97 fn clamp_modifier() {
98 let noise = Perlin::new(42).clamp(-0.5, 0.5);
99 for i in 0..50 {
100 for j in 0..50 {
101 let v = noise.sample(i as f64 * 0.1, j as f64 * 0.1);
102 assert!(v >= -0.5 && v <= 0.5);
103 }
104 }
105 }
106
107 #[test]
108 fn abs_modifier() {
109 let noise = Perlin::new(42).abs();
110 for i in 0..50 {
111 for j in 0..50 {
112 let v = noise.sample(i as f64 * 0.1, j as f64 * 0.1);
113 assert!(v >= 0.0);
114 }
115 }
116 }
117
118 #[test]
119 fn chained_modifiers() {
120 let noise = Perlin::new(42)
121 .scale(0.5)
122 .offset(0.5)
123 .clamp(0.0, 1.0);
124
125 for i in 0..50 {
126 for j in 0..50 {
127 let v = noise.sample(i as f64 * 0.1, j as f64 * 0.1);
128 assert!(v >= 0.0 && v <= 1.0);
129 }
130 }
131 }
132}