# How Apollo PS4 Integrates libfont and TTF Support for Text Rendering

> Discover how Apollo PS4 integrates libfont and TTF support for efficient text rendering. Explore its 2D text engine and font handling capabilities.

- Repository: [Damián Parrino/apollo-ps4](https://github.com/bucanero/apollo-ps4)
- Tags: deep-dive
- Published: 2026-02-26

---

**Apollo PS4 uses a lightweight 2D text engine called `libfont` that renders pre-packed bitmap fonts like Adonais directly from memory, while maintaining a commented-out stub for TrueType Font (TTF) support via callback-based rasterization.**

The `bucanero/apollo-ps4` repository implements a custom font subsystem optimized for the PS4's limited user-mode graphics API. This system prioritizes speed and binary size by using the embedded [`font_adonais.h`](https://github.com/bucanero/apollo-ps4/blob/main/font_adonais.h) bitmap for production rendering, while preserving a documented extension point for developers who require dynamic TTF glyph generation.

## The libfont Architecture: Bitmap vs. TTF Rendering Paths

The font engine in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c) exposes two distinct loading APIs, though only the bitmap path is active in production builds.

### Bitmap Font Pipeline

The `AddFontFromBitmapArray()` function (lines 35–78 in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c)) ingests raw monochrome pixel data and converts it into RSX-compatible textures. It receives:

- A pointer to the source bitmap array (e.g., `data_font_Adonais` from [`font_adonais.h`](https://github.com/bucanero/apollo-ps4/blob/main/font_adonais.h))
- A pointer to RSX texture memory (`gFontTextureBase`)
- Character range (first and last ASCII code)
- Glyph cell dimensions (`w` × `h`)
- Pixel format flags

The function generates two texture copies—black and white—using SDL surface operations, registers them with the RSX texture manager, and stores offsets and dimensions in the global `font_datas` structure.

### TTF Support Stub

The `AddFontFromTTF()` function (lines 82–124 in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c)) is currently wrapped in a comment block and excluded from compilation. Its design expects a user-provided callback with the signature:

```c
void ttf_callback(u8 chr, u8 *bitmap, short *w, short *h, short *y_correction);

```

When enabled, the callback rasterizes individual glyphs on demand into 8-bit grayscale bitmaps. The stub then packs these into the RSX A4R4G4B4 format, builds the same dual-texture (black/white) setup as the bitmap path, and records the texture offsets. This ensures that `DrawString()` and other rendering functions require no modifications to support TTF sources.

## Loading the Adonais Bitmap Font from font_adonais.h

The [`include/font_adonais.h`](https://github.com/bucanero/apollo-ps4/blob/main/include/font_adonais.h) header provides a production-ready monospace font containing 95 printable ASCII characters (0x20–0x7E). The data is defined as:

```c
static const uint8_t data_font_Adonais[124*95] = { ... };

```

Each glyph occupies **124 bytes**, representing a **32×31 pixel** cell at 1 bit per pixel (padded to 32-bit alignment). To integrate this font into Apollo:

```c
#include "libfont.h"
#include "font_adonais.h"

/* RSX-aligned texture memory allocated during graphics initialization */
extern u8 *gFontTexture;

void SetupAdonaisFont(void)
{
    /* Initialize the font subsystem */
    ResetFont();
    
    /* Load the bitmap array into texture memory */
    AddFontFromBitmapArray(
        gFontTexture,              /* destination: RSX texture memory */
        data_font_Adonais,         /* source: embedded bitmap data */
        0x20,                      /* first_char: space */
        0x7E,                      /* last_char: tilde */
        32,                        /* cell width */
        31,                        /* cell height */
        1,                         /* bits per pixel */
        BIT0_FIRST_PIXEL           /* bit packing order */
    );
    
    /* Activate the font for rendering */
    SetCurrentFont(0);
    SetFontSize(32, 31);
    SetFontColor(0xffffffff, 0x00000000);  /* RGBA white, transparent black */
}

```

Because the glyphs are pre-rasterized, this approach eliminates runtime parsing overhead and minimizes memory fragmentation on the PS4.

## Rendering Text with libfont

Once a font is loaded, the API provides fine-grained control over text appearance and positioning.

### Setting Font Properties

Configuration functions (lines 135–165 in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c)) modify the global rendering state:

```c
/* Select which loaded font to use (0-based index) */
SetCurrentFont(0);

/* Set the display size - can scale the 32x31 bitmap up or down */
SetFontSize(32, 31);

/* Set colors: top color (text), bottom color (background/outline) */
SetFontColor(0xffffffff, 0x00000000);

/* Alignment: LEFT, CENTER, or RIGHT relative to draw position */
SetFontAlign(FONT_ALIGN_LEFT);

/* Z-depth for layering text over other 3D elements */
SetFontZ(0.0f);

```

### Drawing Strings

The `DrawString()` function (lines 197–231 in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c)) iterates through the input string, calculates texture coordinates from the `font_datas` array, and submits `tiny3d_DrawTexture` calls for each glyph:

