diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-09 12:26:05 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-09 12:26:05 +0800 |
| commit | ce29bee5026fc708d5aae23c9b95307bb7ad5bd1 (patch) | |
| tree | 0c0af21717d89533ffb9bd84c621bb6bf1f5e6d4 /kon | |
| parent | c7961e8f5a3b94a7b2b319e169e1049796a6739b (diff) | |
Add built in bitmap font
Diffstat (limited to 'kon')
| -rw-r--r-- | kon/konfont.h | 180 |
1 files changed, 178 insertions, 2 deletions
diff --git a/kon/konfont.h b/kon/konfont.h index a75c502..3cd1006 100644 --- a/kon/konfont.h +++ b/kon/konfont.h @@ -41,6 +41,10 @@ typedef struct kon_font kon_font_t; /*** font declarations ***/ kon_font_t *kon_loadFont(const uint8_t *ttf_data, size_t size, float pixelHeight); + +/* a small built in 8x13 bitmap font, needs no files. scale 1 is 13 pixels high, 2 is 26 and so on. + monospace, ascii only, the baseline is 10 rows below the top. kon_fontGetAtlas gives NULL for it */ +kon_font_t *kon_loadBuiltinFont(int scale); void kon_freeFont(kon_font_t *font); kon_image *kon_fontGetAtlas(kon_font_t *font); @@ -61,6 +65,7 @@ void kon_measureText(kon_font_t *font, const char *text, int *outWidth, int *out #include "stb_truetype.h" struct kon_font { + int builtin, scale; const uint8_t *ttf; stbtt_bakedchar chardata[KON_FONT_NUM_CHARS]; uint8_t *atlasPixels; @@ -68,6 +73,151 @@ struct kon_font { float pixelHeight; }; +/*** built in font ***/ + +/* 8x13 glyphs for ascii 32 to 126, one byte per row, leftmost pixel is the top bit. public domain misc-fixed derived font */ +static const unsigned char kon_builtinGlyphs_[KON_FONT_NUM_CHARS][13] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* */ + { 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00 }, /* ! */ + { 0x00, 0x00, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* " */ + { 0x00, 0x00, 0x00, 0x24, 0x24, 0x7E, 0x24, 0x7E, 0x24, 0x24, 0x00, 0x00, 0x00 }, /* # */ + { 0x00, 0x00, 0x10, 0x3C, 0x50, 0x50, 0x38, 0x14, 0x14, 0x78, 0x10, 0x00, 0x00 }, /* $ */ + { 0x00, 0x00, 0x22, 0x52, 0x24, 0x08, 0x08, 0x10, 0x24, 0x2A, 0x44, 0x00, 0x00 }, /* % */ + { 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x48, 0x30, 0x4A, 0x44, 0x3A, 0x00, 0x00 }, /* & */ + { 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* ' */ + { 0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00 }, /* ( */ + { 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00 }, /* ) */ + { 0x00, 0x00, 0x00, 0x00, 0x24, 0x18, 0x7E, 0x18, 0x24, 0x00, 0x00, 0x00, 0x00 }, /* ch42 */ + { 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00 }, /* + */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x30, 0x40, 0x00 }, /* , */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* - */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x10, 0x00 }, /* . */ + { 0x00, 0x00, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00 }, /* ch47 */ + { 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00 }, /* 0 */ + { 0x00, 0x00, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00 }, /* 1 */ + { 0x00, 0x00, 0x3C, 0x42, 0x42, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00, 0x00 }, /* 2 */ + { 0x00, 0x00, 0x7E, 0x02, 0x04, 0x08, 0x1C, 0x02, 0x02, 0x42, 0x3C, 0x00, 0x00 }, /* 3 */ + { 0x00, 0x00, 0x04, 0x0C, 0x14, 0x24, 0x44, 0x44, 0x7E, 0x04, 0x04, 0x00, 0x00 }, /* 4 */ + { 0x00, 0x00, 0x7E, 0x40, 0x40, 0x5C, 0x62, 0x02, 0x02, 0x42, 0x3C, 0x00, 0x00 }, /* 5 */ + { 0x00, 0x00, 0x1C, 0x20, 0x40, 0x40, 0x5C, 0x62, 0x42, 0x42, 0x3C, 0x00, 0x00 }, /* 6 */ + { 0x00, 0x00, 0x7E, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00 }, /* 7 */ + { 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00 }, /* 8 */ + { 0x00, 0x00, 0x3C, 0x42, 0x42, 0x46, 0x3A, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00 }, /* 9 */ + { 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x10, 0x00, 0x00, 0x10, 0x38, 0x10, 0x00 }, /* : */ + { 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x10, 0x00, 0x00, 0x38, 0x30, 0x40, 0x00 }, /* ; */ + { 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00 }, /* < */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00 }, /* = */ + { 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00 }, /* > */ + { 0x00, 0x00, 0x3C, 0x42, 0x42, 0x02, 0x04, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00 }, /* ? */ + { 0x00, 0x00, 0x3C, 0x42, 0x42, 0x4E, 0x52, 0x56, 0x4A, 0x40, 0x3C, 0x00, 0x00 }, /* @ */ + { 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00, 0x00 }, /* A */ + { 0x00, 0x00, 0x78, 0x44, 0x42, 0x44, 0x78, 0x44, 0x42, 0x44, 0x78, 0x00, 0x00 }, /* B */ + { 0x00, 0x00, 0x3C, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00, 0x00 }, /* C */ + { 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00 }, /* D */ + { 0x00, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7E, 0x00, 0x00 }, /* E */ + { 0x00, 0x00, 0x7E, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00 }, /* F */ + { 0x00, 0x00, 0x3C, 0x42, 0x40, 0x40, 0x40, 0x4E, 0x42, 0x46, 0x3A, 0x00, 0x00 }, /* G */ + { 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00 }, /* H */ + { 0x00, 0x00, 0x7C, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00 }, /* I */ + { 0x00, 0x00, 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00 }, /* J */ + { 0x00, 0x00, 0x42, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00 }, /* K */ + { 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00, 0x00 }, /* L */ + { 0x00, 0x00, 0x82, 0x82, 0xC6, 0xAA, 0x92, 0x92, 0x82, 0x82, 0x82, 0x00, 0x00 }, /* M */ + { 0x00, 0x00, 0x42, 0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x42, 0x00, 0x00 }, /* N */ + { 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00 }, /* O */ + { 0x00, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00 }, /* P */ + { 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x52, 0x4A, 0x3C, 0x02, 0x00 }, /* Q */ + { 0x00, 0x00, 0x7C, 0x42, 0x42, 0x42, 0x7C, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00 }, /* R */ + { 0x00, 0x00, 0x3C, 0x42, 0x40, 0x40, 0x3C, 0x02, 0x02, 0x42, 0x3C, 0x00, 0x00 }, /* S */ + { 0x00, 0x00, 0xFE, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00 }, /* T */ + { 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00 }, /* U */ + { 0x00, 0x00, 0x82, 0x82, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, 0x00, 0x00 }, /* V */ + { 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0x92, 0x92, 0x92, 0xAA, 0x44, 0x00, 0x00 }, /* W */ + { 0x00, 0x00, 0x82, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x82, 0x00, 0x00 }, /* X */ + { 0x00, 0x00, 0x82, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00 }, /* Y */ + { 0x00, 0x00, 0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7E, 0x00, 0x00 }, /* Z */ + { 0x00, 0x00, 0x3C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3C, 0x00, 0x00 }, /* [ */ + { 0x00, 0x00, 0x80, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00 }, /* ch92 */ + { 0x00, 0x00, 0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00, 0x00 }, /* ] */ + { 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* ^ */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00 }, /* _ */ + { 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* ` */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x02, 0x3E, 0x42, 0x46, 0x3A, 0x00, 0x00 }, /* a */ + { 0x00, 0x00, 0x40, 0x40, 0x40, 0x5C, 0x62, 0x42, 0x42, 0x62, 0x5C, 0x00, 0x00 }, /* b */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x40, 0x40, 0x42, 0x3C, 0x00, 0x00 }, /* c */ + { 0x00, 0x00, 0x02, 0x02, 0x02, 0x3A, 0x46, 0x42, 0x42, 0x46, 0x3A, 0x00, 0x00 }, /* d */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x7E, 0x40, 0x42, 0x3C, 0x00, 0x00 }, /* e */ + { 0x00, 0x00, 0x1C, 0x22, 0x20, 0x20, 0x7C, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }, /* f */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x44, 0x44, 0x38, 0x40, 0x3C, 0x42, 0x3C }, /* g */ + { 0x00, 0x00, 0x40, 0x40, 0x40, 0x5C, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00 }, /* h */ + { 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00 }, /* i */ + { 0x00, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38 }, /* j */ + { 0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00, 0x00 }, /* k */ + { 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00 }, /* l */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x92, 0x92, 0x92, 0x92, 0x82, 0x00, 0x00 }, /* m */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00 }, /* n */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, 0x00 }, /* o */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x62, 0x42, 0x62, 0x5C, 0x40, 0x40, 0x40 }, /* p */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x46, 0x42, 0x46, 0x3A, 0x02, 0x02, 0x02 }, /* q */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x22, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00 }, /* r */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x42, 0x30, 0x0C, 0x42, 0x3C, 0x00, 0x00 }, /* s */ + { 0x00, 0x00, 0x00, 0x20, 0x20, 0x7C, 0x20, 0x20, 0x20, 0x22, 0x1C, 0x00, 0x00 }, /* t */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x3A, 0x00, 0x00 }, /* u */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x00 }, /* v */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, 0x92, 0x92, 0xAA, 0x44, 0x00, 0x00 }, /* w */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00 }, /* x */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x46, 0x3A, 0x02, 0x42, 0x3C }, /* y */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x00, 0x00 }, /* z */ + { 0x00, 0x00, 0x0E, 0x10, 0x10, 0x08, 0x30, 0x08, 0x10, 0x10, 0x0E, 0x00, 0x00 }, /* { */ + { 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00 }, /* | */ + { 0x00, 0x00, 0x70, 0x08, 0x08, 0x10, 0x0C, 0x10, 0x08, 0x08, 0x70, 0x00, 0x00 }, /* } */ + { 0x00, 0x00, 0x24, 0x54, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* ~ */ +}; + +#define KON_BUILTIN_WIDTH 8 +#define KON_BUILTIN_HEIGHT 13 +#define KON_BUILTIN_BASELINE 10 +#define KON_BUILTIN_MAX_SCALE 8 + +static void kon_fontDrawBuiltin_(kon_framebuffer_t *fb, const kon_font_t *font, int x, int y, const char *text, uint32_t color) { + int s = font->scale; + int top = y - KON_BUILTIN_BASELINE * s; + + color = (color & 0x00FFFFFFu) | 0xFF000000u; + + for (const char *p = text; *p; p++) { + unsigned char c = (unsigned char)*p; + if (c < KON_FONT_FIRST_CHAR || c >= KON_FONT_FIRST_CHAR + KON_FONT_NUM_CHARS) continue; + + for (int row = 0; row < KON_BUILTIN_HEIGHT; row++) { + unsigned char bits = kon_builtinGlyphs_[c - KON_FONT_FIRST_CHAR][row]; + + for (int bit = 0; bit < KON_BUILTIN_WIDTH; ) { + if (!(bits & (0x80 >> bit))) { + bit++; + continue; + } + int start = bit; + while (bit < KON_BUILTIN_WIDTH && (bits & (0x80 >> bit))) bit++; + kon_fillRectangle(fb, x + start * s, top + row * s, (bit - start) * s, s, color); + } + } + x += KON_BUILTIN_WIDTH * s; + } +} + +kon_font_t *kon_loadBuiltinFont(int scale) { + if (scale < 1 || scale > KON_BUILTIN_MAX_SCALE) return NULL; + + kon_font_t *font = calloc(1, sizeof(kon_font_t)); + if (!font) return NULL; + + font->builtin = 1; + font->scale = scale; + font->pixelHeight = (float)(KON_BUILTIN_HEIGHT * scale); + return font; +} + /*** private helpers ***/ static bool kon_fontBakeAtlas(kon_font_t *font, const uint8_t *ttf_data, float pixelHeight) { @@ -100,7 +250,7 @@ kon_font_t *kon_loadFont(const uint8_t *ttf_data, size_t size, float pixelHeight if (!ttf_data || pixelHeight <= 0.0f) return NULL; - kon_font_t *font = malloc(sizeof(kon_font_t)); + kon_font_t *font = calloc(1, sizeof(kon_font_t)); if (!font) return NULL; font->ttf = ttf_data; @@ -131,6 +281,15 @@ int kon_fontResize(kon_font_t *font, float pixelHeight) { if (!font || pixelHeight <= 0.0f) return 0; + if (font->builtin) { + int scale = (int)(pixelHeight / (float)KON_BUILTIN_HEIGHT + 0.5f); + if (scale < 1) scale = 1; + if (scale > KON_BUILTIN_MAX_SCALE) scale = KON_BUILTIN_MAX_SCALE; + font->scale = scale; + font->pixelHeight = (float)(KON_BUILTIN_HEIGHT * scale); + return 1; + } + next = *font; next.atlasPixels = NULL; if (!kon_fontBakeAtlas(&next, font->ttf, pixelHeight)) return 0; @@ -142,7 +301,7 @@ int kon_fontResize(kon_font_t *font, float pixelHeight) { } kon_image *kon_fontGetAtlas(kon_font_t *font) { - if (!font) return NULL; + if (!font || font->builtin) return NULL; int n = font->atlasSize * font->atlasSize; uint8_t *rgba = malloc((size_t)n * 4); @@ -166,6 +325,11 @@ kon_image *kon_fontGetAtlas(kon_font_t *font) { void kon_drawText(kon_framebuffer_t *fb, kon_font_t *font, int x, int y, const char *text, uint32_t color) { if (!fb || !font || !text) return; + if (font->builtin) { + kon_fontDrawBuiltin_(fb, font, x, y, text, color); + return; + } + uint32_t baseColor = color & 0x00FFFFFF; float cursorX = (float)x; @@ -198,6 +362,18 @@ void kon_drawText(kon_framebuffer_t *fb, kon_font_t *font, int x, int y, const c void kon_measureText(kon_font_t *font, const char *text, int *outWidth, int *outHeight) { if (!font || !text) return; + if (font->builtin) { + int count = 0; + + for (const char *p = text; *p; p++) { + unsigned char c = (unsigned char)*p; + if (c >= KON_FONT_FIRST_CHAR && c < KON_FONT_FIRST_CHAR + KON_FONT_NUM_CHARS) count++; + } + if (outWidth) *outWidth = count * KON_BUILTIN_WIDTH * font->scale; + if (outHeight) *outHeight = KON_BUILTIN_HEIGHT * font->scale; + return; + } + float cursorX = 0.0f; float cursorY = 0.0f; float maxX = 0.0f; |
