First draft of switch to quadratic Béziers

This commit is contained in:
Patrick Walton 2017-07-10 20:07:10 -07:00
parent 49026ae3c3
commit a7ba7d200e
7 changed files with 166 additions and 245 deletions

View File

@ -7,7 +7,7 @@ use partitioner::Partitioner;
use tessellator::{QuadTessLevels, Tessellator};
use std::mem;
use std::slice;
use {AntialiasingMode, BQuad, ControlPoints, EdgeInstance, Endpoint, Subpath, Vertex};
use {AntialiasingMode, BQuad, EdgeInstance, Endpoint, Subpath, Vertex};
#[derive(Clone, Copy)]
#[repr(C)]
@ -61,12 +61,13 @@ pub unsafe extern fn pf_legalizer_endpoints(legalizer: *const Legalizer,
#[no_mangle]
pub unsafe extern fn pf_legalizer_control_points(legalizer: *const Legalizer,
out_control_points_count: *mut u32)
-> *const ControlPoints {
-> *const Point2DF32 {
let control_points = (*legalizer).control_points();
if !out_control_points_count.is_null() {
*out_control_points_count = control_points.len() as u32
}
control_points.as_ptr()
// FIXME(pcwalton): This is unsafe! `Point2D<f32>` and `Point2DF32` may have different layouts!
control_points.as_ptr() as *const Point2DF32
}
#[no_mangle]
@ -131,12 +132,14 @@ pub unsafe extern fn pf_partitioner_destroy<'a>(partitioner: *mut Partitioner<'a
pub unsafe extern fn pf_partitioner_init<'a>(partitioner: *mut Partitioner<'a>,
endpoints: *const Endpoint,
endpoint_count: u32,
control_points: *const ControlPoints,
control_points: *const Point2DF32,
control_points_count: u32,
subpaths: *const Subpath,
subpath_count: u32) {
// FIXME(pcwalton): This is unsafe! `Point2D<f32>` and `Point2DF32` may have different layouts!
(*partitioner).init(slice::from_raw_parts(endpoints, endpoint_count as usize),
slice::from_raw_parts(control_points, control_points_count as usize),
slice::from_raw_parts(control_points as *const Point2D<f32>,
control_points_count as usize),
slice::from_raw_parts(subpaths, subpath_count as usize))
}
@ -161,12 +164,13 @@ pub unsafe extern fn pf_partitioner_b_quads<'a>(partitioner: *mut Partitioner<'a
#[no_mangle]
pub unsafe extern fn pf_tessellator_new(endpoints: *const Endpoint,
endpoint_count: u32,
control_points: *const ControlPoints,
control_points: *const Point2D<f32>,
control_points_count: u32,
b_quads: *const BQuad,
b_quad_count: u32,
antialiasing_mode: AntialiasingMode)
-> *mut Tessellator<'static> {
// FIXME(pcwalton): This is unsafe! `Point2D<f32>` and `Point2DF32` may have different layouts!
let mut tessellator =
Box::new(Tessellator::new(slice::from_raw_parts(endpoints, endpoint_count as usize),
slice::from_raw_parts(control_points,

View File

@ -59,61 +59,48 @@ pub fn line_line_crossing_point(a_p0: &Point2D<f32>,
}
// TODO(pcwalton): Implement this.
pub fn line_cubic_bezier_crossing_point(_a_p0: &Point2D<f32>,
_a_p1: &Point2D<f32>,
_b_p0: &Point2D<f32>,
_b_p1: &Point2D<f32>,
_b_p2: &Point2D<f32>,
_b_p3: &Point2D<f32>)
pub fn line_quadratic_bezier_crossing_point(_a_p0: &Point2D<f32>,
_a_p1: &Point2D<f32>,
_b_p0: &Point2D<f32>,
_b_p1: &Point2D<f32>,
_b_p2: &Point2D<f32>)
-> Option<Point2D<f32>> {
None
}
// TODO(pcwalton): Implement this.
pub fn cubic_bezier_cubic_bezier_crossing_point(_a_p0: &Point2D<f32>,
_a_p1: &Point2D<f32>,
_a_p2: &Point2D<f32>,
_a_p3: &Point2D<f32>,
_b_p0: &Point2D<f32>,
_b_p1: &Point2D<f32>,
_b_p2: &Point2D<f32>,
_b_p3: &Point2D<f32>)
-> Option<Point2D<f32>> {
pub fn quadratic_bezier_quadratic_bezier_crossing_point(_a_p0: &Point2D<f32>,
_a_p1: &Point2D<f32>,
_a_p2: &Point2D<f32>,
_b_p0: &Point2D<f32>,
_b_p1: &Point2D<f32>,
_b_p2: &Point2D<f32>)
-> Option<Point2D<f32>> {
None
}
fn sample_cubic_bezier(t: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>,
p3: &Point2D<f32>)
-> Point2D<f32> {
let (p0p1, p1p2, p2p3) = (p0.lerp(*p1, t), p1.lerp(*p2, t), p2.lerp(*p3, t));
let (p0p1p2, p1p2p3) = (p0p1.lerp(p1p2, t), p1p2.lerp(p2p3, t));
p0p1p2.lerp(p1p2p3, t)
fn sample_quadratic_bezier(t: f32, p0: &Point2D<f32>, p1: &Point2D<f32>, p2: &Point2D<f32>)
-> Point2D<f32> {
p0.lerp(*p1, t).lerp(p1.lerp(*p2, t), t)
}
pub fn sample_cubic_bezier_deriv(t: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>,
p3: &Point2D<f32>)
-> Vector2D<f32> {
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves
pub fn sample_quadratic_bezier_deriv(t: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>)
-> Vector2D<f32> {
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Quadratic_B.C3.A9zier_curves
// FIXME(pcwalton): Can this be made faster?
let tt = 1.0 - t;
return (*p1 - *p0) * 3.0 * tt * tt + (*p2 - *p1) * 6.0 * tt * t + (*p3 - *p2) * 3.0 * t * t
return ((*p1 - *p0) * (1.0 - t) + (*p2 - *p1) * t) * 2.0
}
pub fn sample_cubic_bezier_deriv_deriv(t: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>,
p3: &Point2D<f32>)
-> Vector2D<f32> {
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves
pub fn sample_quadratic_bezier_deriv_deriv(p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>)
-> Vector2D<f32> {
// https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Quadratic_B.C3.A9zier_curves
// FIXME(pcwalton): Can this be made faster?
(*p2 - *p1 * 2.0 + p0.to_vector()).lerp(*p3 - *p2 * 2.0 + p1.to_vector(), t) * 6.0
(*p2 - *p1 * 2.0 + p0.to_vector()) * 2.0
}
pub fn solve_line_y_for_x(x: f32, a: &Point2D<f32>, b: &Point2D<f32>) -> f32 {
@ -133,51 +120,45 @@ pub(crate) fn newton_raphson<F, DFDX>(f: F, dfdx: DFDX, mut x_guess: f32) -> f32
x_guess
}
pub fn solve_cubic_bezier_t_for_x(x: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>,
p3: &Point2D<f32>)
-> f32 {
newton_raphson(|t| sample_cubic_bezier(t, p0, p1, p2, p3).x - x,
|t| sample_cubic_bezier_deriv(t, p0, p1, p2, p3).x,
pub fn solve_quadratic_bezier_t_for_x(x: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>)
-> f32 {
// TODO(pcwalton): Use the quadratic equation instead.
newton_raphson(|t| sample_quadratic_bezier(t, p0, p1, p2).x - x,
|t| sample_quadratic_bezier_deriv(t, p0, p1, p2).x,
0.5)
}
pub fn solve_cubic_bezier_y_for_x(x: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>,
p3: &Point2D<f32>)
-> f32 {
sample_cubic_bezier(solve_cubic_bezier_t_for_x(x, p0, p1, p2, p3), p0, p1, p2, p3).y
pub fn solve_quadratic_bezier_y_for_x(x: f32,
p0: &Point2D<f32>,
p1: &Point2D<f32>,
p2: &Point2D<f32>)
-> f32 {
sample_quadratic_bezier(solve_quadratic_bezier_t_for_x(x, p0, p1, p2), p0, p1, p2).y
}
#[derive(Clone, Copy, Debug)]
pub struct SubdividedCubicBezier {
pub struct SubdividedQuadraticBezier {
pub ap0: Point2D<f32>,
pub ap1: Point2D<f32>,
pub ap2: Point2D<f32>,
pub ap3bp0: Point2D<f32>,
pub ap2bp0: Point2D<f32>,
pub bp1: Point2D<f32>,
pub bp2: Point2D<f32>,
pub bp3: Point2D<f32>,
}
impl SubdividedCubicBezier {
pub fn new(t: f32, p0: &Point2D<f32>, p1: &Point2D<f32>, p2: &Point2D<f32>, p3: &Point2D<f32>)
-> SubdividedCubicBezier {
let (ap1, p1p2, bp2) = (p0.lerp(*p1, t), p1.lerp(*p2, t), p2.lerp(*p3, t));
let (ap2, bp1) = (ap1.lerp(p1p2, t), (p1p2.lerp(bp2, t)));
let ap3bp0 = ap2.lerp(bp1, t);
SubdividedCubicBezier {
impl SubdividedQuadraticBezier {
pub fn new(t: f32, p0: &Point2D<f32>, p1: &Point2D<f32>, p2: &Point2D<f32>)
-> SubdividedQuadraticBezier {
let (ap1, bp1) = (p0.lerp(*p1, t), p1.lerp(*p2, t));
let ap2bp0 = ap1.lerp(bp1, t);
SubdividedQuadraticBezier {
ap0: *p0,
ap1: ap1,
ap2: ap2,
ap3bp0: ap3bp0,
ap2bp0: ap2bp0,
bp1: bp1,
bp2: bp2,
bp3: *p3,
bp2: *p2,
}
}
}

View File

@ -1,15 +1,12 @@
// partitionfinder/legalizer.rs
use euclid::Point2D;
use geometry::{self, ApproxOrdered, SubdividedCubicBezier};
use std::u32;
use {ControlPoints, Endpoint, Subpath};
const MAX_SUBDIVISIONS: u8 = 16;
use {Endpoint, Subpath};
pub struct Legalizer {
endpoints: Vec<Endpoint>,
control_points: Vec<ControlPoints>,
control_points: Vec<Point2D<f32>>,
subpaths: Vec<Subpath>,
}
@ -29,7 +26,7 @@ impl Legalizer {
}
#[inline]
pub fn control_points(&self) -> &[ControlPoints] {
pub fn control_points(&self) -> &[Point2D<f32>] {
&self.control_points
}
@ -45,7 +42,7 @@ impl Legalizer {
});
self.endpoints.push(Endpoint {
position: *position,
control_points_index: u32::MAX,
control_point_index: u32::MAX,
subpath_index: (self.subpaths.len() - 1) as u32,
})
}
@ -62,82 +59,39 @@ impl Legalizer {
.last_endpoint_index += 1;
self.endpoints.push(Endpoint {
position: *endpoint,
control_points_index: u32::MAX,
control_point_index: u32::MAX,
subpath_index: (self.subpaths.len() - 1) as u32,
})
}
#[inline]
pub fn quadratic_curve_to(&mut self, control_point: &Point2D<f32>, endpoint: &Point2D<f32>) {
self.bezier_curve_to(control_point, control_point, endpoint)
self.subpaths
.last_mut()
.expect("`line_to()` called with no current subpath")
.last_endpoint_index += 1;
self.endpoints.push(Endpoint {
position: *endpoint,
control_point_index: self.control_points.len() as u32,
subpath_index: (self.subpaths.len() - 1) as u32,
});
self.control_points.push(*control_point)
}
pub fn bezier_curve_to(&mut self,
point1: &Point2D<f32>,
point2: &Point2D<f32>,
endpoint: &Point2D<f32>) {
self.bezier_curve_to_subdividing_if_necessary(point1, point2, endpoint, 0)
}
fn bezier_curve_to_subdividing_if_necessary(&mut self,
point1: &Point2D<f32>,
point2: &Point2D<f32>,
endpoint: &Point2D<f32>,
iteration: u8) {
// https://stackoverflow.com/a/2029695
//
// FIXME(pcwalton): Reimplement subdivision!
let last_endpoint_index = self.subpaths
.last()
.expect("`bezier_curve_to()` called with no current_subpath")
.expect("`bezier_curve_to()` called with no current subpath")
.last_endpoint_index;
let point0 = self.endpoints[last_endpoint_index as usize - 1].position;
if iteration >= MAX_SUBDIVISIONS ||
[point0.x, point1.x, point2.x, endpoint.x].approx_ordered() {
return self.monotone_bezier_curve_to(point1, point2, endpoint)
}
let t = geometry::newton_raphson(|t| {
geometry::sample_cubic_bezier_deriv(t,
&point0,
point1,
point2,
endpoint).x
},
|t| {
geometry::sample_cubic_bezier_deriv_deriv(t,
&point0,
point1,
point2,
endpoint).x
},
0.5);
let subdivision = SubdividedCubicBezier::new(t, &point0, point1, point2, endpoint);
self.bezier_curve_to_subdividing_if_necessary(&subdivision.ap1,
&subdivision.ap2,
&subdivision.ap3bp0,
iteration + 1);
self.bezier_curve_to_subdividing_if_necessary(&subdivision.bp1,
&subdivision.bp2,
&subdivision.bp3,
iteration + 1);
}
fn monotone_bezier_curve_to(&mut self,
point1: &Point2D<f32>,
point2: &Point2D<f32>,
endpoint: &Point2D<f32>) {
self.subpaths
.last_mut()
.expect("`bezier_curve_to()` called with no current subpath")
.last_endpoint_index += 1;
self.control_points.push(ControlPoints {
point1: *point1,
point2: *point2,
});
self.endpoints.push(Endpoint {
position: *endpoint,
control_points_index: (self.control_points.len() - 1) as u32,
subpath_index: (self.subpaths.len() - 1) as u32,
})
let control_point = ((point1.to_vector() + point2.to_vector()) * 0.75 -
(point0.to_vector() + endpoint.to_vector()) * 0.25).to_point();
self.quadratic_curve_to(&control_point, endpoint)
}
}

View File

@ -38,17 +38,10 @@ pub struct BQuad {
pub struct Endpoint {
pub position: Point2D<f32>,
/// `u32::MAX` if not present.
pub control_points_index: u32,
pub control_point_index: u32,
pub subpath_index: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ControlPoints {
pub point1: Point2D<f32>,
pub point2: Point2D<f32>,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Subpath {

View File

@ -7,11 +7,11 @@ use log::LogLevel;
use std::collections::BinaryHeap;
use std::cmp::{self, Ordering};
use std::u32;
use {BQuad, ControlPoints, Endpoint, Subpath};
use {BQuad, Endpoint, Subpath};
pub struct Partitioner<'a> {
endpoints: &'a [Endpoint],
control_points: &'a [ControlPoints],
control_points: &'a [Point2D<f32>],
subpaths: &'a [Subpath],
b_quads: Vec<BQuad>,
@ -39,7 +39,7 @@ impl<'a> Partitioner<'a> {
pub fn init(&mut self,
new_endpoints: &'a [Endpoint],
new_control_points: &'a [ControlPoints],
new_control_points: &'a [Point2D<f32>],
new_subpaths: &'a [Subpath]) {
self.endpoints = new_endpoints;
self.control_points = new_control_points;
@ -374,18 +374,17 @@ impl<'a> Partitioner<'a> {
let next_endpoint_index = active_edge.next_endpoint_index();
let prev_endpoint = &self.endpoints[prev_endpoint_index as usize];
let next_endpoint = &self.endpoints[next_endpoint_index as usize];
match self.control_points_index(next_endpoint_index) {
match self.control_point_index(next_endpoint_index) {
None => {
let x_vector = next_endpoint.position.x - prev_endpoint.position.x;
(x - prev_endpoint.position.x) / x_vector
}
Some(control_points_index) => {
let control_points = &self.control_points[control_points_index as usize];
geometry::solve_cubic_bezier_t_for_x(x,
&prev_endpoint.position,
&control_points.point1,
&control_points.point2,
&next_endpoint.position)
Some(control_point_index) => {
let control_point = &self.control_points[control_point_index as usize];
geometry::solve_quadratic_bezier_t_for_x(x,
&prev_endpoint.position,
control_point,
&next_endpoint.position)
}
}
}
@ -403,7 +402,7 @@ impl<'a> Partitioner<'a> {
fn solve_active_edge_y_for_x(&self, x: f32, active_edge: &ActiveEdge) -> f32 {
let prev_endpoint_index = active_edge.prev_endpoint_index();
let next_endpoint_index = active_edge.next_endpoint_index();
if self.control_points_index(next_endpoint_index).is_none() {
if self.control_point_index(next_endpoint_index).is_none() {
self.solve_line_y_for_x(x, prev_endpoint_index, next_endpoint_index)
} else {
self.solve_cubic_bezier_y_for_x(x, prev_endpoint_index, next_endpoint_index)
@ -421,20 +420,19 @@ impl<'a> Partitioner<'a> {
-> f32 {
let prev_endpoint = &self.endpoints[prev_endpoint_index as usize];
let next_endpoint = &self.endpoints[next_endpoint_index as usize];
let control_points_index = self.control_points_index(next_endpoint_index)
let control_point_index = self.control_point_index(next_endpoint_index)
.expect("Edge not a cubic bezier!");
let control_points = &self.control_points[control_points_index as usize];
geometry::solve_cubic_bezier_y_for_x(x,
&prev_endpoint.position,
&control_points.point1,
&control_points.point2,
&next_endpoint.position)
let control_point = &self.control_points[control_point_index as usize];
geometry::solve_quadratic_bezier_y_for_x(x,
&prev_endpoint.position,
&control_point,
&next_endpoint.position)
}
fn control_points_index(&self, next_endpoint_index: u32) -> Option<u32> {
match self.endpoints[next_endpoint_index as usize].control_points_index {
fn control_point_index(&self, next_endpoint_index: u32) -> Option<u32> {
match self.endpoints[next_endpoint_index as usize].control_point_index {
u32::MAX => None,
control_points_index => Some(control_points_index),
control_point_index => Some(control_point_index),
}
}
@ -486,12 +484,12 @@ impl<'a> Partitioner<'a> {
let next_upper_endpoint_index = upper_active_edge.next_endpoint_index();
let prev_lower_endpoint_index = lower_active_edge.prev_endpoint_index();
let next_lower_endpoint_index = lower_active_edge.next_endpoint_index();
let upper_control_points_index = self.endpoints[next_upper_endpoint_index as usize]
.control_points_index;
let lower_control_points_index = self.endpoints[next_lower_endpoint_index as usize]
.control_points_index;
let upper_control_point_index = self.endpoints[next_upper_endpoint_index as usize]
.control_point_index;
let lower_control_point_index = self.endpoints[next_lower_endpoint_index as usize]
.control_point_index;
match (upper_control_points_index, lower_control_points_index) {
match (upper_control_point_index, lower_control_point_index) {
(u32::MAX, u32::MAX) => {
self.line_line_crossing_point(prev_upper_endpoint_index,
next_upper_endpoint_index,
@ -499,22 +497,22 @@ impl<'a> Partitioner<'a> {
next_lower_endpoint_index)
}
(u32::MAX, _) => {
self.line_cubic_bezier_crossing_point(prev_upper_endpoint_index,
next_upper_endpoint_index,
next_lower_endpoint_index,
next_lower_endpoint_index)
self.line_quadratic_bezier_crossing_point(prev_upper_endpoint_index,
next_upper_endpoint_index,
next_lower_endpoint_index,
next_lower_endpoint_index)
}
(_, u32::MAX) => {
self.line_cubic_bezier_crossing_point(prev_lower_endpoint_index,
next_lower_endpoint_index,
next_upper_endpoint_index,
next_upper_endpoint_index)
self.line_quadratic_bezier_crossing_point(prev_lower_endpoint_index,
next_lower_endpoint_index,
next_upper_endpoint_index,
next_upper_endpoint_index)
}
(_, _) => {
self.cubic_bezier_cubic_bezier_crossing_point(prev_upper_endpoint_index,
next_upper_endpoint_index,
prev_lower_endpoint_index,
next_lower_endpoint_index)
self.quadratic_bezier_quadratic_bezier_crossing_point(prev_upper_endpoint_index,
next_upper_endpoint_index,
prev_lower_endpoint_index,
next_lower_endpoint_index)
}
}
}
@ -532,44 +530,41 @@ impl<'a> Partitioner<'a> {
&endpoints[next_lower_endpoint_index as usize].position)
}
fn line_cubic_bezier_crossing_point(&self,
prev_line_endpoint_index: u32,
next_line_endpoint_index: u32,
prev_bezier_endpoint_index: u32,
next_bezier_endpoint_index: u32)
-> Option<Point2D<f32>> {
let control_points_index = self.control_points_index(next_bezier_endpoint_index)
.expect("Edge not a cubic Bezier!");
let control_points = &self.control_points[control_points_index as usize];
geometry::line_cubic_bezier_crossing_point(
fn line_quadratic_bezier_crossing_point(&self,
prev_line_endpoint_index: u32,
next_line_endpoint_index: u32,
prev_bezier_endpoint_index: u32,
next_bezier_endpoint_index: u32)
-> Option<Point2D<f32>> {
let control_point_index = self.control_point_index(next_bezier_endpoint_index)
.expect("Edge not a quadratic Bezier!");
let control_point = &self.control_points[control_point_index as usize];
geometry::line_quadratic_bezier_crossing_point(
&self.endpoints[prev_line_endpoint_index as usize].position,
&self.endpoints[next_line_endpoint_index as usize].position,
&self.endpoints[prev_bezier_endpoint_index as usize].position,
&control_points.point1,
&control_points.point2,
control_point,
&self.endpoints[next_bezier_endpoint_index as usize].position)
}
fn cubic_bezier_cubic_bezier_crossing_point(&self,
prev_upper_endpoint_index: u32,
next_upper_endpoint_index: u32,
prev_lower_endpoint_index: u32,
next_lower_endpoint_index: u32)
-> Option<Point2D<f32>> {
let upper_control_points_index = self.control_points_index(next_upper_endpoint_index)
.expect("Upper edge not a cubic Bezier!");
let upper_control_points = &self.control_points[upper_control_points_index as usize];
let lower_control_points_index = self.control_points_index(next_lower_endpoint_index)
.expect("Lower edge not a cubic Bezier!");
let lower_control_points = &self.control_points[lower_control_points_index as usize];
geometry::cubic_bezier_cubic_bezier_crossing_point(
fn quadratic_bezier_quadratic_bezier_crossing_point(&self,
prev_upper_endpoint_index: u32,
next_upper_endpoint_index: u32,
prev_lower_endpoint_index: u32,
next_lower_endpoint_index: u32)
-> Option<Point2D<f32>> {
let upper_control_point_index = self.control_point_index(next_upper_endpoint_index)
.expect("Upper edge not a quadratic Bezier!");
let upper_control_point = &self.control_points[upper_control_point_index as usize];
let lower_control_point_index = self.control_point_index(next_lower_endpoint_index)
.expect("Lower edge not a quadratic Bezier!");
let lower_control_point = &self.control_points[lower_control_point_index as usize];
geometry::quadratic_bezier_quadratic_bezier_crossing_point(
&self.endpoints[prev_upper_endpoint_index as usize].position,
&upper_control_points.point1,
&upper_control_points.point2,
upper_control_point,
&self.endpoints[next_upper_endpoint_index as usize].position,
&self.endpoints[prev_lower_endpoint_index as usize].position,
&lower_control_points.point1,
&lower_control_points.point2,
lower_control_point,
&self.endpoints[next_lower_endpoint_index as usize].position)
}

View File

@ -71,12 +71,6 @@ struct pf_endpoint {
typedef struct pf_endpoint pf_endpoint_t;
struct pf_control_points {
pf_point2d_f32_t point1, point2;
};
typedef struct pf_control_points pf_control_points_t;
struct pf_subpath {
uint32_t first_endpoint_index;
uint32_t last_endpoint_index;
@ -103,8 +97,8 @@ void pf_legalizer_destroy(pf_legalizer_t *legalizer);
const pf_endpoint_t *pf_legalizer_endpoints(const pf_legalizer_t *legalizer,
uint32_t *out_endpoint_count);
const pf_control_points_t *pf_legalizer_control_points(const pf_legalizer_t *legalizer,
uint32_t *out_control_points_count);
const pf_point2d_f32_t *pf_legalizer_control_points(const pf_legalizer_t *legalizer,
uint32_t *out_control_point_count);
const pf_subpath_t *pf_legalizer_subpaths(const pf_legalizer_t *legalizer,
uint32_t *out_subpaths_count);
@ -131,8 +125,8 @@ void pf_partitioner_destroy(pf_partitioner_t *partitioner);
void pf_partitioner_init(pf_partitioner_t *partitioner,
const pf_endpoint_t *endpoints,
uint32_t endpoint_count,
const pf_control_points_t *control_points,
uint32_t control_points_count,
const pf_point2d_f32_t *control_points,
uint32_t control_point_count,
const pf_subpath_t *subpaths,
uint32_t subpath_count);
@ -145,8 +139,8 @@ const pf_b_quad_t *pf_partitioner_b_quads(pf_partitioner_t *partitioner,
pf_tessellator_t *pf_tessellator_new(const pf_endpoint_t *endpoints,
uint32_t endpoint_count,
const pf_control_points_t *control_points,
uint32_t control_points_index,
const pf_point2d_f32_t *control_points,
uint32_t control_point_index,
const pf_b_quad_t *b_quads,
uint32_t b_quad_count,
pf_antialiasing_mode_t antialiasing_mode);

View File

@ -2,17 +2,17 @@
#![allow(dead_code)]
use euclid::{Length, Transform2D};
use euclid::{Length, Point2D, Transform2D};
use half::{f16, self};
use std::cmp;
use std::u32;
use {AntialiasingMode, BQuad, ControlPoints, EdgeInstance, Endpoint, Vertex};
use {AntialiasingMode, BQuad, EdgeInstance, Endpoint, Vertex};
const TOLERANCE: f32 = 0.25;
pub struct Tessellator<'a> {
endpoints: &'a [Endpoint],
control_points: &'a [ControlPoints],
control_points: &'a [Point2D<f32>],
b_quads: &'a [BQuad],
antialiasing_mode: AntialiasingMode,
@ -42,7 +42,7 @@ impl QuadTessLevels {
impl<'a> Tessellator<'a> {
pub fn new<'b>(endpoints: &'b [Endpoint],
control_points: &'b [ControlPoints],
control_points: &'b [Point2D<f32>],
b_quads: &'b [BQuad],
antialiasing_mode: AntialiasingMode)
-> Tessellator<'b> {
@ -190,10 +190,10 @@ fn tess_level_for_edge(prev_endpoint_index: u32,
right_time: f32,
transform: &Transform2D<f32>,
endpoints: &[Endpoint],
control_points: &[ControlPoints])
control_points: &[Point2D<f32>])
-> u32 {
let control_points_index = endpoints[next_endpoint_index as usize].control_points_index;
if control_points_index == u32::MAX {
let control_point_index = endpoints[next_endpoint_index as usize].control_point_index;
if control_point_index == u32::MAX {
return 1
}
@ -201,13 +201,13 @@ fn tess_level_for_edge(prev_endpoint_index: u32,
let prev_endpoint = &endpoints[prev_endpoint_index as usize];
let next_endpoint = &endpoints[next_endpoint_index as usize];
let control_points = &control_points[control_points_index as usize];
let control_point = &control_points[control_point_index as usize];
let p0 = transform.transform_point(&prev_endpoint.position);
let p1 = transform.transform_point(&control_points.point1);
let p2 = transform.transform_point(&control_points.point2);
let p3 = transform.transform_point(&next_endpoint.position);
let p1 = transform.transform_point(control_point);
let p2 = transform.transform_point(&next_endpoint.position);
let length = (p1 - p0).length() + (p2 - p1).length() + (p3 - p2).length();
// FIXME(pcwalton): Is this good for quadratics?
let length = (p1 - p0).length() + (p2 - p1).length();
1 + (length * TOLERANCE * (next_time - prev_time)) as u32
}