Game Font - HoraceAndTheSpider/Bloodwych-68k GitHub Wiki
GameFont
The Bloodwych 439 GameFont file is a headerless 640-byte bitmap table:
- 128 glyphs, addressed by
character_code & 0x7f. - Five bytes per glyph (
character_code * 5). - Each byte is one horizontal scanline, top to bottom.
- All eight bits form an eight-pixel scanline, bit 7 through bit 0 from left to right. Most printable designs occupy only the lower six or seven bits.
- The resulting storage/rendering cell is 8 x 5 pixels.
The 68k routines at GameFont calculate code * 5, loop five times, and
advance the screen destination by one scanline after each byte. The data also
validates the interpretation directly: character A is represented by rows
0c 12 3f 21 33.
tools/gamefont_converter.py generates an indexed, transparent PNG sheet,
JSON metadata, and a byte-identical reconstructed font. The JSON retains all
eight bits of every original row. That makes the conversion safe for future
editing and binary re-export.
A spritesheet is preferable to TTF/WOFF as the canonical representation. A normal outline webfont adds hinting, baseline, spacing, and resampling concerns that do not exist in the game. The browser should render the indexed sheet with nearest-neighbour scaling. A generated OpenType bitmap wrapper could later be offered for convenience, but it should remain a derivative asset rather than the editable source.
Atari ST four-plane graphics
The AMOS graphics loader correctly decodes the native repeating unit:
offset + 0: plane 0, big-endian 16-bit word
offset + 2: plane 1, big-endian 16-bit word
offset + 4: plane 2, big-endian 16-bit word
offset + 6: plane 3, big-endian 16-bit word
Each eight-byte unit produces 16 indexed pixels. For pixel x, with bit
15 - x from each plane, the palette index is:
p0 | (p1 << 1) | (p2 << 2) | (p3 << 3)
The AMOS write routine performs the exact inverse operation, so the codec can support edited graphics and byte-for-byte round trips. This codec should be a small shared core service, usable in both Python and TypeScript test vectors.
The hard-coded AMOS Data sections do not describe the pixel encoding. They
describe how sequential 16-pixel strips are arranged into many differently
sized pictures. The current pairs appear to provide strip widths and heights,
with sentinel values such as 9999 allowing a remaining run to continue. This
geometry layer should become versioned, named JSON descriptors rather than be
embedded in the decoder. A descriptor should record:
{
"id": "head_parts_00",
"segment": "Head_Parts",
"byte_offset": 0,
"width_pixels": 16,
"height_pixels": 111,
"palette": "characters",
"transparent_index": 15,
"role": "character-template"
}
Offsets should be derived cumulatively and then checked against the segment size. Width must be a multiple of 16 for the raw planar layer; any visual crop, hotspot, or composition bounds belong in separate metadata. This removes the loader's current uncertainty between storage width and displayed/cropped width.