radiant_utils/math/
mat4.rs

1use prelude::*;
2use super::{Vec2, Vec3, Rect, Vector, Matrix};
3use super::matrix::Mat4 as Mat4Type;
4
5/// A 4x4 matrix.
6#[derive(Copy, Clone)]
7#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))]
8pub struct Mat4<T = f32>(pub [ [ T; 4 ]; 4 ]);
9
10impl<T> Mat4<T> where T: Float {
11    /// Creates a zero matrix.
12    pub fn new() -> Mat4<T> {
13        Mat4([ [ T::zero(); 4]; 4 ])
14    }
15    /// Creates an identity matrix.
16    pub fn identity() -> Mat4<T> {
17        Mat4([
18            [ T::one(),  T::zero(), T::zero(), T::zero()  ],
19            [ T::zero(), T::one(),  T::zero(), T::zero(), ],
20            [ T::zero(), T::zero(), T::one(),  T::zero(), ],
21            [ T::zero(), T::zero(), T::zero(), T::one(),  ],
22        ])
23    }
24    /// Creates viewport matrix mapping viewport top left to (0.0, 0.0) and bottom right to (width, height)
25    pub fn viewport(width: T, height: T) -> Mat4<T> {
26        //const TWO: T = T::one() + T::one(); // TODO: compiler whining
27        #[allow(non_snake_case)]
28        let TWO = T::one() + T::one();
29        Mat4([
30            [ TWO/width, T::zero(), T::zero(), T::zero() ],
31            [ T::zero(), -TWO/height, T::zero(), T::zero() ],
32            [ T::zero(), T::zero(), T::one(), T::zero() ],
33            [ -T::one(), T::one(), T::zero(), T::one() ],
34        ])
35    }
36    /// Creates a look-at matrix with the given eye position, target position, and up-vector.
37    pub fn look_at<E, C, U>(eye: E, target: C, up: U) -> Mat4<T> where E: Vector<T>, C: Vector<T>, U: Vector<T> {
38
39        let eye = eye.as_vec3(T::zero());
40        let target = target.as_vec3(T::zero());
41        let up = up.as_vec3(T::zero());
42        let zero = T::zero();
43        let one = T::one();
44
45        if (eye.0 - target.0).abs() < T::epsilon() && (eye.1 - target.1).abs() < T::epsilon() && (eye.2 - target.2).abs() < T::epsilon() {
46            return Self::identity();
47        }
48
49        let mut z0 = eye.0 - target.0;
50        let mut z1 = eye.1 - target.1;
51        let mut z2 = eye.2 - target.2;
52
53        let recip_len = (z0 * z0 + z1 * z1 + z2 * z2).sqrt().recip();
54        z0 = z0 * recip_len;
55        z1 = z1 * recip_len;
56        z2 = z2 * recip_len;
57
58        let mut x0 = up.1 * z2 - up.2 * z1;
59        let mut x1 = up.2 * z0 - up.0 * z2;
60        let mut x2 = up.0 * z1 - up.1 * z0;
61        let len = (x0 * x0 + x1 * x1 + x2 * x2).sqrt();
62
63        if len < T::epsilon() {
64            x0 = zero;
65            x1 = zero;
66            x2 = zero;
67        } else {
68            let recip_len = len.recip();
69            x0 = x0 * recip_len;
70            x1 = x1 * recip_len;
71            x2 = x2 * recip_len;
72        }
73
74        let mut y0 = z1 * x2 - z2 * x1;
75        let mut y1 = z2 * x0 - z0 * x2;
76        let mut y2 = z0 * x1 - z1 * x0;
77        let len = (y0 * y0 + y1 * y1 + y2 * y2).sqrt();
78
79        if len < T::epsilon() {
80            y0 = zero;
81            y1 = zero;
82            y2 = zero;
83        } else {
84            let recip_len = len.recip();
85            y0 = y0 * recip_len;
86            y1 = y1 * recip_len;
87            y2 = y2 * recip_len;
88        }
89
90        Mat4([
91            [ x0, y0, z0, zero ],
92            [ x1, y1, z1, zero ],
93            [ x2, y2, z2, zero ],
94            [
95                -(x0 * eye.0 + x1 * eye.1 + x2 * eye.2),
96                -(y0 * eye.0 + y1 * eye.1 + y2 * eye.2),
97                -(z0 * eye.0 + z1 * eye.1 + z2 * eye.2),
98                one
99            ]
100        ])
101    }
102    /// Creates an orthogonal projection matrix with the given rectangular bounds at the
103    /// near and far clipping plane.
104    pub fn ortho<R>(rectangle: R, near: T, far: T) -> Mat4<T> where Rect<T>: From<R> {
105        let ((left, top), (right, bottom)) = rectangle.into();
106        let two = T::one() + T::one();
107        let zero = T::zero();
108        let lr = T::one() / (left - right);
109        let bt = T::one() / (bottom - top);
110        let nf = T::one() / (near - far);
111        Mat4([
112            [ -two * lr,            zero,               zero,               zero     ],
113            [ zero,                 -two * bt,          zero,               zero     ],
114            [ zero,                 zero,               two * nf,           zero     ],
115            [ (left + right) * lr, (top + bottom) * bt, (far + near) * nf,  T::one() ],
116        ])
117    }
118    /// Creates a frustum projection matrix with the given rectangular bounds at the
119    /// near clipping plane and rectangle * (far / near) at the far clipping plane.
120    pub fn frustum<R>(rectangle: R, near: T, far: T) -> Mat4<T> where Rect<T>: From<R> {
121        let ((left, top), (right, bottom)) = rectangle.into();
122        let two = T::one() + T::one();
123        let zero = T::zero();
124        let rl = (right - left).recip();
125        let tb = (top - bottom).recip();
126        let nf = (near - far).recip();
127        Mat4([
128            [ (near * two) * rl, zero, zero, zero ],
129            [ zero, (near * two) * tb, zero, zero ],
130            [ (right + left) * rl, (top + bottom) * tb, (far + near) * nf, -T::one() ],
131            [ zero, zero, (far * near * two) * nf, zero ]
132        ])
133    }
134    /// Creates a perspective projection matrix with the given field of view, aspect and
135    /// near/far clipping planes.
136    pub fn perspective(fov_y: T, aspect: T, near: T, far: T) -> Mat4<T> {
137        let two = T::one() + T::one();
138        let f = (fov_y / two).tan().recip();
139        let nf = (near - far).recip();
140        Mat4([
141            [ f / aspect,   T::zero(),  T::zero(),              T::zero() ],
142            [ T::zero(),    f,          T::zero(),              T::zero() ],
143            [ T::zero(),    T::zero(),  (far + near) * nf,      -T::one() ],
144            [ T::zero(),    T::zero(),  two * far * near * nf,  T::zero() ],
145        ])
146    }
147}
148
149/// 4x4 Matrices.
150impl<T> Matrix<T> for Mat4<T> where T: Float {
151    fn set<M>(self: &mut Self, other: M) -> &mut Self where Mat4Type<T>: From<M> {
152        self.0 = other.into();
153        self
154    }
155    fn translate<V>(self: &mut Self, translation_vector: V) -> &mut Self where V: Vector<T> {
156        self.0.translate(translation_vector);
157        self
158    }
159    fn scale<V>(self: &mut Self, scaling_vector: V) -> &mut Self where V: Vector<T> {
160        self.0.scale(scaling_vector);
161        self
162    }
163    fn scale_at<P, V>(self: &mut Self, position: P, scaling_vector: V) -> &mut Self where P: Vector<T>, V: Vector<T> {
164        self.0.scale_at(position, scaling_vector);
165        self
166    }
167    fn rotate(self: &mut Self, radians: T) -> &mut Self {
168        self.0.rotate(radians);
169        self
170    }
171    fn rotate_at<P>(self: &mut Self, position: P, radians: T) -> &mut Self where P: Vector<T> {
172        self.0.rotate_at(position, radians);
173        self
174    }
175    fn rotate_axis<V>(self: &mut Self, radians: T, axis: V) -> &mut Self where Vec3<T>: From<V> {
176        self.0.rotate_axis(radians, axis);
177        self
178    }
179    fn rotate_axis_at<P, V>(self: &mut Self, position: P, radians: T, axis: V) -> &mut Self where P: Vector<T>, Vec3<T>: From<V> {
180        self.0.rotate_axis_at(position, radians, axis);
181        self
182    }
183    fn get_rotation(self: &Self) -> Self {
184        let rot = self.0.get_rotation();
185        Mat4(rot)
186    }
187    fn get_translation(self: &Self) -> Vec3<T> {
188        self.0.get_translation()
189    }
190    fn get_scale(self: &Self) -> Vec3<T> {
191        self.0.get_scale()
192    }
193    fn get_euler(self: &Self) -> Vec3<T> {
194        self.0.get_euler()
195    }
196}
197
198// from array
199
200impl<T> From<Mat4Type<T>> for Mat4<T> where T: Copy {
201    fn from(source: Mat4Type<T>) -> Self {
202        Mat4(source)
203    }
204}
205
206// Default
207
208impl<T> Default for Mat4<T> where T: Float {
209    fn default() -> Self {
210        Mat4::new()
211    }
212}
213
214// operators
215
216impl<T> Mul<T> for Mat4<T> where T: Float {
217    type Output = Mat4<T>;
218    fn mul(self, other: T) -> Mat4<T> {
219        let a = self.0;
220        let b = other;
221        Mat4([
222            [ a[0][0] * b, a[0][1] * b, a[0][2] * b, a[0][3] * b ],
223            [ a[1][0] * b, a[1][1] * b, a[1][2] * b, a[1][3] * b ],
224            [ a[2][0] * b, a[2][1] * b, a[2][2] * b, a[2][3] * b ],
225            [ a[3][0] * b, a[3][1] * b, a[3][2] * b, a[3][3] * b ],
226        ])
227    }
228}
229
230impl<T> Mul<Vec2<T>> for Mat4<T> where T: Float {
231    type Output = Vec2<T>;
232    /// Multiplies the matrix with given vector operand, using 0 as z-component and 1 as w-component of the vector.
233    fn mul(self, other: Vec2<T>) -> Vec2<T> {
234        let mat = self.0;
235        Vec2(
236            other.0 * mat[0][0] + other.1 * mat[1][0] + mat[2][0] + mat[3][0],
237            other.0 * mat[0][1] + other.1 * mat[1][1] + mat[2][0] + mat[3][1]
238        )
239    }
240}
241
242impl<T> Mul<Vec3<T>> for Mat4<T> where T: Float {
243    type Output = Vec3<T>;
244    /// Multiplies the matrix with given vector operand using 1 as w-component of the vector.
245    fn mul(self, other: Vec3<T>) -> Vec3<T> {
246        let mat = self.0;
247        Vec3::<T>(
248            other.0 * mat[0][0] + other.1 * mat[1][0] + other.2 * mat[2][0] + mat[3][0],
249            other.0 * mat[0][1] + other.1 * mat[1][1] + other.2 * mat[2][1] + mat[3][1],
250            other.0 * mat[0][2] + other.1 * mat[1][2] + other.2 * mat[2][2] + mat[3][2]
251        )
252    }
253}
254
255impl<T> Mul<Mat4<T>> for Mat4<T> where T: Float {
256    type Output = Mat4<T>;
257    fn mul(self, other: Mat4<T>) -> Mat4<T> {
258        let a = self.0;
259        let b = other.0;
260        Mat4([
261            [
262                a[0][0]*b[0][0] + a[1][0]*b[0][1] + a[2][0]*b[0][2] + a[3][0]*b[0][3],
263                a[0][1]*b[0][0] + a[1][1]*b[0][1] + a[2][1]*b[0][2] + a[3][1]*b[0][3],
264                a[0][2]*b[0][0] + a[1][2]*b[0][1] + a[2][2]*b[0][2] + a[3][2]*b[0][3],
265                a[0][3]*b[0][0] + a[1][3]*b[0][1] + a[2][3]*b[0][2] + a[3][3]*b[0][3],
266            ],
267            [
268                a[0][0]*b[1][0] + a[1][0]*b[1][1] + a[2][0]*b[1][2] + a[3][0]*b[1][3],
269                a[0][1]*b[1][0] + a[1][1]*b[1][1] + a[2][1]*b[1][2] + a[3][1]*b[1][3],
270                a[0][2]*b[1][0] + a[1][2]*b[1][1] + a[2][2]*b[1][2] + a[3][2]*b[1][3],
271                a[0][3]*b[1][0] + a[1][3]*b[1][1] + a[2][3]*b[1][2] + a[3][3]*b[1][3],
272            ],
273            [
274                a[0][0]*b[2][0] + a[1][0]*b[2][1] + a[2][0]*b[2][2] + a[3][0]*b[2][3],
275                a[0][1]*b[2][0] + a[1][1]*b[2][1] + a[2][1]*b[2][2] + a[3][1]*b[2][3],
276                a[0][2]*b[2][0] + a[1][2]*b[2][1] + a[2][2]*b[2][2] + a[3][2]*b[2][3],
277                a[0][3]*b[2][0] + a[1][3]*b[2][1] + a[2][3]*b[2][2] + a[3][3]*b[2][3],
278            ],
279            [
280                a[0][0]*b[3][0] + a[1][0]*b[3][1] + a[2][0]*b[3][2] + a[3][0]*b[3][3],
281                a[0][1]*b[3][0] + a[1][1]*b[3][1] + a[2][1]*b[3][2] + a[3][1]*b[3][3],
282                a[0][2]*b[3][0] + a[1][2]*b[3][1] + a[2][2]*b[3][2] + a[3][2]*b[3][3],
283                a[0][3]*b[3][0] + a[1][3]*b[3][1] + a[2][3]*b[3][2] + a[3][3]*b[3][3],
284            ],
285        ])
286    }
287}
288
289// as radiant uniform
290
291#[cfg(feature = "uniforms")]
292use radiant_rs::{Uniform, AsUniform};
293
294#[cfg(feature = "uniforms")]
295impl AsUniform for Mat4<f32> {
296    fn as_uniform(&self) -> Uniform {
297        let a = &self.0;
298        Uniform::Mat4([
299            [ a[0][0], a[0][1], a[0][2], a[0][3] ],
300            [ a[1][0], a[1][1], a[1][2], a[1][3] ],
301            [ a[2][0], a[2][1], a[2][2], a[2][3] ],
302            [ a[3][0], a[3][1], a[3][2], a[3][3] ],
303        ])
304    }
305}
306
307#[cfg(feature = "uniforms")]
308impl AsUniform for Mat4<f64> {
309    fn as_uniform(&self) -> Uniform {
310        let a = &self.0;
311        Uniform::DoubleMat4([
312            [ a[0][0], a[0][1], a[0][2], a[0][3] ],
313            [ a[1][0], a[1][1], a[1][2], a[1][3] ],
314            [ a[2][0], a[2][1], a[2][2], a[2][3] ],
315            [ a[3][0], a[3][1], a[3][2], a[3][3] ],
316        ])
317    }
318}
319
320// debug print
321
322impl<T> Debug for Mat4<T> where T: Debug {
323    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
324        let a = &self.0;
325        write!(f, "Mat4(
326  {:?}, {:?}, {:?}, {:?}
327  {:?}, {:?}, {:?}, {:?}
328  {:?}, {:?}, {:?}, {:?}
329  {:?}, {:?}, {:?}, {:?}
330)",
331a[0][0], a[0][1], a[0][2], a[0][3],
332a[1][0], a[1][1], a[1][2], a[1][3],
333a[2][0], a[2][1], a[2][2], a[2][3],
334a[3][0], a[3][1], a[3][2], a[3][3])
335    }
336}