use super::{clamp, Rasterizer};
#[inline(always)] fn fmax(x: f32, y: f32) -> f32 { if x > y { x } else { y } }
#[inline(always)] fn fmin(x: f32, y: f32) -> f32 { if x < y { x } else { y } }
#[inline(always)] fn floor(x: f32) -> i32 { (x as f64).floor() as i32 }
#[inline(always)] fn ceil(x: f32) -> i32 { (x as f64).ceil() as i32 }
impl Rasterizer {
pub fn floating_accumulate_mask(&mut self) {
let buf = self.buf.as_u32();
let mut acc = 0f32;
for v in buf {
acc += unsafe { *(v as *mut u32 as *mut f32) };
let a = clamp_alpha(acc);
*v = (ALMOST65536 * a) as u32;
}
}
pub fn floating_line_to(&mut self, bx: f32, by: f32) {
let [ax, ay] = self.pen;
self.pen = [bx, by];
let (dir, ax, ay, bx, by) = if ay > by {
(-1f32, bx, by, ax, ay)
} else {
(1f32, ax, ay, bx, by)
};
if by-ay <= 0.000001 { return }
let dxdy = (bx - ax) / (by - ay);
let mut x = ax;
let mut y = floor(ay);
let y_max = ceil(by);
let y_max = if y_max > self.size[1] as i32 {
self.size[1] as i32
} else {
y_max
};
let width = self.size[0] as i32;
while y < y_max {
let dy = fmin((y+1) as f32, by) - fmax(y as f32, ay);
let x_next = x + (dy * dxdy) as f32;
if y < 0 {
x = x_next;
continue;
}
let buf = &mut self.buf.as_f32()[(y*width) as usize..];
let d = (dy * dir) as f32;
let (x0, x1) = if x > x_next {
(x_next, x)
} else {
(x, x_next)
};
let x0i = floor(x0);
let x0floor = x0i as f32;
let x1i = ceil(x1);
let x1ceil = x1i as f32;
if x1i <= x0i+1 {
let xmf = (0.5 * (x+x_next)) as f32 - x0floor;
let i = clamp(x0i+0, width);
if i < buf.len() {
buf[i] += d - (d*xmf) as f32;
}
let i = clamp(x0i+1, width);
if i < buf.len() {
buf[i] += (d * xmf) as f32;
}
} else {
let s = 1.0 / (x1 - x0);
let x0f = x0 - x0floor;
let one_minus_x0f = 1.0 - x0f;
let a0 = (0.5 * s * one_minus_x0f * one_minus_x0f) as f32;
let x1f = x1 - x1ceil + 1.0;
let am = (0.5 * s * x1f * x1f) as f32;
let i = clamp(x0i, width);
if i < buf.len() {
buf[i] += (d * a0) as f32;
}
if x1i == x0i+2 {
let i = clamp(x0i+1, width);
if i < buf.len() {
buf[i] += (d * (1.0 - a0 - am)) as f32;
}
} else {
let a1 = (s * (1.5 - x0f)) as f32;
let i = clamp(x0i+1, width);
if i < buf.len() {
buf[i] += (d * (a1 - a0)) as f32;
}
let d_times_s = (d * s) as f32;
for xi in (x0i + 2)..(x1i-1) {
let i = clamp(xi, width);
if i < buf.len() {
buf[i] += d_times_s;
}
}
let a2 = a1 + (s * (x1i-x0i-3) as f32) as f32;
let i = clamp(x1i-1, width);
if i < buf.len() {
buf[i] += (d * (1.0 - a2 - am)) as f32;
}
}
let i = clamp(x1i, width);
if i < buf.len() {
buf[i] += (d * am) as f32;
}
}
x = x_next;
y += 1;
}
}
}
const ALMOST256: f32 = 255.99998;
const ALMOST65536: f32 = ALMOST256 * 256.0;
#[inline(always)]
fn clamp_alpha(mut a: f32) -> f32 {
if a < 0.0 { a = -a; }
if a > 1.0 { a = 1.0; }
a
}
pub fn accumulate_op_over(dst: &mut [u8], src: &[f32]) {
if dst.len() < src.len() { return }
let mut acc = 0f32;
for (i, v) in src.iter().enumerate() {
acc += *v;
let a = clamp_alpha(acc);
let dst_a = (dst[i] as u32) * 0x101;
let mask_a = (ALMOST65536 * a) as u32;
let out_a = dst_a * (0xFFFF - mask_a) / 0xFFFF + mask_a;
dst[i] = (out_a >> 8) as u8;
}
}
pub fn accumulate_op_src(dst: &mut [u8], src: &[f32]) {
if dst.len() < src.len() { return }
let mut acc = 0f32;
for (i, v) in src.iter().enumerate() {
acc += *v;
let a = clamp_alpha(acc);
dst[i] = (ALMOST256 * a) as u8;
}
}
pub fn accumulate_mask(dst: &mut [u32], src: &[f32]) {
if dst.len() < src.len() { return }
let mut acc = 0f32;
for (i, v) in src.iter().enumerate() {
acc += *v;
let a = clamp_alpha(acc);
dst[i] = (ALMOST65536 * a) as u32;
}
}
pub fn accumulate_mask_x(buf: &mut [u32]) {
let src = unsafe { std::mem::transmute(&buf[..]) };
accumulate_mask(buf, src)
}
pub fn accumulate_mask_inplace(buf: &mut super::SimdVec) {
unsafe {
let dst = buf.u_u32();
let src = buf.u_f32();
accumulate_mask(dst, src)
}
}