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