From 75ba5aca551d2b16fa75ba31e616b009ac5dde6a Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 20 Jun 2018 00:52:14 +0200 Subject: [PATCH] Improved font generation and SDF Added: data to CharInfo struct Added: LoadFontData() Added: GenImageFontAtlas() Removed: LoadFontEx() Removed: LoadTTF() [internal] Some code tweaks --- release/include/raylib.h | 27 +- release/libs/win32/mingw32/libraylib.a | Bin 1103438 -> 1116752 bytes src/raylib.h | 27 +- src/text.c | 402 +++++++++++++++---------- src/textures.c | 4 +- 5 files changed, 266 insertions(+), 194 deletions(-) diff --git a/release/include/raylib.h b/release/include/raylib.h index e0cfaa6de..49434d529 100644 --- a/release/include/raylib.h +++ b/release/include/raylib.h @@ -389,6 +389,7 @@ typedef struct CharInfo { int offsetX; // Character offset X when drawing int offsetY; // Character offset Y when drawing int advanceX; // Character advance position X + unsigned char *data; // Character pixel data (grayscale) } CharInfo; // Font type, includes texture and charSet array data @@ -955,29 +956,29 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters - //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) //------------------------------------------------------------------------------------ // Font loading/unloading functions -RLAPI Font GetDefaultFont(void); // Get the default Font -RLAPI Font LoadFont(const char *fileName); // Load Font from file into GPU memory (VRAM) -RLAPI Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load Font from file with extended parameters -RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) +RLAPI Font GetDefaultFont(void); // Get the default Font +RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) +RLAPI CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, bool sdf); // Load font data for further use +RLAPI Image GenImageFontAtlas(CharInfo *chars, int fontSize, int charsCount, int packing); // Generate image font atlas using chars info +RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) // Text drawing functions -RLAPI void DrawFPS(int posX, int posY); // Shows current FPS -RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using Font and additional parameters +RLAPI void DrawFPS(int posX, int posY); // Shows current FPS +RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) +RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters // Text misc. functions -RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string -RLAPI int GetGlyphIndex(Font font, int character); // Returns index position for a unicode character on sprite font +RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font +RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' +RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string +RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on sprite font //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) diff --git a/release/libs/win32/mingw32/libraylib.a b/release/libs/win32/mingw32/libraylib.a index 2701869a717bc927f721e61df2ce922757782435..3425c71aed98130df9eb86722b3fbe3d7b4f72b3 100644 GIT binary patch delta 69547 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%0D)S z3J?=K>gOT>)9e9f`M_BLa8?MM6#-|(z*z}!RtlVz0cYjFSqh-`4=6rG7$O)T7K<=| zcF{n@KpVLrEYPMX2n)1#48nqym?8|IUC97MHr^Q#dM%$q6otbIBO4_B>*jGL>NNgELgE7!T>3d!2RC< zR+tMj;H(BX>jIp`!v<4l0cWMaSr_0e4tAJ22RJJQ&bk0+X>dTxKM{r;4w#k=a25wA zOw0k!ih#4Wz*!&QED>;4A|; zD+A7IfU|bMSpotuy%})U3OMVE0JQuQVPJt479tF=f<}bF1}-)Q&e{NHoq@Anz*!PP zFzX`VtQI(H3!HTU&U#Z1XNEuv5D^AgK_kL20WNj`&bk9O~j?L}6NV;4Bw7D+bOgfwOwxtR-;P9ysd?oCVrY4RIEW7|aeCILiXW z0+oLv3^gDoxDB@h&iVmoSwKri5e9IP305}+F17;Bx&mjtfU`89Wt|9v4V+a2XHAi) zhq>zjT#!K$CZ+&qRlr#<;4B*{n7Rx&YYCk71kSRNhN)|Svkt&m^$aXBFzFIFYX_Y5 z1J1ILg{iB6vv$B)f8Z<&IheWtIBN==bpy^4kq4;*mwy>xCa6EM2F|(wXGti46oO<; z;H(-rYY&|D2hMU(gz2b(vv$B)Kj172B?b?0`%i?yM+v5-1J2q3XR#>5WEJ2n3pgtP z#G3Ay#wWi0l{>c(6QjcPzn+7PN~EeCQj4G>8e>amK*F01?q= zVPF6qEDMr=h&X|mp#5%eHJ}Fhq- z*}^I)>e$#A7!0Pj`f$55Doj7?!>ud~I?)qh&N9#;$J?2Gxi2$<&d|K!#~sHEIxNp3 zh`X=;!68tWQGo$;6b%EzdtL?xfy2lm|9Kf09-xTu@i8zc96?qi&Bwqn0YyZOkAY#q zQDikHd<+Z^P(+;g7#ITTPa-Sw2N`q`StJ^y=nAq(HXj4ShO5XTH6W2|$Rd;Z7#IX@ zAdAf7V_>*&8(Cx>9|Hr!{d#1f-5{SmKo&X0$G~vlA+pGIkUw4`i#+0EU`Y6cEb^6) zfuZ3uvIrMH1H*GSo9LGQa{~lb?aX;XAS-OMV811wWBRy!jaz3VtDr zB=9pZOh6GS;b&lY@E2K47s&em$RacO85k587#Zpj)~^9s#>j}|pq=~-3>VmtMUH?B zVn-Ia3UV|jvIuCi6sT*DFd4K}%77bL4YvRTLjo@&17khh_i_RZ3=RCqip&HU7z~7w zMchGqm_?99q6HWjKA?yc2rw{A5Jy(i1X3e~EHV{jjx}exs^o%F(l%JrvID3tE7>I zAp_c#2eAqkHcdhd4AXt0xMil#i{ciWo)g6_B)Aeq-)

=?6IlWw(Ec;@-u~WMH~| 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 J`aw>?egI?}s=xpM diff --git a/src/raylib.h b/src/raylib.h index e0cfaa6de..49434d529 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -389,6 +389,7 @@ typedef struct CharInfo { int offsetX; // Character offset X when drawing int offsetY; // Character offset Y when drawing int advanceX; // Character advance position X + unsigned char *data; // Character pixel data (grayscale) } CharInfo; // Font type, includes texture and charSet array data @@ -955,29 +956,29 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters - //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) //------------------------------------------------------------------------------------ // Font loading/unloading functions -RLAPI Font GetDefaultFont(void); // Get the default Font -RLAPI Font LoadFont(const char *fileName); // Load Font from file into GPU memory (VRAM) -RLAPI Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load Font from file with extended parameters -RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) +RLAPI Font GetDefaultFont(void); // Get the default Font +RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) +RLAPI CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, bool sdf); // Load font data for further use +RLAPI Image GenImageFontAtlas(CharInfo *chars, int fontSize, int charsCount, int packing); // Generate image font atlas using chars info +RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) // Text drawing functions -RLAPI void DrawFPS(int posX, int posY); // Shows current FPS -RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using Font and additional parameters +RLAPI void DrawFPS(int posX, int posY); // Shows current FPS +RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) +RLAPI void DrawTextEx(Font font, const char* text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters // Text misc. functions -RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font -RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string -RLAPI int GetGlyphIndex(Font font, int character); // Returns index position for a unicode character on sprite font +RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font +RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' +RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string +RLAPI int GetGlyphIndex(Font font, int character); // Get index position for a unicode character on sprite font //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) diff --git a/src/text.c b/src/text.c index 9755ff8b5..3c3ff7513 100644 --- a/src/text.c +++ b/src/text.c @@ -47,15 +47,13 @@ #include "utils.h" // Required for: fopen() Android mapping #if defined(SUPPORT_FILEFORMAT_TTF) - // Following libs are used on LoadTTF() - #define STBTT_STATIC // Define stb_truetype functions static to this module - #define STB_TRUETYPE_IMPLEMENTATION - #include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() -#endif + #define STB_RECT_PACK_IMPLEMENTATION + #include "external/stb_rect_pack.h" // Required for: ttf font rectangles packaging -// Rectangle packing functions (not used at the moment) -//#define STB_RECT_PACK_IMPLEMENTATION -//#include "stb_rect_pack.h" + #define STBTT_STATIC + #define STB_TRUETYPE_IMPLEMENTATION + #include "external/stb_truetype.h" // Required for: ttf font data reading +#endif //---------------------------------------------------------------------------------- // Defines and Macros @@ -89,7 +87,7 @@ static Font LoadImageFont(Image image, Color key, int firstChar); // Load a Imag static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) #endif #if defined(SUPPORT_FILEFORMAT_TTF) -static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data +//static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data #endif #if defined(SUPPORT_DEFAULT_FONT) @@ -276,68 +274,244 @@ Font LoadFont(const char *fileName) // Default hardcoded values for ttf file loading #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs - #define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont + #define DEFAULT_FIRST_CHAR 32 // Expected first char for image sprite font - Font spriteFont = { 0 }; - -#if defined(SUPPORT_FILEFORMAT_TTF) - if (IsFileExtension(fileName, ".ttf")) spriteFont = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); - else -#endif -#if defined(SUPPORT_FILEFORMAT_FNT) - if (IsFileExtension(fileName, ".fnt")) spriteFont = LoadBMFont(fileName); - else -#endif - { - Image image = LoadImage(fileName); - if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); - UnloadImage(image); - } - - if (spriteFont.texture.id == 0) - { - TraceLog(LOG_WARNING, "[%s] Font could not be loaded, using default font", fileName); - spriteFont = GetDefaultFont(); - } - else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance) - - return spriteFont; -} - -// Load Font from TTF font file with generation parameters -// NOTE: You can pass an array with desired characters, those characters should be available in the font -// if array is NULL, default char set is selected 32..126 -Font LoadFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars) -{ - Font spriteFont = { 0 }; - int totalChars = 95; // Default charset [32..126] - bool fontCharsLoaded = false; + Font font = { 0 }; #if defined(SUPPORT_FILEFORMAT_TTF) if (IsFileExtension(fileName, ".ttf")) { - if (charsCount != 0) totalChars = charsCount; - - if (fontChars == NULL) - { - fontChars = (int *)malloc(totalChars*sizeof(int)); - for (int i = 0; i < totalChars; i++) fontChars[i] = i + 32; // Default first character: SPACE[32] - fontCharsLoaded = true; - } - - spriteFont = LoadTTF(fileName, fontSize, totalChars, fontChars); - - if (fontCharsLoaded) free(fontChars); + font.baseSize = DEFAULT_TTF_FONTSIZE; + font.charsCount = DEFAULT_TTF_NUMCHARS; + font.chars = LoadFontData(fileName, font.baseSize, NULL, font.charsCount, false); + Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 0); + font.texture = LoadTextureFromImage(atlas); + UnloadImage(atlas); } + else +#endif +#if defined(SUPPORT_FILEFORMAT_FNT) + if (IsFileExtension(fileName, ".fnt")) font = LoadBMFont(fileName); + else #endif - - if (spriteFont.texture.id == 0) { - TraceLog(LOG_WARNING, "[%s] Font could not be generated, using default font", fileName); - spriteFont = GetDefaultFont(); + Image image = LoadImage(fileName); + if (image.data != NULL) font = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR); + UnloadImage(image); } - return spriteFont; + if (font.texture.id == 0) + { + TraceLog(LOG_WARNING, "[%s] Font could not be loaded, using default font", fileName); + font = GetDefaultFont(); + } + else SetTextureFilter(font.texture, FILTER_POINT); // By default we set point filter (best performance) + + return font; +} + +// Load font data for further use +// NOTE: Requires TTF font and can generate SDF data +CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int charsCount, bool sdf) +{ + // NOTE: Using some SDF generation default values, + // trades off precision with ability to handle *smaller* sizes + #define SDF_CHAR_PADDING 4 + #define SDF_ON_EDGE_VALUE 128 + #define SDF_PIXEL_DIST_SCALE 64.0f + + CharInfo *chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); + + // Load font data (including pixel data) from TTF file + // NOTE: Loaded information should be enough to generate font image atlas, + // using any packaging method + FILE *fontFile = fopen(fileName, "rb"); // Load font file + + fseek(fontFile, 0, SEEK_END); + long size = ftell(fontFile); // Get file size + fseek(fontFile, 0, SEEK_SET); // Reset file pointer + + unsigned char *fontBuffer = (unsigned char *)malloc(size); + + fread(fontBuffer, size, 1, fontFile); + fclose(fontFile); + + // Init font for data reading + stbtt_fontinfo fontInfo; + if (!stbtt_InitFont(&fontInfo, fontBuffer, 0)) TraceLog(LOG_WARNING, "Failed to init font!"); + + // Calculate font scale factor + float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, fontSize); + + // Calculate font basic metrics + // NOTE: ascent is equivalent to font baseline + int ascent, descent, lineGap; + stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); + ascent *= scaleFactor; + descent *= scaleFactor; + + // Fill fontChars in case not provided externally + // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) + int genFontChars = false; + if (fontChars == NULL) genFontChars = true; + if (genFontChars) + { + fontChars = (int *)malloc(charsCount*sizeof(int)); + for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32; + } + + // NOTE: Using simple packaging, one char after another + for (int i = 0; i < charsCount; i++) + { + int chw = 0, chh = 0; // Character width and height (on generation) + int ch = fontChars[i]; // Character value to get info for + chars[i].value = ch; + + // Render a unicode codepoint to a bitmap + // stbtt_GetCodepointBitmap() -- allocates and returns a bitmap + // stbtt_GetCodepointBitmapBox() -- how big the bitmap must be + // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide + + if (!sdf) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); + + chars[i].rec.width = (float)chw; + chars[i].rec.height = (float)chh; + chars[i].offsetY += ascent; + + // Get bounding box for character (may be 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); + + TraceLog(LOG_DEBUG, "Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1); + TraceLog(LOG_DEBUG, "Character offsetY: %i", ascent + chY1); + + stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); + chars[i].advanceX *= scaleFactor; + } + + free(fontBuffer); + if (genFontChars) free(fontChars); + + return chars; +} + +// Generate image font atlas using chars info +// NOTE: Packing method: 0-Default, 1-Skyline +Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int packing) +{ + Image atlas = { 0 }; + + int padding = 10; + + // Calculate atlas texture size based on fontSize + // NOTE: Font texture size is predicted (being as much conservative as possible) + // Predictive method consist of supposing same number of chars by line-column (sqrtf) + // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... + //float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount)); + //int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT + + // TODO: TEXTURE SIZE NOT GOOD ENOUGH! -> Calculate chars area -> guess texture size? + float requiredArea = 0; + for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].rec.width + 2*padding)*(chars[i].rec.height + 2*padding)); + float guessSize = sqrtf(requiredArea)*1.25f; + int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT + + atlas.width = textureSize; // Atlas bitmap width + atlas.height = textureSize; // Atlas bitmap height + atlas.data = (unsigned char *)calloc(1, atlas.width*atlas.height); // Create a bitmap to store characters (8 bpp) + atlas.format = UNCOMPRESSED_GRAYSCALE; + atlas.mipmaps = 1; + + if (packing == 0) // Use basic packing algorythm + { + int offsetX = padding; + int offsetY = padding; + + // NOTE: Using simple packaging, one char after another + for (int i = 0; i < charsCount; i++) + { + // Copy pixel data from fc.data to atlas + for (int y = 0; y < (int)chars[i].rec.height; y++) + { + for (int x = 0; x < (int)chars[i].rec.width; x++) + { + ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = chars[i].data[y*(int)chars[i].rec.width + x]; + } + } + + chars[i].rec.x = offsetX; + chars[i].rec.y = offsetY; + + // Move atlas position X for next character drawing + offsetX += ((int)chars[i].advanceX + 2*padding); + + if (offsetX >= (atlas.width - (int)chars[i].rec.width - padding)) + { + offsetX = padding; + offsetY += (fontSize + 2*padding); + + if (offsetY > (atlas.height - fontSize - padding)) break; + } + } + } + else if (packing == 1) // Use Skyline rect packing algorythm + { + stbrp_context *context = (stbrp_context *)malloc(sizeof(*context)); + stbrp_node *nodes = (stbrp_node *)malloc(charsCount*sizeof(*nodes)); + + stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount); + stbrp_rect *rects = (stbrp_rect *)malloc(charsCount*sizeof(stbrp_rect)); + + // Fill rectangles for packaging + for (int i = 0; i < charsCount; i++) + { + rects[i].id = i; + rects[i].w = (int)chars[i].rec.width + 2*padding; + rects[i].h = (int)chars[i].rec.height + 2*padding; + } + + // Package rectangles into atlas + stbrp_pack_rects(context, rects, charsCount); + + for (int i = 0; i < charsCount; i++) + { + chars[i].rec.x = rects[i].x + padding; + chars[i].rec.y = rects[i].y + padding; + + if (rects[i].was_packed) + { + // Copy pixel data from fc.data to atlas + for (int y = 0; y < (int)chars[i].rec.height; y++) + { + for (int x = 0; x < (int)chars[i].rec.width; x++) + { + ((unsigned char *)atlas.data)[(rects[i].y + padding + y)*atlas.width + (rects[i].x + padding + x)] = chars[i].data[y*(int)chars[i].rec.width + x]; + } + } + } + else TraceLog(LOG_WARNING, "Character could not be packed: %i", i); + } + + free(nodes); + free(context); + } + + // Convert image data from GRAYSCALE to GRAY_ALPHA + //ImageAlphaMask(&atlas, atlas); // WARNING: Not working in this case, requires manual operation + unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels + + for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2) + { + dataGrayAlpha[k] = 255; + dataGrayAlpha[k + 1] = ((unsigned char *)atlas.data)[i]; + } + + free(atlas.data); + atlas.data = dataGrayAlpha; + atlas.format = UNCOMPRESSED_GRAY_ALPHA; + + return atlas; } // Unload Font from GPU memory (VRAM) @@ -811,108 +985,4 @@ static Font LoadBMFont(const char *fileName) return font; } -#endif - -#if defined(SUPPORT_FILEFORMAT_TTF) -// Generate a sprite font from TTF file data (font size required) -// TODO: Review texture packing method and generation (use oversampling) -static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) -{ - #define MAX_TTF_SIZE 16 // Maximum ttf file size in MB - - // NOTE: Font texture size is predicted (being as much conservative as possible) - // Predictive method consist of supposing same number of chars by line-column (sqrtf) - // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... - - // Calculate next power-of-two value - float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount)); - int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT - - TraceLog(LOG_INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); - - unsigned char *ttfBuffer = (unsigned char *)malloc(MAX_TTF_SIZE*1024*1024); - unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! - stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount); - - Font font = { 0 }; - - FILE *ttfFile = fopen(fileName, "rb"); - - if (ttfFile == NULL) - { - TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); - return font; - } - - // 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 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"); - - free(ttfBuffer); - - // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA - unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels - - for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2) - { - dataGrayAlpha[k] = 0xff; - dataGrayAlpha[k + 1] = dataBitmap[i]; - } - - free(dataBitmap); - - // Sprite font generation from TTF extracted data - Image image; - image.width = textureSize; - image.height = textureSize; - image.mipmaps = 1; - image.format = UNCOMPRESSED_GRAY_ALPHA; - image.data = dataGrayAlpha; - font.texture = LoadTextureFromImage(image); // Load image into texture - UnloadImage(image); // Unloads image data (dataGrayAlpha) - - - // Fill font characters info data - font.baseSize = fontSize; - font.charsCount = charsCount; - font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo)); - - for (int i = 0; i < font.charsCount; i++) - { - font.chars[i].value = fontChars[i]; - - font.chars[i].rec.x = (int)charData[i].x0; - font.chars[i].rec.y = (int)charData[i].y0; - font.chars[i].rec.width = (int)charData[i].x1 - (int)charData[i].x0; - font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0; - - font.chars[i].offsetX = charData[i].xoff; - font.chars[i].offsetY = baseline + charData[i].yoff; - font.chars[i].advanceX = (int)charData[i].xadvance; - } - - free(charData); - - return font; -} -#endif +#endif \ No newline at end of file diff --git a/src/textures.c b/src/textures.c index eeaf7ffdf..29316a7af 100644 --- a/src/textures.c +++ b/src/textures.c @@ -828,9 +828,9 @@ void ImageFormat(Image *image, int newFormat) } break; case UNCOMPRESSED_GRAY_ALPHA: { - image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); + image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); - for (int i = 0; i < image->width*image->height*2; i += 2, k++) + for (int i = 0; i < image->width*image->height*2; i += 2, k++) { ((unsigned char *)image->data)[i] = (unsigned char)((pixels[k].x*0.299f + (float)pixels[k].y*0.587f + (float)pixels[k].z*0.114f)*255.0f); ((unsigned char *)image->data)[i + 1] = (unsigned char)(pixels[k].w*255.0f);