From 45bbf230a523dc2398bb22d82d09ca45edec9047 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 29 Nov 2020 10:37:19 -0500 Subject: [PATCH] Add C Font module for FreeType interface. --- Rsconscript | 1 + src/jes/gui/font.c | 129 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 src/jes/gui/font.c diff --git a/Rsconscript b/Rsconscript index afd9cf9..df65825 100644 --- a/Rsconscript +++ b/Rsconscript @@ -2,6 +2,7 @@ configure do check_d_compiler check_lib "X11" check_lib "GLX" + check_cfg package: "freetype2" end build do diff --git a/src/jes/gui/font.c b/src/jes/gui/font.c new file mode 100644 index 0000000..2b94d25 --- /dev/null +++ b/src/jes/gui/font.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include FT_FREETYPE_H + +#define round_up_26_6(val) (((val) + 63) >> 6u) + +static FT_Library Library_Handle; +static bool Initialized; + +typedef struct +{ + FT_Face face; + int32_t advance; + int32_t line_height; + int32_t baseline_offset; +} Font; + +typedef struct +{ + uint8_t * bitmap; + int32_t width; + int32_t height; + int32_t left; + int32_t top; + int32_t advance; +} Glyph; + +static bool Load_FreeType(void) +{ + if (Initialized) + { + return true; + } + + if (FT_Init_FreeType(&Library_Handle) != 0) + { + return false; + } + + return Initialized = true; +} + +Glyph * Font_LoadGlyph(Font * font, uint32_t char_code) +{ + FT_Char ft_char_code = char_code; + if (FT_Load_Char(font->face, ft_char_code, FT_LOAD_RENDER) != 0) + return NULL; + + Glyph * glyph = (Glyph *)malloc(sizeof(Glyph)); + glyph->width = font->face->glyph->bitmap.width; + glyph->height = font->face->glyph->bitmap.rows; + glyph->left = font->face->glyph->bitmap_left; + glyph->top = font->face->glyph->bitmap_top; + glyph->advance = round_up_26_6(font->face->glyph->advance.x); + glyph->bitmap = malloc(glyph->width * glyph->height); + memcpy(glyph->bitmap, font->face->glyph->bitmap.buffer, glyph->width * glyph->height); + + return glyph; +} + +void Font_FreeGlyph(Glyph * glyph) +{ + free(glyph->bitmap); + free(glyph); +} + +static void PreloadGlyphs(Font * font) +{ + static const char preload_glyph_list[] = "HMgjqxy_|^"; + + int max_top = -9999; + int min_bottom = 9999; + font->advance = 0; + + for (size_t i = 0u; i < sizeof(preload_glyph_list) - 1u; i++) + { + Glyph * glyph = Font_LoadGlyph(font, (uint8_t)preload_glyph_list[i]); + if (glyph != NULL) + { + if (font->face->glyph->bitmap_top > max_top) + { + max_top = font->face->glyph->bitmap_top; + } + int bitmap_bottom = font->face->glyph->bitmap_top - font->face->glyph->bitmap.rows; + if (bitmap_bottom < min_bottom) + { + min_bottom = bitmap_bottom; + } + if (glyph->advance > font->advance) + { + font->advance = glyph->advance; + } + } + } + + font->line_height = round_up_26_6(font->face->size->metrics.height); + font->baseline_offset = (font->line_height - (max_top - min_bottom)) / 2 - min_bottom; +} + +Font * Font_Load(const char * fname, int32_t size) +{ + FT_Face face; + + if (!Load_FreeType()) + { + return NULL; + } + + if (FT_New_Face(Library_Handle, fname, 0, &face) != 0) + { + return NULL; + } + + Font * font = (Font *)malloc(sizeof(Font)); + font->face = face; + + FT_Set_Pixel_Sizes(face, 0, size); + + PreloadGlyphs(font); + + return font; +} + +void Font_Free(Font * font) +{ + free(font); +}