From b92441542f2e15c635967ffa06374aa92daaf657 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 2 Jun 2024 00:30:13 +0200 Subject: feat(engine): add cube mesh creation --- engine/src/mesh/cube.rs | 696 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 696 insertions(+) create mode 100644 engine/src/mesh/cube.rs (limited to 'engine/src/mesh') diff --git a/engine/src/mesh/cube.rs b/engine/src/mesh/cube.rs new file mode 100644 index 0000000..f00cf6d --- /dev/null +++ b/engine/src/mesh/cube.rs @@ -0,0 +1,696 @@ +use crate::math::calc_triangle_surface_normal; +use crate::mesh::Mesh; +use crate::util::builder; +use crate::vector::Vec3; +use crate::vertex::{Builder as VertexBuilder, Vertex}; + +builder! { +/// Cube mesh creation specification. +#[builder(name = CreationSpecBuilder, derives = (Debug, Default))] +#[derive(Debug, Default)] +#[non_exhaustive] +pub struct CreationSpec +{ + pub width: f32, + pub height: f32, + pub depth: f32, +} +} + +impl CreationSpec +{ + /// Returns a new `CreationSpec` builder. + #[must_use] + pub fn builder() -> CreationSpecBuilder + { + CreationSpecBuilder::default() + } +} + +#[derive(Debug)] +pub enum Side +{ + Front, + Back, + Left, + Right, + Top, + Bottom, +} + +#[derive(Debug)] +pub enum Corner +{ + TopRight, + TopLeft, + BottomRight, + BottomLeft, +} + +/// Creates a cube mesh. +pub fn create( + creation_spec: CreationSpec, + vertex_builder_cb: impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder, +) -> Mesh +{ + let mut vertices: [Option; VertexIndex::VARIANT_CNT] = + [(); VertexIndex::VARIANT_CNT].map(|()| None); + + create_front(&creation_spec, &mut vertices, &vertex_builder_cb); + create_back(&creation_spec, &mut vertices, &vertex_builder_cb); + create_right(&creation_spec, &mut vertices, &vertex_builder_cb); + create_left(&creation_spec, &mut vertices, &vertex_builder_cb); + create_top(&creation_spec, &mut vertices, &vertex_builder_cb); + create_bottom(&creation_spec, &mut vertices, &vertex_builder_cb); + + let front = [ + // 🮝 + VertexIndex::FrontTopRight, + VertexIndex::FrontBottomRight, + VertexIndex::FrontTopLeft, + // + // 🮟 + VertexIndex::FrontBottomRight, + VertexIndex::FrontBottomLeft, + VertexIndex::FrontTopLeft, + ]; + + let back = [ + // 🮝 + VertexIndex::BackTopRight, + VertexIndex::BackBottomRight, + VertexIndex::BackTopLeft, + // + // 🮟 + VertexIndex::BackBottomRight, + VertexIndex::BackBottomLeft, + VertexIndex::BackTopLeft, + ]; + + let right = [ + // 🮝 + VertexIndex::RightBackTop, + VertexIndex::RightBackBottom, + VertexIndex::RightFrontTop, + // + // 🮟 + VertexIndex::RightBackBottom, + VertexIndex::RightFrontBottom, + VertexIndex::RightFrontTop, + ]; + + let left = [ + // 🮝 + VertexIndex::LeftBackTop, + VertexIndex::LeftBackBottom, + VertexIndex::LeftFrontTop, + // + // 🮟 + VertexIndex::LeftBackBottom, + VertexIndex::LeftFrontBottom, + VertexIndex::LeftFrontTop, + ]; + + let top = [ + // 🮝 + VertexIndex::TopBackRight, + VertexIndex::TopBackLeft, + VertexIndex::TopFrontRight, + // + // 🮟 + VertexIndex::TopBackLeft, + VertexIndex::TopFrontLeft, + VertexIndex::TopFrontRight, + ]; + + let bottom = [ + // 🮝 + VertexIndex::BottomBackRight, + VertexIndex::BottomBackLeft, + VertexIndex::BottomFrontRight, + // + // 🮟 + VertexIndex::BottomBackLeft, + VertexIndex::BottomFrontLeft, + VertexIndex::BottomFrontRight, + ]; + + let indices = [front, back, right, left, top, bottom]; + + Mesh::new( + vertices.map(Option::unwrap).to_vec(), + Some( + indices + .into_iter() + .flatten() + .map(|index| index as u32) + .collect(), + ), + ) +} + +macro_rules! one { + ($tt: tt) => { + 1 + }; +} + +macro_rules! enum_with_variant_cnt { + ( + $(#[$attr: meta])* + enum $name: ident { + $($variant: ident,)* + } + ) => { + $(#[$attr])* + enum $name { + $($variant,)* + } + + impl $name { + const VARIANT_CNT: usize = 0 $(+ one!($variant))*; + } + }; +} + +enum_with_variant_cnt! { +#[repr(u32)] +enum VertexIndex +{ + FrontTopRight, + FrontBottomRight, + FrontBottomLeft, + FrontTopLeft, + + BackTopRight, + BackBottomRight, + BackBottomLeft, + BackTopLeft, + + RightBackTop, + RightBackBottom, + RightFrontTop, + RightFrontBottom, + + LeftBackTop, + LeftBackBottom, + LeftFrontTop, + LeftFrontBottom, + + TopBackRight, + TopBackLeft, + TopFrontRight, + TopFrontLeft, + + BottomBackRight, + BottomBackLeft, + BottomFrontRight, + BottomFrontLeft, +} +} + +fn create_front( + creation_spec: &CreationSpec, + vertices: &mut [Option], + vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder, +) +{ + let front_top_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: creation_spec.height / 2.0, + z: -(creation_spec.depth / 2.0), + }; + + let front_bottom_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: -(creation_spec.height / 2.0), + z: -(creation_spec.depth / 2.0), + }; + + let front_bottom_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: -(creation_spec.height / 2.0), + z: -(creation_spec.depth / 2.0), + }; + + let front_top_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: creation_spec.height / 2.0, + z: -(creation_spec.depth / 2.0), + }; + + let front_normal = calc_triangle_surface_normal( + &front_top_right_pos, + &front_bottom_right_pos, + &front_top_left_pos, + ); + + vertices[VertexIndex::FrontTopRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(front_top_right_pos) + .normal(front_normal), + Side::Front, + Corner::TopRight, + ) + .build(), + ); + + vertices[VertexIndex::FrontBottomRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(front_bottom_right_pos) + .normal(front_normal), + Side::Front, + Corner::BottomRight, + ) + .build(), + ); + + vertices[VertexIndex::FrontBottomLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(front_bottom_left_pos) + .normal(front_normal), + Side::Front, + Corner::BottomLeft, + ) + .build(), + ); + + vertices[VertexIndex::FrontTopLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(front_top_left_pos) + .normal(front_normal), + Side::Front, + Corner::TopLeft, + ) + .build(), + ); +} + +fn create_back( + creation_spec: &CreationSpec, + vertices: &mut [Option], + vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder, +) +{ + let back_top_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: creation_spec.height / 2.0, + z: creation_spec.depth / 2.0, + }; + + let back_bottom_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: -(creation_spec.height / 2.0), + z: creation_spec.depth / 2.0, + }; + + let back_bottom_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: -(creation_spec.height / 2.0), + z: creation_spec.depth / 2.0, + }; + + let back_top_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: creation_spec.height / 2.0, + z: creation_spec.depth / 2.0, + }; + + let back_normal = -calc_triangle_surface_normal( + &back_top_right_pos, + &back_bottom_right_pos, + &back_top_left_pos, + ); + + vertices[VertexIndex::BackTopRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(back_top_right_pos) + .normal(back_normal), + Side::Back, + Corner::TopRight, + ) + .build(), + ); + + vertices[VertexIndex::BackBottomRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(back_bottom_right_pos) + .normal(back_normal), + Side::Back, + Corner::BottomRight, + ) + .build(), + ); + + vertices[VertexIndex::BackBottomLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(back_bottom_left_pos) + .normal(back_normal), + Side::Back, + Corner::BottomLeft, + ) + .build(), + ); + + vertices[VertexIndex::BackTopLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(back_top_left_pos) + .normal(back_normal), + Side::Back, + Corner::TopLeft, + ) + .build(), + ); +} + +fn create_right( + creation_spec: &CreationSpec, + vertices: &mut [Option], + vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder, +) +{ + let right_back_top_pos = Vec3 { + x: creation_spec.width / 2.0, + y: creation_spec.height / 2.0, + z: creation_spec.depth / 2.0, + }; + + let right_back_bottom_pos = Vec3 { + x: creation_spec.width / 2.0, + y: -(creation_spec.height / 2.0), + z: creation_spec.depth / 2.0, + }; + + let right_front_top_pos = Vec3 { + x: creation_spec.width / 2.0, + y: creation_spec.height / 2.0, + z: -(creation_spec.depth / 2.0), + }; + + let right_front_bottom_pos = Vec3 { + x: creation_spec.width / 2.0, + y: -(creation_spec.height / 2.0), + z: -(creation_spec.depth / 2.0), + }; + + let right_normal = calc_triangle_surface_normal( + &right_back_top_pos, + &right_back_bottom_pos, + &right_front_top_pos, + ); + + vertices[VertexIndex::RightBackTop as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(right_back_top_pos) + .normal(right_normal), + Side::Right, + Corner::TopLeft, + ) + .build(), + ); + + vertices[VertexIndex::RightBackBottom as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(right_back_bottom_pos) + .normal(right_normal), + Side::Right, + Corner::BottomLeft, + ) + .build(), + ); + + vertices[VertexIndex::RightFrontTop as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(right_front_top_pos) + .normal(right_normal), + Side::Right, + Corner::TopRight, + ) + .build(), + ); + + vertices[VertexIndex::RightFrontBottom as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(right_front_bottom_pos) + .normal(right_normal), + Side::Right, + Corner::BottomRight, + ) + .build(), + ); +} + +fn create_left( + creation_spec: &CreationSpec, + vertices: &mut [Option], + vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder, +) +{ + let left_back_top_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: creation_spec.height / 2.0, + z: creation_spec.depth / 2.0, + }; + + let left_back_bottom_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: -(creation_spec.height / 2.0), + z: creation_spec.depth / 2.0, + }; + + let left_front_top_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: creation_spec.height / 2.0, + z: -(creation_spec.depth / 2.0), + }; + + let left_front_bottom_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: -(creation_spec.height / 2.0), + z: -(creation_spec.depth / 2.0), + }; + + let left_normal = -calc_triangle_surface_normal( + &left_back_top_pos, + &left_back_bottom_pos, + &left_front_top_pos, + ); + + vertices[VertexIndex::LeftBackTop as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(left_back_top_pos) + .normal(left_normal), + Side::Left, + Corner::TopRight, + ) + .build(), + ); + + vertices[VertexIndex::LeftBackBottom as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(left_back_bottom_pos) + .normal(left_normal), + Side::Left, + Corner::BottomRight, + ) + .build(), + ); + + vertices[VertexIndex::LeftFrontTop as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(left_front_top_pos) + .normal(left_normal), + Side::Left, + Corner::TopLeft, + ) + .build(), + ); + + vertices[VertexIndex::LeftFrontBottom as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(left_front_bottom_pos) + .normal(left_normal), + Side::Left, + Corner::BottomLeft, + ) + .build(), + ); +} + +fn create_top( + creation_spec: &CreationSpec, + vertices: &mut [Option], + vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder, +) +{ + let top_back_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: creation_spec.height / 2.0, + z: creation_spec.depth / 2.0, + }; + + let top_back_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: creation_spec.height / 2.0, + z: creation_spec.depth / 2.0, + }; + + let top_front_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: creation_spec.height / 2.0, + z: -(creation_spec.depth / 2.0), + }; + + let top_front_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: creation_spec.height / 2.0, + z: -(creation_spec.depth / 2.0), + }; + + let top_normal = -calc_triangle_surface_normal( + &top_back_right_pos, + &top_back_left_pos, + &top_front_right_pos, + ); + + vertices[VertexIndex::TopBackRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(top_back_right_pos) + .normal(top_normal), + Side::Top, + Corner::TopRight, + ) + .build(), + ); + + vertices[VertexIndex::TopBackLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(top_back_left_pos) + .normal(top_normal), + Side::Top, + Corner::TopLeft, + ) + .build(), + ); + + vertices[VertexIndex::TopFrontLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(top_front_left_pos) + .normal(top_normal), + Side::Top, + Corner::BottomLeft, + ) + .build(), + ); + + vertices[VertexIndex::TopFrontRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(top_front_right_pos) + .normal(top_normal), + Side::Top, + Corner::BottomRight, + ) + .build(), + ); +} + +fn create_bottom( + creation_spec: &CreationSpec, + vertices: &mut [Option], + vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder, +) +{ + let bottom_back_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: -(creation_spec.height / 2.0), + z: (creation_spec.depth / 2.0), + }; + + let bottom_back_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: -(creation_spec.height / 2.0), + z: creation_spec.depth / 2.0, + }; + + let bottom_front_right_pos = Vec3 { + x: creation_spec.width / 2.0, + y: -(creation_spec.height / 2.0), + z: -(creation_spec.depth / 2.0), + }; + + let bottom_front_left_pos = Vec3 { + x: -(creation_spec.width / 2.0), + y: -(creation_spec.height / 2.0), + z: -(creation_spec.depth / 2.0), + }; + + let bottom_normal = calc_triangle_surface_normal( + &bottom_back_right_pos, + &bottom_back_left_pos, + &bottom_front_right_pos, + ); + + vertices[VertexIndex::BottomBackRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(bottom_back_right_pos) + .normal(bottom_normal), + Side::Bottom, + Corner::BottomRight, + ) + .build(), + ); + + vertices[VertexIndex::BottomBackLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(bottom_back_left_pos) + .normal(bottom_normal), + Side::Bottom, + Corner::BottomLeft, + ) + .build(), + ); + + vertices[VertexIndex::BottomFrontRight as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(bottom_front_right_pos) + .normal(bottom_normal), + Side::Bottom, + Corner::TopRight, + ) + .build(), + ); + + vertices[VertexIndex::BottomFrontLeft as usize] = Some( + vertex_builder_cb( + VertexBuilder::default() + .pos(bottom_front_left_pos) + .normal(bottom_normal), + Side::Bottom, + Corner::TopLeft, + ) + .build(), + ); +} -- cgit v1.2.3-18-g5258