summaryrefslogtreecommitdiff
path: root/src/font.c
diff options
context:
space:
mode:
authorPeter Mikkelsen <petermikkelsen10@gmail.com>2025-07-26 16:03:00 +0200
committerPeter Mikkelsen <petermikkelsen10@gmail.com>2025-07-26 16:03:00 +0200
commitf199eae0154f354c37750c8cd3037f94dbfe70db (patch)
tree90938c26bdbe388745a0c3bbd074af92fd49ae13 /src/font.c
Initial commit
Diffstat (limited to 'src/font.c')
-rw-r--r--src/font.c134
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;
+}