From eb0a61679d5cae2ad5ba7fe4981f3c35177a4f22 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 11 Jul 2019 13:59:39 -0700 Subject: [PATCH] Use operator overloading for 3D matrix multiplication --- demo/common/src/camera.rs | 12 +++----- demo/common/src/lib.rs | 24 +++++++++------ demo/common/src/renderer.rs | 32 ++++++++----------- geometry/src/transform3d.rs | 60 +++++++++++++++++++----------------- renderer/src/gpu/renderer.rs | 2 +- 5 files changed, 66 insertions(+), 64 deletions(-) diff --git a/demo/common/src/camera.rs b/demo/common/src/camera.rs index eea0649e..8fd63fc8 100644 --- a/demo/common/src/camera.rs +++ b/demo/common/src/camera.rs @@ -153,15 +153,13 @@ impl CameraTransform3D { pub fn to_transform(&self) -> Transform3DF { let mut transform = Transform3DF::from_rotation(self.yaw, self.pitch, 0.0); - transform = transform.post_mul(&Transform3DF::from_uniform_scale(2.0 * self.scale)); - transform = transform.post_mul(&Transform3DF::from_translation( - -self.position.x(), - -self.position.y(), - -self.position.z(), - )); + transform *= Transform3DF::from_uniform_scale(2.0 * self.scale); + transform *= Transform3DF::from_translation(-self.position.x(), + -self.position.y(), + -self.position.z()); // Flip Y. - transform = transform.post_mul(&Transform3DF::from_scale(1.0, -1.0, 1.0)); + transform *= Transform3DF::from_scale(1.0, -1.0, 1.0); transform } diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 408e8313..1ea26074 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -256,10 +256,9 @@ impl DemoApp where W: Window { if modelview_transform.offset(*velocity) { self.dirty = true; } - let perspective = scene_transform - .perspective - .post_mul(&scene_transform.modelview_to_eye) - .post_mul(&modelview_transform.to_transform()); + let perspective = scene_transform.perspective * + scene_transform.modelview_to_eye * + modelview_transform.to_transform(); Some(RenderTransform::Perspective(perspective)) } Camera::TwoD(transform) => Some(RenderTransform::Transform2D(transform)), @@ -356,13 +355,20 @@ impl DemoApp where W: Window { *scene_transform = eye_transforms[0]; for (index, eye_transform) in eye_transforms.iter().enumerate().skip(1) { let weight = 1.0 / (index + 1) as f32; - scene_transform.perspective.transform = scene_transform.perspective.transform.lerp(weight, &eye_transform.perspective.transform); - scene_transform.modelview_to_eye = scene_transform.modelview_to_eye.lerp(weight, &eye_transform.modelview_to_eye); + scene_transform.perspective.transform = + scene_transform.perspective + .transform + .lerp(weight, &eye_transform.perspective.transform); + scene_transform.modelview_to_eye = + scene_transform.modelview_to_eye + .lerp(weight, &eye_transform.modelview_to_eye); } // TODO: calculate the eye offset from the eye transforms? - let z_offset = -DEFAULT_EYE_OFFSET * scene_transform.perspective.transform.c0.x(); - scene_transform.modelview_to_eye = scene_transform.modelview_to_eye - .pre_mul(&Transform3DF::from_translation(0.0, 0.0, z_offset)); + let z_offset = -DEFAULT_EYE_OFFSET * + scene_transform.perspective.transform.c0.x(); + scene_transform.modelview_to_eye = + Transform3DF::from_translation(0.0, 0.0, z_offset) * + scene_transform.modelview_to_eye; } } Event::KeyDown(Keycode::Alphanumeric(b'w')) => { diff --git a/demo/common/src/renderer.rs b/demo/common/src/renderer.rs index c4bc0cc3..f7029811 100644 --- a/demo/common/src/renderer.rs +++ b/demo/common/src/renderer.rs @@ -169,18 +169,16 @@ impl DemoApp where W: Window { 1.0, ); - let scene_transform_matrix = scene_transform - .perspective - .post_mul(&scene_transform.modelview_to_eye) - .post_mul(&modelview_transform.to_transform()) - .post_mul(&quad_scale_transform); + let scene_transform_matrix = scene_transform.perspective * + scene_transform.modelview_to_eye * + modelview_transform.to_transform() * + quad_scale_transform; let eye_transform = &eye_transforms[render_scene_index as usize]; - let eye_transform_matrix = eye_transform - .perspective - .post_mul(&eye_transform.modelview_to_eye) - .post_mul(&modelview_transform.to_transform()) - .post_mul(&quad_scale_transform); + let eye_transform_matrix = eye_transform.perspective * + eye_transform.modelview_to_eye * + modelview_transform.to_transform() * + quad_scale_transform; debug!( "eye transform({}).modelview_to_eye={:?}", @@ -214,17 +212,13 @@ impl DemoApp where W: Window { let ground_scale = self.scene_metadata.view_box.max_x() * 2.0; - let mut base_transform = perspective.transform; - base_transform = base_transform.post_mul(&Transform3DF::from_translation( - -0.5 * self.scene_metadata.view_box.max_x(), - self.scene_metadata.view_box.max_y(), - -0.5 * ground_scale, - )); + let base_transform = perspective.transform * + Transform3DF::from_translation(-0.5 * self.scene_metadata.view_box.max_x(), + self.scene_metadata.view_box.max_y(), + -0.5 * ground_scale); // Fill ground. - let mut transform = base_transform; - transform = - transform.post_mul(&Transform3DF::from_scale(ground_scale, 1.0, ground_scale)); + let transform = base_transform * Transform3DF::from_scale(ground_scale, 1.0, ground_scale); // Don't clear the first scene after drawing it. let clear_color = if render_scene_index == 0 { diff --git a/geometry/src/transform3d.rs b/geometry/src/transform3d.rs index eeaa9024..8831cee7 100644 --- a/geometry/src/transform3d.rs +++ b/geometry/src/transform3d.rs @@ -14,7 +14,7 @@ use crate::vector::{Vector2F, Vector2I, Vector4F}; use crate::rect::RectF; use crate::transform2d::Matrix2x2F; use pathfinder_simd::default::F32x4; -use std::ops::{Add, Neg}; +use std::ops::{Add, Mul, MulAssign, Neg}; /// An transform, optimized with SIMD. /// @@ -218,31 +218,6 @@ impl Transform3DF { } } - // FIXME(pcwalton): Is this right, due to transposition? I think we may have to reverse the - // two. - // - // https://stackoverflow.com/a/18508113 - #[inline] - pub fn pre_mul(&self, other: &Transform3DF) -> Transform3DF { - return Transform3DF { - c0: mul_col(self.c0, other), - c1: mul_col(self.c1, other), - c2: mul_col(self.c2, other), - c3: mul_col(self.c3, other), - }; - - fn mul_col(a_col: F32x4, b: &Transform3DF) -> F32x4 { - let (a0, a1) = (F32x4::splat(a_col[0]), F32x4::splat(a_col[1])); - let (a2, a3) = (F32x4::splat(a_col[2]), F32x4::splat(a_col[3])); - a0 * b.c0 + a1 * b.c1 + a2 * b.c2 + a3 * b.c3 - } - } - - #[inline] - pub fn post_mul(&self, other: &Transform3DF) -> Transform3DF { - other.pre_mul(self) - } - #[inline] pub fn transform_point(&self, point: Vector4F) -> Vector4F { let term0 = self.c0 * F32x4::splat(point.x()); @@ -313,6 +288,32 @@ impl Transform3DF { } } +impl Mul for Transform3DF { + type Output = Transform3DF; + + // https://stackoverflow.com/a/18508113 + #[inline] + fn mul(self, other: Transform3DF) -> Transform3DF { + return Transform3DF { + c0: mul_col(&self, other.c0), + c1: mul_col(&self, other.c1), + c2: mul_col(&self, other.c2), + c3: mul_col(&self, other.c3), + }; + + #[inline] + fn mul_col(a: &Transform3DF, b_col: F32x4) -> F32x4 { + a.c0 * b_col.xxxx() + a.c1 * b_col.yyyy() + a.c2 * b_col.zzzz() + a.c3 * b_col.wwww() + } + } +} + +impl MulAssign for Transform3DF { + fn mul_assign(&mut self, other: Transform3DF) { + *self = *self * other + } +} + impl Add for Matrix2x2F { type Output = Matrix2x2F; #[inline] @@ -366,11 +367,14 @@ impl Perspective { let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right); RectF::from_points(min_point, max_point) } +} +impl Mul for Perspective { + type Output = Perspective; #[inline] - pub fn post_mul(&self, other: &Transform3DF) -> Perspective { + fn mul(self, other: Transform3DF) -> Perspective { Perspective { - transform: self.transform.post_mul(other), + transform: self.transform * other, window_size: self.window_size, } } diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index ce6ff354..1184da14 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -472,7 +472,7 @@ where let draw_viewport = self.draw_viewport().size().to_f32(); let scale = F32x2::new(2.0 / draw_viewport.x(), -2.0 / draw_viewport.y()); let transform = Transform3DF::from_scale(scale.x(), scale.y(), 1.0); - Transform3DF::from_translation(-1.0, 1.0, 0.0).post_mul(&transform) + Transform3DF::from_translation(-1.0, 1.0, 0.0) * transform } fn draw_alpha_tiles(&mut self, count: u32) {