diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-26 16:03:00 +0200 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-26 16:03:00 +0200 |
commit | f199eae0154f354c37750c8cd3037f94dbfe70db (patch) | |
tree | 90938c26bdbe388745a0c3bbd074af92fd49ae13 /src/font.c |
Initial commit
Diffstat (limited to 'src/font.c')
-rw-r--r-- | src/font.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..33c81aa --- /dev/null +++ b/src/font.c @@ -0,0 +1,134 @@ +#include "aplos.h" + +static const uint8_t font_data[] = { + #embed "../external/spleen/spleen-8x16.psfu" +// #embed "../external/spleen/spleen-12x24.psfu" +// #embed "../external/spleen/spleen-16x32.psfu" +}; + +static uint32_t header_size; +static uint32_t glyph_count; +static uint32_t bytes_per_glyph; +static uint32_t char_height; +static uint32_t char_width; + +static void font_init_psf1(void); +static void font_init_psf2(void); + +static const uint8_t *font_bitmap(char8_t *c); +static uint64_t lookup_psf1(char8_t *); +static uint64_t lookup_psf2(char8_t *); + +static uint64_t (*lookup)(char8_t *); + +void +font_init(void) +{ + if(read_uint16_le(font_data) == 0x0436) + font_init_psf1(); + else if(read_uint32_le(font_data) == 0x864AB572) + font_init_psf2(); + else + halt(); +} + +static void +font_init_psf1(void) +{ + header_size = 4; + glyph_count = (font_data[2] & 1) ? 512 : 256; + bytes_per_glyph = font_data[3]; + char_height = bytes_per_glyph; + char_width = 8; + lookup = lookup_psf1; +} + +static void +font_init_psf2(void) +{ + header_size = read_uint32_le(font_data+8); + glyph_count = read_uint32_le(font_data+16); + bytes_per_glyph = read_uint32_le(font_data+20); + char_height = read_uint32_le(font_data+24); + char_width = read_uint32_le(font_data+28); + lookup = lookup_psf2; +} + +void +font_draw(char8_t *c, uint32_t row, uint32_t col, uint32_t bg, uint32_t fg) +{ + uint32_t x0 = char_width * col; + uint32_t y0 = char_height * row; + + const uint8_t *data = font_bitmap(c); + data--; + + for(uint32_t y = 0; y < char_height; y++){ + int shift = 0; + for(uint32_t x = 0; x < char_width; x++){ + if(shift == 0){ + shift = 8; + data++; + } + shift--; + + uint8_t val = *data; + uint8_t mask = 1<<shift; + screen_draw_pixel(x0+x, y0+y, (val&mask) ? fg : bg); + } + } +} + +static const uint8_t * +font_bitmap(char8_t *c) +{ + uint64_t index = lookup(c); + if(index == UINT64_MAX){ + if(*c == '?') + index = 0; + else + index = lookup(u8"?"); + } + return font_data + header_size + bytes_per_glyph * index; +} + +static uint64_t +lookup_psf1(char8_t *c) +{ + uint64_t offset = 0; + uint32_t v = utf8_value(c); + if(v > UINT16_MAX) + return 0; + + const uint8_t *p = font_data + header_size + glyph_count * bytes_per_glyph; + while(p < &font_data[nelem(font_data)]){ + uint16_t x = read_uint16_le(p); + p += 2; + if(x == 0xFFFF) + offset++; + else if(x == v) + return offset; + } + return UINT64_MAX; +} + +static uint64_t +lookup_psf2(char8_t *c) +{ + int char_len = utf8_char_length(c); + uint64_t offset = 0; + const uint8_t *p = font_data + header_size + glyph_count * bytes_per_glyph; + while(p < &font_data[nelem(font_data)]){ + if(*p == 0xFF){ + offset++; + p++; + }else if(memcmp(p, c, char_len) == 0){ + return offset; + }else if(*p == 0xFE){ + p++; + }else{ + p += utf8_char_length(p); + } + } + return UINT64_MAX; +} |