minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

rtext.c (102673B)


      1 /**********************************************************************************************
      2 *
      3 *   rtext - Basic functions to load fonts and draw text
      4 *
      5 *   CONFIGURATION:
      6 *       #define SUPPORT_MODULE_RTEXT
      7 *           rtext module is included in the build
      8 *
      9 *       #define SUPPORT_DEFAULT_FONT
     10 *           Load default raylib font on initialization to be used by DrawText() and MeasureText().
     11 *           If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
     12 *
     13 *       #define SUPPORT_FILEFORMAT_FNT
     14 *       #define SUPPORT_FILEFORMAT_TTF
     15 *       #define SUPPORT_FILEFORMAT_BDF
     16 *           Selected desired fileformats to be supported for loading. Some of those formats are
     17 *           supported by default, to remove support, just comment unrequired #define in this module
     18 *
     19 *       #define SUPPORT_FONT_ATLAS_WHITE_REC
     20 *           On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
     21 *           at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
     22 *           drawing text and shapes with a single draw call [SetShapesTexture()].
     23 *
     24 *       #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
     25 *           TextSplit() function static buffer max size
     26 *
     27 *       #define MAX_TEXTSPLIT_COUNT
     28 *           TextSplit() function static substrings pointers array (pointing to static buffer)
     29 *
     30 *   DEPENDENCIES:
     31 *       stb_truetype  - Load TTF file and rasterize characters data
     32 *       stb_rect_pack - Rectangles packing algorithms, required for font atlas generation
     33 *
     34 *
     35 *   LICENSE: zlib/libpng
     36 *
     37 *   Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
     38 *
     39 *   This software is provided "as-is", without any express or implied warranty. In no event
     40 *   will the authors be held liable for any damages arising from the use of this software.
     41 *
     42 *   Permission is granted to anyone to use this software for any purpose, including commercial
     43 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
     44 *
     45 *     1. The origin of this software must not be misrepresented; you must not claim that you
     46 *     wrote the original software. If you use this software in a product, an acknowledgment
     47 *     in the product documentation would be appreciated but is not required.
     48 *
     49 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
     50 *     as being the original software.
     51 *
     52 *     3. This notice may not be removed or altered from any source distribution.
     53 *
     54 **********************************************************************************************/
     55 
     56 #include "raylib.h"         // Declares module functions
     57 
     58 // Check if config flags have been externally provided on compilation line
     59 #if !defined(EXTERNAL_CONFIG_FLAGS)
     60     #include "config.h"     // Defines module configuration flags
     61 #endif
     62 
     63 #if defined(SUPPORT_MODULE_RTEXT)
     64 
     65 #include "utils.h"          // Required for: LoadFile*()
     66 #include "rlgl.h"           // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro()
     67 
     68 #include <stdlib.h>         // Required for: malloc(), free()
     69 #include <stdio.h>          // Required for: vsprintf()
     70 #include <string.h>         // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
     71 #include <stdarg.h>         // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
     72 #include <ctype.h>          // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
     73 
     74 #if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF)
     75     #if defined(__GNUC__) // GCC and Clang
     76         #pragma GCC diagnostic push
     77         #pragma GCC diagnostic ignored "-Wunused-function"
     78     #endif
     79 
     80     #define STB_RECT_PACK_IMPLEMENTATION
     81     #include "external/stb_rect_pack.h"     // Required for: ttf/bdf font rectangles packaging
     82 
     83     #include <math.h>   // Required for: ttf/bdf font rectangles packaging
     84 
     85     #if defined(__GNUC__) // GCC and Clang
     86         #pragma GCC diagnostic pop
     87     #endif
     88 #endif
     89 
     90 #if defined(SUPPORT_FILEFORMAT_TTF)
     91     #if defined(__GNUC__) // GCC and Clang
     92         #pragma GCC diagnostic push
     93         #pragma GCC diagnostic ignored "-Wunused-function"
     94     #endif
     95 
     96     #define STBTT_STATIC
     97     #define STB_TRUETYPE_IMPLEMENTATION
     98     #include "external/stb_truetype.h"      // Required for: ttf font data reading
     99 
    100     #if defined(__GNUC__) // GCC and Clang
    101         #pragma GCC diagnostic pop
    102     #endif
    103 #endif
    104 
    105 //----------------------------------------------------------------------------------
    106 // Defines and Macros
    107 //----------------------------------------------------------------------------------
    108 #ifndef MAX_TEXT_BUFFER_LENGTH
    109     #define MAX_TEXT_BUFFER_LENGTH              1024        // Size of internal static buffers used on some functions:
    110                                                             // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
    111 #endif
    112 #ifndef MAX_TEXT_UNICODE_CHARS
    113     #define MAX_TEXT_UNICODE_CHARS               512        // Maximum number of unicode codepoints: GetCodepoints()
    114 #endif
    115 #ifndef MAX_TEXTSPLIT_COUNT
    116     #define MAX_TEXTSPLIT_COUNT                  128        // Maximum number of substrings to split: TextSplit()
    117 #endif
    118 
    119 //----------------------------------------------------------------------------------
    120 // Types and Structures Definition
    121 //----------------------------------------------------------------------------------
    122 //...
    123 
    124 //----------------------------------------------------------------------------------
    125 // Global variables
    126 //----------------------------------------------------------------------------------
    127 extern bool isGpuReady;
    128 #if defined(SUPPORT_DEFAULT_FONT)
    129 // Default font provided by raylib
    130 // NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
    131 static Font defaultFont = { 0 };
    132 #endif
    133 
    134 //----------------------------------------------------------------------------------
    135 // Other Modules Functions Declaration (required by text)
    136 //----------------------------------------------------------------------------------
    137 //...
    138 
    139 //----------------------------------------------------------------------------------
    140 // Module specific Functions Declaration
    141 //----------------------------------------------------------------------------------
    142 #if defined(SUPPORT_FILEFORMAT_FNT)
    143 static Font LoadBMFont(const char *fileName);   // Load a BMFont file (AngelCode font file)
    144 #endif
    145 #if defined(SUPPORT_FILEFORMAT_BDF)
    146 static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize);
    147 #endif
    148 static int textLineSpacing = 2;                 // Text vertical line spacing in pixels (between lines)
    149 
    150 #if defined(SUPPORT_DEFAULT_FONT)
    151 extern void LoadFontDefault(void);
    152 extern void UnloadFontDefault(void);
    153 #endif
    154 
    155 //----------------------------------------------------------------------------------
    156 // Module Functions Definition
    157 //----------------------------------------------------------------------------------
    158 #if defined(SUPPORT_DEFAULT_FONT)
    159 // Load raylib default font
    160 extern void LoadFontDefault(void)
    161 {
    162     #define BIT_CHECK(a,b) ((a) & (1u << (b)))
    163 
    164     // NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
    165     // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
    166 
    167     defaultFont.glyphCount = 224;   // Number of chars included in our default font
    168     defaultFont.glyphPadding = 0;   // Characters padding
    169 
    170     // Default font is directly defined here (data generated from a sprite font image)
    171     // This way, we reconstruct Font without creating large global variables
    172     // This data is automatically allocated to Stack and automatically deallocated at the end of this function
    173     unsigned int defaultFontData[512] = {
    174         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f,
    175         0x4a2bf2a0, 0x0852091e, 0x41224000, 0x10041450, 0x2e292020, 0x08220812, 0x41222000, 0x10041450, 0x10f92020, 0x3efa084c, 0x7d22103c, 0x107df7de,
    176         0xe8a12020, 0x08220832, 0x05220800, 0x10450410, 0xa4a3f000, 0x08520832, 0x05220400, 0x10450410, 0xe2f92020, 0x0002085e, 0x7d3e0281, 0x107df41f,
    177         0x00200000, 0x8001b000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    178         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xc0000fbe, 0xfbf7e00f, 0x5fbf7e7d, 0x0050bee8, 0x440808a2, 0x0a142fe8, 0x50810285, 0x0050a048,
    179         0x49e428a2, 0x0a142828, 0x40810284, 0x0048a048, 0x10020fbe, 0x09f7ebaf, 0xd89f3e84, 0x0047a04f, 0x09e48822, 0x0a142aa1, 0x50810284, 0x0048a048,
    180         0x04082822, 0x0a142fa0, 0x50810285, 0x0050a248, 0x00008fbe, 0xfbf42021, 0x5f817e7d, 0x07d09ce8, 0x00008000, 0x00000fe0, 0x00000000, 0x00000000,
    181         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000c0180,
    182         0xdfbf4282, 0x0bfbf7ef, 0x42850505, 0x004804bf, 0x50a142c6, 0x08401428, 0x42852505, 0x00a808a0, 0x50a146aa, 0x08401428, 0x42852505, 0x00081090,
    183         0x5fa14a92, 0x0843f7e8, 0x7e792505, 0x00082088, 0x40a15282, 0x08420128, 0x40852489, 0x00084084, 0x40a16282, 0x0842022a, 0x40852451, 0x00088082,
    184         0xc0bf4282, 0xf843f42f, 0x7e85fc21, 0x3e0900bf, 0x00000000, 0x00000004, 0x00000000, 0x000c0180, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    185         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000402, 0x41482000, 0x00000000, 0x00000800,
    186         0x04000404, 0x4100203c, 0x00000000, 0x00000800, 0xf7df7df0, 0x514bef85, 0xbefbefbe, 0x04513bef, 0x14414500, 0x494a2885, 0xa28a28aa, 0x04510820,
    187         0xf44145f0, 0x474a289d, 0xa28a28aa, 0x04510be0, 0x14414510, 0x494a2884, 0xa28a28aa, 0x02910a00, 0xf7df7df0, 0xd14a2f85, 0xbefbe8aa, 0x011f7be0,
    188         0x00000000, 0x00400804, 0x20080000, 0x00000000, 0x00000000, 0x00600f84, 0x20080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    189         0xac000000, 0x00000f01, 0x00000000, 0x00000000, 0x24000000, 0x00000f01, 0x00000000, 0x06000000, 0x24000000, 0x00000f01, 0x00000000, 0x09108000,
    190         0x24fa28a2, 0x00000f01, 0x00000000, 0x013e0000, 0x2242252a, 0x00000f52, 0x00000000, 0x038a8000, 0x2422222a, 0x00000f29, 0x00000000, 0x010a8000,
    191         0x2412252a, 0x00000f01, 0x00000000, 0x010a8000, 0x24fbe8be, 0x00000f01, 0x00000000, 0x0ebe8000, 0xac020000, 0x00000f01, 0x00000000, 0x00048000,
    192         0x0003e000, 0x00000f00, 0x00000000, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000038, 0x8443b80e, 0x00203a03,
    193         0x02bea080, 0xf0000020, 0xc452208a, 0x04202b02, 0xf8029122, 0x07f0003b, 0xe44b388e, 0x02203a02, 0x081e8a1c, 0x0411e92a, 0xf4420be0, 0x01248202,
    194         0xe8140414, 0x05d104ba, 0xe7c3b880, 0x00893a0a, 0x283c0e1c, 0x04500902, 0xc4400080, 0x00448002, 0xe8208422, 0x04500002, 0x80400000, 0x05200002,
    195         0x083e8e00, 0x04100002, 0x804003e0, 0x07000042, 0xf8008400, 0x07f00003, 0x80400000, 0x04000022, 0x00000000, 0x00000000, 0x80400000, 0x04000002,
    196         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00800702, 0x1848a0c2, 0x84010000, 0x02920921, 0x01042642, 0x00005121, 0x42023f7f, 0x00291002,
    197         0xefc01422, 0x7efdfbf7, 0xefdfa109, 0x03bbbbf7, 0x28440f12, 0x42850a14, 0x20408109, 0x01111010, 0x28440408, 0x42850a14, 0x2040817f, 0x01111010,
    198         0xefc78204, 0x7efdfbf7, 0xe7cf8109, 0x011111f3, 0x2850a932, 0x42850a14, 0x2040a109, 0x01111010, 0x2850b840, 0x42850a14, 0xefdfbf79, 0x03bbbbf7,
    199         0x001fa020, 0x00000000, 0x00001000, 0x00000000, 0x00002070, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    200         0x08022800, 0x00012283, 0x02430802, 0x01010001, 0x8404147c, 0x20000144, 0x80048404, 0x00823f08, 0xdfbf4284, 0x7e03f7ef, 0x142850a1, 0x0000210a,
    201         0x50a14684, 0x528a1428, 0x142850a1, 0x03efa17a, 0x50a14a9e, 0x52521428, 0x142850a1, 0x02081f4a, 0x50a15284, 0x4a221428, 0xf42850a1, 0x03efa14b,
    202         0x50a16284, 0x4a521428, 0x042850a1, 0x0228a17a, 0xdfbf427c, 0x7e8bf7ef, 0xf7efdfbf, 0x03efbd0b, 0x00000000, 0x04000000, 0x00000000, 0x00000008,
    203         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200508, 0x00840400, 0x11458122, 0x00014210,
    204         0x00514294, 0x51420800, 0x20a22a94, 0x0050a508, 0x00200000, 0x00000000, 0x00050000, 0x08000000, 0xfefbefbe, 0xfbefbefb, 0xfbeb9114, 0x00fbefbe,
    205         0x20820820, 0x8a28a20a, 0x8a289114, 0x3e8a28a2, 0xfefbefbe, 0xfbefbe0b, 0x8a289114, 0x008a28a2, 0x228a28a2, 0x08208208, 0x8a289114, 0x088a28a2,
    206         0xfefbefbe, 0xfbefbefb, 0xfa2f9114, 0x00fbefbe, 0x00000000, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0x00000000, 0x00000000,
    207         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00210100, 0x00000004, 0x00000000, 0x00000000, 0x14508200, 0x00001402, 0x00000000, 0x00000000,
    208         0x00000010, 0x00000020, 0x00000000, 0x00000000, 0xa28a28be, 0x00002228, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000,
    209         0xa28a28aa, 0x000022a8, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000, 0xbefbefbe, 0x00003e2f, 0x00000000, 0x00000000,
    210         0x00000004, 0x00002028, 0x00000000, 0x00000000, 0x80000000, 0x00003e0f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    211         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    212         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    213         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    214         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    215         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
    216         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
    217 
    218     int charsHeight = 10;
    219     int charsDivisor = 1;    // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
    220 
    221     int charsWidth[224] = { 3, 1, 4, 6, 5, 7, 6, 2, 3, 3, 5, 5, 2, 4, 1, 7, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 4, 3, 6,
    222                             7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 5, 6, 5, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 6, 6, 6, 2, 7, 2, 3, 5,
    223                             2, 5, 5, 5, 5, 5, 4, 5, 5, 1, 2, 5, 2, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 3, 1, 3, 4, 4,
    224                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    225                             1, 1, 5, 5, 5, 7, 1, 5, 3, 7, 3, 5, 4, 1, 7, 4, 3, 5, 3, 3, 2, 5, 6, 1, 2, 2, 3, 5, 6, 6, 6, 6,
    226                             6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 3, 3, 3, 3, 7, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 4, 6,
    227                             5, 5, 5, 5, 5, 5, 9, 5, 5, 5, 5, 5, 2, 2, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5 };
    228 
    229     // Re-construct image from defaultFontData and generate OpenGL texture
    230     //----------------------------------------------------------------------
    231     Image imFont = {
    232         .data = RL_CALLOC(128*128, 2),  // 2 bytes per pixel (gray + alpha)
    233         .width = 128,
    234         .height = 128,
    235         .mipmaps = 1,
    236         .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
    237     };
    238 
    239     // Fill image.data with defaultFontData (convert from bit to pixel!)
    240     for (int i = 0, counter = 0; i < imFont.width*imFont.height; i += 32)
    241     {
    242         for (int j = 31; j >= 0; j--)
    243         {
    244             if (BIT_CHECK(defaultFontData[counter], j))
    245             {
    246                 // NOTE: We are unreferencing data as short, so,
    247                 // we must consider data as little-endian order (alpha + gray)
    248                 ((unsigned short *)imFont.data)[i + j] = 0xffff;
    249             }
    250             else ((unsigned short *)imFont.data)[i + j] = 0x00ff;
    251         }
    252 
    253         counter++;
    254     }
    255 
    256     if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont);
    257 
    258     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
    259     //------------------------------------------------------------------------------
    260 
    261     // Allocate space for our characters info data
    262     // NOTE: This memory must be freed at end! --> Done by CloseWindow()
    263     defaultFont.glyphs = (GlyphInfo *)RL_CALLOC(defaultFont.glyphCount, sizeof(GlyphInfo));
    264     defaultFont.recs = (Rectangle *)RL_CALLOC(defaultFont.glyphCount, sizeof(Rectangle));
    265 
    266     int currentLine = 0;
    267     int currentPosX = charsDivisor;
    268     int testPosX = charsDivisor;
    269 
    270     for (int i = 0; i < defaultFont.glyphCount; i++)
    271     {
    272         defaultFont.glyphs[i].value = 32 + i;  // First char is 32
    273 
    274         defaultFont.recs[i].x = (float)currentPosX;
    275         defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor));
    276         defaultFont.recs[i].width = (float)charsWidth[i];
    277         defaultFont.recs[i].height = (float)charsHeight;
    278 
    279         testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
    280 
    281         if (testPosX >= defaultFont.texture.width)
    282         {
    283             currentLine++;
    284             currentPosX = 2*charsDivisor + charsWidth[i];
    285             testPosX = currentPosX;
    286 
    287             defaultFont.recs[i].x = (float)charsDivisor;
    288             defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor));
    289         }
    290         else currentPosX = testPosX;
    291 
    292         // NOTE: On default font character offsets and xAdvance are not required
    293         defaultFont.glyphs[i].offsetX = 0;
    294         defaultFont.glyphs[i].offsetY = 0;
    295         defaultFont.glyphs[i].advanceX = 0;
    296 
    297         // Fill character image data from fontClear data
    298         defaultFont.glyphs[i].image = ImageFromImage(imFont, defaultFont.recs[i]);
    299     }
    300 
    301     UnloadImage(imFont);
    302 
    303     defaultFont.baseSize = (int)defaultFont.recs[0].height;
    304 
    305     TRACELOG(LOG_INFO, "FONT: Default font loaded successfully (%i glyphs)", defaultFont.glyphCount);
    306 }
    307 
    308 // Unload raylib default font
    309 extern void UnloadFontDefault(void)
    310 {
    311     for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);
    312     if (isGpuReady) UnloadTexture(defaultFont.texture);
    313     RL_FREE(defaultFont.glyphs);
    314     RL_FREE(defaultFont.recs);
    315 }
    316 #endif      // SUPPORT_DEFAULT_FONT
    317 
    318 // Get the default font, useful to be used with extended parameters
    319 Font GetFontDefault()
    320 {
    321 #if defined(SUPPORT_DEFAULT_FONT)
    322     return defaultFont;
    323 #else
    324     Font font = { 0 };
    325     return font;
    326 #endif
    327 }
    328 
    329 // Load Font from file into GPU memory (VRAM)
    330 Font LoadFont(const char *fileName)
    331 {
    332     // Default values for ttf font generation
    333 #ifndef FONT_TTF_DEFAULT_SIZE
    334     #define FONT_TTF_DEFAULT_SIZE           32      // TTF font generation default char size (char-height)
    335 #endif
    336 #ifndef FONT_TTF_DEFAULT_NUMCHARS
    337     #define FONT_TTF_DEFAULT_NUMCHARS       95      // TTF font generation default charset: 95 glyphs (ASCII 32..126)
    338 #endif
    339 #ifndef FONT_TTF_DEFAULT_FIRST_CHAR
    340     #define FONT_TTF_DEFAULT_FIRST_CHAR     32      // TTF font generation default first char for image sprite font (32-Space)
    341 #endif
    342 #ifndef FONT_TTF_DEFAULT_CHARS_PADDING
    343     #define FONT_TTF_DEFAULT_CHARS_PADDING   4      // TTF font generation default chars padding
    344 #endif
    345 
    346     Font font = { 0 };
    347 
    348 #if defined(SUPPORT_FILEFORMAT_TTF)
    349     if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
    350     else
    351 #endif
    352 #if defined(SUPPORT_FILEFORMAT_FNT)
    353     if (IsFileExtension(fileName, ".fnt")) font = LoadBMFont(fileName);
    354     else
    355 #endif
    356 #if defined(SUPPORT_FILEFORMAT_BDF)
    357     if (IsFileExtension(fileName, ".bdf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
    358     else
    359 #endif
    360     {
    361         Image image = LoadImage(fileName);
    362         if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR);
    363         UnloadImage(image);
    364     }
    365 
    366     if (isGpuReady)
    367     {
    368         if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
    369         else
    370         {
    371             SetTextureFilter(font.texture, TEXTURE_FILTER_POINT);    // By default, we set point filter (the best performance)
    372             TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
    373         }
    374     }
    375 
    376     return font;
    377 }
    378 
    379 // Load Font from TTF or BDF font file with generation parameters
    380 // NOTE: You can pass an array with desired characters, those characters should be available in the font
    381 // if array is NULL, default char set is selected 32..126
    382 Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount)
    383 {
    384     Font font = { 0 };
    385 
    386     // Loading file to memory
    387     int dataSize = 0;
    388     unsigned char *fileData = LoadFileData(fileName, &dataSize);
    389 
    390     if (fileData != NULL)
    391     {
    392         // Loading font from memory data
    393         font = LoadFontFromMemory(GetFileExtension(fileName), fileData, dataSize, fontSize, codepoints, codepointCount);
    394 
    395         UnloadFileData(fileData);
    396     }
    397 
    398     return font;
    399 }
    400 
    401 // Load an Image font file (XNA style)
    402 Font LoadFontFromImage(Image image, Color key, int firstChar)
    403 {
    404 #ifndef MAX_GLYPHS_FROM_IMAGE
    405     #define MAX_GLYPHS_FROM_IMAGE   256     // Maximum number of glyphs supported on image scan
    406 #endif
    407 
    408     #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a))
    409 
    410     Font font = GetFontDefault();
    411 
    412     int charSpacing = 0;
    413     int lineSpacing = 0;
    414 
    415     int x = 0;
    416     int y = 0;
    417 
    418     // We allocate a temporal arrays for chars data measures,
    419     // once we get the actual number of chars, we copy data to a sized arrays
    420     int tempCharValues[MAX_GLYPHS_FROM_IMAGE] = { 0 };
    421     Rectangle tempCharRecs[MAX_GLYPHS_FROM_IMAGE] = { 0 };
    422 
    423     Color *pixels = LoadImageColors(image);
    424 
    425     // Parse image data to get charSpacing and lineSpacing
    426     for (y = 0; y < image.height; y++)
    427     {
    428         for (x = 0; x < image.width; x++)
    429         {
    430             if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
    431         }
    432 
    433         if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
    434     }
    435 
    436     if ((x == 0) || (y == 0)) return font; // Security check
    437 
    438     charSpacing = x;
    439     lineSpacing = y;
    440 
    441     int charHeight = 0;
    442     int j = 0;
    443 
    444     while (!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++;
    445 
    446     charHeight = j;
    447 
    448     // Check array values to get characters: value, x, y, w, h
    449     int index = 0;
    450     int lineToRead = 0;
    451     int xPosToRead = charSpacing;
    452 
    453     // Parse image data to get rectangle sizes
    454     while ((lineSpacing + lineToRead*(charHeight + lineSpacing)) < image.height)
    455     {
    456         while ((xPosToRead < image.width) &&
    457               !COLOR_EQUAL((pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead]), key))
    458         {
    459             tempCharValues[index] = firstChar + index;
    460 
    461             tempCharRecs[index].x = (float)xPosToRead;
    462             tempCharRecs[index].y = (float)(lineSpacing + lineToRead*(charHeight + lineSpacing));
    463             tempCharRecs[index].height = (float)charHeight;
    464 
    465             int charWidth = 0;
    466 
    467             while (!COLOR_EQUAL(pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++;
    468 
    469             tempCharRecs[index].width = (float)charWidth;
    470 
    471             index++;
    472 
    473             xPosToRead += (charWidth + charSpacing);
    474         }
    475 
    476         lineToRead++;
    477         xPosToRead = charSpacing;
    478     }
    479 
    480     // NOTE: We need to remove key color borders from image to avoid weird
    481     // artifacts on texture scaling when using TEXTURE_FILTER_BILINEAR or TEXTURE_FILTER_TRILINEAR
    482     for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
    483 
    484     // Create a new image with the processed color data (key color replaced by BLANK)
    485     Image fontClear = {
    486         .data = pixels,
    487         .width = image.width,
    488         .height = image.height,
    489         .mipmaps = 1,
    490         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
    491     };
    492 
    493     // Set font with all data parsed from image
    494     if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
    495     font.glyphCount = index;
    496     font.glyphPadding = 0;
    497 
    498     // We got tempCharValues and tempCharsRecs populated with chars data
    499     // Now we move temp data to sized charValues and charRecs arrays
    500     font.glyphs = (GlyphInfo *)RL_MALLOC(font.glyphCount*sizeof(GlyphInfo));
    501     font.recs = (Rectangle *)RL_MALLOC(font.glyphCount*sizeof(Rectangle));
    502 
    503     for (int i = 0; i < font.glyphCount; i++)
    504     {
    505         font.glyphs[i].value = tempCharValues[i];
    506 
    507         // Get character rectangle in the font atlas texture
    508         font.recs[i] = tempCharRecs[i];
    509 
    510         // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
    511         font.glyphs[i].offsetX = 0;
    512         font.glyphs[i].offsetY = 0;
    513         font.glyphs[i].advanceX = 0;
    514 
    515         // Fill character image data from fontClear data
    516         font.glyphs[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
    517     }
    518 
    519     UnloadImage(fontClear);     // Unload processed image once converted to texture
    520 
    521     font.baseSize = (int)font.recs[0].height;
    522 
    523     return font;
    524 }
    525 
    526 // Load font from memory buffer, fileType refers to extension: i.e. ".ttf"
    527 Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount)
    528 {
    529     Font font = { 0 };
    530 
    531     char fileExtLower[16] = { 0 };
    532     strncpy(fileExtLower, TextToLower(fileType), 16 - 1);
    533 
    534     font.baseSize = fontSize;
    535     font.glyphCount = (codepointCount > 0)? codepointCount : 95;
    536     font.glyphPadding = 0;
    537 
    538 #if defined(SUPPORT_FILEFORMAT_TTF)
    539     if (TextIsEqual(fileExtLower, ".ttf") ||
    540         TextIsEqual(fileExtLower, ".otf"))
    541     {
    542         font.glyphs = LoadFontData(fileData, dataSize, font.baseSize, codepoints, font.glyphCount, FONT_DEFAULT);
    543     }
    544     else
    545 #endif
    546 #if defined(SUPPORT_FILEFORMAT_BDF)
    547     if (TextIsEqual(fileExtLower, ".bdf"))
    548     {
    549         font.glyphs = LoadFontDataBDF(fileData, dataSize, codepoints, font.glyphCount, &font.baseSize);
    550     }
    551     else
    552 #endif
    553     {
    554         font.glyphs = NULL;
    555     }
    556 
    557 #if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF)
    558     if (font.glyphs != NULL)
    559     {
    560         font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
    561 
    562         Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
    563         if (isGpuReady) font.texture = LoadTextureFromImage(atlas);
    564 
    565         // Update glyphs[i].image to use alpha, required to be used on ImageDrawText()
    566         for (int i = 0; i < font.glyphCount; i++)
    567         {
    568             UnloadImage(font.glyphs[i].image);
    569             font.glyphs[i].image = ImageFromImage(atlas, font.recs[i]);
    570         }
    571 
    572         UnloadImage(atlas);
    573 
    574         TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
    575     }
    576     else font = GetFontDefault();
    577 #else
    578     font = GetFontDefault();
    579 #endif
    580 
    581     return font;
    582 }
    583 
    584 // Check if a font is valid (font data loaded)
    585 // WARNING: GPU texture not checked
    586 bool IsFontValid(Font font)
    587 {
    588     return ((font.baseSize > 0) &&      // Validate font size
    589             (font.glyphCount > 0) &&    // Validate font contains some glyph
    590             (font.recs != NULL) &&      // Validate font recs defining glyphs on texture atlas
    591             (font.glyphs != NULL));     // Validate glyph data is loaded
    592 
    593     // NOTE: Further validations could be done to verify if recs and glyphs contain valid data (glyphs values, metrics...)
    594 }
    595 
    596 // Load font data for further use
    597 // NOTE: Requires TTF font memory data and can generate SDF data
    598 GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *codepoints, int codepointCount, int type)
    599 {
    600     // NOTE: Using some SDF generation default values,
    601     // trades off precision with ability to handle *smaller* sizes
    602 #ifndef FONT_SDF_CHAR_PADDING
    603     #define FONT_SDF_CHAR_PADDING            4      // SDF font generation char padding
    604 #endif
    605 #ifndef FONT_SDF_ON_EDGE_VALUE
    606     #define FONT_SDF_ON_EDGE_VALUE         128      // SDF font generation on edge value
    607 #endif
    608 #ifndef FONT_SDF_PIXEL_DIST_SCALE
    609     #define FONT_SDF_PIXEL_DIST_SCALE     64.0f     // SDF font generation pixel distance scale
    610 #endif
    611 #ifndef FONT_BITMAP_ALPHA_THRESHOLD
    612     #define FONT_BITMAP_ALPHA_THRESHOLD     80      // Bitmap (B&W) font generation alpha threshold
    613 #endif
    614 
    615     GlyphInfo *chars = NULL;
    616 
    617 #if defined(SUPPORT_FILEFORMAT_TTF)
    618     // Load font data (including pixel data) from TTF memory file
    619     // NOTE: Loaded information should be enough to generate font image atlas, using any packaging method
    620     if (fileData != NULL)
    621     {
    622         bool genFontChars = false;
    623         stbtt_fontinfo fontInfo = { 0 };
    624 
    625         if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0))     // Initialize font for data reading
    626         {
    627             // Calculate font scale factor
    628             float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
    629 
    630             // Calculate font basic metrics
    631             // NOTE: ascent is equivalent to font baseline
    632             int ascent, descent, lineGap;
    633             stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
    634 
    635             // In case no chars count provided, default to 95
    636             codepointCount = (codepointCount > 0)? codepointCount : 95;
    637 
    638             // Fill fontChars in case not provided externally
    639             // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
    640             if (codepoints == NULL)
    641             {
    642                 codepoints = (int *)RL_MALLOC(codepointCount*sizeof(int));
    643                 for (int i = 0; i < codepointCount; i++) codepoints[i] = i + 32;
    644                 genFontChars = true;
    645             }
    646 
    647             chars = (GlyphInfo *)RL_CALLOC(codepointCount, sizeof(GlyphInfo));
    648 
    649             // NOTE: Using simple packaging, one char after another
    650             for (int i = 0; i < codepointCount; i++)
    651             {
    652                 int chw = 0, chh = 0;   // Character width and height (on generation)
    653                 int ch = codepoints[i];  // Character value to get info for
    654                 chars[i].value = ch;
    655 
    656                 //  Render a unicode codepoint to a bitmap
    657                 //      stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap
    658                 //      stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be
    659                 //      stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide
    660 
    661                 // Check if a glyph is available in the font
    662                 // WARNING: if (index == 0), glyph not found, it could fallback to default .notdef glyph (if defined in font)
    663                 int index = stbtt_FindGlyphIndex(&fontInfo, ch);
    664 
    665                 if (index > 0)
    666                 {
    667                     switch (type)
    668                     {
    669                         case FONT_DEFAULT:
    670                         case FONT_BITMAP: chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); break;
    671                         case FONT_SDF: if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, FONT_SDF_CHAR_PADDING, FONT_SDF_ON_EDGE_VALUE, FONT_SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); break;
    672                         default: break;
    673                     }
    674 
    675                     if (chars[i].image.data != NULL)    // Glyph data has been found in the font
    676                     {
    677                         stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
    678                         chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
    679 
    680                         if (chh > fontSize) TRACELOG(LOG_WARNING, "FONT: Character [0x%08x] size is bigger than expected font size", ch);
    681 
    682                         // Load characters images
    683                         chars[i].image.width = chw;
    684                         chars[i].image.height = chh;
    685                         chars[i].image.mipmaps = 1;
    686                         chars[i].image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
    687 
    688                         chars[i].offsetY += (int)((float)ascent*scaleFactor);
    689                     }
    690 
    691                     // NOTE: We create an empty image for space character,
    692                     // it could be further required for atlas packing
    693                     if (ch == 32)
    694                     {
    695                         stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
    696                         chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
    697 
    698                         Image imSpace = {
    699                             .data = RL_CALLOC(chars[i].advanceX*fontSize, 2),
    700                             .width = chars[i].advanceX,
    701                             .height = fontSize,
    702                             .mipmaps = 1,
    703                             .format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE
    704                         };
    705 
    706                         chars[i].image = imSpace;
    707                     }
    708 
    709                     if (type == FONT_BITMAP)
    710                     {
    711                         // Aliased bitmap (black & white) font generation, avoiding anti-aliasing
    712                         // NOTE: For optimum results, bitmap font should be generated at base pixel size
    713                         for (int p = 0; p < chw*chh; p++)
    714                         {
    715                             if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
    716                             else ((unsigned char *)chars[i].image.data)[p] = 255;
    717                         }
    718                     }
    719                 }
    720                 else
    721                 {
    722                     // TODO: Use some fallback glyph for codepoints not found in the font
    723                 }
    724             }
    725         }
    726         else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data");
    727 
    728         if (genFontChars) RL_FREE(codepoints);
    729     }
    730 #endif
    731 
    732     return chars;
    733 }
    734 
    735 // Generate image font atlas using chars info
    736 // NOTE: Packing method: 0-Default, 1-Skyline
    737 #if defined(SUPPORT_FILEFORMAT_TTF) || defined(SUPPORT_FILEFORMAT_BDF)
    738 Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod)
    739 {
    740     Image atlas = { 0 };
    741 
    742     if (glyphs == NULL)
    743     {
    744         TRACELOG(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
    745         return atlas;
    746     }
    747 
    748     *glyphRecs = NULL;
    749 
    750     // In case no chars count provided we suppose default of 95
    751     glyphCount = (glyphCount > 0)? glyphCount : 95;
    752 
    753     // NOTE: Rectangles memory is loaded here!
    754     Rectangle *recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));
    755 
    756     // Calculate image size based on total glyph width and glyph row count
    757     int totalWidth = 0;
    758     int maxGlyphWidth = 0;
    759 
    760     for (int i = 0; i < glyphCount; i++)
    761     {
    762         if (glyphs[i].image.width > maxGlyphWidth) maxGlyphWidth = glyphs[i].image.width;
    763         totalWidth += glyphs[i].image.width + 2*padding;
    764     }
    765 
    766 //#define SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE
    767 #if defined(SUPPORT_FONT_ATLAS_SIZE_CONSERVATIVE)
    768     int rowCount = 0;
    769     int imageSize = 64;  // Define minimum starting value to avoid unnecessary calculation steps for very small images
    770 
    771     // NOTE: maxGlyphWidth is maximum possible space left at the end of row
    772     while (totalWidth > (imageSize - maxGlyphWidth)*rowCount)
    773     {
    774         imageSize *= 2;                                 // Double the size of image (to keep POT)
    775         rowCount = imageSize/(fontSize + 2*padding);    // Calculate new row count for the new image size
    776     }
    777 
    778     atlas.width = imageSize;   // Atlas bitmap width
    779     atlas.height = imageSize;  // Atlas bitmap height
    780 #else
    781     int paddedFontSize = fontSize + 2*padding;
    782     // No need for a so-conservative atlas generation
    783     float totalArea = totalWidth*paddedFontSize*1.2f;
    784     float imageMinSize = sqrtf(totalArea);
    785     int imageSize = (int)powf(2, ceilf(logf(imageMinSize)/logf(2)));
    786 
    787     if (totalArea < ((imageSize*imageSize)/2))
    788     {
    789         atlas.width = imageSize;    // Atlas bitmap width
    790         atlas.height = imageSize/2; // Atlas bitmap height
    791     }
    792     else
    793     {
    794         atlas.width = imageSize;   // Atlas bitmap width
    795         atlas.height = imageSize;  // Atlas bitmap height
    796     }
    797 #endif
    798 
    799     atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height);   // Create a bitmap to store characters (8 bpp)
    800     atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
    801     atlas.mipmaps = 1;
    802 
    803     // DEBUG: We can see padding in the generated image setting a gray background...
    804     //for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100;
    805 
    806     if (packMethod == 0)   // Use basic packing algorithm
    807     {
    808         int offsetX = padding;
    809         int offsetY = padding;
    810 
    811         // NOTE: Using simple packaging, one char after another
    812         for (int i = 0; i < glyphCount; i++)
    813         {
    814             // Check remaining space for glyph
    815             if (offsetX >= (atlas.width - glyphs[i].image.width - 2*padding))
    816             {
    817                 offsetX = padding;
    818 
    819                 // NOTE: Be careful on offsetY for SDF fonts, by default SDF
    820                 // use an internal padding of 4 pixels, it means char rectangle
    821                 // height is bigger than fontSize, it could be up to (fontSize + 8)
    822                 offsetY += (fontSize + 2*padding);
    823 
    824                 if (offsetY > (atlas.height - fontSize - padding))
    825                 {
    826                     for (int j = i + 1; j < glyphCount; j++)
    827                     {
    828                         TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", j);
    829                         // Make sure remaining recs contain valid data
    830                         recs[j].x = 0;
    831                         recs[j].y = 0;
    832                         recs[j].width = 0;
    833                         recs[j].height = 0;
    834                     }
    835                     break;
    836                 }
    837             }
    838 
    839             // Copy pixel data from glyph image to atlas
    840             for (int y = 0; y < glyphs[i].image.height; y++)
    841             {
    842                 for (int x = 0; x < glyphs[i].image.width; x++)
    843                 {
    844                     ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x];
    845                 }
    846             }
    847 
    848             // Fill chars rectangles in atlas info
    849             recs[i].x = (float)offsetX;
    850             recs[i].y = (float)offsetY;
    851             recs[i].width = (float)glyphs[i].image.width;
    852             recs[i].height = (float)glyphs[i].image.height;
    853 
    854             // Move atlas position X for next character drawing
    855             offsetX += (glyphs[i].image.width + 2*padding);
    856         }
    857     }
    858     else if (packMethod == 1)  // Use Skyline rect packing algorithm (stb_pack_rect)
    859     {
    860         stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
    861         stbrp_node *nodes = (stbrp_node *)RL_MALLOC(glyphCount*sizeof(*nodes));
    862 
    863         stbrp_init_target(context, atlas.width, atlas.height, nodes, glyphCount);
    864         stbrp_rect *rects = (stbrp_rect *)RL_MALLOC(glyphCount*sizeof(stbrp_rect));
    865 
    866         // Fill rectangles for packaging
    867         for (int i = 0; i < glyphCount; i++)
    868         {
    869             rects[i].id = i;
    870             rects[i].w = glyphs[i].image.width + 2*padding;
    871             rects[i].h = glyphs[i].image.height + 2*padding;
    872         }
    873 
    874         // Package rectangles into atlas
    875         stbrp_pack_rects(context, rects, glyphCount);
    876 
    877         for (int i = 0; i < glyphCount; i++)
    878         {
    879             // It returns char rectangles in atlas
    880             recs[i].x = rects[i].x + (float)padding;
    881             recs[i].y = rects[i].y + (float)padding;
    882             recs[i].width = (float)glyphs[i].image.width;
    883             recs[i].height = (float)glyphs[i].image.height;
    884 
    885             if (rects[i].was_packed)
    886             {
    887                 // Copy pixel data from fc.data to atlas
    888                 for (int y = 0; y < glyphs[i].image.height; y++)
    889                 {
    890                     for (int x = 0; x < glyphs[i].image.width; x++)
    891                     {
    892                         ((unsigned char *)atlas.data)[(rects[i].y + padding + y)*atlas.width + (rects[i].x + padding + x)] = ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x];
    893                     }
    894                 }
    895             }
    896             else TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", i);
    897         }
    898 
    899         RL_FREE(rects);
    900         RL_FREE(nodes);
    901         RL_FREE(context);
    902     }
    903 
    904 #if defined(SUPPORT_FONT_ATLAS_WHITE_REC)
    905     // Add a 3x3 white rectangle at the bottom-right corner of the generated atlas,
    906     // useful to use as the white texture to draw shapes with raylib, using this rectangle
    907     // shapes and text can be backed into a single draw call: SetShapesTexture()
    908     for (int i = 0, k = atlas.width*atlas.height - 1; i < 3; i++)
    909     {
    910         ((unsigned char *)atlas.data)[k - 0] = 255;
    911         ((unsigned char *)atlas.data)[k - 1] = 255;
    912         ((unsigned char *)atlas.data)[k - 2] = 255;
    913         k -= atlas.width;
    914     }
    915 #endif
    916 
    917     // Convert image data from GRAYSCALE to GRAY_ALPHA
    918     unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
    919 
    920     for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2)
    921     {
    922         dataGrayAlpha[k] = 255;
    923         dataGrayAlpha[k + 1] = ((unsigned char *)atlas.data)[i];
    924     }
    925 
    926     RL_FREE(atlas.data);
    927     atlas.data = dataGrayAlpha;
    928     atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
    929 
    930     *glyphRecs = recs;
    931 
    932     return atlas;
    933 }
    934 #endif
    935 
    936 // Unload font glyphs info data (RAM)
    937 void UnloadFontData(GlyphInfo *glyphs, int glyphCount)
    938 {
    939     if (glyphs != NULL)
    940     {
    941         for (int i = 0; i < glyphCount; i++) UnloadImage(glyphs[i].image);
    942 
    943         RL_FREE(glyphs);
    944     }
    945 }
    946 
    947 // Unload Font from GPU memory (VRAM)
    948 void UnloadFont(Font font)
    949 {
    950     // NOTE: Make sure font is not default font (fallback)
    951     if (font.texture.id != GetFontDefault().texture.id)
    952     {
    953         UnloadFontData(font.glyphs, font.glyphCount);
    954         if (isGpuReady) UnloadTexture(font.texture);
    955         RL_FREE(font.recs);
    956 
    957         TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
    958     }
    959 }
    960 
    961 // Export font as code file, returns true on success
    962 bool ExportFontAsCode(Font font, const char *fileName)
    963 {
    964     bool success = false;
    965 
    966 #ifndef TEXT_BYTES_PER_LINE
    967     #define TEXT_BYTES_PER_LINE     20
    968 #endif
    969 
    970     #define MAX_FONT_DATA_SIZE      1024*1024       // 1 MB
    971 
    972     // Get file name from path
    973     char fileNamePascal[256] = { 0 };
    974     strncpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)), 256 - 1);
    975 
    976     // NOTE: Text data buffer size is estimated considering image data size in bytes
    977     // and requiring 6 char bytes for every byte: "0x00, "
    978     char *txtData = (char *)RL_CALLOC(MAX_FONT_DATA_SIZE, sizeof(char));
    979 
    980     int byteCount = 0;
    981     byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
    982     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
    983     byteCount += sprintf(txtData + byteCount, "// FontAsCode exporter v1.0 - Font data exported as an array of bytes                 //\n");
    984     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
    985     byteCount += sprintf(txtData + byteCount, "// more info and bugs-report:  github.com/raysan5/raylib                              //\n");
    986     byteCount += sprintf(txtData + byteCount, "// feedback and support:       ray[at]raylib.com                                      //\n");
    987     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
    988     byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2024 Ramon Santamaria (@raysan5)                                //\n");
    989     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
    990     byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n");
    991     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
    992     byteCount += sprintf(txtData + byteCount, "// TODO: Fill the information and license of the exported font here:                  //\n");
    993     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
    994     byteCount += sprintf(txtData + byteCount, "// Font name:    ....                                                                 //\n");
    995     byteCount += sprintf(txtData + byteCount, "// Font creator: ....                                                                 //\n");
    996     byteCount += sprintf(txtData + byteCount, "// Font LICENSE: ....                                                                 //\n");
    997     byteCount += sprintf(txtData + byteCount, "//                                                                                    //\n");
    998     byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
    999 
   1000     // Support font export and initialization
   1001     // NOTE: This mechanism is highly coupled to raylib
   1002     Image image = LoadImageFromTexture(font.texture);
   1003     if (image.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!");
   1004     int imageDataSize = GetPixelDataSize(image.width, image.height, image.format);
   1005 
   1006     // Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE
   1007     //ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
   1008 
   1009 #define SUPPORT_COMPRESSED_FONT_ATLAS
   1010 #if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
   1011     // WARNING: Data is compressed using raylib CompressData() DEFLATE,
   1012     // it requires to be decompressed with raylib DecompressData(), that requires
   1013     // compiling raylib with SUPPORT_COMPRESSION_API config flag enabled
   1014 
   1015     // Compress font image data
   1016     int compDataSize = 0;
   1017     unsigned char *compData = CompressData((const unsigned char *)image.data, imageDataSize, &compDataSize);
   1018 
   1019     // Save font image data (compressed)
   1020     byteCount += sprintf(txtData + byteCount, "#define COMPRESSED_DATA_SIZE_FONT_%s %i\n\n", TextToUpper(fileNamePascal), compDataSize);
   1021     byteCount += sprintf(txtData + byteCount, "// Font image pixels data compressed (DEFLATE)\n");
   1022     byteCount += sprintf(txtData + byteCount, "// NOTE: Original pixel data simplified to GRAYSCALE\n");
   1023     byteCount += sprintf(txtData + byteCount, "static unsigned char fontData_%s[COMPRESSED_DATA_SIZE_FONT_%s] = { ", fileNamePascal, TextToUpper(fileNamePascal));
   1024     for (int i = 0; i < compDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n    " : "0x%02x, "), compData[i]);
   1025     byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", compData[compDataSize - 1]);
   1026     RL_FREE(compData);
   1027 #else
   1028     // Save font image data (uncompressed)
   1029     byteCount += sprintf(txtData + byteCount, "// Font image pixels data\n");
   1030     byteCount += sprintf(txtData + byteCount, "// NOTE: 2 bytes per pixel, GRAY + ALPHA channels\n");
   1031     byteCount += sprintf(txtData + byteCount, "static unsigned char fontImageData_%s[%i] = { ", fileNamePascal, imageDataSize);
   1032     for (int i = 0; i < imageDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n    " : "0x%02x, "), ((unsigned char *)imFont.data)[i]);
   1033     byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", ((unsigned char *)imFont.data)[imageDataSize - 1]);
   1034 #endif
   1035 
   1036     // Save font recs data
   1037     byteCount += sprintf(txtData + byteCount, "// Font characters rectangles data\n");
   1038     byteCount += sprintf(txtData + byteCount, "static Rectangle fontRecs_%s[%i] = {\n", fileNamePascal, font.glyphCount);
   1039     for (int i = 0; i < font.glyphCount; i++)
   1040     {
   1041         byteCount += sprintf(txtData + byteCount, "    { %1.0f, %1.0f, %1.0f , %1.0f },\n", font.recs[i].x, font.recs[i].y, font.recs[i].width, font.recs[i].height);
   1042     }
   1043     byteCount += sprintf(txtData + byteCount, "};\n\n");
   1044 
   1045     // Save font glyphs data
   1046     // NOTE: Glyphs image data not saved (grayscale pixels),
   1047     // it could be generated from image and recs
   1048     byteCount += sprintf(txtData + byteCount, "// Font glyphs info data\n");
   1049     byteCount += sprintf(txtData + byteCount, "// NOTE: No glyphs.image data provided\n");
   1050     byteCount += sprintf(txtData + byteCount, "static GlyphInfo fontGlyphs_%s[%i] = {\n", fileNamePascal, font.glyphCount);
   1051     for (int i = 0; i < font.glyphCount; i++)
   1052     {
   1053         byteCount += sprintf(txtData + byteCount, "    { %i, %i, %i, %i, { 0 }},\n", font.glyphs[i].value, font.glyphs[i].offsetX, font.glyphs[i].offsetY, font.glyphs[i].advanceX);
   1054     }
   1055     byteCount += sprintf(txtData + byteCount, "};\n\n");
   1056 
   1057     // Custom font loading function
   1058     byteCount += sprintf(txtData + byteCount, "// Font loading function: %s\n", fileNamePascal);
   1059     byteCount += sprintf(txtData + byteCount, "static Font LoadFont_%s(void)\n{\n", fileNamePascal);
   1060     byteCount += sprintf(txtData + byteCount, "    Font font = { 0 };\n\n");
   1061     byteCount += sprintf(txtData + byteCount, "    font.baseSize = %i;\n", font.baseSize);
   1062     byteCount += sprintf(txtData + byteCount, "    font.glyphCount = %i;\n", font.glyphCount);
   1063     byteCount += sprintf(txtData + byteCount, "    font.glyphPadding = %i;\n\n", font.glyphPadding);
   1064     byteCount += sprintf(txtData + byteCount, "    // Custom font loading\n");
   1065 #if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
   1066     byteCount += sprintf(txtData + byteCount, "    // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function\n");
   1067     byteCount += sprintf(txtData + byteCount, "    int fontDataSize_%s = 0;\n", fileNamePascal);
   1068     byteCount += sprintf(txtData + byteCount, "    unsigned char *data = DecompressData(fontData_%s, COMPRESSED_DATA_SIZE_FONT_%s, &fontDataSize_%s);\n", fileNamePascal, TextToUpper(fileNamePascal), fileNamePascal);
   1069     byteCount += sprintf(txtData + byteCount, "    Image imFont = { data, %i, %i, 1, %i };\n\n", image.width, image.height, image.format);
   1070 #else
   1071     byteCount += sprintf(txtData + byteCount, "    Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format);
   1072 #endif
   1073     byteCount += sprintf(txtData + byteCount, "    // Load texture from image\n");
   1074     byteCount += sprintf(txtData + byteCount, "    if (isGpuReady) font.texture = LoadTextureFromImage(imFont);\n");
   1075 #if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
   1076     byteCount += sprintf(txtData + byteCount, "    UnloadImage(imFont);  // Uncompressed data can be unloaded from memory\n\n");
   1077 #endif
   1078     // We have two possible mechanisms to assign font.recs and font.glyphs data,
   1079     // that data is already available as global arrays, we two options to assign that data:
   1080     //  - 1. Data copy. This option consumes more memory and Font MUST be unloaded by user, requiring additional code
   1081     //  - 2. Data assignment. This option consumes less memory and Font MUST NOT be unloaded by user because data is on protected DATA segment
   1082 //#define SUPPORT_FONT_DATA_COPY
   1083 #if defined(SUPPORT_FONT_DATA_COPY)
   1084     byteCount += sprintf(txtData + byteCount, "    // Copy glyph recs data from global fontRecs\n");
   1085     byteCount += sprintf(txtData + byteCount, "    // NOTE: Required to avoid issues if trying to free font\n");
   1086     byteCount += sprintf(txtData + byteCount, "    font.recs = (Rectangle *)malloc(font.glyphCount*sizeof(Rectangle));\n");
   1087     byteCount += sprintf(txtData + byteCount, "    memcpy(font.recs, fontRecs_%s, font.glyphCount*sizeof(Rectangle));\n\n", fileNamePascal);
   1088 
   1089     byteCount += sprintf(txtData + byteCount, "    // Copy font glyph info data from global fontChars\n");
   1090     byteCount += sprintf(txtData + byteCount, "    // NOTE: Required to avoid issues if trying to free font\n");
   1091     byteCount += sprintf(txtData + byteCount, "    font.glyphs = (GlyphInfo *)malloc(font.glyphCount*sizeof(GlyphInfo));\n");
   1092     byteCount += sprintf(txtData + byteCount, "    memcpy(font.glyphs, fontGlyphs_%s, font.glyphCount*sizeof(GlyphInfo));\n\n", fileNamePascal);
   1093 #else
   1094     byteCount += sprintf(txtData + byteCount, "    // Assign glyph recs and info data directly\n");
   1095     byteCount += sprintf(txtData + byteCount, "    // WARNING: This font data must not be unloaded\n");
   1096     byteCount += sprintf(txtData + byteCount, "    font.recs = fontRecs_%s;\n", fileNamePascal);
   1097     byteCount += sprintf(txtData + byteCount, "    font.glyphs = fontGlyphs_%s;\n\n", fileNamePascal);
   1098 #endif
   1099     byteCount += sprintf(txtData + byteCount, "    return font;\n");
   1100     byteCount += sprintf(txtData + byteCount, "}\n");
   1101 
   1102     UnloadImage(image);
   1103 
   1104     // NOTE: Text data size exported is determined by '\0' (NULL) character
   1105     success = SaveFileText(fileName, txtData);
   1106 
   1107     RL_FREE(txtData);
   1108 
   1109     if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName);
   1110     else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fileName);
   1111 
   1112     return success;
   1113 }
   1114 
   1115 // Draw current FPS
   1116 // NOTE: Uses default font
   1117 void DrawFPS(int posX, int posY)
   1118 {
   1119     Color color = LIME;                         // Good FPS
   1120     int fps = GetFPS();
   1121 
   1122     if ((fps < 30) && (fps >= 15)) color = ORANGE;  // Warning FPS
   1123     else if (fps < 15) color = RED;             // Low FPS
   1124 
   1125     DrawText(TextFormat("%2i FPS", fps), posX, posY, 20, color);
   1126 }
   1127 
   1128 // Draw text (using default font)
   1129 // NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used
   1130 // NOTE: chars spacing is proportional to fontSize
   1131 void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
   1132 {
   1133     // Check if default font has been loaded
   1134     if (GetFontDefault().texture.id != 0)
   1135     {
   1136         Vector2 position = { (float)posX, (float)posY };
   1137 
   1138         int defaultFontSize = 10;   // Default Font chars height in pixel
   1139         if (fontSize < defaultFontSize) fontSize = defaultFontSize;
   1140         int spacing = fontSize/defaultFontSize;
   1141 
   1142         DrawTextEx(GetFontDefault(), text, position, (float)fontSize, (float)spacing, color);
   1143     }
   1144 }
   1145 
   1146 // Draw text using Font
   1147 // NOTE: chars spacing is NOT proportional to fontSize
   1148 void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
   1149 {
   1150     if (font.texture.id == 0) font = GetFontDefault();  // Security check in case of not valid font
   1151 
   1152     int size = TextLength(text);    // Total size in bytes of the text, scanned by codepoints in loop
   1153 
   1154     float textOffsetY = 0;          // Offset between lines (on linebreak '\n')
   1155     float textOffsetX = 0.0f;       // Offset X to next character to draw
   1156 
   1157     float scaleFactor = fontSize/font.baseSize;         // Character quad scaling factor
   1158 
   1159     for (int i = 0; i < size;)
   1160     {
   1161         // Get next codepoint from byte string and glyph index in font
   1162         int codepointByteCount = 0;
   1163         int codepoint = GetCodepointNext(&text[i], &codepointByteCount);
   1164         int index = GetGlyphIndex(font, codepoint);
   1165 
   1166         if (codepoint == '\n')
   1167         {
   1168             // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
   1169             textOffsetY += (fontSize + textLineSpacing);
   1170             textOffsetX = 0.0f;
   1171         }
   1172         else
   1173         {
   1174             if ((codepoint != ' ') && (codepoint != '\t'))
   1175             {
   1176                 DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
   1177             }
   1178 
   1179             if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
   1180             else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
   1181         }
   1182 
   1183         i += codepointByteCount;   // Move text bytes counter to next codepoint
   1184     }
   1185 }
   1186 
   1187 // Draw text using Font and pro parameters (rotation)
   1188 void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint)
   1189 {
   1190     rlPushMatrix();
   1191 
   1192         rlTranslatef(position.x, position.y, 0.0f);
   1193         rlRotatef(rotation, 0.0f, 0.0f, 1.0f);
   1194         rlTranslatef(-origin.x, -origin.y, 0.0f);
   1195 
   1196         DrawTextEx(font, text, (Vector2){ 0.0f, 0.0f }, fontSize, spacing, tint);
   1197 
   1198     rlPopMatrix();
   1199 }
   1200 
   1201 // Draw one character (codepoint)
   1202 void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint)
   1203 {
   1204     // Character index position in sprite font
   1205     // NOTE: In case a codepoint is not available in the font, index returned points to '?'
   1206     int index = GetGlyphIndex(font, codepoint);
   1207     float scaleFactor = fontSize/font.baseSize;     // Character quad scaling factor
   1208 
   1209     // Character destination rectangle on screen
   1210     // NOTE: We consider glyphPadding on drawing
   1211     Rectangle dstRec = { position.x + font.glyphs[index].offsetX*scaleFactor - (float)font.glyphPadding*scaleFactor,
   1212                       position.y + font.glyphs[index].offsetY*scaleFactor - (float)font.glyphPadding*scaleFactor,
   1213                       (font.recs[index].width + 2.0f*font.glyphPadding)*scaleFactor,
   1214                       (font.recs[index].height + 2.0f*font.glyphPadding)*scaleFactor };
   1215 
   1216     // Character source rectangle from font texture atlas
   1217     // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
   1218     Rectangle srcRec = { font.recs[index].x - (float)font.glyphPadding, font.recs[index].y - (float)font.glyphPadding,
   1219                          font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding };
   1220 
   1221     // Draw the character texture on the screen
   1222     DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
   1223 }
   1224 
   1225 // Draw multiple character (codepoints)
   1226 void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint)
   1227 {
   1228     float textOffsetY = 0;          // Offset between lines (on linebreak '\n')
   1229     float textOffsetX = 0.0f;       // Offset X to next character to draw
   1230 
   1231     float scaleFactor = fontSize/font.baseSize;         // Character quad scaling factor
   1232 
   1233     for (int i = 0; i < codepointCount; i++)
   1234     {
   1235         int index = GetGlyphIndex(font, codepoints[i]);
   1236 
   1237         if (codepoints[i] == '\n')
   1238         {
   1239             // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
   1240             textOffsetY += (fontSize + textLineSpacing);
   1241             textOffsetX = 0.0f;
   1242         }
   1243         else
   1244         {
   1245             if ((codepoints[i] != ' ') && (codepoints[i] != '\t'))
   1246             {
   1247                 DrawTextCodepoint(font, codepoints[i], (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
   1248             }
   1249 
   1250             if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
   1251             else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
   1252         }
   1253     }
   1254 }
   1255 
   1256 // Set vertical line spacing when drawing with line-breaks
   1257 void SetTextLineSpacing(int spacing)
   1258 {
   1259     textLineSpacing = spacing;
   1260 }
   1261 
   1262 // Measure string width for default font
   1263 int MeasureText(const char *text, int fontSize)
   1264 {
   1265     Vector2 textSize = { 0.0f, 0.0f };
   1266 
   1267     // Check if default font has been loaded
   1268     if (GetFontDefault().texture.id != 0)
   1269     {
   1270         int defaultFontSize = 10;   // Default Font chars height in pixel
   1271         if (fontSize < defaultFontSize) fontSize = defaultFontSize;
   1272         int spacing = fontSize/defaultFontSize;
   1273 
   1274         textSize = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing);
   1275     }
   1276 
   1277     return (int)textSize.x;
   1278 }
   1279 
   1280 // Measure string size for Font
   1281 Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
   1282 {
   1283     Vector2 textSize = { 0 };
   1284 
   1285     if ((isGpuReady && (font.texture.id == 0)) || 
   1286         (text == NULL) || (text[0] == '\0')) return textSize; // Security check
   1287 
   1288     int size = TextLength(text);    // Get size in bytes of text
   1289     int tempByteCounter = 0;        // Used to count longer text line num chars
   1290     int byteCounter = 0;
   1291 
   1292     float textWidth = 0.0f;
   1293     float tempTextWidth = 0.0f;     // Used to count longer text line width
   1294 
   1295     float textHeight = fontSize;
   1296     float scaleFactor = fontSize/(float)font.baseSize;
   1297 
   1298     int letter = 0;                 // Current character
   1299     int index = 0;                  // Index position in sprite font
   1300 
   1301     for (int i = 0; i < size;)
   1302     {
   1303         byteCounter++;
   1304 
   1305         int codepointByteCount = 0;
   1306         letter = GetCodepointNext(&text[i], &codepointByteCount);
   1307         index = GetGlyphIndex(font, letter);
   1308 
   1309         i += codepointByteCount;
   1310 
   1311         if (letter != '\n')
   1312         {
   1313             if (font.glyphs[index].advanceX > 0) textWidth += font.glyphs[index].advanceX;
   1314             else textWidth += (font.recs[index].width + font.glyphs[index].offsetX);
   1315         }
   1316         else
   1317         {
   1318             if (tempTextWidth < textWidth) tempTextWidth = textWidth;
   1319             byteCounter = 0;
   1320             textWidth = 0;
   1321 
   1322             // NOTE: Line spacing is a global variable, use SetTextLineSpacing() to setup
   1323             textHeight += (fontSize + textLineSpacing);
   1324         }
   1325 
   1326         if (tempByteCounter < byteCounter) tempByteCounter = byteCounter;
   1327     }
   1328 
   1329     if (tempTextWidth < textWidth) tempTextWidth = textWidth;
   1330 
   1331     textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing);
   1332     textSize.y = textHeight;
   1333 
   1334     return textSize;
   1335 }
   1336 
   1337 // Get index position for a unicode character on font
   1338 // NOTE: If codepoint is not found in the font it fallbacks to '?'
   1339 int GetGlyphIndex(Font font, int codepoint)
   1340 {
   1341     int index = 0;
   1342 
   1343 #define SUPPORT_UNORDERED_CHARSET
   1344 #if defined(SUPPORT_UNORDERED_CHARSET)
   1345     int fallbackIndex = 0;      // Get index of fallback glyph '?'
   1346 
   1347     // Look for character index in the unordered charset
   1348     for (int i = 0; i < font.glyphCount; i++)
   1349     {
   1350         if (font.glyphs[i].value == 63) fallbackIndex = i;
   1351 
   1352         if (font.glyphs[i].value == codepoint)
   1353         {
   1354             index = i;
   1355             break;
   1356         }
   1357     }
   1358 
   1359     if ((index == 0) && (font.glyphs[0].value != codepoint)) index = fallbackIndex;
   1360 #else
   1361     index = codepoint - 32;
   1362 #endif
   1363 
   1364     return index;
   1365 }
   1366 
   1367 // Get glyph font info data for a codepoint (unicode character)
   1368 // NOTE: If codepoint is not found in the font it fallbacks to '?'
   1369 GlyphInfo GetGlyphInfo(Font font, int codepoint)
   1370 {
   1371     GlyphInfo info = { 0 };
   1372 
   1373     info = font.glyphs[GetGlyphIndex(font, codepoint)];
   1374 
   1375     return info;
   1376 }
   1377 
   1378 // Get glyph rectangle in font atlas for a codepoint (unicode character)
   1379 // NOTE: If codepoint is not found in the font it fallbacks to '?'
   1380 Rectangle GetGlyphAtlasRec(Font font, int codepoint)
   1381 {
   1382     Rectangle rec = { 0 };
   1383 
   1384     rec = font.recs[GetGlyphIndex(font, codepoint)];
   1385 
   1386     return rec;
   1387 }
   1388 
   1389 //----------------------------------------------------------------------------------
   1390 // Text strings management functions
   1391 //----------------------------------------------------------------------------------
   1392 // Get text length in bytes, check for \0 character
   1393 unsigned int TextLength(const char *text)
   1394 {
   1395     unsigned int length = 0;
   1396 
   1397     if (text != NULL)
   1398     {
   1399         // NOTE: Alternative: use strlen(text)
   1400 
   1401         while (*text++) length++;
   1402     }
   1403 
   1404     return length;
   1405 }
   1406 
   1407 // Formatting of text with variables to 'embed'
   1408 // WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
   1409 const char *TextFormat(const char *text, ...)
   1410 {
   1411 #ifndef MAX_TEXTFORMAT_BUFFERS
   1412     #define MAX_TEXTFORMAT_BUFFERS 4        // Maximum number of static buffers for text formatting
   1413 #endif
   1414 
   1415     // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
   1416     static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
   1417     static int index = 0;
   1418 
   1419     char *currentBuffer = buffers[index];
   1420     memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH);   // Clear buffer before using
   1421 
   1422     va_list args;
   1423     va_start(args, text);
   1424     int requiredByteCount = vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
   1425     va_end(args);
   1426 
   1427     // If requiredByteCount is larger than the MAX_TEXT_BUFFER_LENGTH, then overflow occured
   1428     if (requiredByteCount >= MAX_TEXT_BUFFER_LENGTH)
   1429     {
   1430         // Inserting "..." at the end of the string to mark as truncated
   1431         char *truncBuffer = buffers[index] + MAX_TEXT_BUFFER_LENGTH - 4; // Adding 4 bytes = "...\0"
   1432         sprintf(truncBuffer, "...");
   1433     }
   1434 
   1435     index += 1;     // Move to next buffer for next function call
   1436     if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
   1437 
   1438     return currentBuffer;
   1439 }
   1440 
   1441 // Get integer value from text
   1442 // NOTE: This function replaces atoi() [stdlib.h]
   1443 int TextToInteger(const char *text)
   1444 {
   1445     int value = 0;
   1446     int sign = 1;
   1447 
   1448     if ((text[0] == '+') || (text[0] == '-'))
   1449     {
   1450         if (text[0] == '-') sign = -1;
   1451         text++;
   1452     }
   1453 
   1454     for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0');
   1455 
   1456     return value*sign;
   1457 }
   1458 
   1459 // Get float value from text
   1460 // NOTE: This function replaces atof() [stdlib.h]
   1461 // WARNING: Only '.' character is understood as decimal point
   1462 float TextToFloat(const char *text)
   1463 {
   1464     float value = 0.0f;
   1465     float sign = 1.0f;
   1466 
   1467     if ((text[0] == '+') || (text[0] == '-'))
   1468     {
   1469         if (text[0] == '-') sign = -1.0f;
   1470         text++;
   1471     }
   1472 
   1473     int i = 0;
   1474     for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0');
   1475 
   1476     if (text[i++] == '.')
   1477     {
   1478         float divisor = 10.0f;
   1479         for (; ((text[i] >= '0') && (text[i] <= '9')); i++)
   1480         {
   1481             value += ((float)(text[i] - '0'))/divisor;
   1482             divisor = divisor*10.0f;
   1483         }
   1484     }
   1485 
   1486     return value*sign;
   1487 }
   1488 
   1489 #if defined(SUPPORT_TEXT_MANIPULATION)
   1490 // Copy one string to another, returns bytes copied
   1491 int TextCopy(char *dst, const char *src)
   1492 {
   1493     int bytes = 0;
   1494 
   1495     if ((src != NULL) && (dst != NULL))
   1496     {
   1497         // NOTE: Alternative: use strcpy(dst, src)
   1498 
   1499         while (*src != '\0')
   1500         {
   1501             *dst = *src;
   1502             dst++;
   1503             src++;
   1504 
   1505             bytes++;
   1506         }
   1507 
   1508         *dst = '\0';
   1509     }
   1510 
   1511     return bytes;
   1512 }
   1513 
   1514 // Check if two text string are equal
   1515 // REQUIRES: strcmp()
   1516 bool TextIsEqual(const char *text1, const char *text2)
   1517 {
   1518     bool result = false;
   1519 
   1520     if ((text1 != NULL) && (text2 != NULL))
   1521     {
   1522         if (strcmp(text1, text2) == 0) result = true;
   1523     }
   1524 
   1525     return result;
   1526 }
   1527 
   1528 // Get a piece of a text string
   1529 const char *TextSubtext(const char *text, int position, int length)
   1530 {
   1531     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
   1532     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1533 
   1534     int textLength = TextLength(text);
   1535 
   1536     if (position >= textLength)
   1537     {
   1538         position = textLength - 1;
   1539         length = 0;
   1540     }
   1541 
   1542     if (length >= textLength) length = textLength;
   1543 
   1544     // NOTE: Alternative: memcpy(buffer, text + position, length)
   1545 
   1546     for (int c = 0 ; c < length ; c++)
   1547     {
   1548         *(buffer + c) = *(text + position);
   1549         text++;
   1550     }
   1551 
   1552     *(buffer + length) = '\0';
   1553 
   1554     return buffer;
   1555 }
   1556 
   1557 // Replace text string
   1558 // REQUIRES: strlen(), strstr(), strncpy(), strcpy()
   1559 // WARNING: Allocated memory must be manually freed
   1560 char *TextReplace(const char *text, const char *replace, const char *by)
   1561 {
   1562     // Sanity checks and initialization
   1563     if (!text || !replace || !by) return NULL;
   1564 
   1565     char *result = NULL;
   1566 
   1567     char *insertPoint = NULL;   // Next insert point
   1568     char *temp = NULL;          // Temp pointer
   1569     int replaceLen = 0;         // Replace string length of (the string to remove)
   1570     int byLen = 0;              // Replacement length (the string to replace by)
   1571     int lastReplacePos = 0;     // Distance between replace and end of last replace
   1572     int count = 0;              // Number of replacements
   1573 
   1574     replaceLen = TextLength(replace);
   1575     if (replaceLen == 0) return NULL;  // Empty replace causes infinite loop during count
   1576 
   1577     byLen = TextLength(by);
   1578 
   1579     // Count the number of replacements needed
   1580     insertPoint = (char *)text;
   1581     for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
   1582 
   1583     // Allocate returning string and point temp to it
   1584     temp = result = (char *)RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
   1585 
   1586     if (!result) return NULL;   // Memory could not be allocated
   1587 
   1588     // First time through the loop, all the variable are set correctly from here on,
   1589     //  - 'temp' points to the end of the result string
   1590     //  - 'insertPoint' points to the next occurrence of replace in text
   1591     //  - 'text' points to the remainder of text after "end of replace"
   1592     while (count--)
   1593     {
   1594         insertPoint = strstr(text, replace);
   1595         lastReplacePos = (int)(insertPoint - text);
   1596         temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
   1597         temp = strcpy(temp, by) + byLen;
   1598         text += lastReplacePos + replaceLen; // Move to next "end of replace"
   1599     }
   1600 
   1601     // Copy remaind text part after replacement to result (pointed by moving temp)
   1602     strcpy(temp, text);
   1603 
   1604     return result;
   1605 }
   1606 
   1607 // Insert text in a specific position, moves all text forward
   1608 // WARNING: Allocated memory must be manually freed
   1609 char *TextInsert(const char *text, const char *insert, int position)
   1610 {
   1611     int textLen = TextLength(text);
   1612     int insertLen = TextLength(insert);
   1613 
   1614     char *result = (char *)RL_MALLOC(textLen + insertLen + 1);
   1615 
   1616     for (int i = 0; i < position; i++) result[i] = text[i];
   1617     for (int i = position; i < insertLen + position; i++) result[i] = insert[i];
   1618     for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
   1619 
   1620     result[textLen + insertLen] = '\0';     // Make sure text string is valid!
   1621 
   1622     return result;
   1623 }
   1624 
   1625 // Join text strings with delimiter
   1626 // REQUIRES: memset(), memcpy()
   1627 const char *TextJoin(const char **textList, int count, const char *delimiter)
   1628 {
   1629     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
   1630     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1631     char *textPtr = buffer;
   1632 
   1633     int totalLength = 0;
   1634     int delimiterLen = TextLength(delimiter);
   1635 
   1636     for (int i = 0; i < count; i++)
   1637     {
   1638         int textLength = TextLength(textList[i]);
   1639 
   1640         // Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
   1641         if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
   1642         {
   1643             memcpy(textPtr, textList[i], textLength);
   1644             totalLength += textLength;
   1645             textPtr += textLength;
   1646 
   1647             if ((delimiterLen > 0) && (i < (count - 1)))
   1648             {
   1649                 memcpy(textPtr, delimiter, delimiterLen);
   1650                 totalLength += delimiterLen;
   1651                 textPtr += delimiterLen;
   1652             }
   1653         }
   1654     }
   1655 
   1656     return buffer;
   1657 }
   1658 
   1659 // Split string into multiple strings
   1660 // REQUIRES: memset()
   1661 const char **TextSplit(const char *text, char delimiter, int *count)
   1662 {
   1663     // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
   1664     // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
   1665     // all used memory is static... it has some limitations:
   1666     //      1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT
   1667     //      2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
   1668 
   1669     static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
   1670     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
   1671     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1672 
   1673     result[0] = buffer;
   1674     int counter = 0;
   1675 
   1676     if (text != NULL)
   1677     {
   1678         counter = 1;
   1679 
   1680         // Count how many substrings we have on text and point to every one
   1681         for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
   1682         {
   1683             buffer[i] = text[i];
   1684             if (buffer[i] == '\0') break;
   1685             else if (buffer[i] == delimiter)
   1686             {
   1687                 buffer[i] = '\0';   // Set an end of string at this point
   1688                 result[counter] = buffer + i + 1;
   1689                 counter++;
   1690 
   1691                 if (counter == MAX_TEXTSPLIT_COUNT) break;
   1692             }
   1693         }
   1694     }
   1695 
   1696     *count = counter;
   1697     return result;
   1698 }
   1699 
   1700 // Append text at specific position and move cursor
   1701 // WARNING: It's up to the user to make sure appended text does not overflow the buffer!
   1702 // REQUIRES: strcpy()
   1703 void TextAppend(char *text, const char *append, int *position)
   1704 {
   1705     strcpy(text + *position, append);
   1706     *position += TextLength(append);
   1707 }
   1708 
   1709 // Find first text occurrence within a string
   1710 // REQUIRES: strstr()
   1711 int TextFindIndex(const char *text, const char *find)
   1712 {
   1713     int position = -1;
   1714 
   1715     char *ptr = strstr(text, find);
   1716 
   1717     if (ptr != NULL) position = (int)(ptr - text);
   1718 
   1719     return position;
   1720 }
   1721 
   1722 // Get upper case version of provided string
   1723 // WARNING: Limited functionality, only basic characters set
   1724 // TODO: Support UTF-8 diacritics to upper-case, check codepoints
   1725 const char *TextToUpper(const char *text)
   1726 {
   1727     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
   1728     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1729 
   1730     if (text != NULL)
   1731     {
   1732         for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
   1733         {
   1734             if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
   1735             else buffer[i] = text[i];
   1736         }
   1737     }
   1738 
   1739     return buffer;
   1740 }
   1741 
   1742 // Get lower case version of provided string
   1743 // WARNING: Limited functionality, only basic characters set
   1744 const char *TextToLower(const char *text)
   1745 {
   1746     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
   1747     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1748 
   1749     if (text != NULL)
   1750     {
   1751         for (int i = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[i] != '\0'); i++)
   1752         {
   1753             if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
   1754             else buffer[i] = text[i];
   1755         }
   1756     }
   1757 
   1758     return buffer;
   1759 }
   1760 
   1761 // Get Pascal case notation version of provided string
   1762 // WARNING: Limited functionality, only basic characters set
   1763 const char *TextToPascal(const char *text)
   1764 {
   1765     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
   1766     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1767 
   1768     if (text != NULL)
   1769     {
   1770         // Upper case first character
   1771         if ((text[0] >= 'a') && (text[0] <= 'z')) buffer[0] = text[0] - 32;
   1772         else buffer[0] = text[0];
   1773 
   1774         // Check for next separator to upper case another character
   1775         for (int i = 1, j = 1; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
   1776         {
   1777             if (text[j] != '_') buffer[i] = text[j];
   1778             else
   1779             {
   1780                 j++;
   1781                 if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32;
   1782             }
   1783         }
   1784     }
   1785 
   1786     return buffer;
   1787 }
   1788 
   1789 // Get snake case notation version of provided string
   1790 // WARNING: Limited functionality, only basic characters set
   1791 const char *TextToSnake(const char *text)
   1792 {
   1793     static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
   1794     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1795 
   1796     if (text != NULL)
   1797     {
   1798         // Check for next separator to upper case another character
   1799         for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
   1800         {
   1801             if ((text[j] >= 'A') && (text[j] <= 'Z'))
   1802             {
   1803                 if (i >= 1)
   1804                 {
   1805                     buffer[i] = '_';
   1806                     i++;
   1807                 }
   1808                 buffer[i] = text[j] + 32;
   1809             }
   1810             else buffer[i] = text[j];
   1811         }
   1812     }
   1813 
   1814     return buffer;
   1815 }
   1816 
   1817 // Get Camel case notation version of provided string
   1818 // WARNING: Limited functionality, only basic characters set
   1819 const char *TextToCamel(const char *text)
   1820 {
   1821     static char buffer[MAX_TEXT_BUFFER_LENGTH] = {0};
   1822     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
   1823 
   1824     if (text != NULL)
   1825     {
   1826         // Lower case first character
   1827         if ((text[0] >= 'A') && (text[0] <= 'Z')) buffer[0] = text[0] + 32;
   1828         else buffer[0] = text[0];
   1829 
   1830         // Check for next separator to upper case another character
   1831         for (int i = 1, j = 1; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++)
   1832         {
   1833             if (text[j] != '_') buffer[i] = text[j];
   1834             else
   1835             {
   1836                 j++;
   1837                 if ((text[j] >= 'a') && (text[j] <= 'z')) buffer[i] = text[j] - 32;
   1838             }
   1839         }
   1840     }
   1841 
   1842     return buffer;
   1843 }
   1844 
   1845 // Encode text codepoint into UTF-8 text
   1846 // REQUIRES: memcpy()
   1847 // WARNING: Allocated memory must be manually freed
   1848 char *LoadUTF8(const int *codepoints, int length)
   1849 {
   1850     // We allocate enough memory to fit all possible codepoints
   1851     // NOTE: 5 bytes for every codepoint should be enough
   1852     char *text = (char *)RL_CALLOC(length*5, 1);
   1853     const char *utf8 = NULL;
   1854     int size = 0;
   1855 
   1856     for (int i = 0, bytes = 0; i < length; i++)
   1857     {
   1858         utf8 = CodepointToUTF8(codepoints[i], &bytes);
   1859         memcpy(text + size, utf8, bytes);
   1860         size += bytes;
   1861     }
   1862 
   1863     // Resize memory to text length + string NULL terminator
   1864     void *ptr = RL_REALLOC(text, size + 1);
   1865 
   1866     if (ptr != NULL) text = (char *)ptr;
   1867 
   1868     return text;
   1869 }
   1870 
   1871 // Unload UTF-8 text encoded from codepoints array
   1872 void UnloadUTF8(char *text)
   1873 {
   1874     RL_FREE(text);
   1875 }
   1876 
   1877 // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter
   1878 int *LoadCodepoints(const char *text, int *count)
   1879 {
   1880     int textLength = TextLength(text);
   1881 
   1882     int codepointSize = 0;
   1883     int codepointCount = 0;
   1884 
   1885     // Allocate a big enough buffer to store as many codepoints as text bytes
   1886     int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int));
   1887 
   1888     for (int i = 0; i < textLength; codepointCount++)
   1889     {
   1890         codepoints[codepointCount] = GetCodepointNext(text + i, &codepointSize);
   1891         i += codepointSize;
   1892     }
   1893 
   1894     // Re-allocate buffer to the actual number of codepoints loaded
   1895     codepoints = (int *)RL_REALLOC(codepoints, codepointCount*sizeof(int));
   1896 
   1897     *count = codepointCount;
   1898 
   1899     return codepoints;
   1900 }
   1901 
   1902 // Unload codepoints data from memory
   1903 void UnloadCodepoints(int *codepoints)
   1904 {
   1905     RL_FREE(codepoints);
   1906 }
   1907 
   1908 // Get total number of characters(codepoints) in a UTF-8 encoded text, until '\0' is found
   1909 // NOTE: If an invalid UTF-8 sequence is encountered a '?'(0x3f) codepoint is counted instead
   1910 int GetCodepointCount(const char *text)
   1911 {
   1912     unsigned int length = 0;
   1913     char *ptr = (char *)&text[0];
   1914 
   1915     while (*ptr != '\0')
   1916     {
   1917         int next = 0;
   1918         GetCodepointNext(ptr, &next);
   1919 
   1920         ptr += next;
   1921 
   1922         length++;
   1923     }
   1924 
   1925     return length;
   1926 }
   1927 
   1928 // Encode codepoint into utf8 text (char array length returned as parameter)
   1929 // NOTE: It uses a static array to store UTF-8 bytes
   1930 const char *CodepointToUTF8(int codepoint, int *utf8Size)
   1931 {
   1932     static char utf8[6] = { 0 };
   1933     memset(utf8, 0, 6); // Clear static array
   1934     int size = 0;       // Byte size of codepoint
   1935 
   1936     if (codepoint <= 0x7f)
   1937     {
   1938         utf8[0] = (char)codepoint;
   1939         size = 1;
   1940     }
   1941     else if (codepoint <= 0x7ff)
   1942     {
   1943         utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
   1944         utf8[1] = (char)((codepoint & 0x3f) | 0x80);
   1945         size = 2;
   1946     }
   1947     else if (codepoint <= 0xffff)
   1948     {
   1949         utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
   1950         utf8[1] = (char)(((codepoint >>  6) & 0x3f) | 0x80);
   1951         utf8[2] = (char)((codepoint & 0x3f) | 0x80);
   1952         size = 3;
   1953     }
   1954     else if (codepoint <= 0x10ffff)
   1955     {
   1956         utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
   1957         utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
   1958         utf8[2] = (char)(((codepoint >>  6) & 0x3f) | 0x80);
   1959         utf8[3] = (char)((codepoint & 0x3f) | 0x80);
   1960         size = 4;
   1961     }
   1962 
   1963     *utf8Size = size;
   1964 
   1965     return utf8;
   1966 }
   1967 #endif      // SUPPORT_TEXT_MANIPULATION
   1968 
   1969 // Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
   1970 // When an invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
   1971 // Total number of bytes processed are returned as a parameter
   1972 // NOTE: The standard says U+FFFD should be returned in case of errors
   1973 // but that character is not supported by the default font in raylib
   1974 int GetCodepoint(const char *text, int *codepointSize)
   1975 {
   1976 /*
   1977     UTF-8 specs from https://www.ietf.org/rfc/rfc3629.txt
   1978 
   1979     Char. number range  |        UTF-8 octet sequence
   1980       (hexadecimal)    |              (binary)
   1981     --------------------+---------------------------------------------
   1982     0000 0000-0000 007F | 0xxxxxxx
   1983     0000 0080-0000 07FF | 110xxxxx 10xxxxxx
   1984     0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
   1985     0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   1986 */
   1987     // NOTE: on decode errors we return as soon as possible
   1988 
   1989     int codepoint = 0x3f;   // Codepoint (defaults to '?')
   1990     int octet = (unsigned char)(text[0]); // The first UTF8 octet
   1991     *codepointSize = 1;
   1992 
   1993     if (octet <= 0x7f)
   1994     {
   1995         // Only one octet (ASCII range x00-7F)
   1996         codepoint = text[0];
   1997     }
   1998     else if ((octet & 0xe0) == 0xc0)
   1999     {
   2000         // Two octets
   2001 
   2002         // [0]xC2-DF    [1]UTF8-tail(x80-BF)
   2003         unsigned char octet1 = text[1];
   2004 
   2005         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *codepointSize = 2; return codepoint; } // Unexpected sequence
   2006 
   2007         if ((octet >= 0xc2) && (octet <= 0xdf))
   2008         {
   2009             codepoint = ((octet & 0x1f) << 6) | (octet1 & 0x3f);
   2010             *codepointSize = 2;
   2011         }
   2012     }
   2013     else if ((octet & 0xf0) == 0xe0)
   2014     {
   2015         // Three octets
   2016         unsigned char octet1 = text[1];
   2017         unsigned char octet2 = '\0';
   2018 
   2019         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *codepointSize = 2; return codepoint; } // Unexpected sequence
   2020 
   2021         octet2 = text[2];
   2022 
   2023         if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *codepointSize = 3; return codepoint; } // Unexpected sequence
   2024 
   2025         // [0]xE0    [1]xA0-BF       [2]UTF8-tail(x80-BF)
   2026         // [0]xE1-EC [1]UTF8-tail    [2]UTF8-tail(x80-BF)
   2027         // [0]xED    [1]x80-9F       [2]UTF8-tail(x80-BF)
   2028         // [0]xEE-EF [1]UTF8-tail    [2]UTF8-tail(x80-BF)
   2029 
   2030         if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
   2031             ((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *codepointSize = 2; return codepoint; }
   2032 
   2033         if ((octet >= 0xe0) && (octet <= 0xef))
   2034         {
   2035             codepoint = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
   2036             *codepointSize = 3;
   2037         }
   2038     }
   2039     else if ((octet & 0xf8) == 0xf0)
   2040     {
   2041         // Four octets
   2042         if (octet > 0xf4) return codepoint;
   2043 
   2044         unsigned char octet1 = text[1];
   2045         unsigned char octet2 = '\0';
   2046         unsigned char octet3 = '\0';
   2047 
   2048         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *codepointSize = 2; return codepoint; }  // Unexpected sequence
   2049 
   2050         octet2 = text[2];
   2051 
   2052         if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *codepointSize = 3; return codepoint; }  // Unexpected sequence
   2053 
   2054         octet3 = text[3];
   2055 
   2056         if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *codepointSize = 4; return codepoint; }  // Unexpected sequence
   2057 
   2058         // [0]xF0       [1]x90-BF       [2]UTF8-tail  [3]UTF8-tail
   2059         // [0]xF1-F3    [1]UTF8-tail    [2]UTF8-tail  [3]UTF8-tail
   2060         // [0]xF4       [1]x80-8F       [2]UTF8-tail  [3]UTF8-tail
   2061 
   2062         if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) ||
   2063             ((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *codepointSize = 2; return codepoint; } // Unexpected sequence
   2064 
   2065         if (octet >= 0xf0)
   2066         {
   2067             codepoint = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f);
   2068             *codepointSize = 4;
   2069         }
   2070     }
   2071 
   2072     if (codepoint > 0x10ffff) codepoint = 0x3f;     // Codepoints after U+10ffff are invalid
   2073 
   2074     return codepoint;
   2075 }
   2076 
   2077 // Get next codepoint in a byte sequence and bytes processed
   2078 int GetCodepointNext(const char *text, int *codepointSize)
   2079 {
   2080     const char *ptr = text;
   2081     int codepoint = 0x3f;       // Codepoint (defaults to '?')
   2082     *codepointSize = 1;
   2083 
   2084     // Get current codepoint and bytes processed
   2085     if (0xf0 == (0xf8 & ptr[0]))
   2086     {
   2087         // 4 byte UTF-8 codepoint
   2088         if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
   2089         codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]);
   2090         *codepointSize = 4;
   2091     }
   2092     else if (0xe0 == (0xf0 & ptr[0]))
   2093     {
   2094         // 3 byte UTF-8 codepoint */
   2095         if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } // 10xxxxxx checks
   2096         codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]);
   2097         *codepointSize = 3;
   2098     }
   2099     else if (0xc0 == (0xe0 & ptr[0]))
   2100     {
   2101         // 2 byte UTF-8 codepoint
   2102         if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } // 10xxxxxx checks
   2103         codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]);
   2104         *codepointSize = 2;
   2105     }
   2106     else if (0x00 == (0x80 & ptr[0]))
   2107     {
   2108         // 1 byte UTF-8 codepoint
   2109         codepoint = ptr[0];
   2110         *codepointSize = 1;
   2111     }
   2112 
   2113     return codepoint;
   2114 }
   2115 
   2116 // Get previous codepoint in a byte sequence and bytes processed
   2117 int GetCodepointPrevious(const char *text, int *codepointSize)
   2118 {
   2119     const char *ptr = text;
   2120     int codepoint = 0x3f;       // Codepoint (defaults to '?')
   2121     int cpSize = 0;
   2122     *codepointSize = 0;
   2123 
   2124     // Move to previous codepoint
   2125     do ptr--;
   2126     while (((0x80 & ptr[0]) != 0) && ((0xc0 & ptr[0]) ==  0x80));
   2127 
   2128     codepoint = GetCodepointNext(ptr, &cpSize);
   2129 
   2130     if (codepoint != 0) *codepointSize = cpSize;
   2131 
   2132     return codepoint;
   2133 }
   2134 
   2135 //----------------------------------------------------------------------------------
   2136 // Module specific Functions Definition
   2137 //----------------------------------------------------------------------------------
   2138 #if defined(SUPPORT_FILEFORMAT_FNT) || defined(SUPPORT_FILEFORMAT_BDF)
   2139 // Read a line from memory
   2140 // REQUIRES: memcpy()
   2141 // NOTE: Returns the number of bytes read
   2142 static int GetLine(const char *origin, char *buffer, int maxLength)
   2143 {
   2144     int count = 0;
   2145     for (; count < maxLength - 1; count++) if (origin[count] == '\n') break;
   2146     memcpy(buffer, origin, count);
   2147     buffer[count] = '\0';
   2148     return count;
   2149 }
   2150 #endif
   2151 
   2152 #if defined(SUPPORT_FILEFORMAT_FNT)
   2153 // Load a BMFont file (AngelCode font file)
   2154 // REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
   2155 static Font LoadBMFont(const char *fileName)
   2156 {
   2157     #define MAX_BUFFER_SIZE       256
   2158     #define MAX_FONT_IMAGE_PAGES    8
   2159 
   2160     Font font = { 0 };
   2161 
   2162     char buffer[MAX_BUFFER_SIZE] = { 0 };
   2163     char *searchPoint = NULL;
   2164 
   2165     int fontSize = 0;
   2166     int glyphCount = 0;
   2167 
   2168     int imWidth = 0;
   2169     int imHeight = 0;
   2170     int pageCount = 1;
   2171     char imFileName[MAX_FONT_IMAGE_PAGES][129] = { 0 };
   2172 
   2173     int base = 0;       // Useless data
   2174     int readBytes = 0;  // Data bytes read
   2175     int readVars = 0;   // Variables filled by sscanf()
   2176 
   2177     char *fileText = LoadFileText(fileName);
   2178 
   2179     if (fileText == NULL) return font;
   2180 
   2181     char *fileTextPtr = fileText;
   2182 
   2183     // NOTE: We skip first line, it contains no useful information
   2184     readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
   2185     fileTextPtr += (readBytes + 1);
   2186 
   2187     // Read line data
   2188     readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
   2189     searchPoint = strstr(buffer, "lineHeight");
   2190     readVars = sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i pages=%i", &fontSize, &base, &imWidth, &imHeight, &pageCount);
   2191     fileTextPtr += (readBytes + 1);
   2192 
   2193     if (readVars < 4) { UnloadFileText(fileText); return font; } // Some data not available, file malformed
   2194 
   2195     if (pageCount > MAX_FONT_IMAGE_PAGES)
   2196     {
   2197         TRACELOG(LOG_WARNING, "FONT: [%s] Font defines more pages than supported: %i/%i", fileName, pageCount, MAX_FONT_IMAGE_PAGES);
   2198         pageCount = MAX_FONT_IMAGE_PAGES;
   2199     }
   2200 
   2201     for (int i = 0; i < pageCount; i++)
   2202     {
   2203         readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
   2204         searchPoint = strstr(buffer, "file");
   2205         readVars = sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName[i]);
   2206         fileTextPtr += (readBytes + 1);
   2207 
   2208         if (readVars < 1) { UnloadFileText(fileText); return font; } // No fileName read
   2209     }
   2210 
   2211     readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
   2212     searchPoint = strstr(buffer, "count");
   2213     readVars = sscanf(searchPoint, "count=%i", &glyphCount);
   2214     fileTextPtr += (readBytes + 1);
   2215 
   2216     if (readVars < 1) { UnloadFileText(fileText); return font; } // No glyphCount read
   2217 
   2218     // Load all required images for further compose
   2219     Image *imFonts = (Image *)RL_CALLOC(pageCount, sizeof(Image)); // Font atlases, multiple images
   2220 
   2221     for (int i = 0; i < pageCount; i++)
   2222     {
   2223         imFonts[i] = LoadImage(TextFormat("%s/%s", GetDirectoryPath(fileName), imFileName[i]));
   2224 
   2225         if (imFonts[i].format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
   2226         {
   2227             // Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
   2228             Image imFontAlpha = {
   2229                 .data = RL_CALLOC(imFonts[i].width*imFonts[i].height, 2),
   2230                 .width = imFonts[i].width,
   2231                 .height = imFonts[i].height,
   2232                 .mipmaps = 1,
   2233                 .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
   2234             };
   2235 
   2236             for (int p = 0, pi = 0; p < (imFonts[i].width*imFonts[i].height*2); p += 2, pi++)
   2237             {
   2238                 ((unsigned char *)(imFontAlpha.data))[p] = 0xff;
   2239                 ((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFonts[i].data)[pi];
   2240             }
   2241 
   2242             UnloadImage(imFonts[i]);
   2243             imFonts[i] = imFontAlpha;
   2244         }
   2245     }
   2246 
   2247     Image fullFont = imFonts[0];
   2248     for (int i = 1; i < pageCount; i++) UnloadImage(imFonts[i]);
   2249 
   2250     // If multiple atlas, then merge atlas
   2251     // NOTE: WARNING: This process could be really slow!
   2252     if (pageCount > 1)
   2253     {
   2254         // Resize font atlas to draw additional images
   2255         ImageResizeCanvas(&fullFont, imWidth, imHeight*pageCount, 0, 0, BLACK);
   2256 
   2257         for (int i = 1; i < pageCount; i++)
   2258         {
   2259             Rectangle srcRec = { 0.0f, 0.0f, (float)imWidth, (float)imHeight };
   2260             Rectangle destRec = { 0.0f, (float)imHeight*(float)i, (float)imWidth, (float)imHeight };
   2261             ImageDraw(&fullFont, imFonts[i], srcRec, destRec, WHITE);
   2262         }
   2263     }
   2264 
   2265     RL_FREE(imFonts);
   2266 
   2267     if (isGpuReady) font.texture = LoadTextureFromImage(fullFont);
   2268 
   2269     // Fill font characters info data
   2270     font.baseSize = fontSize;
   2271     font.glyphCount = glyphCount;
   2272     font.glyphPadding = 0;
   2273     font.glyphs = (GlyphInfo *)RL_MALLOC(glyphCount*sizeof(GlyphInfo));
   2274     font.recs = (Rectangle *)RL_MALLOC(glyphCount*sizeof(Rectangle));
   2275 
   2276     int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX, pageID;
   2277 
   2278     for (int i = 0; i < glyphCount; i++)
   2279     {
   2280         readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
   2281         readVars = sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i page=%i",
   2282                        &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX, &pageID);
   2283         fileTextPtr += (readBytes + 1);
   2284 
   2285         if (readVars == 9)  // Make sure all char data has been properly read
   2286         {
   2287             // Get character rectangle in the font atlas texture
   2288             font.recs[i] = (Rectangle){ (float)charX, (float)charY + (float)imHeight*pageID, (float)charWidth, (float)charHeight };
   2289 
   2290             // Save data properly in sprite font
   2291             font.glyphs[i].value = charId;
   2292             font.glyphs[i].offsetX = charOffsetX;
   2293             font.glyphs[i].offsetY = charOffsetY;
   2294             font.glyphs[i].advanceX = charAdvanceX;
   2295 
   2296             // Fill character image data from full font data
   2297             font.glyphs[i].image = ImageFromImage(fullFont, font.recs[i]);
   2298         }
   2299         else
   2300         {
   2301             font.glyphs[i].image = GenImageColor((int)font.recs[i].width, (int)font.recs[i].height, BLACK);
   2302             TRACELOG(LOG_WARNING, "FONT: [%s] Some characters data not correctly provided", fileName);
   2303         }
   2304     }
   2305 
   2306     UnloadImage(fullFont);
   2307     UnloadFileText(fileText);
   2308 
   2309     if (isGpuReady && (font.texture.id == 0))
   2310     {
   2311         UnloadFont(font);
   2312         font = GetFontDefault();
   2313         TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName);
   2314     }
   2315     else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully (%i glyphs)", fileName, font.glyphCount);
   2316 
   2317     return font;
   2318 }
   2319 
   2320 #endif
   2321 
   2322 #if defined(SUPPORT_FILEFORMAT_BDF)
   2323 
   2324 // Convert hexadecimal to decimal (single digit)
   2325 static unsigned char HexToInt(char hex)
   2326 {
   2327     if (hex >= '0' && hex <= '9') return hex - '0';
   2328     else if (hex >= 'a' && hex <= 'f') return hex - 'a' + 10;
   2329     else if (hex >= 'A' && hex <= 'F') return hex - 'A' + 10;
   2330     else return 0;
   2331 }
   2332 
   2333 // Load font data for further use
   2334 // NOTE: Requires BDF font memory data
   2335 static GlyphInfo *LoadFontDataBDF(const unsigned char *fileData, int dataSize, int *codepoints, int codepointCount, int *outFontSize)
   2336 {
   2337     #define MAX_BUFFER_SIZE 256
   2338 
   2339     char buffer[MAX_BUFFER_SIZE] = { 0 };
   2340 
   2341     GlyphInfo *glyphs = NULL;
   2342     bool genFontChars = false;
   2343 
   2344     int totalReadBytes = 0;         // Data bytes read (total)
   2345     int readBytes = 0;              // Data bytes read (line)
   2346     int readVars = 0;               // Variables filled by sscanf()
   2347 
   2348     const char *fileText = (const char *)fileData;
   2349     const char *fileTextPtr = fileText;
   2350 
   2351     bool fontMalformed = false;     // Is the font malformed
   2352     bool fontStarted = false;       // Has font started (STARTFONT)
   2353     int fontBBw = 0;                // Font base character bounding box width
   2354     int fontBBh = 0;                // Font base character bounding box height
   2355     int fontBBxoff0 = 0;            // Font base character bounding box X0 offset
   2356     int fontBByoff0 = 0;            // Font base character bounding box Y0 offset
   2357     int fontAscent = 0;             // Font ascent
   2358 
   2359     bool charStarted = false;       // Has character started (STARTCHAR)
   2360     bool charBitmapStarted = false; // Has bitmap data started (BITMAP)
   2361     int charBitmapNextRow = 0;      // Y position for the next row of bitmap data
   2362     int charEncoding = -1;          // The unicode value of the character (-1 if not set)
   2363     int charBBw = 0;                // Character bounding box width
   2364     int charBBh = 0;                // Character bounding box height
   2365     int charBBxoff0 = 0;            // Character bounding box X0 offset
   2366     int charBByoff0 = 0;            // Character bounding box Y0 offset
   2367     int charDWidthX = 0;            // Character advance X
   2368     int charDWidthY = 0;            // Character advance Y (unused)
   2369     GlyphInfo *charGlyphInfo = NULL; // Pointer to output glyph info (NULL if not set)
   2370 
   2371     if (fileData == NULL) return glyphs;
   2372 
   2373     // In case no chars count provided, default to 95
   2374     codepointCount = (codepointCount > 0)? codepointCount : 95;
   2375 
   2376     // Fill fontChars in case not provided externally
   2377     // NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
   2378     if (codepoints == NULL)
   2379     {
   2380         codepoints = (int *)RL_MALLOC(codepointCount*sizeof(int));
   2381         for (int i = 0; i < codepointCount; i++) codepoints[i] = i + 32;
   2382         genFontChars = true;
   2383     }
   2384 
   2385     glyphs = (GlyphInfo *)RL_CALLOC(codepointCount, sizeof(GlyphInfo));
   2386 
   2387     while (totalReadBytes <= dataSize)
   2388     {
   2389         readBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
   2390         totalReadBytes += (readBytes + 1);
   2391         fileTextPtr += (readBytes + 1);
   2392 
   2393         // Line: COMMENT
   2394         if (strstr(buffer, "COMMENT") != NULL) continue; // Ignore line
   2395 
   2396         if (charStarted)
   2397         {
   2398             // Line: ENDCHAR
   2399             if (strstr(buffer, "ENDCHAR") != NULL)
   2400             {
   2401                 charStarted = false;
   2402                 continue;
   2403             }
   2404 
   2405             if (charBitmapStarted)
   2406             {
   2407                 if (charGlyphInfo != NULL)
   2408                 {
   2409                     int pixelY = charBitmapNextRow++;
   2410 
   2411                     if (pixelY >= charGlyphInfo->image.height) break;
   2412 
   2413                     for (int x = 0; x < readBytes; x++)
   2414                     {
   2415                         unsigned char byte = HexToInt(buffer[x]);
   2416 
   2417                         for (int bitX = 0; bitX < 4; bitX++)
   2418                         {
   2419                             int pixelX = ((x*4) + bitX);
   2420 
   2421                             if (pixelX >= charGlyphInfo->image.width) break;
   2422 
   2423                             if ((byte & (8 >> bitX)) > 0) ((unsigned char *)charGlyphInfo->image.data)[(pixelY*charGlyphInfo->image.width) + pixelX] = 255;
   2424                         }
   2425                     }
   2426                 }
   2427                 continue;
   2428             }
   2429 
   2430             // Line: ENCODING
   2431             if (strstr(buffer, "ENCODING") != NULL)
   2432             {
   2433                 readVars = sscanf(buffer, "ENCODING %i", &charEncoding);
   2434                 continue;
   2435             }
   2436 
   2437             // Line: BBX
   2438             if (strstr(buffer, "BBX") != NULL)
   2439             {
   2440                 readVars = sscanf(buffer, "BBX %i %i %i %i", &charBBw, &charBBh, &charBBxoff0, &charBByoff0);
   2441                 continue;
   2442             }
   2443 
   2444             // Line: DWIDTH
   2445             if (strstr(buffer, "DWIDTH") != NULL)
   2446             {
   2447                 readVars = sscanf(buffer, "DWIDTH %i %i", &charDWidthX, &charDWidthY);
   2448                 continue;
   2449             }
   2450 
   2451             // Line: BITMAP
   2452             if (strstr(buffer, "BITMAP") != NULL)
   2453             {
   2454                 // Search for glyph index in codepoints
   2455                 charGlyphInfo = NULL;
   2456 
   2457                 for (int codepointIndex = 0; codepointIndex < codepointCount; codepointIndex++)
   2458                 {
   2459                     if (codepoints[codepointIndex] == charEncoding)
   2460                     {
   2461                         charGlyphInfo = &glyphs[codepointIndex];
   2462                         break;
   2463                     }
   2464                 }
   2465 
   2466                 // Init glyph info
   2467                 if (charGlyphInfo != NULL)
   2468                 {
   2469                     charGlyphInfo->value = charEncoding;
   2470                     charGlyphInfo->offsetX = charBBxoff0 + fontBByoff0;
   2471                     charGlyphInfo->offsetY = fontBBh - (charBBh + charBByoff0 + fontBByoff0 + fontAscent);
   2472                     charGlyphInfo->advanceX = charDWidthX;
   2473 
   2474                     charGlyphInfo->image.data = RL_CALLOC(charBBw*charBBh, 1);
   2475                     charGlyphInfo->image.width = charBBw;
   2476                     charGlyphInfo->image.height = charBBh;
   2477                     charGlyphInfo->image.mipmaps = 1;
   2478                     charGlyphInfo->image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
   2479                 }
   2480 
   2481                 charBitmapStarted = true;
   2482                 charBitmapNextRow = 0;
   2483 
   2484                 continue;
   2485             }
   2486         }
   2487         else if (fontStarted)
   2488         {
   2489             // Line: ENDFONT
   2490             if (strstr(buffer, "ENDFONT") != NULL)
   2491             {
   2492                 fontStarted = false;
   2493                 break;
   2494             }
   2495 
   2496             // Line: SIZE
   2497             if (strstr(buffer, "SIZE") != NULL)
   2498             {
   2499                 if (outFontSize != NULL) readVars = sscanf(buffer, "SIZE %i", outFontSize);
   2500                 continue;
   2501             }
   2502 
   2503             // PIXEL_SIZE
   2504             if (strstr(buffer, "PIXEL_SIZE") != NULL)
   2505             {
   2506                 if (outFontSize != NULL) readVars = sscanf(buffer, "PIXEL_SIZE %i", outFontSize);
   2507                 continue;
   2508             }
   2509 
   2510             // FONTBOUNDINGBOX
   2511             if (strstr(buffer, "FONTBOUNDINGBOX") != NULL)
   2512             {
   2513                 readVars = sscanf(buffer, "FONTBOUNDINGBOX %i %i %i %i", &fontBBw, &fontBBh, &fontBBxoff0, &fontBByoff0);
   2514                 continue;
   2515             }
   2516 
   2517             // FONT_ASCENT
   2518             if (strstr(buffer, "FONT_ASCENT") != NULL)
   2519             {
   2520                 readVars = sscanf(buffer, "FONT_ASCENT %i", &fontAscent);
   2521                 continue;
   2522             }
   2523 
   2524             // STARTCHAR
   2525             if (strstr(buffer, "STARTCHAR") != NULL)
   2526             {
   2527                 charStarted = true;
   2528                 charEncoding = -1;
   2529                 charGlyphInfo = NULL;
   2530                 charBBw = 0;
   2531                 charBBh = 0;
   2532                 charBBxoff0 = 0;
   2533                 charBByoff0 = 0;
   2534                 charDWidthX = 0;
   2535                 charDWidthY = 0;
   2536                 charGlyphInfo = NULL;
   2537                 charBitmapStarted = false;
   2538                 charBitmapNextRow = 0;
   2539                 continue;
   2540             }
   2541         }
   2542         else
   2543         {
   2544             // STARTFONT
   2545             if (strstr(buffer, "STARTFONT") != NULL)
   2546             {
   2547                 if (fontStarted)
   2548                 {
   2549                     fontMalformed = true;
   2550                     break;
   2551                 }
   2552                 else
   2553                 {
   2554                     fontStarted = true;
   2555                     continue;
   2556                 }
   2557             }
   2558         }
   2559     }
   2560 
   2561     if (genFontChars) RL_FREE(codepoints);
   2562 
   2563     if (fontMalformed)
   2564     {
   2565         RL_FREE(glyphs);
   2566         glyphs = NULL;
   2567     }
   2568 
   2569     return glyphs;
   2570 }
   2571 #endif      // SUPPORT_FILEFORMAT_BDF
   2572 
   2573 #endif      // SUPPORT_MODULE_RTEXT