1use auto_ops::impl_op_ex;
2
3use crate::{Quaternion, Vec3, Vec4};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[repr(C)]
13pub struct Mat4 {
14 pub values: [f32; 4 * 4],
15}
16
17impl Default for Mat4 {
18 fn default() -> Self {
20 Self::identity()
21 }
22}
23
24#[cfg(not(feature = "mat-row-major"))]
25const fn cr(c: usize, r: usize) -> usize {
26 r + c * 4
27}
28#[cfg(feature = "mat-row-major")]
29const fn cr(c: usize, r: usize) -> usize {
30 r * 4 + c
31}
32
33impl Mat4 {
34 pub const fn identity() -> Self {
36 Self {
37 values: [
38 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,
39 ],
40 }
41 }
42
43 pub const fn translate(t: Vec3) -> Self {
45 let mut res = Self::identity();
46
47 res.values[cr(3, 0)] = t.x;
48 res.values[cr(3, 1)] = t.y;
49 res.values[cr(3, 2)] = t.z;
50
51 res
52 }
53
54 pub fn rotate(r: Quaternion) -> Self {
56 let mut res = Self::identity();
57
58 let right = r.right();
59 let up = r.up();
60 let fwd = r.forward();
61
62 res.values[cr(0, 0)] = right.x;
63 res.values[cr(0, 1)] = right.y;
64 res.values[cr(0, 2)] = right.z;
65
66 res.values[cr(1, 0)] = up.x;
67 res.values[cr(1, 1)] = up.y;
68 res.values[cr(1, 2)] = up.z;
69
70 res.values[cr(2, 0)] = fwd.x;
71 res.values[cr(2, 1)] = fwd.y;
72 res.values[cr(2, 2)] = fwd.z;
73
74 res
75 }
76
77 pub const fn scale(s: Vec3) -> Self {
79 let mut res = Self::identity();
80
81 res.values[cr(0, 0)] = s.x;
82 res.values[cr(1, 1)] = s.y;
83 res.values[cr(2, 2)] = s.z;
84
85 res
86 }
87
88 pub fn local_to_world(t: Vec3, r: Quaternion, s: Vec3) -> Self {
97 Self::translate(t) * Self::rotate(r) * Self::scale(s)
98 }
99
100 pub fn world_to_local(t: Vec3, r: Quaternion, s: Vec3) -> Self {
104 Self::scale(1.0 / s) * Self::rotate(-r) * Self::translate(-t)
105 }
106
107 pub fn orthographic_vulkan(
110 left: f32,
111 right: f32,
112 bottom: f32,
113 top: f32,
114 near: f32,
115 far: f32,
116 ) -> Self {
117 let mut res = Self::identity();
118
119 let a = 2.0 / (right - left);
120 let b = (-left - right) / (right - left);
121 let c = 2.0 / (top - bottom);
122 let d = (-bottom - top) / (top - bottom);
123 let e = 1.0 / (far - near);
124 let f = -near / (far - near);
125
126 res.values[cr(0, 0)] = a;
127 res.values[cr(3, 0)] = b;
128
129 res.values[cr(1, 1)] = c;
130 res.values[cr(3, 1)] = d;
131
132 res.values[cr(2, 2)] = e;
133 res.values[cr(3, 2)] = f;
134
135 res
136 }
137
138 pub fn orthographic_opengl(
141 left: f32,
142 right: f32,
143 bottom: f32,
144 top: f32,
145 near: f32,
146 far: f32,
147 ) -> Self {
148 let mut res = Self::identity();
149
150 let a = 2.0 / (right - left);
151 let b = (-left - right) / (right - left);
152 let c = 2.0 / (top - bottom);
153 let d = (-bottom - top) / (top - bottom);
154 let e = 2.0 / (far - near);
155 let f = (-near - far) / (far - near);
156
157 res.values[cr(0, 0)] = a;
158 res.values[cr(3, 0)] = b;
159
160 res.values[cr(1, 1)] = c;
161 res.values[cr(3, 1)] = d;
162
163 res.values[cr(2, 2)] = e;
164 res.values[cr(3, 2)] = f;
165
166 res
167 }
168
169 pub fn inverse_orthographic_vulkan(
175 left: f32,
176 right: f32,
177 bottom: f32,
178 top: f32,
179 near: f32,
180 far: f32,
181 ) -> Self {
182 let mut res = Self::identity();
183
184 let a = 2.0 * (right - left);
185 let b = (-left - right) / (right - left);
186 let c = 2.0 * (top - bottom);
187 let d = (-bottom - top) / (top - bottom);
188 let e = 1.0 / (far - near);
189 let f = -near / (far - near);
190
191 res.values[cr(0, 0)] = 1.0 / a;
192 res.values[cr(3, 0)] = -b / a;
193
194 res.values[cr(1, 1)] = 1.0 / c;
195 res.values[cr(3, 1)] = -d / c;
196
197 res.values[cr(2, 2)] = 1.0 / e;
198 res.values[cr(3, 2)] = -f / e;
199
200 res
201 }
202
203 pub fn inverse_orthographic_opengl(
209 left: f32,
210 right: f32,
211 bottom: f32,
212 top: f32,
213 near: f32,
214 far: f32,
215 ) -> Self {
216 let mut res = Self::identity();
217
218 let a = 2.0 * (right - left);
219 let b = (-left - right) / (right - left);
220 let c = 2.0 * (top - bottom);
221 let d = (-bottom - top) / (top - bottom);
222 let e = 2.0 * (far - near);
223 let f = (-near - far) / (far - near);
224
225 res.values[cr(0, 0)] = 1.0 / a;
226 res.values[cr(3, 0)] = -b / a;
227
228 res.values[cr(1, 1)] = 1.0 / c;
229 res.values[cr(3, 1)] = -d / c;
230
231 res.values[cr(2, 2)] = 1.0 / e;
232 res.values[cr(3, 2)] = -f / e;
233
234 res
235 }
236
237 pub fn perspective_vulkan(fov_rad: f32, near: f32, far: f32, aspect: f32) -> Self {
240 let mut res = Self::identity();
241 let thfov = (fov_rad * 0.5).tan();
242
243 res.values[cr(0, 0)] = 1.0 / (thfov * aspect);
244 res.values[cr(1, 1)] = 1.0 / thfov;
245
246 res.values[cr(2, 2)] = far / (far - near);
247 res.values[cr(3, 2)] = (-far * near) / (far - near);
248
249 res.values[cr(2, 3)] = 1.0;
250 res.values[cr(3, 3)] = 0.0;
251
252 res
253 }
254
255 pub fn perspective_opengl(fov_rad: f32, near: f32, far: f32, aspect: f32) -> Self {
258 let mut res = Self::identity();
259 let thfov = (fov_rad * 0.5).tan();
260
261 res.values[cr(0, 0)] = 1.0 / (thfov * aspect);
262 res.values[cr(1, 1)] = 1.0 / thfov;
263
264 res.values[cr(2, 2)] = (far + near) / (far - near);
265 res.values[cr(3, 2)] = (-2.0 * far * near) / (far - near);
266
267 res.values[cr(2, 3)] = 1.0;
268 res.values[cr(3, 3)] = 0.0;
269
270 res
271 }
272
273 pub fn inverse_perspective_vulkan(fov_rad: f32, near: f32, far: f32, aspect: f32) -> Self {
284 let mut res = Self::identity();
285
286 let thfov = (fov_rad * 0.5).tan();
287 let c = far / (far - near);
288 let d = (-far * near) / (far - near);
289
290 res.values[cr(0, 0)] = thfov * aspect;
291 res.values[cr(1, 1)] = thfov;
292
293 res.values[cr(3, 2)] = 1.0;
294
295 res.values[cr(2, 2)] = 0.0;
296 res.values[cr(2, 3)] = 1.0 / d;
297 res.values[cr(3, 3)] = -c / d;
298
299 res
300 }
301
302 pub fn inverse_perspective_opengl(fov_rad: f32, near: f32, far: f32, aspect: f32) -> Self {
313 let mut res = Self::identity();
314
315 let thfov = (fov_rad * 0.5).tan();
316 let c = (far + near) / (far - near);
317 let d = (-2.0 * far * near) / (far - near);
318
319 res.values[cr(0, 0)] = thfov * aspect;
320 res.values[cr(1, 1)] = thfov;
321
322 res.values[cr(3, 2)] = 1.0;
323
324 res.values[cr(2, 2)] = 0.0;
325 res.values[cr(2, 3)] = 1.0 / d;
326 res.values[cr(3, 3)] = -c / d;
327
328 res
329 }
330
331 pub const fn get(&self, column: usize, row: usize) -> f32 {
333 self.values[cr(column, row)]
334 }
335
336 pub fn set(&mut self, column: usize, row: usize, val: f32) {
338 self.values[cr(column, row)] = val;
339 }
340
341 #[must_use]
343 pub fn transposed(&self) -> Mat4 {
344 let mut res = Mat4::identity();
345
346 for c in 0..4 {
347 for r in 0..4 {
348 res.values[cr(r, c)] = self.values[cr(c, r)];
349 }
350 }
351
352 res
353 }
354
355 pub fn as_slice(&self) -> &[f32] {
357 &self.values
358 }
359
360 pub fn as_mut_slice(&mut self) -> &mut [f32] {
362 &mut self.values
363 }
364
365 pub fn as_ptr(&self) -> *const f32 {
367 self.values.as_ptr()
368 }
369
370 pub fn as_mut_ptr(&mut self) -> *mut f32 {
372 self.values.as_mut_ptr()
373 }
374}
375
376impl_op_ex!(*|a: &Mat4, b: &Mat4| -> Mat4 {
377 let mut res = Mat4::identity();
378
379 for r in 0..4 {
380 for c in 0..4 {
381 res.values[cr(c, r)] = a.values[cr(0, r)] * b.values[cr(c, 0)]
382 + a.values[cr(1, r)] * b.values[cr(c, 1)]
383 + a.values[cr(2, r)] * b.values[cr(c, 2)]
384 + a.values[cr(3, r)] * b.values[cr(c, 3)];
385 }
386 }
387
388 res
389});
390
391impl_op_ex!(*|a: &Mat4, b: &Vec4| -> Vec4 {
392 Vec4 {
393 x: a.values[cr(0, 0)] * b.x
394 + a.values[cr(1, 0)] * b.y
395 + a.values[cr(2, 0)] * b.z
396 + a.values[cr(3, 0)] * b.w,
397 y: a.values[cr(0, 1)] * b.x
398 + a.values[cr(1, 1)] * b.y
399 + a.values[cr(2, 1)] * b.z
400 + a.values[cr(3, 1)] * b.w,
401 z: a.values[cr(0, 2)] * b.x
402 + a.values[cr(1, 2)] * b.y
403 + a.values[cr(2, 2)] * b.z
404 + a.values[cr(3, 2)] * b.w,
405 w: a.values[cr(0, 3)] * b.x
406 + a.values[cr(1, 3)] * b.y
407 + a.values[cr(2, 3)] * b.z
408 + a.values[cr(3, 3)] * b.w,
409 }
410});
411
412impl_op_ex!(*|a: &Mat4, b: &Vec3| -> Vec3 {
413 Vec3 {
414 x: a.values[cr(0, 0)] * b.x + a.values[cr(1, 0)] * b.y + a.values[cr(2, 0)] * b.z,
415 y: a.values[cr(0, 1)] * b.x + a.values[cr(1, 1)] * b.y + a.values[cr(2, 1)] * b.z,
416 z: a.values[cr(0, 2)] * b.x + a.values[cr(1, 2)] * b.y + a.values[cr(2, 2)] * b.z,
417 }
418});
419
420impl From<[f32; 16]> for Mat4 {
421 fn from(d: [f32; 16]) -> Self {
422 Self { values: d }
423 }
424}
425
426impl From<[[f32; 4]; 4]> for Mat4 {
427 fn from(d: [[f32; 4]; 4]) -> Self {
428 Self {
429 values: [
430 d[0][0], d[0][1], d[0][2], d[0][3], d[1][0], d[1][1], d[1][2], d[1][3], d[2][0],
431 d[2][1], d[2][2], d[2][3], d[3][0], d[3][1], d[3][2], d[3][3],
432 ],
433 }
434 }
435}
436
437impl std::ops::Index<(usize, usize)> for Mat4 {
438 type Output = f32;
439
440 fn index(&self, (c, r): (usize, usize)) -> &Self::Output {
441 &self.values[cr(c, r)]
442 }
443}
444
445impl std::ops::IndexMut<(usize, usize)> for Mat4 {
446 fn index_mut(&mut self, (c, r): (usize, usize)) -> &mut Self::Output {
447 &mut self.values[cr(c, r)]
448 }
449}