1mod rect;
12mod transform;
13mod lerp;
14mod angle;
15
16pub use glam::{Vec2, Vec3, Vec4, Mat4, Quat};
17pub use rect::Rect;
18pub use transform::Transform;
19pub use lerp::Lerp;
20pub use angle::Angle;
21
22#[inline(always)]
26pub const fn vec2(x: f32, y: f32) -> Vec2 {
27 Vec2::new(x, y)
28}
29
30#[inline(always)]
32pub const fn vec3(x: f32, y: f32, z: f32) -> Vec3 {
33 Vec3::new(x, y, z)
34}
35
36#[inline(always)]
38pub const fn ivec2(x: i32, y: i32) -> glam::IVec2 {
39 glam::IVec2::new(x, y)
40}
41
42pub mod consts {
44 use super::*;
45
46 pub const ZERO: Vec2 = Vec2::new(0.0, 0.0);
48 pub const RIGHT: Vec2 = Vec2::new(1.0, 0.0);
50 pub const LEFT: Vec2 = Vec2::new(-1.0, 0.0);
52 pub const UP: Vec2 = Vec2::new(0.0, -1.0);
54 pub const DOWN: Vec2 = Vec2::new(0.0, 1.0);
56 pub const ONE: Vec2 = Vec2::new(1.0, 1.0);
58
59 pub const PI: f32 = std::f32::consts::PI;
61 pub const HALF_PI: f32 = PI / 2.0;
63 pub const TAU: f32 = PI * 2.0;
65}
66
67pub trait Vec2Ext {
69 fn distance_to(self, other: Vec2) -> f32;
71 fn distance_squared_to(self, other: Vec2) -> f32;
73 fn angle_to(self, other: Vec2) -> f32;
75 fn rotated(self, angle: f32) -> Vec2;
77 fn move_toward(self, target: Vec2, max_delta: f32) -> Vec2;
79 fn reflect(self, normal: Vec2) -> Vec2;
81 fn projected_onto(self, onto: Vec2) -> Vec2;
83 fn perp(self) -> Vec2;
85 fn to_ivec(self) -> glam::IVec2;
87}
88
89impl Vec2Ext for Vec2 {
90 #[inline]
91 fn distance_to(self, other: Vec2) -> f32 {
92 (self - other).length()
93 }
94
95 #[inline]
96 fn distance_squared_to(self, other: Vec2) -> f32 {
97 (self - other).length_squared()
98 }
99
100 #[inline]
101 fn angle_to(self, other: Vec2) -> f32 {
102 let diff = other - self;
103 diff.y.atan2(diff.x)
104 }
105
106 #[inline]
107 fn rotated(self, angle: f32) -> Vec2 {
108 let (sin, cos) = angle.sin_cos();
109 Vec2::new(
110 self.x * cos - self.y * sin,
111 self.x * sin + self.y * cos,
112 )
113 }
114
115 #[inline]
116 fn move_toward(self, target: Vec2, max_delta: f32) -> Vec2 {
117 let diff = target - self;
118 let dist = diff.length();
119 if dist <= max_delta || dist < 1e-6 {
120 target
121 } else {
122 self + diff * (max_delta / dist)
123 }
124 }
125
126 #[inline]
127 fn reflect(self, normal: Vec2) -> Vec2 {
128 self - 2.0 * self.dot(normal) * normal
129 }
130
131 #[inline]
132 fn projected_onto(self, onto: Vec2) -> Vec2 {
133 onto * (self.dot(onto) / onto.length_squared())
134 }
135
136 #[inline]
137 fn perp(self) -> Vec2 {
138 Vec2::new(self.y, -self.x)
139 }
140
141 #[inline]
142 fn to_ivec(self) -> glam::IVec2 {
143 glam::IVec2::new(self.x as i32, self.y as i32)
144 }
145}
146
147pub trait FloatExt {
149 fn lerp(self, other: f32, t: f32) -> f32;
151 fn clamp(self, min: f32, max: f32) -> f32;
153 fn map_range(self, in_min: f32, in_max: f32, out_min: f32, out_max: f32) -> f32;
155 fn deadzone(self, deadzone: f32) -> f32;
157 fn snap(self, step: f32) -> f32;
159}
160
161impl FloatExt for f32 {
162 #[inline]
163 fn lerp(self, other: f32, t: f32) -> f32 {
164 self + (other - self) * t.clamp(0.0, 1.0)
165 }
166
167 #[inline]
168 fn clamp(self, min: f32, max: f32) -> f32 {
169 Self::clamp(self, min, max)
170 }
171
172 #[inline]
173 fn map_range(self, in_min: f32, in_max: f32, out_min: f32, out_max: f32) -> f32 {
174 (self - in_min) / (in_max - in_min) * (out_max - out_min) + out_min
175 }
176
177 #[inline]
178 fn deadzone(self, deadzone: f32) -> f32 {
179 if self.abs() < deadzone { 0.0 } else { self }
180 }
181
182 #[inline]
183 fn snap(self, step: f32) -> f32 {
184 (self / step).round() * step
185 }
186}