2024-11-05 19:47:22 -06:00
|
|
|
.{log, memory} := @use("../../stn/src/lib.hb")
|
2024-10-26 03:23:28 -05:00
|
|
|
|
|
|
|
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,
|
2024-11-05 19:47:22 -06:00
|
|
|
unicode: ?^u16,
|
2024-10-26 03:23:28 -05:00
|
|
|
}
|
|
|
|
|
2024-11-03 16:31:53 -06:00
|
|
|
font_from_psf1 := fn(psf: ^u8): ?Font {
|
2024-10-26 03:23:28 -05:00
|
|
|
header := @as(^PSF1Header, @bitcast(psf))
|
|
|
|
if header.magic != 0x436 {
|
|
|
|
log.error("failed to load psf font: not a psf1 font, idiot\0")
|
2024-11-03 16:31:53 -06:00
|
|
|
return null
|
2024-10-26 03:23:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
psf += @sizeof(PSF1Header)
|
|
|
|
|
|
|
|
return .(
|
|
|
|
psf,
|
|
|
|
8,
|
2024-11-03 16:31:53 -06:00
|
|
|
header.character_size,
|
2024-10-26 03:23:28 -05:00
|
|
|
256,
|
2024-11-03 16:31:53 -06:00
|
|
|
header.character_size,
|
2024-10-26 03:23:28 -05:00
|
|
|
0,
|
|
|
|
0,
|
2024-11-05 19:47:22 -06:00
|
|
|
null,
|
2024-10-26 03:23:28 -05:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-11-05 19:47:22 -06:00
|
|
|
font_from_psf2 := fn(psf: ^u8, unicode: bool): ?Font {
|
2024-10-26 03:23:28 -05:00
|
|
|
header := @as(^PSF2Header, @bitcast(psf))
|
|
|
|
if header.magic != 0x864AB572 {
|
|
|
|
log.error("failed to load psf font: not a psf2 font, idiot\0")
|
2024-11-03 16:31:53 -06:00
|
|
|
return null
|
2024-10-26 03:23:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
psf += header.header_size
|
|
|
|
|
2024-11-05 19:47:22 -06:00
|
|
|
font := Font.(
|
2024-10-26 03:23:28 -05:00
|
|
|
psf,
|
2024-11-03 16:31:53 -06:00
|
|
|
header.width,
|
|
|
|
header.height,
|
|
|
|
header.num_glyph,
|
|
|
|
header.bytes_per_glyph,
|
2024-10-26 03:23:28 -05:00
|
|
|
0,
|
|
|
|
0,
|
2024-11-05 19:47:22 -06:00
|
|
|
null,
|
2024-10-26 03:23:28 -05:00
|
|
|
)
|
2024-11-05 19:47:22 -06:00
|
|
|
if (header.flags & 1) != 0 & unicode {
|
|
|
|
init_unicode(&font)
|
|
|
|
}
|
|
|
|
return font
|
2024-10-26 03:23:28 -05:00
|
|
|
}
|
|
|
|
|
2024-11-12 14:14:37 -06:00
|
|
|
$get_glyph := fn(font: Font, index: u8): ^u8 {
|
2024-11-05 19:47:22 -06:00
|
|
|
return font.data + @as(uint, index) * font.bytes_per_glyph
|
|
|
|
}
|
|
|
|
|
2024-11-12 14:14:37 -06:00
|
|
|
$UNC_TABLE_SIZE := 1 << 16
|
2024-11-05 19:47:22 -06:00
|
|
|
|
|
|
|
init_unicode := fn(font: ^Font): void {
|
|
|
|
font.unicode = memory.alloc(u16, UNC_TABLE_SIZE)
|
|
|
|
|
2024-11-12 14:14:37 -06:00
|
|
|
memory.set(u16, &0xFFFF, font.unicode, UNC_TABLE_SIZE)
|
2024-11-05 19:47:22 -06:00
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
}
|
2024-10-26 03:23:28 -05:00
|
|
|
}
|