use std::alloc::Layout; use crate::vector::Vec3; pub mod cube; pub mod vertex_buffer; pub const POSITION_VERTEX_ATTRIB_NAME: &str = "pos"; #[derive(Debug, Clone)] pub struct Mesh { vertex_buf: vertex_buffer::VertexBuffer, indices: Option>, } impl Mesh { pub fn builder() -> Builder { Builder::default() } pub fn vertex_buf(&self) -> &vertex_buffer::VertexBuffer { &self.vertex_buf } #[must_use] pub fn indices(&self) -> Option<&[u32]> { self.indices.as_deref() } #[must_use] pub fn indices_mut(&mut self) -> Option<&mut [u32]> { self.indices.as_deref_mut() } /// Finds the vertex positions that are furthest in every 3D direction. Keep in mind /// that this can be quite time-expensive if the mesh has many vertices. pub fn find_furthest_vertex_positions(&self) -> DirectionPositions { let mut pos_iter = self .vertex_buf() .iter::<[f32; 3]>(POSITION_VERTEX_ATTRIB_NAME) .map(|vertex_pos| Vec3::from(*vertex_pos)) .into_iter(); let first_pos = pos_iter.next().unwrap(); pos_iter .fold( FurthestPosAcc { up: FurthestPos::new(first_pos, &Vec3::UP), down: FurthestPos::new(first_pos, &Vec3::DOWN), left: FurthestPos::new(first_pos, &Vec3::LEFT), right: FurthestPos::new(first_pos, &Vec3::RIGHT), back: FurthestPos::new(first_pos, &Vec3::BACK), front: FurthestPos::new(first_pos, &Vec3::FRONT), }, |mut furthest_pos_acc, pos| { furthest_pos_acc.up.update_if_further(pos); furthest_pos_acc.down.update_if_further(pos); furthest_pos_acc.left.update_if_further(pos); furthest_pos_acc.right.update_if_further(pos); furthest_pos_acc.back.update_if_further(pos); furthest_pos_acc.front.update_if_further(pos); furthest_pos_acc }, ) .into() } } /// Mesh builder #[derive(Debug, Clone, Default)] pub struct Builder { vertex_buf: vertex_buffer::VertexBuffer, indices: Option>, } impl Builder { pub fn new() -> Self { Self::default() } pub fn vertices(mut self, vertices_bytes: vertex_buffer::VertexBuffer) -> Self { self.vertex_buf = vertices_bytes; self } pub fn indices(mut self, indices: impl IntoIterator) -> Self { self.indices = Some(indices.into_iter().collect()); self } pub fn build(self) -> Mesh { Mesh { vertex_buf: self.vertex_buf, indices: self.indices, } } } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum VertexAttrType { Float32, Float32Array { length: usize, }, } impl VertexAttrType { pub fn layout(&self) -> Layout { match self { Self::Float32 => Layout::new::(), Self::Float32Array { length } => Layout::array::(*length).unwrap(), } } } #[derive(Debug, Clone)] pub struct DirectionPositions { pub up: Vec3, pub down: Vec3, pub left: Vec3, pub right: Vec3, pub back: Vec3, pub front: Vec3, } impl<'mesh> From> for DirectionPositions { fn from(acc: FurthestPosAcc<'mesh>) -> Self { Self { up: acc.up.pos, down: acc.down.pos, left: acc.left.pos, right: acc.right.pos, back: acc.back.pos, front: acc.front.pos, } } } #[derive(Debug)] struct FurthestPosAcc<'mesh> { up: FurthestPos<'mesh>, down: FurthestPos<'mesh>, left: FurthestPos<'mesh>, right: FurthestPos<'mesh>, back: FurthestPos<'mesh>, front: FurthestPos<'mesh>, } #[derive(Debug)] struct FurthestPos<'mesh> { pos: Vec3, dot_prod: f32, direction: &'mesh Vec3, } impl<'mesh> FurthestPos<'mesh> { fn new(pos: Vec3, direction: &'mesh Vec3) -> Self { Self { pos, dot_prod: direction.dot(&pos), direction, } } fn update_if_further(&mut self, point: Vec3) { let point_dot_prod = self.direction.dot(&point); if point_dot_prod > self.dot_prod { self.pos = point; self.dot_prod = point_dot_prod; } } }