Skip to main content

camera_toggle/util/
mod.rs

1use 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}