atanor 0.1.0

Motor 3D ray-traced que vive solo y exclusivamente en la terminal.
Documentation
use glam::Vec3;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Color;
use ratatui::widgets::Widget;

pub struct Framebuffer {
    pub width: u16,
    pub height: u16,
    pub pixels: Vec<Vec3>,
}

impl Framebuffer {
    pub fn new(width: u16, height: u16) -> Self {
        Self {
            width,
            height,
            pixels: vec![Vec3::ZERO; width as usize * height as usize],
        }
    }

    pub fn resize(&mut self, width: u16, height: u16) {
        if self.width == width && self.height == height {
            return;
        }
        self.width = width;
        self.height = height;
        self.pixels.resize(width as usize * height as usize, Vec3::ZERO);
    }

    #[inline]
    pub fn idx(&self, x: u16, y: u16) -> usize {
        y as usize * self.width as usize + x as usize
    }

    #[allow(dead_code)]
    pub fn clear(&mut self, color: Vec3) {
        self.pixels.fill(color);
    }
}

pub struct FramebufferView<'a> {
    pub fb: &'a Framebuffer,
}

impl<'a> Widget for FramebufferView<'a> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        let fb = self.fb;
        let cols = area.width.min(fb.width);
        let rows_cells = area.height.min(fb.height / 2);

        for cy in 0..rows_cells {
            let y_top = cy * 2;
            let y_bot = y_top + 1;
            for cx in 0..cols {
                let top = fb.pixels[fb.idx(cx, y_top)];
                let bot = fb.pixels[fb.idx(cx, y_bot)];
                let cell = &mut buf[(area.x + cx, area.y + cy)];
                cell.set_char('\u{2580}'); // ▀ UPPER HALF BLOCK
                cell.set_fg(vec3_to_color(top));
                cell.set_bg(vec3_to_color(bot));
            }
        }
    }
}

#[inline]
fn vec3_to_color(c: Vec3) -> Color {
    let r = (c.x.clamp(0.0, 1.0) * 255.0) as u8;
    let g = (c.y.clamp(0.0, 1.0) * 255.0) as u8;
    let b = (c.z.clamp(0.0, 1.0) * 255.0) as u8;
    Color::Rgb(r, g, b)
}