enigma_3d/
collision_world.rs

1use std::fmt::Debug;
2use crate::AppState;
3use nalgebra::{Matrix4, Point3, Vector3, Vector4};
4use uuid::Uuid;
5use crate::camera::Camera;
6use crate::geometry::BoundingBox;
7
8
9pub struct MouseState {
10    pub current_position: (f64, f64),
11    previous_position: (f64, f64),
12    delta: (f64, f64),
13    pub world_space: Vector3<f32>,
14}
15
16pub struct RayCast {
17    origin: Vector3<f32>,
18    direction: Vector3<f32>,
19    length: f32,
20    intersection_objects: indexmap::IndexMap<Uuid, Vector3<f32>>
21}
22
23pub fn is_colliding(aabb1: &BoundingBox, aabb2: &BoundingBox) -> bool {
24    let aabb1_min = aabb1.min_point();
25    let aabb1_max = aabb1.max_point();
26    let aabb2_min = aabb2.min_point();
27    let aabb2_max = aabb2.max_point();
28
29    if aabb1_min.x > aabb2_max.x || aabb1_max.x < aabb2_min.x {
30        return false;
31    }
32
33    if aabb1_min.y > aabb2_max.y || aabb1_max.y < aabb2_min.y {
34        return false;
35    }
36
37    if aabb1_min.z > aabb2_max.z || aabb1_max.z < aabb2_min.z {
38        return false;
39    }
40
41    true
42}
43
44impl Debug for MouseState {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        f.debug_struct("MousePosition")
47            .field("current_position", &self.current_position)
48            .field("previous_position", &self.previous_position)
49            .field("delta", &self.delta)
50            .field("world_space", &self.world_space)
51            .finish()
52    }
53}
54
55impl MouseState {
56    pub fn new() -> Self {
57        Self {
58            current_position: (0.0, 0.0),
59            previous_position: (0.0, 0.0),
60            delta: (0.0,0.0),
61            world_space: Vector3::new(0.0, 0.0, 0.0),
62        }
63    }
64
65    pub fn get_world_position(&self, camera: &Camera) -> (Vector3<f32>, Vector3<f32>) {
66        let clip_space_x = (self.current_position.0 as f32 / camera.width) * 2.0 - 1.0;
67        let clip_space_y = 1.0-(self.current_position.1 as f32 / camera.height) * 2.0;
68        let clip_space_z = -1.0;
69        let clip_space_coord: Vector4<f32> = Vector4::new(clip_space_x, clip_space_y, clip_space_z, 1.0);
70        let view_space_coord = Matrix4::from(camera.get_projection_matrix()).try_inverse().unwrap().transform_point(&Point3::from_homogeneous(clip_space_coord).unwrap());
71        let world_space_coord = Matrix4::from(camera.get_view_matrix()).try_inverse().unwrap().transform_point(&view_space_coord);
72        let world_space_point: Point3<f32> = world_space_coord.xyz().into();
73        let ray_direction: Vector3<f32> = (world_space_point - camera.transform.get_position()).coords.normalize();
74
75        (world_space_point.coords, ray_direction)
76    }
77
78    pub fn get_screen_position(&self) -> (f64, f64) {
79        self.current_position
80    }
81
82    pub fn update_position(&mut self, new_position: (f64, f64)) {
83        self.previous_position = self.current_position;
84        self.current_position = new_position;
85        self.delta = (
86            self.current_position.0 - self.previous_position.0,
87            self.current_position.1 - self.previous_position.1,
88        );
89    }
90    pub fn get_delta(&self) -> (f64, f64) {
91        self.delta
92    }
93}
94
95impl RayCast {
96    pub fn new(origin: Vector3<f32>, direction: Vector3<f32>, length: f32) -> Self {
97        Self {
98            origin,
99            direction,
100            length,
101            intersection_objects: indexmap::IndexMap::new(),
102        }
103    }
104
105    pub fn get_intersection_map(&self) -> &indexmap::IndexMap<Uuid, Vector3<f32>> {
106        &self.intersection_objects
107    }
108
109    pub fn get_intersection_uuids(&self) -> Vec<Uuid> {
110        let mut uuids = Vec::new();
111        for (uuid, _) in self.intersection_objects.iter() {
112            uuids.push(*uuid);
113        }
114        uuids
115    }
116
117    pub fn get_intersection_points(&self) -> Vec<Vector3<f32>> {
118        let mut points = Vec::new();
119        for (_, point) in self.intersection_objects.iter() {
120            points.push(*point);
121        }
122        points
123    }
124
125    pub fn cast(&mut self, app_state: &mut AppState) {
126        for object in app_state.objects.iter_mut() {
127            if object.get_collision() == &false{
128                continue
129            }
130            let aabb = object.get_bounding_box();
131            match self.intersects_bounding_box(&aabb) {
132                Some(intersection_point) => {
133                    self.intersection_objects.insert(object.get_unique_id(), intersection_point);
134                },
135                None => {}
136            }
137        }
138    }
139
140    fn intersects_bounding_box(&self, bounding_box: &BoundingBox) -> Option<Vector3<f32>> {
141        let inv_direction = Vector3::new(1.0 / self.direction.x, 1.0 / self.direction.y, 1.0 / self.direction.z);
142        let sign = [
143            (inv_direction.x < 0.0) as usize,
144            (inv_direction.y < 0.0) as usize,
145            (inv_direction.z < 0.0) as usize,
146        ];
147
148        let bbox = [bounding_box.min_point(), bounding_box.max_point()];
149        let mut tmin = (bbox[sign[0]].x - self.origin.x) * inv_direction.x;
150        let mut tmax = (bbox[1 - sign[0]].x - self.origin.x) * inv_direction.x;
151        let tymin = (bbox[sign[1]].y - self.origin.y) * inv_direction.y;
152        let tymax = (bbox[1 - sign[1]].y - self.origin.y) * inv_direction.y;
153
154        if (tmin > tymax) || (tymin > tmax) {
155            return None;
156        }
157
158        if tymin > tmin {
159            tmin = tymin;
160        }
161
162        if tymax < tmax {
163            tmax = tymax;
164        }
165
166        let tzmin = (bbox[sign[2]].z - self.origin.z) * inv_direction.z;
167        let tzmax = (bbox[1 - sign[2]].z - self.origin.z) * inv_direction.z;
168
169        if (tmin > tzmax) || (tzmin > tmax) {
170            return None;
171        }
172
173        if tzmin > tmin {
174            tmin = tzmin;
175        }
176
177        if tzmax < tmax {
178            tmax = tzmax;
179        }
180
181        if (tmin < self.length) && (tmax > 0.0) {
182            return Some(self.origin + tmin * self.direction);
183        }
184
185        None
186    }
187}