Added caching to the font system
I never liked how much of a bottleneck the font renderer was. Maybe now the credits won't stutter like mad on the Raspberry Pi.
This commit is contained in:
parent
f25df2ce07
commit
cc4eb82162
1 changed files with 112 additions and 59 deletions
115
src/Font.cpp
115
src/Font.cpp
|
@ -21,6 +21,18 @@
|
|||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
typedef struct CachedGlyph
|
||||
{
|
||||
unsigned long unicode_value;
|
||||
FT_Bitmap bitmap;
|
||||
unsigned char pixel_mode;
|
||||
int x;
|
||||
int y;
|
||||
int x_advance;
|
||||
|
||||
struct CachedGlyph *next;
|
||||
} CachedGlyph;
|
||||
|
||||
typedef struct FontObject
|
||||
{
|
||||
FT_Library library;
|
||||
|
@ -29,6 +41,7 @@ typedef struct FontObject
|
|||
#ifndef DISABLE_FONT_ANTIALIASING
|
||||
bool lcd_mode;
|
||||
#endif
|
||||
CachedGlyph *glyph_list_head;
|
||||
} FontObject;
|
||||
|
||||
#ifdef JAPANESE
|
||||
|
@ -1691,6 +1704,55 @@ static unsigned long UTF8ToUnicode(const unsigned char *string, unsigned int *by
|
|||
}
|
||||
#endif
|
||||
|
||||
static CachedGlyph* GetGlyphCached(FontObject *font_object, unsigned long unicode_value)
|
||||
{
|
||||
for (CachedGlyph *glyph = font_object->glyph_list_head; glyph != NULL; glyph = glyph->next)
|
||||
if (glyph->unicode_value == unicode_value)
|
||||
return glyph;
|
||||
|
||||
CachedGlyph *glyph = (CachedGlyph*)malloc(sizeof(CachedGlyph));
|
||||
|
||||
if (glyph)
|
||||
{
|
||||
glyph->next = font_object->glyph_list_head;
|
||||
font_object->glyph_list_head = glyph;
|
||||
|
||||
unsigned int glyph_index = FT_Get_Char_Index(font_object->face, unicode_value);
|
||||
|
||||
#ifndef DISABLE_FONT_ANTIALIASING
|
||||
FT_Load_Glyph(font_object->face, glyph_index, FT_LOAD_RENDER | (font_object->lcd_mode ? FT_LOAD_TARGET_LCD : 0));
|
||||
#else
|
||||
FT_Load_Glyph(font_object->face, glyph_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
|
||||
#endif
|
||||
|
||||
glyph->unicode_value = unicode_value;
|
||||
FT_Bitmap_New(&glyph->bitmap);
|
||||
FT_Bitmap_Convert(font_object->library, &font_object->face->glyph->bitmap, &glyph->bitmap, 1);
|
||||
glyph->pixel_mode = font_object->face->glyph->bitmap.pixel_mode;
|
||||
glyph->x = font_object->face->glyph->bitmap_left;
|
||||
glyph->y = (FT_MulFix(font_object->face->ascender, font_object->face->size->metrics.y_scale) - font_object->face->glyph->metrics.horiBearingY + (64 / 2)) / 64;
|
||||
glyph->x_advance = font_object->face->glyph->advance.x / 64;
|
||||
}
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
static void UnloadCachedGlyphs(FontObject *font_object)
|
||||
{
|
||||
CachedGlyph *glyph = font_object->glyph_list_head;
|
||||
while (glyph != NULL)
|
||||
{
|
||||
CachedGlyph *next_glyph = glyph->next;
|
||||
|
||||
FT_Bitmap_Done(font_object->library, &glyph->bitmap);
|
||||
free(glyph);
|
||||
|
||||
glyph = next_glyph;
|
||||
}
|
||||
|
||||
font_object->glyph_list_head = NULL;
|
||||
}
|
||||
|
||||
FontObject* LoadFontFromData(const unsigned char *data, size_t data_size, unsigned int cell_width, unsigned int cell_height)
|
||||
{
|
||||
FontObject *font_object = (FontObject*)malloc(sizeof(FontObject));
|
||||
|
@ -1769,8 +1831,6 @@ void DrawText(FontObject *font_object, unsigned char *bitmap_buffer, size_t bitm
|
|||
{
|
||||
const unsigned char colours[3] = {(unsigned char)colour, (unsigned char)(colour >> 8), (unsigned char)(colour >> 16)};
|
||||
|
||||
FT_Face face = font_object->face;
|
||||
|
||||
unsigned int pen_x = 0;
|
||||
|
||||
const unsigned char *string_pointer = (unsigned char*)string;
|
||||
|
@ -1780,35 +1840,27 @@ void DrawText(FontObject *font_object, unsigned char *bitmap_buffer, size_t bitm
|
|||
{
|
||||
unsigned int bytes_read;
|
||||
#ifdef JAPANESE
|
||||
const unsigned short val = ShiftJISToUnicode(string_pointer, &bytes_read);
|
||||
const unsigned short unicode_value = ShiftJISToUnicode(string_pointer, &bytes_read);
|
||||
#else
|
||||
const unsigned long val = UTF8ToUnicode(string_pointer, &bytes_read);
|
||||
const unsigned long unicode_value = UTF8ToUnicode(string_pointer, &bytes_read);
|
||||
#endif
|
||||
string_pointer += bytes_read;
|
||||
|
||||
unsigned int glyph_index = FT_Get_Char_Index(face, val);
|
||||
CachedGlyph *glyph = GetGlyphCached(font_object, unicode_value);
|
||||
|
||||
#ifndef DISABLE_FONT_ANTIALIASING
|
||||
FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | (font_object->lcd_mode ? FT_LOAD_TARGET_LCD : 0));
|
||||
#else
|
||||
FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
|
||||
#endif
|
||||
if (glyph)
|
||||
{
|
||||
const int letter_x = x + pen_x + glyph->x;
|
||||
const int letter_y = y + glyph->y;
|
||||
|
||||
FT_Bitmap converted;
|
||||
FT_Bitmap_New(&converted);
|
||||
FT_Bitmap_Convert(font_object->library, &face->glyph->bitmap, &converted, 1);
|
||||
|
||||
const int letter_x = x + pen_x + face->glyph->bitmap_left;
|
||||
const int letter_y = y + ((FT_MulFix(face->ascender, face->size->metrics.y_scale) - face->glyph->metrics.horiBearingY + (64 / 2)) / 64);
|
||||
|
||||
switch (face->glyph->bitmap.pixel_mode)
|
||||
switch (glyph->pixel_mode)
|
||||
{
|
||||
case FT_PIXEL_MODE_LCD:
|
||||
for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)converted.rows, bitmap_height); ++iy)
|
||||
for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)glyph->bitmap.rows, bitmap_height); ++iy)
|
||||
{
|
||||
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width / 3, bitmap_width); ++ix)
|
||||
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)glyph->bitmap.width / 3, bitmap_width); ++ix)
|
||||
{
|
||||
const unsigned char *font_pixel = converted.buffer + iy * converted.pitch + ix * 3;
|
||||
const unsigned char *font_pixel = glyph->bitmap.buffer + iy * glyph->bitmap.pitch + ix * 3;
|
||||
|
||||
if (font_pixel[0] || font_pixel[1] || font_pixel[2])
|
||||
{
|
||||
|
@ -1826,15 +1878,15 @@ void DrawText(FontObject *font_object, unsigned char *bitmap_buffer, size_t bitm
|
|||
break;
|
||||
|
||||
case FT_PIXEL_MODE_GRAY:
|
||||
for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)converted.rows, bitmap_height); ++iy)
|
||||
for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)glyph->bitmap.rows, bitmap_height); ++iy)
|
||||
{
|
||||
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, bitmap_width); ++ix)
|
||||
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)glyph->bitmap.width, bitmap_width); ++ix)
|
||||
{
|
||||
const unsigned char font_pixel = converted.buffer[iy * converted.pitch + ix];
|
||||
const unsigned char font_pixel = glyph->bitmap.buffer[iy * glyph->bitmap.pitch + ix];
|
||||
|
||||
if (font_pixel)
|
||||
{
|
||||
const double alpha = pow((double)font_pixel / (converted.num_grays - 1), 1.0 / 1.8); // Gamma-corrected
|
||||
const double alpha = pow((double)font_pixel / (glyph->bitmap.num_grays - 1), 1.0 / 1.8); // Gamma-corrected
|
||||
|
||||
unsigned char *bitmap_pixel = bitmap_buffer + (letter_y + iy) * bitmap_pitch + (letter_x + ix) * 3;
|
||||
|
||||
|
@ -1847,11 +1899,11 @@ void DrawText(FontObject *font_object, unsigned char *bitmap_buffer, size_t bitm
|
|||
break;
|
||||
|
||||
case FT_PIXEL_MODE_MONO:
|
||||
for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)converted.rows, bitmap_height); ++iy)
|
||||
for (int iy = MAX(-letter_y, 0); letter_y + iy < MIN(letter_y + (int)glyph->bitmap.rows, bitmap_height); ++iy)
|
||||
{
|
||||
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)converted.width, bitmap_width); ++ix)
|
||||
for (int ix = MAX(-letter_x, 0); letter_x + ix < MIN(letter_x + (int)glyph->bitmap.width, bitmap_width); ++ix)
|
||||
{
|
||||
if (converted.buffer[iy * converted.pitch + ix])
|
||||
if (glyph->bitmap.buffer[iy * glyph->bitmap.pitch + ix])
|
||||
{
|
||||
unsigned char *bitmap_pixel = bitmap_buffer + (letter_y + iy) * bitmap_pitch + (letter_x + ix) * 3;
|
||||
|
||||
|
@ -1864,9 +1916,8 @@ void DrawText(FontObject *font_object, unsigned char *bitmap_buffer, size_t bitm
|
|||
break;
|
||||
}
|
||||
|
||||
FT_Bitmap_Done(font_object->library, &converted);
|
||||
|
||||
pen_x += face->glyph->advance.x / 64;
|
||||
pen_x += glyph->x_advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1875,6 +1926,8 @@ void UnloadFont(FontObject *font_object)
|
|||
{
|
||||
if (font_object != NULL)
|
||||
{
|
||||
UnloadCachedGlyphs(font_object);
|
||||
|
||||
FT_Done_Face(font_object->face);
|
||||
free(font_object->data);
|
||||
FT_Done_FreeType(font_object->library);
|
||||
|
|
Loading…
Add table
Reference in a new issue