summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engine/src/collision.rs142
-rw-r--r--engine/src/data_types/vector.rs21
-rw-r--r--engine/src/lib.rs1
-rw-r--r--engine/src/mesh.rs100
-rw-r--r--engine/src/vertex.rs7
5 files changed, 268 insertions, 3 deletions
diff --git a/engine/src/collision.rs b/engine/src/collision.rs
new file mode 100644
index 0000000..aefd9b6
--- /dev/null
+++ b/engine/src/collision.rs
@@ -0,0 +1,142 @@
+use ecs::Component;
+
+use crate::mesh::Mesh;
+use crate::vector::Vec3;
+
+pub trait Collider<Other>
+{
+ fn intersects(&self, other: &Other) -> bool;
+}
+
+#[derive(Debug, Default, Clone, Component)]
+#[non_exhaustive]
+pub struct BoxCollider
+{
+ pub min: Vec3<f32>,
+ pub max: Vec3<f32>,
+}
+
+impl BoxCollider
+{
+ pub fn for_mesh(mesh: &Mesh) -> Self
+ {
+ let furthest_dir_points = mesh.find_furthest_vertex_positions();
+
+ Self {
+ min: Vec3 {
+ x: furthest_dir_points.left.x,
+ y: furthest_dir_points.down.y,
+ z: furthest_dir_points.back.z,
+ },
+ max: Vec3 {
+ x: furthest_dir_points.right.x,
+ y: furthest_dir_points.up.y,
+ z: furthest_dir_points.front.z,
+ },
+ }
+ }
+
+ pub fn offset(self, offset: Vec3<f32>) -> Self
+ {
+ Self {
+ min: self.min + offset,
+ max: self.max + offset,
+ }
+ }
+}
+
+impl Collider<BoxCollider> for BoxCollider
+{
+ fn intersects(&self, other: &BoxCollider) -> bool
+ {
+ self.min.x <= other.max.x
+ && self.max.x >= other.min.x
+ && self.min.y <= other.max.y
+ && self.max.y >= other.min.y
+ && self.min.z <= other.max.z
+ && self.max.z >= other.min.z
+ }
+}
+
+impl Collider<SphereCollider> for BoxCollider
+{
+ fn intersects(&self, other: &SphereCollider) -> bool
+ {
+ other.intersects(self)
+ }
+}
+
+impl Collider<Vec3<f32>> for BoxCollider
+{
+ fn intersects(&self, other: &Vec3<f32>) -> bool
+ {
+ other.x >= self.min.x
+ && other.y >= self.min.y
+ && other.z >= self.min.z
+ && other.x <= self.max.x
+ && other.y <= self.max.y
+ && other.z <= self.max.z
+ }
+}
+
+#[derive(Debug, Default, Clone, Component)]
+pub struct SphereCollider
+{
+ pub center: Vec3<f32>,
+ pub radius: f32,
+}
+
+impl SphereCollider
+{
+ pub fn offset(self, offset: Vec3<f32>) -> Self
+ {
+ Self {
+ center: self.center + offset,
+ radius: self.radius,
+ }
+ }
+}
+
+impl Collider<SphereCollider> for SphereCollider
+{
+ fn intersects(&self, other: &SphereCollider) -> bool
+ {
+ (&self.center - &other.center).length() <= self.radius + other.radius
+ }
+}
+
+impl Collider<BoxCollider> for SphereCollider
+{
+ fn intersects(&self, other: &BoxCollider) -> bool
+ {
+ let mut min_distance = 0.0;
+
+ if self.center.x < other.min.x {
+ min_distance += (self.center.x - other.min.x).powf(2.0);
+ } else if self.center.x > other.max.x {
+ min_distance += (self.center.x - other.max.x).powf(2.0);
+ }
+
+ if self.center.y < other.min.y {
+ min_distance += (self.center.y - other.min.y).powf(2.0);
+ } else if self.center.y > other.max.y {
+ min_distance += (self.center.y - other.max.y).powf(2.0);
+ }
+
+ if self.center.z < other.min.z {
+ min_distance += (self.center.z - other.min.z).powf(2.0);
+ } else if self.center.z > other.max.z {
+ min_distance += (self.center.z - other.max.z).powf(2.0);
+ }
+
+ min_distance <= self.radius.powf(2.0)
+ }
+}
+
+impl Collider<Vec3<f32>> for SphereCollider
+{
+ fn intersects(&self, other: &Vec3<f32>) -> bool
+ {
+ (&self.center - other).length() <= self.radius
+ }
+}
diff --git a/engine/src/data_types/vector.rs b/engine/src/data_types/vector.rs
index 17953f4..6746b76 100644
--- a/engine/src/data_types/vector.rs
+++ b/engine/src/data_types/vector.rs
@@ -85,6 +85,11 @@ pub struct Vec3<Value>
impl Vec3<f32>
{
+ pub const BACK: Self = Self { x: 0.0, y: 1.0, z: -1.0 };
+ pub const DOWN: Self = Self { x: 0.0, y: -1.0, z: 0.0 };
+ pub const FRONT: Self = Self { x: 0.0, y: 1.0, z: 1.0 };
+ pub const LEFT: Self = Self { x: -1.0, y: 0.0, z: 0.0 };
+ pub const RIGHT: Self = Self { x: 1.0, y: 0.0, z: 0.0 };
pub const UP: Self = Self { x: 0.0, y: 1.0, z: 0.0 };
/// Returns the length of the vector.
@@ -209,6 +214,22 @@ where
}
}
+impl<Value> Mul for Vec3<Value>
+where
+ Value: Mul<Value, Output = Value>,
+{
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output
+ {
+ Self::Output {
+ x: self.x * rhs.x,
+ y: self.y * rhs.y,
+ z: self.z * rhs.z,
+ }
+ }
+}
+
impl<Value> Neg for Vec3<Value>
where
Value: Neg<Output = Value>,
diff --git a/engine/src/lib.rs b/engine/src/lib.rs
index 5b9d8e1..a9a5a97 100644
--- a/engine/src/lib.rs
+++ b/engine/src/lib.rs
@@ -15,6 +15,7 @@ mod opengl;
mod util;
pub mod camera;
+pub mod collision;
pub mod data_types;
pub mod delta_time;
pub mod draw_flags;
diff --git a/engine/src/mesh.rs b/engine/src/mesh.rs
index de0af70..a9914e7 100644
--- a/engine/src/mesh.rs
+++ b/engine/src/mesh.rs
@@ -1,5 +1,6 @@
use ecs::Component;
+use crate::vector::Vec3;
use crate::vertex::Vertex;
pub mod cube;
@@ -30,4 +31,103 @@ impl Mesh
{
self.indices.as_deref()
}
+
+ /// 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.
+ pub fn find_furthest_vertex_positions(&self) -> DirectionPositions<'_>
+ {
+ let mut point_iter = self.vertices().iter().map(|vertex| &vertex.pos).into_iter();
+
+ let first_point = point_iter.next().unwrap();
+
+ point_iter
+ .fold(
+ FurthestPosAcc {
+ up: FurthestPos::new(&first_point, &Vec3::UP),
+ down: FurthestPos::new(&first_point, &Vec3::DOWN),
+ left: FurthestPos::new(&first_point, &Vec3::LEFT),
+ right: FurthestPos::new(&first_point, &Vec3::RIGHT),
+ back: FurthestPos::new(&first_point, &Vec3::BACK),
+ front: FurthestPos::new(&first_point, &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()
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct DirectionPositions<'mesh>
+{
+ pub up: &'mesh Vec3<f32>,
+ pub down: &'mesh Vec3<f32>,
+ pub left: &'mesh Vec3<f32>,
+ pub right: &'mesh Vec3<f32>,
+ pub back: &'mesh Vec3<f32>,
+ pub front: &'mesh Vec3<f32>,
+}
+
+impl<'mesh> From<FurthestPosAcc<'mesh>> for DirectionPositions<'mesh>
+{
+ 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: &'mesh Vec3<f32>,
+ dot_prod: f32,
+ direction: &'mesh Vec3<f32>,
+}
+
+impl<'mesh> FurthestPos<'mesh>
+{
+ fn new(pos: &'mesh Vec3<f32>, direction: &'mesh Vec3<f32>) -> Self
+ {
+ Self {
+ pos,
+ dot_prod: direction.dot(&pos),
+ direction,
+ }
+ }
+
+ fn update_if_further(&mut self, point: &'mesh 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;
+ }
+ }
}
diff --git a/engine/src/vertex.rs b/engine/src/vertex.rs
index 897ee97..5739323 100644
--- a/engine/src/vertex.rs
+++ b/engine/src/vertex.rs
@@ -7,11 +7,12 @@ builder! {
#[builder(name = Builder, derives = (Debug, Default))]
#[derive(Debug, Clone, Default)]
#[repr(C)]
+#[non_exhaustive]
pub struct Vertex
{
- pos: Vec3<f32>,
- texture_coords: Vec2<f32>,
- normal: Vec3<f32>,
+ pub pos: Vec3<f32>,
+ pub texture_coords: Vec2<f32>,
+ pub normal: Vec3<f32>,
}
}