Bitmap font parser and render helpers for Odin.
Currently supports parsing following BMFont formats:
- XML — Standard BMFont XML (
.xml,.fnt), produced by virtually every exporter. Requires a separate atlas texture. Check./fonts/WhitePeaberry.xmlfor example. - Text — AngelCode's text format (
.txt,.fnt) — one tag per line followed bykey=valuepairs. Check./fonts/WhitePeaberry.txtfor example. Requires a separate atlas texture. - JSON byte stream — Each character's pixels are encoded directly as bit-pattern
entries in a JSON map. The parser packs them into a virtual atlas for you.
Check
./fonts/monogram-bitfontmaker.jsonfor example.
import "bmfont"
// Load and parse your XML font to bmfont.Font
font, err := bmfont.load_bmfont_xml(#load("fonts/WhitePeaberry.xml"))
defer bmfont.destroy_font(font) // Remember to free it after use
// Text format is also supported
font, err := bmfont.load_bmfont_text(#load("fonts/WhitePeaberry.txt"),
allocator=context.temp_allocator)
// JSON bytestream — returns the `Font` and `Atlas :: struct {pixels: [][4]u8, size: [2]int}`
font, atlas, err := bmfont.load_json_bytestream(
#load("fonts/monogram-bitfontmaker.json"),
include = "", // string of codepoints to keep in atlas/font; empty keeps everything
space_width = 4, // space glyph is made from empty bytes, so you need to set it's width explicitly
atlas_cols = 10, // how many glyphs should be in the atlas horizontally
atlas_gap = 1, // gap in pixels between glyphs in atlas
allocator = context.temp_allocator,
)
defer delete(atlas.pixels) // atlas pixels are allocated with `allocator` paramfind_glyph(font, codepoint) resolves a rune to a Glyph in O(runs of
consecutive codepoints) via the per-font ranges table.
draw_text is backend-agnostic.
Each glyph turn calls the callback with the source rect (in atlas pixels)
and the destination rect (in screen pixels)
so the caller can blit however it likes:
import "bmfont"
bmfont.draw_text("Hello", font,
my_draw_callback, // proc (src, dst: Rect)
scale = 4, // atlas-pixel-to-screen-pixel multiplier
origin = {10, 10}, // top-left of the text in screen pixels
cursor = &cursor, // optional pen position; updated as text advances
)Newlines (\n) reset the pen to origin.x and advance y by the line height.
Tabs (\t) advance the pen by four spaces.
Unknown codepoints fall through to the next glyph with a space-width advance.
font.info.spacing.x (horizontal) is added to each glyph's advance, and
font.info.spacing.y (vertical) is added to the line height, so the BMFont
<info spacing="…"> attribute flows through to the layout automatically.
measure_text(text, font, scale) returns the [width, height] in screen
pixels the text would occupy. Use it to size a container, compute a wrap width,
or pre-compute a cursor offset without drawing:
size := bmfont.measure_text("Hello, world!", font, scale=4)
if size.x > max_width {
// wrap, truncate, or fall back to a smaller font_size
}space_advance(font) returns the pixel advance of a single space
(used as the fallback when a codepoint isn't in the font).
In example/ you'll see how to draw some text using bitmap fonts.
make # or `odin run example`It uses karl2d for windowing and rendering.
It requires to have it in the shared: odin collection. (odin/shared/karl2d)
See example/static_fonts.odin for how can bmfonts be loaded directly to karl2d state,
so you can use k2.draw_text() and k2.measure_text() with bmfonts.
-
Odin library — MIT License
-
example/— Public Domain -
Peaberry font — by Emily (emhuo) — Open Font License Version 1.1
-
Monogram font — by Datagoblin — CC0
-
Pixel Bitmap Fonts — by frostyfreeze — CC0 / Public Domain
