Add C Font module for FreeType interface.

This commit is contained in:
Josh Holtrop 2020-11-29 10:37:19 -05:00
parent 401eb1d960
commit 45bbf230a5
2 changed files with 130 additions and 0 deletions

View File

@ -2,6 +2,7 @@ configure do
check_d_compiler
check_lib "X11"
check_lib "GLX"
check_cfg package: "freetype2"
end
build do

129
src/jes/gui/font.c Normal file
View File

@ -0,0 +1,129 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <ft2build.h>
#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);
}