aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-07-16 14:53:25 +0200
committeruser <user@clank>2026-07-16 14:53:25 +0200
commitdb022ffc366c8e81cd1120aa0190661e43d5dc32 (patch)
tree56c2682f04db9fe5171393ff407bdebd390ec42f
parentterm: 40-column text terminal on the CGB LCD (4x8 dynamic tiles) (diff)
downloadgbos-db022ffc366c8e81cd1120aa0190661e43d5dc32.tar.gz
gbos-db022ffc366c8e81cd1120aa0190661e43d5dc32.tar.xz
gbos-db022ffc366c8e81cd1120aa0190661e43d5dc32.zip
font: full mixed-case + punctuation glyph set (not uppercase-only)
Replace the small-caps placeholder font with a real baseline-aligned 4x8 set covering all 96 printable ASCII: distinct lowercase with true ascenders (b d f h k l t) and descenders (g j p q y), digits, and punctuation. Metrics: caps/ascenders rows 1-5, x-height rows 2-5, baseline row 5, descenders into rows 6-7. Glyphs are ~3px wide in the 4px cell -- cramped but legible; the tile mechanism itself imposes no character-set limit. genfont.py now takes per-glyph (top, rows) so glyphs sit on the baseline. Demo strings in term_test updated to show mixed case + punctuation. Verified by screenshot: descenders visibly drop below the baseline.
Diffstat (limited to '')
-rw-r--r--src/font.asm192
-rw-r--r--src/term.asm12
-rw-r--r--tools/genfont.py201
3 files changed, 208 insertions, 197 deletions
diff --git a/src/font.asm b/src/font.asm
index a6ff7d9..ce83d2a 100644
--- a/src/font.asm
+++ b/src/font.asm
@@ -1,99 +1,99 @@
-; auto-generated by tools/genfont.py - 4x8 font (3x5 glyphs), 96 glyphs
+; auto-generated by tools/genfont.py - 4x8 mixed-case font, 96 glyphs
SECTION "font", ROM0
FontData::
- db $00,$00,$00,$00,$00,$00,$00,$00 ; ' '
- db $04,$04,$04,$00,$04,$00,$00,$00 ; '!'
- db $0A,$0A,$00,$00,$00,$00,$00,$00 ; '"'
- db $0A,$0E,$0A,$0E,$0A,$00,$00,$00 ; '#'
- db $04,$06,$0C,$06,$0C,$00,$00,$00 ; '$'
- db $0A,$02,$04,$08,$0A,$00,$00,$00 ; '%'
- db $04,$0A,$04,$0A,$06,$00,$00,$00 ; '&'
- db $04,$04,$00,$00,$00,$00,$00,$00 ; '''
- db $02,$04,$04,$04,$02,$00,$00,$00 ; '('
- db $08,$04,$04,$04,$08,$00,$00,$00 ; ')'
- db $0A,$04,$0E,$04,$0A,$00,$00,$00 ; '*'
- db $00,$04,$0E,$04,$00,$00,$00,$00 ; '+'
- db $00,$00,$00,$04,$08,$00,$00,$00 ; ','
- db $00,$00,$0E,$00,$00,$00,$00,$00 ; '-'
+ db $00,$00,$00,$00,$00,$00,$00,$00 ; 'SP'
+ db $00,$04,$04,$04,$00,$04,$00,$00 ; '!'
+ db $00,$0A,$0A,$00,$00,$00,$00,$00 ; '"'
+ db $00,$0A,$0E,$0A,$0E,$0A,$00,$00 ; '#'
+ db $00,$06,$0A,$04,$0A,$0C,$00,$00 ; '$'
+ db $00,$0A,$02,$04,$08,$0A,$00,$00 ; '%'
+ db $00,$04,$0A,$04,$0A,$06,$00,$00 ; '&'
+ db $00,$04,$04,$00,$00,$00,$00,$00 ; '''
+ db $00,$02,$04,$04,$04,$02,$00,$00 ; '('
+ db $00,$08,$04,$04,$04,$08,$00,$00 ; ')'
+ db $00,$0A,$04,$0E,$04,$0A,$00,$00 ; '*'
+ db $00,$00,$04,$0E,$04,$00,$00,$00 ; '+'
+ db $00,$00,$00,$00,$04,$08,$00,$00 ; ','
+ db $00,$00,$00,$0E,$00,$00,$00,$00 ; '-'
db $00,$00,$00,$00,$04,$00,$00,$00 ; '.'
- db $02,$02,$04,$08,$08,$00,$00,$00 ; '/'
- db $04,$0A,$0A,$0A,$04,$00,$00,$00 ; '0'
- db $04,$0C,$04,$04,$0E,$00,$00,$00 ; '1'
- db $0C,$02,$04,$08,$0E,$00,$00,$00 ; '2'
- db $0C,$02,$04,$02,$0C,$00,$00,$00 ; '3'
- db $0A,$0A,$0E,$02,$02,$00,$00,$00 ; '4'
- db $0E,$08,$0C,$02,$0C,$00,$00,$00 ; '5'
- db $06,$08,$0C,$0A,$04,$00,$00,$00 ; '6'
- db $0E,$02,$04,$04,$04,$00,$00,$00 ; '7'
- db $04,$0A,$04,$0A,$04,$00,$00,$00 ; '8'
- db $04,$0A,$06,$02,$0C,$00,$00,$00 ; '9'
- db $00,$04,$00,$04,$00,$00,$00,$00 ; ':'
- db $00,$04,$00,$04,$08,$00,$00,$00 ; ';'
- db $02,$04,$08,$04,$02,$00,$00,$00 ; '<'
- db $00,$0E,$00,$0E,$00,$00,$00,$00 ; '='
- db $08,$04,$02,$04,$08,$00,$00,$00 ; '>'
- db $0C,$02,$04,$00,$04,$00,$00,$00 ; '?'
- db $04,$0A,$0E,$08,$06,$00,$00,$00 ; '@'
- db $0C,$0A,$0E,$0A,$0A,$00,$00,$00 ; 'A'
- db $0C,$0A,$0C,$0A,$0C,$00,$00,$00 ; 'B'
- db $06,$08,$08,$08,$06,$00,$00,$00 ; 'C'
- db $0C,$0A,$0A,$0A,$0C,$00,$00,$00 ; 'D'
- db $0E,$08,$0C,$08,$0E,$00,$00,$00 ; 'E'
- db $0E,$08,$0C,$08,$08,$00,$00,$00 ; 'F'
- db $06,$08,$0A,$0A,$06,$00,$00,$00 ; 'G'
- db $0A,$0A,$0E,$0A,$0A,$00,$00,$00 ; 'H'
- db $0E,$04,$04,$04,$0E,$00,$00,$00 ; 'I'
- db $02,$02,$02,$0A,$04,$00,$00,$00 ; 'J'
- db $0A,$0A,$0C,$0A,$0A,$00,$00,$00 ; 'K'
- db $08,$08,$08,$08,$0E,$00,$00,$00 ; 'L'
- db $0A,$0E,$0E,$0A,$0A,$00,$00,$00 ; 'M'
- db $0A,$0E,$0E,$0E,$0A,$00,$00,$00 ; 'N'
- db $04,$0A,$0A,$0A,$04,$00,$00,$00 ; 'O'
- db $0C,$0A,$0C,$08,$08,$00,$00,$00 ; 'P'
- db $04,$0A,$0A,$04,$02,$00,$00,$00 ; 'Q'
- db $0C,$0A,$0C,$0A,$0A,$00,$00,$00 ; 'R'
- db $06,$08,$04,$02,$0C,$00,$00,$00 ; 'S'
- db $0E,$04,$04,$04,$04,$00,$00,$00 ; 'T'
- db $0A,$0A,$0A,$0A,$06,$00,$00,$00 ; 'U'
- db $0A,$0A,$0A,$04,$04,$00,$00,$00 ; 'V'
- db $0A,$0A,$0E,$0E,$0A,$00,$00,$00 ; 'W'
- db $0A,$0A,$04,$0A,$0A,$00,$00,$00 ; 'X'
- db $0A,$0A,$04,$04,$04,$00,$00,$00 ; 'Y'
- db $0E,$02,$04,$08,$0E,$00,$00,$00 ; 'Z'
- db $0C,$08,$08,$08,$0C,$00,$00,$00 ; '['
- db $08,$08,$04,$02,$02,$00,$00,$00 ; '?'
- db $06,$02,$02,$02,$06,$00,$00,$00 ; ']'
- db $04,$0A,$00,$00,$00,$00,$00,$00 ; '^'
- db $00,$00,$00,$00,$0E,$00,$00,$00 ; '_'
- db $08,$04,$00,$00,$00,$00,$00,$00 ; '`'
- db $0C,$0A,$0E,$0A,$0A,$00,$00,$00 ; 'a'
- db $0C,$0A,$0C,$0A,$0C,$00,$00,$00 ; 'b'
- db $06,$08,$08,$08,$06,$00,$00,$00 ; 'c'
- db $0C,$0A,$0A,$0A,$0C,$00,$00,$00 ; 'd'
- db $0E,$08,$0C,$08,$0E,$00,$00,$00 ; 'e'
- db $0E,$08,$0C,$08,$08,$00,$00,$00 ; 'f'
- db $06,$08,$0A,$0A,$06,$00,$00,$00 ; 'g'
- db $0A,$0A,$0E,$0A,$0A,$00,$00,$00 ; 'h'
- db $0E,$04,$04,$04,$0E,$00,$00,$00 ; 'i'
- db $02,$02,$02,$0A,$04,$00,$00,$00 ; 'j'
- db $0A,$0A,$0C,$0A,$0A,$00,$00,$00 ; 'k'
- db $08,$08,$08,$08,$0E,$00,$00,$00 ; 'l'
- db $0A,$0E,$0E,$0A,$0A,$00,$00,$00 ; 'm'
- db $0A,$0E,$0E,$0E,$0A,$00,$00,$00 ; 'n'
- db $04,$0A,$0A,$0A,$04,$00,$00,$00 ; 'o'
- db $0C,$0A,$0C,$08,$08,$00,$00,$00 ; 'p'
- db $04,$0A,$0A,$04,$02,$00,$00,$00 ; 'q'
- db $0C,$0A,$0C,$0A,$0A,$00,$00,$00 ; 'r'
- db $06,$08,$04,$02,$0C,$00,$00,$00 ; 's'
- db $0E,$04,$04,$04,$04,$00,$00,$00 ; 't'
- db $0A,$0A,$0A,$0A,$06,$00,$00,$00 ; 'u'
- db $0A,$0A,$0A,$04,$04,$00,$00,$00 ; 'v'
- db $0A,$0A,$0E,$0E,$0A,$00,$00,$00 ; 'w'
- db $0A,$0A,$04,$0A,$0A,$00,$00,$00 ; 'x'
- db $0A,$0A,$04,$04,$04,$00,$00,$00 ; 'y'
- db $0E,$02,$04,$08,$0E,$00,$00,$00 ; 'z'
- db $02,$04,$0C,$04,$02,$00,$00,$00 ; '{'
- db $04,$04,$04,$04,$04,$00,$00,$00 ; '|'
- db $08,$04,$06,$04,$08,$00,$00,$00 ; '}'
- db $00,$06,$0C,$00,$00,$00,$00,$00 ; '~'
- db $0E,$0A,$0A,$0A,$0E,$00,$00,$00 ; '?'
+ db $00,$02,$02,$04,$08,$08,$00,$00 ; '/'
+ db $00,$04,$0A,$0A,$0A,$04,$00,$00 ; '0'
+ db $00,$04,$0C,$04,$04,$0E,$00,$00 ; '1'
+ db $00,$0C,$02,$04,$08,$0E,$00,$00 ; '2'
+ db $00,$0C,$02,$04,$02,$0C,$00,$00 ; '3'
+ db $00,$0A,$0A,$0E,$02,$02,$00,$00 ; '4'
+ db $00,$0E,$08,$0C,$02,$0C,$00,$00 ; '5'
+ db $00,$06,$08,$0C,$0A,$04,$00,$00 ; '6'
+ db $00,$0E,$02,$04,$04,$04,$00,$00 ; '7'
+ db $00,$04,$0A,$04,$0A,$04,$00,$00 ; '8'
+ db $00,$04,$0A,$06,$02,$0C,$00,$00 ; '9'
+ db $00,$00,$04,$00,$04,$00,$00,$00 ; ':'
+ db $00,$00,$04,$00,$04,$08,$00,$00 ; ';'
+ db $00,$02,$04,$08,$04,$02,$00,$00 ; '<'
+ db $00,$00,$0E,$00,$0E,$00,$00,$00 ; '='
+ db $00,$08,$04,$02,$04,$08,$00,$00 ; '>'
+ db $00,$0C,$02,$04,$00,$04,$00,$00 ; '?'
+ db $00,$04,$0A,$0E,$08,$06,$00,$00 ; '@'
+ db $00,$0C,$0A,$0E,$0A,$0A,$00,$00 ; 'A'
+ db $00,$0C,$0A,$0C,$0A,$0C,$00,$00 ; 'B'
+ db $00,$06,$08,$08,$08,$06,$00,$00 ; 'C'
+ db $00,$0C,$0A,$0A,$0A,$0C,$00,$00 ; 'D'
+ db $00,$0E,$08,$0C,$08,$0E,$00,$00 ; 'E'
+ db $00,$0E,$08,$0C,$08,$08,$00,$00 ; 'F'
+ db $00,$06,$08,$0A,$0A,$06,$00,$00 ; 'G'
+ db $00,$0A,$0A,$0E,$0A,$0A,$00,$00 ; 'H'
+ db $00,$0E,$04,$04,$04,$0E,$00,$00 ; 'I'
+ db $00,$02,$02,$02,$0A,$04,$00,$00 ; 'J'
+ db $00,$0A,$0A,$0C,$0A,$0A,$00,$00 ; 'K'
+ db $00,$08,$08,$08,$08,$0E,$00,$00 ; 'L'
+ db $00,$0A,$0E,$0E,$0A,$0A,$00,$00 ; 'M'
+ db $00,$0A,$0E,$0E,$0E,$0A,$00,$00 ; 'N'
+ db $00,$04,$0A,$0A,$0A,$04,$00,$00 ; 'O'
+ db $00,$0C,$0A,$0C,$08,$08,$00,$00 ; 'P'
+ db $00,$04,$0A,$0A,$04,$02,$00,$00 ; 'Q'
+ db $00,$0C,$0A,$0C,$0A,$0A,$00,$00 ; 'R'
+ db $00,$06,$08,$04,$02,$0C,$00,$00 ; 'S'
+ db $00,$0E,$04,$04,$04,$04,$00,$00 ; 'T'
+ db $00,$0A,$0A,$0A,$0A,$06,$00,$00 ; 'U'
+ db $00,$0A,$0A,$0A,$04,$04,$00,$00 ; 'V'
+ db $00,$0A,$0A,$0E,$0E,$0A,$00,$00 ; 'W'
+ db $00,$0A,$0A,$04,$0A,$0A,$00,$00 ; 'X'
+ db $00,$0A,$0A,$04,$04,$04,$00,$00 ; 'Y'
+ db $00,$0E,$02,$04,$08,$0E,$00,$00 ; 'Z'
+ db $00,$0C,$08,$08,$08,$0C,$00,$00 ; '['
+ db $00,$08,$08,$04,$02,$02,$00,$00 ; '\\'
+ db $00,$06,$02,$02,$02,$06,$00,$00 ; ']'
+ db $00,$04,$0A,$00,$00,$00,$00,$00 ; '^'
+ db $00,$00,$00,$00,$00,$00,$00,$0E ; '_'
+ db $00,$08,$04,$00,$00,$00,$00,$00 ; '`'
+ db $00,$00,$0C,$06,$0A,$06,$00,$00 ; 'a'
+ db $00,$08,$08,$0C,$0A,$0C,$00,$00 ; 'b'
+ db $00,$00,$06,$08,$08,$06,$00,$00 ; 'c'
+ db $00,$02,$02,$06,$0A,$06,$00,$00 ; 'd'
+ db $00,$00,$04,$0A,$0C,$06,$00,$00 ; 'e'
+ db $00,$06,$04,$0E,$04,$04,$00,$00 ; 'f'
+ db $00,$00,$06,$0A,$06,$02,$0C,$00 ; 'g'
+ db $00,$08,$08,$0C,$0A,$0A,$00,$00 ; 'h'
+ db $00,$04,$00,$04,$04,$04,$00,$00 ; 'i'
+ db $00,$00,$02,$00,$02,$02,$0C,$00 ; 'j'
+ db $00,$08,$0A,$0C,$0A,$0A,$00,$00 ; 'k'
+ db $00,$0C,$04,$04,$04,$06,$00,$00 ; 'l'
+ db $00,$00,$0A,$0E,$0E,$0A,$00,$00 ; 'm'
+ db $00,$00,$0C,$0A,$0A,$0A,$00,$00 ; 'n'
+ db $00,$00,$04,$0A,$0A,$04,$00,$00 ; 'o'
+ db $00,$00,$0C,$0A,$0C,$08,$08,$00 ; 'p'
+ db $00,$00,$06,$0A,$06,$02,$02,$00 ; 'q'
+ db $00,$00,$0A,$0C,$08,$08,$00,$00 ; 'r'
+ db $00,$00,$06,$0C,$06,$0C,$00,$00 ; 's'
+ db $00,$04,$0E,$04,$04,$06,$00,$00 ; 't'
+ db $00,$00,$0A,$0A,$0A,$06,$00,$00 ; 'u'
+ db $00,$00,$0A,$0A,$0A,$04,$00,$00 ; 'v'
+ db $00,$00,$0A,$0E,$0E,$0A,$00,$00 ; 'w'
+ db $00,$00,$0A,$04,$04,$0A,$00,$00 ; 'x'
+ db $00,$00,$0A,$0A,$06,$02,$0C,$00 ; 'y'
+ db $00,$00,$0E,$02,$04,$0E,$00,$00 ; 'z'
+ db $00,$02,$04,$0C,$04,$02,$00,$00 ; '{'
+ db $00,$04,$04,$04,$04,$04,$00,$00 ; '|'
+ db $00,$08,$04,$06,$04,$08,$00,$00 ; '}'
+ db $00,$00,$00,$06,$0C,$00,$00,$00 ; '~'
+ db $00,$0E,$0A,$0A,$0A,$0E,$00,$00 ; 'DEL'
diff --git a/src/term.asm b/src/term.asm
index 9d13b80..2b5caf3 100644
--- a/src/term.asm
+++ b/src/term.asm
@@ -373,9 +373,9 @@ term_test::
call term_puts
call term_show
ret
-.s0 db "GBOS TERMINAL - 40 COLUMNS x 18 ROWS", 0
-.s1 db "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789", 0
-.s2 db "the quick brown fox jumps over the dog.", 0
-.s3 db "0123456789012345678901234567890123456789", 0
-.s4 db "row 10: some text in the middle here...", 0
-.s5 db "LAST ROW 17 - exercises bank-1 tiles!!!", 0
+.s0 db "GBOS Terminal - now with lowercase!", 0
+.s1 db "The quick brown fox jumps over a", 0
+.s2 db "lazy dog. Digits 0123456789 too.", 0
+.s3 db "abcdefghijklmnopqrstuvwxyz", 0
+.s4 db "ascenders bdfhklt, descenders gjpqy", 0
+.s5 db "Punct .,:;!? +-*/=<>()[]#@ ok", 0
diff --git a/tools/genfont.py b/tools/genfont.py
index 7fe7689..2f94881 100644
--- a/tools/genfont.py
+++ b/tools/genfont.py
@@ -1,105 +1,116 @@
#!/usr/bin/env python3
-# Generate a 4x8 font (3x5 glyphs, left-aligned in a 4px cell) as RGBDS asm.
+# 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 3px glyph, bit0 = gap.
+# bit3 = leftmost pixel of the cell, bits 3..1 = the glyph, bit0 = gap.
G = {}
-def d(ch, rows): # rows: 5 strings of width 3 ('#'/' ')
- G[ch] = rows
-# space
-d(' ', [" "," "," "," "," "])
-# letters (uppercase; lowercase mapped to these)
-d('A',["## ","# #","###","# #","# #"])
-d('B',["## ","# #","## ","# #","## "])
-d('C',[" ##","# ","# ","# "," ##"])
-d('D',["## ","# #","# #","# #","## "])
-d('E',["###","# ","## ","# ","###"])
-d('F',["###","# ","## ","# ","# "])
-d('G',[" ##","# ","# #","# #"," ##"])
-d('H',["# #","# #","###","# #","# #"])
-d('I',["###"," # "," # "," # ","###"])
-d('J',[" #"," #"," #","# #"," # "])
-d('K',["# #","# #","## ","# #","# #"])
-d('L',["# ","# ","# ","# ","###"])
-d('M',["# #","###","###","# #","# #"])
-d('N',["# #","###","###","###","# #"])
-d('O',[" # ","# #","# #","# #"," # "])
-d('P',["## ","# #","## ","# ","# "])
-d('Q',[" # ","# #","# #"," # "," #"])
-d('R',["## ","# #","## ","# #","# #"])
-d('S',[" ##","# "," # "," #","## "])
-d('T',["###"," # "," # "," # "," # "])
-d('U',["# #","# #","# #","# #"," ##"])
-d('V',["# #","# #","# #"," # "," # "])
-d('W',["# #","# #","###","###","# #"])
-d('X',["# #","# #"," # ","# #","# #"])
-d('Y',["# #","# #"," # "," # "," # "])
-d('Z',["###"," #"," # ","# ","###"])
-# digits
-d('0',[" # ","# #","# #","# #"," # "])
-d('1',[" # ","## "," # "," # ","###"])
-d('2',["## "," #"," # ","# ","###"])
-d('3',["## "," #"," # "," #","## "])
-d('4',["# #","# #","###"," #"," #"])
-d('5',["###","# ","## "," #","## "])
-d('6',[" ##","# ","## ","# #"," # "])
-d('7',["###"," #"," # "," # "," # "])
-d('8',[" # ","# #"," # ","# #"," # "])
-d('9',[" # ","# #"," ##"," #","## "])
-# punctuation
-d('.',[" "," "," "," "," # "])
-d(',',[" "," "," "," # ","# "])
-d(':',[" "," # "," "," # "," "])
-d(';',[" "," # "," "," # ","# "])
-d('!',[" # "," # "," # "," "," # "])
-d('?',["## "," #"," # "," "," # "])
-d('-',[" "," ","###"," "," "])
-d('+',[" "," # ","###"," # "," "])
-d('=',[" ","###"," ","###"," "])
-d('*',["# #"," # ","###"," # ","# #"])
-d('/',[" #"," #"," # ","# ","# "])
-d('\\',["# ","# "," # "," #"," #"])
-d('(',[" #"," # "," # "," # "," #"])
-d(')',["# "," # "," # "," # ","# "])
-d('[',["## ","# ","# ","# ","## "])
-d(']',[" ##"," #"," #"," #"," ##"])
-d('<',[" #"," # ","# "," # "," #"])
-d('>',["# "," # "," #"," # ","# "])
-d('#',["# #","###","# #","###","# #"])
-d('$',[" # "," ##","## "," ##","## "]) # rough
-d('%',["# #"," #"," # ","# ","# #"])
-d('&',[" # ","# #"," # ","# #"," ##"])
-d("'",[" # "," # "," "," "," "])
-d('"',["# #","# #"," "," "," "])
-d('@',[" # ","# #","###","# "," ##"])
-d('_',[" "," "," "," ","###"])
-d('~',[" "," ##","## "," "," "])
-d('^',[" # ","# #"," "," "," "])
-d('|',[" # "," # "," # "," # "," # "])
-d('{',[" #"," # ","## "," # "," #"])
-d('}',["# "," # "," ##"," # ","# "])
-d('`',["# "," # "," "," "," "])
+def d(ch, top, rows): # rows: list of 3-char strings ('#'=on)
+ G[ch] = (top, rows)
-def glyph_bytes(rows):
- out=[]
- # 5 glyph rows in the top; cell is 4px wide, glyph 3px left-aligned (bit3..1)
- for r in range(8):
- if r < 5:
- s = rows[r]
- v = 0
- for i,px in enumerate(s): # i=0 leftmost -> bit3
- if px=='#': v |= (1 << (3-i))
- out.append(v)
- else:
- out.append(0)
+# ---- 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 font (3x5 glyphs), 96 glyphs",
+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)
- key = ch.upper() if ch.isalpha() else ch
- rows = G.get(key, G.get(ch, ["###","# #","# #","# #","###"])) # box for unknown
- b = glyph_bytes(rows)
- lines.append(" db " + ",".join("$%02X"%x for x in b) + " ; '%s'"%(ch if ch!='\\' and code!=127 else '?'))
+ 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<code<127 else ('SP' if code==32 else 'DEL')))
open("/home/user/dev/gbos/src/font.asm","w").write("\n".join(lines)+"\n")
-print("wrote src/font.inc:", (128-32), "glyphs")
+print("wrote src/font.asm; missing glyphs:", "".join(missing) or "(none)")