Support unordered charset, neither fixed first char

Still requires some testing...
This commit is contained in:
raysan5 2016-11-01 00:58:21 +01:00
parent 3393fda384
commit 6d3b11ef91
1 changed files with 42 additions and 37 deletions

View File

@ -44,7 +44,6 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define FONT_FIRST_CHAR 32 // NOTE: Expected first char for a sprite font
#define MAX_FORMATTEXT_LENGTH 64 #define MAX_FORMATTEXT_LENGTH 64
#define MAX_SUBTEXT_LENGTH 64 #define MAX_SUBTEXT_LENGTH 64
@ -69,6 +68,8 @@ static SpriteFont defaultFont; // Default font provided by raylib
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static int GetCharIndex(SpriteFont font, int letter);
static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style)
static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font)
static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
@ -197,7 +198,7 @@ extern void LoadDefaultFont(void)
for (int i = 0; i < defaultFont.numChars; i++) for (int i = 0; i < defaultFont.numChars; i++)
{ {
defaultFont.charValues[i] = FONT_FIRST_CHAR + i; // First char is 32 defaultFont.charValues[i] = 32 + i; // First char is 32
defaultFont.charRecs[i].x = currentPosX; defaultFont.charRecs[i].x = currentPosX;
defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor);
@ -248,6 +249,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
// Default hardcoded values for ttf file loading // Default hardcoded values for ttf file loading
#define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space)
#define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs
#define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont
SpriteFont spriteFont = { 0 }; SpriteFont spriteFont = { 0 };
@ -258,7 +260,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
else else
{ {
Image image = LoadImage(fileName); Image image = LoadImage(fileName);
if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, FONT_FIRST_CHAR); if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR);
UnloadImage(image); UnloadImage(image);
} }
@ -267,7 +269,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName);
spriteFont = GetDefaultFont(); spriteFont = GetDefaultFont();
} }
else SetTextureFilter(spriteFont.texture, FILTER_BILINEAR); else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance)
return spriteFont; return spriteFont;
} }
@ -356,22 +358,18 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
// TODO: Right now we are supposing characters that follow a continous order and start at FONT_FIRST_CHAR,
// this sytem can be improved to support any characters order and init value...
// An intermediate table could be created to link char values with predefined char position index in chars rectangle array
if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK!
{ {
// Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿)
letter = (unsigned char)text[i + 1]; letter = (unsigned char)text[i + 1];
rec = spriteFont.charRecs[letter - FONT_FIRST_CHAR]; rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)letter)];
i++; i++;
} }
else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK!
{ {
// Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ)
letter = (unsigned char)text[i + 1]; letter = (unsigned char)text[i + 1];
rec = spriteFont.charRecs[letter - FONT_FIRST_CHAR + 64]; rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)letter + 64)];
i++; i++;
} }
else else
@ -383,17 +381,19 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
textOffsetX = 0; textOffsetX = 0;
rec.x = -1; rec.x = -1;
} }
else rec = spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR]; else rec = spriteFont.charRecs[GetCharIndex(spriteFont, (int)text[i])];
} }
if (rec.x >= 0) if (rec.x >= 0)
{ {
DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x*scaleFactor, int index = GetCharIndex(spriteFont, (int)text[i]);
position.y + textOffsetY + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].y*scaleFactor,
DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor,
position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor,
rec.width*scaleFactor, rec.height*scaleFactor} , (Vector2){ 0, 0 }, 0.0f, tint); rec.width*scaleFactor, rec.height*scaleFactor} , (Vector2){ 0, 0 }, 0.0f, tint);
if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] == 0) textOffsetX += (rec.width*scaleFactor + spacing); if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (rec.width*scaleFactor + spacing);
else textOffsetX += (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]*scaleFactor + spacing); else textOffsetX += (spriteFont.charAdvanceX[index]*scaleFactor + spacing);
} }
} }
} }
@ -473,8 +473,10 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int
if (text[i] != '\n') if (text[i] != '\n')
{ {
if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] != 0) textWidth += spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]; int index = GetCharIndex(spriteFont, (int)text[i]);
else textWidth += (spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR].width + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x);
if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index];
else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x);
} }
else else
{ {
@ -531,6 +533,27 @@ void DrawFPS(int posX, int posY)
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static int GetCharIndex(SpriteFont font, int letter)
{
//#define UNORDERED_CHARSET
#if defined(UNORDERED_CHARSET)
int index = 0;
for (int i = 0; i < font.numChars; i++)
{
if (font.charValues[i] == letter)
{
index = i;
break;
}
}
return index;
#else
return (letter - 32);
#endif
}
// Load an Image font file (XNA style) // Load an Image font file (XNA style)
static SpriteFont LoadImageFont(Image image, Color key, int firstChar) static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
{ {
@ -857,6 +880,7 @@ static SpriteFont LoadBMFont(const char *fileName)
if (imFont.format == UNCOMPRESSED_GRAYSCALE) ImageAlphaMask(&imFont, imFont); if (imFont.format == UNCOMPRESSED_GRAYSCALE) ImageAlphaMask(&imFont, imFont);
font.texture = LoadTextureFromImage(imFont); font.texture = LoadTextureFromImage(imFont);
font.size = fontSize; font.size = fontSize;
font.numChars = numChars; font.numChars = numChars;
font.charValues = (int *)malloc(numChars*sizeof(int)); font.charValues = (int *)malloc(numChars*sizeof(int));
@ -870,30 +894,12 @@ static SpriteFont LoadBMFont(const char *fileName)
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
bool unorderedChars = false;
int firstChar = 32;
for (int i = 0; i < numChars; i++) for (int i = 0; i < numChars; i++)
{ {
fgets(buffer, MAX_BUFFER_SIZE, fntFile); fgets(buffer, MAX_BUFFER_SIZE, fntFile);
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
if ((i == 0) && (charId != FONT_FIRST_CHAR))
{
TraceLog(WARNING, "BMFont not supported: expected SPACE(32) as first character, falling back to default font");
firstChar = charId;
break;
}
else if ((i < (126 - FONT_FIRST_CHAR)) && (i != (charId - FONT_FIRST_CHAR)))
{
// NOTE: We expect the first 95 chars (32..126) to be ordered for quick drawing access,
// characters above are stored and we look for them (search algorythm) when drawing
TraceLog(WARNING, "BMFont not supported: unordered chars data, falling back to default font");
unorderedChars = true;
break;
}
// Save data properly in sprite font // Save data properly in sprite font
font.charValues[i] = charId; font.charValues[i] = charId;
font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight }; font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight };
@ -903,8 +909,7 @@ static SpriteFont LoadBMFont(const char *fileName)
fclose(fntFile); fclose(fntFile);
// NOTE: Font data could be not ordered by charId: 32,33,34,35... raylib does not support unordered BMFonts if (font.texture.id == 0)
if ((firstChar != FONT_FIRST_CHAR) || (unorderedChars) || (font.texture.id == 0))
{ {
UnloadSpriteFont(font); UnloadSpriteFont(font);
font = GetDefaultFont(); font = GetDefaultFont();