Get rid of the `down_` prefix for oriented edges
This commit is contained in:
parent
4f527a4f66
commit
a937855a0e
|
@ -727,6 +727,16 @@ impl Segment {
|
||||||
flags: self.flags,
|
flags: self.flags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reverses if necessary so that the from point is above the to point. Calling this method
|
||||||
|
// again will undo the transformation.
|
||||||
|
fn orient(&self, y_winding: i32) -> Segment {
|
||||||
|
if y_winding >= 0 {
|
||||||
|
*self
|
||||||
|
} else {
|
||||||
|
self.reversed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
|
@ -1458,6 +1468,48 @@ impl BuiltObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(pcwalton): Optimize this better with SIMD!
|
||||||
|
fn generate_fill_primitives_for_line(&mut self, mut segment: LineSegmentF32, tile_y: i16) {
|
||||||
|
/*
|
||||||
|
println!("... generate_fill_primitives_for_line(): segment={:?} tile_y={} ({}-{})",
|
||||||
|
segment,
|
||||||
|
tile_y,
|
||||||
|
tile_y as f32 * TILE_HEIGHT as f32,
|
||||||
|
(tile_y + 1) as f32 * TILE_HEIGHT as f32);
|
||||||
|
*/
|
||||||
|
|
||||||
|
let winding = segment.from_x() > segment.to_x();
|
||||||
|
let (segment_left, segment_right) = if !winding {
|
||||||
|
(segment.from_x(), segment.to_x())
|
||||||
|
} else {
|
||||||
|
(segment.to_x(), segment.from_x())
|
||||||
|
};
|
||||||
|
|
||||||
|
let segment_tile_left = (f32::floor(segment_left) as i32 / TILE_WIDTH as i32) as i16;
|
||||||
|
let segment_tile_right = alignup_i32(f32::ceil(segment_right) as i32,
|
||||||
|
TILE_WIDTH as i32) as i16;
|
||||||
|
|
||||||
|
for subsegment_tile_x in segment_tile_left..segment_tile_right {
|
||||||
|
let (mut fill_from, mut fill_to) = (segment.from(), segment.to());
|
||||||
|
let subsegment_tile_right =
|
||||||
|
((i32::from(subsegment_tile_x) + 1) * TILE_HEIGHT as i32) as f32;
|
||||||
|
if subsegment_tile_right < segment_right {
|
||||||
|
let x = subsegment_tile_right;
|
||||||
|
let point = Point2DF32::new(x, segment.solve_y_for_x(x));
|
||||||
|
if !winding {
|
||||||
|
fill_to = point;
|
||||||
|
segment = LineSegmentF32::new(&point, &segment.to());
|
||||||
|
} else {
|
||||||
|
fill_from = point;
|
||||||
|
segment = LineSegmentF32::new(&segment.from(), &point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fill_segment = LineSegmentF32::new(&fill_from, &fill_to);
|
||||||
|
self.add_fill(&fill_segment, subsegment_tile_x, tile_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): Use a `Point2D<i16>` instead?
|
// FIXME(pcwalton): Use a `Point2D<i16>` instead?
|
||||||
fn tile_coords_to_index(&self, tile_x: i16, tile_y: i16) -> u32 {
|
fn tile_coords_to_index(&self, tile_x: i16, tile_y: i16) -> u32 {
|
||||||
/*println!("tile_coords_to_index(x={}, y={}, tile_rect={:?})",
|
/*println!("tile_coords_to_index(x={}, y={}, tile_rect={:?})",
|
||||||
|
@ -1864,88 +1916,65 @@ impl ActiveEdge {
|
||||||
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
||||||
// println!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom);
|
// println!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom);
|
||||||
|
|
||||||
let mut down_segment = self.segment;
|
/*let mut down_segment = self.segment;
|
||||||
let winds_up = down_segment.baseline.from_y() > down_segment.baseline.to_y();
|
let winds_up = down_segment.baseline.from_y() > down_segment.baseline.to_y();
|
||||||
if winds_up {
|
if winds_up {
|
||||||
down_segment = down_segment.reversed();
|
down_segment = down_segment.reversed();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if down_segment.is_line_segment() {
|
let mut segment = self.segment;
|
||||||
let down_line_segment = down_segment.as_line_segment().unwrap();
|
let winding = segment.baseline.y_winding();
|
||||||
if down_line_segment.to_y() > tile_bottom {
|
|
||||||
let (mut upper_part, mut lower_part) = down_line_segment.split_at_y(tile_bottom);
|
|
||||||
self.crossing = upper_part.to();
|
|
||||||
|
|
||||||
if winds_up {
|
if segment.is_line_segment() {
|
||||||
upper_part = upper_part.reversed();
|
let line_segment = segment.as_line_segment().unwrap();
|
||||||
lower_part = lower_part.reversed();
|
if line_segment.max_y() > tile_bottom {
|
||||||
}
|
let (upper_part, lower_part) = line_segment.split_at_y(tile_bottom);
|
||||||
|
self.crossing = upper_part.lower_point();
|
||||||
generate_fill_primitives_for_line(upper_part, built_object, tile_y);
|
built_object.generate_fill_primitives_for_line(upper_part, tile_y);
|
||||||
self.segment = Segment::from_line(&lower_part);
|
self.segment = Segment::from_line(&lower_part);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut line_segment = down_line_segment;
|
built_object.generate_fill_primitives_for_line(line_segment, tile_y);
|
||||||
if winds_up {
|
|
||||||
line_segment = line_segment.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_fill_primitives_for_line(line_segment, built_object, tile_y);
|
|
||||||
self.segment = Segment::new();
|
self.segment = Segment::new();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Don't degree elevate!
|
// TODO(pcwalton): Don't degree elevate!
|
||||||
if !down_segment.is_cubic_segment() {
|
if !segment.is_cubic_segment() {
|
||||||
down_segment = down_segment.to_cubic();
|
segment = segment.to_cubic();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If necessary, draw initial line.
|
// If necessary, draw initial line.
|
||||||
//assert!(down_segment.baseline.from_y() < tile_bottom);
|
//assert!(down_segment.baseline.from_y() < tile_bottom);
|
||||||
if self.crossing.y() < down_segment.baseline.from_y() {
|
if self.crossing.y() < segment.baseline.min_y() {
|
||||||
let first_down_line_segment = LineSegmentF32::new(&self.crossing,
|
let first_line_segment =
|
||||||
&down_segment.baseline.from());
|
LineSegmentF32::new(&self.crossing,
|
||||||
if first_down_line_segment.to_y() > tile_bottom {
|
&segment.baseline.upper_point()).orient(winding);
|
||||||
|
if first_line_segment.max_y() > tile_bottom {
|
||||||
// Shouldn't happen much…
|
// Shouldn't happen much…
|
||||||
// FIXME(pcwalton): Reduce duplication!
|
// FIXME(pcwalton): Reduce duplication!
|
||||||
|
|
||||||
let (down_upper_part, _) = first_down_line_segment.split_at_y(tile_bottom);
|
let (upper_part, _) = first_line_segment.split_at_y(tile_bottom);
|
||||||
self.crossing = down_upper_part.to();
|
self.crossing = upper_part.lower_point();
|
||||||
|
|
||||||
let mut upper_part = down_upper_part;
|
|
||||||
if winds_up {
|
|
||||||
upper_part = upper_part.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// println!("... FIRST crossed tile Y {}", tile_bottom);
|
// println!("... FIRST crossed tile Y {}", tile_bottom);
|
||||||
generate_fill_primitives_for_line(upper_part, built_object, tile_y);
|
built_object.generate_fill_primitives_for_line(upper_part, tile_y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut first_line_segment = first_down_line_segment;
|
built_object.generate_fill_primitives_for_line(first_line_segment, tile_y);
|
||||||
if winds_up {
|
|
||||||
first_line_segment = first_line_segment.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_fill_primitives_for_line(first_line_segment, built_object, tile_y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let rest_down_segment = match down_segment.as_cubic_segment().flatten_once() {
|
let rest_segment = match segment.orient(winding).as_cubic_segment().flatten_once() {
|
||||||
None => {
|
None => {
|
||||||
let down_line_segment = down_segment.baseline;
|
let line_segment = segment.baseline;
|
||||||
|
|
||||||
// FIXME(pcwalton): Eliminate duplication with below!!
|
// FIXME(pcwalton): Eliminate duplication with below!!
|
||||||
if down_line_segment.to_y() > tile_bottom {
|
if line_segment.max_y() > tile_bottom {
|
||||||
let (down_upper_part, down_lower_part) =
|
let (upper_part, lower_part) = line_segment.split_at_y(tile_bottom);
|
||||||
down_line_segment.split_at_y(tile_bottom);
|
self.crossing = upper_part.lower_point();
|
||||||
self.crossing = down_upper_part.to();
|
|
||||||
|
|
||||||
let mut upper_part = down_upper_part;
|
|
||||||
if winds_up {
|
|
||||||
upper_part = upper_part.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
println!("... cubic crossed tile Y {} (LAST); down_line_segment={:#?} \
|
println!("... cubic crossed tile Y {} (LAST); down_line_segment={:#?} \
|
||||||
|
@ -1955,41 +1984,25 @@ impl ActiveEdge {
|
||||||
down_lower_part);
|
down_lower_part);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
generate_fill_primitives_for_line(upper_part, built_object, tile_y);
|
built_object.generate_fill_primitives_for_line(upper_part, tile_y);
|
||||||
|
|
||||||
let mut lower_part = down_lower_part;
|
|
||||||
if winds_up {
|
|
||||||
lower_part = lower_part.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.segment = Segment::from_line(&lower_part);
|
self.segment = Segment::from_line(&lower_part);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut line_segment = down_segment.baseline;
|
built_object.generate_fill_primitives_for_line(line_segment, tile_y);
|
||||||
if winds_up {
|
|
||||||
line_segment = line_segment.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_fill_primitives_for_line(line_segment, built_object, tile_y);
|
|
||||||
|
|
||||||
self.segment = Segment::new();
|
self.segment = Segment::new();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(rest_down_segment) => rest_down_segment,
|
Some(rest_segment) => rest_segment.orient(winding),
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_assert!(down_segment.baseline.from_y() <= tile_bottom);
|
debug_assert!(segment.baseline.min_y() <= tile_bottom);
|
||||||
let down_line_segment = LineSegmentF32::new(&down_segment.baseline.from(),
|
let line_segment =
|
||||||
&rest_down_segment.baseline.from());
|
LineSegmentF32::new(&segment.baseline.upper_point(),
|
||||||
if down_line_segment.to_y() > tile_bottom {
|
&rest_segment.baseline.upper_point()).orient(winding);
|
||||||
let (down_upper_part, _) = down_line_segment.split_at_y(tile_bottom);
|
if line_segment.max_y() > tile_bottom {
|
||||||
self.crossing = down_upper_part.to();
|
let (upper_part, _) = line_segment.split_at_y(tile_bottom);
|
||||||
|
self.crossing = upper_part.lower_point();
|
||||||
let mut upper_part = down_upper_part;
|
|
||||||
if winds_up {
|
|
||||||
upper_part = upper_part.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
println!("... cubic crossed tile Y {}; down_line_segment={:#?} down_rest={:#?}",
|
println!("... cubic crossed tile Y {}; down_line_segment={:#?} down_rest={:#?}",
|
||||||
|
@ -1998,72 +2011,17 @@ impl ActiveEdge {
|
||||||
rest_down_segment);
|
rest_down_segment);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
generate_fill_primitives_for_line(upper_part, built_object, tile_y);
|
built_object.generate_fill_primitives_for_line(upper_part, tile_y);
|
||||||
|
|
||||||
let mut rest_segment = rest_down_segment;
|
|
||||||
if winds_up {
|
|
||||||
rest_segment = rest_segment.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.segment = rest_segment;
|
self.segment = rest_segment;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
down_segment = rest_down_segment;
|
segment = rest_segment;
|
||||||
|
|
||||||
let mut line_segment = down_line_segment;
|
built_object.generate_fill_primitives_for_line(line_segment, tile_y);
|
||||||
if winds_up {
|
|
||||||
line_segment = line_segment.reversed();
|
|
||||||
}
|
|
||||||
|
|
||||||
generate_fill_primitives_for_line(line_segment, built_object, tile_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(pcwalton): Optimize this better with SIMD!
|
|
||||||
fn generate_fill_primitives_for_line(mut segment: LineSegmentF32,
|
|
||||||
built_object: &mut BuiltObject,
|
|
||||||
tile_y: i16) {
|
|
||||||
/*
|
|
||||||
println!("... generate_fill_primitives_for_line(): segment={:?} tile_y={} ({}-{})",
|
|
||||||
segment,
|
|
||||||
tile_y,
|
|
||||||
tile_y as f32 * TILE_HEIGHT as f32,
|
|
||||||
(tile_y + 1) as f32 * TILE_HEIGHT as f32);
|
|
||||||
*/
|
|
||||||
|
|
||||||
let winding = segment.from_x() > segment.to_x();
|
|
||||||
let (segment_left, segment_right) = if !winding {
|
|
||||||
(segment.from_x(), segment.to_x())
|
|
||||||
} else {
|
|
||||||
(segment.to_x(), segment.from_x())
|
|
||||||
};
|
|
||||||
|
|
||||||
let segment_tile_left = (f32::floor(segment_left) as i32 / TILE_WIDTH as i32) as i16;
|
|
||||||
let segment_tile_right = alignup_i32(f32::ceil(segment_right) as i32,
|
|
||||||
TILE_WIDTH as i32) as i16;
|
|
||||||
|
|
||||||
for subsegment_tile_x in segment_tile_left..segment_tile_right {
|
|
||||||
let (mut fill_from, mut fill_to) = (segment.from(), segment.to());
|
|
||||||
let subsegment_tile_right =
|
|
||||||
((i32::from(subsegment_tile_x) + 1) * TILE_HEIGHT as i32) as f32;
|
|
||||||
if subsegment_tile_right < segment_right {
|
|
||||||
let x = subsegment_tile_right;
|
|
||||||
let point = Point2DF32::new(x, segment.solve_y_for_x(x));
|
|
||||||
if !winding {
|
|
||||||
fill_to = point;
|
|
||||||
segment = LineSegmentF32::new(&point, &segment.to());
|
|
||||||
} else {
|
|
||||||
fill_from = point;
|
|
||||||
segment = LineSegmentF32::new(&segment.from(), &point);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fill_segment = LineSegmentF32::new(&fill_from, &fill_to);
|
|
||||||
built_object.add_fill(&fill_segment, subsegment_tile_x, tile_y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd<ActiveEdge> for ActiveEdge {
|
impl PartialOrd<ActiveEdge> for ActiveEdge {
|
||||||
|
@ -2205,9 +2163,14 @@ impl LineSegmentF32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Optimize?
|
// Returns the upper segment first, followed by the lower segment.
|
||||||
fn split_at_y(&self, y: f32) -> (LineSegmentF32, LineSegmentF32) {
|
fn split_at_y(&self, y: f32) -> (LineSegmentF32, LineSegmentF32) {
|
||||||
self.split((y - self.from_y()) / (self.to_y() - self.from_y()))
|
let (min_part, max_part) = self.split((y - self.from_y()) / (self.to_y() - self.from_y()));
|
||||||
|
if min_part.from_y() < max_part.from_y() {
|
||||||
|
(min_part, max_part)
|
||||||
|
} else {
|
||||||
|
(max_part, min_part)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_line_segment_u4(&self) -> LineSegmentU4 {
|
fn to_line_segment_u4(&self) -> LineSegmentU4 {
|
||||||
|
@ -2242,6 +2205,39 @@ impl LineSegmentF32 {
|
||||||
LineSegmentF32(Sse41::shuffle_ps(self.0, self.0, 0b0100_1110))
|
LineSegmentF32(Sse41::shuffle_ps(self.0, self.0, 0b0100_1110))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn upper_point(&self) -> Point2DF32 {
|
||||||
|
if self.from_y() < self.to_y() {
|
||||||
|
self.from()
|
||||||
|
} else {
|
||||||
|
self.to()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_point(&self) -> Point2DF32 {
|
||||||
|
if self.from_y() < self.to_y() {
|
||||||
|
self.to()
|
||||||
|
} else {
|
||||||
|
self.from()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn min_y(&self) -> f32 { f32::min(self.from_y(), self.to_y()) }
|
||||||
|
fn max_y(&self) -> f32 { f32::max(self.from_y(), self.to_y()) }
|
||||||
|
|
||||||
|
fn y_winding(&self) -> i32 {
|
||||||
|
if self.from_y() < self.to_y() { 1 } else { -1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverses if necessary so that the from point is above the to point. Calling this method
|
||||||
|
// again will undo the transformation.
|
||||||
|
fn orient(&self, y_winding: i32) -> LineSegmentF32 {
|
||||||
|
if y_winding >= 0 {
|
||||||
|
*self
|
||||||
|
} else {
|
||||||
|
self.reversed()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for LineSegmentF32 {
|
impl PartialEq for LineSegmentF32 {
|
||||||
|
|
Loading…
Reference in New Issue