use typed_arena::Arena;
use euclid::Point2D;
type Point = Point2D<f32>;
use crate::blitter::Blitter;
use std::ptr::NonNull;
struct Edge {
x1: i32,
y1: i32,
x2: i32,
y2: i32,
control_x: i32,
control_y: i32,
}
pub struct ActiveEdge {
x2: i32,
y2: i32,
next: Option<NonNull<ActiveEdge>>,
slope_x: i32,
fullx: i32,
next_x: i32,
next_y: i32,
dx: i32,
ddx: i32,
dy: i32,
ddy: i32,
old_x: i32,
old_y: i32,
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: i32) {
if self.shift != 0 {
if cury >= (self.next_y >> 16) {
self.old_y = self.next_y;
self.old_x = self.next_x;
self.fullx = self.next_x;
while self.count > 0 && (cury >= (self.next_y >> 16)) {
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 = self.y2 << 16;
self.next_x = self.x2 << 16;
}
if (cury + 1) < self.y2 {
self.slope_x = ((self.next_x - self.old_x) << 3) / ((self.next_y - self.old_y) >> 13);
}
}
self.fullx += self.slope_x;
} else {
self.fullx += self.slope_x;
}
}
}
#[derive(Clone, Copy)]
pub enum Winding {
EvenOdd,
NonZero,
}
pub struct Rasterizer
{
edge_starts: Vec<Option<NonNull<ActiveEdge>>>,
width: i32,
height: i32,
cur_y: 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..(height * 4) {
edge_starts.push(None);
}
Rasterizer {
width: width * 4,
height: height * 4,
cur_y: 0,
edge_starts,
edge_arena: Arena::new(),
active_edges: None,
}
}
}
fn abs(mut value: i32) -> i32 {
if value < 0 {
value = -value;
}
return value;
}
fn cheap_distance(mut dx: i32, mut dy: i32) -> i32 {
dx = abs(dx);
dy = abs(dy);
if dx > dy {
dx += dy >> 1;
} else {
dx = dy + (dx >> 1);
}
return dx;
}
fn diff_to_shift(dx: i32, dy: i32) -> i32 {
let mut dist = cheap_distance(dx, dy);
dist = (dist + (1 << 4)) >> 5;
return ((32 - ((dist as u32).leading_zeros() )as i32)) >> 1;
}
fn compute_curve_steps(e: &Edge) -> i32 {
let dx = (e.control_x << 1) - e.x1 - e.x2;
let dy = (e.control_y << 1) - e.y1 - e.y2;
let shift = diff_to_shift(dx << 4, dy << 4);
assert!(shift >= 0);
return shift;
}
const SAMPLE_SIZE: f32 = 4.;
const SAMPLE_SHIFT: i32 = 2;
const SHIFT: i32 = 2;
const SCALE: i32 = (1 << SHIFT);
const MASK: i32 = (SCALE - 1);
const MAX_COEFF_SHIFT: i32 = 6;
impl Rasterizer {
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: (start.x * SAMPLE_SIZE) as i32,
y1: (start.y * SAMPLE_SIZE) as i32,
control_x: (control.x * SAMPLE_SIZE) as i32,
control_y: (control.y * SAMPLE_SIZE) as i32,
x2: (end.x * SAMPLE_SIZE) as i32,
y2: (end.y * SAMPLE_SIZE) as i32,
};
e.x2 = edge.x2;
e.y2 = edge.y2;
e.next = None;
let mut cury = edge.y1;
e.fullx = edge.x1 << 16;
if edge.y2 < 0 || edge.y1 > self.height {
return;
}
if cury >= e.y2 {
return;
}
if curve {
let mut A = (edge.x1 - edge.control_x - edge.control_x + edge.x2) << 15;
let mut B = edge.control_x - edge.x1;
let mut C = 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 * 65536;
e.ddx = 2 * (A >> (shift - 1));
A = (edge.y1 - edge.control_y - edge.control_y + edge.y2) << 15;
B = edge.control_y - edge.y1;
C = edge.y1;
e.dy = 2 * (A >> shift) + 2 * B * 65536;
e.ddy = 2 * (A >> (shift - 1));
e.count -= 1;
e.next_x = (e.fullx) + (e.dx >> e.shift);
e.next_y = (cury * 65536) + (e.dy >> e.shift);
e.dx += e.ddx;
e.dy += e.ddy;
while e.count > 0 && cury >= (e.next_y >> 16) {
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 = edge.y2 << 16;
e.next_x = edge.x2 << 16;
}
e.slope_x = ((e.next_x - (e.fullx)) << 2) / ((e.next_y - (cury << 16)) >> 14);
} else {
e.shift = 0;
e.slope_x = ((edge.x2 - edge.x1) * (1 << 16)) / (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(unsafe { NonNull::new_unchecked(e as *mut _) });
}
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;
}
}
}
impl Rasterizer {
fn scan_edges(&mut self, blitter: &mut Blitter, 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, (prevx + (1 << 15)) >> 16, (e.fullx + (1 << 15)) >> 16);
}
if (e.fullx >> 16) >= 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 Blitter, winding_mode: Winding) {
self.cur_y = 0;
while self.cur_y < self.height {
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 reset(&mut self) {
self.active_edges = None;
for e in &mut self.edge_starts {
*e = None;
}
self.edge_arena = Arena::new();
}
}