summaryrefslogtreecommitdiff
path: root/engine/src/mesh
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/mesh')
-rw-r--r--engine/src/mesh/cube.rs209
-rw-r--r--engine/src/mesh/vertex_buffer.rs247
2 files changed, 326 insertions, 130 deletions
diff --git a/engine/src/mesh/cube.rs b/engine/src/mesh/cube.rs
index fe45a4a..dba6473 100644
--- a/engine/src/mesh/cube.rs
+++ b/engine/src/mesh/cube.rs
@@ -1,7 +1,14 @@
+use std::collections::HashMap;
+
use crate::builder;
use crate::data_types::dimens::Dimens3;
use crate::math::calc_triangle_surface_normal;
-use crate::mesh::{Mesh, 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! {
@@ -39,29 +46,6 @@ impl CreationSpecBuilder
}
}
-/// Describes a single side of a cube (obviously).
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub enum Side
-{
- /// +Z
- Front,
-
- /// -Z
- Back,
-
- /// -X
- Left,
-
- /// +X
- Right,
-
- /// +Y
- Top,
-
- /// -Y
- Bottom,
-}
-
/// Describes what location on a side of a cube a face is.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum FaceLocation
@@ -77,11 +61,10 @@ pub enum FaceLocation
///
/// 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,
- face_cb: impl FnMut(FaceVertices, Side, FaceLocation) -> FaceVertices,
-) -> Mesh
+pub fn create(creation_spec: CreationSpec) -> Mesh
{
+ // TODO: Reimplement this mess
+
let mut data = Data::default();
create_side(&SidePositions::new_top(&creation_spec), &mut data);
@@ -91,7 +74,7 @@ pub fn create(
create_side(&SidePositions::new_back(&creation_spec), &mut data);
create_side(&SidePositions::new_front(&creation_spec), &mut data);
- data.into_mesh(face_cb)
+ data.into_mesh()
}
#[derive(Debug, Default)]
@@ -110,88 +93,55 @@ struct VertexData
impl Data
{
- fn into_mesh(
- self,
- mut face_cb: impl FnMut(FaceVertices, Side, FaceLocation) -> FaceVertices,
- ) -> Mesh
+ fn into_mesh(self) -> Mesh
{
- let mut vertices = Vec::<Vertex>::with_capacity(self.faces.len() * 3);
+ 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 side = face.side;
-
- let face_vertices = face_cb(
- FaceVertices::new(face, &vertex_data)
- .with_full_per_side_tex_coords(face_location),
- side,
- face_location,
- );
-
- for vertex in face_vertices.vertices {
- if let Some((prev_vertex_index, _)) = vertices
- .iter()
- .enumerate()
- .find(|(_, prev_vertex)| *prev_vertex == &vertex)
- {
- indices
- .push(u32::try_from(prev_vertex_index).expect(
- "Vertex index does not fit into 32-bit unsigned int",
- ));
-
+ 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;
}
- vertices.push(vertex);
-
- let vertex_index = u32::try_from(vertices.len() - 1)
- .expect("Vertex index does not fit into 32-bit unsigned int");
-
- indices.push(vertex_index);
- }
-
- match face_location {
- FaceLocation::RightUp => face_location = FaceLocation::LeftDown,
- FaceLocation::LeftDown => face_location = FaceLocation::RightUp,
- }
- }
-
- Mesh::new(vertices, Some(indices))
- }
-}
-
-/// The vertices of a single face of a cube.
-#[derive(Debug, Default, Clone)]
-pub struct FaceVertices
-{
- /// The three vertices of a face in counter-clockwise order.
- ///
- /// Order when [`FaceLocation::RightUp`]:
- /// ```text
- /// ₂ ₁
- /// 🮝
- /// ³
- /// ```
- ///
- /// Order when [`FaceLocation::LeftDown`]:
- /// ```text
- /// ₁
- /// 🮟
- /// ² ³
- /// ```
- pub vertices: [Vertex; 3],
-}
-
-impl FaceVertices
-{
- fn new(face: Face, vertex_data: &VertexData) -> Self
- {
- Self {
- vertices: face.vertices.map(|face_vertex| {
let vertex_pos = vertex_data
.vertex_positions
.get(face_vertex.pos_index as usize)
@@ -204,30 +154,39 @@ impl FaceVertices
.expect("Vertex normal index is out of bounds")
.clone();
- Vertex::builder()
- .pos(vertex_pos)
- .normal(vertex_normal)
- .build()
- }),
- }
- }
+ 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");
- fn with_full_per_side_tex_coords(mut self, face_location: FaceLocation) -> Self
- {
- match face_location {
- FaceLocation::RightUp => {
- self.vertices[0].texture_coords = Vec2 { x: 1.0, y: 1.0 }.into();
- self.vertices[1].texture_coords = Vec2 { x: 0.0, y: 1.0 }.into();
- self.vertices[2].texture_coords = Vec2 { x: 1.0, y: 0.0 }.into();
+ indices.push(vertex_index);
+
+ added_face_vertices.insert(face_vertex.clone(), vertex_index);
}
- FaceLocation::LeftDown => {
- self.vertices[0].texture_coords = Vec2 { x: 0.0, y: 1.0 }.into();
- self.vertices[1].texture_coords = Vec2 { x: 0.0, y: 0.0 }.into();
- self.vertices[2].texture_coords = Vec2 { x: 1.0, y: 0.0 }.into();
+
+ match face_location {
+ FaceLocation::RightUp => face_location = FaceLocation::LeftDown,
+ FaceLocation::LeftDown => face_location = FaceLocation::RightUp,
}
- };
+ }
- self
+ Mesh::builder()
+ .vertices(vertex_buf)
+ .indices(indices)
+ .build()
}
}
@@ -235,7 +194,6 @@ impl FaceVertices
struct Face
{
vertices: [FaceVertex; 3],
- side: Side,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
@@ -253,7 +211,6 @@ struct SidePositions
down_left: Vec3<f32>,
down_right: Vec3<f32>,
normal_calc_order: NormalCalcOrder,
- side: Side,
}
impl SidePositions
@@ -278,7 +235,6 @@ impl SidePositions
down_left: Vec3 { x: up_left.x, ..down_right.clone() },
down_right,
normal_calc_order: NormalCalcOrder::Clockwise,
- side: Side::Top,
}
}
@@ -302,7 +258,6 @@ impl SidePositions
down_left: Vec3 { x: up_left.x, ..down_right.clone() },
down_right,
normal_calc_order: NormalCalcOrder::CounterClockwise,
- side: Side::Bottom,
}
}
@@ -326,7 +281,6 @@ impl SidePositions
down_left: Vec3 { z: up_left.z, ..down_right.clone() },
down_right,
normal_calc_order: NormalCalcOrder::CounterClockwise,
- side: Side::Left,
}
}
@@ -350,7 +304,6 @@ impl SidePositions
down_left: Vec3 { z: up_left.z, ..down_right.clone() },
down_right,
normal_calc_order: NormalCalcOrder::Clockwise,
- side: Side::Right,
}
}
@@ -374,7 +327,6 @@ impl SidePositions
down_left: Vec3 { x: up_left.x, ..down_right.clone() },
down_right,
normal_calc_order: NormalCalcOrder::Clockwise,
- side: Side::Back,
}
}
@@ -398,7 +350,6 @@ impl SidePositions
down_left: Vec3 { x: up_left.x, ..down_right.clone() },
down_right,
normal_calc_order: NormalCalcOrder::CounterClockwise,
- side: Side::Front,
}
}
}
@@ -469,7 +420,6 @@ fn create_side(side_positions: &SidePositions, data: &mut Data)
normal_index: top_normal_index as u32,
},
],
- side: side_positions.side,
});
// 🮟
@@ -488,6 +438,5 @@ fn create_side(side_positions: &SidePositions, data: &mut Data)
normal_index: top_normal_index as u32,
},
],
- side: side_positions.side,
});
}
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);
+});