amiga-bootcamp/08_graphics/text_fonts.md
Ilia Sharin f61c26b542 Expand documentation suite: 30+ articles enriched with diagrams, code examples, and hardware details
Graphics: text_fonts (bitmap layout, styles), sprites (DMA, multiplexing), gfx_base (chipset detection), rastport (draw modes, clipping), ham_ehb (mermaid fixes), display_modes (HAM palettes)

Devices: scsi (per-model interfaces, Gayle limits, CD-ROM, native vs vendor drivers), console (ANSI sequences, CON:/RAW:), parallel (CIA registers, pinout), timer (resource exhaustion), gameport (quadrature, XOR state)

Libraries: workbench (WBStartup, AppWindow/Icon/MenuItem), rexxsyslib (ARexx port hosting, command parsing), diskfont (font directory, colour fonts), keymap (rawkey codes, dead keys), locale (catalogue system, date formatting), layers (ClipRect, refresh types), utility (TagItem chains), icon (DiskObject, ToolTypes), iffparse (IFF structure, ByteRun1), expansion (Zorro AutoConfig)

Networking: tcp_ip_stacks (major rewrite - Amiga vs Unix architecture, SANA-II pipeline, PPP/SLIP dial-up, Ethernet cards, MiSTer), bsdsocket (pure API ref), sana2 (buffer hooks, driver requirements), protocols (all code examples). Deduplicated overlap between the three files.

Toolchain: debugging (Enforcer patterns, SnoopDOS, GDB remote, kprintf checklist), sasc (pragma encoding, __saveds idioms), stormc (NEW - StormC IDE, C++, PowerPC)

References: error_codes (DOS, Exec, trackdisk, Intuition error tables)
Driver development: rtg_driver (Native driver analysis, P96 tuning)

All 22 README indexes updated. Root README synced with stormc.md entry.
2026-04-23 21:37:26 -04:00

