summaryrefslogtreecommitdiff
path: root/engine/src/mesh
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/mesh')
-rw-r--r--engine/src/mesh/cube.rs990
-rw-r--r--engine/src/mesh/vertex_buffer.rs247
2 files changed, 612 insertions, 625 deletions
diff --git a/engine/src/mesh/cube.rs b/engine/src/mesh/cube.rs
index 7cdf885..dba6473 100644
--- a/engine/src/mesh/cube.rs
+++ b/engine/src/mesh/cube.rs
@@ -1,8 +1,15 @@
+use std::collections::HashMap;
+
+use crate::builder;
+use crate::data_types::dimens::Dimens3;
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};
+use crate::mesh::vertex_buffer::{
+ NamedVertexAttr,
+ VertexAttrInfo,
+ VertexBuffer as MeshVertexBuffer,
+};
+use crate::mesh::{Mesh, POSITION_VERTEX_ATTRIB_NAME, VertexAttrType};
+use crate::vector::{Vec2, Vec3};
builder! {
/// Cube mesh creation specification.
@@ -27,676 +34,409 @@ impl CreationSpec
}
}
-#[derive(Debug)]
-pub enum Side
+impl CreationSpecBuilder
{
- Front,
- Back,
- Left,
- Right,
- Top,
- Bottom,
+ pub fn dimens(mut self, dimens: Dimens3<f32>) -> Self
+ {
+ self.width = dimens.width;
+ self.height = dimens.height;
+ self.depth = dimens.depth;
+
+ self
+ }
}
-#[derive(Debug)]
-pub enum Corner
+/// Describes what location on a side of a cube a face is.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum FaceLocation
{
- TopRight,
- TopLeft,
- BottomRight,
- BottomLeft,
+ /// 🮝
+ RightUp,
+
+ /// 🮟
+ LeftDown,
}
/// Creates a cube mesh.
-pub fn create(
- creation_spec: CreationSpec,
- vertex_builder_cb: impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder,
-) -> Mesh
+///
+/// By default, the texture coordinates are arranged so that the full texture is visible
+/// on every side. This can be changed inside of the `face_cb` function.
+pub fn create(creation_spec: CreationSpec) -> Mesh
{
- let mut vertices = [const { None }; VertexIndex::VARIANT_CNT];
-
- 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);
-
- Mesh::new(
- vertices.map(Option::unwrap).to_vec(),
- Some(
- VERTEX_INDICES
- .into_iter()
- .flatten()
- .map(|index| index as u32)
- .collect(),
- ),
- )
-}
+ // TODO: Reimplement this mess
-macro_rules! one {
- ($tt: tt) => {
- 1
- };
-}
+ let mut data = Data::default();
-macro_rules! enum_with_variant_cnt {
- (
- $(#[$attr: meta])*
- enum $name: ident {
- $($variant: ident,)*
- }
- ) => {
- $(#[$attr])*
- enum $name {
- $($variant,)*
- }
+ create_side(&SidePositions::new_top(&creation_spec), &mut data);
+ create_side(&SidePositions::new_bottom(&creation_spec), &mut data);
+ create_side(&SidePositions::new_left(&creation_spec), &mut data);
+ create_side(&SidePositions::new_right(&creation_spec), &mut data);
+ create_side(&SidePositions::new_back(&creation_spec), &mut data);
+ create_side(&SidePositions::new_front(&creation_spec), &mut data);
- impl $name {
- const VARIANT_CNT: usize = 0 $(+ one!($variant))*;
- }
- };
+ data.into_mesh()
}
-enum_with_variant_cnt! {
-#[repr(u32)]
-enum VertexIndex
+#[derive(Debug, Default)]
+struct Data
{
- FrontTopRight,
- FrontBottomRight,
- FrontBottomLeft,
- FrontTopLeft,
-
- BackTopRight,
- BackBottomRight,
- BackBottomLeft,
- BackTopLeft,
-
- RightBackTop,
- RightBackBottom,
- RightFrontTop,
- RightFrontBottom,
-
- LeftBackTop,
- LeftBackBottom,
- LeftFrontTop,
- LeftFrontBottom,
-
- TopBackRight,
- TopBackLeft,
- TopFrontRight,
- TopFrontLeft,
-
- BottomBackRight,
- BottomBackLeft,
- BottomFrontRight,
- BottomFrontLeft,
-}
+ faces: Vec<Face>,
+ vertex_data: VertexData,
}
-fn create_front(
- creation_spec: &CreationSpec,
- vertices: &mut [Option<Vertex>],
- vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder,
-)
+#[derive(Debug, Default)]
+struct VertexData
{
- 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(),
- );
+ vertex_positions: Vec<Vec3<f32>>,
+ vertex_normals: Vec<Vec3<f32>>,
}
-fn create_back(
- creation_spec: &CreationSpec,
- vertices: &mut [Option<Vertex>],
- vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder,
-)
+impl Data
{
- 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,
- };
+ fn into_mesh(self) -> Mesh
+ {
+ let mut vertex_buf = MeshVertexBuffer::with_capacity(
+ &[
+ VertexAttrInfo {
+ name: POSITION_VERTEX_ATTRIB_NAME.into(),
+ ty: VertexAttrType::Float32Array { length: 3 },
+ },
+ VertexAttrInfo {
+ name: "texture_coords".into(),
+ ty: VertexAttrType::Float32Array { length: 2 },
+ },
+ VertexAttrInfo {
+ name: "normal".into(),
+ ty: VertexAttrType::Float32Array { length: 3 },
+ },
+ ],
+ self.faces.len() * 3,
+ );
+
+ let mut indices = Vec::<u32>::with_capacity(self.faces.len() * 3);
+
+ let mut added_face_vertices = HashMap::<FaceVertex, u32>::new();
+
+ let mut face_location = FaceLocation::RightUp;
+
+ let Self { faces, vertex_data } = self;
+
+ for face in faces {
+ let face_texture_coords = match face_location {
+ FaceLocation::RightUp => [
+ Vec2 { x: 1.0, y: 1.0 },
+ Vec2 { x: 0.0, y: 1.0 },
+ Vec2 { x: 1.0, y: 0.0 },
+ ],
+ FaceLocation::LeftDown => [
+ Vec2 { x: 0.0, y: 1.0 },
+ Vec2 { x: 0.0, y: 0.0 },
+ Vec2 { x: 1.0, y: 0.0 },
+ ],
+ };
+
+ for (face_vertex, vertex_uv) in face.vertices.iter().zip(face_texture_coords)
+ {
+ if let Some(vertex_index) = added_face_vertices.get(face_vertex) {
+ indices.push(*vertex_index);
+ continue;
+ }
+
+ let vertex_pos = vertex_data
+ .vertex_positions
+ .get(face_vertex.pos_index as usize)
+ .expect("Vertex position index is out of bounds")
+ .clone();
+
+ let vertex_normal = vertex_data
+ .vertex_normals
+ .get(face_vertex.normal_index as usize)
+ .expect("Vertex normal index is out of bounds")
+ .clone();
+
+ vertex_buf.push((
+ NamedVertexAttr {
+ name: POSITION_VERTEX_ATTRIB_NAME,
+ value: vertex_pos.into_array(),
+ },
+ NamedVertexAttr {
+ name: "texture_coords",
+ value: vertex_uv.into_array(),
+ },
+ NamedVertexAttr {
+ name: "normal",
+ value: vertex_normal.into_array(),
+ },
+ ));
+
+ let vertex_index = u32::try_from(vertex_buf.len() - 1)
+ .expect("Vertex index does not fit into 32-bit unsigned int");
+
+ indices.push(vertex_index);
+
+ added_face_vertices.insert(face_vertex.clone(), vertex_index);
+ }
+
+ match face_location {
+ FaceLocation::RightUp => face_location = FaceLocation::LeftDown,
+ FaceLocation::LeftDown => face_location = FaceLocation::RightUp,
+ }
+ }
- 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(),
- );
+ Mesh::builder()
+ .vertices(vertex_buf)
+ .indices(indices)
+ .build()
+ }
}
-fn create_right(
- creation_spec: &CreationSpec,
- vertices: &mut [Option<Vertex>],
- vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder,
-)
+#[derive(Debug)]
+struct Face
{
- 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),
- };
+ vertices: [FaceVertex; 3],
+}
- let right_front_bottom_pos = Vec3 {
- x: creation_spec.width / 2.0,
- y: -(creation_spec.height / 2.0),
- z: -(creation_spec.depth / 2.0),
- };
+#[derive(Debug, PartialEq, Eq, Hash, Clone)]
+struct FaceVertex
+{
+ pos_index: u32,
+ normal_index: u32,
+}
- 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(),
- );
+#[derive(Debug)]
+struct SidePositions
+{
+ up_left: Vec3<f32>,
+ up_right: Vec3<f32>,
+ down_left: Vec3<f32>,
+ down_right: Vec3<f32>,
+ normal_calc_order: NormalCalcOrder,
}
-fn create_left(
- creation_spec: &CreationSpec,
- vertices: &mut [Option<Vertex>],
- vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder,
-)
+impl SidePositions
{
- let left_back_top_pos = Vec3 {
- x: -(creation_spec.width / 2.0),
- y: creation_spec.height / 2.0,
- z: creation_spec.depth / 2.0,
- };
+ fn new_top(creation_spec: &CreationSpec) -> Self
+ {
+ let up_left = Vec3 {
+ x: -(creation_spec.width / 2.0),
+ y: creation_spec.height / 2.0,
+ z: creation_spec.depth / 2.0,
+ };
+
+ let down_right = Vec3 {
+ x: creation_spec.width / 2.0,
+ y: creation_spec.height / 2.0,
+ z: -(creation_spec.depth / 2.0),
+ };
+
+ Self {
+ up_left,
+ up_right: Vec3 { x: down_right.x, ..up_left.clone() },
+ down_left: Vec3 { x: up_left.x, ..down_right.clone() },
+ down_right,
+ normal_calc_order: NormalCalcOrder::Clockwise,
+ }
+ }
- let left_back_bottom_pos = Vec3 {
- x: -(creation_spec.width / 2.0),
- y: -(creation_spec.height / 2.0),
- z: creation_spec.depth / 2.0,
- };
+ fn new_bottom(creation_spec: &CreationSpec) -> Self
+ {
+ let up_left = Vec3 {
+ x: -(creation_spec.width / 2.0),
+ y: -creation_spec.height / 2.0,
+ z: creation_spec.depth / 2.0,
+ };
+
+ let down_right = Vec3 {
+ x: creation_spec.width / 2.0,
+ y: -creation_spec.height / 2.0,
+ z: -(creation_spec.depth / 2.0),
+ };
+
+ Self {
+ up_left,
+ up_right: Vec3 { x: down_right.x, ..up_left.clone() },
+ down_left: Vec3 { x: up_left.x, ..down_right.clone() },
+ down_right,
+ normal_calc_order: NormalCalcOrder::CounterClockwise,
+ }
+ }
- let left_front_top_pos = Vec3 {
- x: -(creation_spec.width / 2.0),
- y: creation_spec.height / 2.0,
- z: -(creation_spec.depth / 2.0),
- };
+ fn new_left(creation_spec: &CreationSpec) -> Self
+ {
+ let up_left = Vec3 {
+ x: -(creation_spec.width / 2.0),
+ y: creation_spec.height / 2.0,
+ z: -(creation_spec.depth / 2.0),
+ };
+
+ let down_right = Vec3 {
+ x: -(creation_spec.width / 2.0),
+ y: -(creation_spec.height / 2.0),
+ z: creation_spec.depth / 2.0,
+ };
+
+ Self {
+ up_left,
+ up_right: Vec3 { z: down_right.z, ..up_left.clone() },
+ down_left: Vec3 { z: up_left.z, ..down_right.clone() },
+ down_right,
+ normal_calc_order: NormalCalcOrder::CounterClockwise,
+ }
+ }
- let left_front_bottom_pos = Vec3 {
- x: -(creation_spec.width / 2.0),
- y: -(creation_spec.height / 2.0),
- z: -(creation_spec.depth / 2.0),
- };
+ fn new_right(creation_spec: &CreationSpec) -> Self
+ {
+ let up_left = Vec3 {
+ x: (creation_spec.width / 2.0),
+ y: creation_spec.height / 2.0,
+ z: -(creation_spec.depth / 2.0),
+ };
+
+ let down_right = Vec3 {
+ x: (creation_spec.width / 2.0),
+ y: -(creation_spec.height / 2.0),
+ z: creation_spec.depth / 2.0,
+ };
+
+ Self {
+ up_left,
+ up_right: Vec3 { z: down_right.z, ..up_left.clone() },
+ down_left: Vec3 { z: up_left.z, ..down_right.clone() },
+ down_right,
+ normal_calc_order: NormalCalcOrder::Clockwise,
+ }
+ }
+
+ fn new_back(creation_spec: &CreationSpec) -> Self
+ {
+ let up_left = Vec3 {
+ x: -(creation_spec.width / 2.0),
+ y: creation_spec.height / 2.0,
+ z: -creation_spec.depth / 2.0,
+ };
+
+ let down_right = Vec3 {
+ x: creation_spec.width / 2.0,
+ y: -(creation_spec.height / 2.0),
+ z: -creation_spec.depth / 2.0,
+ };
+
+ Self {
+ up_left,
+ up_right: Vec3 { x: down_right.x, ..up_left.clone() },
+ down_left: Vec3 { x: up_left.x, ..down_right.clone() },
+ down_right,
+ normal_calc_order: NormalCalcOrder::Clockwise,
+ }
+ }
- 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 new_front(creation_spec: &CreationSpec) -> Self
+ {
+ let up_left = Vec3 {
+ x: -(creation_spec.width / 2.0),
+ y: creation_spec.height / 2.0,
+ z: creation_spec.depth / 2.0,
+ };
+
+ let down_right = Vec3 {
+ x: creation_spec.width / 2.0,
+ y: -(creation_spec.height / 2.0),
+ z: creation_spec.depth / 2.0,
+ };
+
+ Self {
+ up_left,
+ up_right: Vec3 { x: down_right.x, ..up_left.clone() },
+ down_left: Vec3 { x: up_left.x, ..down_right.clone() },
+ down_right,
+ normal_calc_order: NormalCalcOrder::CounterClockwise,
+ }
+ }
}
-fn create_top(
- creation_spec: &CreationSpec,
- vertices: &mut [Option<Vertex>],
- vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder,
-)
+#[derive(Debug)]
+enum NormalCalcOrder
{
- 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(),
- );
+ Clockwise,
+ CounterClockwise,
}
-fn create_bottom(
- creation_spec: &CreationSpec,
- vertices: &mut [Option<Vertex>],
- vertex_builder_cb: &impl Fn(VertexBuilder, Side, Corner) -> VertexBuilder,
-)
+fn create_side(side_positions: &SidePositions, data: &mut Data)
{
- 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 normal = match side_positions.normal_calc_order {
+ NormalCalcOrder::Clockwise => calc_triangle_surface_normal(
+ &side_positions.up_left,
+ &side_positions.up_right,
+ &side_positions.down_left,
+ ),
+ NormalCalcOrder::CounterClockwise => calc_triangle_surface_normal(
+ &side_positions.up_left,
+ &side_positions.down_left,
+ &side_positions.up_right,
+ ),
};
- let bottom_back_left_pos = Vec3 {
- x: -(creation_spec.width / 2.0),
- y: -(creation_spec.height / 2.0),
- z: creation_spec.depth / 2.0,
- };
+ data.vertex_data.vertex_normals.push(normal);
- 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 top_normal_index = data.vertex_data.vertex_normals.len() - 1;
- let bottom_front_left_pos = Vec3 {
- x: -(creation_spec.width / 2.0),
- y: -(creation_spec.height / 2.0),
- z: -(creation_spec.depth / 2.0),
- };
+ data.vertex_data
+ .vertex_positions
+ .push(side_positions.up_right);
- 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(),
- );
-}
+ let up_right_pos_index = data.vertex_data.vertex_positions.len() - 1;
-const VERTEX_INDICES_FRONT: [VertexIndex; 6] = [
- // 🮝
- VertexIndex::FrontTopRight,
- VertexIndex::FrontBottomRight,
- VertexIndex::FrontTopLeft,
- //
- // 🮟
- VertexIndex::FrontBottomRight,
- VertexIndex::FrontBottomLeft,
- VertexIndex::FrontTopLeft,
-];
+ data.vertex_data
+ .vertex_positions
+ .push(side_positions.up_left);
-const VERTEX_INDICES_BACK: [VertexIndex; 6] = [
- // 🮝
- VertexIndex::BackTopRight,
- VertexIndex::BackBottomRight,
- VertexIndex::BackTopLeft,
- //
- // 🮟
- VertexIndex::BackBottomRight,
- VertexIndex::BackBottomLeft,
- VertexIndex::BackTopLeft,
-];
+ let up_left_pos_index = data.vertex_data.vertex_positions.len() - 1;
-const VERTEX_INDICES_RIGHT: [VertexIndex; 6] = [
- // 🮝
- VertexIndex::RightBackTop,
- VertexIndex::RightBackBottom,
- VertexIndex::RightFrontTop,
- //
- // 🮟
- VertexIndex::RightBackBottom,
- VertexIndex::RightFrontBottom,
- VertexIndex::RightFrontTop,
-];
+ data.vertex_data
+ .vertex_positions
+ .push(side_positions.down_left);
-const VERTEX_INDICES_LEFT: [VertexIndex; 6] = [
- // 🮝
- VertexIndex::LeftBackTop,
- VertexIndex::LeftBackBottom,
- VertexIndex::LeftFrontTop,
- //
- // 🮟
- VertexIndex::LeftBackBottom,
- VertexIndex::LeftFrontBottom,
- VertexIndex::LeftFrontTop,
-];
+ let down_left_pos_index = data.vertex_data.vertex_positions.len() - 1;
-const VERTEX_INDICES_TOP: [VertexIndex; 6] = [
- // 🮝
- VertexIndex::TopBackRight,
- VertexIndex::TopBackLeft,
- VertexIndex::TopFrontRight,
- //
- // 🮟
- VertexIndex::TopBackLeft,
- VertexIndex::TopFrontLeft,
- VertexIndex::TopFrontRight,
-];
+ data.vertex_data
+ .vertex_positions
+ .push(side_positions.down_right);
+
+ let down_right_pos_index = data.vertex_data.vertex_positions.len() - 1;
-const VERTEX_INDICES_BOTTOM: [VertexIndex; 6] = [
// 🮝
- VertexIndex::BottomBackRight,
- VertexIndex::BottomBackLeft,
- VertexIndex::BottomFrontRight,
- //
+ data.faces.push(Face {
+ vertices: [
+ FaceVertex {
+ pos_index: up_right_pos_index as u32,
+ normal_index: top_normal_index as u32,
+ },
+ FaceVertex {
+ pos_index: up_left_pos_index as u32,
+ normal_index: top_normal_index as u32,
+ },
+ FaceVertex {
+ pos_index: down_right_pos_index as u32,
+ normal_index: top_normal_index as u32,
+ },
+ ],
+ });
+
// 🮟
- VertexIndex::BottomBackLeft,
- VertexIndex::BottomFrontLeft,
- VertexIndex::BottomFrontRight,
-];
-
-const VERTEX_INDICES: [[VertexIndex; 6]; 6] = [
- VERTEX_INDICES_FRONT,
- VERTEX_INDICES_BACK,
- VERTEX_INDICES_RIGHT,
- VERTEX_INDICES_LEFT,
- VERTEX_INDICES_TOP,
- VERTEX_INDICES_BOTTOM,
-];
+ data.faces.push(Face {
+ vertices: [
+ FaceVertex {
+ pos_index: up_left_pos_index as u32,
+ normal_index: top_normal_index as u32,
+ },
+ FaceVertex {
+ pos_index: down_left_pos_index as u32,
+ normal_index: top_normal_index as u32,
+ },
+ FaceVertex {
+ pos_index: down_right_pos_index as u32,
+ normal_index: top_normal_index as u32,
+ },
+ ],
+ });
+}
diff --git a/engine/src/mesh/vertex_buffer.rs b/engine/src/mesh/vertex_buffer.rs
new file mode 100644
index 0000000..3e3c467
--- /dev/null
+++ b/engine/src/mesh/vertex_buffer.rs
@@ -0,0 +1,247 @@
+use std::alloc::Layout;
+use std::borrow::Cow;
+use std::marker::PhantomData;
+
+use seq_macro::seq;
+use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
+
+use crate::mesh::VertexAttrType;
+
+pub trait VertexAttrValue:
+ IntoBytes + FromBytes + KnownLayout + Immutable + 'static
+{
+ fn ty() -> VertexAttrType;
+}
+
+impl VertexAttrValue for f32
+{
+ fn ty() -> VertexAttrType
+ {
+ VertexAttrType::Float32
+ }
+}
+
+impl<const LEN: usize> VertexAttrValue for [f32; LEN]
+{
+ fn ty() -> VertexAttrType
+ {
+ VertexAttrType::Float32Array { length: LEN }
+ }
+}
+
+#[derive(Debug)]
+pub struct NamedVertexAttr<'name, Value: VertexAttrValue>
+{
+ pub name: &'name str,
+ pub value: Value,
+}
+
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub struct VertexAttrProperties
+{
+ pub name: Cow<'static, str>,
+ pub ty: VertexAttrType,
+ pub layout: Layout,
+ pub byte_offset: usize,
+}
+
+#[derive(Debug)]
+pub struct VertexAttrInfo
+{
+ pub name: Cow<'static, str>,
+ pub ty: VertexAttrType,
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct VertexBuffer
+{
+ buf: Vec<u8>,
+ vertex_size: usize,
+ vertex_attr_props: Vec<VertexAttrProperties>,
+}
+
+impl VertexBuffer
+{
+ pub fn with_capacity(vertex_attrs: &[VertexAttrInfo], capacity: usize) -> Self
+ {
+ let mut vertex_attr_props = vertex_attrs
+ .iter()
+ .map(|VertexAttrInfo { name, ty }| VertexAttrProperties {
+ name: name.clone(),
+ ty: ty.clone(),
+ layout: ty.layout(),
+ byte_offset: 0,
+ })
+ .collect::<Vec<_>>();
+
+ let mut vertex_layout = Layout::new::<()>();
+
+ for VertexAttrProperties {
+ name: _,
+ ty: _,
+ layout: vertex_attr_layout,
+ byte_offset: vertex_attr_byte_offset,
+ } in &mut vertex_attr_props
+ {
+ let (new_struct_layout, byte_offset) =
+ vertex_layout.extend(*vertex_attr_layout).unwrap();
+
+ *vertex_attr_byte_offset = byte_offset;
+ vertex_layout = new_struct_layout;
+ }
+
+ let vertex_layout = vertex_layout.pad_to_align();
+
+ Self {
+ buf: Vec::with_capacity(vertex_layout.size() * capacity),
+ vertex_size: vertex_layout.size(),
+ vertex_attr_props,
+ }
+ }
+
+ pub fn push<'name, VertexAttrs: NamedVertexAttrs<'name>>(
+ &mut self,
+ vertex: VertexAttrs,
+ )
+ {
+ assert_eq!(
+ self.vertex_attr_props.len(),
+ vertex.vertex_attr_cnt(),
+ "Vertex has incorrect amount of attributes"
+ );
+
+ if self.buf.spare_capacity_mut().len() < self.vertex_size {
+ self.buf.reserve_exact(self.vertex_size * (self.len() / 2));
+ }
+
+ let spare_capacity = self.buf.spare_capacity_mut();
+
+ let vertex_attrs = vertex.vertex_attrs();
+
+ for (vertex_attr_name, vertex_attr_bytes, vertex_attr_ty) in vertex_attrs {
+ let vertex_attr_props = self
+ .vertex_attr_props
+ .iter()
+ .find(|vertex_attr_props| vertex_attr_props.name == vertex_attr_name)
+ .unwrap();
+
+ assert_eq!(vertex_attr_ty, vertex_attr_props.ty);
+
+ let start_offset = vertex_attr_props.byte_offset;
+
+ let end_offset = start_offset + vertex_attr_props.layout.size();
+
+ spare_capacity[start_offset..end_offset]
+ .write_copy_of_slice(vertex_attr_bytes);
+ }
+
+ unsafe {
+ self.buf.set_len(self.buf.len() + self.vertex_size);
+ }
+ }
+
+ pub fn vertex_attr_props(&self) -> &[VertexAttrProperties]
+ {
+ &self.vertex_attr_props
+ }
+
+ pub fn len(&self) -> usize
+ {
+ assert_eq!(self.buf.len() % self.vertex_size, 0, "Invalid length");
+
+ self.buf.len() / self.vertex_size
+ }
+
+ pub fn vertex_size(&self) -> usize
+ {
+ self.vertex_size
+ }
+
+ pub fn as_bytes(&self) -> &[u8]
+ {
+ &self.buf
+ }
+
+ pub fn iter<VertexAttr: VertexAttrValue>(
+ &self,
+ vertex_attr_name: &str,
+ ) -> Iter<'_, VertexAttr>
+ {
+ let vertex_attr_props = self
+ .vertex_attr_props
+ .iter()
+ .find(|vertex_attr_props| vertex_attr_props.name == vertex_attr_name)
+ .unwrap();
+
+ assert_eq!(VertexAttr::ty(), vertex_attr_props.ty);
+
+ Iter {
+ buf: self,
+ vertex_attr_props,
+ curr_index: 0,
+ _pd: PhantomData,
+ }
+ }
+}
+
+pub struct Iter<'a, VertexAttr: VertexAttrValue>
+{
+ buf: &'a VertexBuffer,
+ vertex_attr_props: &'a VertexAttrProperties,
+ curr_index: usize,
+ _pd: PhantomData<VertexAttr>,
+}
+
+impl<'a, VertexAttr: VertexAttrValue> Iterator for Iter<'a, VertexAttr>
+{
+ type Item = &'a VertexAttr;
+
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ let start_offset =
+ (self.buf.vertex_size * self.curr_index) + self.vertex_attr_props.byte_offset;
+
+ let end_offset = start_offset + self.vertex_attr_props.layout.size();
+
+ let bytes = self.buf.buf.get(start_offset..end_offset)?;
+
+ self.curr_index += 1;
+
+ Some(VertexAttr::ref_from_bytes(bytes).unwrap())
+ }
+}
+
+pub trait NamedVertexAttrs<'name>
+{
+ fn vertex_attr_cnt(&self) -> usize;
+
+ fn vertex_attrs(&self) -> impl Iterator<Item = (&'name str, &[u8], VertexAttrType)>;
+}
+
+macro_rules! impl_named_vertex_attrs {
+ ($cnt: tt) => {
+ seq!(I in 0..$cnt {
+ impl<'name, #(VertexAttr~I: VertexAttrValue,)*>
+ NamedVertexAttrs<'name> for (#(NamedVertexAttr<'name, VertexAttr~I>,)*)
+ {
+ fn vertex_attr_cnt(&self) -> usize
+ {
+ $cnt
+ }
+
+ fn vertex_attrs(&self)
+ -> impl Iterator<Item = (&'name str, &[u8], VertexAttrType)>
+ {
+ [#(
+ (self.I.name, self.I.value.as_bytes(), VertexAttr~I::ty()),
+ )*].into_iter()
+ }
+ }
+ });
+ };
+}
+
+seq!(I in 0..16 {
+ impl_named_vertex_attrs!(I);
+});