use crate::Mesh;
use crate::MeshData;
use crate::Vec3;
use macaw::ColorRgba8;
pub fn create_box_mesh(extents: Vec3, color: Option<ColorRgba8>) -> Mesh {
let s = extents / 2.0;
let mut positions = vec![
Vec3::new(s.x, -s.y, s.z), Vec3::new(s.x, -s.y, -s.z), Vec3::new(s.x, s.y, -s.z), Vec3::new(s.x, s.y, s.z), Vec3::new(-s.x, -s.y, s.z), Vec3::new(-s.x, -s.y, -s.z), Vec3::new(-s.x, s.y, -s.z), Vec3::new(-s.x, s.y, s.z), ];
let mut indices: Vec<u32> = vec![
4, 0, 3, 4, 3, 7, 0, 1, 2, 0, 2, 3, 1, 5, 6, 1, 6, 2, 5, 4, 7, 5, 7, 6, 7, 3, 2, 7, 2, 6,
0, 5, 1, 0, 4, 5,
];
let use_normals = true;
let normals = use_normals.then(|| {
let face_normals = indices
.chunks(3)
.map(|i| {
let p = positions[i[0] as usize];
let a = positions[i[1] as usize] - p;
let b = positions[i[2] as usize] - p;
a.cross(b).normalize()
})
.collect::<Vec<_>>();
positions = indices
.iter()
.map(|i| positions[*i as usize])
.collect::<Vec<_>>();
indices = (0..36_u32).collect::<Vec<_>>();
indices
.iter()
.map(|i| *face_normals[(i / 3) as usize].as_ref())
.collect::<Vec<[f32; 3]>>()
});
let color = color.unwrap_or(ColorRgba8([255, 255, 255, 255]));
let colors = vec![color; positions.len()];
let half_size = s;
Mesh {
bounding_box_min: -half_size,
bounding_box_max: half_size,
bounding_sphere_radius: half_size.length(),
primitive_count: (indices.len() / 3) as u64,
data: Some(MeshData {
name: "box".into(),
indices,
positions: positions
.iter()
.map(|p| *p.as_ref())
.collect::<Vec<[f32; 3]>>(),
normals,
colors: Some(colors),
}),
}
}
pub fn create_sphere_mesh(
radius: f32,
subdivision_x: usize,
subdivision_y: usize,
color: Option<ColorRgba8>,
) -> Mesh {
let subdivision_x = 3.max(subdivision_x as u32);
let subdivision_y = 3.max(subdivision_y as u32);
let delta_x = 2.0 * std::f32::consts::PI / subdivision_x as f32;
let delta_y = std::f32::consts::PI / subdivision_y as f32;
let mut positions = vec![];
let mut normals = vec![];
positions.push(Vec3::new(0.0, radius, 0.0));
for y in 1..subdivision_y {
let angle_y = delta_y * y as f32;
for x in 0..subdivision_x {
let angle_x = delta_x * x as f32;
let pos = Vec3::new(
angle_x.cos() * angle_y.sin(),
angle_y.cos(),
angle_x.sin() * angle_y.sin(),
) * radius;
positions.push(pos);
}
}
positions.push(Vec3::new(0.0, -radius, 0.0));
for p in &positions {
normals.push(p.normalize());
}
let mut indices: Vec<u32> = vec![];
for i in 0..subdivision_x {
indices.push(0);
indices.push(1 + (i + 1) % subdivision_x);
indices.push(1 + i);
}
for y in 0..subdivision_y - 2 {
for x in 0..subdivision_x {
let b = 1 + y * subdivision_x + x;
let b_next = 1 + y * subdivision_x + (x + 1) % subdivision_x;
indices.push(b);
indices.push(b_next);
indices.push(b + subdivision_x);
indices.push(b_next);
indices.push(b_next + subdivision_x);
indices.push(b + subdivision_x);
}
}
let b = 1 + (subdivision_y - 2) * subdivision_x;
for i in 0..subdivision_x {
indices.push(b + (i + 1) % subdivision_x);
indices.push(b + subdivision_x);
indices.push(b + i);
}
let color = color.unwrap_or(ColorRgba8([255, 255, 255, 255]));
let colors = vec![color; positions.len()];
Mesh {
bounding_box_min: -Vec3::splat(radius),
bounding_box_max: Vec3::splat(radius),
bounding_sphere_radius: radius,
primitive_count: (indices.len() / 3) as u64,
data: Some(MeshData {
name: "sphere".into(),
indices,
positions: positions
.iter()
.map(|p| *p.as_ref())
.collect::<Vec<[f32; 3]>>(),
normals: Some(
normals
.iter()
.map(|p| *p.as_ref())
.collect::<Vec<[f32; 3]>>(),
),
colors: Some(colors),
}),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn box_mesh() {
let color = Some(ColorRgba8([255, 255, 255, 255]));
create_box_mesh(Vec3::new(2.0, 1.0, 0.5), None)
.validate()
.unwrap();
create_box_mesh(Vec3::new(2.0, 1.0, 0.5), color)
.validate()
.unwrap();
create_box_mesh(Vec3::new(-2.0, -1.0, -0.5), None)
.validate()
.unwrap();
create_box_mesh(Vec3::new(-2.0, -1.0, -0.5), color)
.validate()
.unwrap();
}
#[test]
fn sphere_mesh() {
assert_eq!(
create_sphere_mesh(5.0, 0, 0, None),
create_sphere_mesh(5.0, 3, 3, None),
);
assert_eq!(
create_sphere_mesh(5.0, 1, 0, None),
create_sphere_mesh(5.0, 3, 3, None),
);
assert_eq!(
create_sphere_mesh(5.0, 2, 0, None),
create_sphere_mesh(5.0, 3, 3, None),
);
assert_eq!(
create_sphere_mesh(5.0, 4, 0, None),
create_sphere_mesh(5.0, 4, 3, None),
);
assert_eq!(
create_sphere_mesh(5.0, 4, 1, None),
create_sphere_mesh(5.0, 4, 3, None),
);
assert_eq!(
create_sphere_mesh(5.0, 4, 2, None),
create_sphere_mesh(5.0, 4, 3, None),
);
assert_eq!(
create_sphere_mesh(5.0, 4, 3, None),
create_sphere_mesh(5.0, 4, 3, None),
);
assert_eq!(
create_sphere_mesh(5.0, 4, 4, None),
create_sphere_mesh(5.0, 4, 4, None),
);
}
}