Build outlines from segments; move SIMD points into `geometry`
This commit is contained in:
parent
c8bbb71dd4
commit
8ff3da8a68
|
@ -429,9 +429,12 @@ name = "pathfinder_geometry"
|
|||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lyon_geom 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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)",
|
||||
"simdeez 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
[package]
|
||||
name = "pathfinder_geometry"
|
||||
version = "0.3.0"
|
||||
edition = "2018"
|
||||
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.4"
|
||||
euclid = "0.19"
|
||||
lyon_geom = "0.12"
|
||||
lyon_path = "0.12"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
simdeez = "0.4"
|
||||
|
|
|
@ -12,16 +12,16 @@
|
|||
//!
|
||||
//! These may be merged into upstream Lyon eventually.
|
||||
|
||||
extern crate arrayvec;
|
||||
extern crate lyon_path;
|
||||
use simdeez::sse41::Sse41;
|
||||
|
||||
use lyon_path::geom as lyon_geom;
|
||||
use lyon_path::geom::euclid;
|
||||
// TODO(pcwalton): Make this configurable.
|
||||
pub type SimdImpl = Sse41;
|
||||
|
||||
pub mod clip;
|
||||
pub mod cubic_to_quadratic;
|
||||
pub mod normals;
|
||||
pub mod orientation;
|
||||
pub mod point;
|
||||
pub mod segments;
|
||||
pub mod stroke;
|
||||
pub mod transform;
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::orientation::Orientation;
|
||||
use euclid::approxeq::ApproxEq;
|
||||
use euclid::{Point2D, Vector2D};
|
||||
use lyon_path::PathEvent;
|
||||
use orientation::Orientation;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SegmentNormals {
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
// pathfinder/geometry/src/point.rs
|
||||
//
|
||||
// Copyright © 2019 The Pathfinder Project Developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A SIMD-optimized point type.
|
||||
|
||||
use crate::SimdImpl;
|
||||
use euclid::Point2D;
|
||||
use simdeez::Simd;
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Point2DF32(pub <SimdImpl as Simd>::Vf32);
|
||||
|
||||
impl Point2DF32 {
|
||||
#[inline]
|
||||
pub fn new(x: f32, y: f32) -> Point2DF32 {
|
||||
unsafe {
|
||||
let mut data = SimdImpl::setzero_ps();
|
||||
data[0] = x;
|
||||
data[1] = y;
|
||||
Point2DF32(data)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn splat(value: f32) -> Point2DF32 {
|
||||
unsafe { Point2DF32(SimdImpl::set1_ps(value)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_euclid(point: Point2D<f32>) -> Point2DF32 {
|
||||
Point2DF32::new(point.x, point.y)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_euclid(&self) -> Point2D<f32> {
|
||||
Point2D::new(self.0[0], self.0[1])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn x(&self) -> f32 {
|
||||
self.0[0]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn y(&self) -> f32 {
|
||||
self.0[1]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn min(&self, other: Point2DF32) -> Point2DF32 {
|
||||
unsafe { Point2DF32(SimdImpl::min_ps(self.0, other.0)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max(&self, other: Point2DF32) -> Point2DF32 {
|
||||
unsafe { Point2DF32(SimdImpl::max_ps(self.0, other.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Point2DF32 {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Point2DF32) -> bool {
|
||||
unsafe {
|
||||
let results = SimdImpl::castps_epi32(SimdImpl::cmpeq_ps(self.0, other.0));
|
||||
results[0] == -1 && results[1] == -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Point2DF32 {
|
||||
#[inline]
|
||||
fn default() -> Point2DF32 {
|
||||
unsafe { Point2DF32(SimdImpl::setzero_ps()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Point2DF32> for Point2DF32 {
|
||||
type Output = Point2DF32;
|
||||
#[inline]
|
||||
fn add(self, other: Point2DF32) -> Point2DF32 {
|
||||
Point2DF32(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Point2DF32> for Point2DF32 {
|
||||
type Output = Point2DF32;
|
||||
#[inline]
|
||||
fn sub(self, other: Point2DF32) -> Point2DF32 {
|
||||
Point2DF32(self.0 - other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Point2DF32> for Point2DF32 {
|
||||
type Output = Point2DF32;
|
||||
#[inline]
|
||||
fn mul(self, other: Point2DF32) -> Point2DF32 {
|
||||
Point2DF32(self.0 * other.0)
|
||||
}
|
||||
}
|
|
@ -10,11 +10,10 @@
|
|||
|
||||
//! Utilities for converting path strokes to fills.
|
||||
|
||||
use crate::segments::{Segment, SegmentIter};
|
||||
use lyon_path::PathEvent;
|
||||
use lyon_path::iterator::PathIterator;
|
||||
|
||||
use segments::{Segment, SegmentIter};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StrokeStyle {
|
||||
pub width: f32,
|
||||
|
|
|
@ -27,6 +27,7 @@ use hashbrown::HashMap;
|
|||
use jemallocator;
|
||||
use lyon_path::PathEvent;
|
||||
use lyon_path::iterator::PathIter;
|
||||
use pathfinder_geometry::point::Point2DF32;
|
||||
use pathfinder_geometry::stroke::{StrokeStyle, StrokeToFillIter};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||
|
@ -40,7 +41,7 @@ use std::fs::File;
|
|||
use std::io::{self, BufWriter, Write};
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
use std::ops::Sub;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -236,8 +237,7 @@ impl Scene {
|
|||
let path = UsvgPathToSegments::new(path.segments.iter().cloned());
|
||||
let path = PathTransformingIter::new(path, &transform);
|
||||
let path = MonotonicConversionIter::new(path);
|
||||
let path = SegmentsToPathEvents::new(path);
|
||||
let outline = Outline::from_path_events(path);
|
||||
let outline = Outline::from_segments(path);
|
||||
|
||||
scene.bounds = scene.bounds.union(&outline.bounds);
|
||||
scene.objects.push(PathObject::new(outline,
|
||||
|
@ -258,8 +258,7 @@ impl Scene {
|
|||
let path = PathEventsToSegments::new(path);
|
||||
let path = PathTransformingIter::new(path, &transform);
|
||||
let path = MonotonicConversionIter::new(path);
|
||||
let path = SegmentsToPathEvents::new(path);
|
||||
let outline = Outline::from_path_events(path);
|
||||
let outline = Outline::from_segments(path);
|
||||
|
||||
scene.bounds = scene.bounds.union(&outline.bounds);
|
||||
scene.objects.push(PathObject::new(outline,
|
||||
|
@ -350,54 +349,48 @@ impl Outline {
|
|||
}
|
||||
}
|
||||
|
||||
// NB: Assumes the path has already been transformed.
|
||||
fn from_path_events<I>(path_events: I) -> Outline where I: Iterator<Item = PathEvent> {
|
||||
fn from_segments<I>(segments: I) -> Outline where I: Iterator<Item = Segment> {
|
||||
let mut outline = Outline::new();
|
||||
let mut current_contour = Contour::new();
|
||||
let mut bounding_points = None;
|
||||
|
||||
for path_event in path_events {
|
||||
match path_event {
|
||||
PathEvent::MoveTo(to) => {
|
||||
if !current_contour.is_empty() {
|
||||
outline.contours.push(mem::replace(&mut current_contour, Contour::new()))
|
||||
}
|
||||
current_contour.push_point(Point2DF32::from_euclid(to),
|
||||
PointFlags::empty(),
|
||||
&mut bounding_points);
|
||||
}
|
||||
PathEvent::LineTo(to) => {
|
||||
current_contour.push_point(Point2DF32::from_euclid(to),
|
||||
PointFlags::empty(),
|
||||
&mut bounding_points);
|
||||
}
|
||||
PathEvent::QuadraticTo(ctrl, to) => {
|
||||
current_contour.push_point(Point2DF32::from_euclid(ctrl),
|
||||
PointFlags::CONTROL_POINT_0,
|
||||
&mut bounding_points);
|
||||
current_contour.push_point(Point2DF32::from_euclid(to),
|
||||
PointFlags::empty(),
|
||||
&mut bounding_points);
|
||||
}
|
||||
PathEvent::CubicTo(ctrl0, ctrl1, to) => {
|
||||
current_contour.push_point(Point2DF32::from_euclid(ctrl0),
|
||||
PointFlags::CONTROL_POINT_0,
|
||||
&mut bounding_points);
|
||||
current_contour.push_point(Point2DF32::from_euclid(ctrl1),
|
||||
PointFlags::CONTROL_POINT_1,
|
||||
&mut bounding_points);
|
||||
current_contour.push_point(Point2DF32::from_euclid(to),
|
||||
PointFlags::empty(),
|
||||
&mut bounding_points);
|
||||
}
|
||||
PathEvent::Close => {
|
||||
for segment in segments {
|
||||
if segment.flags.contains(SegmentFlags::FIRST_IN_SUBPATH) {
|
||||
if !current_contour.is_empty() {
|
||||
outline.contours.push(mem::replace(&mut current_contour, Contour::new()));
|
||||
}
|
||||
current_contour.push_point(segment.baseline.from(),
|
||||
PointFlags::empty(),
|
||||
&mut bounding_points);
|
||||
}
|
||||
PathEvent::Arc(..) => unimplemented!("arcs"),
|
||||
|
||||
if segment.flags.contains(SegmentFlags::CLOSES_SUBPATH) {
|
||||
if !current_contour.is_empty() {
|
||||
outline.contours.push(mem::replace(&mut current_contour, Contour::new()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if segment.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !segment.is_line() {
|
||||
current_contour.push_point(segment.ctrl.from(),
|
||||
PointFlags::CONTROL_POINT_0,
|
||||
&mut bounding_points);
|
||||
if !segment.is_quadratic() {
|
||||
current_contour.push_point(segment.ctrl.to(),
|
||||
PointFlags::CONTROL_POINT_1,
|
||||
&mut bounding_points);
|
||||
}
|
||||
}
|
||||
|
||||
current_contour.push_point(segment.baseline.to(),
|
||||
PointFlags::empty(),
|
||||
&mut bounding_points);
|
||||
}
|
||||
|
||||
if !current_contour.is_empty() {
|
||||
outline.contours.push(current_contour)
|
||||
}
|
||||
|
@ -2179,64 +2172,6 @@ impl PartialOrd<ActiveEdge> for ActiveEdge {
|
|||
|
||||
// Geometry
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct Point2DF32(<Sse41 as Simd>::Vf32);
|
||||
|
||||
impl Point2DF32 {
|
||||
fn new(x: f32, y: f32) -> Point2DF32 {
|
||||
unsafe {
|
||||
let mut data = Sse41::setzero_ps();
|
||||
data[0] = x;
|
||||
data[1] = y;
|
||||
Point2DF32(data)
|
||||
}
|
||||
}
|
||||
|
||||
fn splat(value: f32) -> Point2DF32 { unsafe { Point2DF32(Sse41::set1_ps(value)) } }
|
||||
|
||||
fn from_euclid(point: Point2D<f32>) -> Point2DF32 { Point2DF32::new(point.x, point.y) }
|
||||
fn as_euclid(&self) -> Point2D<f32> { Point2D::new(self.0[0], self.0[1]) }
|
||||
|
||||
fn x(&self) -> f32 { self.0[0] }
|
||||
fn y(&self) -> f32 { self.0[1] }
|
||||
|
||||
fn min(&self, other: Point2DF32) -> Point2DF32 {
|
||||
unsafe { Point2DF32(Sse41::min_ps(self.0, other.0)) }
|
||||
}
|
||||
|
||||
fn max(&self, other: Point2DF32) -> Point2DF32 {
|
||||
unsafe { Point2DF32(Sse41::max_ps(self.0, other.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Point2DF32 {
|
||||
fn eq(&self, other: &Point2DF32) -> bool {
|
||||
unsafe {
|
||||
let results: <Sse41 as Simd>::Vi32 = mem::transmute(Sse41::cmpeq_ps(self.0, other.0));
|
||||
results[0] == -1 && results[1] == -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Point2DF32 {
|
||||
fn default() -> Point2DF32 { unsafe { Point2DF32(Sse41::setzero_ps()) } }
|
||||
}
|
||||
|
||||
impl Add<Point2DF32> for Point2DF32 {
|
||||
type Output = Point2DF32;
|
||||
fn add(self, other: Point2DF32) -> Point2DF32 { Point2DF32(self.0 + other.0) }
|
||||
}
|
||||
|
||||
impl Sub<Point2DF32> for Point2DF32 {
|
||||
type Output = Point2DF32;
|
||||
fn sub(self, other: Point2DF32) -> Point2DF32 { Point2DF32(self.0 - other.0) }
|
||||
}
|
||||
|
||||
impl Mul<Point2DF32> for Point2DF32 {
|
||||
type Output = Point2DF32;
|
||||
fn mul(self, other: Point2DF32) -> Point2DF32 { Point2DF32(self.0 * other.0) }
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct LineSegmentF32(pub <Sse41 as Simd>::Vf32);
|
||||
|
||||
|
|
Loading…
Reference in New Issue