#!/usr/bin/env python3 # Generate a 4x8 font as RGBDS asm. Glyphs are up to 3px wide (in a 4px cell, # 1px right gap) and use the full 8px height with a real baseline at row 5: # caps/ascenders rows 1..5 x-height (lowercase) rows 2..5 # descenders reach rows 6..7 row 0 = top gap / line spacing # Output: 96 glyphs (ASCII 32..127), 8 bytes each; each byte = one 4-px row, # bit3 = leftmost pixel of the cell, bits 3..1 = the glyph, bit0 = gap. G = {} def d(ch, top, rows): # rows: list of 3-char strings ('#'=on) G[ch] = (top, rows) # ---- uppercase (top=1, 5 tall) ---- CAPS = { 'A':["##.","#.#","###","#.#","#.#"], 'B':["##.","#.#","##.","#.#","##."], 'C':[".##","#..","#..","#..",".##"], 'D':["##.","#.#","#.#","#.#","##."], 'E':["###","#..","##.","#..","###"], 'F':["###","#..","##.","#..","#.."], 'G':[".##","#..","#.#","#.#",".##"], 'H':["#.#","#.#","###","#.#","#.#"], 'I':["###",".#.",".#.",".#.","###"], 'J':["..#","..#","..#","#.#",".#."], 'K':["#.#","#.#","##.","#.#","#.#"], 'L':["#..","#..","#..","#..","###"], 'M':["#.#","###","###","#.#","#.#"], 'N':["#.#","###","###","###","#.#"], 'O':[".#.","#.#","#.#","#.#",".#."], 'P':["##.","#.#","##.","#..","#.."], 'Q':[".#.","#.#","#.#",".#.","..#"], 'R':["##.","#.#","##.","#.#","#.#"], 'S':[".##","#..",".#.","..#","##."], 'T':["###",".#.",".#.",".#.",".#."], 'U':["#.#","#.#","#.#","#.#",".##"], 'V':["#.#","#.#","#.#",".#.",".#."], 'W':["#.#","#.#","###","###","#.#"], 'X':["#.#","#.#",".#.","#.#","#.#"], 'Y':["#.#","#.#",".#.",".#.",".#."], 'Z':["###","..#",".#.","#..","###"], } for c,r in CAPS.items(): d(c,1,r) # ---- digits (top=1, 5 tall) ---- DIG = { '0':[".#.","#.#","#.#","#.#",".#."], '1':[".#.","##.",".#.",".#.","###"], '2':["##.","..#",".#.","#..","###"], '3':["##.","..#",".#.","..#","##."], '4':["#.#","#.#","###","..#","..#"], '5':["###","#..","##.","..#","##."], '6':[".##","#..","##.","#.#",".#."], '7':["###","..#",".#.",".#.",".#."], '8':[".#.","#.#",".#.","#.#",".#."], '9':[".#.","#.#",".##","..#","##."], } for c,r in DIG.items(): d(c,1,r) # ---- lowercase: x-height rows 2..5, baseline row 5 ---- # plain x-height (top=2, 4 tall) XH = { 'a':["##.",".##","#.#",".##"], 'c':[".##","#..","#..",".##"], 'e':[".#.","#.#","##.",".##"], 'm':["#.#","###","###","#.#"], 'n':["##.","#.#","#.#","#.#"], 'o':[".#.","#.#","#.#",".#."], 'r':["#.#","##.","#..","#.."], 's':[".##","##.",".##","##."], 'u':["#.#","#.#","#.#",".##"], 'v':["#.#","#.#","#.#",".#."], 'w':["#.#","###","###","#.#"], 'x':["#.#",".#.",".#.","#.#"], 'z':["###","..#",".#.","###"], } for c,r in XH.items(): d(c,2,r) # ascenders (top=1, 5 tall) ASC = { 'b':["#..","#..","##.","#.#","##."], 'd':["..#","..#",".##","#.#",".##"], 'f':[".##",".#.","###",".#.",".#."], 'h':["#..","#..","##.","#.#","#.#"], 'k':["#..","#.#","##.","#.#","#.#"], 'l':["##.",".#.",".#.",".#.",".##"], 't':[".#.","###",".#.",".#.",".##"], 'i':[".#.","...",".#.",".#.",".#."], } for c,r in ASC.items(): d(c,1,r) # descenders (top=2, body 4 + descender -> rows 2..7) DESC = { 'g':[".##","#.#",".##","..#","##."], 'p':["##.","#.#","##.","#..","#.."], 'q':[".##","#.#",".##","..#","..#"], 'y':["#.#","#.#",".##","..#","##."], 'j':["..#","...","..#","..#","##."], } for c,r in DESC.items(): d(c,2,r) # ---- punctuation ---- P = { '.':(4,[".#."]), ',':(4,[".#.","#.."]), ':':(2,[".#.","...",".#."]), ';':(2,[".#.","...",".#.","#.."]), '!':(1,[".#.",".#.",".#.","...",".#."]), '?':(1,["##.","..#",".#.","...",".#."]), '-':(3,["###"]), '+':(2,[".#.","###",".#."]), '=':(2,["###","...","###"]), '*':(1,["#.#",".#.","###",".#.","#.#"]), '/':(1,["..#","..#",".#.","#..","#.."]), '\\':(1,["#..","#..",".#.","..#","..#"]), '(':(1,["..#",".#.",".#.",".#.","..#"]), ')':(1,["#..",".#.",".#.",".#.","#.."]), '[':(1,["##.","#..","#..","#..","##."]), ']':(1,[".##","..#","..#","..#",".##"]), '<':(1,["..#",".#.","#..",".#.","..#"]), '>':(1,["#..",".#.","..#",".#.","#.."]), '#':(1,["#.#","###","#.#","###","#.#"]), '$':(1,[".##","#.#",".#.","#.#","##."]), '%':(1,["#.#","..#",".#.","#..","#.#"]), '&':(1,[".#.","#.#",".#.","#.#",".##"]), "'":(1,[".#.",".#."]), '"':(1,["#.#","#.#"]), '@':(1,[".#.","#.#","###","#..",".##"]), '_':(7,["###"]), '~':(3,[".##","##."]), '^':(1,[".#.","#.#"]), '|':(1,[".#.",".#.",".#.",".#.",".#."]), '`':(1,["#..",".#."]), '{':(1,["..#",".#.","##.",".#.","..#"]), '}':(1,["#..",".#.",".##",".#.","#.."]), ' ':(0,[]), } for c,(t,r) in P.items(): d(c,t,r) def bits(s): v=0 for i,px in enumerate(s[:3]): if px=='#': v |= (1 << (3-i)) return v def glyph_bytes(top, rows): out=[0]*8 for k,s in enumerate(rows): r = top + k if 0 <= r < 8: out[r] = bits(s) return out lines=["; auto-generated by tools/genfont.py - 4x8 mixed-case font, 96 glyphs", "SECTION \"font\", ROM0", "FontData::"] missing=[] for code in range(32,128): ch = chr(code) if ch in G: top,rows = G[ch] else: top,rows = 1,["###","#.#","#.#","#.#","###"] # box for undefined if code!=127: missing.append(ch) b = glyph_bytes(top,rows) label = ch if ch not in '\\' else '\\\\' lines.append(" db " + ",".join("$%02X"%x for x in b) + " ; '%s'"%(label if 32