This commit is contained in:
Patrick Walton 2018-12-20 11:39:01 -08:00
parent bf50b5bd60
commit 24d6dd4055
1 changed files with 167 additions and 30 deletions

View File

@ -466,6 +466,26 @@ impl Outline {
fn segment_after(&self, endpoint_index: PointIndex) -> Segment { fn segment_after(&self, endpoint_index: PointIndex) -> Segment {
self.contours[endpoint_index.contour_index].segment_after(endpoint_index.point_index) self.contours[endpoint_index.contour_index].segment_after(endpoint_index.point_index)
} }
fn point_is_logically_above(&self, a: &PointIndex, b: &PointIndex) -> bool {
let a_y = self.contours[a.contour_index].points[a.point_index].y;
let b_y = self.contours[b.contour_index].points[b.point_index].y;
match a_y.partial_cmp(&b_y) {
Some(Ordering::Less) => true,
Some(Ordering::Greater) => false,
None | Some(Ordering::Equal) => {
match a.contour_index.cmp(&b.contour_index) {
Ordering::Less => true,
Ordering::Greater => false,
Ordering::Equal => a.point_index < b.point_index,
}
}
}
}
fn get(&self, point_index: &PointIndex) -> Point2D<f32> {
self.contours[point_index.contour_index].points[point_index.point_index]
}
} }
impl Contour { impl Contour {
@ -541,6 +561,49 @@ impl Contour {
index index
} }
} }
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 prev_endpoint_index_of(&self, mut point_index: usize) -> usize {
loop {
point_index = self.prev_point_index_of(point_index);
if self.point_is_endpoint(point_index) {
return point_index
}
}
}
fn next_endpoint_index_of(&self, mut point_index: usize) -> usize {
loop {
point_index = self.next_point_index_of(point_index);
if self.point_is_endpoint(point_index) {
return point_index
}
}
}
fn prev_point_index_of(&self, point_index: usize) -> usize {
if point_index == 0 {
self.points.len() - 1
} else {
point_index - 1
}
}
fn next_point_index_of(&self, point_index: usize) -> usize {
if point_index == self.points.len() - 1 {
0
} else {
point_index + 1
}
}
} }
impl Debug for Contour { impl Debug for Contour {
@ -928,6 +991,34 @@ impl<'o, 'p> Tiler<'o, 'p> {
} }
fn generate_tiles(&mut self) { fn generate_tiles(&mut self) {
// Find MIN points.
self.point_queue.clear();
for (contour_index, contour) in self.outline.contours.iter().enumerate() {
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);
while cur_endpoint_index < next_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) {
let point_index = PointIndex {
contour_index,
point_index: cur_endpoint_index,
};
let outline = &self.outline;
self.point_queue.push(point_index, |a_index, b_index| {
if outline.point_is_logically_above(a_index, b_index) {
Ordering::Less
} else {
Ordering::Greater
}
});
}
prev_endpoint_index = cur_endpoint_index;
cur_endpoint_index = next_endpoint_index;
next_endpoint_index = contour.next_endpoint_index_of(cur_endpoint_index);
}
}
// Sort all edge indices. // Sort all edge indices.
// TODO(pcwalton): Only find MIN points. // TODO(pcwalton): Only find MIN points.
/* /*
@ -1049,36 +1140,46 @@ impl<'o, 'p> Tiler<'o, 'p> {
self.active_edges.retain(|edge| !edge.is_none()); self.active_edges.retain(|edge| !edge.is_none());
// Add new active edges. // Add new active edges.
/* loop {
while next_edge_index_index < self.sorted_edge_indices.len() { match self.point_queue.peek_min() {
let from_point_index = self.sorted_edge_indices[next_edge_index_index]; Some(point_index) if self.outline.get(point_index).y < strip_extent.y => {}
let strip_range = (strip_bounds.origin.x)..(strip_bounds.max_x()); Some(_) | None => break,
let segment = self.outline.segment_after(from_point_index);
if segment.min_y() > strip_extent.y {
break
} }
//println!("processing new active edge: {:?}", segment); let outline = &self.outline;
if !segment.is_degenerate() { let point_index = self.point_queue.shift_min(|a_index, b_index| {
//println!("... is not degenerate ..."); if outline.point_is_logically_above(a_index, b_index) {
if let Some(mut segment) = segment.clip_x(strip_range.clone()) { Ordering::Less
//println!("... clipped to {:?}: {:?}", strip_range, segment); } else {
let fills = if above_view_box { None } else { Some(&mut strip_fills) }; Ordering::Greater
process_active_edge(&mut segment,
&strip_bounds,
fills,
&mut self.active_intervals,
&mut used_strip_tiles);
if !segment.is_none() {
self.active_edges.push(segment);
}
} }
} }).unwrap();
next_edge_index_index += 1; let contour = &outline.contours[point_index.contour_index];
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 fills = if above_view_box { None } else { Some(&mut strip_fills) };
process_active_segment(contour,
prev_endpoint_index,
&mut self.active_edges,
&strip_bounds,
fills,
&mut self.active_intervals,
&mut used_strip_tiles);
}
if contour.point_is_logically_above(point_index.point_index, next_endpoint_index) {
let fills = if above_view_box { None } else { Some(&mut strip_fills) };
process_active_segment(contour,
point_index.point_index,
&mut self.active_edges,
&strip_bounds,
fills,
&mut self.active_intervals,
&mut used_strip_tiles);
}
} }
*/
// Finalize tiles. // Finalize tiles.
if !above_view_box { if !above_view_box {
@ -1121,6 +1222,34 @@ impl<'o, 'p> Tiler<'o, 'p> {
} }
} }
fn process_active_segment(contour: &Contour,
from_endpoint_index: usize,
active_edges: &mut Vec<Segment>,
strip_bounds: &Rect<f32>,
mut fills: Option<&mut Vec<FillPrimitive>>,
active_intervals: &mut Intervals,
used_tiles: &mut FixedBitSet) {
let segment = contour.segment_after(from_endpoint_index);
if segment.is_degenerate() {
return
}
//println!("processing new active edge: {:?}", segment);
//println!("... is not degenerate ...");
let strip_range = (strip_bounds.origin.x)..(strip_bounds.max_x());
let mut segment = match segment.clip_x(strip_range.clone()) {
Some(segment) => segment,
None => return,
};
//println!("... clipped to {:?}: {:?}", strip_range, segment);
process_active_edge(&mut segment, &strip_bounds, fills, active_intervals, used_tiles);
if !segment.is_none() {
active_edges.push(segment);
}
}
fn process_active_edge(active_edge: &mut Segment, fn process_active_edge(active_edge: &mut Segment,
strip_bounds: &Rect<f32>, strip_bounds: &Rect<f32>,
mut fills: Option<&mut Vec<FillPrimitive>>, mut fills: Option<&mut Vec<FillPrimitive>>,
@ -1772,10 +1901,18 @@ impl<T> Heap<T> {
self.sift_up(index, compare); self.sift_up(index, compare);
} }
fn shift_min<C>(&mut self, mut compare: C) -> T where C: FnMut(&T, &T) -> Ordering { fn peek_min(&self) -> Option<&T> {
let min = self.array.swap_remove(0); self.array.get(0)
self.sift_down(0, compare); }
min
fn shift_min<C>(&mut self, mut compare: C) -> Option<T> where C: FnMut(&T, &T) -> Ordering {
if self.array.is_empty() {
None
} else {
let min = self.array.swap_remove(0);
self.sift_down(0, compare);
Some(min)
}
} }
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
@ -1834,7 +1971,7 @@ mod test {
values.sort(); values.sort();
let mut results = Vec::with_capacity(values.len()); let mut results = Vec::with_capacity(values.len());
while !heap.is_empty() { while !heap.is_empty() {
results.push(heap.shift_min(|a, b| a.cmp(&b))); results.push(heap.shift_min(|a, b| a.cmp(&b)).unwrap());
} }
assert_eq!(&values, &results); assert_eq!(&values, &results);