Browse Source

Support unordered charset, neither fixed first char

Still requires some testing...
raysan5 8 years ago
parent
commit
6d3b11ef91
1 changed files with 42 additions and 37 deletions
  1. 42 37
      src/text.c

+ 42 - 37
src/text.c

@@ -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,
-                                                                 position.y + textOffsetY + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].y*scaleFactor,
+            int index = GetCharIndex(spriteFont, (int)text[i]);
+            
+            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);
-            else textOffsetX += (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]*scaleFactor + spacing);
+            if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (rec.width*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];
-            else textWidth += (spriteFont.charRecs[(int)text[i] - FONT_FIRST_CHAR].width + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x);
+            int index = GetCharIndex(spriteFont, (int)text[i]);
+            
+            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 ((firstChar != FONT_FIRST_CHAR) || (unorderedChars) || (font.texture.id == 0))
+    if (font.texture.id == 0)
     {
     {
         UnloadSpriteFont(font);
         UnloadSpriteFont(font);
         font = GetDefaultFont();
         font = GetDefaultFont();