diff options
Diffstat (limited to 'engine/src/mesh.rs')
| -rw-r--r-- | engine/src/mesh.rs | 570 |
1 files changed, 561 insertions, 9 deletions
diff --git a/engine/src/mesh.rs b/engine/src/mesh.rs index de0af70..b52edb1 100644 --- a/engine/src/mesh.rs +++ b/engine/src/mesh.rs @@ -1,28 +1,258 @@ -use ecs::Component; +use std::alloc::Layout; -use crate::vertex::Vertex; +use zerocopy::IntoBytes; -pub mod cube; +use crate::asset::Asset; +use crate::data_types::dimens::Dimens3; +use crate::mesh::vertex_buffer::{VertexAttrProperties, VertexLabel}; +use crate::vector::{Vec2, Vec3}; -#[derive(Debug, Clone, Component)] +pub mod vertex_buffer; + +#[derive(Debug, Clone)] pub struct Mesh { - vertices: Vec<Vertex>, + vertex_buf: vertex_buffer::VertexBuffer, indices: Option<Vec<u32>>, } impl Mesh { #[must_use] - pub fn new(vertices: Vec<Vertex>, indices: Option<Vec<u32>>) -> Self + pub fn cube(size: Dimens3<f32>) -> Self + { + Self::cube_with_options(CubeOptions::default().size(size)) + } + + #[must_use] + pub fn cube_with_options(options: CubeOptions) -> Self { - Self { vertices, indices } + #[inline] + fn vertex(pos: [f32; 3], uv: [f32; 2], normal: Vec3<f32>) -> [f32; 8] + { + let [pos_x, pos_y, pos_z] = pos; + let [uv_x, uv_y] = uv; + + [ + pos_x, pos_y, pos_z, uv_x, uv_y, normal.x, normal.y, normal.z, + ] + } + + let CubeOptions { + size, + top_face: + CubeFaceOptions { + uv_upper_left: top_uv_upper_left, + uv_lower_right: top_uv_lower_right, + }, + bottom_face: + CubeFaceOptions { + uv_upper_left: bot_uv_upper_left, + uv_lower_right: bot_uv_lower_right, + }, + left_face: + CubeFaceOptions { + uv_upper_left: left_uv_upper_left, + uv_lower_right: left_uv_lower_right, + }, + right_face: + CubeFaceOptions { + uv_upper_left: right_uv_upper_left, + uv_lower_right: right_uv_lower_right, + }, + back_face: + CubeFaceOptions { + uv_upper_left: back_uv_upper_left, + uv_lower_right: back_uv_lower_right, + }, + front_face: + CubeFaceOptions { + uv_upper_left: front_uv_upper_left, + uv_lower_right: front_uv_lower_right, + }, + } = options; + + let half_w = size.width / 2.0; + let half_h = size.height / 2.0; + let half_d = size.depth / 2.0; + + let top_vertices = [ + ( + [half_w, half_h, half_d], + [top_uv_upper_left.x, top_uv_upper_left.y], + ), + ( + [-half_w, half_h, half_d], + [top_uv_lower_right.x, top_uv_upper_left.y], + ), + ( + [half_w, half_h, -half_d], + [top_uv_upper_left.x, top_uv_lower_right.y], + ), + ( + [-half_w, half_h, -half_d], + [top_uv_lower_right.x, top_uv_lower_right.y], + ), + ] + .map(|(pos, uv)| vertex(pos, uv, Vec3::UP)); + + let bottom_vertices = [ + ( + [half_w, -half_h, half_d], + [bot_uv_upper_left.x, bot_uv_upper_left.y], + ), + ( + [-half_w, -half_h, half_d], + [bot_uv_lower_right.x, bot_uv_upper_left.y], + ), + ( + [half_w, -half_h, -half_d], + [bot_uv_upper_left.x, bot_uv_lower_right.y], + ), + ( + [-half_w, -half_h, -half_d], + [bot_uv_lower_right.x, bot_uv_lower_right.y], + ), + ] + .map(|(pos, uv)| vertex(pos, uv, Vec3::DOWN)); + + let left_vertices = [ + ( + [-half_w, half_h, half_d], + [left_uv_upper_left.x, left_uv_upper_left.y], + ), + ( + [-half_w, half_h, -half_d], + [left_uv_lower_right.x, left_uv_upper_left.y], + ), + ( + [-half_w, -half_h, half_d], + [left_uv_upper_left.x, left_uv_lower_right.y], + ), + ( + [-half_w, -half_h, -half_d], + [left_uv_lower_right.x, left_uv_lower_right.y], + ), + ] + .map(|(pos, uv)| vertex(pos, uv, Vec3::LEFT)); + + let right_vertices = [ + ( + [half_w, half_h, half_d], + [right_uv_upper_left.x, right_uv_upper_left.y], + ), + ( + [half_w, half_h, -half_d], + [right_uv_lower_right.x, right_uv_upper_left.y], + ), + ( + [half_w, -half_h, half_d], + [right_uv_upper_left.x, right_uv_lower_right.y], + ), + ( + [half_w, -half_h, -half_d], + [right_uv_lower_right.x, right_uv_lower_right.y], + ), + ] + .map(|(pos, uv)| vertex(pos, uv, Vec3::RIGHT)); + + let back_vertices = [ + ( + [half_w, half_h, -half_d], + [back_uv_upper_left.x, back_uv_upper_left.y], + ), + ( + [-half_w, half_h, -half_d], + [back_uv_lower_right.x, back_uv_upper_left.y], + ), + ( + [half_w, -half_h, -half_d], + [back_uv_upper_left.x, back_uv_lower_right.y], + ), + ( + [-half_w, -half_h, -half_d], + [back_uv_lower_right.x, back_uv_lower_right.y], + ), + ] + .map(|(pos, uv)| vertex(pos, uv, Vec3::BACK)); + + let front_vertices = [ + ( + [half_w, half_h, half_d], + [front_uv_upper_left.x, front_uv_upper_left.y], + ), + ( + [-half_w, half_h, half_d], + [front_uv_lower_right.x, front_uv_upper_left.y], + ), + ( + [half_w, -half_h, half_d], + [front_uv_upper_left.x, front_uv_lower_right.y], + ), + ( + [-half_w, -half_h, half_d], + [front_uv_lower_right.x, front_uv_lower_right.y], + ), + ] + .map(|(pos, uv)| vertex(pos, uv, Vec3::FRONT)); + + Mesh::builder() + .vertices(unsafe { + vertex_buffer::VertexBuffer::from_raw( + &[ + VertexAttrProperties { + label: VertexLabel::Position, + ty: VertexAttrType::Float32Array { length: 3 }, + layout: Layout::new::<[f32; 3]>(), + byte_offset: 0, + }, + VertexAttrProperties { + label: VertexLabel::UvFromTopLeft, + ty: VertexAttrType::Float32Array { length: 2 }, + layout: Layout::new::<[f32; 2]>(), + byte_offset: size_of::<[f32; 3]>(), + }, + VertexAttrProperties { + label: VertexLabel::Normal, + ty: VertexAttrType::Float32Array { length: 3 }, + layout: Layout::new::<[f32; 3]>(), + byte_offset: size_of::<[f32; 3]>() + size_of::<[f32; 2]>(), + }, + ], + [ + top_vertices, + bottom_vertices, + left_vertices, + right_vertices, + back_vertices, + front_vertices, + ] + .as_bytes() + .to_vec(), + ) + }) + .indices([ + 0, 1, 2, 1, 3, 2, 4, 5, 6, 5, 7, 6, 8, 9, 10, 9, 11, 10, 12, 13, 14, 13, + 15, 14, 16, 17, 18, 17, 19, 18, 20, 21, 22, 21, 23, 22, + ]) + .build() } #[must_use] - pub fn vertices(&self) -> &[Vertex] + pub fn builder() -> Builder { - &self.vertices + Builder::default() + } + + #[must_use] + pub fn vertex_buf(&self) -> &vertex_buffer::VertexBuffer + { + &self.vertex_buf + } + + pub fn vertex_buf_mut(&mut self) -> &mut vertex_buffer::VertexBuffer + { + &mut self.vertex_buf } #[must_use] @@ -30,4 +260,326 @@ impl Mesh { self.indices.as_deref() } + + #[must_use] + pub fn indices_mut(&mut self) -> Option<&mut [u32]> + { + self.indices.as_deref_mut() + } + + pub fn set_indices(&mut self, indices: impl IntoIterator<Item = u32>) + { + let curr_indices = self.indices.get_or_insert_with(Vec::new); + + curr_indices.clear(); + + curr_indices.extend(indices); + } + + /// 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. + #[must_use] + pub fn find_furthest_vertex_positions(&self) -> DirectionPositions + { + let mut pos_iter = self + .vertex_buf() + .iter::<[f32; 3]>(VertexLabel::Position) + .map(|vertex_pos| Vec3::from(*vertex_pos)); + + 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() + } +} + +impl Asset for Mesh +{ + fn dependencies(&self) -> impl Iterator<Item = crate::asset::Dependency<'_>> + { + [].into_iter() + } +} + +/// Mesh builder +#[derive(Debug, Clone, Default)] +pub struct Builder +{ + vertex_buf: vertex_buffer::VertexBuffer, + indices: Option<Vec<u32>>, +} + +impl Builder +{ + #[must_use] + pub fn new() -> Self + { + Self::default() + } + + #[must_use] + pub fn vertices(mut self, vertices_bytes: vertex_buffer::VertexBuffer) -> Self + { + self.vertex_buf = vertices_bytes; + self + } + + #[must_use] + pub fn indices(mut self, indices: impl IntoIterator<Item = u32>) -> Self + { + self.indices = Some(indices.into_iter().collect()); + self + } + + #[must_use] + 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 +{ + #[must_use] + pub fn layout(&self) -> Layout + { + match self { + Self::Float32 => Layout::new::<f32>(), + Self::Float32Array { length } => Layout::array::<f32>(*length).unwrap(), + } + } +} + +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct CubeOptions +{ + pub size: Dimens3<f32>, + pub top_face: CubeFaceOptions, + pub bottom_face: CubeFaceOptions, + pub front_face: CubeFaceOptions, + pub back_face: CubeFaceOptions, + pub left_face: CubeFaceOptions, + pub right_face: CubeFaceOptions, +} + +impl CubeOptions +{ + #[must_use] + pub fn size(mut self, size: Dimens3<f32>) -> Self + { + self.size = size; + self + } + + #[must_use] + pub fn top_face(mut self, top_face: CubeFaceOptions) -> Self + { + self.top_face = top_face; + self + } + + #[must_use] + pub fn bottom_face(mut self, bottom_face: CubeFaceOptions) -> Self + { + self.bottom_face = bottom_face; + self + } + + #[must_use] + pub fn front_face(mut self, front_face: CubeFaceOptions) -> Self + { + self.front_face = front_face; + self + } + + #[must_use] + pub fn back_face(mut self, back_face: CubeFaceOptions) -> Self + { + self.back_face = back_face; + self + } + + #[must_use] + pub fn left_face(mut self, left_face: CubeFaceOptions) -> Self + { + self.left_face = left_face; + self + } + + #[must_use] + pub fn right_face(mut self, right_face: CubeFaceOptions) -> Self + { + self.right_face = right_face; + self + } +} + +impl Default for CubeOptions +{ + fn default() -> Self + { + Self { + size: Dimens3 { width: 1.0, height: 1.0, depth: 1.0 }, + top_face: CubeFaceOptions::default(), + bottom_face: CubeFaceOptions::default(), + front_face: CubeFaceOptions::default(), + back_face: CubeFaceOptions::default(), + left_face: CubeFaceOptions::default(), + right_face: CubeFaceOptions::default(), + } + } +} + +#[derive(Debug, Clone)] +#[non_exhaustive] +pub struct CubeFaceOptions +{ + /// Seeing the face head on, this is the texture coordinate for the corner that + /// would be on the upper left of the face. + /// + /// The default is `(0, 0)` + pub uv_upper_left: Vec2<f32>, + + /// Seeing the face head on, this is the texture coordinate for the corner that + /// would be on the lower right of the face. + /// + /// The default is `(1, 1)` + pub uv_lower_right: Vec2<f32>, +} + +impl CubeFaceOptions +{ + /// Seeing the face head on, this is the texture coordinate for the corner that + /// would be on the upper left of the face. + /// + /// The default is `(0, 0)` + #[must_use] + pub fn uv_upper_left(mut self, uv_upper_left: Vec2<f32>) -> Self + { + self.uv_upper_left = uv_upper_left; + self + } + + /// Seeing the face head on, this is the texture coordinate for the corner that + /// would be on the lower right of the face. + /// + /// The default is `(1, 1)` + #[must_use] + pub fn uv_lower_right(mut self, uv_lower_right: Vec2<f32>) -> Self + { + self.uv_lower_right = uv_lower_right; + self + } +} + +impl Default for CubeFaceOptions +{ + fn default() -> Self + { + Self { + uv_upper_left: Vec2 { x: 0.0, y: 0.0 }, + uv_lower_right: Vec2 { x: 1.0, y: 1.0 }, + } + } +} + +#[derive(Debug, Clone)] +pub struct DirectionPositions +{ + pub up: Vec3<f32>, + pub down: Vec3<f32>, + pub left: Vec3<f32>, + pub right: Vec3<f32>, + pub back: Vec3<f32>, + pub front: Vec3<f32>, +} + +impl<'mesh> From<FurthestPosAcc<'mesh>> 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<f32>, + dot_prod: f32, + direction: &'mesh Vec3<f32>, +} + +impl<'mesh> FurthestPos<'mesh> +{ + fn new(pos: Vec3<f32>, direction: &'mesh Vec3<f32>) -> Self + { + Self { + pos, + dot_prod: direction.dot(&pos), + direction, + } + } + + fn update_if_further(&mut self, point: Vec3<f32>) + { + let point_dot_prod = self.direction.dot(&point); + + if point_dot_prod > self.dot_prod { + self.pos = point; + self.dot_prod = point_dot_prod; + } + } } |
