use crate::framebuffer::FramebufferInfo;
use libm::{floorf, roundf};
fn fractf(x: f32) -> f32 {
x - floorf(x)
}
pub fn framebuffer_x_demo(fb: &mut FramebufferInfo) {
let top_left = (0, 0);
let top_right = (fb.width.saturating_sub(1), 0);
let bottom_left = (0, fb.height.saturating_sub(1));
let bottom_right = (fb.width.saturating_sub(1), fb.height.saturating_sub(1));
draw_wu_line(top_left.0, top_left.1, bottom_right.0, bottom_right.1, fb);
draw_wu_line(top_right.0, top_right.1, bottom_left.0, bottom_left.1, fb);
}
pub fn draw_bresenham(x0: usize, y0: usize, x1: usize, y1: usize, fb: &mut FramebufferInfo) {
let (mut x0, mut y0, x1, y1) = (x0 as isize, y0 as isize, x1 as isize, y1 as isize);
let dx = (x1 - x0).abs();
let dy = -(y1 - y0).abs();
let sx = if x0 < x1 { 1 } else { -1 };
let sy = if y0 < y1 { 1 } else { -1 };
let mut err = dx + dy;
loop {
if x0 >= 0 && (x0 as usize) < fb.width && y0 >= 0 && (y0 as usize) < fb.height {
let offset = fb.address as usize + (((y0 as usize) * fb.stride + (x0 as usize)) * 4);
let pixel_ptr = offset as *mut u32;
unsafe {
pixel_ptr.write_volatile(0xFFFF_FFFF);
}
}
if x0 == x1 && y0 == y1 {
break;
}
let e2 = 2 * err;
if e2 >= dy {
err += dy;
x0 += sx;
}
if e2 <= dx {
err += dx;
y0 += sy;
}
}
}
fn blend_pixel(x: isize, y: isize, brightness: f32, fb: &mut FramebufferInfo) {
if x >= 0 && (x as usize) < fb.width && y >= 0 && (y as usize) < fb.height {
let offset = fb.address as usize + (((y as usize) * fb.stride + (x as usize)) * 4);
let pixel_ptr = offset as *mut u32;
unsafe {
let bg = pixel_ptr.read_volatile();
let alpha = (brightness.clamp(0.0, 1.0) * 255.0) as u32;
let inv_alpha = 255 - alpha;
let r = ((bg >> 16) & 0xFF) * inv_alpha / 255 + 255 * alpha / 255;
let g = ((bg >> 8) & 0xFF) * inv_alpha / 255 + 255 * alpha / 255;
let b = (bg & 0xFF) * inv_alpha / 255 + 255 * alpha / 255;
let blended = (0xFF << 24) | (r << 16) | (g << 8) | b;
pixel_ptr.write_volatile(blended);
}
}
}
pub fn draw_wu_line(x0: usize, y0: usize, x1: usize, y1: usize, fb: &mut FramebufferInfo) {
let (mut x0, mut y0, mut x1, mut y1) = (x0 as f32, y0 as f32, x1 as f32, y1 as f32);
let steep = (y1 - y0).abs() > (x1 - x0).abs();
if steep {
core::mem::swap(&mut x0, &mut y0);
core::mem::swap(&mut x1, &mut y1);
}
if x0 > x1 {
core::mem::swap(&mut x0, &mut x1);
core::mem::swap(&mut y0, &mut y1);
}
let dx = x1 - x0;
let dy = y1 - y0;
let gradient = if dx == 0.0 { 1.0 } else { dy / dx };
let xend = roundf(x0);
let yend = y0 + gradient * (xend - x0);
let xgap = 1.0 - fractf(x0 + 0.5);
let xpxl1 = xend as isize;
let ypxl1 = floorf(yend) as isize;
if steep {
blend_pixel(ypxl1, xpxl1, (1.0 - fractf(yend)) * xgap, fb);
blend_pixel(ypxl1 + 1, xpxl1, fractf(yend) * xgap, fb);
} else {
blend_pixel(xpxl1, ypxl1, (1.0 - fractf(yend)) * xgap, fb);
blend_pixel(xpxl1, ypxl1 + 1, fractf(yend) * xgap, fb);
}
let mut intery = yend + gradient;
let xend = roundf(x1);
let yend = y1 + gradient * (xend - x1);
let xgap = fractf(x1 + 0.5);
let xpxl2 = xend as isize;
let ypxl2 = floorf(yend) as isize;
if steep {
blend_pixel(ypxl2, xpxl2, (1.0 - fractf(yend)) * xgap, fb);
blend_pixel(ypxl2 + 1, xpxl2, fractf(yend) * xgap, fb);
} else {
blend_pixel(xpxl2, ypxl2, (1.0 - fractf(yend)) * xgap, fb);
blend_pixel(xpxl2, ypxl2 + 1, fractf(yend) * xgap, fb);
}
if steep {
for x in (xpxl1 + 1)..xpxl2 {
let y = floorf(intery) as isize;
blend_pixel(y, x, 1.0 - fractf(intery), fb);
blend_pixel(y + 1, x, fractf(intery), fb);
intery += gradient;
}
} else {
for x in (xpxl1 + 1)..xpxl2 {
let y = floorf(intery) as isize;
blend_pixel(x, y, 1.0 - fractf(intery), fb);
blend_pixel(x, y + 1, fractf(intery), fb);
intery += gradient;
}
}
}