use typed_arena::Arena;
use crate::{IntRect, Point};
use crate::blitter::RasterBlitter;
use crate::path_builder::Winding;
use crate::geom::intrect;
use std::ptr::NonNull;
struct Edge {
x1: Dot2,
y1: Dot2,
x2: Dot2,
y2: Dot2,
control_x: Dot2,
control_y: Dot2,
}
type Dot16 = i32;
type Dot2 = i32;
type Dot6 = i32;
type ShiftedDot16 = i32;
fn div_fixed16_fixed16(a: Dot16, b: Dot16) -> Dot16 {
(((a as i64) << 16) / (b as i64)) as i32
}
#[inline]
fn dot2_to_dot16(val: Dot2) -> Dot16 {
val << (16 - SAMPLE_SHIFT)
}
#[inline]
fn dot16_to_dot2(val: Dot2) -> Dot16 {
val >> (16 - SAMPLE_SHIFT)
}
#[inline]
fn dot2_to_int(val: Dot2) -> i32 {
val >> SAMPLE_SHIFT
}
#[inline]
fn int_to_dot2(val: i32) -> Dot2 {
val << SAMPLE_SHIFT
}
#[inline]
fn f32_to_dot2(val: f32) -> Dot2 {
(val * SAMPLE_SIZE) as i32
}
#[inline]
fn dot2_to_dot6(val: Dot2) -> Dot6 {
val << 4
}
pub struct ActiveEdge {
x2: Dot2,
y2: Dot2,
next: Option<NonNull<ActiveEdge>>,
slope_x: Dot16,
fullx: Dot16,
next_x: Dot16,
next_y: Dot16,
dx: Dot16,
ddx: ShiftedDot16,
dy: Dot16,
ddy: ShiftedDot16,
old_x: Dot16,
old_y: Dot16,
shift: i32,
count: i32,
winding: i8, }
impl ActiveEdge {
fn new() -> ActiveEdge {
ActiveEdge {
x2: 0,
y2: 0,
next: None,
slope_x: 0,
fullx: 0,
next_x: 0,
next_y: 0,
dx: 0,
ddx: 0,
dy: 0,
ddy: 0,
old_x: 0,
old_y: 0,
shift: 0,
count: 0,
winding: 0,
}
}
fn step(&mut self, cury: Dot2) {
if self.shift != 0 {
if cury >= dot16_to_dot2(self.next_y) {
self.old_y = self.next_y;
self.old_x = self.next_x;
self.fullx = self.next_x;
while self.count > 0 && cury >= dot16_to_dot2(self.next_y) {
self.next_x += self.dx >> self.shift;
self.dx += self.ddx;
self.next_y += self.dy >> self.shift;
self.dy += self.ddy;
self.count -= 1;
}
if self.count == 0 {
self.next_y = dot2_to_dot16(self.y2);
self.next_x = dot2_to_dot16(self.x2);
}
if (cury + 1) < self.y2 {
self.slope_x = div_fixed16_fixed16(self.next_x - self.old_x, self.next_y - self.old_y) >> 2;
}
}
self.fullx += self.slope_x;
} else {
self.fullx += self.slope_x;
}
}
}
pub struct Rasterizer {
edge_starts: Vec<Option<NonNull<ActiveEdge>>>,
width: i32,
height: i32,
cur_y: Dot2,
bounds_top: i32,
bounds_bottom: i32,
bounds_left: i32,
bounds_right: i32,
active_edges: Option<NonNull<ActiveEdge>>,
edge_arena: Arena<ActiveEdge>,
}
impl Rasterizer {
pub fn new(width: i32, height: i32) -> Rasterizer {
let mut edge_starts = Vec::new();
for _ in 0..int_to_dot2(height) {
edge_starts.push(None);
}
Rasterizer {
width: int_to_dot2(width),
height: int_to_dot2(height),
bounds_right: 0,
bounds_left: width,
bounds_top: height,
bounds_bottom: 0,
cur_y: 0,
edge_starts,
edge_arena: Arena::new(),
active_edges: None,
}
}
}
fn cheap_distance(mut dx: Dot6, mut dy: Dot6) -> Dot6 {
dx = dx.abs();
dy = dy.abs();
if dx > dy {
dx + (dy >> 1)
} else {
dy + (dx >> 1)
}
}
fn diff_to_shift(dx: Dot6, dy: Dot6) -> i32 {
let mut dist = cheap_distance(dx, dy);
dist = (dist + (1 << 4)) >> 5;
(32 - ((dist as u32).leading_zeros()) as i32) >> 1
}
fn compute_curve_steps(e: &Edge) -> i32 {
let dx = e.control_x * 2 - e.x1 - e.x2;
let dy = e.control_y * 2 - e.y1 - e.y2;
let shift = diff_to_shift(dot2_to_dot6(dx), dot2_to_dot6(dy));
assert!(shift >= 0);
shift
}
const SAMPLE_SIZE: f32 = (1 << SAMPLE_SHIFT) as f32;
pub const SAMPLE_SHIFT: i32 = 2;
const MAX_COEFF_SHIFT: i32 = 6;
impl Rasterizer {
#[allow(non_snake_case)]
pub fn add_edge(&mut self, mut start: Point, mut end: Point, curve: bool, control: Point) {
if curve {
} else {
}
let e = self.edge_arena.alloc(ActiveEdge::new());
if end.y < start.y {
std::mem::swap(&mut start, &mut end);
e.winding = -1;
} else {
e.winding = 1;
}
let edge = Edge {
x1: f32_to_dot2(start.x),
y1: f32_to_dot2(start.y),
control_x: f32_to_dot2(control.x),
control_y: f32_to_dot2(control.y),
x2: f32_to_dot2(end.x),
y2: f32_to_dot2(end.y),
};
e.x2 = edge.x2;
e.y2 = edge.y2;
e.next = None;
let mut cury = edge.y1;
e.fullx = dot2_to_dot16(edge.x1);
if edge.y2 < 0 || edge.y1 >= self.height {
return;
}
if cury >= e.y2 {
return;
}
self.bounds_top = self.bounds_top.min(dot2_to_int(edge.y1));
self.bounds_bottom = self.bounds_bottom.max(dot2_to_int(edge.y2 + 3));
self.bounds_left = self.bounds_left.min(dot2_to_int(edge.x1));
self.bounds_left = self.bounds_left.min(dot2_to_int(edge.x2));
self.bounds_right = self.bounds_right.max(dot2_to_int(edge.x1 + 3));
self.bounds_right = self.bounds_right.max(dot2_to_int(edge.x2 + 3));
if curve {
self.bounds_left = self.bounds_left.min(dot2_to_int(edge.control_x));
self.bounds_right = self.bounds_right.max(dot2_to_int(edge.control_x + 3));
let mut A = (edge.x1 - edge.control_x - edge.control_x + edge.x2) << (15 - SAMPLE_SHIFT);
let mut B = edge.control_x - edge.x1; let mut shift = compute_curve_steps(&edge);
if shift == 0 {
shift = 1;
} else if shift > MAX_COEFF_SHIFT {
shift = MAX_COEFF_SHIFT;
}
e.shift = shift;
e.count = 1 << shift;
e.dx = 2 * (A >> shift) + 2 * B * (1 << (16 - SAMPLE_SHIFT));
e.ddx = 2 * (A >> (shift - 1));
A = (edge.y1 - edge.control_y - edge.control_y + edge.y2) << (15 - SAMPLE_SHIFT);
B = edge.control_y - edge.y1;
e.dy = 2 * (A >> shift) + 2 * B * (1 << (16 - SAMPLE_SHIFT));
e.ddy = 2 * (A >> (shift - 1));
e.count -= 1;
e.next_x = (e.fullx) + (e.dx >> e.shift);
e.next_y = (cury * (1 << (16 - SAMPLE_SHIFT))) + (e.dy >> e.shift);
e.dx += e.ddx;
e.dy += e.ddy;
while e.count > 0 && cury >= dot16_to_dot2(e.next_y) {
e.next_x += e.dx >> shift;
e.dx += e.ddx;
e.next_y += e.dy >> shift;
e.dy += e.ddy;
e.count -= 1;
}
if e.count == 0 {
e.next_y = dot2_to_dot16(edge.y2);
e.next_x = dot2_to_dot16(edge.x2);
}
e.slope_x = (e.next_x - (e.fullx)) / dot16_to_dot2(e.next_y - dot2_to_dot16(cury));
} else {
e.shift = 0;
e.slope_x = (edge.x2 - edge.x1) * (1 << (16 - SAMPLE_SHIFT)) / (edge.y2 - edge.y1);
}
if cury < 0 {
while cury < 0 {
e.step(cury);
cury += 1;
}
if cury >= e.y2 {
return;
}
}
e.next = self.edge_starts[cury as usize];
self.edge_starts[cury as usize] = Some(NonNull::from(e));
}
fn step_edges(&mut self) {
let mut prev_ptr = &mut self.active_edges as *mut _;
let mut edge = self.active_edges;
let cury = self.cur_y; while let Some(mut e_ptr) = edge {
let e = unsafe { e_ptr.as_mut() };
e.step(cury);
let next = e.next;
if (cury + 1) >= e.y2 {
unsafe { *prev_ptr = next };
} else {
prev_ptr = &mut e.next;
}
edge = next;
}
}
fn insert_starting_edges(&mut self) {
let mut new_edges: Option<NonNull<ActiveEdge>> = None;
let mut edge = self.edge_starts[self.cur_y as usize];
while let Some(mut e_ptr) = edge {
let e = unsafe { e_ptr.as_mut() };
let mut prev_ptr = &mut new_edges as *mut _;
let mut new = new_edges;
while let Some(mut new_ptr) = new {
let a = unsafe { new_ptr.as_mut() };
if e.fullx <= a.fullx {
break;
}
prev_ptr = &mut a.next;
new = a.next;
}
edge = e.next;
e.next = new;
unsafe { *prev_ptr = Some(e_ptr) };
}
let mut prev_ptr = &mut self.active_edges as *mut _;
let mut active = self.active_edges;
let mut edge = new_edges;
while let Some(mut e_ptr) = edge {
let e = unsafe { e_ptr.as_mut() };
while let Some(mut a_ptr) = active {
let a = unsafe { a_ptr.as_mut() };
if e.fullx <= a.fullx {
break;
}
prev_ptr = &mut a.next;
active = a.next;
}
edge = e.next;
e.next = active;
let next_prev_ptr = &mut e.next as *mut _;
unsafe { *prev_ptr = Some(e_ptr) };
prev_ptr = next_prev_ptr;
}
}
fn scan_edges(&mut self, blitter: &mut dyn RasterBlitter, winding_mode: Winding) {
let mut edge = self.active_edges;
let mut winding = 0;
while let Some(mut e_ptr) = edge {
let e = unsafe { e_ptr.as_mut() };
if e.fullx >= 0 {
break;
}
winding += e.winding as i32;
edge = e.next;
}
let mut prevx = 0;
while let Some(mut e_ptr) = edge {
let e = unsafe { e_ptr.as_mut() };
let inside = match winding_mode {
Winding::EvenOdd => winding & 1 != 0,
Winding::NonZero => winding != 0,
};
if inside {
blitter.blit_span(
self.cur_y,
dot16_to_dot2(prevx + (1 << (15 - SAMPLE_SHIFT))),
dot16_to_dot2(e.fullx + (1 << (15 - SAMPLE_SHIFT))),
);
}
if dot16_to_dot2(e.fullx) >= self.width {
break;
}
winding += e.winding as i32;
prevx = e.fullx;
edge = e.next;
}
}
fn sort_edges(&mut self) {
if self.active_edges.is_none() {
return;
}
let mut swapped;
loop {
swapped = false;
let mut edge = self.active_edges.unwrap();
let mut next_edge = unsafe { edge.as_mut() }.next;
let mut prev = &mut self.active_edges as *mut _;
while let Some(mut next_ptr) = next_edge {
let next = unsafe { next_ptr.as_mut() };
if unsafe { edge.as_mut() }.fullx > next.fullx {
unsafe { edge.as_mut() }.next = next.next;
next.next = Some(edge);
unsafe { (*prev) = Some(next_ptr) };
swapped = true;
}
prev = (&mut unsafe { edge.as_mut() }.next) as *mut _;
edge = next_ptr;
next_edge = unsafe { edge.as_mut() }.next;
}
if !swapped {
break;
}
}
}
pub fn rasterize(&mut self, blitter: &mut dyn RasterBlitter, winding_mode: Winding) {
let start = int_to_dot2(self.bounds_top).max(0);
let end = int_to_dot2(self.bounds_bottom).min(self.height);
self.cur_y = start;
while self.cur_y < end {
for _ in 0..4 {
self.insert_starting_edges();
self.scan_edges(blitter, winding_mode);
self.step_edges();
self.sort_edges();
self.cur_y += 1;
}
}
}
pub fn get_bounds(&self) -> IntRect {
intrect(self.bounds_left.max(0),
self.bounds_top.max(0),
self.bounds_right.min(dot2_to_int(self.width)),
self.bounds_bottom.min(dot2_to_int(self.height)))
}
pub fn reset(&mut self) {
if self.bounds_bottom < self.bounds_top {
debug_assert_eq!(self.active_edges, None);
for e in &mut self.edge_starts {
debug_assert_eq!(*e, None);
}
debug_assert_eq!(self.bounds_bottom, 0);
debug_assert_eq!(self.bounds_right, 0);
debug_assert_eq!(self.bounds_top, dot2_to_int(self.height));
debug_assert_eq!(self.bounds_left, dot2_to_int(self.width));
self.edge_arena = Arena::new();
return;
}
let start = int_to_dot2(self.bounds_top).max(0) as usize;
let end = int_to_dot2(self.bounds_bottom).min(self.height) as usize;
self.active_edges = None;
for e in &mut self.edge_starts[start..end] {
*e = None;
}
self.edge_arena = Arena::new();
self.bounds_bottom = 0;
self.bounds_right = 0;
self.bounds_top = dot2_to_int(self.height);
self.bounds_left = dot2_to_int(self.width);
}
}