1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
//! Hikari PSF2 Font
pub const psf2_magic: u32 = 0x864AB572;
pub const Psf2Header = extern struct {
magic: u32,
version: u32,
header_size: u32,
flags: u32,
glyph_count: u32,
glyph_size: u32,
height: u32,
width: u32,
pub fn is_valid(self: *const Psf2Header) bool {
return self.magic == psf2_magic;
}
pub fn has_unicode_table(self: *const Psf2Header) bool {
return (self.flags & 0x01) != 0;
}
pub fn bytes_per_row(self: *const Psf2Header) u32 {
return (self.width + 7) / 8;
}
};
pub const Font = struct {
header: *const Psf2Header,
glyphs: [*]const u8,
glyph_count: u32,
glyph_size: u32,
width: u32,
height: u32,
bytes_per_row: u32,
pub fn load(data: [*]const u8, size: u64) ?Font {
if (size < @sizeOf(Psf2Header)) {
return null;
}
const header: *const Psf2Header = @ptrCast(@alignCast(data));
if (!header.is_valid()) {
return null;
}
const glyphs = data + header.header_size;
return Font{
.header = header,
.glyphs = glyphs,
.glyph_count = header.glyph_count,
.glyph_size = header.glyph_size,
.width = header.width,
.height = header.height,
.bytes_per_row = header.bytes_per_row(),
};
}
pub fn get_glyph(self: *const Font, codepoint: u32) ?[*]const u8 {
if (codepoint >= self.glyph_count) {
return null;
}
return self.glyphs + (codepoint * self.glyph_size);
}
pub fn get_glyph_pixel(self: *const Font, glyph: [*]const u8, x: u32, y: u32) bool {
if (x >= self.width or y >= self.height) {
return false;
}
const row = glyph + (y * self.bytes_per_row);
const byte_index = x / 8;
const bit_index: u3 = @truncate(7 - (x % 8));
return ((row[byte_index] >> bit_index) & 1) != 0;
}
};
|