1use core::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
15
16use azul_css::props::style::{StyleTransform, StyleTransformOrigin};
17
18use crate::geom::LogicalPosition;
19
20pub static INITIALIZED: AtomicBool = AtomicBool::new(false);
22pub static USE_AVX: AtomicBool = AtomicBool::new(false);
24pub static USE_SSE: AtomicBool = AtomicBool::new(false);
26
27#[derive(Debug, Copy, Clone)]
33pub enum RotationMode {
34 ForWebRender,
36 ForHitTesting,
38}
39
40#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
56#[repr(C)]
57pub struct ComputedTransform3D {
58 pub m: [[f32; 4]; 4],
60}
61
62impl ComputedTransform3D {
63 pub const IDENTITY: Self = Self {
65 m: [
66 [1.0, 0.0, 0.0, 0.0],
67 [0.0, 1.0, 0.0, 0.0],
68 [0.0, 0.0, 1.0, 0.0],
69 [0.0, 0.0, 0.0, 1.0],
70 ],
71 };
72
73 pub const fn new(
77 m11: f32,
78 m12: f32,
79 m13: f32,
80 m14: f32,
81 m21: f32,
82 m22: f32,
83 m23: f32,
84 m24: f32,
85 m31: f32,
86 m32: f32,
87 m33: f32,
88 m34: f32,
89 m41: f32,
90 m42: f32,
91 m43: f32,
92 m44: f32,
93 ) -> Self {
94 Self {
95 m: [
96 [m11, m12, m13, m14],
97 [m21, m22, m23, m24],
98 [m31, m32, m33, m34],
99 [m41, m42, m43, m44],
100 ],
101 }
102 }
103
104 pub const fn new_2d(m11: f32, m12: f32, m21: f32, m22: f32, m41: f32, m42: f32) -> Self {
111 Self::new(
112 m11, m12, 0.0, 0.0, m21, m22, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, m41, m42, 0.0, 1.0,
113 )
114 }
115
116 pub fn inverse(&self) -> Self {
123 let det = self.determinant();
124
125 let m = ComputedTransform3D::new(
128 self.m[1][2] * self.m[2][3] * self.m[3][1] - self.m[1][3] * self.m[2][2] * self.m[3][1]
129 + self.m[1][3] * self.m[2][1] * self.m[3][2]
130 - self.m[1][1] * self.m[2][3] * self.m[3][2]
131 - self.m[1][2] * self.m[2][1] * self.m[3][3]
132 + self.m[1][1] * self.m[2][2] * self.m[3][3],
133 self.m[0][3] * self.m[2][2] * self.m[3][1]
134 - self.m[0][2] * self.m[2][3] * self.m[3][1]
135 - self.m[0][3] * self.m[2][1] * self.m[3][2]
136 + self.m[0][1] * self.m[2][3] * self.m[3][2]
137 + self.m[0][2] * self.m[2][1] * self.m[3][3]
138 - self.m[0][1] * self.m[2][2] * self.m[3][3],
139 self.m[0][2] * self.m[1][3] * self.m[3][1] - self.m[0][3] * self.m[1][2] * self.m[3][1]
140 + self.m[0][3] * self.m[1][1] * self.m[3][2]
141 - self.m[0][1] * self.m[1][3] * self.m[3][2]
142 - self.m[0][2] * self.m[1][1] * self.m[3][3]
143 + self.m[0][1] * self.m[1][2] * self.m[3][3],
144 self.m[0][3] * self.m[1][2] * self.m[2][1]
145 - self.m[0][2] * self.m[1][3] * self.m[2][1]
146 - self.m[0][3] * self.m[1][1] * self.m[2][2]
147 + self.m[0][1] * self.m[1][3] * self.m[2][2]
148 + self.m[0][2] * self.m[1][1] * self.m[2][3]
149 - self.m[0][1] * self.m[1][2] * self.m[2][3],
150 self.m[1][3] * self.m[2][2] * self.m[3][0]
151 - self.m[1][2] * self.m[2][3] * self.m[3][0]
152 - self.m[1][3] * self.m[2][0] * self.m[3][2]
153 + self.m[1][0] * self.m[2][3] * self.m[3][2]
154 + self.m[1][2] * self.m[2][0] * self.m[3][3]
155 - self.m[1][0] * self.m[2][2] * self.m[3][3],
156 self.m[0][2] * self.m[2][3] * self.m[3][0] - self.m[0][3] * self.m[2][2] * self.m[3][0]
157 + self.m[0][3] * self.m[2][0] * self.m[3][2]
158 - self.m[0][0] * self.m[2][3] * self.m[3][2]
159 - self.m[0][2] * self.m[2][0] * self.m[3][3]
160 + self.m[0][0] * self.m[2][2] * self.m[3][3],
161 self.m[0][3] * self.m[1][2] * self.m[3][0]
162 - self.m[0][2] * self.m[1][3] * self.m[3][0]
163 - self.m[0][3] * self.m[1][0] * self.m[3][2]
164 + self.m[0][0] * self.m[1][3] * self.m[3][2]
165 + self.m[0][2] * self.m[1][0] * self.m[3][3]
166 - self.m[0][0] * self.m[1][2] * self.m[3][3],
167 self.m[0][2] * self.m[1][3] * self.m[2][0] - self.m[0][3] * self.m[1][2] * self.m[2][0]
168 + self.m[0][3] * self.m[1][0] * self.m[2][2]
169 - self.m[0][0] * self.m[1][3] * self.m[2][2]
170 - self.m[0][2] * self.m[1][0] * self.m[2][3]
171 + self.m[0][0] * self.m[1][2] * self.m[2][3],
172 self.m[1][1] * self.m[2][3] * self.m[3][0] - self.m[1][3] * self.m[2][1] * self.m[3][0]
173 + self.m[1][3] * self.m[2][0] * self.m[3][1]
174 - self.m[1][0] * self.m[2][3] * self.m[3][1]
175 - self.m[1][1] * self.m[2][0] * self.m[3][3]
176 + self.m[1][0] * self.m[2][1] * self.m[3][3],
177 self.m[0][3] * self.m[2][1] * self.m[3][0]
178 - self.m[0][1] * self.m[2][3] * self.m[3][0]
179 - self.m[0][3] * self.m[2][0] * self.m[3][1]
180 + self.m[0][0] * self.m[2][3] * self.m[3][1]
181 + self.m[0][1] * self.m[2][0] * self.m[3][3]
182 - self.m[0][0] * self.m[2][1] * self.m[3][3],
183 self.m[0][1] * self.m[1][3] * self.m[3][0] - self.m[0][3] * self.m[1][1] * self.m[3][0]
184 + self.m[0][3] * self.m[1][0] * self.m[3][1]
185 - self.m[0][0] * self.m[1][3] * self.m[3][1]
186 - self.m[0][1] * self.m[1][0] * self.m[3][3]
187 + self.m[0][0] * self.m[1][1] * self.m[3][3],
188 self.m[0][3] * self.m[1][1] * self.m[2][0]
189 - self.m[0][1] * self.m[1][3] * self.m[2][0]
190 - self.m[0][3] * self.m[1][0] * self.m[2][1]
191 + self.m[0][0] * self.m[1][3] * self.m[2][1]
192 + self.m[0][1] * self.m[1][0] * self.m[2][3]
193 - self.m[0][0] * self.m[1][1] * self.m[2][3],
194 self.m[1][2] * self.m[2][1] * self.m[3][0]
195 - self.m[1][1] * self.m[2][2] * self.m[3][0]
196 - self.m[1][2] * self.m[2][0] * self.m[3][1]
197 + self.m[1][0] * self.m[2][2] * self.m[3][1]
198 + self.m[1][1] * self.m[2][0] * self.m[3][2]
199 - self.m[1][0] * self.m[2][1] * self.m[3][2],
200 self.m[0][1] * self.m[2][2] * self.m[3][0] - self.m[0][2] * self.m[2][1] * self.m[3][0]
201 + self.m[0][2] * self.m[2][0] * self.m[3][1]
202 - self.m[0][0] * self.m[2][2] * self.m[3][1]
203 - self.m[0][1] * self.m[2][0] * self.m[3][2]
204 + self.m[0][0] * self.m[2][1] * self.m[3][2],
205 self.m[0][2] * self.m[1][1] * self.m[3][0]
206 - self.m[0][1] * self.m[1][2] * self.m[3][0]
207 - self.m[0][2] * self.m[1][0] * self.m[3][1]
208 + self.m[0][0] * self.m[1][2] * self.m[3][1]
209 + self.m[0][1] * self.m[1][0] * self.m[3][2]
210 - self.m[0][0] * self.m[1][1] * self.m[3][2],
211 self.m[0][1] * self.m[1][2] * self.m[2][0] - self.m[0][2] * self.m[1][1] * self.m[2][0]
212 + self.m[0][2] * self.m[1][0] * self.m[2][1]
213 - self.m[0][0] * self.m[1][2] * self.m[2][1]
214 - self.m[0][1] * self.m[1][0] * self.m[2][2]
215 + self.m[0][0] * self.m[1][1] * self.m[2][2],
216 );
217
218 m.multiply_scalar(1.0 / det)
219 }
220
221 fn determinant(&self) -> f32 {
222 self.m[0][3] * self.m[1][2] * self.m[2][1] * self.m[3][0]
223 - self.m[0][2] * self.m[1][3] * self.m[2][1] * self.m[3][0]
224 - self.m[0][3] * self.m[1][1] * self.m[2][2] * self.m[3][0]
225 + self.m[0][1] * self.m[1][3] * self.m[2][2] * self.m[3][0]
226 + self.m[0][2] * self.m[1][1] * self.m[2][3] * self.m[3][0]
227 - self.m[0][1] * self.m[1][2] * self.m[2][3] * self.m[3][0]
228 - self.m[0][3] * self.m[1][2] * self.m[2][0] * self.m[3][1]
229 + self.m[0][2] * self.m[1][3] * self.m[2][0] * self.m[3][1]
230 + self.m[0][3] * self.m[1][0] * self.m[2][2] * self.m[3][1]
231 - self.m[0][0] * self.m[1][3] * self.m[2][2] * self.m[3][1]
232 - self.m[0][2] * self.m[1][0] * self.m[2][3] * self.m[3][1]
233 + self.m[0][0] * self.m[1][2] * self.m[2][3] * self.m[3][1]
234 + self.m[0][3] * self.m[1][1] * self.m[2][0] * self.m[3][2]
235 - self.m[0][1] * self.m[1][3] * self.m[2][0] * self.m[3][2]
236 - self.m[0][3] * self.m[1][0] * self.m[2][1] * self.m[3][2]
237 + self.m[0][0] * self.m[1][3] * self.m[2][1] * self.m[3][2]
238 + self.m[0][1] * self.m[1][0] * self.m[2][3] * self.m[3][2]
239 - self.m[0][0] * self.m[1][1] * self.m[2][3] * self.m[3][2]
240 - self.m[0][2] * self.m[1][1] * self.m[2][0] * self.m[3][3]
241 + self.m[0][1] * self.m[1][2] * self.m[2][0] * self.m[3][3]
242 + self.m[0][2] * self.m[1][0] * self.m[2][1] * self.m[3][3]
243 - self.m[0][0] * self.m[1][2] * self.m[2][1] * self.m[3][3]
244 - self.m[0][1] * self.m[1][0] * self.m[2][2] * self.m[3][3]
245 + self.m[0][0] * self.m[1][1] * self.m[2][2] * self.m[3][3]
246 }
247
248 fn multiply_scalar(&self, x: f32) -> Self {
249 ComputedTransform3D::new(
250 self.m[0][0] * x,
251 self.m[0][1] * x,
252 self.m[0][2] * x,
253 self.m[0][3] * x,
254 self.m[1][0] * x,
255 self.m[1][1] * x,
256 self.m[1][2] * x,
257 self.m[1][3] * x,
258 self.m[2][0] * x,
259 self.m[2][1] * x,
260 self.m[2][2] * x,
261 self.m[2][3] * x,
262 self.m[3][0] * x,
263 self.m[3][1] * x,
264 self.m[3][2] * x,
265 self.m[3][3] * x,
266 )
267 }
268
269 pub fn from_style_transform_vec(
271 t_vec: &[StyleTransform],
272 transform_origin: &StyleTransformOrigin,
273 percent_resolve_x: f32,
274 percent_resolve_y: f32,
275 rotation_mode: RotationMode,
276 ) -> Self {
277 let mut matrix = Self::IDENTITY;
279 let use_avx =
280 INITIALIZED.load(AtomicOrdering::SeqCst) && USE_AVX.load(AtomicOrdering::SeqCst);
281 let use_sse = !use_avx
282 && INITIALIZED.load(AtomicOrdering::SeqCst)
283 && USE_SSE.load(AtomicOrdering::SeqCst);
284
285 if use_avx {
286 for t in t_vec.iter() {
287 #[cfg(target_arch = "x86_64")]
288 unsafe {
289 matrix = matrix.then_avx8(&Self::from_style_transform(
290 t,
291 transform_origin,
292 percent_resolve_x,
293 percent_resolve_y,
294 rotation_mode,
295 ));
296 }
297 }
298 } else if use_sse {
299 for t in t_vec.iter() {
300 #[cfg(target_arch = "x86_64")]
301 unsafe {
302 matrix = matrix.then_sse(&Self::from_style_transform(
303 t,
304 transform_origin,
305 percent_resolve_x,
306 percent_resolve_y,
307 rotation_mode,
308 ));
309 }
310 }
311 } else {
312 for t in t_vec.iter() {
314 matrix = matrix.then(&Self::from_style_transform(
315 t,
316 transform_origin,
317 percent_resolve_x,
318 percent_resolve_y,
319 rotation_mode,
320 ));
321 }
322 }
323
324 matrix
325 }
326
327 pub fn from_style_transform(
330 t: &StyleTransform,
331 transform_origin: &StyleTransformOrigin,
332 percent_resolve_x: f32,
333 percent_resolve_y: f32,
334 rotation_mode: RotationMode,
335 ) -> Self {
336 use azul_css::props::style::StyleTransform::*;
337 match t {
338 Matrix(mat2d) => {
339 let a = mat2d.a.get();
340 let b = mat2d.b.get();
341 let c = mat2d.c.get();
342 let d = mat2d.d.get();
343 let tx = mat2d.tx.get();
344 let ty = mat2d.ty.get();
345
346 Self::new_2d(a, b, c, d, tx, ty)
347 }
348 Matrix3D(mat3d) => {
349 let m11 = mat3d.m11.get();
350 let m12 = mat3d.m12.get();
351 let m13 = mat3d.m13.get();
352 let m14 = mat3d.m14.get();
353 let m21 = mat3d.m21.get();
354 let m22 = mat3d.m22.get();
355 let m23 = mat3d.m23.get();
356 let m24 = mat3d.m24.get();
357 let m31 = mat3d.m31.get();
358 let m32 = mat3d.m32.get();
359 let m33 = mat3d.m33.get();
360 let m34 = mat3d.m34.get();
361 let m41 = mat3d.m41.get();
362 let m42 = mat3d.m42.get();
363 let m43 = mat3d.m43.get();
364 let m44 = mat3d.m44.get();
365
366 Self::new(
367 m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44,
368 )
369 }
370 Translate(trans2d) => {
371 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
372 Self::new_translation(
373 trans2d
374 .x
375 .to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
376 trans2d
377 .y
378 .to_pixels_internal(percent_resolve_y, DEFAULT_FONT_SIZE),
379 0.0,
380 )
381 }
382 Translate3D(trans3d) => {
383 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
384 Self::new_translation(
385 trans3d
386 .x
387 .to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
388 trans3d
389 .y
390 .to_pixels_internal(percent_resolve_y, DEFAULT_FONT_SIZE),
391 trans3d
392 .z
393 .to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE), )
395 }
396 TranslateX(trans_x) => {
397 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
398 Self::new_translation(
399 trans_x.to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
400 0.0,
401 0.0,
402 )
403 }
404 TranslateY(trans_y) => {
405 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
406 Self::new_translation(
407 0.0,
408 trans_y.to_pixels_internal(percent_resolve_y, DEFAULT_FONT_SIZE),
409 0.0,
410 )
411 }
412 TranslateZ(trans_z) => {
413 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
414 Self::new_translation(
415 0.0,
416 0.0,
417 trans_z.to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
418 )
419 } Rotate3D(rot3d) => {
421 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
422 let rotation_origin = (
423 transform_origin
424 .x
425 .to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
426 transform_origin
427 .y
428 .to_pixels_internal(percent_resolve_y, DEFAULT_FONT_SIZE),
429 );
430 Self::make_rotation(
431 rotation_origin,
432 rot3d.angle.to_degrees(),
433 rot3d.x.get(),
434 rot3d.y.get(),
435 rot3d.z.get(),
436 rotation_mode,
437 )
438 }
439 RotateX(angle_x) => {
440 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
441 let rotation_origin = (
442 transform_origin
443 .x
444 .to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
445 transform_origin
446 .y
447 .to_pixels_internal(percent_resolve_y, DEFAULT_FONT_SIZE),
448 );
449 Self::make_rotation(
450 rotation_origin,
451 angle_x.to_degrees(),
452 1.0,
453 0.0,
454 0.0,
455 rotation_mode,
456 )
457 }
458 RotateY(angle_y) => {
459 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
460 let rotation_origin = (
461 transform_origin
462 .x
463 .to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
464 transform_origin
465 .y
466 .to_pixels_internal(percent_resolve_y, DEFAULT_FONT_SIZE),
467 );
468 Self::make_rotation(
469 rotation_origin,
470 angle_y.to_degrees(),
471 0.0,
472 1.0,
473 0.0,
474 rotation_mode,
475 )
476 }
477 Rotate(angle_z) | RotateZ(angle_z) => {
478 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
479 let rotation_origin = (
480 transform_origin
481 .x
482 .to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE),
483 transform_origin
484 .y
485 .to_pixels_internal(percent_resolve_y, DEFAULT_FONT_SIZE),
486 );
487 Self::make_rotation(
488 rotation_origin,
489 angle_z.to_degrees(),
490 0.0,
491 0.0,
492 1.0,
493 rotation_mode,
494 )
495 }
496 Scale(scale2d) => Self::new_scale(scale2d.x.get(), scale2d.y.get(), 1.0),
497 Scale3D(scale3d) => Self::new_scale(scale3d.x.get(), scale3d.y.get(), scale3d.z.get()),
498 ScaleX(scale_x) => Self::new_scale(scale_x.normalized(), 1.0, 1.0),
499 ScaleY(scale_y) => Self::new_scale(1.0, scale_y.normalized(), 1.0),
500 ScaleZ(scale_z) => Self::new_scale(1.0, 1.0, scale_z.normalized()),
501 Skew(skew2d) => Self::new_skew(skew2d.x.to_degrees(), skew2d.y.to_degrees()),
502 SkewX(skew_x) => Self::new_skew(skew_x.to_degrees(), 0.0),
503 SkewY(skew_y) => Self::new_skew(0.0, skew_y.to_degrees()),
504 Perspective(px) => {
505 use azul_css::props::basic::pixel::DEFAULT_FONT_SIZE;
506 Self::new_perspective(px.to_pixels_internal(percent_resolve_x, DEFAULT_FONT_SIZE))
507 }
508 }
509 }
510
511 #[inline]
512 pub const fn new_scale(x: f32, y: f32, z: f32) -> Self {
513 Self::new(
514 x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, 1.0,
515 )
516 }
517
518 #[inline]
519 pub const fn new_translation(x: f32, y: f32, z: f32) -> Self {
520 Self::new(
521 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, x, y, z, 1.0,
522 )
523 }
524
525 #[inline]
526 pub fn new_perspective(d: f32) -> Self {
527 Self::new(
528 1.0,
529 0.0,
530 0.0,
531 0.0,
532 0.0,
533 1.0,
534 0.0,
535 0.0,
536 0.0,
537 0.0,
538 1.0,
539 -1.0 / d,
540 0.0,
541 0.0,
542 0.0,
543 1.0,
544 )
545 }
546
547 #[inline]
550 pub fn new_rotation(x: f32, y: f32, z: f32, theta_radians: f32) -> Self {
551 let xx = x * x;
552 let yy = y * y;
553 let zz = z * z;
554
555 let half_theta = theta_radians / 2.0;
556 let sc = half_theta.sin() * half_theta.cos();
557 let sq = half_theta.sin() * half_theta.sin();
558
559 Self::new(
560 1.0 - 2.0 * (yy + zz) * sq,
561 2.0 * (x * y * sq + z * sc),
562 2.0 * (x * z * sq - y * sc),
563 0.0,
564 2.0 * (x * y * sq - z * sc),
565 1.0 - 2.0 * (xx + zz) * sq,
566 2.0 * (y * z * sq + x * sc),
567 0.0,
568 2.0 * (x * z * sq + y * sc),
569 2.0 * (y * z * sq - x * sc),
570 1.0 - 2.0 * (xx + yy) * sq,
571 0.0,
572 0.0,
573 0.0,
574 0.0,
575 1.0,
576 )
577 }
578
579 #[inline]
580 pub fn new_skew(alpha: f32, beta: f32) -> Self {
581 let (sx, sy) = (beta.to_radians().tan(), alpha.to_radians().tan());
582 Self::new(
583 1.0, sx, 0.0, 0.0, sy, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
584 )
585 }
586
587 pub fn get_column_major(&self) -> Self {
588 ComputedTransform3D::new(
589 self.m[0][0],
590 self.m[1][0],
591 self.m[2][0],
592 self.m[3][0],
593 self.m[0][1],
594 self.m[1][1],
595 self.m[2][1],
596 self.m[3][1],
597 self.m[0][2],
598 self.m[1][2],
599 self.m[2][2],
600 self.m[3][2],
601 self.m[0][3],
602 self.m[1][3],
603 self.m[2][3],
604 self.m[3][3],
605 )
606 }
607
608 #[must_use]
610 pub fn transform_point2d(&self, p: LogicalPosition) -> Option<LogicalPosition> {
611 let w =
612 p.x.mul_add(self.m[0][3], p.y.mul_add(self.m[1][3], self.m[3][3]));
613
614 if !w.is_sign_positive() {
615 return None;
616 }
617
618 let x =
619 p.x.mul_add(self.m[0][0], p.y.mul_add(self.m[1][0], self.m[3][0]));
620 let y =
621 p.x.mul_add(self.m[0][1], p.y.mul_add(self.m[1][1], self.m[3][1]));
622
623 Some(LogicalPosition { x: x / w, y: y / w })
624 }
625
626 pub fn scale_for_dpi(&mut self, scale_factor: f32) {
627 self.m[3][0] *= scale_factor;
629 self.m[3][1] *= scale_factor;
630 self.m[3][2] *= scale_factor;
631 }
632
633 #[must_use]
635 #[inline]
636 pub fn then(&self, other: &Self) -> Self {
637 Self::new(
638 self.m[0][0].mul_add(
639 other.m[0][0],
640 self.m[0][1].mul_add(
641 other.m[1][0],
642 self.m[0][2].mul_add(other.m[2][0], self.m[0][3] * other.m[3][0]),
643 ),
644 ),
645 self.m[0][0].mul_add(
646 other.m[0][1],
647 self.m[0][1].mul_add(
648 other.m[1][1],
649 self.m[0][2].mul_add(other.m[2][1], self.m[0][3] * other.m[3][1]),
650 ),
651 ),
652 self.m[0][0].mul_add(
653 other.m[0][2],
654 self.m[0][1].mul_add(
655 other.m[1][2],
656 self.m[0][2].mul_add(other.m[2][2], self.m[0][3] * other.m[3][2]),
657 ),
658 ),
659 self.m[0][0].mul_add(
660 other.m[0][3],
661 self.m[0][1].mul_add(
662 other.m[1][3],
663 self.m[0][2].mul_add(other.m[2][3], self.m[0][3] * other.m[3][3]),
664 ),
665 ),
666 self.m[1][0].mul_add(
667 other.m[0][0],
668 self.m[1][1].mul_add(
669 other.m[1][0],
670 self.m[1][2].mul_add(other.m[2][0], self.m[1][3] * other.m[3][0]),
671 ),
672 ),
673 self.m[1][0].mul_add(
674 other.m[0][1],
675 self.m[1][1].mul_add(
676 other.m[1][1],
677 self.m[1][2].mul_add(other.m[2][1], self.m[1][3] * other.m[3][1]),
678 ),
679 ),
680 self.m[1][0].mul_add(
681 other.m[0][2],
682 self.m[1][1].mul_add(
683 other.m[1][2],
684 self.m[1][2].mul_add(other.m[2][2], self.m[1][3] * other.m[3][2]),
685 ),
686 ),
687 self.m[1][0].mul_add(
688 other.m[0][3],
689 self.m[1][1].mul_add(
690 other.m[1][3],
691 self.m[1][2].mul_add(other.m[2][3], self.m[1][3] * other.m[3][3]),
692 ),
693 ),
694 self.m[2][0].mul_add(
695 other.m[0][0],
696 self.m[2][1].mul_add(
697 other.m[1][0],
698 self.m[2][2].mul_add(other.m[2][0], self.m[2][3] * other.m[3][0]),
699 ),
700 ),
701 self.m[2][0].mul_add(
702 other.m[0][1],
703 self.m[2][1].mul_add(
704 other.m[1][1],
705 self.m[2][2].mul_add(other.m[2][1], self.m[2][3] * other.m[3][1]),
706 ),
707 ),
708 self.m[2][0].mul_add(
709 other.m[0][2],
710 self.m[2][1].mul_add(
711 other.m[1][2],
712 self.m[2][2].mul_add(other.m[2][2], self.m[2][3] * other.m[3][2]),
713 ),
714 ),
715 self.m[2][0].mul_add(
716 other.m[0][3],
717 self.m[2][1].mul_add(
718 other.m[1][3],
719 self.m[2][2].mul_add(other.m[2][3], self.m[2][3] * other.m[3][3]),
720 ),
721 ),
722 self.m[3][0].mul_add(
723 other.m[0][0],
724 self.m[3][1].mul_add(
725 other.m[1][0],
726 self.m[3][2].mul_add(other.m[2][0], self.m[3][3] * other.m[3][0]),
727 ),
728 ),
729 self.m[3][0].mul_add(
730 other.m[0][1],
731 self.m[3][1].mul_add(
732 other.m[1][1],
733 self.m[3][2].mul_add(other.m[2][1], self.m[3][3] * other.m[3][1]),
734 ),
735 ),
736 self.m[3][0].mul_add(
737 other.m[0][2],
738 self.m[3][1].mul_add(
739 other.m[1][2],
740 self.m[3][2].mul_add(other.m[2][2], self.m[3][3] * other.m[3][2]),
741 ),
742 ),
743 self.m[3][0].mul_add(
744 other.m[0][3],
745 self.m[3][1].mul_add(
746 other.m[1][3],
747 self.m[3][2].mul_add(other.m[2][3], self.m[3][3] * other.m[3][3]),
748 ),
749 ),
750 )
751 }
752
753 #[cfg(target_arch = "x86_64")]
758 #[inline]
759 unsafe fn linear_combine_sse(a: [f32; 4], b: &ComputedTransform3D) -> [f32; 4] {
760 use core::{
761 arch::x86_64::{__m128, _mm_add_ps, _mm_mul_ps, _mm_shuffle_ps},
762 mem,
763 };
764
765 let a: __m128 = mem::transmute(a);
766 let mut result = _mm_mul_ps(_mm_shuffle_ps(a, a, 0x00), mem::transmute(b.m[0]));
767 result = _mm_add_ps(
768 result,
769 _mm_mul_ps(_mm_shuffle_ps(a, a, 0x55), mem::transmute(b.m[1])),
770 );
771 result = _mm_add_ps(
772 result,
773 _mm_mul_ps(_mm_shuffle_ps(a, a, 0xaa), mem::transmute(b.m[2])),
774 );
775 result = _mm_add_ps(
776 result,
777 _mm_mul_ps(_mm_shuffle_ps(a, a, 0xff), mem::transmute(b.m[3])),
778 );
779
780 mem::transmute(result)
781 }
782
783 #[cfg(target_arch = "x86_64")]
784 #[inline]
785 pub unsafe fn then_sse(&self, other: &Self) -> Self {
786 Self {
787 m: [
788 Self::linear_combine_sse(self.m[0], other),
789 Self::linear_combine_sse(self.m[1], other),
790 Self::linear_combine_sse(self.m[2], other),
791 Self::linear_combine_sse(self.m[3], other),
792 ],
793 }
794 }
795
796 #[cfg(target_arch = "x86_64")]
798 pub unsafe fn linear_combine_avx8(
799 a01: core::arch::x86_64::__m256,
800 b: &ComputedTransform3D,
801 ) -> core::arch::x86_64::__m256 {
802 use core::{
803 arch::x86_64::{_mm256_add_ps, _mm256_broadcast_ps, _mm256_mul_ps, _mm256_shuffle_ps},
804 mem,
805 };
806
807 let mut result = _mm256_mul_ps(
808 _mm256_shuffle_ps(a01, a01, 0x00),
809 _mm256_broadcast_ps(mem::transmute(&b.m[0])),
810 );
811 result = _mm256_add_ps(
812 result,
813 _mm256_mul_ps(
814 _mm256_shuffle_ps(a01, a01, 0x55),
815 _mm256_broadcast_ps(mem::transmute(&b.m[1])),
816 ),
817 );
818 result = _mm256_add_ps(
819 result,
820 _mm256_mul_ps(
821 _mm256_shuffle_ps(a01, a01, 0xaa),
822 _mm256_broadcast_ps(mem::transmute(&b.m[2])),
823 ),
824 );
825 result = _mm256_add_ps(
826 result,
827 _mm256_mul_ps(
828 _mm256_shuffle_ps(a01, a01, 0xff),
829 _mm256_broadcast_ps(mem::transmute(&b.m[3])),
830 ),
831 );
832 result
833 }
834
835 #[cfg(target_arch = "x86_64")]
836 #[inline]
837 pub unsafe fn then_avx8(&self, other: &Self) -> Self {
838 use core::{
839 arch::x86_64::{__m256, _mm256_loadu_ps, _mm256_storeu_ps, _mm256_zeroupper},
840 mem,
841 };
842
843 _mm256_zeroupper();
844
845 let a01: __m256 = _mm256_loadu_ps(mem::transmute(&self.m[0][0]));
846 let a23: __m256 = _mm256_loadu_ps(mem::transmute(&self.m[2][0]));
847
848 let out01x = Self::linear_combine_avx8(a01, other);
849 let out23x = Self::linear_combine_avx8(a23, other);
850
851 let mut out = Self {
852 m: [self.m[0], self.m[1], self.m[2], self.m[3]],
853 };
854
855 _mm256_storeu_ps(mem::transmute(&mut out.m[0][0]), out01x);
856 _mm256_storeu_ps(mem::transmute(&mut out.m[2][0]), out23x);
857
858 out
859 }
860
861 #[inline]
864 pub fn make_rotation(
865 rotation_origin: (f32, f32),
866 mut degrees: f32,
867 axis_x: f32,
868 axis_y: f32,
869 axis_z: f32,
870 rotation_mode: RotationMode,
872 ) -> Self {
873 degrees = match rotation_mode {
874 RotationMode::ForWebRender => -degrees,
876 RotationMode::ForHitTesting => degrees,
878 };
879
880 let (origin_x, origin_y) = rotation_origin;
881 let pre_transform = Self::new_translation(-origin_x, -origin_y, -0.0);
882 let post_transform = Self::new_translation(origin_x, origin_y, 0.0);
883 let theta = 2.0_f32 * core::f32::consts::PI - degrees.to_radians();
884 let rotate_transform =
885 Self::new_rotation(axis_x, axis_y, axis_z, theta).then(&Self::IDENTITY);
886
887 pre_transform.then(&rotate_transform).then(&post_transform)
888 }
889}