Implement bold and italic font rendering in libretro builds

This commit is contained in:
刘皓 2025-08-02 18:04:32 -04:00
parent b16068e661
commit cf34d9d464
No known key found for this signature in database
GPG key ID: 7901753DB465B711

View file

@ -108,9 +108,17 @@ return __VA_ARGS__; \
#define OUTLINE_SIZE 1 #define OUTLINE_SIZE 1
#ifdef MKXPZ_RETRO #ifdef MKXPZ_RETRO
#define DIFF_TILE_SIZE (size_t)64 # define DIFF_TILE_SIZE (size_t)64
#define FLOOR_DIV_DIFF_TILE_SIZE(x) ((size_t)(x) / DIFF_TILE_SIZE) # define FLOOR_DIV_DIFF_TILE_SIZE(x) ((size_t)(x) / DIFF_TILE_SIZE)
#define CEIL_DIV_DIFF_TILE_SIZE(x) ((((size_t)(x) - 1) / DIFF_TILE_SIZE) + 1) # define CEIL_DIV_DIFF_TILE_SIZE(x) ((((size_t)(x) - 1) / DIFF_TILE_SIZE) + 1)
// This formula is from SDL_ttf (licensed MIT); we may want to adjust it for better accuracy with RPG Maker
# define GET_BOLD_WIDTH(ft_face) ((ft_face)->size->metrics.y_ppem / 10)
// This formula is from SDL_ttf (licensed MIT); we may want to adjust it for better accuracy with RPG Maker
static const FT_Matrix ITALIC_TRANSFORM = (FT_Matrix){1 << 16, 0x0366a, 0, 1 << 16};
# define GET_ITALIC_WIDTH(ft_face) (((uint32_t)ITALIC_TRANSFORM.xy * (uint32_t)(((int32_t)(ft_face)->ascender - (int32_t)(ft_face)->descender)) / 64) >> 16)
static uint64_t next_id = 1; static uint64_t next_id = 1;
#endif // MKXPZ_RETRO #endif // MKXPZ_RETRO
@ -2752,7 +2760,8 @@ IntRect Bitmap::textRect(Exception &exception, const char *str, bool solid)
FT_Face font; FT_Face font;
GUARD_V(IntRect(), font = p->font->getSdlFont(exception)); GUARD_V(IntRect(), font = p->font->getSdlFont(exception));
// TODO: handle kerning const unsigned short bold_width = p->font->getBold() ? GET_BOLD_WIDTH(font) : 0;
const unsigned short italic_width = p->font->getItalic() ? GET_ITALIC_WIDTH(font) : 0;
int bitmap_left = 0; int bitmap_left = 0;
int bitmap_right = 0; int bitmap_right = 0;
int bitmap_top = -font->size->metrics.ascender / 64; int bitmap_top = -font->size->metrics.ascender / 64;
@ -2787,11 +2796,11 @@ IntRect Bitmap::textRect(Exception &exception, const char *str, bool solid)
continue; continue;
int glyph_left = glyph_x + font->glyph->bitmap_left; int glyph_left = glyph_x + font->glyph->bitmap_left;
int glyph_right = glyph_left + font->glyph->bitmap.width; int glyph_right = glyph_left + font->glyph->bitmap.width + bold_width + italic_width;
int glyph_top = glyph_y - font->glyph->bitmap_top; int glyph_top = glyph_y - font->glyph->bitmap_top;
int glyph_bottom = glyph_top + font->glyph->bitmap.rows; int glyph_bottom = glyph_top + font->glyph->bitmap.rows;
glyph_x += font->glyph->advance.x / 64; glyph_x += font->glyph->advance.x / 64 + bold_width;
glyph_y += font->glyph->advance.y / 64; glyph_y += font->glyph->advance.y / 64;
bitmap_left = std::min(bitmap_left, std::min(glyph_left, glyph_x)); bitmap_left = std::min(bitmap_left, std::min(glyph_left, glyph_x));
@ -2807,8 +2816,10 @@ IntRect Bitmap::textRect(Exception &exception, const char *str, bool solid)
SDL_Surface *Bitmap::drawTextInner(Exception &exception, FT_Face font, const char *str, SDL_Color &c, size_t outline) SDL_Surface *Bitmap::drawTextInner(Exception &exception, FT_Face font, const char *str, SDL_Color &c, size_t outline)
{ {
// TODO: handle kerning
const bool solid = p->font->isSolid(); const bool solid = p->font->isSolid();
const unsigned short bold_width = p->font->getBold() ? GET_BOLD_WIDTH(font) : 0;
const bool italic = p->font->getItalic();
const bool needs_transform = italic || outline > 0;
IntRect bitmapRect; IntRect bitmapRect;
GUARD_V(nullptr, bitmapRect = textRect(exception, str, solid)); GUARD_V(nullptr, bitmapRect = textRect(exception, str, solid));
bitmapRect.x -= outline; bitmapRect.x -= outline;
@ -2850,12 +2861,15 @@ SDL_Surface *Bitmap::drawTextInner(Exception &exception, FT_Face font, const cha
else else
break; break;
if (outline > 0) if (needs_transform)
{ {
if (FT_Load_Char(font, charcode, solid ? (FT_LOAD_DEFAULT | FT_LOAD_TARGET_MONO) : (FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL))) if (FT_Load_Char(font, charcode, solid ? (FT_LOAD_DEFAULT | FT_LOAD_TARGET_MONO) : (FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL)))
continue; continue;
if (italic)
FT_Outline_Transform(&font->glyph->outline, &ITALIC_TRANSFORM);
if (FT_Get_Glyph(font->glyph, &glyph)) if (FT_Get_Glyph(font->glyph, &glyph))
continue; continue;
if (outline > 0)
{ {
FT_Stroker stroker; FT_Stroker stroker;
if (FT_Stroker_New(shState->fontState().getLibrary(), &stroker)) if (FT_Stroker_New(shState->fontState().getLibrary(), &stroker))
@ -2884,32 +2898,43 @@ SDL_Surface *Bitmap::drawTextInner(Exception &exception, FT_Face font, const cha
continue; continue;
} }
int glyph_left = glyph_x + (outline > 0 ? ((FT_BitmapGlyph)glyph)->left : font->glyph->bitmap_left); int glyph_left = glyph_x + (needs_transform ? ((FT_BitmapGlyph)glyph)->left : font->glyph->bitmap_left);
int glyph_top = glyph_y - (outline > 0 ? ((FT_BitmapGlyph)glyph)->top : font->glyph->bitmap_top); int glyph_top = glyph_y - (needs_transform ? ((FT_BitmapGlyph)glyph)->top : font->glyph->bitmap_top);
FT_Bitmap *bitmap = outline > 0 ? &((FT_BitmapGlyph)glyph)->bitmap : &font->glyph->bitmap; FT_Bitmap *bitmap = needs_transform ? &((FT_BitmapGlyph)glyph)->bitmap : &font->glyph->bitmap;
unsigned int glyph_width = bitmap->width; unsigned int glyph_width = bitmap->width;
unsigned int glyph_height = bitmap->rows; unsigned int glyph_height = bitmap->rows;
if (solid) if (solid)
for (unsigned int y = 0; y < glyph_height; ++y) for (unsigned int y = 0; y < glyph_height; ++y)
{ {
for (unsigned int x = 0; x < glyph_width; ++x) for (unsigned int x = 0; x < glyph_width + bold_width; ++x)
{ {
if (((uint8_t *)bitmap->buffer)[bitmap->pitch * y + x / 8] & (1 << (7 - (x % 8)))) for (unsigned int i = x < glyph_width ? 0 : x - glyph_width + 1; i <= bold_width && i <= x; ++i)
{
if (((uint8_t *)bitmap->buffer)[bitmap->pitch * y + (x - i) / 8] & (1 << (7 - ((x - i) % 8))))
{ {
((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x)] = c.r; ((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x)] = c.r;
((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x) + 1] = c.g; ((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x) + 1] = c.g;
((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x) + 2] = c.b; ((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x) + 2] = c.b;
((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x) + 3] = 255; ((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x) + 3] = -1;
break;
}
} }
} }
} }
else else
for (unsigned int y = 0; y < glyph_height; ++y) for (unsigned int y = 0; y < glyph_height; ++y)
{ {
for (unsigned int x = 0; x < glyph_width; ++x) for (unsigned int x = 0; x < glyph_width + bold_width; ++x)
{ {
uint8_t alpha = ((uint8_t *)bitmap->buffer)[bitmap->pitch * y + x]; uint8_t alpha = 0;
for (unsigned int i = x < glyph_width ? 0 : x - glyph_width + 1; i <= bold_width && i <= x; ++i)
{
uint8_t new_alpha = alpha + ((uint8_t *)bitmap->buffer)[bitmap->pitch * y + x - i];
if (new_alpha < alpha)
new_alpha = -1;
alpha = new_alpha;
}
if (alpha > 0) if (alpha > 0)
{ {
((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x)] = c.r; ((uint8_t *)txtSurf->pixels)[4 * (bitmapRect.w * (glyph_top + y) + glyph_left + x)] = c.r;
@ -2920,10 +2945,10 @@ SDL_Surface *Bitmap::drawTextInner(Exception &exception, FT_Face font, const cha
} }
} }
glyph_x += font->glyph->advance.x / 64; glyph_x += font->glyph->advance.x / 64 + bold_width;
glyph_y += font->glyph->advance.y / 64; glyph_y += font->glyph->advance.y / 64;
if (outline > 0) if (needs_transform)
FT_Done_Glyph(glyph); FT_Done_Glyph(glyph);
} }
} }