```c
void RenderFrame(void)
{
    /* Draw left-aligned text at (100, 200) */
    DrawString(100.0f, 200.0f, "Save Manager");
    
    /* Draw centered text */
    SetFontAlign(FONT_ALIGN_CENTER);
    DrawString(640.0f, 400.0f, "Press X to Continue");
    
    /* Monospaced variant for UI lists */
    DrawStringMono(50.0f, 300.0f, "Slot 1: [Active]");
}

```

The engine automatically handles kerning for proportional fonts (using per-glyph width tables) and supports monospaced rendering via `DrawStringMono()`.

## Enabling TTF Support (Developer Reference)

While the production build relies on [`font_adonais.h`](https://github.com/bucanero/apollo-ps4/blob/main/font_adonais.h), developers requiring dynamic font sizes or Unicode support can activate the TTF stub.

To enable TTF rendering:

1. **Uncomment the block** in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c) (lines 82–124)
2. **Link FreeType** (or another rasterizer) to the project
3. **Implement the callback** matching the expected signature:

```c
void my_ttf_callback(u8 chr, u8 *bitmap, short *w, short *h, short *y_correction)
{
    /* Use FreeType to render the glyph to grayscale */
    FT_Load_Char(face, chr, FT_LOAD_RENDER);
    *w = face->glyph->bitmap.width;
    *h = face->glyph->bitmap.rows;
    *y_correction = face->glyph->bitmap_top - *h;
    memcpy(bitmap, face->glyph->bitmap.buffer, (*w) * (*h));
}

```

When `AddFontFromTTF()` is called, it invokes this callback for each character in the specified range, converts the resulting 8-bit grayscale to RSX A4R4G4B4 format, and uploads the textures exactly like the bitmap path. This ensures `DrawString()` works identically regardless of the font source.

## Summary

- **Apollo PS4** uses a custom `libfont` engine located in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c) to handle all text rendering without heavy external dependencies.
- **Bitmap fonts** are the production standard, with [`font_adonais.h`](https://github.com/bucanero/apollo-ps4/blob/main/font_adonais.h) providing a 95-glyph, 32×31 pixel monochrome font embedded as `data_font_Adonais`.
- **Loading workflow**: Call `ResetFont()`, then `AddFontFromBitmapArray()` with the RSX texture pointer and font data, followed by `SetCurrentFont()` and `SetFontSize()`.
- **Rendering**: `DrawString()` and `DrawStringMono()` iterate glyphs stored in the global `font_datas` array and submit `tiny3d_DrawTexture` calls for each character.
- **TTF support** exists as a commented stub (`AddFontFromTTF()` at lines 82–124) that accepts a rasterization callback, allowing developers to integrate FreeType or similar libraries without modifying the drawing logic.

## Frequently Asked Questions

### How do I change the font color in Apollo PS4?

Call `SetFontColor()` with two 32-bit RGBA values before drawing. The first parameter sets the text color, and the second sets the background or outline color. For opaque white text on a transparent background, use `SetFontColor(0xffffffff, 0x00000000)`.

### Why is the TTF support commented out in the source code?

The `AddFontFromTTF()` function is wrapped in a comment block to keep the Apollo binary small and avoid dependencies on large libraries like FreeType. The stub serves as a reference implementation for developers who need dynamic glyph generation; enabling it requires uncommenting lines 82–124 in [`source/libfont.c`](https://github.com/bucanero/apollo-ps4/blob/main/source/libfont.c) and providing a compatible rasterization callback.

### What is the resolution of the Adonais font included in font_adonais.h?

The Adonais font uses 32×31 pixel glyph cells at 1 bit per pixel. The header defines 95 printable ASCII characters (0x20 through 0x7E) stored in a static array of 11,780 bytes (`124 bytes per glyph × 95 glyphs`).

### Can I use multiple fonts simultaneously in Apollo PS4?

Yes. Call `AddFontFromBitmapArray()` multiple times to load different fonts into separate indices. Use `SetCurrentFont(n)` where `n` is the 0-based index to switch between them at runtime. The global `font_datas` array stores up to the maximum number of fonts defined in [`include/libfont.h`](https://github.com/bucanero/apollo-ps4/blob/main/include/libfont.h).