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