nx_font_1bpp.nx source
↩ module page · 115 lines · 4069 B
1// nx_font_1bpp.nx -- bitmap font (caller-supplied glyph data).
2//
3// Substrate-layer font primitive. Caller supplies the glyph bytes
4// (e.g., a public-domain 5x7 monospace ASCII font), substrate
5// provides the lookup + bounds-checking. Designed for SSD1306-class
6// 1bpp displays where 5x7 = 35 bits = 5 bytes per glyph (with
7// vertical-byte layout matching the framebuffer).
8//
9// Glyph layout: each glyph_width column is one byte (top bit = top
10// pixel for fonts up to height 8). For height > 8, multiple bytes
11// per column (caller arranges).
12//
13// Composes:
14// nx_fb_1bpp -- destination framebuffer
15// nx_text_render -- draws strings using this font primitive
16//
17// V1 ships:
18// - struct NxFont with caller-allocated glyph data
19// - new + glyph_at for lookup
20// - glyph_width / glyph_height getters
21//
22// Gap list:
23// - no variable-width font support yet (monospace V1)
24// - no anti-aliasing (1bpp by design)
25// - no UTF-8 (ASCII only V1)
26
27import "nx_syscalls.nx"
28import "nx_tier.nx"
29
30const NX_FT_OK: nx_int = 0
31const NX_FT_ERR_BAD_CHAR: nx_int = 1
32const NX_FT_ERR_BAD_DIM: nx_int = 2
33
34// ===== Struct: NxFont =============================================
35
36struct NxFont {
37 glyph_data: *u8, // glyph_count * glyph_bytes_per_glyph
38 glyph_width: nx_size, // column count per glyph
39 glyph_height: nx_size, // row count per glyph
40 glyph_count: nx_int,
41 base_char: nx_int, // first ASCII character in table
42 bytes_per_glyph: nx_size, // = glyph_width * ((glyph_height + 7) / 8)
43}
44
45func nx_font_new(glyph_data: *u8,
46 glyph_width: nx_size,
47 glyph_height: nx_size,
48 glyph_count: nx_int,
49 base_char: nx_int) -> *NxFont {
50 if glyph_width == 0 { return (0 as i64) as *NxFont }
51 if glyph_height == 0 { return (0 as i64) as *NxFont }
52 if glyph_count <= 0 { return (0 as i64) as *NxFont }
53 let f: *NxFont = (sys_mmap(48)) as *NxFont
54 f.glyph_data = glyph_data
55 f.glyph_width = glyph_width
56 f.glyph_height = glyph_height
57 f.glyph_count = glyph_count
58 f.base_char = base_char
59 f.bytes_per_glyph = glyph_width * ((glyph_height + 7) / 8)
60 return f
61}
62
63// ===== nx_font_glyph_at ===========================================
64//
65// Returns pointer to the start of glyph data for character ch.
66// Returns NULL if ch is outside the font's range. Caller iterates
67// the bytes_per_glyph bytes there to render.
68
69func nx_font_glyph_at(f: *NxFont, ch: nx_int) -> *u8 {
70 let idx: nx_int = ch - f.base_char
71 if idx < 0 { return (0 as i64) as *u8 }
72 if idx >= f.glyph_count { return (0 as i64) as *u8 }
73 let off: nx_size = (idx as nx_size) * f.bytes_per_glyph
74 return (f.glyph_data as i64 + off as i64) as *u8
75}
76
77func nx_font_has_char(f: *NxFont, ch: nx_int) -> nx_int {
78 let idx: nx_int = ch - f.base_char
79 if idx < 0 { return 0 }
80 if idx >= f.glyph_count { return 0 }
81 return 1
82}
83
84func nx_font_glyph_width(f: *NxFont) -> nx_size {
85 return f.glyph_width
86}
87
88func nx_font_glyph_height(f: *NxFont) -> nx_size {
89 return f.glyph_height
90}
91
92func nx_font_bytes_per_glyph(f: *NxFont) -> nx_size {
93 return f.bytes_per_glyph
94}
95
96// ===== nx_font_glyph_pixel ========================================
97//
98// Get the pixel value (0 or 1) at (col, row) within glyph for ch.
99// Layout: vertical bytes — col*ceil(h/8) bytes per column, MSB at
100// bottom of column-group (matching SSD1306 page layout convention).
101
102func nx_font_glyph_pixel(f: *NxFont, ch: nx_int,
103 col: nx_size, row: nx_size) -> nx_int {
104 if col >= f.glyph_width { return 0 }
105 if row >= f.glyph_height { return 0 }
106 let g: *u8 = nx_font_glyph_at(f, ch)
107 if (g as i64) == 0 { return 0 }
108 let page: nx_size = row / 8
109 let bit_in_page: nx_size = row - (page * 8)
110 let bytes_per_col: nx_size = (f.glyph_height + 7) / 8
111 let byte_off: nx_size = col * bytes_per_col + page
112 let b: nx_int = (g[byte_off] as i64) & 255
113 if (b & (1 << bit_in_page)) != 0 { return 1 }
114 return 0
115}