Renderer for bitmap fonts on the GBA using the agb framework
Use the AGB Font Converter to convert images to fonts and for loading fonts from images via macro
In Cargo.toml gba_agb_font_renderer = "0.6.0"
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:
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);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);TypewriterRenderer reveals text one chunk at a time. Call update() once per frame and draw() to blit newly revealed characters.
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:
tw.clear(&font);
tw.load_text(b"New message", vec2(8, 16));MultiTypewriterRenderer manages several independent text streams over a single shared tile pool. Each stream gets a slot index returned by add_text.
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();Two modes are supported, selected by the mode byte at offset 0.
| 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 |
| 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 |
| Offset | Size | Field |
|---|---|---|
| 3 | 256 | char_widths — advance width per code point |
| 259 | 1 | padding to 4-byte boundary |
| 260 | varies | 4bpp pixel data |
Stored as u32 values, each holding 8 pixels at 4 bits per pixel (4bpp). Each glyph row occupies (glyph_width + 7) / 8 u32s. Palette index 0 is transparent.