1use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
2#[allow(unused_imports)]
4use num_traits::Float;
5use num_traits::{NumCast, Signed};
6
7#[macro_export]
8macro_rules! vec2 {
9 ($x:expr, $y:expr $(,)?) => {
10 $crate::math::Vec2::new($x, $y)
11 };
12 (x: $x:expr, y: $y:expr $(,)?) => {
13 $crate::math::Vec2::new($x, $y)
14 };
15 () => {
16 $crate::math::Vec2::default()
17 };
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
21pub struct Vec2<T> {
22 pub x: T,
23 pub y: T,
24}
25
26impl<T> Vec2<T> {
27 #[inline]
29 pub const fn new(x: T, y: T) -> Self {
30 Self { x, y }
31 }
32
33 #[inline]
35 pub fn splat(v: T) -> Self
36 where
37 T: Clone,
38 {
39 Self { x: v.clone(), y: v }
40 }
41
42 #[inline]
44 pub fn dot(self, other: Self) -> T
45 where
46 T: Add<Output = T> + Mul<Output = T>,
47 {
48 self.x * other.x + self.y * other.y
49 }
50
51 #[inline]
53 pub fn length(self) -> f32
54 where
55 T: Into<f32> + Clone,
56 {
57 let x = self.x.clone().into();
58 let y = self.y.clone().into();
59 (x * x + y * y).sqrt()
60 }
61
62 #[inline]
64 pub fn cast<U: NumCast>(self) -> Vec2<U>
65 where
66 T: NumCast,
67 {
68 self.try_cast().unwrap()
69 }
70
71 #[inline]
73 pub fn try_cast<U: NumCast>(self) -> Option<Vec2<U>>
74 where
75 T: NumCast,
76 {
77 match (NumCast::from(self.x), NumCast::from(self.y)) {
78 (Some(x), Some(y)) => Some(Vec2::new(x, y)),
79 _ => None,
80 }
81 }
82
83 #[inline]
85 pub fn abs(self) -> Self
86 where
87 T: Signed,
88 {
89 Self::new(self.x.abs(), self.y.abs())
90 }
91
92 #[inline]
94 pub fn cross(self, other: Self) -> T
95 where
96 T: Sub<Output = T> + Mul<Output = T>,
97 {
98 self.x * other.y - self.y * other.x
99 }
100
101 #[inline]
103 pub fn yx(self) -> Self {
104 Self::new(self.y, self.x)
105 }
106
107 #[inline]
109 pub fn square_length(self) -> T
110 where
111 T: Add<Output = T> + Mul<Output = T> + Clone,
112 {
113 self.x.clone() * self.x + self.y.clone() * self.y
114 }
115
116 #[inline]
118 pub fn distance(self, other: Self) -> f32
119 where
120 T: Into<f32> + Clone,
121 {
122 let x = self.x.clone().into() - other.x.clone().into();
123 let y = self.y.clone().into() - other.y.clone().into();
124 (x * x + y * y).sqrt()
125 }
126}
127
128impl Vec2<f32> {
129 #[inline]
131 pub fn round(self) -> Self {
132 Self::new(self.x.round(), self.y.round())
133 }
134
135 #[inline]
137 pub fn ceil(self) -> Self {
138 Self::new(self.x.ceil(), self.y.ceil())
139 }
140
141 #[inline]
143 pub fn floor(self) -> Self {
144 Self::new(self.x.floor(), self.y.floor())
145 }
146
147 #[inline]
149 pub fn normalize(self) -> Self {
150 let length = self.length();
151 if length == 0.0 {
152 return Self::ZERO;
153 }
154 self / length
155 }
156
157 #[inline]
159 pub fn with_length(self, length: f32) -> Self {
160 self.normalize() * length
161 }
162
163 #[inline]
165 pub fn rotate_around(self, center: Self, radians: f32) -> Self {
166 let (sin, cos) = radians.sin_cos();
167 let x = self.x - center.x;
168 let y = self.y - center.y;
169 Self::new(x * cos - y * sin + center.x, x * sin + y * cos + center.y)
170 }
171
172 #[inline]
174 pub fn rotate(self, radians: f32) -> Self {
175 let (sin, cos) = radians.sin_cos();
176 Self::new(self.x * cos - self.y * sin, self.x * sin + self.y * cos)
177 }
178
179 #[inline]
181 pub fn scale(self, other: Self) -> Self {
182 Self::new(self.x * other.x, self.y * other.y)
183 }
184
185 #[inline]
187 pub fn translate(self, other: Self) -> Self {
188 Self::new(self.x + other.x, self.y + other.y)
189 }
190
191 #[inline]
193 pub fn project_onto(self, other: Self) -> Self {
194 let other = other.normalize();
195 other * self.dot(other)
196 }
197
198 #[inline]
200 pub fn reflect(self, normal: Self) -> Self {
201 self - normal * 2.0 * self.dot(normal)
202 }
203}
204
205impl<T> From<(T, T)> for Vec2<T> {
206 #[inline]
207 fn from(v: (T, T)) -> Self {
208 Self { x: v.0, y: v.1 }
209 }
210}
211
212impl<T> From<Vec2<T>> for (T, T) {
213 #[inline]
214 fn from(val: Vec2<T>) -> Self {
215 (val.x, val.y)
216 }
217}
218
219impl<T> From<Vec2<T>> for [T; 2] {
220 #[inline]
221 fn from(val: Vec2<T>) -> Self {
222 [val.x, val.y]
223 }
224}
225
226impl<T: Add<Output = T> + Clone> Add<T> for Vec2<T> {
227 type Output = Self;
228 #[inline]
229 fn add(self, rhs: T) -> Self::Output {
230 Self::new(self.x + rhs.clone(), self.y + rhs)
231 }
232}
233
234impl<T: Add<Output = T>> Add<Self> for Vec2<T> {
235 type Output = Self;
236 #[inline]
237 fn add(self, rhs: Self) -> Self::Output {
238 Self::new(self.x + rhs.x, self.y + rhs.y)
239 }
240}
241
242impl<T: AddAssign<T> + Clone> AddAssign<T> for Vec2<T> {
243 #[inline]
244 fn add_assign(&mut self, rhs: T) {
245 self.x += rhs.clone();
246 self.y += rhs;
247 }
248}
249
250impl<T: AddAssign<T>> AddAssign<Self> for Vec2<T> {
251 #[inline]
252 fn add_assign(&mut self, rhs: Self) {
253 self.x += rhs.x;
254 self.y += rhs.y;
255 }
256}
257
258impl<T: Sub<Output = T> + Clone> Sub<T> for Vec2<T> {
259 type Output = Self;
260 #[inline]
261 fn sub(self, rhs: T) -> Self::Output {
262 Self::new(self.x - rhs.clone(), self.y - rhs)
263 }
264}
265
266impl<T: Sub<Output = T>> Sub<Self> for Vec2<T> {
267 type Output = Self;
268 #[inline]
269 fn sub(self, rhs: Self) -> Self::Output {
270 Self::new(self.x - rhs.x, self.y - rhs.y)
271 }
272}
273
274impl<T: SubAssign<T> + Clone> SubAssign<T> for Vec2<T> {
275 #[inline]
276 fn sub_assign(&mut self, rhs: T) {
277 self.x -= rhs.clone();
278 self.y -= rhs;
279 }
280}
281
282impl<T: SubAssign<T>> SubAssign<Self> for Vec2<T> {
283 #[inline]
284 fn sub_assign(&mut self, rhs: Self) {
285 self.x -= rhs.x;
286 self.y -= rhs.y;
287 }
288}
289
290impl<T: Mul<Output = T> + Clone> Mul<T> for Vec2<T> {
291 type Output = Self;
292 #[inline]
293 fn mul(self, rhs: T) -> Self::Output {
294 Self::new(self.x * rhs.clone(), self.y * rhs)
295 }
296}
297
298impl<T: MulAssign<T>> MulAssign<Self> for Vec2<T> {
299 #[inline]
300 fn mul_assign(&mut self, rhs: Self) {
301 self.x *= rhs.x;
302 self.y *= rhs.y;
303 }
304}
305
306impl<T: Div<Output = T> + Clone> Div<T> for Vec2<T> {
307 type Output = Self;
308 #[inline]
309 fn div(self, rhs: T) -> Self::Output {
310 Self::new(self.x / rhs.clone(), self.y / rhs)
311 }
312}
313
314impl<T: DivAssign<T>> DivAssign<Self> for Vec2<T> {
315 #[inline]
316 fn div_assign(&mut self, rhs: Self) {
317 self.x /= rhs.x;
318 self.y /= rhs.y;
319 }
320}
321
322impl Vec2<i8> {
323 pub const ZERO: Self = Self { x: 0, y: 0 };
324}
325
326impl Vec2<u8> {
327 pub const ZERO: Self = Self { x: 0, y: 0 };
328}
329
330impl Vec2<i32> {
331 pub const ZERO: Self = Self { x: 0, y: 0 };
332}
333
334impl Vec2<u32> {
335 pub const ZERO: Self = Self { x: 0, y: 0 };
336}
337
338impl Vec2<isize> {
339 pub const ZERO: Self = Self { x: 0, y: 0 };
340}
341
342impl Vec2<usize> {
343 pub const ZERO: Self = Self { x: 0, y: 0 };
344}
345
346impl Vec2<f32> {
347 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
348}
349
350#[macro_export]
351macro_rules! size {
352 ($w:expr, $h:expr $(,)?) => {
353 $crate::math::Size::new($w, $h)
354 };
355 (w: $w:expr, h: $h:expr $(,)?) => {
356 $crate::math::Size::new($w, $h)
357 };
358 (width: $w:expr, height: $h:expr $(,)?) => {
359 $crate::math::Size::new($w, $h)
360 };
361 (square: $square: expr $(,)?) => {
362 $crate::math::Size::splat($square)
363 };
364 () => {
365 $crate::math::Size::default()
366 };
367}
368
369#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
370pub struct Size<T> {
371 pub width: T,
372 pub height: T,
373}
374
375impl<T> Size<T> {
376 #[inline]
378 pub const fn new(width: T, height: T) -> Self {
379 Self { width, height }
380 }
381
382 #[inline]
384 pub fn splat(v: T) -> Self
385 where
386 T: Clone,
387 {
388 Self {
389 width: v.clone(),
390 height: v,
391 }
392 }
393
394 #[inline]
396 pub fn cast<U: NumCast>(self) -> Size<U>
397 where
398 T: NumCast,
399 {
400 self.try_cast().unwrap()
401 }
402
403 #[inline]
405 pub fn try_cast<U: NumCast>(self) -> Option<Size<U>>
406 where
407 T: NumCast,
408 {
409 match (NumCast::from(self.width), NumCast::from(self.height)) {
410 (Some(w), Some(h)) => Some(Size::new(w, h)),
411 _ => None,
412 }
413 }
414
415 #[inline]
417 pub fn area(self) -> T
418 where
419 T: Mul<Output = T>,
420 {
421 self.width * self.height
422 }
423
424 #[inline]
426 pub fn aspect_ratio(self) -> f32
427 where
428 T: Into<f32> + Clone,
429 {
430 let width = self.width.clone().into();
431 let height = self.height.clone().into();
432 width / height
433 }
434}
435
436impl Size<u8> {
437 pub const ZERO: Self = Self::new(0, 0);
438 pub const ONE: Self = Self::new(1, 1);
439 pub const TILE16: Self = Self::new(16, 16);
440 pub const TILE32: Self = Self::new(32, 32);
441 pub const TILE64: Self = Self::new(64, 64);
442}
443
444impl Size<i8> {
445 pub const ZERO: Self = Self::new(0, 0);
446 pub const ONE: Self = Self::new(1, 1);
447 pub const TILE16: Self = Self::new(16, 16);
448 pub const TILE32: Self = Self::new(32, 32);
449 pub const TILE64: Self = Self::new(64, 64);
450}
451
452impl Size<u16> {
453 pub const ZERO: Self = Self::new(0, 0);
454 pub const ONE: Self = Self::new(1, 1);
455 pub const TILE16: Self = Self::new(16, 16);
456 pub const TILE32: Self = Self::new(32, 32);
457 pub const TILE64: Self = Self::new(64, 64);
458}
459
460impl Size<i16> {
461 pub const ZERO: Self = Self::new(0, 0);
462 pub const ONE: Self = Self::new(1, 1);
463 pub const TILE16: Self = Self::new(16, 16);
464 pub const TILE32: Self = Self::new(32, 32);
465 pub const TILE64: Self = Self::new(64, 64);
466}
467
468impl Size<u32> {
469 pub const ZERO: Self = Self::new(0, 0);
470 pub const ONE: Self = Self::new(1, 1);
471 pub const TILE16: Self = Self::new(16, 16);
472 pub const TILE32: Self = Self::new(32, 32);
473 pub const TILE64: Self = Self::new(64, 64);
474}
475
476impl Size<i32> {
477 pub const ZERO: Self = Self::new(0, 0);
478 pub const ONE: Self = Self::new(1, 1);
479 pub const TILE16: Self = Self::new(16, 16);
480 pub const TILE32: Self = Self::new(32, 32);
481 pub const TILE64: Self = Self::new(64, 64);
482}
483
484impl Size<usize> {
485 pub const ZERO: Self = Self::new(0, 0);
486 pub const ONE: Self = Self::new(1, 1);
487 pub const TILE16: Self = Self::new(16, 16);
488 pub const TILE32: Self = Self::new(32, 32);
489 pub const TILE64: Self = Self::new(64, 64);
490}
491
492impl Size<isize> {
493 pub const ZERO: Self = Self::new(0, 0);
494 pub const ONE: Self = Self::new(1, 1);
495 pub const TILE16: Self = Self::new(16, 16);
496 pub const TILE32: Self = Self::new(32, 32);
497 pub const TILE64: Self = Self::new(64, 64);
498}
499
500impl Size<f32> {
501 pub const ZERO: Self = Self::new(0.0, 0.0);
502 pub const ONE: Self = Self::new(1.0, 1.0);
503 pub const TILE16: Self = Self::new(16.0, 16.0);
504 pub const TILE32: Self = Self::new(32.0, 32.0);
505 pub const TILE64: Self = Self::new(64.0, 64.0);
506
507 #[inline]
509 pub fn round(self) -> Self {
510 Self::new(self.width.round(), self.height.round())
511 }
512
513 #[inline]
515 pub fn ceil(self) -> Self {
516 Self::new(self.width.ceil(), self.height.ceil())
517 }
518
519 #[inline]
521 pub fn floor(self) -> Self {
522 Self::new(self.width.floor(), self.height.floor())
523 }
524
525 #[inline]
527 pub fn scale(self, scale: Vec2<f32>) -> Self {
528 Self::new(self.width * scale.x, self.height * scale.y)
529 }
530}
531
532#[macro_export]
533macro_rules! rect {
534 (x: $x:expr, y: $y:expr, w: $w:expr, h: $h:expr $(,)?) => {
535 $crate::math::Rect::new($x, $y, $w, $h)
536 };
537 (x: $x:expr, y: $y:expr, width: $w:expr, height: $h:expr $(,)?) => {
538 $crate::math::Rect::new($x, $y, $w, $h)
539 };
540 (pos: $p:expr, size: $s:expr $(,)?) => {
541 $crate::math::Rect::from_point_and_size($p, $s)
542 };
543 () => {
544 $crate::math::Rect::default()
545 };
546}
547
548#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
549pub struct Rect<T> {
550 pub x: T,
551 pub y: T,
552 pub width: T,
553 pub height: T,
554}
555
556impl<T> Rect<T> {
557 #[inline]
559 pub const fn new(x: T, y: T, width: T, height: T) -> Self {
560 Self {
561 x,
562 y,
563 width,
564 height,
565 }
566 }
567
568 #[inline]
570 pub fn from_pos_and_size(pos: Vec2<T>, size: Size<T>) -> Self {
571 Self {
572 x: pos.x,
573 y: pos.y,
574 width: size.width,
575 height: size.height,
576 }
577 }
578
579 #[inline]
581 pub fn pos(&self) -> Vec2<T>
582 where
583 T: Clone,
584 {
585 Vec2::new(self.x.clone(), self.y.clone())
586 }
587
588 #[inline]
590 pub fn size(&self) -> Size<T>
591 where
592 T: Clone,
593 {
594 Size::new(self.width.clone(), self.height.clone())
595 }
596
597 #[inline]
599 pub fn cast<U: NumCast>(self) -> Rect<U>
600 where
601 T: NumCast,
602 {
603 self.try_cast().unwrap()
604 }
605
606 #[inline]
608 pub fn try_cast<U: NumCast>(self) -> Option<Rect<U>>
609 where
610 T: NumCast,
611 {
612 match (
613 NumCast::from(self.x),
614 NumCast::from(self.y),
615 NumCast::from(self.width),
616 NumCast::from(self.height),
617 ) {
618 (Some(x), Some(y), Some(w), Some(h)) => Some(Rect::new(x, y, w, h)),
619 _ => None,
620 }
621 }
622
623 #[inline]
625 pub fn area(&self) -> T
626 where
627 T: Mul<Output = T> + Clone,
628 {
629 self.width.clone() * self.height.clone()
630 }
631
632 #[inline]
634 pub fn aspect_ratio(&self) -> f32
635 where
636 T: Into<f32> + Clone,
637 {
638 let width = self.width.clone().into();
639 let height = self.height.clone().into();
640 width / height
641 }
642
643 #[inline]
645 pub fn intersection(&self, other: &Self) -> Option<Self>
646 where
647 T: PartialOrd + Add<T, Output = T> + Sub<T, Output = T> + Default + Clone + Copy,
648 {
649 let min = |a: T, b: T| if a < b { a } else { b };
650 let max = |a: T, b: T| if a > b { a } else { b };
651 let x = max(self.x, other.x);
652 let y = max(self.y, other.y);
653 let width = min(self.x + self.width, other.x + other.width) - x;
654 let height = min(self.y + self.height, other.y + other.height) - y;
655 if width <= T::default() || height <= T::default() {
656 None
657 } else {
658 Some(Self::new(x, y, width, height))
659 }
660 }
661}
662
663impl Rect<f32> {
664 #[inline]
666 pub fn round(self) -> Self {
667 Self::new(
668 self.x.round(),
669 self.y.round(),
670 self.width.round(),
671 self.height.round(),
672 )
673 }
674
675 #[inline]
677 pub fn ceil(self) -> Self {
678 Self::new(
679 self.x.ceil(),
680 self.y.ceil(),
681 self.width.ceil(),
682 self.height.ceil(),
683 )
684 }
685
686 #[inline]
688 pub fn floor(self) -> Self {
689 Self::new(
690 self.x.floor(),
691 self.y.floor(),
692 self.width.floor(),
693 self.height.floor(),
694 )
695 }
696
697 #[inline]
699 pub fn scale(self, scale: Vec2<f32>) -> Self {
700 Self::new(self.x, self.y, self.width * scale.x, self.height * scale.y)
701 }
702
703 #[inline]
705 pub fn translate(self, delta: Vec2<f32>) -> Self {
706 Self::new(self.x + delta.x, self.y + delta.y, self.width, self.height)
707 }
708
709 #[inline]
711 pub fn center(&self) -> Vec2<f32> {
712 Vec2::new(self.x + self.width / 2.0, self.y + self.height / 2.0)
713 }
714
715 #[inline]
717 pub fn intersects(&self, other: &Self) -> bool {
718 self.x < other.x + other.width
719 && self.x + self.width > other.x
720 && self.y < other.y + other.height
721 && self.y + self.height > other.y
722 }
723
724 #[inline]
726 pub fn contains_point(&self, point: Vec2<f32>) -> bool {
727 point.x >= self.x
728 && point.x <= self.x + self.width
729 && point.y >= self.y
730 && point.y <= self.y + self.height
731 }
732
733 #[inline]
735 pub fn contains_rect(&self, other: &Self) -> bool {
736 self.x <= other.x
737 && self.x + self.width >= other.x + other.width
738 && self.y <= other.y
739 && self.y + self.height >= other.y + other.height
740 }
741}
742
743impl From<Rect<f32>> for sys::PDRect {
744 #[inline]
745 fn from(val: Rect<f32>) -> Self {
746 sys::PDRect {
747 x: val.x,
748 y: val.y,
749 width: val.width,
750 height: val.height,
751 }
752 }
753}
754
755impl From<sys::PDRect> for Rect<f32> {
756 #[inline]
757 fn from(rect: sys::PDRect) -> Self {
758 Self {
759 x: rect.x,
760 y: rect.y,
761 width: rect.width,
762 height: rect.height,
763 }
764 }
765}
766
767impl From<sys::CollisionPoint> for Vec2<f32> {
768 #[inline]
769 fn from(v: sys::CollisionPoint) -> Self {
770 Self { x: v.x, y: v.y }
771 }
772}
773
774impl From<sys::CollisionVector> for Vec2<i32> {
775 #[inline]
776 fn from(v: sys::CollisionVector) -> Self {
777 Self { x: v.x, y: v.y }
778 }
779}
780
781pub struct SideOffsets<T> {
782 pub left: T,
783 pub right: T,
784 pub top: T,
785 pub bottom: T,
786}
787
788impl<T> SideOffsets<T> {
789 #[inline]
790 pub fn new(left: T, right: T, top: T, bottom: T) -> Self {
791 Self {
792 left,
793 right,
794 top,
795 bottom,
796 }
797 }
798
799 #[inline]
800 pub fn splat(v: T) -> Self
801 where
802 T: Clone,
803 {
804 Self {
805 left: v.clone(),
806 right: v.clone(),
807 top: v.clone(),
808 bottom: v,
809 }
810 }
811
812 #[inline]
814 pub fn cast<U: NumCast>(self) -> SideOffsets<U>
815 where
816 T: NumCast,
817 {
818 self.try_cast().unwrap()
819 }
820
821 #[inline]
823 pub fn try_cast<U: NumCast>(self) -> Option<SideOffsets<U>>
824 where
825 T: NumCast,
826 {
827 match (
828 NumCast::from(self.left),
829 NumCast::from(self.right),
830 NumCast::from(self.top),
831 NumCast::from(self.bottom),
832 ) {
833 (Some(l), Some(r), Some(t), Some(b)) => Some(SideOffsets::new(l, r, t, b)),
834 _ => None,
835 }
836 }
837}
838
839impl SideOffsets<i32> {
840 pub const ZERO: Self = Self {
841 left: 0,
842 right: 0,
843 top: 0,
844 bottom: 0,
845 };
846}
847
848impl From<SideOffsets<i32>> for sys::LCDRect {
849 #[inline]
850 fn from(val: SideOffsets<i32>) -> Self {
851 sys::LCDRect {
852 left: val.left,
853 right: val.right,
854 top: val.top,
855 bottom: val.bottom,
856 }
857 }
858}