graphene/
matrix.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, ops};
4
5use glib::translate::*;
6
7use crate::{ffi, Matrix, Point, Point3D, Vec3, Vec4};
8
9impl Matrix {
10    #[doc(alias = "graphene_matrix_init_from_2d")]
11    #[doc(alias = "init_from_2d")]
12    pub fn from_2d(xx: f64, yx: f64, xy: f64, yy: f64, x_0: f64, y_0: f64) -> Self {
13        assert_initialized_main_thread!();
14        unsafe {
15            let mut mat = Self::uninitialized();
16            ffi::graphene_matrix_init_from_2d(mat.to_glib_none_mut().0, xx, yx, xy, yy, x_0, y_0);
17            mat
18        }
19    }
20
21    #[doc(alias = "graphene_matrix_init_from_float")]
22    #[doc(alias = "init_from_float")]
23    pub fn from_float(v: [f32; 16]) -> Self {
24        assert_initialized_main_thread!();
25        unsafe {
26            let mut mat = Self::uninitialized();
27            ffi::graphene_matrix_init_from_float(mat.to_glib_none_mut().0, v.as_ptr() as *const _);
28            mat
29        }
30    }
31
32    #[doc(alias = "graphene_matrix_init_from_vec4")]
33    #[doc(alias = "init_from_vec4")]
34    pub fn from_vec4(v0: &Vec4, v1: &Vec4, v2: &Vec4, v3: &Vec4) -> Self {
35        assert_initialized_main_thread!();
36        unsafe {
37            let mut mat = Self::uninitialized();
38            ffi::graphene_matrix_init_from_vec4(
39                mat.to_glib_none_mut().0,
40                v0.to_glib_none().0,
41                v1.to_glib_none().0,
42                v2.to_glib_none().0,
43                v3.to_glib_none().0,
44            );
45            mat
46        }
47    }
48
49    #[doc(alias = "graphene_matrix_init_frustum")]
50    #[doc(alias = "init_frustum")]
51    pub fn new_frustum(
52        left: f32,
53        right: f32,
54        bottom: f32,
55        top: f32,
56        z_near: f32,
57        z_far: f32,
58    ) -> Self {
59        assert_initialized_main_thread!();
60        unsafe {
61            let mut mat = Self::uninitialized();
62            ffi::graphene_matrix_init_frustum(
63                mat.to_glib_none_mut().0,
64                left,
65                right,
66                bottom,
67                top,
68                z_near,
69                z_far,
70            );
71            mat
72        }
73    }
74
75    #[doc(alias = "graphene_matrix_init_identity")]
76    #[doc(alias = "init_identity")]
77    pub fn new_identity() -> Self {
78        assert_initialized_main_thread!();
79        unsafe {
80            let mut mat = Self::uninitialized();
81            ffi::graphene_matrix_init_identity(mat.to_glib_none_mut().0);
82            mat
83        }
84    }
85
86    #[doc(alias = "graphene_matrix_init_look_at")]
87    #[doc(alias = "init_look_at")]
88    pub fn new_look_at(eye: &Vec3, center: &Vec3, up: &Vec3) -> Self {
89        assert_initialized_main_thread!();
90        unsafe {
91            let mut mat = Self::uninitialized();
92            ffi::graphene_matrix_init_look_at(
93                mat.to_glib_none_mut().0,
94                eye.to_glib_none().0,
95                center.to_glib_none().0,
96                up.to_glib_none().0,
97            );
98            mat
99        }
100    }
101
102    #[doc(alias = "graphene_matrix_init_ortho")]
103    #[doc(alias = "init_ortho")]
104    pub fn new_ortho(
105        left: f32,
106        right: f32,
107        top: f32,
108        bottom: f32,
109        z_near: f32,
110        z_far: f32,
111    ) -> Self {
112        assert_initialized_main_thread!();
113        unsafe {
114            let mut mat = Self::uninitialized();
115            ffi::graphene_matrix_init_ortho(
116                mat.to_glib_none_mut().0,
117                left,
118                right,
119                top,
120                bottom,
121                z_near,
122                z_far,
123            );
124            mat
125        }
126    }
127
128    #[doc(alias = "graphene_matrix_init_perspective")]
129    #[doc(alias = "init_perspective")]
130    pub fn new_perspective(fovy: f32, aspect: f32, z_near: f32, z_far: f32) -> Self {
131        assert_initialized_main_thread!();
132        unsafe {
133            let mut mat = Self::uninitialized();
134            ffi::graphene_matrix_init_perspective(
135                mat.to_glib_none_mut().0,
136                fovy,
137                aspect,
138                z_near,
139                z_far,
140            );
141            mat
142        }
143    }
144
145    #[doc(alias = "graphene_matrix_init_rotate")]
146    #[doc(alias = "init_rotate")]
147    pub fn new_rotate(angle: f32, axis: &Vec3) -> Self {
148        assert_initialized_main_thread!();
149        unsafe {
150            let mut mat = Self::uninitialized();
151            ffi::graphene_matrix_init_rotate(
152                mat.to_glib_none_mut().0,
153                angle,
154                axis.to_glib_none().0,
155            );
156            mat
157        }
158    }
159
160    #[doc(alias = "graphene_matrix_init_scale")]
161    #[doc(alias = "init_scale")]
162    pub fn new_scale(x: f32, y: f32, z: f32) -> Self {
163        assert_initialized_main_thread!();
164        unsafe {
165            let mut mat = Self::uninitialized();
166            ffi::graphene_matrix_init_scale(mat.to_glib_none_mut().0, x, y, z);
167            mat
168        }
169    }
170
171    #[doc(alias = "graphene_matrix_init_skew")]
172    #[doc(alias = "init_skew")]
173    pub fn new_skew(x_skew: f32, y_skew: f32) -> Self {
174        assert_initialized_main_thread!();
175        unsafe {
176            let mut mat = Self::uninitialized();
177            ffi::graphene_matrix_init_skew(mat.to_glib_none_mut().0, x_skew, y_skew);
178            mat
179        }
180    }
181
182    #[doc(alias = "graphene_matrix_init_translate")]
183    #[doc(alias = "init_translate")]
184    pub fn new_translate(p: &Point3D) -> Self {
185        assert_initialized_main_thread!();
186        unsafe {
187            let mut mat = Self::uninitialized();
188            ffi::graphene_matrix_init_translate(mat.to_glib_none_mut().0, p.to_glib_none().0);
189            mat
190        }
191    }
192
193    #[doc(alias = "graphene_matrix_to_float")]
194    pub fn to_float(&self) -> [f32; 16] {
195        unsafe {
196            let mut out = std::mem::MaybeUninit::uninit();
197            ffi::graphene_matrix_to_float(self.to_glib_none().0, out.as_mut_ptr());
198            out.assume_init()
199        }
200    }
201
202    #[inline]
203    pub fn values(&self) -> &[[f32; 4]; 4] {
204        unsafe { &*(&self.inner.value as *const ffi::graphene_simd4x4f_t as *const [[f32; 4]; 4]) }
205    }
206}
207
208impl fmt::Debug for Matrix {
209    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210        f.debug_struct("Matrix")
211            .field("values", &self.values())
212            .finish()
213    }
214}
215
216impl Default for Matrix {
217    fn default() -> Self {
218        Self::new_identity()
219    }
220}
221
222// Scalar multiplication
223impl ops::Mul<Matrix> for f32 {
224    type Output = Matrix;
225
226    fn mul(self, mut rhs: Matrix) -> Self::Output {
227        rhs.scale(self, self, self);
228        rhs
229    }
230}
231
232// Matrix-matrix/-vector multiplication
233impl ops::Mul<Matrix> for Matrix {
234    type Output = Matrix;
235
236    fn mul(self, rhs: Matrix) -> Self::Output {
237        Matrix::multiply(&self, &rhs)
238    }
239}
240impl ops::MulAssign<Matrix> for Matrix {
241    fn mul_assign(&mut self, rhs: Matrix) {
242        *self = *self * rhs;
243    }
244}
245
246impl ops::Mul<Vec4> for Matrix {
247    type Output = Vec4;
248
249    /// Transforms this `Vec4` using the provided matrix.
250    /// See [Matrix::transform_vec4].
251    fn mul(self, rhs: Vec4) -> Self::Output {
252        Matrix::transform_vec4(&self, &rhs)
253    }
254}
255
256impl ops::Mul<Vec3> for Matrix {
257    type Output = Vec3;
258
259    /// Transforms this `Vec3` using the provided matrix.
260    /// See [Matrix::transform_vec3].
261    fn mul(self, rhs: Vec3) -> Self::Output {
262        Matrix::transform_vec3(&self, &rhs)
263    }
264}
265
266impl ops::Mul<Point> for Matrix {
267    type Output = Point;
268
269    fn mul(self, rhs: Point) -> Self::Output {
270        Matrix::transform_point(&self, &rhs)
271    }
272}
273
274impl ops::Mul<Point3D> for Matrix {
275    type Output = Point3D;
276
277    /// Transforms this point using the provided matrix.
278    /// See [Matrix::transform_point3d].
279    fn mul(self, rhs: Point3D) -> Self::Output {
280        Matrix::transform_point3d(&self, &rhs)
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use super::Matrix;
287    #[test]
288    fn test_matrix_values() {
289        let matrix = Matrix::new_identity();
290        assert_eq!(
291            matrix.values(),
292            &[
293                [1.0, 0.0, 0.0, 0.0],
294                [0.0, 1.0, 0.0, 0.0],
295                [0.0, 0.0, 1.0, 0.0],
296                [0.0, 0.0, 0.0, 1.0]
297            ],
298        );
299    }
300}