Auto merge of #419 - pcwalton:tile-iteration-cap, r=pcwalton
Clip line segments before tiling them, and remove the cap on the number of iterations when tiling. Closes #416.
This commit is contained in:
commit
37a328552e
|
@ -18,7 +18,7 @@ use arrayvec::ArrayVec;
|
|||
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||
use pathfinder_geometry::rect::RectF;
|
||||
use pathfinder_geometry::util::lerp;
|
||||
use pathfinder_geometry::vector::{Vector2F, Vector4F};
|
||||
use pathfinder_geometry::vector::{Vector2F, Vector4F, vec2f};
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::Debug;
|
||||
use std::mem;
|
||||
|
@ -490,6 +490,80 @@ pub(crate) fn rect_is_inside_polygon(rect: RectF, polygon_points: &[Vector2F]) -
|
|||
true
|
||||
}
|
||||
|
||||
/// Clips a line segment to an axis-aligned rectangle using Cohen-Sutherland clipping.
|
||||
pub fn clip_line_segment_to_rect(mut line_segment: LineSegment2F, rect: RectF)
|
||||
-> Option<LineSegment2F> {
|
||||
let mut outcode_from = compute_outcode(line_segment.from(), rect);
|
||||
let mut outcode_to = compute_outcode(line_segment.to(), rect);
|
||||
|
||||
loop {
|
||||
if outcode_from.is_empty() && outcode_to.is_empty() {
|
||||
return Some(line_segment);
|
||||
}
|
||||
if !(outcode_from & outcode_to).is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let clip_from = outcode_from.bits() > outcode_to.bits();
|
||||
let (mut point, outcode) = if clip_from {
|
||||
(line_segment.from(), outcode_from)
|
||||
} else {
|
||||
(line_segment.to(), outcode_to)
|
||||
};
|
||||
|
||||
if outcode.contains(Outcode::LEFT) {
|
||||
point = vec2f(rect.min_x(),
|
||||
lerp(line_segment.from_y(),
|
||||
line_segment.to_y(),
|
||||
(line_segment.min_x() - line_segment.from_x()) /
|
||||
(line_segment.max_x() - line_segment.min_x())));
|
||||
} else if outcode.contains(Outcode::RIGHT) {
|
||||
point = vec2f(rect.max_x(),
|
||||
lerp(line_segment.from_y(),
|
||||
line_segment.to_y(),
|
||||
(line_segment.max_x() - line_segment.from_x()) /
|
||||
(line_segment.max_x() - line_segment.min_x())));
|
||||
} else if outcode.contains(Outcode::TOP) {
|
||||
point = vec2f(lerp(line_segment.from_x(),
|
||||
line_segment.to_x(),
|
||||
(line_segment.min_y() - line_segment.from_y()) /
|
||||
(line_segment.max_y() - line_segment.min_y())),
|
||||
rect.min_y());
|
||||
} else if outcode.contains(Outcode::LEFT) {
|
||||
point = vec2f(lerp(line_segment.from_x(),
|
||||
line_segment.to_x(),
|
||||
(line_segment.max_y() - line_segment.from_y()) /
|
||||
(line_segment.max_y() - line_segment.min_y())),
|
||||
rect.min_y());
|
||||
}
|
||||
|
||||
if clip_from {
|
||||
line_segment.set_from(point);
|
||||
outcode_from = compute_outcode(point, rect);
|
||||
} else {
|
||||
line_segment.set_to(point);
|
||||
outcode_to = compute_outcode(point, rect);
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_outcode(point: Vector2F, rect: RectF) -> Outcode {
|
||||
let mut outcode = Outcode::empty();
|
||||
if point.x() < rect.min_x() {
|
||||
outcode.insert(Outcode::LEFT);
|
||||
}
|
||||
if point.y() < rect.min_y() {
|
||||
outcode.insert(Outcode::TOP);
|
||||
}
|
||||
if point.x() > rect.max_x() {
|
||||
outcode.insert(Outcode::RIGHT);
|
||||
}
|
||||
if point.y() > rect.max_y() {
|
||||
outcode.insert(Outcode::BOTTOM);
|
||||
}
|
||||
outcode
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
struct Outcode: u8 {
|
||||
const LEFT = 0x01;
|
||||
|
|
|
@ -50,7 +50,7 @@ const CURVE_IS_CUBIC: u32 = 0x40000000;
|
|||
const MAX_CLIP_BATCHES: u32 = 32;
|
||||
|
||||
pub(crate) struct SceneBuilder<'a, 'b, 'c, 'd> {
|
||||
scene: &'a mut Scene,
|
||||
pub(crate) scene: &'a mut Scene,
|
||||
built_options: &'b PreparedBuildOptions,
|
||||
next_alpha_tile_indices: [AtomicUsize; ALPHA_TILE_LEVEL_COUNT],
|
||||
pub(crate) sink: &'c mut SceneSink<'d>,
|
||||
|
|
|
@ -17,6 +17,7 @@ use crate::gpu_data::AlphaTileId;
|
|||
use crate::options::PrepareMode;
|
||||
use crate::scene::{ClipPathId, PathId};
|
||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH, TilingPathInfo};
|
||||
use pathfinder_content::clip;
|
||||
use pathfinder_content::fill::FillRule;
|
||||
use pathfinder_content::outline::{ContourIterFlags, Outline};
|
||||
use pathfinder_content::segment::Segment;
|
||||
|
@ -24,6 +25,7 @@ use pathfinder_geometry::line_segment::LineSegment2F;
|
|||
use pathfinder_geometry::rect::RectF;
|
||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
||||
use pathfinder_simd::default::{F32x2, U32x2};
|
||||
use std::f32::NEG_INFINITY;
|
||||
|
||||
const FLATTENING_TOLERANCE: f32 = 0.25;
|
||||
|
||||
|
@ -189,6 +191,14 @@ fn process_segment(segment: &Segment,
|
|||
fn process_line_segment(line_segment: LineSegment2F,
|
||||
scene_builder: &SceneBuilder,
|
||||
object_builder: &mut ObjectBuilder) {
|
||||
let view_box = scene_builder.scene.view_box();
|
||||
let clip_box = RectF::from_points(vec2f(view_box.min_x(), NEG_INFINITY),
|
||||
view_box.lower_right());
|
||||
let line_segment = match clip::clip_line_segment_to_rect(line_segment, clip_box) {
|
||||
None => return,
|
||||
Some(line_segment) => line_segment,
|
||||
};
|
||||
|
||||
let tile_size = vec2f(TILE_WIDTH as f32, TILE_HEIGHT as f32);
|
||||
let tile_size_recip = Vector2F::splat(1.0) / tile_size;
|
||||
|
||||
|
@ -214,12 +224,8 @@ fn process_line_segment(line_segment: LineSegment2F,
|
|||
|
||||
let (mut current_position, mut tile_coords) = (line_segment.from(), from_tile_coords);
|
||||
let mut last_step_direction = None;
|
||||
let mut iteration = 0;
|
||||
|
||||
loop {
|
||||
// Quick check to catch missing the end tile.
|
||||
debug_assert!(iteration < MAX_ITERATIONS);
|
||||
|
||||
let next_step_direction = if t_max.x() < t_max.y() {
|
||||
StepDirection::X
|
||||
} else if t_max.x() > t_max.y() {
|
||||
|
@ -292,11 +298,7 @@ fn process_line_segment(line_segment: LineSegment2F,
|
|||
|
||||
current_position = next_position;
|
||||
last_step_direction = next_step_direction;
|
||||
|
||||
iteration += 1;
|
||||
}
|
||||
|
||||
const MAX_ITERATIONS: u32 = 1024;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
|
|
Loading…
Reference in New Issue