use crate::rasterizer_scanline_aa::Scanline;
#[derive(Debug, Clone, Copy, Default)]
pub struct PackedSpan {
pub x: i32,
pub len: i32,
pub cover_offset: usize,
}
pub struct ScanlineP8 {
last_x: i32,
y_val: i32,
covers: Vec<u8>,
cover_ptr: usize,
spans: Vec<PackedSpan>,
cur_span: usize,
}
impl ScanlineP8 {
pub fn new() -> Self {
Self {
last_x: 0x7FFF_FFF0,
y_val: 0,
covers: Vec::new(),
cover_ptr: 0,
spans: Vec::new(),
cur_span: 0,
}
}
pub fn reset(&mut self, _min_x: i32, max_x: i32) {
let max_len = (max_x + 3) as usize;
if max_len > self.spans.len() {
self.spans.resize(max_len, PackedSpan::default());
self.covers.resize(max_len, 0);
}
self.last_x = 0x7FFF_FFF0;
self.cover_ptr = 0;
self.cur_span = 0;
self.spans[0].len = 0;
}
pub fn begin(&self) -> &[PackedSpan] {
&self.spans[1..=self.cur_span]
}
pub fn covers(&self) -> &[u8] {
&self.covers
}
}
impl Scanline for ScanlineP8 {
fn reset_spans(&mut self) {
self.last_x = 0x7FFF_FFF0;
self.cover_ptr = 0;
self.cur_span = 0;
self.spans[0].len = 0;
}
fn add_cell(&mut self, x: i32, cover: u32) {
self.covers[self.cover_ptr] = cover as u8;
if x == self.last_x + 1 && self.spans[self.cur_span].len > 0 {
self.spans[self.cur_span].len += 1;
} else {
self.cur_span += 1;
self.spans[self.cur_span].cover_offset = self.cover_ptr;
self.spans[self.cur_span].x = x;
self.spans[self.cur_span].len = 1;
}
self.last_x = x;
self.cover_ptr += 1;
}
fn add_span(&mut self, x: i32, len: u32, cover: u32) {
if x == self.last_x + 1
&& self.spans[self.cur_span].len < 0
&& cover as u8 == self.covers[self.spans[self.cur_span].cover_offset]
{
self.spans[self.cur_span].len -= len as i32;
} else {
self.covers[self.cover_ptr] = cover as u8;
self.cur_span += 1;
self.spans[self.cur_span].cover_offset = self.cover_ptr;
self.cover_ptr += 1;
self.spans[self.cur_span].x = x;
self.spans[self.cur_span].len = -(len as i32);
}
self.last_x = x + len as i32 - 1;
}
fn finalize(&mut self, y: i32) {
self.y_val = y;
}
fn num_spans(&self) -> u32 {
self.cur_span as u32
}
fn y(&self) -> i32 {
self.y_val
}
}
impl Default for ScanlineP8 {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let sl = ScanlineP8::new();
assert_eq!(sl.num_spans(), 0);
}
#[test]
fn test_add_cell() {
let mut sl = ScanlineP8::new();
sl.reset(0, 100);
sl.add_cell(10, 128);
assert_eq!(sl.num_spans(), 1);
let spans = sl.begin();
assert_eq!(spans[0].x, 10);
assert_eq!(spans[0].len, 1); assert_eq!(sl.covers()[spans[0].cover_offset], 128);
}
#[test]
fn test_adjacent_cells_form_per_pixel_span() {
let mut sl = ScanlineP8::new();
sl.reset(0, 100);
sl.add_cell(10, 100);
sl.add_cell(11, 200);
sl.add_cell(12, 150);
assert_eq!(sl.num_spans(), 1);
let spans = sl.begin();
assert_eq!(spans[0].len, 3); }
#[test]
fn test_add_span_creates_solid_span() {
let mut sl = ScanlineP8::new();
sl.reset(0, 100);
sl.add_span(5, 10, 255);
assert_eq!(sl.num_spans(), 1);
let spans = sl.begin();
assert_eq!(spans[0].x, 5);
assert_eq!(spans[0].len, -10); assert_eq!(sl.covers()[spans[0].cover_offset], 255);
}
#[test]
fn test_adjacent_solid_spans_merge() {
let mut sl = ScanlineP8::new();
sl.reset(0, 100);
sl.add_span(5, 10, 255);
sl.add_span(15, 5, 255); assert_eq!(sl.num_spans(), 1);
let spans = sl.begin();
assert_eq!(spans[0].len, -15); }
#[test]
fn test_adjacent_solid_spans_different_cover_no_merge() {
let mut sl = ScanlineP8::new();
sl.reset(0, 100);
sl.add_span(5, 10, 255);
sl.add_span(15, 5, 128); assert_eq!(sl.num_spans(), 2);
}
#[test]
fn test_cell_after_solid_span_new_span() {
let mut sl = ScanlineP8::new();
sl.reset(0, 100);
sl.add_span(5, 3, 200);
sl.add_cell(8, 100); assert_eq!(sl.num_spans(), 2);
}
#[test]
fn test_reset_spans() {
let mut sl = ScanlineP8::new();
sl.reset(0, 100);
sl.add_cell(10, 128);
sl.reset_spans();
assert_eq!(sl.num_spans(), 0);
}
}