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