use engine_macros::Reflection; use zerocopy::{Immutable, IntoBytes}; use crate::builder; use crate::vector::Vec3; pub mod cube; #[derive(Debug, Clone, Default)] pub struct Mesh { vertices: Vec, indices: Option>, } impl Mesh { #[must_use] pub fn new(vertices: Vec, indices: Option>) -> Self { Self { vertices, indices } } #[must_use] pub fn vertices(&self) -> &[Vertex] { &self.vertices } #[must_use] pub fn vertices_mut(&mut self) -> &mut [Vertex] { &mut self.vertices } #[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 point_iter = self .vertices() .iter() .map(|vertex| Vec3::from(vertex.pos)) .into_iter(); let first_point = point_iter.next().unwrap(); point_iter .fold( FurthestPosAcc { up: FurthestPos::new(first_point, &Vec3::UP), down: FurthestPos::new(first_point, &Vec3::DOWN), left: FurthestPos::new(first_point, &Vec3::LEFT), right: FurthestPos::new(first_point, &Vec3::RIGHT), back: FurthestPos::new(first_point, &Vec3::BACK), front: FurthestPos::new(first_point, &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() } } builder! { #[builder(name = VertexBuilder, derives = (Debug, Default, Clone))] #[derive(Debug, Clone, Default, PartialEq, IntoBytes, Immutable, Reflection)] #[non_exhaustive] pub struct Vertex { #[builder(skip_generate_fn)] pub pos: [f32; 3], #[builder(skip_generate_fn)] pub texture_coords: [f32; 2], #[builder(skip_generate_fn)] pub normal: [f32; 3], } } impl Vertex { #[must_use] pub fn builder() -> VertexBuilder { VertexBuilder::default() } } impl VertexBuilder { pub fn pos(mut self, pos: impl Into<[f32; 3]>) -> Self { self.pos = pos.into(); self } pub fn texture_coords(mut self, texture_coords: impl Into<[f32; 2]>) -> Self { self.texture_coords = texture_coords.into(); self } pub fn normal(mut self, normal: impl Into<[f32; 3]>) -> Self { self.normal = normal.into(); self } } #[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; } } }