Skip to main content

qualia_client_core/chora/layers/
mesh_gen.rs

1use qualia_core_db::render::assets::Mesh;
2
3pub fn generate_sphere_mesh(segments: u32, rings: u32) -> Mesh {
4    let mut positions = Vec::new();
5    let mut triangles = Vec::new();
6
7    for r in 0..=rings {
8        let phi = std::f32::consts::PI * (r as f32) / (rings as f32);
9        let y = phi.cos();
10        let radius = phi.sin();
11        for s in 0..=segments {
12            let theta = 2.0 * std::f32::consts::PI * (s as f32) / (segments as f32);
13            let x = radius * theta.cos();
14            let z = radius * theta.sin();
15            positions.push([x, y, z]);
16        }
17    }
18
19    for r in 0..rings {
20        for s in 0..segments {
21            let a = r * (segments + 1) + s;
22            let b = a + segments + 1;
23            if r > 0 {
24                triangles.push([a, b, a + 1]);
25            }
26            if r < rings - 1 {
27                triangles.push([a + 1, b, b + 1]);
28            }
29        }
30    }
31
32    let min = [-1.0, -1.0, -1.0];
33    let max = [1.0, 1.0, 1.0];
34    Mesh {
35        positions,
36        triangles,
37        min,
38        max,
39    }
40}
41
42pub fn generate_sphere_mesh_colored(
43    segments: u32,
44    rings: u32,
45    color_sampler: impl Fn(f32, f32) -> [f32; 3],
46) -> (Vec<[f32; 3]>, Vec<[f32; 4]>, Vec<u32>) {
47    let mesh = generate_sphere_mesh(segments, rings);
48    let mut colors = Vec::with_capacity(mesh.positions.len());
49    for &p in &mesh.positions {
50        let lat = p[1].asin().to_degrees();
51        let lon = p[0].atan2(p[2]).to_degrees();
52        let [r, g, b] = color_sampler(lat, lon);
53        colors.push([r, g, b, 1.0]);
54    }
55    let indices: Vec<u32> = mesh
56        .triangles
57        .iter()
58        .flat_map(|t| [t[0], t[1], t[2]])
59        .collect();
60    (mesh.positions, colors, indices)
61}
62
63pub fn generate_starfield_mesh(positions: &[[f32; 3]], colors: &[[f32; 4]]) -> Mesh {
64    let triangles: Vec<[u32; 3]> = (0..positions.len() as u32)
65        .step_by(1)
66        .map(|i| [i, i, i])
67        .collect();
68    let _ = colors;
69    let min = [-1e6, -1e6, -1e6];
70    let max = [1e6, 1e6, 1e6];
71    Mesh {
72        positions: positions.to_vec(),
73        triangles,
74        min,
75        max,
76    }
77}
78
79pub fn generate_terrain_mesh(heightfield: &[f32], width: u32, height: u32, scale: f32) -> Mesh {
80    let mut positions = Vec::with_capacity((width * height) as usize);
81    let mut triangles = Vec::new();
82
83    for y in 0..height {
84        for x in 0..width {
85            let idx = (y * width + x) as usize;
86            let h = heightfield.get(idx).copied().unwrap_or(0.0) * scale;
87            let px = (x as f32 / width as f32 - 0.5) * 2.0;
88            let pz = (y as f32 / height as f32 - 0.5) * 2.0;
89            positions.push([px, h, pz]);
90        }
91    }
92
93    for y in 0..height - 1 {
94        for x in 0..width - 1 {
95            let a = (y * width + x) as u32;
96            let b = a + 1;
97            let c = a + width;
98            let d = c + 1;
99            triangles.push([a, c, b]);
100            triangles.push([b, c, d]);
101        }
102    }
103
104    let min = [-1.0, 0.0, -1.0];
105    let max = [1.0, scale, 1.0];
106    Mesh {
107        positions,
108        triangles,
109        min,
110        max,
111    }
112}