Skip to content

Font

Descriptor for a bitmap font using 1bpp sprites.

Description

A Font contains an array of Sprite structures, one for each character in the font's character set. Each glyph is rendered as a 1bpp sprite, allowing consistent rendering across platforms.

The font uses fixed-width glyphs for simplicity and performance. All glyphs share the same width and height, with spacing between characters controlled by the spacing field.

Namespace

namespace pixelroot32::graphics {
    struct Font {
        // ...
    };
}

Structure

const Sprite* glyphs

Array of sprites, one per character (indexed by character code - firstChar).

Type: const Sprite*

Access: Read-only

Notes: - Array must contain sprites for all characters from firstChar to lastChar - Each sprite represents one character glyph - Should be stored in flash (const/constexpr) for best performance

Example:

static const Sprite FONT_GLYPHS[] = {
    spaceGlyph,    // Index 0 = ' ' (firstChar = 32)
    exclamationGlyph, // Index 1 = '!'
    // ... more glyphs
};

static const Font myFont = {
    FONT_GLYPHS,
    32,  // firstChar
    126, // lastChar
    5,   // glyphWidth
    7,   // glyphHeight
    1,   // spacing
    8    // lineHeight
};

uint8_t firstChar

First character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 32 (space character)

Notes: - ASCII code of the first character - Common: 32 (space ' ') for ASCII fonts - Glyphs array starts at index 0 for this character

Example:

firstChar = 32;  // Starts at space character

uint8_t lastChar

Last character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 126 (tilde '~')

Notes: - ASCII code of the last character - Common: 126 (tilde '~') for full ASCII fonts - Glyphs array must contain (lastChar - firstChar + 1) sprites

Example:

lastChar = 126;  // Ends at tilde character
// Font contains characters 32-126 (95 characters)

uint8_t glyphWidth

Fixed width of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same width - Typical values: 5, 6, 8 pixels - Smaller = more characters per line, less readable

Example:

glyphWidth = 5;  // 5 pixels wide (like FONT_5X7)

uint8_t glyphHeight

Fixed height of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same height - Typical values: 7, 8, 10 pixels - Smaller = more lines, less readable

Example:

glyphHeight = 7;  // 7 pixels tall (like FONT_5X7)

uint8_t spacing

Horizontal spacing between characters in pixels.

Type: uint8_t

Access: Read-only

Default: Typically 1

Notes: - Space added between characters - 0 = no spacing (characters touch) - 1 = 1 pixel gap (common) - Higher values = more readable but wider text

Example:

spacing = 1;  // 1 pixel between characters

uint8_t lineHeight

Total line height including vertical spacing.

Type: uint8_t

Access: Read-only

Notes: - Should be glyphHeight + verticalSpacing - Used for line breaks and multi-line text - Typical: glyphHeight + 1 or glyphHeight + 2

Example:

lineHeight = 8;  // 7 pixel glyph + 1 pixel spacing

Built-in Fonts

FONT_5X7

Standard 5x7 pixel font (built-in).

Properties: - Width: 5 pixels - Height: 7 pixels - Characters: Typically ASCII 32-126 - Spacing: 1 pixel - Line height: 8 pixels

Usage:

#include "graphics/Font.h"

renderer.drawText("Hello", 10, 10, Color::White, 1, &FONT_5X7);

Creating Custom Fonts

Step 1: Create Glyph Sprites

// Space character (ASCII 32)
static const uint16_t SPACE_GLYPH[] = {
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000
};

// 'A' character (ASCII 65)
static const uint16_t A_GLYPH[] = {
    0b00100,
    0b01010,
    0b10001,
    0b11111,
    0b10001,
    0b10001,
    0b00000
};

// ... more glyphs

Step 2: Create Glyph Array

static const Sprite FONT_GLYPHS[] = {
    {SPACE_GLYPH, 5, 7},  // Index 0 = ' ' (32)
    // ... more glyphs
    {A_GLYPH, 5, 7},      // Index 33 = 'A' (65)
    // ... more glyphs
};

Step 3: Create Font Structure

static const Font MY_FONT = {
    FONT_GLYPHS,  // glyphs array
    32,           // firstChar (space)
    126,          // lastChar (tilde)
    5,            // glyphWidth
    7,            // glyphHeight
    1,            // spacing
    8             // lineHeight
};

Step 4: Use Font

renderer.drawText("Hello", 10, 10, Color::White, 1, &MY_FONT);

Usage Example

#include "graphics/Font.h"
#include "graphics/Renderer.h"

// Using built-in font
void draw(Renderer& renderer) override {
    // Default font
    renderer.drawText("Score: 100", 10, 10, Color::White, 1);

    // Explicit font
    renderer.drawText("Score: 100", 10, 30, Color::White, 1, &FONT_5X7);

    // Centered text with font
    renderer.drawTextCentered("Game Over", 64, Color::Yellow, 2, &FONT_5X7);
}

// Custom font example
static const uint16_t CUSTOM_GLYPHS[][7] = {
    // Space, A, B, C, etc.
};

static const Sprite CUSTOM_SPRITES[] = {
    {CUSTOM_GLYPHS[0], 6, 8},  // Space
    {CUSTOM_GLYPHS[1], 6, 8},  // A
    // ... more
};

static const Font CUSTOM_FONT = {
    CUSTOM_SPRITES,
    32,   // firstChar
    90,   // lastChar (A-Z only)
    6,    // width
    8,    // height
    1,    // spacing
    9     // lineHeight
};

void draw(Renderer& renderer) override {
    renderer.drawText("CUSTOM", 10, 10, Color::White, 1, &CUSTOM_FONT);
}

Text Sizing

Calculate text dimensions:

int getTextWidth(const Font* font, const char* text) {
    if (!font || !text) return 0;

    int width = 0;
    for (int i = 0; text[i] != '\0'; i++) {
        if (text[i] >= font->firstChar && text[i] <= font->lastChar) {
            width += font->glyphWidth + font->spacing;
        }
    }
    return width - font->spacing;  // Remove last spacing
}

int getTextHeight(const Font* font) {
    return font ? font->lineHeight : 8;
}

Performance Considerations

  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)

ESP32 Considerations

  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed

See Also