.{log, memory} := @use("../../stn/src/lib.hb") PSF1Header := packed struct { magic: u16, font_mode: u8, character_size: u8, } PSF2Header := packed struct { magic: u32, version: u32, header_size: u32, flags: u32, num_glyph: u32, bytes_per_glyph: u32, height: u32, width: u32, } Font := struct { data: ^u8, width: uint, height: uint, num_glyphs: uint, bytes_per_glyph: uint, line_gap: uint, char_gap: uint, unicode: ?^u16, } font_from_psf1 := fn(psf: ^u8): ?Font { header := @as(^PSF1Header, @bitcast(psf)) if header.magic != 0x436 { log.error("failed to load psf font: not a psf1 font, idiot\0") return null } psf += @sizeof(PSF1Header) return .( psf, 8, header.character_size, 256, header.character_size, 0, 0, null, ) } font_from_psf2 := fn(psf: ^u8, unicode: bool): ?Font { header := @as(^PSF2Header, @bitcast(psf)) if header.magic != 0x864AB572 { log.error("failed to load psf font: not a psf2 font, idiot\0") return null } psf += header.header_size font := Font.( psf, header.width, header.height, header.num_glyph, header.bytes_per_glyph, 0, 0, null, ) if (header.flags & 1) != 0 & unicode { init_unicode(&font) } return font } get_glyph := fn(font: Font, index: u8): ^u8 { return font.data + @as(uint, index) * font.bytes_per_glyph } UNC_TABLE_SIZE := 1 << 16 init_unicode := fn(font: ^Font): void { font.unicode = memory.alloc(u16, UNC_TABLE_SIZE) @inline(memory.set, u16, &0xFFFF, font.unicode, UNC_TABLE_SIZE) table := font.data + font.num_glyphs * font.bytes_per_glyph curr_glyph := @as(u16, 0) loop if curr_glyph >= font.num_glyphs break else { loop { byte := *table table += 1 if byte == 0xFF break if byte == 0xFE { continue } unicode := @as(uint, 0) bytes_to_read := @as(uint, 1) if (byte & 0x80) == 0 { unicode = byte } else if (byte & 0xE0) == 0xC0 { unicode = byte & 0x1F bytes_to_read = 2 } else if (byte & 0xF0) == 0xE0 { unicode = byte & 0xF bytes_to_read = 3 } else if (byte & 0xF8) == 0xF0 { unicode = byte & 0x7 bytes_to_read = 4 } else { continue } valid := true loop if bytes_to_read <= 1 break else { next_byte := *table if (next_byte & 0xC0) != 0x80 { valid = false } if valid == false { break } unicode = unicode << 6 | next_byte & 0x3F table += 1 bytes_to_read -= 1 } if valid == false continue if bytes_to_read == 4 { if unicode < 0x10000 | unicode > 0x10FFFF continue if unicode <= 0xFFFF { if unicode < UNC_TABLE_SIZE { *(@unwrap(font.unicode) + unicode) = curr_glyph } } else { unicode -= 0x10000 high_surrogate := 0xD800 | unicode >> 10 & 0x3FF low_surrogate := 0xDC00 | unicode & 0x3FF if high_surrogate < UNC_TABLE_SIZE { *(@unwrap(font.unicode) + high_surrogate) = curr_glyph } if low_surrogate < UNC_TABLE_SIZE { *(@unwrap(font.unicode) + low_surrogate) = curr_glyph } } } else { if unicode < UNC_TABLE_SIZE { *(@unwrap(font.unicode) + unicode) = curr_glyph } } } curr_glyph += 1 } }