1use crate::prelude::{draw_line, draw_rectangle_from_rect, draw_rectangle_lines_from_rect, draw_rectangle_lines_rounded_from_rect, draw_rectangle_lines_rounded_from_rect_ex, draw_rectangle_rotated, draw_rectangle_rounded_from_rect, draw_rectangle_rounded_from_rect_ex, mouse_position_vec2, mouse_position_vec2_global, Color, Vector2};
2use cgmath::vec2;
3
4#[derive(Debug, Clone, Copy, Default, PartialEq, PartialOrd)]
30pub struct Rect {
31 pub x: f32,
32 pub y: f32,
33 pub w: f32,
34 pub h: f32,
35}
36
37impl Rect {
38 pub const fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
40 Self { x, y, w, h }
41 }
42
43 pub fn from_corners(a: Vector2, b: Vector2) -> Self {
45 let x = a.x.min(b.x);
46 let y = a.y.min(b.y);
47 Self::new(x, y, (a.x - b.x).abs(), (a.y - b.y).abs())
48 }
49
50 pub fn from_center(center: Vector2, w: f32, h: f32) -> Self {
52 Self::new(center.x - w / 2.0, center.y - h / 2.0, w, h)
53 }
54
55 pub const fn left(&self) -> f32 {
57 self.x
58 }
59 pub const fn right(&self) -> f32 {
60 self.x + self.w
61 }
62 pub const fn top(&self) -> f32 {
63 self.y
64 }
65 pub const fn bottom(&self) -> f32 {
66 self.y + self.h
67 }
68
69 pub const fn top_left(&self) -> Vector2 {
71 vec2(self.x, self.y)
72 }
73 pub const fn top_right(&self) -> Vector2 {
74 vec2(self.x + self.w, self.y)
75 }
76 pub const fn bottom_left(&self) -> Vector2 {
77 vec2(self.x, self.y + self.h)
78 }
79 pub const fn bottom_right(&self) -> Vector2 {
80 vec2(self.x + self.w, self.y + self.h)
81 }
82 pub const fn xy(&self) -> Vector2 {
83 vec2(self.x, self.y)
84 }
85 pub const fn wh(&self) -> Vector2 {
86 vec2(self.w, self.h)
87 }
88 pub const fn xw(&self) -> Vector2 {
89 vec2(self.x, self.w)
90 }
91 pub const fn xh(&self) -> Vector2 {
92 vec2(self.x, self.h)
93 }
94 pub const fn yw(&self) -> Vector2 {
95 vec2(self.y, self.w)
96 }
97 pub const fn yh(&self) -> Vector2 {
98 vec2(self.y, self.h)
99 }
100
101 pub fn corners(&self) -> [Vector2; 4] {
102 [
103 self.top_left(),
104 self.top_right(),
105 self.bottom_left(),
106 self.bottom_right(),
107 ]
108 }
109 pub fn center(&self) -> Vector2 {
110 vec2(self.x + self.w / 2.0, self.y + self.h / 2.0)
111 }
112
113 pub const fn area(&self) -> f32 {
115 self.w * self.h
116 }
117 pub const fn perimeter(&self) -> f32 {
118 2.0 * (self.w + self.h)
119 }
120 pub const fn size(&self) -> Vector2 {
121 vec2(self.w, self.h)
122 }
123 pub const fn position(&self) -> Vector2 {
124 vec2(self.x, self.y)
125 }
126
127 pub const fn with_x(&self, x: f32) -> Self {
130 Self::new(x, self.y, self.w, self.h)
131 }
132 pub const fn with_y(&self, y: f32) -> Self {
134 Self::new(self.x, y, self.w, self.h)
135 }
136 pub const fn with_w(&self, w: f32) -> Self {
138 Self::new(self.x, self.y, w, self.h)
139 }
140 pub const fn with_h(&self, h: f32) -> Self {
142 Self::new(self.x, self.y, self.w, h)
143 }
144
145 pub fn with_position(&self, pos: Vector2) -> Self {
147 Self::new(pos.x, pos.y, self.w, self.h)
148 }
149 pub fn with_position_xy(&self, x: f32, y: f32) -> Self {
151 Self::new(x, y, self.w, self.h)
152 }
153
154 pub fn change_position_by(&mut self, offset: Vector2) {
156 self.x += offset.x;
157 self.y += offset.y;
158 }
159
160 pub fn change_size_by(&mut self, offset: Vector2) {
162 self.w += offset.x;
163 self.h += offset.y;
164 }
165
166 pub fn with_size(&self, size: Vector2) -> Self {
168 Self::new(self.x, self.y, size.x, size.y)
169 }
170
171 pub fn translated(&self, offset: Vector2) -> Self {
173 Self::new(self.x + offset.x, self.y + offset.y, self.w, self.h)
174 }
175
176 pub fn centered_at(&self, center: Vector2) -> Self {
178 Self::from_center(center, self.w, self.h)
179 }
180
181 pub fn inflated(&self, amount: f32) -> Self {
183 Self::new(
184 self.x - amount,
185 self.y - amount,
186 self.w + amount * 2.0,
187 self.h + amount * 2.0,
188 )
189 }
190
191 pub const fn scaled(&self, factor: f32) -> Self {
193 Self::new(self.x, self.y, self.w * factor, self.h * factor)
194 }
195
196 pub fn scaled_from_center(&self, factor: f32) -> Self {
198 let center = self.center();
199 Self::from_center(center, self.w * factor, self.h * factor)
200 }
201
202 pub fn union(&self, other: &Rect) -> Self {
204 let x1 = self.x.min(other.x);
205 let y1 = self.y.min(other.y);
206 let x2 = (self.x + self.w).max(other.x + other.w);
207 let y2 = (self.y + self.h).max(other.y + other.h);
208 Self::new(x1, y1, x2 - x1, y2 - y1)
209 }
210
211 pub fn clamp_point(&self, point: Vector2) -> Vector2 {
213 vec2(
214 point.x.clamp(self.left(), self.right()),
215 point.y.clamp(self.top(), self.bottom()),
216 )
217 }
218
219 pub fn normalized(&self) -> Self {
221 let (x, w) = if self.w < 0.0 {
222 (self.x + self.w, -self.w)
223 } else {
224 (self.x, self.w)
225 };
226 let (y, h) = if self.h < 0.0 {
227 (self.y + self.h, -self.h)
228 } else {
229 (self.y, self.h)
230 };
231 Self::new(x, y, w, h)
232 }
233
234 pub fn to_array(&self) -> [f32; 4] {
235 [self.x, self.y, self.w, self.h]
236 }
237
238 pub fn lerp(self, other: Rect, t: f32) -> Self {
240 Self::new(
241 self.x + (other.x - self.x) * t,
242 self.y + (other.y - self.y) * t,
243 self.w + (other.w - self.w) * t,
244 self.h + (other.h - self.h) * t,
245 )
246 }
247
248 pub const fn contains_point(&self, x: f32, y: f32) -> bool {
250 x >= self.x && y >= self.y && x <= self.x + self.w && y <= self.y + self.h
251 }
252
253 pub const fn contains_point_fully(&self, x: f32, y: f32) -> bool {
255 x > self.x && y > self.y && x < self.x + self.w && y < self.y + self.h
256 }
257
258 pub const fn contains_point_vec2(&self, point: Vector2) -> bool {
260 self.contains_point(point.x, point.y)
261 }
262
263 pub const fn contains_point_fully_vec2(&self, point: Vector2) -> bool {
265 self.contains_point_fully(point.x, point.y)
266 }
267
268 pub fn contains_mouse(&self) -> bool {
270 self.contains_point_vec2(mouse_position_vec2())
271 }
272
273 pub fn contains_mouse_global(&self) -> bool {
275 self.contains_point_vec2(mouse_position_vec2_global())
276 }
277
278 pub fn contains_mouse_fully(&self) -> bool {
280 self.contains_point_fully_vec2(mouse_position_vec2())
281 }
282
283 pub fn contains_mouse_fully_global(&self) -> bool {
285 self.contains_point_fully_vec2(mouse_position_vec2_global())
286 }
287
288 pub const fn intersects(&self, other: &Rect) -> bool {
290 self.x < other.x + other.w
291 && self.x + self.w > other.x
292 && self.y < other.y + other.h
293 && self.y + self.h > other.y
294 }
295
296 pub const fn intersection(&self, other: Rect) -> Option<Rect> {
298 let x1 = self.x.max(other.x);
299 let y1 = self.y.max(other.y);
300 let x2 = (self.x + self.w).min(other.x + other.w);
301 let y2 = (self.y + self.h).min(other.y + other.h);
302
303 if x1 < x2 && y1 < y2 {
304 Some(Rect::new(x1, y1, x2 - x1, y2 - y1))
305 } else {
306 None
307 }
308 }
309
310 pub const fn contains_rect_fully(&self, other: &Rect) -> bool {
312 self.x <= other.x
313 && self.y <= other.y
314 && self.x + self.w >= other.x + other.w
315 && self.y + self.h >= other.y + other.h
316 }
317
318 pub fn update(&mut self, new_rect: Rect) -> Rect {
320 *self = new_rect;
321 new_rect
322 }
323
324 pub fn draw(&self, color: Color) {
326 draw_rectangle_from_rect(*self, color);
327 }
328
329 pub fn draw_rounded(&self, radius: f32, color: Color) {
330 draw_rectangle_rounded_from_rect(*self, radius, color);
331 }
332
333 pub fn draw_rounded_ex(
334 &self,
335 top_left: f32,
336 top_right: f32,
337 bottom_left: f32,
338 bottom_right: f32,
339 color: Color,
340 ) {
341 draw_rectangle_rounded_from_rect_ex(
342 *self,
343 top_left,
344 top_right,
345 bottom_left,
346 bottom_right,
347 color,
348 );
349 }
350
351 pub fn draw_lines(&self, thickness: f32, color: Color) {
353 draw_rectangle_lines_from_rect(*self, thickness, color);
354 }
355
356 pub fn draw_lines_rounded(&self, radius: f32, thickness: f32, color: Color) {
357 draw_rectangle_lines_rounded_from_rect(*self, radius, thickness, color);
358 }
359
360 pub fn draw_lines_rounded_ex(
361 &self,
362 top_left: f32,
363 top_right: f32,
364 bottom_left: f32,
365 bottom_right: f32,
366 thickness: f32,
367 color: Color,
368 ) {
369 draw_rectangle_lines_rounded_from_rect_ex(
370 *self,
371 top_left,
372 top_right,
373 bottom_left,
374 bottom_right,
375 thickness,
376 color,
377 );
378 }
379}
380
381impl Into<[f32; 4]> for Rect {
382 fn into(self) -> [f32; 4] {
383 self.to_array()
384 }
385}
386
387impl Rect {
390 pub fn resolve_collision(&mut self, other: Rect) -> Option<Vector2> {
393 let c = self.intersection(other)?;
394 let (sc, oc) = (self.center(), other.center());
395
396 if c.w < c.h {
397 let dir = if sc.x < oc.x { -1.0 } else { 1.0 };
398 self.x += c.w * dir;
399 Some(vec2(dir, 0.0))
400 } else {
401 let dir = if sc.y < oc.y { -1.0 } else { 1.0 };
402 self.y += c.h * dir;
403 Some(vec2(0.0, dir))
404 }
405 }
406
407 pub fn resolve_collision_obb(
410 &mut self,
411 angle: f32,
412 other: &Rect,
413 other_angle: f32,
414 ) -> Option<Vector2> {
415 let mtv = self.intersection_obb(angle, other, other_angle)?;
416 let len = (mtv.x * mtv.x + mtv.y * mtv.y).sqrt();
417 if len <= f32::EPSILON {
418 return None;
419 }
420 self.change_position_by(mtv);
421 Some(mtv / len)
422 }
423
424 pub fn intersection_obb(&self, angle: f32, other: &Rect, other_angle: f32) -> Option<Vector2> {
427 let dot = |a: Vector2, b: Vector2| a.x * b.x + a.y * b.y;
428 let axes = |a: f32| {
429 let (s, c) = a.sin_cos();
430 [vec2(c, s), vec2(-s, c)]
431 };
432
433 let a_axes = axes(angle);
434 let b_axes = axes(other_angle);
435 let (ha, hb) = (self.size() * 0.5, other.size() * 0.5);
436 let d = other.center() - self.center();
437
438 let mut min_overlap = f32::MAX;
439 let mut mtv = vec2(0.0, 0.0);
440
441 for n in a_axes.iter().chain(b_axes.iter()) {
442 let n = *n;
443
444 let ra = ha.x * dot(a_axes[0], n).abs() + ha.y * dot(a_axes[1], n).abs();
446 let rb = hb.x * dot(b_axes[0], n).abs() + hb.y * dot(b_axes[1], n).abs();
447
448 let dist = dot(d, n);
449 let overlap = ra + rb - dist.abs();
450
451 if overlap <= 0.0 {
452 return None; }
454
455 if overlap < min_overlap {
456 min_overlap = overlap;
457 let sign = if dist > 0.0 { -1.0 } else { 1.0 };
458 mtv = n * (sign * overlap);
459 }
460 }
461
462 Some(mtv)
463 }
464
465 pub fn intersects_obb(&self, angle: f32, other: &Rect, other_angle: f32) -> bool {
467 self.intersection_obb(angle, other, other_angle).is_some()
468 }
469
470 pub fn corners_by_angle(&self, angle: f32) -> [Vector2; 4] {
472 let c = self.center();
473 let (s, co) = angle.sin_cos();
474 let (hw, hh) = (self.w / 2.0, self.h / 2.0);
475 [(-hw, -hh), (hw, -hh), (hw, hh), (-hw, hh)]
476 .map(|(x, y)| vec2(c.x + x * co - y * s, c.y + x * s + y * co))
477 }
478
479 pub fn draw_rotated(&self, angle: f32, color: Color) {
481 let c = self.center();
482 draw_rectangle_rotated(c.x, c.y, self.w, self.h, angle, color);
483 }
484
485 pub fn draw_lines_rotated(&self, angle: f32, thickness: f32, color: Color) {
487 let c = self.corners_by_angle(angle);
488 for i in 0..4 {
489 let (a, b) = (c[i], c[(i + 1) % 4]);
490 draw_line(a.x, a.y, b.x, b.y, thickness, color);
491 }
492 }
493}