agb 0.23.1

Library for Game Boy Advance Development
Documentation
use core::fmt::Write;

use crate::{
    display::{HEIGHT, WIDTH, bitmap3::Bitmap3, font::Font},
    fixnum::Vector2D,
};

static FONT: Font = include_font!("fnt/ark-pixel-10px-proportional-latin.ttf", 10);

pub struct BitmapTextRender<'bitmap, 'gba> {
    head_position: Vector2D<i32>,
    start_x: i32,
    bitmap: &'bitmap mut Bitmap3<'gba>,
    colour: u16,
    previous_char: Option<char>,
}

impl<'bitmap, 'gba> BitmapTextRender<'bitmap, 'gba> {
    pub fn new(
        bitmap: &'bitmap mut Bitmap3<'gba>,
        position: Vector2D<i32>,
        start_colour: u16,
    ) -> Self {
        Self {
            head_position: position,
            start_x: position.x,
            bitmap,
            colour: start_colour,
            previous_char: None,
        }
    }

    pub fn head_y_position(&self) -> i32 {
        self.head_position.y
    }

    fn render_letter(&mut self, c: char) {
        let letter = FONT.letter(c);

        self.head_position.x += letter.xmin as i32
            + self
                .previous_char
                .take()
                .map_or(0, |c| letter.kerning_amount(c));
        self.previous_char = Some(c);

        if self.head_position.x + letter.width as i32 >= WIDTH {
            self.newline();
        }

        if self.head_position.y + letter.height as i32 >= HEIGHT {
            return;
        }

        let y_position_start =
            self.head_position.y + FONT.ascent() - letter.height as i32 - letter.ymin as i32;

        for y in 0..letter.height as usize {
            for x in 0..letter.width as usize {
                let rendered = letter.bit_absolute(x, y);
                let x = x as i32 + self.head_position.x;
                let y = y as i32 + y_position_start;

                if rendered && (0..WIDTH).contains(&x) && (0..HEIGHT).contains(&y) {
                    self.bitmap.draw_point(x, y, self.colour);
                }
            }
        }

        self.head_position.x += letter.advance_width as i32;
    }

    fn render_char(&mut self, c: char) {
        match c {
            '\n' => {
                self.newline();
            }
            ' ' => {
                self.head_position.x += FONT.letter(' ').advance_width as i32;
            }
            letter => self.render_letter(letter),
        }
    }

    fn newline(&mut self) {
        self.head_position.x = self.start_x;
        self.head_position.y += FONT.line_height();
    }
}

impl Write for BitmapTextRender<'_, '_> {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        for c in s.chars() {
            self.render_char(c);
        }

        Ok(())
    }
}