summaryrefslogtreecommitdiff
path: root/engine/src/mesh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/mesh.rs')
-rw-r--r--engine/src/mesh.rs570
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;
+ }
+ }
}