summaryrefslogtreecommitdiff
path: root/engine/src/mesh/cube.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-06-02 00:30:13 +0200
committerHampusM <hampus@hampusmat.com>2024-06-02 00:30:13 +0200
commitb92441542f2e15c635967ffa06374aa92daaf657 (patch)
treeb554193d579999be581761d1856c99be31f8d2a2 /engine/src/mesh/cube.rs
parent526edc6f4cb5f29d17e2fe384e316236c033fccd (diff)
feat(engine): add cube mesh creation
Diffstat (limited to 'engine/src/mesh/cube.rs')
-rw-r--r--engine/src/mesh/cube.rs696
1 files changed, 696 insertions, 0 deletions
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<Vertex>; 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>],
+ 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>],
+ 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>],
+ 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>],
+ 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>],
+ 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>],
+ 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(),
+ );
+}