1#![allow(clippy::unnecessary_cast)]
15
16use crate::collision::CastOutput;
17use crate::math_functions::{
18 abs, lerp, min_float, round_down_float, round_up_float, sub, Aabb, Pos, Vec2, VEC2_ZERO,
19};
20
21pub fn perimeter(a: Aabb) -> f32 {
23 let wx = a.upper_bound.x - a.lower_bound.x;
24 let wy = a.upper_bound.y - a.lower_bound.y;
25 2.0 * (wx + wy)
26}
27
28pub fn enlarge_aabb(a: &mut Aabb, b: Aabb) -> bool {
32 let mut changed = false;
33 if b.lower_bound.x < a.lower_bound.x {
34 a.lower_bound.x = b.lower_bound.x;
35 changed = true;
36 }
37
38 if b.lower_bound.y < a.lower_bound.y {
39 a.lower_bound.y = b.lower_bound.y;
40 changed = true;
41 }
42
43 if a.upper_bound.x < b.upper_bound.x {
44 a.upper_bound.x = b.upper_bound.x;
45 changed = true;
46 }
47
48 if a.upper_bound.y < b.upper_bound.y {
49 a.upper_bound.y = b.upper_bound.y;
50 changed = true;
51 }
52
53 changed
54}
55
56pub fn offset_aabb(box_: Aabb, origin: Pos) -> Aabb {
64 Aabb {
65 lower_bound: Vec2 {
66 x: round_down_float(origin.x as f64 + box_.lower_bound.x as f64),
67 y: round_down_float(origin.y as f64 + box_.lower_bound.y as f64),
68 },
69 upper_bound: Vec2 {
70 x: round_up_float(origin.x as f64 + box_.upper_bound.x as f64),
71 y: round_up_float(origin.y as f64 + box_.upper_bound.y as f64),
72 },
73 }
74}
75
76pub fn aabb_ray_cast(a: Aabb, p1: Vec2, p2: Vec2) -> CastOutput {
79 let mut output = CastOutput::default();
80
81 let mut t_min = -f32::MAX;
82 let mut t_max = f32::MAX;
83
84 let p = p1;
85 let d = sub(p2, p1);
86 let abs_d = abs(d);
87
88 let mut normal = VEC2_ZERO;
89
90 if abs_d.x < f32::EPSILON {
92 if p.x < a.lower_bound.x || a.upper_bound.x < p.x {
94 return output;
95 }
96 } else {
97 let inv_d = 1.0 / d.x;
98 let mut t1 = (a.lower_bound.x - p.x) * inv_d;
99 let mut t2 = (a.upper_bound.x - p.x) * inv_d;
100
101 let mut s = -1.0;
103
104 if t1 > t2 {
105 core::mem::swap(&mut t1, &mut t2);
106 s = 1.0;
107 }
108
109 if t1 > t_min {
111 normal.y = 0.0;
112 normal.x = s;
113 t_min = t1;
114 }
115
116 t_max = min_float(t_max, t2);
118
119 if t_min > t_max {
120 return output;
121 }
122 }
123
124 if abs_d.y < f32::EPSILON {
126 if p.y < a.lower_bound.y || a.upper_bound.y < p.y {
128 return output;
129 }
130 } else {
131 let inv_d = 1.0 / d.y;
132 let mut t1 = (a.lower_bound.y - p.y) * inv_d;
133 let mut t2 = (a.upper_bound.y - p.y) * inv_d;
134
135 let mut s = -1.0;
137
138 if t1 > t2 {
139 core::mem::swap(&mut t1, &mut t2);
140 s = 1.0;
141 }
142
143 if t1 > t_min {
145 normal.x = 0.0;
146 normal.y = s;
147 t_min = t1;
148 }
149
150 t_max = min_float(t_max, t2);
152
153 if t_min > t_max {
154 return output;
155 }
156 }
157
158 if t_min < 0.0 {
160 return output;
161 }
162
163 if 1.0 < t_min {
165 return output;
166 }
167
168 output.fraction = t_min;
170 output.normal = normal;
171 output.point = lerp(p1, p2, t_min);
172 output.hit = true;
173 output
174}