From 437eda96da86020ffd3e357648546dd901807a64 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 12 Jul 2019 11:55:01 -0700 Subject: [PATCH] Overload `*` between transforms and points --- content/src/outline.rs | 4 +-- content/src/transform.rs | 18 ++++++------- demo/common/src/camera.rs | 2 +- geometry/src/line_segment.rs | 2 +- geometry/src/transform2d.rs | 39 +++++++++++++++------------- geometry/src/transform3d.rs | 50 ++++++++++++++++++------------------ renderer/src/options.rs | 9 ++----- text/src/lib.rs | 2 +- 8 files changed, 61 insertions(+), 65 deletions(-) diff --git a/content/src/outline.rs b/content/src/outline.rs index 5dd7f709..e2e5dec2 100644 --- a/content/src/outline.rs +++ b/content/src/outline.rs @@ -533,14 +533,14 @@ impl Contour { } for (point_index, point) in self.points.iter_mut().enumerate() { - *point = transform.transform_point(*point); + *point = *transform * *point; union_rect(&mut self.bounds, *point, point_index == 0); } } pub fn apply_perspective(&mut self, perspective: &Perspective) { for (point_index, point) in self.points.iter_mut().enumerate() { - *point = perspective.transform_point_2d(*point); + *point = *perspective * *point; union_rect(&mut self.bounds, *point, point_index == 0); } } diff --git a/content/src/transform.rs b/content/src/transform.rs index a8abcde5..4f2cde2b 100644 --- a/content/src/transform.rs +++ b/content/src/transform.rs @@ -34,12 +34,12 @@ where // TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD? let mut segment = self.iter.next()?; if !segment.is_none() { - segment.baseline.set_from(self.transform.transform_point(segment.baseline.from())); - segment.baseline.set_to(self.transform.transform_point(segment.baseline.to())); + segment.baseline.set_from(self.transform * segment.baseline.from()); + segment.baseline.set_to(self.transform * segment.baseline.to()); if !segment.is_line() { - segment.ctrl.set_from(self.transform.transform_point(segment.ctrl.from())); + segment.ctrl.set_from(self.transform * segment.ctrl.from()); if !segment.is_quadratic() { - segment.ctrl.set_to(self.transform.transform_point(segment.ctrl.to())); + segment.ctrl.set_to(self.transform * segment.ctrl.to()); } } } @@ -79,14 +79,12 @@ where fn next(&mut self) -> Option { let mut segment = self.iter.next()?; if !segment.is_none() { - segment.baseline.set_from( - self.perspective.transform_point_2d(segment.baseline.from()), - ); - segment.baseline.set_to(self.perspective.transform_point_2d(segment.baseline.to())); + segment.baseline.set_from(self.perspective * segment.baseline.from()); + segment.baseline.set_to(self.perspective * segment.baseline.to()); if !segment.is_line() { - segment.ctrl.set_from(self.perspective.transform_point_2d(segment.ctrl.from())); + segment.ctrl.set_from(self.perspective * segment.ctrl.from()); if !segment.is_quadratic() { - segment.ctrl.set_to(self.perspective.transform_point_2d(segment.ctrl.to())); + segment.ctrl.set_to(self.perspective * segment.ctrl.to()); } } } diff --git a/demo/common/src/camera.rs b/demo/common/src/camera.rs index 28975750..888abe48 100644 --- a/demo/common/src/camera.rs +++ b/demo/common/src/camera.rs @@ -147,7 +147,7 @@ impl CameraTransform3D { let update = !vector.is_zero(); if update { let rotation = Transform4F::from_rotation(-self.yaw, -self.pitch, 0.0); - self.position = self.position + rotation.transform_point(vector); + self.position = self.position + rotation * vector; } update } diff --git a/geometry/src/line_segment.rs b/geometry/src/line_segment.rs index 63012a3c..4a15e471 100644 --- a/geometry/src/line_segment.rs +++ b/geometry/src/line_segment.rs @@ -232,7 +232,7 @@ impl LineSegment2F { if f32::abs(matrix.det()) < EPSILON { return None; } - return Some(matrix.inverse().transform_point(self.from() - other.from()).y()); + return Some((matrix.inverse() * (self.from() - other.from())).y()); const EPSILON: f32 = 0.0001; } diff --git a/geometry/src/transform2d.rs b/geometry/src/transform2d.rs index 779cdeb0..55807bd0 100644 --- a/geometry/src/transform2d.rs +++ b/geometry/src/transform2d.rs @@ -60,12 +60,6 @@ impl Matrix2x2F { Matrix2x2F(self.0.wyzx() * F32x4::new(1.0, -1.0, -1.0, 1.0)) } - #[inline] - pub fn transform_point(&self, point: Vector2F) -> Vector2F { - let halves = self.0 * point.0.to_f32x4().xxyy(); - Vector2F(halves.xy() + halves.zw()) - } - #[inline] pub fn det(&self) -> f32 { self.0[0] * self.0[3] - self.0[2] * self.0[1] @@ -110,6 +104,15 @@ impl Mul for Matrix2x2F { } } +impl Mul for Matrix2x2F { + type Output = Vector2F; + #[inline] + fn mul(self, vector: Vector2F) -> Vector2F { + let halves = self.0 * vector.0.to_f32x4().xxyy(); + Vector2F(halves.xy() + halves.zw()) + } +} + /// An affine transform, optimized with SIMD. #[derive(Clone, Copy, Debug, PartialEq)] pub struct Transform2F { @@ -179,23 +182,15 @@ impl Transform2F { } } - #[inline] - pub fn transform_point(&self, point: Vector2F) -> Vector2F { - self.matrix.transform_point(point) + self.vector - } - #[inline] pub fn transform_line_segment(&self, line_segment: LineSegment2F) -> LineSegment2F { - LineSegment2F::new(self.transform_point(line_segment.from()), - self.transform_point(line_segment.to())) + LineSegment2F::new(*self * line_segment.from(), *self * line_segment.to()) } #[inline] pub fn transform_rect(&self, rect: &RectF) -> RectF { - let upper_left = self.transform_point(rect.origin()); - let upper_right = self.transform_point(rect.upper_right()); - let lower_left = self.transform_point(rect.lower_left()); - let lower_right = self.transform_point(rect.lower_right()); + let (upper_left, upper_right) = (*self * rect.origin(), *self * rect.upper_right()); + let (lower_left, lower_right) = (*self * rect.lower_left(), *self * rect.lower_right()); let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right); let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right); RectF::from_points(min_point, max_point) @@ -297,11 +292,19 @@ impl Mul for Transform2F { fn mul(self, other: Transform2F) -> Transform2F { Transform2F { matrix: self.matrix * other.matrix, - vector: self.transform_point(other.vector), + vector: self * other.vector, } } } +impl Mul for Transform2F { + type Output = Vector2F; + #[inline] + fn mul(self, vector: Vector2F) -> Vector2F { + self.matrix * vector + self.vector + } +} + impl MulAssign for Transform2F { #[inline] fn mul_assign(&mut self, other: Transform2F) { diff --git a/geometry/src/transform3d.rs b/geometry/src/transform3d.rs index c892d52d..7630ea3b 100644 --- a/geometry/src/transform3d.rs +++ b/geometry/src/transform3d.rs @@ -240,15 +240,6 @@ impl Transform4F { Transform4F::from_translation(translation) * *self } - #[inline] - pub fn transform_point(&self, point: Vector4F) -> Vector4F { - let term0 = self.c0 * F32x4::splat(point.x()); - let term1 = self.c1 * F32x4::splat(point.y()); - let term2 = self.c2 * F32x4::splat(point.z()); - let term3 = self.c3 * F32x4::splat(point.w()); - Vector4F(term0 + term1 + term2 + term3) - } - #[inline] pub fn upper_left(&self) -> Matrix2x2F { Matrix2x2F(self.c0.concat_xy_xy(self.c1)) @@ -330,6 +321,19 @@ impl Mul for Transform4F { } } +impl Mul for Transform4F { + type Output = Vector4F; + + #[inline] + fn mul(self, vector: Vector4F) -> Vector4F { + let term0 = self.c0 * F32x4::splat(vector.x()); + let term1 = self.c1 * F32x4::splat(vector.y()); + let term2 = self.c2 * F32x4::splat(vector.z()); + let term3 = self.c3 * F32x4::splat(vector.w()); + Vector4F(term0 + term1 + term2 + term3) + } +} + impl MulAssign for Transform4F { fn mul_assign(&mut self, other: Transform4F) { *self = *self * other @@ -367,24 +371,10 @@ impl Perspective { } } - #[inline] - pub fn transform_point_2d(&self, point: Vector2F) -> Vector2F { - let point = self - .transform - .transform_point(point.to_3d()) - .perspective_divide() - .to_2d() - * Vector2F::new(1.0, -1.0); - (point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5) - } - - // TODO(pcwalton): SIMD? #[inline] pub fn transform_rect(&self, rect: RectF) -> RectF { - let upper_left = self.transform_point_2d(rect.origin()); - let upper_right = self.transform_point_2d(rect.upper_right()); - let lower_left = self.transform_point_2d(rect.lower_left()); - let lower_right = self.transform_point_2d(rect.lower_right()); + let (upper_left, upper_right) = (*self * rect.origin(), *self * rect.upper_right()); + let (lower_left, lower_right) = (*self * rect.lower_left(), *self * rect.lower_right()); let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right); let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right); RectF::from_points(min_point, max_point) @@ -402,6 +392,16 @@ impl Mul for Perspective { } } +impl Mul for Perspective { + type Output = Vector2F; + #[inline] + fn mul(self, vector: Vector2F) -> Vector2F { + let point = (self.transform * vector.to_3d()).perspective_divide().to_2d() * + Vector2F::new(1.0, -1.0); + (point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5) + } +} + #[cfg(test)] mod test { use crate::vector::Vector4F; diff --git a/renderer/src/options.rs b/renderer/src/options.rs index a6eb52c8..170d2cb7 100644 --- a/renderer/src/options.rs +++ b/renderer/src/options.rs @@ -83,7 +83,7 @@ impl RenderTransform { debug!("-----"); debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points); for point in &mut points { - *point = perspective.transform.transform_point(*point); + *point = perspective.transform * *point; } debug!("... PERSPECTIVE quad={:?}", points); @@ -105,12 +105,7 @@ impl RenderTransform { let inverse_transform = perspective.transform.inverse(); let clip_polygon = points .into_iter() - .map(|point| { - inverse_transform - .transform_point(point) - .perspective_divide() - .to_2d() - }) + .map(|point| (inverse_transform * point).perspective_divide().to_2d()) .collect(); return PreparedRenderTransform::Perspective { perspective, diff --git a/text/src/lib.rs b/text/src/lib.rs index 8b2d780c..9de965a1 100644 --- a/text/src/lib.rs +++ b/text/src/lib.rs @@ -147,7 +147,7 @@ impl OutlinePathBuilder { } fn convert_point(&self, point: Point2D) -> Vector2F { - self.transform.transform_point(Vector2F::new(point.x, point.y)) + self.transform * Vector2F::new(point.x, point.y) } }