Skip to content

Commit

Permalink
REVIEWED: WARNING: LoadFontData() avoid fallback glyphs
Browse files Browse the repository at this point in the history
This is a redesign on font loading, missing glyphs are skipped instead of falling back to font `.notdef` special character (usually "tofu" character).
It is changed because not all fonts support a fallback glyph.
One improvement could be allowing users to define a custom fallback character, for example `?` glyph.
  • Loading branch information
raysan5 committed Dec 4, 2023
1 parent a016b4d commit 731b210
Showing 1 changed file with 52 additions and 42 deletions.
94 changes: 52 additions & 42 deletions src/rtext.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,57 +625,67 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide

if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, FONT_SDF_CHAR_PADDING, FONT_SDF_ON_EDGE_VALUE, FONT_SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else chars[i].image.data = NULL;
// Check if a glyph is available in the font
// WARNING: if (index == 0), glyph not found, it could fallback to default .notdef glyph (if defined in font)
int index = stbtt_FindGlyphIndex(&fontInfo, ch);

if (chars[i].image.data != NULL) // Glyph data has been found in the font
if (index > 0)
{
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
switch (type)
{
case FONT_DEFAULT:
case FONT_BITMAP: chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); break;
case FONT_SDF: if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, FONT_SDF_CHAR_PADDING, FONT_SDF_ON_EDGE_VALUE, FONT_SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); break;
default: break;
}

// Load characters images
chars[i].image.width = chw;
chars[i].image.height = chh;
chars[i].image.mipmaps = 1;
chars[i].image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
if (chars[i].image.data != NULL) // Glyph data has been found in the font
{
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);

chars[i].offsetY += (int)((float)ascent*scaleFactor);
}
// Load characters images
chars[i].image.width = chw;
chars[i].image.height = chh;
chars[i].image.mipmaps = 1;
chars[i].image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;

// NOTE: We create an empty image for space character, it could be further required for atlas packing
if (ch == 32)
{
Image imSpace = {
.data = RL_CALLOC(chars[i].advanceX*fontSize, 2),
.width = chars[i].advanceX,
.height = fontSize,
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE
};

chars[i].image = imSpace;
}
chars[i].offsetY += (int)((float)ascent*scaleFactor);
}

if (type == FONT_BITMAP)
{
// Aliased bitmap (black & white) font generation, avoiding anti-aliasing
// NOTE: For optimum results, bitmap font should be generated at base pixel size
for (int p = 0; p < chw*chh; p++)
// NOTE: We create an empty image for space character,
// it could be further required for atlas packing
if (ch == 32)
{
if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
else ((unsigned char *)chars[i].image.data)[p] = 255;
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);

Image imSpace = {
.data = RL_CALLOC(chars[i].advanceX*fontSize, 2),
.width = chars[i].advanceX,
.height = fontSize,
.mipmaps = 1,
.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE
};

chars[i].image = imSpace;
}
}

// Get bounding box for character (maybe offset to account for chars that dip above or below the line)
/*
int chX1, chY1, chX2, chY2;
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);

TRACELOGD("FONT: Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1);
TRACELOGD("FONT: Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1);
*/
if (type == FONT_BITMAP)
{
// Aliased bitmap (black & white) font generation, avoiding anti-aliasing
// NOTE: For optimum results, bitmap font should be generated at base pixel size
for (int p = 0; p < chw*chh; p++)
{
if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
else ((unsigned char *)chars[i].image.data)[p] = 255;
}
}
}
else
{
// TODO: Use some fallback glyph for codepoints not found in the font
}
}
}
else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data");
Expand Down

0 comments on commit 731b210

Please sign in to comment.