Skip to content

Commit 9de7986

Browse files
DongkunLeeDongkun Leeraysan5
authored
BM Font Extender (#3536)
* loadbmfont * bmfontextender * bm font * Modify LoadBM Font * Delete loadbmfontex.diff * REVIEWED: `LoadBMFont()` PR * Update rtext.c * Update rtext.c --------- Co-authored-by: Dongkun Lee <hope81dklee@outlook.com> Co-authored-by: Ray <raysan5@gmail.com>
1 parent e001f7e commit 9de7986

File tree

1 file changed

+67
-49
lines changed

1 file changed

+67
-49
lines changed

src/rtext.c

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,7 +2051,8 @@ static int GetLine(const char *origin, char *buffer, int maxLength)
20512051
// REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
20522052
static Font LoadBMFont(const char *fileName)
20532053
{
2054-
#define MAX_BUFFER_SIZE 256
2054+
#define MAX_BUFFER_SIZE 256
2055+
#define MAX_FONT_IMAGE_PAGES 8
20552056

20562057
Font font = { 0 };
20572058

@@ -2063,7 +2064,8 @@ static Font LoadBMFont(const char *fileName)
20632064

20642065
int imWidth = 0;
20652066
int imHeight = 0;
2066-
char imFileName[129] = { 0 };
2067+
int pageCount = 1;
2068+
char imFileName[MAX_FONT_IMAGE_PAGES][129] = { 0 };
20672069

20682070
int base = 0; // Useless data
20692071
int readBytes = 0; // Data bytes read
@@ -2082,17 +2084,26 @@ static Font LoadBMFont(const char *fileName)
20822084
// Read line data
20832085
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
20842086
searchPoint = strstr(buffer, "lineHeight");
2085-
readVars = sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight);
2087+
readVars = sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i pages=%i", &fontSize, &base, &imWidth, &imHeight, &pageCount);
20862088
fileTextPtr += (readBytes + 1);
20872089

20882090
if (readVars < 4) { UnloadFileText(fileText); return font; } // Some data not available, file malformed
2091+
2092+
if (pageCount > MAX_FONT_IMAGE_PAGES)
2093+
{
2094+
TRACELOG(LOG_WARNING, "FONT: [%s] Font defines more pages than supported: %i/%i", fileName, pageCount, MAX_FONT_IMAGE_PAGES);
2095+
pageCount = MAX_FONT_IMAGE_PAGES;
2096+
}
20892097

2090-
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
2091-
searchPoint = strstr(buffer, "file");
2092-
readVars = sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName);
2093-
fileTextPtr += (readBytes + 1);
2098+
for (int i = 0; i < pageCount; i++)
2099+
{
2100+
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
2101+
searchPoint = strstr(buffer, "file");
2102+
readVars = sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName[i]);
2103+
fileTextPtr += (readBytes + 1);
20942104

2095-
if (readVars < 1) { UnloadFileText(fileText); return font; } // No fileName read
2105+
if (readVars < 1) { UnloadFileText(fileText); return font; } // No fileName read
2106+
}
20962107

20972108
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
20982109
searchPoint = strstr(buffer, "count");
@@ -2101,50 +2112,56 @@ static Font LoadBMFont(const char *fileName)
21012112

21022113
if (readVars < 1) { UnloadFileText(fileText); return font; } // No glyphCount read
21032114

2104-
// Compose correct path using route of .fnt file (fileName) and imFileName
2105-
char *imPath = NULL;
2106-
char *lastSlash = NULL;
2115+
// Load all required images for further compose
2116+
Image *imFonts = (Image *)RL_CALLOC(pageCount, sizeof(Image)); // Font atlases, multiple images
21072117

