From 80db7155b8611f5ab1804f842687499946db2651 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 25 Jan 2019 17:07:37 -0800 Subject: [PATCH] wip --- Cargo.lock | 25 +++++++++++++++++++ geometry/Cargo.toml | 1 + geometry/src/clip.rs | 50 +++++++++++++++++++++++++------------ geometry/src/outline.rs | 13 ++++++++-- geometry/src/transform3d.rs | 13 ++++++---- renderer/src/scene.rs | 14 +++++++++-- 6 files changed, 91 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6a6437d..877d5e9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -513,6 +513,7 @@ dependencies = [ "lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -880,6 +881,14 @@ name = "slab" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "strsim" version = "0.7.0" @@ -993,6 +1002,14 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "usvg" version = "0.4.0" @@ -1022,6 +1039,11 @@ name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.6" @@ -1171,6 +1193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum simplecss 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "135685097a85a64067df36e28a243e94a94f76d829087ce0be34eeb014260c0e" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" +"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum svgdom 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a9b53b3ed152fc6b871f7232a8772c640567fd25d056941450637ecba32924d" "checksum svgtypes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c43c25e6de7264024b5e351eb0c342039eb5acf51f2e9d0099bbd324b661453b" @@ -1183,10 +1206,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum usvg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ebf4d5244ba2e8305caf9de7949377794ecdea5a9e3c84fc5610d78d21f5ee" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" diff --git a/geometry/Cargo.toml b/geometry/Cargo.toml index fde1fafa..765443ac 100644 --- a/geometry/Cargo.toml +++ b/geometry/Cargo.toml @@ -12,3 +12,4 @@ lyon_geom = "0.12" lyon_path = "0.12" serde = "1.0" serde_derive = "1.0" +smallvec = "0.6" diff --git a/geometry/src/clip.rs b/geometry/src/clip.rs index 6f83d46c..225409e3 100644 --- a/geometry/src/clip.rs +++ b/geometry/src/clip.rs @@ -16,6 +16,7 @@ use crate::simd::F32x4; use crate::util::lerp; use euclid::Rect; use lyon_path::PathEvent; +use smallvec::SmallVec; use std::mem; pub struct RectClipper<'a> { @@ -241,26 +242,43 @@ impl Edge { } } -pub(crate) struct ContourRectClipper { - clip_rect: Rect, +pub(crate) struct ContourClipper { + clip_polygon: SmallVec<[Point2DF32; 4]>, contour: Contour, } -impl ContourRectClipper { +impl ContourClipper { #[inline] - pub(crate) fn new(clip_rect: &Rect, contour: Contour) -> ContourRectClipper { - ContourRectClipper { clip_rect: *clip_rect, contour } + pub(crate) fn new(clip_polygon: &[Point2DF32], contour: Contour) -> ContourClipper { + debug_assert!(!clip_polygon.is_empty()); + ContourClipper { clip_polygon: SmallVec::from_slice(clip_polygon), contour } + } + + #[inline] + pub(crate) fn from_rect(clip_rect: &Rect, contour: Contour) -> ContourClipper { + ContourClipper::new(&[ + Point2DF32::from_euclid(clip_rect.origin), + Point2DF32::from_euclid(clip_rect.top_right()), + Point2DF32::from_euclid(clip_rect.bottom_right()), + Point2DF32::from_euclid(clip_rect.bottom_left()), + ], contour) } pub(crate) fn clip(mut self) -> Contour { - if self.clip_rect.contains_rect(&self.contour.bounds()) { + // TODO(pcwalton): Reenable this optimization. + /*if self.clip_rect.contains_rect(&self.contour.bounds()) { return self.contour - } + }*/ - self.clip_against(Edge::left(&self.clip_rect)); - self.clip_against(Edge::top(&self.clip_rect)); - self.clip_against(Edge::right(&self.clip_rect)); - self.clip_against(Edge::bottom(&self.clip_rect)); + let clip_polygon = mem::replace(&mut self.clip_polygon, SmallVec::default()); + let mut prev = match clip_polygon.last() { + None => return Contour::new(), + Some(prev) => *prev, + }; + for &next in &clip_polygon { + self.clip_against(Edge(LineSegmentF32::new(&prev, &next))); + prev = next; + } /* let top = Point2DF32::new(lerp(self.clip_rect.origin.x, self.clip_rect.max_x(), 0.5), @@ -399,7 +417,7 @@ impl PolygonClipper3D { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] enum Edge3D { Left, Right, @@ -413,9 +431,9 @@ impl Edge3D { #[inline] fn point_is_inside(self, point: Point3DF32) -> bool { match self { - Edge3D::Left => point.x() > -1.0, Edge3D::Right => point.x() < 1.0, - Edge3D::Bottom => point.y() > -1.0, Edge3D::Top => point.y() < 1.0, - Edge3D::Near => point.z() > -1.0, Edge3D::Far => point.z() < 1.0, + Edge3D::Left => point.x() >= -1.0, Edge3D::Right => point.x() <= 1.0, + Edge3D::Bottom => point.y() >= -1.0, Edge3D::Top => point.y() <= 1.0, + Edge3D::Near => point.z() >= -1.0, Edge3D::Far => point.z() <= 1.0, } } @@ -429,6 +447,6 @@ impl Edge3D { Edge3D::Left | Edge3D::Bottom | Edge3D::Near => -1.0, Edge3D::Right | Edge3D::Top | Edge3D::Far => 1.0, }; - prev.lerp(next, (x0 - x) / (x1 - x0)) + prev.lerp(next, (x - x0) / (x1 - x0)) } } diff --git a/geometry/src/outline.rs b/geometry/src/outline.rs index cb1f2229..ee359005 100644 --- a/geometry/src/outline.rs +++ b/geometry/src/outline.rs @@ -10,7 +10,7 @@ //! A compressed in-memory representation of paths. -use crate::clip::ContourRectClipper; +use crate::clip::ContourClipper; use crate::line_segment::LineSegmentF32; use crate::monotonic::MonotonicConversionIter; use crate::point::Point2DF32; @@ -123,9 +123,18 @@ impl Outline { self.contours.push(contour); } + pub fn clip_against_polygon(&mut self, clip_polygon: &[Point2DF32]) { + for contour in mem::replace(&mut self.contours, vec![]) { + let contour = ContourClipper::new(clip_polygon, contour).clip(); + if !contour.is_empty() { + self.push_contour(contour); + } + } + } + pub fn clip_against_rect(&mut self, clip_rect: &Rect) { for contour in mem::replace(&mut self.contours, vec![]) { - let contour = ContourRectClipper::new(clip_rect, contour).clip(); + let contour = ContourClipper::from_rect(clip_rect, contour).clip(); if !contour.is_empty() { self.push_contour(contour); } diff --git a/geometry/src/transform3d.rs b/geometry/src/transform3d.rs index c97539a5..3861de2a 100644 --- a/geometry/src/transform3d.rs +++ b/geometry/src/transform3d.rs @@ -179,6 +179,11 @@ impl Transform3DF32 { Point4DF32(term0 + term1 + term2 + term3) } + #[inline] + pub fn transform_point_3d(&self, point: Point3DF32) -> Point3DF32 { + self.transform_point(point.to_4d()).perspective_divide() + } + #[inline] pub fn upper_left(&self) -> Matrix2x2F32 { Matrix2x2F32(self.c0.combine_axaybxby(self.c1)) @@ -200,6 +205,9 @@ impl Transform3DF32 { } // https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion + // + // If A is the upper left submatrix of this matrix, this method assumes that A and the Schur + // complement of A are invertible. pub fn inverse(&self) -> Transform3DF32 { // Extract submatrices. let (a, b) = (self.upper_left(), self.upper_right()); @@ -263,11 +271,6 @@ impl Perspective { (point + Point2DF32::splat(1.0)) * size_scale } - #[inline] - pub fn transform_point_3d(&self, point: &Point3DF32) -> Point3DF32 { - self.transform.transform_point(point.to_4d()).perspective_divide() - } - // TODO(pcwalton): SIMD? #[inline] pub fn transform_rect(&self, rect: &Rect) -> Rect { diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index a87ea461..4a7a0eb7 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -120,10 +120,16 @@ impl Scene { pub fn apply_perspective(&mut self, perspective: &Perspective) { let quad = self.clip_bounding_quad_with_perspective(perspective); - println!("bounds={:?} quad={:?}", self.bounds, quad); + println!("bounds={:?} PRE-transform quad={:?}", self.bounds, quad); + let inverse_transform = perspective.transform.inverse(); + let quad: Vec<_> = quad.into_iter().map(|point| { + inverse_transform.transform_point_3d(point).to_2d() + }).collect(); + println!("bounds={:?} POST-transform quad={:?}", self.bounds, quad); let mut bounds = Rect::zero(); for (object_index, object) in self.objects.iter_mut().enumerate() { + object.outline.clip_against_polygon(&quad); object.outline.apply_perspective(perspective); object.outline.clip_against_rect(&self.view_box); @@ -145,9 +151,13 @@ impl Scene { Point3DF32::from_euclid_2d(&self.bounds.bottom_right()), Point3DF32::from_euclid_2d(&self.bounds.bottom_left()), ]; + println!("-----"); + println!("bounds={:?} ORIGINAL quad={:?}", self.bounds, points); for point in &mut points { - *point = perspective.transform_point_3d(point); + *point = perspective.transform.transform_point_3d(*point); } + println!("PERSPECTIVE quad={:?}", points); + //points PolygonClipper3D::new(points).clip() } }