wip
This commit is contained in:
parent
dda3e16d2e
commit
670a6001fb
|
@ -60,12 +60,15 @@ fn main() {
|
||||||
let path = PathBuf::from(env::args().skip(1).next().unwrap());
|
let path = PathBuf::from(env::args().skip(1).next().unwrap());
|
||||||
let scene = Scene::from_path(&path);
|
let scene = Scene::from_path(&path);
|
||||||
|
|
||||||
|
const RUNS: u32 = 1000;
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
scene.generate_tiles();
|
for _ in 0..RUNS {
|
||||||
|
scene.generate_tiles();
|
||||||
|
}
|
||||||
let elapsed_time = Instant::now() - start_time;
|
let elapsed_time = Instant::now() - start_time;
|
||||||
println!("{}ms elapsed",
|
let elapsed_ms = elapsed_time.as_secs() as f64 * 1000.0 +
|
||||||
elapsed_time.as_secs() as f64 * 1000.0 +
|
elapsed_time.subsec_micros() as f64 / 1000.0;
|
||||||
elapsed_time.subsec_micros() as f64 / 1000.0);
|
println!("{}ms elapsed", elapsed_ms / RUNS as f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -205,9 +208,10 @@ impl Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_tiles(&self) {
|
fn generate_tiles(&self) {
|
||||||
|
let mut strips = vec![];
|
||||||
for object in &self.objects {
|
for object in &self.objects {
|
||||||
let mut tiler = Tiler::from_outline(&object.outline);
|
let mut tiler = Tiler::from_outline(&object.outline);
|
||||||
tiler.generate_tiles();
|
tiler.generate_tiles(&mut strips);
|
||||||
// TODO(pcwalton)
|
// TODO(pcwalton)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,17 +485,26 @@ struct PointIndex {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
enum Segment {
|
enum Segment {
|
||||||
|
None,
|
||||||
Line(LineSegment<f32>),
|
Line(LineSegment<f32>),
|
||||||
Quadratic(QuadraticBezierSegment<f32>),
|
Quadratic(QuadraticBezierSegment<f32>),
|
||||||
Cubic(CubicBezierSegment<f32>),
|
Cubic(CubicBezierSegment<f32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Segment {
|
impl Segment {
|
||||||
|
fn is_none(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Segment::None => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn endpoints(&self) -> (Point2D<f32>, Point2D<f32>) {
|
fn endpoints(&self) -> (Point2D<f32>, Point2D<f32>) {
|
||||||
match *self {
|
match *self {
|
||||||
Segment::Line(ref line) => (line.from, line.to),
|
Segment::Line(ref line) => (line.from, line.to),
|
||||||
Segment::Quadratic(ref curve) => (curve.from, curve.to),
|
Segment::Quadratic(ref curve) => (curve.from, curve.to),
|
||||||
Segment::Cubic(ref curve) => (curve.from, curve.to),
|
Segment::Cubic(ref curve) => (curve.from, curve.to),
|
||||||
|
Segment::None => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,6 +521,7 @@ impl Segment {
|
||||||
f32::min(f32::min(f32::min(curve.from.y, curve.ctrl1.y), curve.ctrl2.y),
|
f32::min(f32::min(f32::min(curve.from.y, curve.ctrl1.y), curve.ctrl2.y),
|
||||||
curve.to.y)
|
curve.to.y)
|
||||||
}
|
}
|
||||||
|
Segment::None => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +554,7 @@ impl Segment {
|
||||||
swapped_curve.assume_monotonic().solve_t_for_x(y, 0.0..1.0, TOLERANCE));
|
swapped_curve.assume_monotonic().solve_t_for_x(y, 0.0..1.0, TOLERANCE));
|
||||||
(Segment::Cubic(prev), Segment::Cubic(next))
|
(Segment::Cubic(prev), Segment::Cubic(next))
|
||||||
}
|
}
|
||||||
|
Segment::None => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if from.y <= to.y {
|
if from.y <= to.y {
|
||||||
|
@ -574,6 +589,7 @@ impl Segment {
|
||||||
to: curve.to + *by,
|
to: curve.to + *by,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Segment::None => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -590,64 +606,73 @@ const TILE_HEIGHT: f32 = 4.0;
|
||||||
|
|
||||||
struct Tiler<'a> {
|
struct Tiler<'a> {
|
||||||
outline: &'a Outline,
|
outline: &'a Outline,
|
||||||
|
|
||||||
|
sorted_edge_indices: Vec<PointIndex>,
|
||||||
|
active_intervals: Intervals,
|
||||||
|
active_edges: Vec<Segment>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Tiler<'a> {
|
impl<'a> Tiler<'a> {
|
||||||
fn from_outline(outline: &Outline) -> Tiler {
|
fn from_outline(outline: &Outline) -> Tiler {
|
||||||
Tiler {
|
Tiler {
|
||||||
outline,
|
outline,
|
||||||
|
|
||||||
|
sorted_edge_indices: vec![],
|
||||||
|
active_intervals: Intervals::new(0.0),
|
||||||
|
active_edges: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_tiles(&mut self) {
|
fn generate_tiles(&mut self, strips: &mut Vec<Strip>) {
|
||||||
// Sort all edge indices.
|
// Sort all edge indices.
|
||||||
let mut sorted_edge_indices = vec![];
|
self.sorted_edge_indices.clear();
|
||||||
for contour_index in 0..self.outline.contours.len() {
|
for contour_index in 0..self.outline.contours.len() {
|
||||||
let contour = &self.outline.contours[contour_index];
|
let contour = &self.outline.contours[contour_index];
|
||||||
for point_index in 0..contour.points.len() {
|
for point_index in 0..contour.points.len() {
|
||||||
if contour.point_is_endpoint(point_index) {
|
if contour.point_is_endpoint(point_index) {
|
||||||
sorted_edge_indices.push(PointIndex { contour_index, point_index })
|
self.sorted_edge_indices.push(PointIndex { contour_index, point_index })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sorted_edge_indices.sort_by(|edge_index_a, edge_index_b| {
|
{
|
||||||
let segment_a = self.outline.segment_after(*edge_index_a);
|
let outline = &self.outline;
|
||||||
let segment_b = self.outline.segment_after(*edge_index_b);
|
self.sorted_edge_indices.sort_by(|edge_index_a, edge_index_b| {
|
||||||
segment_a.min_y().partial_cmp(&segment_b.min_y()).unwrap_or(Ordering::Equal)
|
let segment_a = outline.segment_after(*edge_index_a);
|
||||||
});
|
let segment_b = outline.segment_after(*edge_index_b);
|
||||||
|
segment_a.min_y().partial_cmp(&segment_b.min_y()).unwrap_or(Ordering::Equal)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let bounds = self.outline.bounds;
|
let bounds = self.outline.bounds;
|
||||||
let (max_x, max_y) = (bounds.max_x(), bounds.max_y());
|
let (max_x, max_y) = (bounds.max_x(), bounds.max_y());
|
||||||
|
|
||||||
let mut active_intervals = Intervals::new(max_x);
|
self.active_intervals.reset(max_x);
|
||||||
let mut active_edges = vec![];
|
self.active_edges.clear();
|
||||||
let mut next_edge_index_index = 0;
|
let mut next_edge_index_index = 0;
|
||||||
let mut tile_top = bounds.origin.y - bounds.origin.y % TILE_HEIGHT;
|
|
||||||
let mut strips = vec![];
|
|
||||||
|
|
||||||
|
let mut tile_top = bounds.origin.y - bounds.origin.y % TILE_HEIGHT;
|
||||||
while tile_top < max_y {
|
while tile_top < max_y {
|
||||||
let mut strip = Strip::new(tile_top);
|
let mut strip = Strip::new(tile_top);
|
||||||
|
|
||||||
// TODO(pcwalton): Populate tile strip with active intervals.
|
// TODO(pcwalton): Populate tile strip with active intervals.
|
||||||
|
|
||||||
for active_edge in mem::replace(&mut active_edges, vec![]) {
|
for active_edge in &mut self.active_edges {
|
||||||
self.process_edge(active_edge,
|
process_active_edge(active_edge, &mut strip, &mut self.active_intervals)
|
||||||
&mut strip,
|
|
||||||
&mut active_edges,
|
|
||||||
&mut active_intervals);
|
|
||||||
}
|
}
|
||||||
|
self.active_edges.retain(|edge| !edge.is_none());
|
||||||
|
|
||||||
while next_edge_index_index < sorted_edge_indices.len() {
|
while next_edge_index_index < self.sorted_edge_indices.len() {
|
||||||
let segment =
|
let mut segment =
|
||||||
self.outline.segment_after(sorted_edge_indices[next_edge_index_index]);
|
self.outline.segment_after(self.sorted_edge_indices[next_edge_index_index]);
|
||||||
if segment.min_y() > strip.tile_bottom() {
|
if segment.min_y() > strip.tile_bottom() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
self.process_edge(segment,
|
process_active_edge(&mut segment, &mut strip, &mut self.active_intervals);
|
||||||
&mut strip,
|
if !segment.is_none() {
|
||||||
&mut active_edges,
|
self.active_edges.push(segment);
|
||||||
&mut active_intervals);
|
}
|
||||||
|
|
||||||
next_edge_index_index += 1;
|
next_edge_index_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,30 +680,30 @@ impl<'a> Tiler<'a> {
|
||||||
strips.push(strip);
|
strips.push(strip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn process_edge(&mut self,
|
fn process_active_edge(active_edge: &mut Segment,
|
||||||
edge: Segment,
|
strip: &mut Strip,
|
||||||
strip: &mut Strip,
|
active_intervals: &mut Intervals) {
|
||||||
active_edges: &mut Vec<Segment>,
|
let clipped = active_edge.clip_y(strip.tile_bottom());
|
||||||
intervals: &mut Intervals) {
|
if let Some(upper_segment) = clipped.min {
|
||||||
let clipped = edge.clip_y(strip.tile_bottom());
|
strip.push_segment(upper_segment);
|
||||||
if let Some(upper_segment) = clipped.min {
|
// FIXME(pcwalton): Assumes x-monotonicity!
|
||||||
strip.push_segment(upper_segment);
|
// FIXME(pcwalton): The min call below is a hack!
|
||||||
// FIXME(pcwalton): Assumes x-monotonicity!
|
let (from, to) = upper_segment.endpoints();
|
||||||
// FIXME(pcwalton): The min call below is a hack!
|
let from_x = f32::max(0.0, f32::min(active_intervals.extent(), from.x));
|
||||||
let (from, to) = upper_segment.endpoints();
|
let to_x = f32::max(0.0, f32::min(active_intervals.extent(), to.x));
|
||||||
let from_x = f32::max(0.0, f32::min(intervals.extent(), from.x));
|
if from_x < to_x {
|
||||||
let to_x = f32::max(0.0, f32::min(intervals.extent(), to.x));
|
active_intervals.add(IntervalRange::new(from_x, to_x, -1.0))
|
||||||
if from_x < to_x {
|
} else {
|
||||||
intervals.add(IntervalRange::new(from_x, to_x, -1.0))
|
active_intervals.add(IntervalRange::new(to_x, from_x, 1.0))
|
||||||
} else {
|
|
||||||
intervals.add(IntervalRange::new(to_x, from_x, 1.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(lower_segment) = clipped.max {
|
|
||||||
active_edges.push(lower_segment);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match clipped.max {
|
||||||
|
Some(lower_segment) => *active_edge = lower_segment,
|
||||||
|
None => *active_edge = Segment::None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strips
|
// Strips
|
||||||
|
@ -748,8 +773,7 @@ impl Intervals {
|
||||||
self.merge_adjacent();
|
self.merge_adjacent();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn reset(&mut self, end: f32) {
|
||||||
let end = self.ranges.last().unwrap().end;
|
|
||||||
self.ranges.truncate(1);
|
self.ranges.truncate(1);
|
||||||
self.ranges[0] = IntervalRange::new(0.0, end, 0.0);
|
self.ranges[0] = IntervalRange::new(0.0, end, 0.0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue