cogl/auto/quaternion.rs
1#![allow(
2 clippy::too_many_arguments,
3 clippy::let_and_return,
4 clippy::from_over_into
5)]
6
7use crate::{Euler, Matrix};
8
9use glib::translate::*;
10use std::boxed::Box as Box_;
11use std::mem;
12
13glib_wrapper! {
14 #[derive(Debug, PartialOrd, Ord)] // Hash
15 pub struct Quaternion(Boxed<ffi::CoglQuaternion>);
16
17 match fn {
18 copy => |ptr| ffi::cogl_quaternion_copy(mut_override(ptr)),
19 free => |ptr| ffi::cogl_quaternion_free(ptr),
20 get_type => || ffi::cogl_quaternion_get_gtype(),
21 }
22}
23
24impl Quaternion {
25 ///
26 /// ## `b`
27 /// A `Quaternion`
28 pub fn dot_product(&self, b: &Quaternion) -> f32 {
29 unsafe { ffi::cogl_quaternion_dot_product(self.to_glib_none().0, b.to_glib_none().0) }
30 }
31
32 ///
33 pub fn get_rotation_angle(&self) -> f32 {
34 unsafe { ffi::cogl_quaternion_get_rotation_angle(self.to_glib_none().0) }
35 }
36
37 ///
38 /// ## `vector3`
39 /// an allocated 3-float array
40 pub fn get_rotation_axis(&self) -> f32 {
41 unsafe {
42 let mut vector3 = mem::MaybeUninit::uninit();
43 ffi::cogl_quaternion_get_rotation_axis(self.to_glib_none().0, vector3.as_mut_ptr());
44 vector3.assume_init()
45 }
46 }
47
48 /// Initializes a quaternion that rotates `angle` degrees around the
49 /// axis vector (`x`, `y`, `z`). The axis vector does not need to be
50 /// normalized.
51 ///
52 /// ## `angle`
53 /// The angle you want to rotate around the given axis
54 /// ## `x`
55 /// The x component of your axis vector about which you want to
56 /// rotate.
57 /// ## `y`
58 /// The y component of your axis vector about which you want to
59 /// rotate.
60 /// ## `z`
61 /// The z component of your axis vector about which you want to
62 /// rotate.
63 pub fn init(&mut self, angle: f32, x: f32, y: f32, z: f32) {
64 unsafe {
65 ffi::cogl_quaternion_init(self.to_glib_none_mut().0, angle, x, y, z);
66 }
67 }
68
69 /// Initializes a quaternion that rotates `angle` degrees around the
70 /// given `axis` vector. The axis vector does not need to be
71 /// normalized.
72 ///
73 /// ## `angle`
74 /// The angle to rotate around `axis3f`
75 /// ## `axis3f`
76 /// your 3 component axis vector about which you want to rotate.
77 pub fn init_from_angle_vector(&mut self, angle: f32, axis3f: &[f32; 3]) {
78 unsafe {
79 ffi::cogl_quaternion_init_from_angle_vector(
80 self.to_glib_none_mut().0,
81 angle,
82 axis3f.to_glib_none().0,
83 );
84 }
85 }
86
87 /// Initializes a [w (x, y,z)] quaternion directly from an array of 4
88 /// floats: [w,x,y,z].
89 ///
90 /// ## `array`
91 /// An array of 4 floats w,(x,y,z)
92 pub fn init_from_array(&mut self, array: &[f32]) {
93 unsafe {
94 ffi::cogl_quaternion_init_from_array(self.to_glib_none_mut().0, array.as_ptr());
95 }
96 }
97
98 ///
99 /// ## `euler`
100 /// A `Euler` with which to initialize the quaternion
101 pub fn init_from_euler(&mut self, euler: &Euler) {
102 unsafe {
103 ffi::cogl_quaternion_init_from_euler(self.to_glib_none_mut().0, euler.to_glib_none().0);
104 }
105 }
106
107 /// Initializes a quaternion from a rotation matrix.
108 /// ## `matrix`
109 /// A rotation matrix with which to initialize the quaternion
110 pub fn init_from_matrix(&mut self, matrix: &Matrix) {
111 unsafe {
112 ffi::cogl_quaternion_init_from_matrix(
113 self.to_glib_none_mut().0,
114 matrix.to_glib_none().0,
115 );
116 }
117 }
118
119 ///
120 /// ## `src`
121 /// A `Quaternion` with which to initialize `self`
122 pub fn init_from_quaternion(&mut self, src: &mut Quaternion) {
123 unsafe {
124 ffi::cogl_quaternion_init_from_quaternion(
125 self.to_glib_none_mut().0,
126 src.to_glib_none_mut().0,
127 );
128 }
129 }
130
131 /// XXX: check which direction this rotates
132 ///
133 /// ## `angle`
134 /// The angle to rotate around the x axis
135 pub fn init_from_x_rotation(&mut self, angle: f32) {
136 unsafe {
137 ffi::cogl_quaternion_init_from_x_rotation(self.to_glib_none_mut().0, angle);
138 }
139 }
140
141 ///
142 /// ## `angle`
143 /// The angle to rotate around the y axis
144 pub fn init_from_y_rotation(&mut self, angle: f32) {
145 unsafe {
146 ffi::cogl_quaternion_init_from_y_rotation(self.to_glib_none_mut().0, angle);
147 }
148 }
149
150 ///
151 /// ## `angle`
152 /// The angle to rotate around the z axis
153 pub fn init_from_z_rotation(&mut self, angle: f32) {
154 unsafe {
155 ffi::cogl_quaternion_init_from_z_rotation(self.to_glib_none_mut().0, angle);
156 }
157 }
158
159 /// Initializes the quaternion with the canonical quaternion identity
160 /// [1 (0, 0, 0)] which represents no rotation. Multiplying a
161 /// quaternion with this identity leaves the quaternion unchanged.
162 ///
163 /// You might also want to consider using
164 /// `cogl_get_static_identity_quaternion`.
165 ///
166 pub fn init_identity(&mut self) {
167 unsafe {
168 ffi::cogl_quaternion_init_identity(self.to_glib_none_mut().0);
169 }
170 }
171
172 ///
173 pub fn invert(&mut self) {
174 unsafe {
175 ffi::cogl_quaternion_invert(self.to_glib_none_mut().0);
176 }
177 }
178
179 /// This combines the rotations of two quaternions into `self`. The
180 /// operation is not commutative so the order is important because AxB
181 /// != BxA. Cogl follows the standard convention for quaternions here
182 /// so the rotations are applied `right` to `left`. This is similar to the
183 /// combining of matrices.
184 ///
185 /// `<note>`It is possible to multiply the `a` quaternion in-place, so
186 /// `self` can be equal to `a` but can't be equal to `b`.`</note>`
187 ///
188 /// ## `left`
189 /// The second `Quaternion` rotation to apply
190 /// ## `right`
191 /// The first `Quaternion` rotation to apply
192 pub fn multiply(&mut self, left: &Quaternion, right: &Quaternion) {
193 unsafe {
194 ffi::cogl_quaternion_multiply(
195 self.to_glib_none_mut().0,
196 left.to_glib_none().0,
197 right.to_glib_none().0,
198 );
199 }
200 }
201
202 /// Performs a normalized linear interpolation between two quaternions.
203 /// That is it does a linear interpolation of the quaternion components
204 /// and then normalizes the result. This will follow the shortest arc
205 /// between the two orientations (just like the `slerp` function) but
206 /// will not progress at a constant speed. Unlike `slerp` nlerp is
207 /// commutative which is useful if you are blending animations
208 /// together. (I.e. nlerp (tmp, a, b) followed by nlerp (result, tmp,
209 /// d) is the same as nlerp (tmp, a, d) followed by nlerp (result, tmp,
210 /// b)). Finally nlerp is cheaper than slerp so it can be a good choice
211 /// if you don't need the constant speed property of the `slerp` function.
212 ///
213 /// Notable properties:
214 /// `<itemizedlist>`
215 /// `<listitem>`
216 /// commutative: Yes
217 /// `</listitem>`
218 /// `<listitem>`
219 /// constant velocity: No
220 /// `</listitem>`
221 /// `<listitem>`
222 /// torque minimal (travels along the surface of the 4-sphere): Yes
223 /// `</listitem>`
224 /// `<listitem>`
225 /// faster than `Quaternion::slerp`
226 /// `</listitem>`
227 /// `</itemizedlist>`
228 /// ## `a`
229 /// The first `Quaternion`
230 /// ## `b`
231 /// The second `Quaternion`
232 /// ## `t`
233 /// The factor in the range [0,1] used to interpolate between
234 /// quaterion `a` and `b`.
235 pub fn nlerp(&mut self, a: &Quaternion, b: &Quaternion, t: f32) {
236 unsafe {
237 ffi::cogl_quaternion_nlerp(
238 self.to_glib_none_mut().0,
239 a.to_glib_none().0,
240 b.to_glib_none().0,
241 t,
242 );
243 }
244 }
245
246 ///
247 pub fn normalize(&mut self) {
248 unsafe {
249 ffi::cogl_quaternion_normalize(self.to_glib_none_mut().0);
250 }
251 }
252
253 ///
254 /// ## `exponent`
255 /// the exponent
256 pub fn pow(&mut self, exponent: f32) {
257 unsafe {
258 ffi::cogl_quaternion_pow(self.to_glib_none_mut().0, exponent);
259 }
260 }
261
262 /// Performs a spherical linear interpolation between two quaternions.
263 ///
264 /// Noteable properties:
265 /// `<itemizedlist>`
266 /// `<listitem>`
267 /// commutative: No
268 /// `</listitem>`
269 /// `<listitem>`
270 /// constant velocity: Yes
271 /// `</listitem>`
272 /// `<listitem>`
273 /// torque minimal (travels along the surface of the 4-sphere): Yes
274 /// `</listitem>`
275 /// `<listitem>`
276 /// more expensive than `Quaternion::nlerp`
277 /// `</listitem>`
278 /// `</itemizedlist>`
279 /// ## `a`
280 /// The first `Quaternion`
281 /// ## `b`
282 /// The second `Quaternion`
283 /// ## `t`
284 /// The factor in the range [0,1] used to interpolate between
285 /// quaternion `a` and `b`.
286 pub fn slerp(&mut self, a: &Quaternion, b: &Quaternion, t: f32) {
287 unsafe {
288 ffi::cogl_quaternion_slerp(
289 self.to_glib_none_mut().0,
290 a.to_glib_none().0,
291 b.to_glib_none().0,
292 t,
293 );
294 }
295 }
296
297 ///
298 /// ## `prev`
299 /// A `Quaternion` used before `a`
300 /// ## `a`
301 /// The first `Quaternion`
302 /// ## `b`
303 /// The second `Quaternion`
304 /// ## `next`
305 /// A `Quaternion` that will be used after `b`
306 /// ## `t`
307 /// The factor in the range [0,1] used to interpolate between
308 /// quaternion `a` and `b`.
309 pub fn squad(
310 &mut self,
311 prev: &Quaternion,
312 a: &Quaternion,
313 b: &Quaternion,
314 next: &Quaternion,
315 t: f32,
316 ) {
317 unsafe {
318 ffi::cogl_quaternion_squad(
319 self.to_glib_none_mut().0,
320 prev.to_glib_none().0,
321 a.to_glib_none().0,
322 b.to_glib_none().0,
323 next.to_glib_none().0,
324 t,
325 );
326 }
327 }
328
329 fn equal(v1: &Self, v2: &Self) -> bool {
330 let a = Box_::into_raw(Box::new(v1)) as *mut _;
331 let b = Box_::into_raw(Box::new(v2)) as *mut _;
332 unsafe { ffi::cogl_quaternion_equal(a, b) == crate::TRUE }
333 }
334}
335
336impl PartialEq for Quaternion {
337 #[inline]
338 fn eq(&self, other: &Self) -> bool {
339 Quaternion::equal(self, other)
340 }
341}
342
343impl Eq for Quaternion {}