diff options
Diffstat (limited to 'src/text.c')
| -rw-r--r-- | src/text.c | 189 |
1 files changed, 85 insertions, 104 deletions
@@ -6,7 +6,7 @@ * * #define SUPPORT_FILEFORMAT_FNT * #define SUPPORT_FILEFORMAT_TTF -* Selected desired fileformats to be supported for loading. Some of those formats are +* Selected desired fileformats to be supported for loading. Some of those formats are * supported by default, to remove support, just comment unrequired #define in this module * * #define SUPPORT_DEFAULT_FONT @@ -17,7 +17,7 @@ * * LICENSE: zlib/libpng * -* Copyright (c) 2014-2017 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -36,12 +36,7 @@ * **********************************************************************************************/ -// Default supported features -//------------------------------------- -#define SUPPORT_DEFAULT_FONT -#define SUPPORT_FILEFORMAT_FNT -#define SUPPORT_FILEFORMAT_TTF -//------------------------------------- +#include "config.h" #include "raylib.h" @@ -66,8 +61,8 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MAX_FORMATTEXT_LENGTH 64 -#define MAX_SUBTEXT_LENGTH 64 +#define MAX_FORMATTEXT_LENGTH 256 +#define MAX_SUBTEXT_LENGTH 256 //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -90,11 +85,9 @@ static SpriteFont defaultFont; // Default font provided by raylib //---------------------------------------------------------------------------------- // 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) #if defined(SUPPORT_FILEFORMAT_FNT) -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) #endif #if defined(SUPPORT_FILEFORMAT_TTF) static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data @@ -113,7 +106,7 @@ extern void UnloadDefaultFont(void); // Load raylib default font extern void LoadDefaultFont(void) { - #define BIT_CHECK(a,b) ((a) & (1 << (b))) + #define BIT_CHECK(a,b) ((a) & (1u << (b))) // NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // http://www.utf8-chartable.de/unicode-utf8-table.pl @@ -288,40 +281,14 @@ SpriteFont LoadSpriteFont(const char *fileName) SpriteFont spriteFont = { 0 }; - // Check file extension - if (IsFileExtension(fileName, ".rres")) - { - // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA) - RRES rres = LoadResource(fileName, 0); - - // Load sprite font texture - if (rres[0].type == RRES_TYPE_FONT_IMAGE) - { - // NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps - Image image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3); - spriteFont.texture = LoadTextureFromImage(image); - UnloadImage(image); - } - - // Load sprite characters data - if (rres[1].type == RRES_TYPE_FONT_CHARDATA) - { - // NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount - spriteFont.baseSize = rres[1].param1; - spriteFont.charsCount = rres[1].param2; - spriteFont.chars = rres[1].data; - } - - // TODO: Do not free rres.data memory (chars info data!) - //UnloadResource(rres[0]); - } #if defined(SUPPORT_FILEFORMAT_TTF) - else if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); + if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadSpriteFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); + else #endif #if defined(SUPPORT_FILEFORMAT_FNT) - else if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); -#endif + if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); else +#endif { Image image = LoadImage(fileName); if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); @@ -344,21 +311,20 @@ SpriteFont LoadSpriteFont(const char *fileName) SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars) { SpriteFont spriteFont = { 0 }; + int totalChars = 95; // Default charset [32..126] #if defined(SUPPORT_FILEFORMAT_TTF) if (IsFileExtension(fileName, ".ttf")) { - if ((fontChars == NULL) || (charsCount == 0)) + if (charsCount != 0) totalChars = charsCount; + + if (fontChars == NULL) { - int totalChars = 95; // Default charset [32..126] - - int *defaultFontChars = (int *)malloc(totalChars*sizeof(int)); - - for (int i = 0; i < totalChars; i++) defaultFontChars[i] = i + 32; // Default first character: SPACE[32] - - spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars); + fontChars = (int *)malloc(totalChars*sizeof(int)); + for (int i = 0; i < totalChars; i++) fontChars[i] = i + 32; // Default first character: SPACE[32] } - else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars); + + spriteFont = LoadTTF(fileName, fontSize, totalChars, fontChars); } #endif @@ -372,13 +338,13 @@ SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, } // Unload SpriteFont from GPU memory (VRAM) -void UnloadSpriteFont(SpriteFont spriteFont) +void UnloadSpriteFont(SpriteFont font) { // NOTE: Make sure spriteFont is not default font (fallback) - if (spriteFont.texture.id != GetDefaultFont().texture.id) + if (font.texture.id != GetDefaultFont().texture.id) { - UnloadTexture(spriteFont.texture); - free(spriteFont.chars); + UnloadTexture(font.texture); + free(font.chars); TraceLog(LOG_DEBUG, "Unloaded sprite font data"); } @@ -404,7 +370,7 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color) // Draw text using SpriteFont // NOTE: chars spacing is NOT proportional to fontSize -void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float fontSize, int spacing, Color tint) +void DrawTextEx(SpriteFont font, const char *text, Vector2 position, float fontSize, int spacing, Color tint) { int length = strlen(text); int textOffsetX = 0; // Offset between characters @@ -414,7 +380,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float unsigned char letter; // Current character int index; // Index position in sprite font - scaleFactor = fontSize/spriteFont.baseSize; + scaleFactor = fontSize/font.baseSize; // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly // written in C code files (codified by default as UTF-8) @@ -424,7 +390,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float if ((unsigned char)text[i] == '\n') { // NOTE: Fixed line spacing of 1.5 lines - textOffsetY += (int)((spriteFont.baseSize + spriteFont.baseSize/2)*scaleFactor); + textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetX = 0; } else @@ -433,26 +399,29 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float { // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) letter = (unsigned char)text[i + 1]; - index = GetCharIndex(spriteFont, (int)letter); + index = GetGlyphIndex(font, (int)letter); i++; } else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK! { // Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ) letter = (unsigned char)text[i + 1]; - index = GetCharIndex(spriteFont, (int)letter + 64); + index = GetGlyphIndex(font, (int)letter + 64); i++; } - else index = GetCharIndex(spriteFont, (unsigned char)text[i]); - - DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec, - (Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor, - position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor, - spriteFont.chars[index].rec.width*scaleFactor, - spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); + else index = GetGlyphIndex(font, (unsigned char)text[i]); + + if ((unsigned char)text[i] != ' ') + { + DrawTexturePro(font.texture, font.chars[index].rec, + (Rectangle){ position.x + textOffsetX + font.chars[index].offsetX*scaleFactor, + position.y + textOffsetY + font.chars[index].offsetY*scaleFactor, + font.chars[index].rec.width*scaleFactor, + font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); + } - if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing); - else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing); + if (font.chars[index].advanceX == 0) textOffsetX += (int)(font.chars[index].rec.width*scaleFactor + spacing); + else textOffsetX += (int)(font.chars[index].advanceX*scaleFactor + spacing); } } } @@ -514,7 +483,7 @@ int MeasureText(const char *text, int fontSize) } // Measure string size for SpriteFont -Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing) +Vector2 MeasureTextEx(SpriteFont font, const char *text, float fontSize, int spacing) { int len = strlen(text); int tempLen = 0; // Used to count longer text line num chars @@ -523,8 +492,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i float textWidth = 0; float tempTextWidth = 0; // Used to count longer text line width - float textHeight = (float)spriteFont.baseSize; - float scaleFactor = fontSize/(float)spriteFont.baseSize; + float textHeight = (float)font.baseSize; + float scaleFactor = fontSize/(float)font.baseSize; for (int i = 0; i < len; i++) { @@ -532,17 +501,17 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i if (text[i] != '\n') { - int index = GetCharIndex(spriteFont, (int)text[i]); + int index = GetGlyphIndex(font, (int)text[i]); - if (spriteFont.chars[index].advanceX != 0) textWidth += spriteFont.chars[index].advanceX; - else textWidth += (spriteFont.chars[index].rec.width + spriteFont.chars[index].offsetX); + if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX; + else textWidth += (font.chars[index].rec.width + font.chars[index].offsetX); } else { if (tempTextWidth < textWidth) tempTextWidth = textWidth; lenCounter = 0; textWidth = 0; - textHeight += ((float)spriteFont.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines + textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines } if (tempLen < lenCounter) tempLen = lenCounter; @@ -557,6 +526,28 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i return vec; } +// Returns index position for a unicode character on spritefont +int GetGlyphIndex(SpriteFont font, int character) +{ +#define UNORDERED_CHARSET +#if defined(UNORDERED_CHARSET) + int index = 0; + + for (int i = 0; i < font.charsCount; i++) + { + if (font.chars[i].value == character) + { + index = i; + break; + } + } + + return index; +#else + return (character - 32); +#endif +} + // Shows current FPS on top-left corner // NOTE: Uses default font void DrawFPS(int posX, int posY) @@ -583,27 +574,6 @@ void DrawFPS(int posX, int posY) // 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.charsCount; i++) - { - if (font.chars[i].value == letter) - { - index = i; - break; - } - } - - return index; -#else - return (letter - 32); -#endif -} - // Load an Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar) { @@ -733,7 +703,7 @@ static SpriteFont LoadBMFont(const char *fileName) int fontSize = 0; int texWidth, texHeight; - char texFileName[128]; + char texFileName[129]; int charsCount = 0; int base; // Useless data @@ -872,14 +842,25 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, in // NOTE: We try reading up to 16 MB of elements of 1 byte fread(ttfBuffer, 1, MAX_TTF_SIZE*1024*1024, ttfFile); - + + // Find font baseline (vertical origin of the font) + // NOTE: This value is required because y-offset depends on it! + stbtt_fontinfo fontInfo; + int ascent, baseline; + float scale; + + stbtt_InitFont(&fontInfo, ttfBuffer, 0); + scale = stbtt_ScaleForPixelHeight(&fontInfo, fontSize); + stbtt_GetFontVMetrics(&fontInfo, &ascent, 0, 0); + baseline = (int)(ascent*scale); + if (fontChars[0] != 32) TraceLog(LOG_WARNING, "TTF spritefont loading: first character is not SPACE(32) character"); - // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... + // NOTE: Using stb_truetype crappy packing method, no guarantee the font fits the image... // TODO: Replace this function by a proper packing method and support random chars order, // we already receive a list (fontChars) with the ordered expected characters int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], charsCount, charData); - + //if (result > 0) TraceLog(LOG_INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); if (result < 0) TraceLog(LOG_WARNING, "TTF spritefont loading: Not all the characters fit in the font"); @@ -924,7 +905,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, in font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0; font.chars[i].offsetX = charData[i].xoff; - font.chars[i].offsetY = charData[i].yoff; + font.chars[i].offsetY = baseline + charData[i].yoff; font.chars[i].advanceX = (int)charData[i].xadvance; } |
