First draft of switch to quadratic Béziers
This commit is contained in:
parent
49026ae3c3
commit
a7ba7d200e
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue