camera_toggle/util/
mod.rs1use mittens_engine::engine;
2
3#[derive(Debug, Clone, Copy)]
4pub struct PerlinNoise {
5 perm: [u8; 512],
6}
7
8impl PerlinNoise {
9 pub fn new(seed: u32) -> Self {
10 let mut base = [0u8; 256];
11 for (i, slot) in base.iter_mut().enumerate() {
12 *slot = i as u8;
13 }
14
15 let mut state = seed;
16 for i in (1..256).rev() {
17 state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
18 let j = (state as usize) % (i + 1);
19 base.swap(i, j);
20 }
21
22 let mut perm = [0u8; 512];
23 for i in 0..512 {
24 perm[i] = base[i & 255];
25 }
26
27 Self { perm }
28 }
29
30 pub fn sample2(&self, x: f32, y: f32) -> f32 {
31 let xi = x.floor() as i32 & 255;
32 let yi = y.floor() as i32 & 255;
33
34 let xf = x - x.floor();
35 let yf = y - y.floor();
36
37 let u = fade(xf);
38 let v = fade(yf);
39
40 let aa = self.perm[(self.perm[xi as usize] as usize + yi as usize) & 255];
41 let ab = self.perm[(self.perm[xi as usize] as usize + ((yi + 1) as usize)) & 255];
42 let ba = self.perm[(self.perm[((xi + 1) & 255) as usize] as usize + yi as usize) & 255];
43 let bb =
44 self.perm[(self.perm[((xi + 1) & 255) as usize] as usize + ((yi + 1) as usize)) & 255];
45
46 let x1 = lerp(grad2(aa, xf, yf), grad2(ba, xf - 1.0, yf), u);
47 let x2 = lerp(grad2(ab, xf, yf - 1.0), grad2(bb, xf - 1.0, yf - 1.0), u);
48 lerp(x1, x2, v)
49 }
50
51 pub fn fractal2(&self, x: f32, y: f32, octaves: u32, lacunarity: f32, gain: f32) -> f32 {
52 let mut freq = 1.0;
53 let mut amp = 1.0;
54 let mut total = 0.0;
55 let mut norm = 0.0;
56
57 for _ in 0..octaves.max(1) {
58 total += self.sample2(x * freq, y * freq) * amp;
59 norm += amp;
60 freq *= lacunarity;
61 amp *= gain;
62 }
63
64 if norm > 0.0 { total / norm } else { 0.0 }
65 }
66}
67
68fn fade(t: f32) -> f32 {
69 t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
70}
71
72fn lerp(a: f32, b: f32, t: f32) -> f32 {
73 a + (b - a) * t
74}
75
76fn grad2(hash: u8, x: f32, y: f32) -> f32 {
77 match hash & 0x7 {
78 0 => x + y,
79 1 => -x + y,
80 2 => x - y,
81 3 => -x - y,
82 4 => x,
83 5 => -x,
84 6 => y,
85 _ => -y,
86 }
87}
88
89pub fn spawn_perlin_cube_patch(
90 universe: &mut engine::Universe,
91 anchor: [f32; 3],
92 width: usize,
93 depth: usize,
94) {
95 use engine::ecs::component::{ColorComponent, RenderableComponent, TransformComponent};
96
97 if width == 0 || depth == 0 {
98 return;
99 }
100
101 let noise = PerlinNoise::new(0xCA7F_2026);
102 let spacing = 0.22_f32;
103 let cube_size = 0.20_f32;
104 let sample_scale = 0.052_f32;
105 let height_scale = 2.6_f32;
106 let half_w = (width as f32 - 1.0) * spacing * 0.5;
107 let half_d = (depth as f32 - 1.0) * spacing * 0.5;
108
109 let root = universe
110 .world
111 .add_component(TransformComponent::new().with_position(anchor[0], anchor[1], anchor[2]));
112 universe.add(root);
113
114 for z in 0..depth {
115 for x in 0..width {
116 let nx = x as f32 * sample_scale;
117 let nz = z as f32 * sample_scale;
118 let h = noise.fractal2(nx, nz, 5, 2.0, 0.5);
119 let y = h * height_scale;
120
121 let tx = universe.world.add_component(
122 TransformComponent::new()
123 .with_position(x as f32 * spacing - half_w, y, z as f32 * spacing - half_d)
124 .with_scale(cube_size, cube_size, cube_size),
125 );
126 let renderable = universe.world.add_component(RenderableComponent::cube());
127
128 let shade = ((h + 1.0) * 0.5).clamp(0.0, 1.0);
129 let r = 0.10 + 0.18 * shade;
130 let g = 0.28 + 0.55 * shade;
131 let b = 0.40 + 0.22 * shade;
132 let color = universe
133 .world
134 .add_component(ColorComponent::rgba(r, g, b, 1.0));
135
136 let _ = universe.attach(root, tx);
137 let _ = universe.attach(tx, renderable);
138 let _ = universe.attach(renderable, color);
139 }
140 }
141}