use crate::resources::types::*;
pub(crate) fn generate_edge_indices(triangle_indices: &[u32]) -> Vec<u32> {
use std::collections::HashSet;
let mut edges: HashSet<(u32, u32)> = HashSet::new();
let mut result = Vec::new();
for tri in triangle_indices.chunks(3) {
if tri.len() < 3 {
continue;
}
let pairs = [(tri[0], tri[1]), (tri[1], tri[2]), (tri[2], tri[0])];
for (a, b) in &pairs {
let edge = if a < b { (*a, *b) } else { (*b, *a) };
if edges.insert(edge) {
result.push(*a);
result.push(*b);
}
}
}
result
}
pub(crate) fn build_unit_cube() -> (Vec<Vertex>, Vec<u32>) {
let white = [1.0f32, 1.0, 1.0, 1.0];
let mut verts: Vec<Vertex> = Vec::with_capacity(24);
let mut idx: Vec<u32> = Vec::with_capacity(36);
let mut add_face = |positions: [[f32; 3]; 4], normal: [f32; 3]| {
let base = verts.len() as u32;
for pos in &positions {
verts.push(Vertex {
position: *pos,
normal,
colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
});
}
idx.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
};
add_face(
[
[0.5, -0.5, -0.5],
[0.5, 0.5, -0.5],
[0.5, 0.5, 0.5],
[0.5, -0.5, 0.5],
],
[1.0, 0.0, 0.0],
);
add_face(
[
[-0.5, -0.5, 0.5],
[-0.5, 0.5, 0.5],
[-0.5, 0.5, -0.5],
[-0.5, -0.5, -0.5],
],
[-1.0, 0.0, 0.0],
);
add_face(
[
[-0.5, 0.5, -0.5],
[-0.5, 0.5, 0.5],
[0.5, 0.5, 0.5],
[0.5, 0.5, -0.5],
],
[0.0, 1.0, 0.0],
);
add_face(
[
[-0.5, -0.5, 0.5],
[-0.5, -0.5, -0.5],
[0.5, -0.5, -0.5],
[0.5, -0.5, 0.5],
],
[0.0, -1.0, 0.0],
);
add_face(
[
[-0.5, -0.5, 0.5],
[0.5, -0.5, 0.5],
[0.5, 0.5, 0.5],
[-0.5, 0.5, 0.5],
],
[0.0, 0.0, 1.0],
);
add_face(
[
[0.5, -0.5, -0.5],
[-0.5, -0.5, -0.5],
[-0.5, 0.5, -0.5],
[0.5, 0.5, -0.5],
],
[0.0, 0.0, -1.0],
);
(verts, idx)
}
pub(crate) fn build_glyph_arrow() -> (Vec<Vertex>, Vec<u32>) {
let white = [1.0f32, 1.0, 1.0, 1.0];
let segments = 16usize;
let mut verts: Vec<Vertex> = Vec::new();
let mut idx: Vec<u32> = Vec::new();
let shaft_r = 0.05f32;
let shaft_bot = 0.0f32;
let shaft_top = 0.7f32;
let cone_r = 0.12f32;
let cone_bot = shaft_top;
let cone_tip = 1.0f32;
let ring_verts = |verts: &mut Vec<Vertex>, z: f32, r: f32, normal_z: f32| {
for i in 0..segments {
let angle = 2.0 * std::f32::consts::PI * (i as f32) / (segments as f32);
let (s, c) = angle.sin_cos();
let nx = if r > 0.0 { c } else { 0.0 };
let ny = if r > 0.0 { s } else { 0.0 };
let len = (nx * nx + ny * ny + normal_z * normal_z).sqrt();
verts.push(Vertex {
position: [c * r, s * r, z],
normal: [nx / len, ny / len, normal_z / len],
colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
});
}
};
let shaft_bot_base = verts.len() as u32;
ring_verts(&mut verts, shaft_bot, shaft_r, 0.0);
let shaft_bot_center = verts.len() as u32;
verts.push(Vertex {
position: [0.0, 0.0, shaft_bot],
normal: [0.0, 0.0, -1.0],
colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
});
for i in 0..segments {
let a = shaft_bot_base + i as u32;
let b = shaft_bot_base + ((i + 1) % segments) as u32;
idx.extend_from_slice(&[shaft_bot_center, b, a]);
}
let shaft_top_ring_base = verts.len() as u32;
ring_verts(&mut verts, shaft_bot, shaft_r, 0.0); let shaft_top_ring_top = verts.len() as u32;
ring_verts(&mut verts, shaft_top, shaft_r, 0.0);
for i in 0..segments {
let a = shaft_top_ring_base + i as u32;
let b = shaft_top_ring_base + ((i + 1) % segments) as u32;
let c = shaft_top_ring_top + i as u32;
let d = shaft_top_ring_top + ((i + 1) % segments) as u32;
idx.extend_from_slice(&[a, b, d, a, d, c]);
}
let cone_len = ((cone_tip - cone_bot).powi(2) + cone_r * cone_r).sqrt();
let normal_z_cone = cone_r / cone_len; let normal_r_cone = (cone_tip - cone_bot) / cone_len;
let cone_base_ring = verts.len() as u32;
for i in 0..segments {
let angle = 2.0 * std::f32::consts::PI * (i as f32) / (segments as f32);
let (s, c) = angle.sin_cos();
verts.push(Vertex {
position: [c * cone_r, s * cone_r, cone_bot],
normal: [c * normal_r_cone, s * normal_r_cone, normal_z_cone],
colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
});
}
let cone_tip_v = verts.len() as u32;
verts.push(Vertex {
position: [0.0, 0.0, cone_tip],
normal: [0.0, 0.0, 1.0],
colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
});
for i in 0..segments {
let a = cone_base_ring + i as u32;
let b = cone_base_ring + ((i + 1) % segments) as u32;
idx.extend_from_slice(&[a, b, cone_tip_v]);
}
let cone_cap_base = verts.len() as u32;
for i in 0..segments {
let angle = 2.0 * std::f32::consts::PI * (i as f32) / (segments as f32);
let (s, c) = angle.sin_cos();
verts.push(Vertex {
position: [c * cone_r, s * cone_r, cone_bot],
normal: [0.0, 0.0, -1.0],
colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
});
}
let cone_cap_center = verts.len() as u32;
verts.push(Vertex {
position: [0.0, 0.0, cone_bot],
normal: [0.0, 0.0, -1.0],
colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
});
for i in 0..segments {
let a = cone_cap_base + i as u32;
let b = cone_cap_base + ((i + 1) % segments) as u32;
idx.extend_from_slice(&[cone_cap_center, b, a]);
}
for v in &mut verts {
let [px, py, pz] = v.position;
v.position = [px, pz, -py];
let [nx, ny, nz] = v.normal;
v.normal = [nx, nz, -ny];
}
(verts, idx)
}
pub(crate) fn build_glyph_sphere() -> (Vec<Vertex>, Vec<u32>) {
let white = [1.0f32, 1.0, 1.0, 1.0];
let t = (1.0 + 5.0f32.sqrt()) / 2.0;
let raw_verts = [
[-1.0, t, 0.0],
[1.0, t, 0.0],
[-1.0, -t, 0.0],
[1.0, -t, 0.0],
[0.0, -1.0, t],
[0.0, 1.0, t],
[0.0, -1.0, -t],
[0.0, 1.0, -t],
[t, 0.0, -1.0],
[t, 0.0, 1.0],
[-t, 0.0, -1.0],
[-t, 0.0, 1.0],
];
let mut positions: Vec<[f32; 3]> = raw_verts
.iter()
.map(|v| {
let l = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
[v[0] / l, v[1] / l, v[2] / l]
})
.collect();
let mut triangles: Vec<[usize; 3]> = vec![
[0, 11, 5],
[0, 5, 1],
[0, 1, 7],
[0, 7, 10],
[0, 10, 11],
[1, 5, 9],
[5, 11, 4],
[11, 10, 2],
[10, 7, 6],
[7, 1, 8],
[3, 9, 4],
[3, 4, 2],
[3, 2, 6],
[3, 6, 8],
[3, 8, 9],
[4, 9, 5],
[2, 4, 11],
[6, 2, 10],
[8, 6, 7],
[9, 8, 1],
];
for _ in 0..2 {
let mut mid_cache: std::collections::HashMap<(usize, usize), usize> =
std::collections::HashMap::new();
let mut new_triangles: Vec<[usize; 3]> = Vec::with_capacity(triangles.len() * 4);
let midpoint = |positions: &mut Vec<[f32; 3]>,
a: usize,
b: usize,
cache: &mut std::collections::HashMap<(usize, usize), usize>|
-> usize {
let key = if a < b { (a, b) } else { (b, a) };
if let Some(&idx) = cache.get(&key) {
return idx;
}
let pa = positions[a];
let pb = positions[b];
let mx = (pa[0] + pb[0]) * 0.5;
let my = (pa[1] + pb[1]) * 0.5;
let mz = (pa[2] + pb[2]) * 0.5;
let l = (mx * mx + my * my + mz * mz).sqrt();
let idx = positions.len();
positions.push([mx / l, my / l, mz / l]);
cache.insert(key, idx);
idx
};
for tri in &triangles {
let a = tri[0];
let b = tri[1];
let c = tri[2];
let ab = midpoint(&mut positions, a, b, &mut mid_cache);
let bc = midpoint(&mut positions, b, c, &mut mid_cache);
let ca = midpoint(&mut positions, c, a, &mut mid_cache);
new_triangles.push([a, ab, ca]);
new_triangles.push([b, bc, ab]);
new_triangles.push([c, ca, bc]);
new_triangles.push([ab, bc, ca]);
}
triangles = new_triangles;
}
let verts: Vec<Vertex> = positions
.iter()
.map(|&p| Vertex {
position: p,
normal: p, colour: white,
uv: [0.0, 0.0],
tangent: [0.0, 0.0, 0.0, 1.0],
})
.collect();
let idx: Vec<u32> = triangles
.iter()
.flat_map(|t| [t[0] as u32, t[1] as u32, t[2] as u32])
.collect();
(verts, idx)
}