From e95836387272bc75e4e0422fb5b7bae730512d4f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 29 Jan 2019 14:50:15 -0800 Subject: [PATCH] Allow scenes to be dumped as SVG (untested) and make 3D mode optional in the demo --- demo3/src/main.rs | 53 +++++++++++++++++++++++--------- geometry/src/outline.rs | 68 +++++++++++++++++++++++++++++------------ renderer/src/paint.rs | 20 +++++++++++- renderer/src/scene.rs | 29 +++++++++++++++++- 4 files changed, 134 insertions(+), 36 deletions(-) diff --git a/demo3/src/main.rs b/demo3/src/main.rs index 27514a9e..c7adb265 100644 --- a/demo3/src/main.rs +++ b/demo3/src/main.rs @@ -90,23 +90,35 @@ fn main() { let window_size = Size2D::new(drawable_width, drawable_height); let mut base_scene = load_scene(&options, &window_size); + let mut dump_transformed_scene = false; while !exit { - let rotation = Transform3DF32::from_rotation(-camera_yaw, -camera_pitch, 0.0); - camera_position = camera_position + rotation.transform_point(camera_velocity); - - let mut transform = Transform3DF32::from_perspective(FRAC_PI_4, 4.0 / 3.0, 0.01, 100.0); - transform = transform.post_mul(&Transform3DF32::from_rotation(camera_yaw, - camera_pitch, - 0.0)); - transform = transform.post_mul(&Transform3DF32::from_translation(-camera_position.x(), - -camera_position.y(), - -camera_position.z())); - transform = transform.post_mul(&Transform3DF32::from_scale(1.0 / 800.0, 1.0 / 800.0, 1.0)); - let perspective = Perspective::new(&transform, &window_size); - let mut scene = base_scene.clone(); - scene.apply_perspective(&perspective); + + if options.run_in_3d { + let rotation = Transform3DF32::from_rotation(-camera_yaw, -camera_pitch, 0.0); + camera_position = camera_position + rotation.transform_point(camera_velocity); + + let mut transform = + Transform3DF32::from_perspective(FRAC_PI_4, 4.0 / 3.0, 0.0001, 100.0); + transform = transform.post_mul(&Transform3DF32::from_rotation(camera_yaw, + camera_pitch, + 0.0)); + transform = + transform.post_mul(&Transform3DF32::from_translation(-camera_position.x(), + -camera_position.y(), + -camera_position.z())); + transform = + transform.post_mul(&Transform3DF32::from_scale(1.0 / 800.0, 1.0 / 800.0, 1.0)); + + let perspective = Perspective::new(&transform, &window_size); + scene.apply_perspective(&perspective); + } + + if dump_transformed_scene { + println!("{:?}", scene); + dump_transformed_scene = false; + } let built_scene = build_scene(&scene, &options); @@ -139,6 +151,9 @@ fn main() { Event::KeyDown { keycode: Some(Keycode::D), .. } => { camera_velocity.set_x(CAMERA_VELOCITY) } + Event::KeyDown { keycode: Some(Keycode::T), .. } => { + dump_transformed_scene = true; + } Event::KeyUp { keycode: Some(Keycode::W), .. } | Event::KeyUp { keycode: Some(Keycode::S), .. } => { camera_velocity.set_z(0.0); @@ -155,6 +170,7 @@ fn main() { struct Options { jobs: Option, + run_in_3d: bool, input_path: PathBuf, } @@ -169,6 +185,12 @@ impl Options { .takes_value(true) .help("Number of threads to use"), ) + .arg( + Arg::with_name("3d") + .short("3") + .long("3d") + .help("Run in 3D"), + ) .arg( Arg::with_name("INPUT") .help("Path to the SVG file to render") @@ -179,6 +201,7 @@ impl Options { let jobs: Option = matches .value_of("jobs") .map(|string| string.parse().unwrap()); + let run_in_3d = matches.is_present("3d"); let input_path = PathBuf::from(matches.value_of("INPUT").unwrap()); // Set up Rayon. @@ -188,7 +211,7 @@ impl Options { } thread_pool_builder.build_global().unwrap(); - Options { jobs, input_path } + Options { jobs, run_in_3d, input_path } } } diff --git a/geometry/src/outline.rs b/geometry/src/outline.rs index ee359005..40970606 100644 --- a/geometry/src/outline.rs +++ b/geometry/src/outline.rs @@ -21,7 +21,7 @@ use euclid::{Point2D, Rect, Size2D}; use std::fmt::{self, Debug, Formatter}; use std::mem; -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Outline { pub contours: Vec, bounds: Rect, @@ -142,6 +142,18 @@ impl Outline { } } +impl Debug for Outline { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + for (contour_index, contour) in self.contours.iter().enumerate() { + if contour_index > 0 { + write!(formatter, " ")?; + } + contour.fmt(formatter)?; + } + Ok(()) + } +} + impl Contour { #[inline] pub fn new() -> Contour { @@ -328,27 +340,45 @@ impl Contour { } impl Debug for Contour { - #[inline] fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("[")?; - if formatter.alternate() { - formatter.write_str("\n")? - } - for (index, segment) in self.iter().enumerate() { - if index > 0 { - formatter.write_str(" ")?; + for (segment_index, segment) in self.iter().enumerate() { + if segment_index == 0 { + write!(formatter, + "M {} {}", + segment.baseline.from_x(), + segment.baseline.from_y())?; } - if formatter.alternate() { - formatter.write_str("\n ")?; - } - segment.fmt(formatter)?; - } - if formatter.alternate() { - formatter.write_str("\n")? - } - formatter.write_str("]")?; - return Ok(()); + match segment.kind { + SegmentKind::None => {} + SegmentKind::Line => { + write!(formatter, + " L {} {}", + segment.baseline.to_x(), + segment.baseline.to_y())?; + } + SegmentKind::Quadratic => { + write!(formatter, + " Q {} {} {} {}", + segment.ctrl.from_x(), + segment.ctrl.from_y(), + segment.baseline.to_x(), + segment.baseline.to_y())?; + } + SegmentKind::Cubic => { + write!(formatter, + " C {} {} {} {} {} {}", + segment.ctrl.from_x(), + segment.ctrl.from_y(), + segment.ctrl.to_x(), + segment.ctrl.to_y(), + segment.baseline.to_x(), + segment.baseline.to_y())?; + } + } + } + + write!(formatter, " z") } } diff --git a/renderer/src/paint.rs b/renderer/src/paint.rs index 41354fda..0c30a167 100644 --- a/renderer/src/paint.rs +++ b/renderer/src/paint.rs @@ -10,6 +10,8 @@ //! How a path is to be filled. +use std::fmt::{self, Debug, Formatter}; + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Paint { pub color: ColorU, @@ -18,7 +20,7 @@ pub struct Paint { #[derive(Clone, Copy, PartialEq, Debug)] pub struct PaintId(pub u16); -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)] pub struct ColorU { pub r: u8, pub g: u8, @@ -38,6 +40,22 @@ impl ColorU { } } +impl Debug for ColorU { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + if self.a == 255 { + write!(formatter, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b) + } else { + write!(formatter, + "rgba({}, {}, {}, {})", + self.r, + self.g, + self.b, + self.a as f32 / 255.0) + } + } +} + + #[derive(Clone, Copy, Debug, PartialEq)] pub struct ShaderId(pub u16); diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index 7c2813b4..7a0d7620 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -22,8 +22,9 @@ use pathfinder_geometry::point::Point3DF32; use pathfinder_geometry::transform3d::Perspective; use pathfinder_geometry::transform::Transform2DF32; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; +use std::fmt::{self, Debug, Formatter}; -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct Scene { pub objects: Vec, pub paints: Vec, @@ -162,6 +163,27 @@ impl Scene { } } +impl Debug for Scene { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + writeln!(formatter, + "", + self.view_box.origin.x, + self.view_box.origin.y, + self.view_box.size.width, + self.view_box.size.height)?; + for object in &self.objects { + let paint = &self.paints[object.paint.0 as usize]; + write!(formatter, " ", paint.color, object.outline)?; + } + writeln!(formatter, "")?; + Ok(()) + } +} + #[derive(Clone, Debug)] pub struct PathObject { outline: Outline, @@ -187,6 +209,11 @@ impl PathObject { kind, } } + + #[inline] + pub fn outline(&self) -> &Outline { + &self.outline + } } #[inline]