2108-
lastSlash = strrchr(fileName, '/');
2109-
if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');
2110-
2111-
if (lastSlash != NULL)
2118+
for (int i = 0; i < pageCount; i++)
21122119
{
2113-
// NOTE: We need some extra space to avoid memory corruption on next allocations!
2114-
imPath = (char *)RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
2115-
memcpy(imPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
2116-
memcpy(imPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
2117-
}
2118-
else imPath = imFileName;
2120+
imFonts[i] = LoadImage(TextFormat("%s/%s", GetDirectoryPath(fileName), imFileName[i]));
21192121

2120-
TRACELOGD(" > Image loading path: %s", imPath);
2122+
if (imFonts[i].format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
2123+
{
2124+
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
2125+
Image imFontAlpha = {
2126+
.data = RL_CALLOC(imFonts[i].width*imFonts[i].height, 2),
2127+
.width = imFonts[i].width,
2128+
.height = imFonts[i].height,
2129+
.mipmaps = 1,
2130+
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
2131+
};
2132+
2133+
for (int p = 0, pi = 0; p < (imFonts[i].width*imFonts[i].height*2); p += 2, pi++)
2134+
{
2135+
((unsigned char *)(imFontAlpha.data))[p] = 0xff;
2136+
((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFonts[i].data)[pi];
2137+
}
2138+
2139+
UnloadImage(imFonts[i]);
2140+
imFonts[i] = imFontAlpha;
2141+
}
2142+
}
21212143

2122-
Image imFont = LoadImage(imPath);
2144+
Image fullFont = imFonts[0];
2145+
for (int i = 1; i < pageCount; i++) UnloadImage(imFonts[i]);
21232146

2124-
if (imFont.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
2147+
// If multiple atlas, then merge atlas
2148+
// NOTE: WARNING: This process could be really slow!
2149+
if (pageCount > 1)
21252150
{
2126-
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
2127-
Image imFontAlpha = {
2128-
.data = RL_CALLOC(imFont.width*imFont.height, 2),
2129-
.width = imFont.width,
2130-
.height = imFont.height,
2131-
.mipmaps = 1,
2132-
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
2133-
};
2151+
// Resize font atlas to draw additional images
2152+
ImageResizeCanvas(&fullFont, imWidth, imHeight*pageCount, 0, 0, BLACK);
21342153

2135-
for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
2154+
for (int i = 1; i < pageCount; i++)
21362155
{
2137-
((unsigned char *)(imFontAlpha.data))[p] = 0xff;
2138-
((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i];
2156+
Rectangle srcRec = { 0.0f, 0.0f, (float)imWidth, (float)imHeight };
2157+
Rectangle destRec = { 0.0f, (float)imHeight*(float)i, (float)imWidth, (float)imHeight };
2158+
ImageDraw(&fullFont, imFonts[i], srcRec, destRec, WHITE);
21392159
}
2140-
2141-
UnloadImage(imFont);
2142-
imFont = imFontAlpha;
21432160
}
2161+
2162+
RL_FREE(imFonts);
21442163

2145-
font.texture = LoadTextureFromImage(imFont);
2146-
2147-
if (lastSlash != NULL) RL_FREE(imPath);
2164+
font.texture = LoadTextureFromImage(fullFont);
21482165

21492166
// Fill font characters info data
21502167
font.baseSize = fontSize;
@@ -2153,33 +2170,33 @@ static Font LoadBMFont(const char *fileName)
21532170
font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo));
21542171
font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));
21552172

2156-
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
2173+
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX, pageID;
21572174

21582175
for (int i = 0; i < glyphCount; i++)
21592176
{
21602177
readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
2161-
readVars = sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
2162-
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
2178+
readVars = sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i page=%i",
2179+
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX, &pageID);
21632180
fileTextPtr += (readBytes + 1);
21642181

2165-
if (readVars == 8) // Make sure all char data has been properly read
2182+
if (readVars == 9) // Make sure all char data has been properly read
21662183
{
21672184
// Get character rectangle in the font atlas texture
2168-
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
2185+
font.recs[i] = (Rectangle){ (float)charX, (float)charY + (float)imHeight*pageID, (float)charWidth, (float)charHeight };
21692186

21702187
// Save data properly in sprite font
21712188
font.glyphs[i].value = charId;
21722189
font.glyphs[i].offsetX = charOffsetX;
21732190
font.glyphs[i].offsetY = charOffsetY;
21742191
font.glyphs[i].advanceX = charAdvanceX;
21752192

2176-
// Fill character image data from imFont data
2177-
font.glyphs[i].image = ImageFromImage(imFont, font.recs[i]);
2193+
// Fill character image data from full font data
2194+
font.glyphs[i].image = ImageFromImage(fullFont, font.recs[i]);
21782195
}
21792196
else TRACELOG(LOG_WARNING, "FONT: [%s] Some characters data not correctly provided", fileName);
21802197
}
21812198

2182-
UnloadImage(imFont);
2199+
UnloadImage(fullFont);
21832200
UnloadFileText(fileText);
21842201

21852202
if (font.texture.id == 0)
@@ -2192,6 +2209,7 @@ static Font LoadBMFont(const char *fileName)
21922209

21932210
return font;
21942211
}
2212+
21952213
#endif
21962214

21972215
#endif // SUPPORT_MODULE_RTEXT

0 commit comments

Comments
 (0)