[![Crates.io](https://img.shields.io/crates/v/gba_agb_font_renderer)](https://crates.io/crates/gba_agb_font_renderer "Crates.io version")
[![Documentation](https://img.shields.io/docsrs/gba_agb_font_renderer)](https://docs.rs/gba_agb_font_renderer "Documentation")

# Bitmap Font for GBA/AGB

Renderer for bitmap fonts on the GBA using the [`agb`](https://github.com/agbrs/agb) framework

## Font converter

Use the [AGB Font Converter](https://github.com/emmabritton/agb_font_converter) to convert images to fonts and for loading fonts from images via macro

## Usage

In Cargo.toml `gba_agb_font_renderer = "0.6.0"`

### Loading a font

> [!TIP]
> Use the macro from https://crates.io/crates/gba_agb_font_loader instead of these

Two font types are available: `FullFont` (all 256 code points) and `PrintableFont` (95 printable ASCII chars, 0x20–0x7E). Load them at compile time with the corresponding macro:

```rust
use gba_agb_font_renderer::prelude::*;

// Full 256-char font from ROM (default)
let font = full_font!(include_bytes!("my_font.bin"));

// Printable ASCII font, placed in IWRAM for faster blitting
// (~8× fewer waitstates per pixel row — only worthwhile for printable fonts ~3 KB)
let font = printable_font!(include_bytes!("my_font.bin"), iwram);

// Full 256-char font placed in EWRAM
let font = full_font!(include_bytes!("my_font.bin"), ewram);
```

### Rendering text

```rust
use gba_agb_font_renderer::prelude::*;
use agb::fixnum::vec2;

let format = TextFormat::new(TextOverflow::Wrap(200, true), TextAlign::Left, (0, 0));
let mut renderer = TextRenderer::default();
renderer.draw_text(b"Hello, world!", &font, &mut bg, vec2(8, 16), &format);
```

### Typewriter effect

`TypewriterRenderer` reveals text one chunk at a time. Call `update()` once per frame and `draw()` to blit newly revealed characters.

```rust
use gba_agb_font_renderer::prelude::*;
use agb::fixnum::vec2;

let format = TextFormat::new(TextOverflow::Wrap(200, true), TextAlign::Left, (0, 0));
// 1 character revealed every 2 frames
let mut tw = TypewriterRenderer::new(1, 2, &format);
tw.load_text(b"Hello, world!", vec2(8, 16));

loop {
    tw.update();
    tw.draw(&font, &mut bg, 15);
    if tw.is_complete() { break; }
    vblank.wait_for_vblank();
}
```

To clear the text area before loading new text:

```rust
tw.clear(&font);
tw.load_text(b"New message", vec2(8, 16));
```

### Multiple typewriter streams

`MultiTypewriterRenderer` manages several independent text streams over a single shared tile pool. Each stream gets a slot index returned by `add_text`.

```rust
use gba_agb_font_renderer::prelude::*;
use agb::fixnum::vec2;

let name_format = TextFormat::default();
let dialog_format = TextFormat::new(TextOverflow::Wrap(200, true), TextAlign::Left, (0, 0));

// default: 1 char revealed every 2 frames
let mut mtw = MultiTypewriterRenderer::new(2, 1);
mtw.add_text(SlotFont::from(&NAME_FONT), b"Hero", vec2(8, 8), &name_format);
let dialog = mtw.add_text(SlotFont::from(&DIALOG_FONT), b"Hello, world!", vec2(8, 24), &dialog_format);

loop {
    mtw.update();
    mtw.draw(&mut bg, 15);
    if mtw.is_complete() { break; }
    vblank.wait_for_vblank();
}
mtw.clear_all();
```

## Font binary format

Two modes are supported, selected by the `mode` byte at offset 0.

### Common header

| Offset | Size | Field                                         |
|--------|------|-----------------------------------------------|
| 0      | 1    | `mode` — `0` = printable ASCII, `1` = all-256 |
| 1      | 1    | `glyph_width` — glyph cell width in pixels    |
| 2      | 1    | `glyph_height` — glyph cell height in pixels  |

### Mode 0 — printable ASCII (95 glyphs)

| Offset | Size   | Field                                                             |
|--------|--------|-------------------------------------------------------------------|
| 3      | 95     | `char_widths` — advance width per character, ascending byte order |
| 98     | 2      | padding to 4-byte boundary                                        |
| 100    | varies | 4bpp pixel data                                                   |

### Mode 1 — all-256 (256 glyphs)

| Offset | Size   | Field                                        |
|--------|--------|----------------------------------------------|
| 3      | 256    | `char_widths` — advance width per code point |
| 259    | 1      | padding to 4-byte boundary                   |
| 260    | varies | 4bpp pixel data                              |

### Pixel data

Stored as `u32` values, each holding 8 pixels at 4 bits per pixel (4bpp). Each glyph row occupies `(glyph_width + 7) / 8` `u32`s. Palette index 0 is transparent.
