mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
215 lines
6.3 KiB
Markdown
215 lines
6.3 KiB
Markdown
[← 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 31–16 = bit offset into tf_CharData
|
||
bits 15–0 = 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
|