aboutsummaryrefslogtreecommitdiff
path: root/hikari/display/font.zig
blob: 8abb94ce0b391429a3689c7ec399b0eaeb77ab68 (plain)
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;
    }
};