Add C Font module for FreeType interface.
This commit is contained in:
parent
401eb1d960
commit
45bbf230a5
@ -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
129
src/jes/gui/font.c
Normal 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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user