1use std::ops::{Add, Mul, Neg, Sub};
5
6#[derive(Debug, Clone, Copy, PartialEq, Default)]
8pub struct Vec2 {
9 pub x: f32,
10 pub y: f32,
11}
12
13impl Vec2 {
14 pub const ZERO: Self = Self::new(0.0, 0.0);
15
16 pub const fn new(x: f32, y: f32) -> Self {
17 Self { x, y }
18 }
19
20 pub fn dot(self, o: Self) -> f32 {
21 self.x * o.x + self.y * o.y
22 }
23
24 pub fn length(self) -> f32 {
25 self.dot(self).sqrt()
26 }
27
28 pub fn distance(self, o: Self) -> f32 {
29 (self - o).length()
30 }
31
32 pub fn normalize(self) -> Self {
34 let l = self.length();
35 if l < 1e-6 { self } else { self * (1.0 / l) }
36 }
37
38 pub fn lerp(self, to: Self, t: f32) -> Self {
39 self + (to - self) * t
40 }
41
42 pub fn perp(self) -> Self {
44 Self::new(-self.y, self.x)
45 }
46}
47
48impl Add for Vec2 {
49 type Output = Self;
50 fn add(self, o: Self) -> Self {
51 Self::new(self.x + o.x, self.y + o.y)
52 }
53}
54
55impl Sub for Vec2 {
56 type Output = Self;
57 fn sub(self, o: Self) -> Self {
58 Self::new(self.x - o.x, self.y - o.y)
59 }
60}
61
62impl Mul<f32> for Vec2 {
63 type Output = Self;
64 fn mul(self, k: f32) -> Self {
65 Self::new(self.x * k, self.y * k)
66 }
67}
68
69impl Neg for Vec2 {
70 type Output = Self;
71 fn neg(self) -> Self {
72 Self::new(-self.x, -self.y)
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Default)]
77pub struct Vec3 {
78 pub x: f32,
79 pub y: f32,
80 pub z: f32,
81}
82
83impl Vec3 {
84 pub const ZERO: Self = Self::new(0.0, 0.0, 0.0);
85 pub const ONE: Self = Self::new(1.0, 1.0, 1.0);
86
87 pub const fn new(x: f32, y: f32, z: f32) -> Self {
88 Self { x, y, z }
89 }
90
91 pub fn from_array(a: [f32; 3]) -> Self {
92 Self::new(a[0], a[1], a[2])
93 }
94
95 pub fn to_array(self) -> [f32; 3] {
96 [self.x, self.y, self.z]
97 }
98
99 pub fn dot(self, o: Self) -> f32 {
100 self.x * o.x + self.y * o.y + self.z * o.z
101 }
102
103 pub fn cross(self, o: Self) -> Self {
104 Self::new(self.y * o.z - self.z * o.y, self.z * o.x - self.x * o.z, self.x * o.y - self.y * o.x)
105 }
106
107 pub fn length(self) -> f32 {
108 self.dot(self).sqrt()
109 }
110
111 pub fn normalize(self) -> Self {
113 let l = self.length();
114 if l < 1e-6 { self } else { self * (1.0 / l) }
115 }
116
117 pub fn lerp(self, to: Self, t: f32) -> Self {
118 self + (to - self) * t
119 }
120
121 pub fn scale(self, o: Self) -> Self {
123 Self::new(self.x * o.x, self.y * o.y, self.z * o.z)
124 }
125}
126
127impl Add for Vec3 {
128 type Output = Self;
129 fn add(self, o: Self) -> Self {
130 Self::new(self.x + o.x, self.y + o.y, self.z + o.z)
131 }
132}
133
134impl Sub for Vec3 {
135 type Output = Self;
136 fn sub(self, o: Self) -> Self {
137 Self::new(self.x - o.x, self.y - o.y, self.z - o.z)
138 }
139}
140
141impl Mul<f32> for Vec3 {
142 type Output = Self;
143 fn mul(self, k: f32) -> Self {
144 Self::new(self.x * k, self.y * k, self.z * k)
145 }
146}
147
148impl Neg for Vec3 {
149 type Output = Self;
150 fn neg(self) -> Self {
151 Self::new(-self.x, -self.y, -self.z)
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq)]
157pub struct Mat4(pub [f32; 16]);
158
159impl Default for Mat4 {
160 fn default() -> Self {
161 Self::IDENTITY
162 }
163}
164
165impl Mat4 {
166 pub const IDENTITY: Self = Self([1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]);
167
168 fn at(&self, row: usize, col: usize) -> f32 {
169 self.0[col * 4 + row]
170 }
171
172 pub fn translation(v: Vec3) -> Self {
173 let mut m = Self::IDENTITY;
174 m.0[12] = v.x;
175 m.0[13] = v.y;
176 m.0[14] = v.z;
177 m
178 }
179
180 pub fn scaling(v: Vec3) -> Self {
181 let mut m = Self::IDENTITY;
182 m.0[0] = v.x;
183 m.0[5] = v.y;
184 m.0[10] = v.z;
185 m
186 }
187
188 pub fn rotation_x(a: f32) -> Self {
190 let (s, c) = a.sin_cos();
191 Self([1.0, 0.0, 0.0, 0.0, 0.0, c, s, 0.0, 0.0, -s, c, 0.0, 0.0, 0.0, 0.0, 1.0])
192 }
193
194 pub fn rotation_y(a: f32) -> Self {
195 let (s, c) = a.sin_cos();
196 Self([c, 0.0, -s, 0.0, 0.0, 1.0, 0.0, 0.0, s, 0.0, c, 0.0, 0.0, 0.0, 0.0, 1.0])
197 }
198
199 pub fn rotation_z(a: f32) -> Self {
200 let (s, c) = a.sin_cos();
201 Self([c, s, 0.0, 0.0, -s, c, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0])
202 }
203
204 pub fn rotation_zyx(r: Vec3) -> Self {
207 Self::rotation_z(r.z) * Self::rotation_y(r.y) * Self::rotation_x(r.x)
208 }
209
210 pub fn transform_point(&self, p: Vec3) -> Vec3 {
211 Vec3::new(
212 self.at(0, 0) * p.x + self.at(0, 1) * p.y + self.at(0, 2) * p.z + self.at(0, 3),
213 self.at(1, 0) * p.x + self.at(1, 1) * p.y + self.at(1, 2) * p.z + self.at(1, 3),
214 self.at(2, 0) * p.x + self.at(2, 1) * p.y + self.at(2, 2) * p.z + self.at(2, 3),
215 )
216 }
217
218 pub fn transform_dir(&self, d: Vec3) -> Vec3 {
220 Vec3::new(
221 self.at(0, 0) * d.x + self.at(0, 1) * d.y + self.at(0, 2) * d.z,
222 self.at(1, 0) * d.x + self.at(1, 1) * d.y + self.at(1, 2) * d.z,
223 self.at(2, 0) * d.x + self.at(2, 1) * d.y + self.at(2, 2) * d.z,
224 )
225 }
226
227 pub fn transform_normal(&self, n: Vec3) -> Vec3 {
230 self.transform_dir(n).normalize()
231 }
232}
233
234impl Mul for Mat4 {
235 type Output = Self;
236 fn mul(self, o: Self) -> Self {
237 let mut r = [0.0; 16];
238 for col in 0..4 {
239 for row in 0..4 {
240 r[col * 4 + row] = (0..4).map(|k| self.at(row, k) * o.at(k, col)).sum();
241 }
242 }
243 Self(r)
244 }
245}
246
247pub fn rad(deg: Vec3) -> Vec3 {
249 deg * (std::f32::consts::PI / 180.0)
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 fn close(a: Vec3, b: Vec3) -> bool {
257 (a - b).length() < 1e-5
258 }
259
260 #[test]
261 fn rotations_are_right_handed() {
262 let half = std::f32::consts::FRAC_PI_2;
263 assert!(close(Mat4::rotation_x(half).transform_point(Vec3::new(0.0, 1.0, 0.0)), Vec3::new(0.0, 0.0, 1.0)));
264 assert!(close(Mat4::rotation_y(half).transform_point(Vec3::new(0.0, 0.0, 1.0)), Vec3::new(1.0, 0.0, 0.0)));
265 assert!(close(Mat4::rotation_z(half).transform_point(Vec3::new(1.0, 0.0, 0.0)), Vec3::new(0.0, 1.0, 0.0)));
266 }
267
268 #[test]
269 fn moving_comes_after_turning() {
270 let m = Mat4::translation(Vec3::new(5.0, 0.0, 0.0)) * Mat4::rotation_zyx(Vec3::new(0.0, 0.0, std::f32::consts::FRAC_PI_2)) * Mat4::scaling(Vec3::ONE);
271 assert!(close(m.transform_point(Vec3::new(1.0, 0.0, 0.0)), Vec3::new(5.0, 1.0, 0.0)));
272 }
273}