diff --git a/demo3/src/main.rs b/demo3/src/main.rs index 67be668c..57d92707 100644 --- a/demo3/src/main.rs +++ b/demo3/src/main.rs @@ -24,8 +24,10 @@ use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::video::GLProfile; use std::f32::consts::FRAC_PI_4; -use std::time::Instant; +use std::panic; use std::path::PathBuf; +use std::process; +use std::time::Instant; use usvg::{Options as UsvgOptions, Tree}; #[global_allocator] @@ -259,9 +261,20 @@ fn load_scene(options: &Options, window_size: &Size2D) -> Scene { fn build_scene(scene: &Scene, options: &Options) -> BuiltScene { let z_buffer = ZBuffer::new(&scene.view_box); - let built_objects = match options.jobs { - Some(1) => scene.build_objects_sequentially(&z_buffer), - _ => scene.build_objects(&z_buffer), + let built_objects = panic::catch_unwind(|| { + match options.jobs { + Some(1) => scene.build_objects_sequentially(&z_buffer), + _ => scene.build_objects(&z_buffer), + } + }); + + let built_objects = match built_objects { + Ok(built_objects) => built_objects, + Err(_) => { + eprintln!("Scene building crashed! Dumping scene:"); + println!("{:?}", scene); + process::exit(1); + } }; let mut built_scene = BuiltScene::new(&scene.view_box); diff --git a/geometry/src/clip.rs b/geometry/src/clip.rs index a35cf2f4..29a6e053 100644 --- a/geometry/src/clip.rs +++ b/geometry/src/clip.rs @@ -11,8 +11,7 @@ use crate::line_segment::LineSegmentF32; use crate::outline::{Contour, PointFlags}; use crate::point::{Point2DF32, Point3DF32}; -use crate::segment::Segment; -use crate::simd::F32x4; +use crate::segment::{CubicSegment, Segment}; use crate::util::lerp; use arrayvec::ArrayVec; use euclid::Rect; @@ -198,72 +197,37 @@ impl Edge { -> Option { /*println!("... intersect_cubic_segment({:?}, {:?}, t=({}, {}))", self, segment, t_min, t_max);*/ - let cubic_segment = segment.as_cubic_segment(); + let mut segment = segment.as_cubic_segment().split_after(t_min); + segment = segment.as_cubic_segment().split_before(t_max / (1.0 - t_min)); + + if !self.intersects_cubic_segment_hull(segment.as_cubic_segment()) { + return None + } + loop { let t_mid = lerp(t_min, t_max, 0.5); if t_max - t_min < 0.00001 { return Some(t_mid); } - let min_sign = self.point_is_inside(&cubic_segment.sample(t_min)); - let mid_sign = self.point_is_inside(&cubic_segment.sample(t_mid)); - let max_sign = self.point_is_inside(&cubic_segment.sample(t_max)); - /*println!("... ... ({}, {}, {}) ({}, {}, {})", - t_min, t_mid, t_max, - min_sign, mid_sign, max_sign);*/ - - match (min_sign == mid_sign, max_sign == mid_sign) { - (true, false) => t_min = t_mid, - (false, true) => t_max = t_mid, - _ => return None, + let (prev_segment, next_segment) = segment.as_cubic_segment().split(0.5); + if self.intersects_cubic_segment_hull(prev_segment.as_cubic_segment()) { + t_max = t_mid; + segment = prev_segment; + } else if self.intersects_cubic_segment_hull(next_segment.as_cubic_segment()) { + t_min = t_mid; + segment = next_segment; + } else { + return None; } } } - fn fixup_clipped_segments(&self, segment: &(Segment, Segment)) -> Option<(Segment, Segment)> { - let (mut prev, mut next) = *segment; - - let point = prev.baseline.to(); - - let line_coords = self.0.line_coords(); - let (a, b, c) = (line_coords[0], line_coords[1], line_coords[2]); - let denom = 1.0 / (a * a + b * b); - let factor = b * point.x() - a * point.y(); - let snapped = Point2DF32::new(b * factor - a * c, a * -factor - b * c) * - Point2DF32::splat(denom); - - prev.baseline.set_to(&snapped); - next.baseline.set_from(&snapped); - - // FIXME(pcwalton): Do this more efficiently... - // FIXME(pcwalton): Remove duplication! - if self.0.from_x() == self.0.to_x() { - let x = self.0.from_x(); - prev.baseline.set_to_x(x); - next.baseline.set_from_x(x); - } - if self.0.from_y() == self.0.to_y() { - let y = self.0.from_y(); - prev.baseline.set_to_y(y); - next.baseline.set_from_y(y); - } - - if prev.is_tiny() { - return None - } - - /*match *self { - Edge::Left(x) | Edge::Right(x) => { - before.baseline.set_to_x(x); - after.baseline.set_from_x(x); - } - Edge::Top(y) | Edge::Bottom(y) => { - before.baseline.set_to_y(y); - after.baseline.set_from_y(y); - } - }*/ - - Some((prev, next)) + fn intersects_cubic_segment_hull(&self, cubic_segment: CubicSegment) -> bool { + let inside = self.point_is_inside(&cubic_segment.0.baseline.from()); + inside != self.point_is_inside(&cubic_segment.0.ctrl.from()) || + inside != self.point_is_inside(&cubic_segment.0.ctrl.to()) || + inside != self.point_is_inside(&cubic_segment.0.baseline.to()) } } diff --git a/geometry/src/outline.rs b/geometry/src/outline.rs index 958d018c..1d13246e 100644 --- a/geometry/src/outline.rs +++ b/geometry/src/outline.rs @@ -320,9 +320,6 @@ impl Contour { *point = transform.transform_point(point); union_rect(&mut self.bounds, *point, point_index == 0); } - - // TODO(pcwalton): Skip this step if the transform is rectilinear. - self.make_monotonic(); } #[inline] @@ -331,8 +328,6 @@ impl Contour { *point = perspective.transform_point_2d(point); union_rect(&mut self.bounds, *point, point_index == 0); } - - self.make_monotonic(); } #[inline] diff --git a/geometry/src/segment.rs b/geometry/src/segment.rs index d7563a92..52d6ec67 100644 --- a/geometry/src/segment.rs +++ b/geometry/src/segment.rs @@ -172,7 +172,7 @@ bitflags! { } #[derive(Clone, Copy, Debug)] -pub struct CubicSegment<'s>(&'s Segment); +pub struct CubicSegment<'s>(pub &'s Segment); impl<'s> CubicSegment<'s> { // See Kaspar Fischer, "Piecewise Linear Approximation of Bézier Curves", 2000. @@ -199,41 +199,61 @@ impl<'s> CubicSegment<'s> { #[inline] pub fn split(self, t: f32) -> (Segment, Segment) { - let tttt = F32x4::splat(t); + let (baseline0, ctrl0, baseline1, ctrl1); + if t <= 0.0 { + let from = &self.0.baseline.from(); + baseline0 = LineSegmentF32::new(from, from); + ctrl0 = LineSegmentF32::new(from, from); + baseline1 = self.0.baseline; + ctrl1 = self.0.ctrl; + } else if t >= 1.0 { + let to = &self.0.baseline.to(); + baseline0 = self.0.baseline; + ctrl0 = self.0.ctrl; + baseline1 = LineSegmentF32::new(to, to); + ctrl1 = LineSegmentF32::new(to, to); + } else { + let tttt = F32x4::splat(t); - let (p0p3, p1p2) = (self.0.baseline.0, self.0.ctrl.0); - let p0p1 = p0p3.combine_axaybxby(p1p2); + let (p0p3, p1p2) = (self.0.baseline.0, self.0.ctrl.0); + let p0p1 = p0p3.combine_axaybxby(p1p2); - // p01 = lerp(p0, p1, t), p12 = lerp(p1, p2, t), p23 = lerp(p2, p3, t) - let p01p12 = p0p1 + tttt * (p1p2 - p0p1); - let pxxp23 = p1p2 + tttt * (p0p3 - p1p2); - let p12p23 = p01p12.combine_azawbzbw(pxxp23); + // p01 = lerp(p0, p1, t), p12 = lerp(p1, p2, t), p23 = lerp(p2, p3, t) + let p01p12 = p0p1 + tttt * (p1p2 - p0p1); + let pxxp23 = p1p2 + tttt * (p0p3 - p1p2); + let p12p23 = p01p12.combine_azawbzbw(pxxp23); - // p012 = lerp(p01, p12, t), p123 = lerp(p12, p23, t) - let p012p123 = p01p12 + tttt * (p12p23 - p01p12); - let p123 = p012p123.zwzw(); + // p012 = lerp(p01, p12, t), p123 = lerp(p12, p23, t) + let p012p123 = p01p12 + tttt * (p12p23 - p01p12); + let p123 = p012p123.zwzw(); - // p0123 = lerp(p012, p123, t) - let p0123 = p012p123 + tttt * (p123 - p012p123); + // p0123 = lerp(p012, p123, t) + let p0123 = p012p123 + tttt * (p123 - p012p123); - let baseline0 = p0p3.combine_axaybxby(p0123); - let ctrl0 = p01p12.combine_axaybxby(p012p123); - let baseline1 = p0123.combine_axaybzbw(p0p3); - let ctrl1 = p012p123.combine_azawbzbw(p12p23); + baseline0 = LineSegmentF32(p0p3.combine_axaybxby(p0123)); + ctrl0 = LineSegmentF32(p01p12.combine_axaybxby(p012p123)); + baseline1 = LineSegmentF32(p0123.combine_axaybzbw(p0p3)); + ctrl1 = LineSegmentF32(p012p123.combine_azawbzbw(p12p23)); + } (Segment { - baseline: LineSegmentF32(baseline0), - ctrl: LineSegmentF32(ctrl0), + baseline: baseline0, + ctrl: ctrl0, kind: SegmentKind::Cubic, flags: self.0.flags & SegmentFlags::FIRST_IN_SUBPATH, }, Segment { - baseline: LineSegmentF32(baseline1), - ctrl: LineSegmentF32(ctrl1), + baseline: baseline1, + ctrl: ctrl1, kind: SegmentKind::Cubic, flags: self.0.flags & SegmentFlags::CLOSES_SUBPATH, }) } + #[inline] + pub fn split_before(self, t: f32) -> Segment { + self.split(t).0 + } + #[inline] pub fn split_after(self, t: f32) -> Segment { self.split(t).1 diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 3daed811..1dc19503 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -118,6 +118,7 @@ impl Scene { pub fn prepare(&mut self) { for object in &mut self.objects { + object.outline.clip_against_rect(&self.view_box); object.outline.make_monotonic(); } } @@ -126,6 +127,7 @@ impl Scene { for object in &mut self.objects { object.outline.transform(transform); object.outline.clip_against_rect(&self.view_box); + object.outline.make_monotonic(); } self.update_bounds(); @@ -146,6 +148,7 @@ impl Scene { object.outline.clip_against_polygon(&quad); object.outline.apply_perspective(perspective); object.outline.clip_against_rect(&self.view_box); + object.outline.make_monotonic(); } self.update_bounds(); @@ -159,6 +162,7 @@ impl Scene { object.outline.clip_against_polygon(&quad); object.outline.apply_perspective(perspective); object.outline.clip_against_rect(&view_box); + object.outline.make_monotonic(); }); self.update_bounds();