Many fixes to tile clipping

This commit is contained in:
Patrick Walton 2018-12-19 18:20:22 -08:00
parent 4a00468595
commit bfbe48959a
1 changed files with 90 additions and 69 deletions

View File

@ -94,6 +94,11 @@ fn main() {
for (index, tile) in built_scene.solid_tiles.iter().enumerate() {
println!("... {}: {:?}", index, tile);
}
println!("fills:");
for (index, fill) in built_scene.fills.iter().enumerate() {
println!("... {}: {:?}", index, fill);
}
*/
if let Some(output_path) = output_path {
@ -758,41 +763,46 @@ impl Segment {
}
fn split_y(&self, y: f32) -> (Option<Segment>, Option<Segment>) {
//println!("split_y({:?}, {:?})", self, y);
// Trivial cases.
if self.from.y <= y && self.to.y <= y {
return if self.from.y < self.to.y {
(Some(*self), None)
} else {
(None, Some(*self))
}
return (Some(*self), None)
}
if self.from.y >= y && self.to.y >= y {
return if self.from.y < self.to.y {
(None, Some(*self))
} else {
(Some(*self), None)
}
return (None, Some(*self))
}
// TODO(pcwalton): Reduce code duplication?
if let Some(mut line_segment) = self.as_line_segment() {
let (prev, next) = match self.as_line_segment() {
Some(line_segment) => {
let t = LineAxis::from_y(&line_segment).solve_for_t(y).unwrap();
let (prev, next) = line_segment.split(t);
return (Some(Segment::from_line(&prev)), Some(Segment::from_line(&next)));
//println!("... split line at {}: {:?}, {:?}", t, prev, next);
(Segment::from_line(&prev), Segment::from_line(&next))
}
None => {
// TODO(pcwalton): Don't degree elevate!
let mut cubic_segment = self.as_cubic_segment().unwrap();
let t = CubicAxis::from_y(&cubic_segment).solve_for_t(y);
let t = t.expect("Failed to solve cubic for Y!");
let (prev, next) = cubic_segment.split(t);
(Some(Segment::from_cubic(&prev)), Some(Segment::from_cubic(&next)))
(Segment::from_cubic(&prev), Segment::from_cubic(&next))
}
};
if self.from.y < self.to.y {
(Some(prev), Some(next))
} else {
(Some(next), Some(prev))
}
}
fn generate_fill_primitives(&self,
strip_origin: &Point2D<f32>,
primitives: &mut Vec<FillPrimitive>) {
if let Some(ref line_segment) = self.as_line_segment() {
//println!("generate_fill_primitives({:?}, {:?})", strip_origin, line_segment);
generate_fill_primitives_for_line(line_segment, strip_origin, primitives);
return;
}
@ -823,6 +833,10 @@ impl Segment {
f32::max(0.0, f32::floor((segment.to.x - strip_origin.x) / TILE_WIDTH)) as u32;
if from_tile_index == to_tile_index {
/*println!("... ... pushing LAST fill primitive {}: {:?} @ {:?}",
primitives.len(),
segment,
tile_offset);*/
primitives.push(FillPrimitive {
from: segment.from - tile_offset,
to: segment.to - tile_offset,
@ -832,13 +846,16 @@ impl Segment {
}
// Split line at tile boundary.
let next_tile_index = if segment.from.x < segment.to.x {
from_tile_index + 1
let (next_tile_index, split_x) = if segment.from.x < segment.to.x {
(from_tile_index + 1, tile_offset.x + TILE_WIDTH)
} else {
from_tile_index - 1
(from_tile_index - 1, tile_offset.x)
};
let next_tile_x = (next_tile_index as f32) * TILE_WIDTH + strip_origin.x;
let (prev_segment, next_segment) = segment.split_at_x(next_tile_x);
let (prev_segment, next_segment) = segment.split_at_x(split_x);
/*println!("... ... pushing fill primitive {}: {:?} @ {:?}",
primitives.len(),
prev_segment,
tile_offset);*/
primitives.push(FillPrimitive {
from: prev_segment.from - tile_offset,
to: prev_segment.to - tile_offset,
@ -911,6 +928,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
fn generate_tiles(&mut self) {
// Sort all edge indices.
// TODO(pcwalton): Only find MIN points.
self.sorted_edge_indices.clear();
for contour_index in 0..self.outline.contours.len() {
let contour = &self.outline.contours[contour_index];
@ -983,6 +1001,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
}
// Populate tile strip with active intervals.
// TODO(pcwalton): Use only the active edge list!
let mut strip_tile_index = 0;
for interval in &self.active_intervals.ranges {
if interval.winding == 0.0 {
@ -1004,8 +1023,8 @@ impl<'o, 'p> Tiler<'o, 'p> {
if tile_interval == (tile_left..tile_right) {
strip_tiles[strip_tile_index].backdrop = interval.winding
} else {
let left = Point2D::new(interval.start, strip_origin.y);
let right = Point2D::new(interval.end, strip_origin.y);
let left = Point2D::new(interval.start - tile_left, strip_origin.y);
let right = Point2D::new(interval.end - tile_left, strip_origin.y);
strip_fills.push(FillPrimitive {
from: if interval.winding < 0.0 { left } else { right },
to: if interval.winding < 0.0 { right } else { left },
@ -1020,6 +1039,7 @@ impl<'o, 'p> Tiler<'o, 'p> {
// Process old active edges.
for active_edge in &mut self.active_edges {
let fills = if above_view_box { None } else { Some(&mut strip_fills) };
//println!("processing old active edge: {:?}", active_edge);
process_active_edge(active_edge,
&strip_bounds,
fills,
@ -1037,8 +1057,11 @@ impl<'o, 'p> Tiler<'o, 'p> {
break
}
//println!("processing new active edge: {:?}", segment);
if !segment.is_degenerate() {
if let Some(mut segment) = segment.clip_x(strip_range) {
//println!("... is not degenerate ...");
if let Some(mut segment) = segment.clip_x(strip_range.clone()) {
//println!("... clipped to {:?}: {:?}", strip_range, segment);
let fills = if above_view_box { None } else { Some(&mut strip_fills) };
process_active_edge(&mut segment,
&strip_bounds,
@ -1096,18 +1119,14 @@ fn process_active_edge(active_edge: &mut Segment,
used_tiles: &mut FixedBitSet) {
let strip_extent = strip_bounds.bottom_right();
let (prev_segment, next_segment) = active_edge.split_y(strip_extent.y);
// TODO(pcwalton): Maybe these shouldn't be Options?
let (upper_segment, lower_segment) = active_edge.split_y(strip_extent.y);
*active_edge = Segment::new();
for &segment in [&prev_segment, &next_segment].into_iter() {
let segment = match *segment {
None => continue,
Some(ref segment) => segment,
};
if segment.from.y < strip_extent.y || segment.to.y < strip_extent.y {
if let Some(segment) = upper_segment {
if let Some(ref mut fills) = fills {
active_edge.generate_fill_primitives(&strip_bounds.origin, *fills);
//println!("process_active_edge: generating fill primitives for {:?}", segment);
segment.generate_fill_primitives(&strip_bounds.origin, *fills);
}
// FIXME(pcwalton): Assumes x-monotonicity!
@ -1136,9 +1155,11 @@ fn process_active_edge(active_edge: &mut Segment,
for tile_index in left_tile_index..right_tile_index {
used_tiles.insert(tile_index as usize);
}
} else {
*active_edge = *segment;
}
match lower_segment {
Some(segment) => *active_edge = segment,
None => *active_edge = Segment::new(),
}
}