enigma_3d/
collision_world.rs1use 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}