215 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[← Home](../README.md) · [Graphics](README.md)
# Text and Fonts — TextFont, TextAttr, Rendering
## Overview
AmigaOS uses **bitmap fonts** rendered through `graphics.library`. Each font character is stored as a strip of pixels in a single bitmap. Fonts can be ROM-resident (topaz — always available), loaded from disk via `diskfont.library`, or generated algorithmically (bold, italic, underline).
```mermaid
flowchart LR
subgraph "Font Sources"
ROM["ROM Fonts<br/>(topaz 8, topaz 9)"]
DISK["Disk Fonts<br/>(FONTS: directory)"]
end
ROM -->|"OpenFont"| TF["struct TextFont"]
DISK -->|"OpenDiskFont"| TF
TF -->|"SetFont(rp, font)"| RP["RastPort"]
RP -->|"Text(rp, str, len)"| BM["BitMap<br/>(rendered text)"]
style TF fill:#e8f4fd,stroke:#2196f3,color:#333
```
---
## Key Structures
```c
/* graphics/text.h — NDK39 */
/* Font request — describes what you want: */
struct TextAttr {
STRPTR ta_Name; /* font name, e.g. "topaz.font" */
UWORD ta_YSize; /* desired height in pixels */
UBYTE ta_Style; /* FSF_BOLD, FSF_ITALIC, FSF_UNDERLINED */
UBYTE ta_Flags; /* FPF_ROMFONT, FPF_DISKFONT, etc. */
};
/* Loaded font instance: */
struct TextFont {
struct Message tf_Message; /* standard message header */
UWORD tf_YSize; /* actual font height */
UBYTE tf_Style; /* styles this font has built-in */
UBYTE tf_Flags;
UWORD tf_XSize; /* nominal character width */
UWORD tf_Baseline; /* pixels from top to baseline */
UWORD tf_BoldSmear; /* extra pixels for algorithmic bold */
UWORD tf_Accessors; /* current open count */
UBYTE tf_LoChar; /* first character code (usually 32) */
UBYTE tf_HiChar; /* last character code (usually 127 or 255) */
APTR tf_CharData; /* bitmap strip containing all glyphs */
UWORD tf_Modulo; /* bytes per row of font bitmap */
APTR tf_CharLoc; /* location table: offset + width per char */
APTR tf_CharSpace; /* proportional spacing table (NULL = fixed) */
APTR tf_CharKern; /* kerning adjustment table (NULL = none) */
};
```
### Font Bitmap Layout
All characters are stored in a single bitmap strip. The `tf_CharLoc` table tells the renderer where each character starts:
```
tf_CharData bitmap:
┌──┬───┬──┬───┬──┬──┬───────────────────┐
│A │ B │C │ D │E │F │ ... all chars ... │
└──┴───┴──┴───┴──┴──┴───────────────────┘
tf_CharLoc[ch - tf_LoChar]:
bits 3116 = bit offset into tf_CharData
bits 150 = character width in pixels
tf_CharSpace[ch - tf_LoChar]:
spacing advance (proportional fonts)
```
---
## Opening Fonts
```c
/* ROM font (topaz — always available, no disk access): */
struct TextAttr ta = {"topaz.font", 8, 0, FPF_ROMFONT};
struct TextFont *font = OpenFont(&ta);
/* Disk font (requires diskfont.library): */
struct Library *DiskfontBase = OpenLibrary("diskfont.library", 0);
struct TextAttr ta2 = {"helvetica.font", 24, 0, FPF_DISKFONT};
struct TextFont *font2 = OpenDiskFont(&ta2);
/* Request with style (may get algorithmically generated): */
struct TextAttr ta3 = {"topaz.font", 8, FSF_BOLD, FPF_ROMFONT};
struct TextFont *bold = OpenFont(&ta3);
/* Assign to RastPort: */
SetFont(rp, font);
/* Close when done: */
CloseFont(font);
```
---
## Rendering Text
```c
/* Position cursor then render: */
Move(rp, 10, 20 + rp->Font->tf_Baseline); /* baseline-relative! */
Text(rp, "Hello Amiga", 11);
/* Measure width before rendering (for centering/alignment): */
UWORD width = TextLength(rp, "Hello Amiga", 11);
/* Centre text: */
WORD centreX = (screenWidth - width) / 2;
Move(rp, centreX, 100);
Text(rp, "Hello Amiga", 11);
/* Pixel-perfect extent info: */
struct TextExtent te;
TextExtent(rp, "Hello", 5, &te);
/* te.te_Width = total pixel width */
/* te.te_Height = total pixel height */
/* te.te_Extent = bounding rectangle */
```
> [!IMPORTANT]
> `Text()` renders at the **current pen position**, which should be at the font's **baseline** — not the top of the character. The baseline offset is `font->tf_Baseline` pixels below the top.
---
## Algorithmic Styles
```c
/* Style flags: */
#define FSF_UNDERLINED 0x01
#define FSF_BOLD 0x02
#define FSF_ITALIC 0x04
#define FSF_EXTENDED 0x08
/* Ask which styles this font supports algorithmically: */
UWORD supported = AskSoftStyle(rp);
/* Apply bold + italic: */
SetSoftStyle(rp, FSF_BOLD | FSF_ITALIC, supported);
Text(rp, "Bold Italic Text", 16);
/* Reset to normal: */
SetSoftStyle(rp, 0, supported);
```
| Style | Method | Notes |
|---|---|---|
| Bold | Smear right by `tf_BoldSmear` | Characters become slightly wider |
| Italic | Shear top scanlines right | Fixed-angle slant |
| Underline | Draw line at descender level | 1-pixel line below baseline |
| Extended | Widen each character | Rarely used |
---
## Available Font Lists
```c
/* List all fonts available on FONTS: */
struct AvailFontsHeader *afh;
LONG bufSize = 4096;
do {
afh = AllocMem(bufSize, MEMF_ANY);
LONG shortBy = AvailFonts((STRPTR)afh, bufSize,
AFF_DISK | AFF_MEMORY | AFF_SCALED);
if (shortBy > 0) {
FreeMem(afh, bufSize);
bufSize += shortBy;
afh = NULL;
}
} while (!afh);
struct AvailFonts *af = &afh->afh_AF;
for (int i = 0; i < afh->afh_NumEntries; i++)
{
Printf("Font: %s, size %ld, type %s\n",
af[i].af_Attr.ta_Name,
af[i].af_Attr.ta_YSize,
(af[i].af_Type & AFF_DISK) ? "disk" : "ROM");
}
FreeMem(afh, bufSize);
```
---
## Font Preferences
The system font can be changed via Preferences. Applications should respect the user's choice:
```c
/* Get the current screen font (user's preference): */
struct TextAttr *screenFont;
struct Preferences prefs;
GetPrefs(&prefs, sizeof(prefs));
/* prefs contains font info */
/* Better: use the screen's font directly: */
struct TextFont *scrFont = screen->RastPort.Font;
SetFont(myRastPort, scrFont);
```
---
## References
- NDK39: `graphics/text.h`, `graphics/rastport.h`
- ADCD 2.1: `OpenFont`, `OpenDiskFont`, `SetFont`, `Text`, `TextLength`
- See also: [diskfont.md](../11_libraries/diskfont.md) — disk font loading
- See also: [rastport.md](rastport.md) — RastPort text rendering context