Compress point indices

This commit is contained in:
Patrick Walton 2018-12-21 17:58:39 -08:00
parent b29ad14d83
commit 5bac1b6517
1 changed files with 69 additions and 72 deletions

View File

@ -477,6 +477,14 @@ impl Contour {
self.points.is_empty()
}
fn len(&self) -> u32 {
self.points.len() as u32
}
fn position_of(&self, index: u32) -> Point2D<f32> {
self.points[index as usize]
}
fn push_transformed_point(&mut self,
point: &Point2D<f32>,
flags: PointFlags,
@ -495,42 +503,42 @@ impl Contour {
}
}
fn segment_after(&self, point_index: usize) -> Segment {
fn segment_after(&self, point_index: u32) -> Segment {
debug_assert!(self.point_is_endpoint(point_index));
let mut segment = Segment::new();
segment.from = self.points[point_index];
segment.from = self.position_of(point_index);
segment.flags |= SegmentFlags::HAS_ENDPOINTS;
let point1_index = self.add_to_point_index(point_index, 1);
if self.point_is_endpoint(point1_index) {
segment.to = self.points[point1_index];
segment.to = self.position_of(point1_index);
} else {
segment.ctrl0 = self.points[point1_index];
segment.ctrl0 = self.position_of(point1_index);
segment.flags |= SegmentFlags::HAS_CONTROL_POINT_0;
let point2_index = self.add_to_point_index(point_index, 2);
if self.point_is_endpoint(point2_index) {
segment.to = self.points[point2_index];
segment.to = self.position_of(point2_index);
} else {
segment.ctrl1 = self.points[point2_index];
segment.ctrl1 = self.position_of(point2_index);
segment.flags |= SegmentFlags::HAS_CONTROL_POINT_1;
let point3_index = self.add_to_point_index(point_index, 3);
segment.to = self.points[point3_index];
segment.to = self.position_of(point3_index);
}
}
segment
}
fn point_is_endpoint(&self, point_index: usize) -> bool {
!self.flags[point_index].intersects(PointFlags::CONTROL_POINT_0 |
PointFlags::CONTROL_POINT_1)
fn point_is_endpoint(&self, point_index: u32) -> bool {
!self.flags[point_index as usize].intersects(PointFlags::CONTROL_POINT_0 |
PointFlags::CONTROL_POINT_1)
}
fn add_to_point_index(&self, point_index: usize, addend: usize) -> usize {
let (index, limit) = (point_index + addend, self.points.len());
fn add_to_point_index(&self, point_index: u32, addend: u32) -> u32 {
let (index, limit) = (point_index + addend, self.len());
if index >= limit {
index - limit
} else {
@ -538,16 +546,12 @@ impl Contour {
}
}
fn point_is_logically_above(&self, a: usize, b: usize) -> bool {
let (a_y, b_y) = (self.points[a].y, self.points[b].y);
match a_y.partial_cmp(&b_y) {
Some(Ordering::Less) => true,
Some(Ordering::Greater) => false,
None | Some(Ordering::Equal) => a < b,
}
fn point_is_logically_above(&self, a: u32, b: u32) -> bool {
let (a_y, b_y) = (self.points[a as usize].y, self.points[b as usize].y);
a_y < b_y || (a_y == b_y && a < b)
}
fn prev_endpoint_index_of(&self, mut point_index: usize) -> usize {
fn prev_endpoint_index_of(&self, mut point_index: u32) -> u32 {
loop {
point_index = self.prev_point_index_of(point_index);
if self.point_is_endpoint(point_index) {
@ -556,7 +560,7 @@ impl Contour {
}
}
fn next_endpoint_index_of(&self, mut point_index: usize) -> usize {
fn next_endpoint_index_of(&self, mut point_index: u32) -> u32 {
loop {
point_index = self.next_point_index_of(point_index);
if self.point_is_endpoint(point_index) {
@ -565,16 +569,16 @@ impl Contour {
}
}
fn prev_point_index_of(&self, point_index: usize) -> usize {
fn prev_point_index_of(&self, point_index: u32) -> u32 {
if point_index == 0 {
self.points.len() - 1
self.len() - 1
} else {
point_index - 1
}
}
fn next_point_index_of(&self, point_index: usize) -> usize {
if point_index == self.points.len() - 1 {
fn next_point_index_of(&self, point_index: u32) -> u32 {
if point_index == self.len() - 1 {
0
} else {
point_index + 1
@ -607,14 +611,25 @@ impl Debug for Contour {
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
struct PointIndex {
contour_index: usize,
point_index: usize,
struct PointIndex(u32);
impl PointIndex {
fn new(contour: u32, point: u32) -> PointIndex {
PointIndex((contour << 20) | point)
}
fn contour(self) -> u32 {
self.0 >> 20
}
fn point(self) -> u32 {
self.0 & 0x000fffff
}
}
struct ContourIter<'a> {
contour: &'a Contour,
index: usize,
index: u32,
}
impl<'a> Iterator for ContourIter<'a> {
@ -622,16 +637,16 @@ impl<'a> Iterator for ContourIter<'a> {
fn next(&mut self) -> Option<PathEvent> {
let contour = self.contour;
if self.index == contour.points.len() + 1 {
if self.index == contour.len() + 1 {
return None
}
if self.index == contour.points.len() {
if self.index == contour.len() {
self.index += 1;
return Some(PathEvent::Close)
}
let point0_index = self.index;
let point0 = contour.points[point0_index];
let point0 = contour.position_of(point0_index);
self.index += 1;
if point0_index == 0 {
return Some(PathEvent::MoveTo(point0))
@ -641,14 +656,14 @@ impl<'a> Iterator for ContourIter<'a> {
}
let point1_index = self.index;
let point1 = contour.points[point1_index];
let point1 = contour.position_of(point1_index);
self.index += 1;
if contour.point_is_endpoint(point1_index) {
return Some(PathEvent::QuadraticTo(point0, point1))
}
let point2_index = self.index;
let point2 = contour.points[point2_index];
let point2 = contour.position_of(point2_index);
self.index += 1;
debug_assert!(contour.point_is_endpoint(point2_index));
Some(PathEvent::CubicTo(point0, point1, point2))
@ -1133,44 +1148,38 @@ impl<'o, 'p> Tiler<'o, 'p> {
let outline = &self.outline;
let point_index = self.point_queue.pop().unwrap().point_index;
let contour = &outline.contours[point_index.contour_index];
let contour = &outline.contours[point_index.contour() as usize];
// TODO(pcwalton): Could use a bitset of processed edges…
let prev_endpoint_index = contour.prev_endpoint_index_of(point_index.point_index);
let next_endpoint_index = contour.next_endpoint_index_of(point_index.point_index);
if contour.point_is_logically_above(point_index.point_index, prev_endpoint_index) {
let prev_endpoint_index = contour.prev_endpoint_index_of(point_index.point());
let next_endpoint_index = contour.next_endpoint_index_of(point_index.point());
if contour.point_is_logically_above(point_index.point(), prev_endpoint_index) {
let fills = if above_view_box { None } else { Some(&mut self.strip_fills) };
process_active_segment(contour,
prev_endpoint_index,
&mut self.active_edges,
&strip_bounds,
fills,
&mut self.used_strip_tiles);
prev_endpoint_index,
&mut self.active_edges,
&strip_bounds,
fills,
&mut self.used_strip_tiles);
self.point_queue.push(QueuedEndpoint {
point_index: PointIndex {
contour_index: point_index.contour_index,
point_index: prev_endpoint_index,
},
y: contour.points[prev_endpoint_index].y,
point_index: PointIndex::new(point_index.contour(), prev_endpoint_index),
y: contour.position_of(prev_endpoint_index).y,
});
}
if contour.point_is_logically_above(point_index.point_index, next_endpoint_index) {
if contour.point_is_logically_above(point_index.point(), next_endpoint_index) {
let fills = if above_view_box { None } else { Some(&mut self.strip_fills) };
process_active_segment(contour,
point_index.point_index,
point_index.point(),
&mut self.active_edges,
&strip_bounds,
fills,
&mut self.used_strip_tiles);
self.point_queue.push(QueuedEndpoint {
point_index: PointIndex {
contour_index: point_index.contour_index,
point_index: next_endpoint_index,
},
y: contour.points[next_endpoint_index].y,
point_index: PointIndex::new(point_index.contour(), next_endpoint_index),
y: contour.position_of(next_endpoint_index).y,
});
}
}
@ -1210,6 +1219,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
// Find MIN points.
self.point_queue.clear();
for (contour_index, contour) in self.outline.contours.iter().enumerate() {
let contour_index = contour_index as u32;
let mut cur_endpoint_index = 0;
let mut prev_endpoint_index = contour.prev_endpoint_index_of(cur_endpoint_index);
let mut next_endpoint_index = contour.next_endpoint_index_of(cur_endpoint_index);
@ -1217,11 +1227,8 @@ impl<'o, 'p> Tiler<'o, 'p> {
if contour.point_is_logically_above(cur_endpoint_index, prev_endpoint_index) &&
contour.point_is_logically_above(cur_endpoint_index, next_endpoint_index) {
self.point_queue.push(QueuedEndpoint {
point_index: PointIndex {
contour_index,
point_index: cur_endpoint_index,
},
y: contour.points[cur_endpoint_index].y,
point_index: PointIndex::new(contour_index, cur_endpoint_index),
y: contour.position_of(cur_endpoint_index).y,
});
}
@ -1234,7 +1241,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
}
fn process_active_segment(contour: &Contour,
from_endpoint_index: usize,
from_endpoint_index: u32,
active_edges: &mut SortedVector<ActiveEdge>,
strip_bounds: &Rect<f32>,
fills: Option<&mut Vec<FillPrimitive>>,
@ -1784,17 +1791,7 @@ impl Eq for QueuedEndpoint {}
impl PartialOrd<QueuedEndpoint> for QueuedEndpoint {
fn partial_cmp(&self, other: &QueuedEndpoint) -> Option<Ordering> {
// NB: Reversed!
match other.y.partial_cmp(&self.y) {
Some(Ordering::Equal) | None => {
match other.point_index.contour_index.cmp(&self.point_index.contour_index) {
Ordering::Equal => {
Some(other.point_index.point_index.cmp(&self.point_index.point_index))
}
ordering => Some(ordering),
}
}
Some(ordering) => Some(ordering),
}
(other.y, other.point_index).partial_cmp(&(self.y, self.point_index))
}
}