]> git.sesse.net Git - pistorm/blob - raylib/text.c
Add Meson build files.
[pistorm] / raylib / text.c
1 /**********************************************************************************************
2 *
3 *   raylib.text - Basic functions to load Fonts and draw Text
4 *
5 *   CONFIGURATION:
6 *
7 *   #define SUPPORT_FILEFORMAT_FNT
8 *   #define SUPPORT_FILEFORMAT_TTF
9 *       Selected desired fileformats to be supported for loading. Some of those formats are
10 *       supported by default, to remove support, just comment unrequired #define in this module
11 *
12 *   #define SUPPORT_DEFAULT_FONT
13 *       Load default raylib font on initialization to be used by DrawText() and MeasureText().
14 *       If no default font loaded, DrawTextEx() and MeasureTextEx() are required.
15 *
16 *   #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
17 *       TextSplit() function static buffer max size
18 *
19 *   #define MAX_TEXTSPLIT_COUNT
20 *       TextSplit() function static substrings pointers array (pointing to static buffer)
21 *
22 *
23 *   DEPENDENCIES:
24 *       stb_truetype  - Load TTF file and rasterize characters data
25 *       stb_rect_pack - Rectangles packing algorythms, required for font atlas generation
26 *
27 *
28 *   LICENSE: zlib/libpng
29 *
30 *   Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
31 *
32 *   This software is provided "as-is", without any express or implied warranty. In no event
33 *   will the authors be held liable for any damages arising from the use of this software.
34 *
35 *   Permission is granted to anyone to use this software for any purpose, including commercial
36 *   applications, and to alter it and redistribute it freely, subject to the following restrictions:
37 *
38 *     1. The origin of this software must not be misrepresented; you must not claim that you
39 *     wrote the original software. If you use this software in a product, an acknowledgment
40 *     in the product documentation would be appreciated but is not required.
41 *
42 *     2. Altered source versions must be plainly marked as such, and must not be misrepresented
43 *     as being the original software.
44 *
45 *     3. This notice may not be removed or altered from any source distribution.
46 *
47 **********************************************************************************************/
48
49 #include "raylib.h"         // Declares module functions
50
51 // Check if config flags have been externally provided on compilation line
52 #if !defined(EXTERNAL_CONFIG_FLAGS)
53     #include "config.h"     // Defines module configuration flags
54 #endif
55
56 #include <stdlib.h>         // Required for: malloc(), free()
57 #include <stdio.h>          // Required for: vsprintf()
58 #include <string.h>         // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
59 #include <stdarg.h>         // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
60 #include <ctype.h>          // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
61
62 #include "utils.h"          // Required for: LoadFileText()
63
64 #if defined(SUPPORT_FILEFORMAT_TTF)
65     #define STB_RECT_PACK_IMPLEMENTATION
66     #include "external/stb_rect_pack.h"     // Required for: ttf font rectangles packaging
67
68     #define STBTT_STATIC
69     #define STB_TRUETYPE_IMPLEMENTATION
70     #include "external/stb_truetype.h"      // Required for: ttf font data reading
71 #endif
72
73 //----------------------------------------------------------------------------------
74 // Defines and Macros
75 //----------------------------------------------------------------------------------
76 #ifndef MAX_TEXT_BUFFER_LENGTH
77     #define MAX_TEXT_BUFFER_LENGTH              1024        // Size of internal static buffers used on some functions:
78                                                             // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
79 #endif
80 #ifndef MAX_TEXT_UNICODE_CHARS
81     #define MAX_TEXT_UNICODE_CHARS               512        // Maximum number of unicode codepoints: GetCodepoints()
82 #endif
83 #ifndef MAX_TEXTSPLIT_COUNT
84     #define MAX_TEXTSPLIT_COUNT                  128        // Maximum number of substrings to split: TextSplit()
85 #endif
86
87 //----------------------------------------------------------------------------------
88 // Types and Structures Definition
89 //----------------------------------------------------------------------------------
90 // ...
91
92 //----------------------------------------------------------------------------------
93 // Global variables
94 //----------------------------------------------------------------------------------
95 #if defined(SUPPORT_DEFAULT_FONT)
96 // Default font provided by raylib
97 // NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
98 static Font defaultFont = { 0 };
99 #endif
100
101 //----------------------------------------------------------------------------------
102 // Other Modules Functions Declaration (required by text)
103 //----------------------------------------------------------------------------------
104 //...
105
106 //----------------------------------------------------------------------------------
107 // Module specific Functions Declaration
108 //----------------------------------------------------------------------------------
109 #if defined(SUPPORT_FILEFORMAT_FNT)
110 static Font LoadBMFont(const char *fileName);     // Load a BMFont file (AngelCode font file)
111 #endif
112
113 #if defined(SUPPORT_DEFAULT_FONT)
114 extern void LoadFontDefault(void);
115 extern void UnloadFontDefault(void);
116 #endif
117
118 //----------------------------------------------------------------------------------
119 // Module Functions Definition
120 //----------------------------------------------------------------------------------
121 #if defined(SUPPORT_DEFAULT_FONT)
122
123 // Load raylib default font
124 extern void LoadFontDefault(void)
125 {
126     #define BIT_CHECK(a,b) ((a) & (1u << (b)))
127
128     // NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
129     // Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
130
131     defaultFont.charsCount = 224;   // Number of chars included in our default font
132     defaultFont.charsPadding = 0;   // Characters padding
133
134     // Default font is directly defined here (data generated from a sprite font image)
135     // This way, we reconstruct Font without creating large global variables
136     // This data is automatically allocated to Stack and automatically deallocated at the end of this function
137     unsigned int defaultFontData[512] = {
138         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f,
139         0x4a2bf2a0, 0x0852091e, 0x41224000, 0x10041450, 0x2e292020, 0x08220812, 0x41222000, 0x10041450, 0x10f92020, 0x3efa084c, 0x7d22103c, 0x107df7de,
140         0xe8a12020, 0x08220832, 0x05220800, 0x10450410, 0xa4a3f000, 0x08520832, 0x05220400, 0x10450410, 0xe2f92020, 0x0002085e, 0x7d3e0281, 0x107df41f,
141         0x00200000, 0x8001b000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
142         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xc0000fbe, 0xfbf7e00f, 0x5fbf7e7d, 0x0050bee8, 0x440808a2, 0x0a142fe8, 0x50810285, 0x0050a048,
143         0x49e428a2, 0x0a142828, 0x40810284, 0x0048a048, 0x10020fbe, 0x09f7ebaf, 0xd89f3e84, 0x0047a04f, 0x09e48822, 0x0a142aa1, 0x50810284, 0x0048a048,
144         0x04082822, 0x0a142fa0, 0x50810285, 0x0050a248, 0x00008fbe, 0xfbf42021, 0x5f817e7d, 0x07d09ce8, 0x00008000, 0x00000fe0, 0x00000000, 0x00000000,
145         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000c0180,
146         0xdfbf4282, 0x0bfbf7ef, 0x42850505, 0x004804bf, 0x50a142c6, 0x08401428, 0x42852505, 0x00a808a0, 0x50a146aa, 0x08401428, 0x42852505, 0x00081090,
147         0x5fa14a92, 0x0843f7e8, 0x7e792505, 0x00082088, 0x40a15282, 0x08420128, 0x40852489, 0x00084084, 0x40a16282, 0x0842022a, 0x40852451, 0x00088082,
148         0xc0bf4282, 0xf843f42f, 0x7e85fc21, 0x3e0900bf, 0x00000000, 0x00000004, 0x00000000, 0x000c0180, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
149         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000402, 0x41482000, 0x00000000, 0x00000800,
150         0x04000404, 0x4100203c, 0x00000000, 0x00000800, 0xf7df7df0, 0x514bef85, 0xbefbefbe, 0x04513bef, 0x14414500, 0x494a2885, 0xa28a28aa, 0x04510820,
151         0xf44145f0, 0x474a289d, 0xa28a28aa, 0x04510be0, 0x14414510, 0x494a2884, 0xa28a28aa, 0x02910a00, 0xf7df7df0, 0xd14a2f85, 0xbefbe8aa, 0x011f7be0,
152         0x00000000, 0x00400804, 0x20080000, 0x00000000, 0x00000000, 0x00600f84, 0x20080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
153         0xac000000, 0x00000f01, 0x00000000, 0x00000000, 0x24000000, 0x00000f01, 0x00000000, 0x06000000, 0x24000000, 0x00000f01, 0x00000000, 0x09108000,
154         0x24fa28a2, 0x00000f01, 0x00000000, 0x013e0000, 0x2242252a, 0x00000f52, 0x00000000, 0x038a8000, 0x2422222a, 0x00000f29, 0x00000000, 0x010a8000,
155         0x2412252a, 0x00000f01, 0x00000000, 0x010a8000, 0x24fbe8be, 0x00000f01, 0x00000000, 0x0ebe8000, 0xac020000, 0x00000f01, 0x00000000, 0x00048000,
156         0x0003e000, 0x00000f00, 0x00000000, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000038, 0x8443b80e, 0x00203a03,
157         0x02bea080, 0xf0000020, 0xc452208a, 0x04202b02, 0xf8029122, 0x07f0003b, 0xe44b388e, 0x02203a02, 0x081e8a1c, 0x0411e92a, 0xf4420be0, 0x01248202,
158         0xe8140414, 0x05d104ba, 0xe7c3b880, 0x00893a0a, 0x283c0e1c, 0x04500902, 0xc4400080, 0x00448002, 0xe8208422, 0x04500002, 0x80400000, 0x05200002,
159         0x083e8e00, 0x04100002, 0x804003e0, 0x07000042, 0xf8008400, 0x07f00003, 0x80400000, 0x04000022, 0x00000000, 0x00000000, 0x80400000, 0x04000002,
160         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00800702, 0x1848a0c2, 0x84010000, 0x02920921, 0x01042642, 0x00005121, 0x42023f7f, 0x00291002,
161         0xefc01422, 0x7efdfbf7, 0xefdfa109, 0x03bbbbf7, 0x28440f12, 0x42850a14, 0x20408109, 0x01111010, 0x28440408, 0x42850a14, 0x2040817f, 0x01111010,
162         0xefc78204, 0x7efdfbf7, 0xe7cf8109, 0x011111f3, 0x2850a932, 0x42850a14, 0x2040a109, 0x01111010, 0x2850b840, 0x42850a14, 0xefdfbf79, 0x03bbbbf7,
163         0x001fa020, 0x00000000, 0x00001000, 0x00000000, 0x00002070, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
164         0x08022800, 0x00012283, 0x02430802, 0x01010001, 0x8404147c, 0x20000144, 0x80048404, 0x00823f08, 0xdfbf4284, 0x7e03f7ef, 0x142850a1, 0x0000210a,
165         0x50a14684, 0x528a1428, 0x142850a1, 0x03efa17a, 0x50a14a9e, 0x52521428, 0x142850a1, 0x02081f4a, 0x50a15284, 0x4a221428, 0xf42850a1, 0x03efa14b,
166         0x50a16284, 0x4a521428, 0x042850a1, 0x0228a17a, 0xdfbf427c, 0x7e8bf7ef, 0xf7efdfbf, 0x03efbd0b, 0x00000000, 0x04000000, 0x00000000, 0x00000008,
167         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200508, 0x00840400, 0x11458122, 0x00014210,
168         0x00514294, 0x51420800, 0x20a22a94, 0x0050a508, 0x00200000, 0x00000000, 0x00050000, 0x08000000, 0xfefbefbe, 0xfbefbefb, 0xfbeb9114, 0x00fbefbe,
169         0x20820820, 0x8a28a20a, 0x8a289114, 0x3e8a28a2, 0xfefbefbe, 0xfbefbe0b, 0x8a289114, 0x008a28a2, 0x228a28a2, 0x08208208, 0x8a289114, 0x088a28a2,
170         0xfefbefbe, 0xfbefbefb, 0xfa2f9114, 0x00fbefbe, 0x00000000, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0x00000000, 0x00000000,
171         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00210100, 0x00000004, 0x00000000, 0x00000000, 0x14508200, 0x00001402, 0x00000000, 0x00000000,
172         0x00000010, 0x00000020, 0x00000000, 0x00000000, 0xa28a28be, 0x00002228, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000,
173         0xa28a28aa, 0x000022a8, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000, 0xbefbefbe, 0x00003e2f, 0x00000000, 0x00000000,
174         0x00000004, 0x00002028, 0x00000000, 0x00000000, 0x80000000, 0x00003e0f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
175         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
176         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
177         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
178         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
179         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
180         0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
181
182     int charsHeight = 10;
183     int charsDivisor = 1;    // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
184
185     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,
186                             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,
187                             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,
188                             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,
189                             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,
190                             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,
191                             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 };
192
193     // Re-construct image from defaultFontData and generate OpenGL texture
194     //----------------------------------------------------------------------
195     Image imFont = {
196         .data = calloc(128*128, 2),  // 2 bytes per pixel (gray + alpha)
197         .width = 128,
198         .height = 128,
199         .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,
200         .mipmaps = 1
201     };
202
203     // Fill image.data with defaultFontData (convert from bit to pixel!)
204     for (int i = 0, counter = 0; i < imFont.width*imFont.height; i += 32)
205     {
206         for (int j = 31; j >= 0; j--)
207         {
208             if (BIT_CHECK(defaultFontData[counter], j))
209             {
210                 // NOTE: We are unreferencing data as short, so,
211                 // we must consider data as little-endian order (alpha + gray)
212                 ((unsigned short *)imFont.data)[i + j] = 0xffff;
213             }
214             else ((unsigned short *)imFont.data)[i + j] = 0x00ff;
215         }
216
217         counter++;
218     }
219
220     defaultFont.texture = LoadTextureFromImage(imFont);
221
222     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
223     //------------------------------------------------------------------------------
224
225     // Allocate space for our characters info data
226     // NOTE: This memory should be freed at end! --> CloseWindow()
227     defaultFont.chars = (CharInfo *)RL_MALLOC(defaultFont.charsCount*sizeof(CharInfo));
228     defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.charsCount*sizeof(Rectangle));
229
230     int currentLine = 0;
231     int currentPosX = charsDivisor;
232     int testPosX = charsDivisor;
233
234     for (int i = 0; i < defaultFont.charsCount; i++)
235     {
236         defaultFont.chars[i].value = 32 + i;  // First char is 32
237
238         defaultFont.recs[i].x = (float)currentPosX;
239         defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor));
240         defaultFont.recs[i].width = (float)charsWidth[i];
241         defaultFont.recs[i].height = (float)charsHeight;
242
243         testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
244
245         if (testPosX >= defaultFont.texture.width)
246         {
247             currentLine++;
248             currentPosX = 2*charsDivisor + charsWidth[i];
249             testPosX = currentPosX;
250
251             defaultFont.recs[i].x = (float)charsDivisor;
252             defaultFont.recs[i].y = (float)(charsDivisor + currentLine*(charsHeight + charsDivisor));
253         }
254         else currentPosX = testPosX;
255
256         // NOTE: On default font character offsets and xAdvance are not required
257         defaultFont.chars[i].offsetX = 0;
258         defaultFont.chars[i].offsetY = 0;
259         defaultFont.chars[i].advanceX = 0;
260
261         // Fill character image data from fontClear data
262         defaultFont.chars[i].image = ImageFromImage(imFont, defaultFont.recs[i]);
263     }
264
265     UnloadImage(imFont);
266
267     defaultFont.baseSize = (int)defaultFont.recs[0].height;
268
269     TRACELOG(LOG_INFO, "FONT: Default font loaded successfully");
270 }
271
272 // Unload raylib default font
273 extern void UnloadFontDefault(void)
274 {
275     for (int i = 0; i < defaultFont.charsCount; i++) UnloadImage(defaultFont.chars[i].image);
276     UnloadTexture(defaultFont.texture);
277     RL_FREE(defaultFont.chars);
278     RL_FREE(defaultFont.recs);
279 }
280 #endif      // SUPPORT_DEFAULT_FONT
281
282 // Get the default font, useful to be used with extended parameters
283 Font GetFontDefault()
284 {
285 #if defined(SUPPORT_DEFAULT_FONT)
286     return defaultFont;
287 #else
288     Font font = { 0 };
289     return font;
290 #endif
291 }
292
293 // Load Font from file into GPU memory (VRAM)
294 Font LoadFont(const char *fileName)
295 {
296     // Default values for ttf font generation
297 #ifndef FONT_TTF_DEFAULT_SIZE
298     #define FONT_TTF_DEFAULT_SIZE           32      // TTF font generation default char size (char-height)
299 #endif
300 #ifndef FONT_TTF_DEFAULT_NUMCHARS
301     #define FONT_TTF_DEFAULT_NUMCHARS       95      // TTF font generation default charset: 95 glyphs (ASCII 32..126)
302 #endif
303 #ifndef FONT_TTF_DEFAULT_FIRST_CHAR
304     #define FONT_TTF_DEFAULT_FIRST_CHAR     32      // TTF font generation default first char for image sprite font (32-Space)
305 #endif
306 #ifndef FONT_TTF_DEFAULT_CHARS_PADDING
307     #define FONT_TTF_DEFAULT_CHARS_PADDING   4      // TTF font generation default chars padding
308 #endif
309
310     Font font = { 0 };
311
312 #if defined(SUPPORT_FILEFORMAT_TTF)
313     if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
314     else
315 #endif
316 #if defined(SUPPORT_FILEFORMAT_FNT)
317     if (IsFileExtension(fileName, ".fnt")) font = LoadBMFont(fileName);
318     else
319 #endif
320     {
321         Image image = LoadImage(fileName);
322         if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR);
323         UnloadImage(image);
324     }
325
326     if (font.texture.id == 0)
327     {
328         TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
329         font = GetFontDefault();
330     }
331     else SetTextureFilter(font.texture, TEXTURE_FILTER_POINT);    // By default we set point filter (best performance)
332
333     return font;
334 }
335
336 // Load Font from TTF font file with generation parameters
337 // NOTE: You can pass an array with desired characters, those characters should be available in the font
338 // if array is NULL, default char set is selected 32..126
339 Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCount)
340 {
341     Font font = { 0 };
342
343     // Loading file to memory
344     unsigned int fileSize = 0;
345     unsigned char *fileData = LoadFileData(fileName, &fileSize);
346
347     if (fileData != NULL)
348     {
349         // Loading font from memory data
350         font = LoadFontFromMemory(GetFileExtension(fileName), fileData, fileSize, fontSize, fontChars, charsCount);
351
352         RL_FREE(fileData);
353     }
354     else font = GetFontDefault();
355
356     return font;
357 }
358
359 // Load an Image font file (XNA style)
360 Font LoadFontFromImage(Image image, Color key, int firstChar)
361 {
362 #ifndef MAX_GLYPHS_FROM_IMAGE
363     #define MAX_GLYPHS_FROM_IMAGE   256     // Maximum number of glyphs supported on image scan
364 #endif
365
366     #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
367
368     int charSpacing = 0;
369     int lineSpacing = 0;
370
371     int x = 0;
372     int y = 0;
373
374     // We allocate a temporal arrays for chars data measures,
375     // once we get the actual number of chars, we copy data to a sized arrays
376     int tempCharValues[MAX_GLYPHS_FROM_IMAGE];
377     Rectangle tempCharRecs[MAX_GLYPHS_FROM_IMAGE];
378
379     Color *pixels = LoadImageColors(image);
380
381     // Parse image data to get charSpacing and lineSpacing
382     for (y = 0; y < image.height; y++)
383     {
384         for (x = 0; x < image.width; x++)
385         {
386             if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
387         }
388
389         if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
390     }
391
392     charSpacing = x;
393     lineSpacing = y;
394
395     int charHeight = 0;
396     int j = 0;
397
398     while (!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++;
399
400     charHeight = j;
401
402     // Check array values to get characters: value, x, y, w, h
403     int index = 0;
404     int lineToRead = 0;
405     int xPosToRead = charSpacing;
406
407     // Parse image data to get rectangle sizes
408     while ((lineSpacing + lineToRead*(charHeight + lineSpacing)) < image.height)
409     {
410         while ((xPosToRead < image.width) &&
411               !COLOR_EQUAL((pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead]), key))
412         {
413             tempCharValues[index] = firstChar + index;
414
415             tempCharRecs[index].x = (float)xPosToRead;
416             tempCharRecs[index].y = (float)(lineSpacing + lineToRead*(charHeight + lineSpacing));
417             tempCharRecs[index].height = (float)charHeight;
418
419             int charWidth = 0;
420
421             while (!COLOR_EQUAL(pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++;
422
423             tempCharRecs[index].width = (float)charWidth;
424
425             index++;
426
427             xPosToRead += (charWidth + charSpacing);
428         }
429
430         lineToRead++;
431         xPosToRead = charSpacing;
432     }
433
434     // NOTE: We need to remove key color borders from image to avoid weird
435     // artifacts on texture scaling when using TEXTURE_FILTER_BILINEAR or TEXTURE_FILTER_TRILINEAR
436     for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
437
438     // Create a new image with the processed color data (key color replaced by BLANK)
439     Image fontClear = {
440         .data = pixels,
441         .width = image.width,
442         .height = image.height,
443         .format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
444         .mipmaps = 1
445     };
446
447     // Create spritefont with all data parsed from image
448     Font font = { 0 };
449
450     font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
451     font.charsCount = index;
452     font.charsPadding = 0;
453
454     // We got tempCharValues and tempCharsRecs populated with chars data
455     // Now we move temp data to sized charValues and charRecs arrays
456     font.chars = (CharInfo *)RL_MALLOC(font.charsCount*sizeof(CharInfo));
457     font.recs = (Rectangle *)RL_MALLOC(font.charsCount*sizeof(Rectangle));
458
459     for (int i = 0; i < font.charsCount; i++)
460     {
461         font.chars[i].value = tempCharValues[i];
462
463         // Get character rectangle in the font atlas texture
464         font.recs[i] = tempCharRecs[i];
465
466         // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
467         font.chars[i].offsetX = 0;
468         font.chars[i].offsetY = 0;
469         font.chars[i].advanceX = 0;
470
471         // Fill character image data from fontClear data
472         font.chars[i].image = ImageFromImage(fontClear, tempCharRecs[i]);
473     }
474
475     UnloadImage(fontClear);     // Unload processed image once converted to texture
476
477     font.baseSize = (int)font.recs[0].height;
478
479     return font;
480 }
481
482 // Load font from memory buffer, fileType refers to extension: i.e. ".ttf"
483 Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount)
484 {
485     Font font = { 0 };
486
487     char fileExtLower[16] = { 0 };
488     strcpy(fileExtLower, TextToLower(fileType));
489
490 #if defined(SUPPORT_FILEFORMAT_TTF)
491     if (TextIsEqual(fileExtLower, ".ttf") ||
492         TextIsEqual(fileExtLower, ".otf"))
493     {
494         font.baseSize = fontSize;
495         font.charsCount = (charsCount > 0)? charsCount : 95;
496         font.charsPadding = 0;
497         font.chars = LoadFontData(fileData, dataSize, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
498
499         if (font.chars != NULL)
500         {
501             font.charsPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
502
503             Image atlas = GenImageFontAtlas(font.chars, &font.recs, font.charsCount, font.baseSize, font.charsPadding, 0);
504             font.texture = LoadTextureFromImage(atlas);
505
506             // Update chars[i].image to use alpha, required to be used on ImageDrawText()
507             for (int i = 0; i < font.charsCount; i++)
508             {
509                 UnloadImage(font.chars[i].image);
510                 font.chars[i].image = ImageFromImage(atlas, font.recs[i]);
511             }
512
513             UnloadImage(atlas);
514         }
515         else font = GetFontDefault();
516     }
517 #else
518     font = GetFontDefault();
519 #endif
520
521     return font;
522 }
523
524 // Load font data for further use
525 // NOTE: Requires TTF font memory data and can generate SDF data
526 CharInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int charsCount, int type)
527 {
528     // NOTE: Using some SDF generation default values,
529     // trades off precision with ability to handle *smaller* sizes
530 #ifndef FONT_SDF_CHAR_PADDING
531     #define FONT_SDF_CHAR_PADDING            4      // SDF font generation char padding
532 #endif
533 #ifndef FONT_SDF_ON_EDGE_VALUE
534     #define FONT_SDF_ON_EDGE_VALUE         128      // SDF font generation on edge value
535 #endif
536 #ifndef FONT_SDF_PIXEL_DIST_SCALE
537     #define FONT_SDF_PIXEL_DIST_SCALE     64.0f     // SDF font generation pixel distance scale
538 #endif
539 #ifndef FONT_BITMAP_ALPHA_THRESHOLD
540     #define FONT_BITMAP_ALPHA_THRESHOLD     80      // Bitmap (B&W) font generation alpha threshold
541 #endif
542
543     CharInfo *chars = NULL;
544
545 #if defined(SUPPORT_FILEFORMAT_TTF)
546     // Load font data (including pixel data) from TTF memory file
547     // NOTE: Loaded information should be enough to generate font image atlas, using any packaging method
548     if (fileData != NULL)
549     {
550         int genFontChars = false;
551         stbtt_fontinfo fontInfo = { 0 };
552
553         if (stbtt_InitFont(&fontInfo, (unsigned char *)fileData, 0))     // Init font for data reading
554         {
555             // Calculate font scale factor
556             float scaleFactor = stbtt_ScaleForPixelHeight(&fontInfo, (float)fontSize);
557
558             // Calculate font basic metrics
559             // NOTE: ascent is equivalent to font baseline
560             int ascent, descent, lineGap;
561             stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
562
563             // In case no chars count provided, default to 95
564             charsCount = (charsCount > 0)? charsCount : 95;
565
566             // Fill fontChars in case not provided externally
567             // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
568
569             if (fontChars == NULL)
570             {
571                 fontChars = (int *)RL_MALLOC(charsCount*sizeof(int));
572                 for (int i = 0; i < charsCount; i++) fontChars[i] = i + 32;
573                 genFontChars = true;
574             }
575
576             chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo));
577
578             // NOTE: Using simple packaging, one char after another
579             for (int i = 0; i < charsCount; i++)
580             {
581                 int chw = 0, chh = 0;   // Character width and height (on generation)
582                 int ch = fontChars[i];  // Character value to get info for
583                 chars[i].value = ch;
584
585                 //  Render a unicode codepoint to a bitmap
586                 //      stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap
587                 //      stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be
588                 //      stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide
589
590                 if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
591                 else 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);
592                 else chars[i].image.data = NULL;
593
594                 stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
595                 chars[i].advanceX = (int)((float)chars[i].advanceX*scaleFactor);
596
597                 // Load characters images
598                 chars[i].image.width = chw;
599                 chars[i].image.height = chh;
600                 chars[i].image.mipmaps = 1;
601                 chars[i].image.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
602
603                 chars[i].offsetY += (int)((float)ascent*scaleFactor);
604
605                 // NOTE: We create an empty image for space character, it could be further required for atlas packing
606                 if (ch == 32)
607                 {
608                     Image imSpace = {
609                         .data = calloc(chars[i].advanceX*fontSize, 2),
610                         .width = chars[i].advanceX,
611                         .height = fontSize,
612                         .format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE,
613                         .mipmaps = 1
614                     };
615
616                     chars[i].image = imSpace;
617                 }
618
619                 if (type == FONT_BITMAP)
620                 {
621                     // Aliased bitmap (black & white) font generation, avoiding anti-aliasing
622                     // NOTE: For optimum results, bitmap font should be generated at base pixel size
623                     for (int p = 0; p < chw*chh; p++)
624                     {
625                         if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
626                         else ((unsigned char *)chars[i].image.data)[p] = 255;
627                     }
628                 }
629
630                 // Get bounding box for character (may be offset to account for chars that dip above or below the line)
631                 /*
632                 int chX1, chY1, chX2, chY2;
633                 stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
634
635                 TRACELOGD("FONT: Character box measures: %i, %i, %i, %i", chX1, chY1, chX2 - chX1, chY2 - chY1);
636                 TRACELOGD("FONT: Character offsetY: %i", (int)((float)ascent*scaleFactor) + chY1);
637                 */
638             }
639         }
640         else TRACELOG(LOG_WARNING, "FONT: Failed to process TTF font data");
641
642         if (genFontChars) RL_FREE(fontChars);
643     }
644 #endif
645
646     return chars;
647 }
648
649 // Generate image font atlas using chars info
650 // NOTE: Packing method: 0-Default, 1-Skyline
651 #if defined(SUPPORT_FILEFORMAT_TTF)
652 Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCount, int fontSize, int padding, int packMethod)
653 {
654     Image atlas = { 0 };
655
656     if (chars == NULL)
657     {
658         TraceLog(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
659         return atlas;
660     }
661
662     *charRecs = NULL;
663
664     // In case no chars count provided we suppose default of 95
665     charsCount = (charsCount > 0)? charsCount : 95;
666
667     // NOTE: Rectangles memory is loaded here!
668     Rectangle *recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle));
669
670     // Calculate image size based on required pixel area
671     // NOTE 1: Image is forced to be squared and POT... very conservative!
672     // NOTE 2: SDF font characters already contain an internal padding,
673     // so image size would result bigger than default font type
674     float requiredArea = 0;
675     for (int i = 0; i < charsCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding));
676     float guessSize = sqrtf(requiredArea)*1.3f;
677     int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2)));  // Calculate next POT
678
679     atlas.width = imageSize;   // Atlas bitmap width
680     atlas.height = imageSize;  // Atlas bitmap height
681     atlas.data = (unsigned char *)RL_CALLOC(1, atlas.width*atlas.height);      // Create a bitmap to store characters (8 bpp)
682     atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
683     atlas.mipmaps = 1;
684
685     // DEBUG: We can see padding in the generated image setting a gray background...
686     //for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100;
687
688     if (packMethod == 0)   // Use basic packing algorythm
689     {
690         int offsetX = padding;
691         int offsetY = padding;
692
693         // NOTE: Using simple packaging, one char after another
694         for (int i = 0; i < charsCount; i++)
695         {
696             // Copy pixel data from fc.data to atlas
697             for (int y = 0; y < chars[i].image.height; y++)
698             {
699                 for (int x = 0; x < chars[i].image.width; x++)
700                 {
701                     ((unsigned char *)atlas.data)[(offsetY + y)*atlas.width + (offsetX + x)] = ((unsigned char *)chars[i].image.data)[y*chars[i].image.width + x];
702                 }
703             }
704
705             // Fill chars rectangles in atlas info
706             recs[i].x = (float)offsetX;
707             recs[i].y = (float)offsetY;
708             recs[i].width = (float)chars[i].image.width;
709             recs[i].height = (float)chars[i].image.height;
710
711             // Move atlas position X for next character drawing
712             offsetX += (chars[i].image.width + 2*padding);
713
714             if (offsetX >= (atlas.width - chars[i].image.width - 2*padding))
715             {
716                 offsetX = padding;
717
718                 // NOTE: Be careful on offsetY for SDF fonts, by default SDF
719                 // use an internal padding of 4 pixels, it means char rectangle
720                 // height is bigger than fontSize, it could be up to (fontSize + 8)
721                 offsetY += (fontSize + 2*padding);
722
723                 if (offsetY > (atlas.height - fontSize - padding)) break;
724             }
725         }
726     }
727     else if (packMethod == 1)  // Use Skyline rect packing algorythm (stb_pack_rect)
728     {
729         stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
730         stbrp_node *nodes = (stbrp_node *)RL_MALLOC(charsCount*sizeof(*nodes));
731
732         stbrp_init_target(context, atlas.width, atlas.height, nodes, charsCount);
733         stbrp_rect *rects = (stbrp_rect *)RL_MALLOC(charsCount*sizeof(stbrp_rect));
734
735         // Fill rectangles for packaging
736         for (int i = 0; i < charsCount; i++)
737         {
738             rects[i].id = i;
739             rects[i].w = chars[i].image.width + 2*padding;
740             rects[i].h = chars[i].image.height + 2*padding;
741         }
742
743         // Package rectangles into atlas
744         stbrp_pack_rects(context, rects, charsCount);
745
746         for (int i = 0; i < charsCount; i++)
747         {
748             // It return char rectangles in atlas
749             recs[i].x = rects[i].x + (float)padding;
750             recs[i].y = rects[i].y + (float)padding;
751             recs[i].width = (float)chars[i].image.width;
752             recs[i].height = (float)chars[i].image.height;
753
754             if (rects[i].was_packed)
755             {
756                 // Copy pixel data from fc.data to atlas
757                 for (int y = 0; y < chars[i].image.height; y++)
758                 {
759                     for (int x = 0; x < chars[i].image.width; x++)
760                     {
761                         ((unsigned char *)atlas.data)[(rects[i].y + padding + y)*atlas.width + (rects[i].x + padding + x)] = ((unsigned char *)chars[i].image.data)[y*chars[i].image.width + x];
762                     }
763                 }
764             }
765             else TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", i);
766         }
767
768         RL_FREE(rects);
769         RL_FREE(nodes);
770         RL_FREE(context);
771     }
772
773     // TODO: Crop image if required for smaller size
774
775     // Convert image data from GRAYSCALE to GRAY_ALPHA
776     unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
777
778     for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2)
779     {
780         dataGrayAlpha[k] = 255;
781         dataGrayAlpha[k + 1] = ((unsigned char *)atlas.data)[i];
782     }
783
784     RL_FREE(atlas.data);
785     atlas.data = dataGrayAlpha;
786     atlas.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
787
788     *charRecs = recs;
789
790     return atlas;
791 }
792 #endif
793
794 // Unload font chars info data (RAM)
795 void UnloadFontData(CharInfo *chars, int charsCount)
796 {
797     for (int i = 0; i < charsCount; i++) UnloadImage(chars[i].image);
798
799     RL_FREE(chars);
800 }
801
802 // Unload Font from GPU memory (VRAM)
803 void UnloadFont(Font font)
804 {
805     // NOTE: Make sure font is not default font (fallback)
806     if (font.texture.id != GetFontDefault().texture.id)
807     {
808         UnloadFontData(font.chars, font.charsCount);
809         UnloadTexture(font.texture);
810         RL_FREE(font.recs);
811
812         TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
813     }
814 }
815
816 // Draw current FPS
817 // NOTE: Uses default font
818 void DrawFPS(int posX, int posY)
819 {
820     Color color = LIME; // good fps
821     int fps = GetFPS();
822
823     if (fps < 30 && fps >= 15) color = ORANGE;  // warning FPS
824     else if (fps < 15) color = RED;    // bad FPS
825
826     DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, color);
827 }
828
829 // Draw text (using default font)
830 // NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used
831 // NOTE: chars spacing is proportional to fontSize
832 void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
833 {
834     // Check if default font has been loaded
835     if (GetFontDefault().texture.id != 0)
836     {
837         Vector2 position = { (float)posX, (float)posY };
838
839         int defaultFontSize = 10;   // Default Font chars height in pixel
840         if (fontSize < defaultFontSize) fontSize = defaultFontSize;
841         int spacing = fontSize/defaultFontSize;
842
843         DrawTextEx(GetFontDefault(), text, position, (float)fontSize, (float)spacing, color);
844     }
845 }
846
847 // Draw text using Font
848 // NOTE: chars spacing is NOT proportional to fontSize
849 void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint)
850 {
851     int length = TextLength(text);      // Total length in bytes of the text, scanned by codepoints in loop
852
853     int textOffsetY = 0;            // Offset between lines (on line break '\n')
854     float textOffsetX = 0.0f;       // Offset X to next character to draw
855
856     float scaleFactor = fontSize/font.baseSize;     // Character quad scaling factor
857
858     for (int i = 0; i < length;)
859     {
860         // Get next codepoint from byte string and glyph index in font
861         int codepointByteCount = 0;
862         int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
863         int index = GetGlyphIndex(font, codepoint);
864
865         // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
866         // but we need to draw all of the bad bytes using the '?' symbol moving one byte
867         if (codepoint == 0x3f) codepointByteCount = 1;
868
869         if (codepoint == '\n')
870         {
871             // NOTE: Fixed line spacing of 1.5 line-height
872             // TODO: Support custom line spacing defined by user
873             textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
874             textOffsetX = 0.0f;
875         }
876         else
877         {
878             if ((codepoint != ' ') && (codepoint != '\t'))
879             {
880                 DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
881             }
882
883             if (font.chars[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
884             else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing);
885         }
886
887         i += codepointByteCount;   // Move text bytes counter to next codepoint
888     }
889 }
890
891 // Draw text using font inside rectangle limits
892 void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint)
893 {
894     DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE);
895 }
896
897 // Draw text using font inside rectangle limits with support for text selection
898 void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint)
899 {
900     int length = TextLength(text);  // Total length in bytes of the text, scanned by codepoints in loop
901
902     int textOffsetY = 0;            // Offset between lines (on line break '\n')
903     float textOffsetX = 0.0f;       // Offset X to next character to draw
904
905     float scaleFactor = fontSize/font.baseSize;     // Character quad scaling factor
906
907     // Word/character wrapping mechanism variables
908     enum { MEASURE_STATE = 0, DRAW_STATE = 1 };
909     int state = wordWrap? MEASURE_STATE : DRAW_STATE;
910
911     int startLine = -1;         // Index where to begin drawing (where a line begins)
912     int endLine = -1;           // Index where to stop drawing (where a line ends)
913     int lastk = -1;             // Holds last value of the character position
914
915     for (int i = 0, k = 0; i < length; i++, k++)
916     {
917         // Get next codepoint from byte string and glyph index in font
918         int codepointByteCount = 0;
919         int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
920         int index = GetGlyphIndex(font, codepoint);
921
922         // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
923         // but we need to draw all of the bad bytes using the '?' symbol moving one byte
924         if (codepoint == 0x3f) codepointByteCount = 1;
925         i += (codepointByteCount - 1);
926
927         int glyphWidth = 0;
928         if (codepoint != '\n')
929         {
930             glyphWidth = (font.chars[index].advanceX == 0)?
931                          (int)(font.recs[index].width*scaleFactor + spacing):
932                          (int)(font.chars[index].advanceX*scaleFactor + spacing);
933         }
934
935         // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
936         // We store this info in startLine and endLine, then we change states, draw the text between those two variables
937         // and change states again and again recursively until the end of the text (or until we get outside of the container).
938         // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
939         // and begin drawing on the next line before we can get outside the container.
940         if (state == MEASURE_STATE)
941         {
942             // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
943             // Ref: http://jkorpela.fi/chars/spaces.html
944             if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
945
946             if ((textOffsetX + glyphWidth + 1) >= rec.width)
947             {
948                 endLine = (endLine < 1)? i : endLine;
949                 if (i == endLine) endLine -= codepointByteCount;
950                 if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
951
952                 state = !state;
953             }
954             else if ((i + 1) == length)
955             {
956                 endLine = i;
957
958                 state = !state;
959             }
960             else if (codepoint == '\n') state = !state;
961
962             if (state == DRAW_STATE)
963             {
964                 textOffsetX = 0;
965                 i = startLine;
966                 glyphWidth = 0;
967
968                 // Save character position when we switch states
969                 int tmp = lastk;
970                 lastk = k - 1;
971                 k = tmp;
972             }
973         }
974         else
975         {
976             if (codepoint == '\n')
977             {
978                 if (!wordWrap)
979                 {
980                     textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
981                     textOffsetX = 0;
982                 }
983             }
984             else
985             {
986                 if (!wordWrap && ((textOffsetX + glyphWidth + 1) >= rec.width))
987                 {
988                     textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
989                     textOffsetX = 0;
990                 }
991
992                 // When text overflows rectangle height limit, just stop drawing
993                 if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break;
994
995                 // Draw selection background
996                 bool isGlyphSelected = false;
997                 if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
998                 {
999                     DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, (float)glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint);
1000                     isGlyphSelected = true;
1001                 }
1002
1003                 // Draw current character glyph
1004                 if ((codepoint != ' ') && (codepoint != '\t'))
1005                 {
1006                     DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint);
1007                 }
1008             }
1009
1010             if (wordWrap && (i == endLine))
1011             {
1012                 textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
1013                 textOffsetX = 0;
1014                 startLine = endLine;
1015                 endLine = -1;
1016                 glyphWidth = 0;
1017                 selectStart += lastk - k;
1018                 k = lastk;
1019
1020                 state = !state;
1021             }
1022         }
1023
1024         textOffsetX += glyphWidth;
1025     }
1026 }
1027
1028 // Draw one character (codepoint)
1029 void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint)
1030 {
1031     // Character index position in sprite font
1032     // NOTE: In case a codepoint is not available in the font, index returned points to '?'
1033     int index = GetGlyphIndex(font, codepoint);
1034     float scaleFactor = fontSize/font.baseSize;     // Character quad scaling factor
1035
1036     // Character destination rectangle on screen
1037     // NOTE: We consider charsPadding on drawing
1038     Rectangle dstRec = { position.x + font.chars[index].offsetX*scaleFactor - (float)font.charsPadding*scaleFactor,
1039                       position.y + font.chars[index].offsetY*scaleFactor - (float)font.charsPadding*scaleFactor,
1040                       (font.recs[index].width + 2.0f*font.charsPadding)*scaleFactor,
1041                       (font.recs[index].height + 2.0f*font.charsPadding)*scaleFactor };
1042
1043     // Character source rectangle from font texture atlas
1044     // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
1045     Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding,
1046                          font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding };
1047
1048     // Draw the character texture on the screen
1049     DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
1050 }
1051
1052 // Measure string width for default font
1053 int MeasureText(const char *text, int fontSize)
1054 {
1055     Vector2 vec = { 0.0f, 0.0f };
1056
1057     // Check if default font has been loaded
1058     if (GetFontDefault().texture.id != 0)
1059     {
1060         int defaultFontSize = 10;   // Default Font chars height in pixel
1061         if (fontSize < defaultFontSize) fontSize = defaultFontSize;
1062         int spacing = fontSize/defaultFontSize;
1063
1064         vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing);
1065     }
1066
1067     return (int)vec.x;
1068 }
1069
1070 // Measure string size for Font
1071 Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
1072 {
1073     int len = TextLength(text);
1074     int tempLen = 0;                // Used to count longer text line num chars
1075     int lenCounter = 0;
1076
1077     float textWidth = 0.0f;
1078     float tempTextWidth = 0.0f;     // Used to count longer text line width
1079
1080     float textHeight = (float)font.baseSize;
1081     float scaleFactor = fontSize/(float)font.baseSize;
1082
1083     int letter = 0;                 // Current character
1084     int index = 0;                  // Index position in sprite font
1085
1086     for (int i = 0; i < len; i++)
1087     {
1088         lenCounter++;
1089
1090         int next = 0;
1091         letter = GetNextCodepoint(&text[i], &next);
1092         index = GetGlyphIndex(font, letter);
1093
1094         // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
1095         // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
1096         if (letter == 0x3f) next = 1;
1097         i += next - 1;
1098
1099         if (letter != '\n')
1100         {
1101             if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX;
1102             else textWidth += (font.recs[index].width + font.chars[index].offsetX);
1103         }
1104         else
1105         {
1106             if (tempTextWidth < textWidth) tempTextWidth = textWidth;
1107             lenCounter = 0;
1108             textWidth = 0;
1109             textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
1110         }
1111
1112         if (tempLen < lenCounter) tempLen = lenCounter;
1113     }
1114
1115     if (tempTextWidth < textWidth) tempTextWidth = textWidth;
1116
1117     Vector2 vec = { 0 };
1118     vec.x = tempTextWidth*scaleFactor + (float)((tempLen - 1)*spacing); // Adds chars spacing to measure
1119     vec.y = textHeight*scaleFactor;
1120
1121     return vec;
1122 }
1123
1124 // Returns index position for a unicode character on spritefont
1125 int GetGlyphIndex(Font font, int codepoint)
1126 {
1127 #ifndef GLYPH_NOTFOUND_CHAR_FALLBACK
1128     #define GLYPH_NOTFOUND_CHAR_FALLBACK     63      // Character used if requested codepoint is not found: '?'
1129 #endif
1130
1131 // Support charsets with any characters order
1132 #define SUPPORT_UNORDERED_CHARSET
1133 #if defined(SUPPORT_UNORDERED_CHARSET)
1134     int index = GLYPH_NOTFOUND_CHAR_FALLBACK;
1135
1136     for (int i = 0; i < font.charsCount; i++)
1137     {
1138         if (font.chars[i].value == codepoint)
1139         {
1140             index = i;
1141             break;
1142         }
1143     }
1144
1145     return index;
1146 #else
1147     return (codepoint - 32);
1148 #endif
1149 }
1150
1151 //----------------------------------------------------------------------------------
1152 // Text strings management functions
1153 //----------------------------------------------------------------------------------
1154 // Get text length in bytes, check for \0 character
1155 unsigned int TextLength(const char *text)
1156 {
1157     unsigned int length = 0; //strlen(text)
1158
1159     if (text != NULL)
1160     {
1161         while (*text++) length++;
1162     }
1163
1164     return length;
1165 }
1166
1167 // Formatting of text with variables to 'embed'
1168 // WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
1169 const char *TextFormat(const char *text, ...)
1170 {
1171 #ifndef MAX_TEXTFORMAT_BUFFERS
1172     #define MAX_TEXTFORMAT_BUFFERS 4        // Maximum number of static buffers for text formatting
1173 #endif
1174
1175     // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
1176     static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
1177     static int  index = 0;
1178
1179     char *currentBuffer = buffers[index];
1180     memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH);   // Clear buffer before using
1181
1182     va_list args;
1183     va_start(args, text);
1184     vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
1185     va_end(args);
1186
1187     index += 1;     // Move to next buffer for next function call
1188     if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
1189
1190     return currentBuffer;
1191 }
1192
1193 // Get integer value from text
1194 // NOTE: This function replaces atoi() [stdlib.h]
1195 int TextToInteger(const char *text)
1196 {
1197     int value = 0;
1198     int sign = 1;
1199
1200     if ((text[0] == '+') || (text[0] == '-'))
1201     {
1202         if (text[0] == '-') sign = -1;
1203         text++;
1204     }
1205
1206     for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
1207
1208     return value*sign;
1209 }
1210
1211 #if defined(SUPPORT_TEXT_MANIPULATION)
1212 // Copy one string to another, returns bytes copied
1213 int TextCopy(char *dst, const char *src)
1214 {
1215     int bytes = 0;
1216
1217     if (dst != NULL)
1218     {
1219         while (*src != '\0')
1220         {
1221             *dst = *src;
1222             dst++;
1223             src++;
1224
1225             bytes++;
1226         }
1227
1228         *dst = '\0';
1229     }
1230
1231     return bytes;
1232 }
1233
1234 // Check if two text string are equal
1235 // REQUIRES: strcmp()
1236 bool TextIsEqual(const char *text1, const char *text2)
1237 {
1238     bool result = false;
1239
1240     if (strcmp(text1, text2) == 0) result = true;
1241
1242     return result;
1243 }
1244
1245 // Get a piece of a text string
1246 const char *TextSubtext(const char *text, int position, int length)
1247 {
1248     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1249
1250     int textLength = TextLength(text);
1251
1252     if (position >= textLength)
1253     {
1254         position = textLength - 1;
1255         length = 0;
1256     }
1257
1258     if (length >= textLength) length = textLength;
1259
1260     for (int c = 0 ; c < length ; c++)
1261     {
1262         *(buffer + c) = *(text + position);
1263         text++;
1264     }
1265
1266     *(buffer + length) = '\0';
1267
1268     return buffer;
1269 }
1270
1271 // Replace text string
1272 // REQUIRES: strstr(), strncpy(), strcpy()
1273 // WARNING: Internally allocated memory must be freed by the user (if return != NULL)
1274 char *TextReplace(char *text, const char *replace, const char *by)
1275 {
1276     // Sanity checks and initialization
1277     if (!text || !replace || !by) return NULL;
1278
1279     char *result;
1280
1281     char *insertPoint;      // Next insert point
1282     char *temp;             // Temp pointer
1283     int replaceLen;         // Replace string length of (the string to remove)
1284     int byLen;              // Replacement length (the string to replace replace by)
1285     int lastReplacePos;     // Distance between replace and end of last replace
1286     int count;              // Number of replacements
1287
1288     replaceLen = TextLength(replace);
1289     if (replaceLen == 0) return NULL;  // Empty replace causes infinite loop during count
1290
1291     byLen = TextLength(by);
1292
1293     // Count the number of replacements needed
1294     insertPoint = text;
1295     for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
1296
1297     // Allocate returning string and point temp to it
1298     temp = result = RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
1299
1300     if (!result) return NULL;   // Memory could not be allocated
1301
1302     // First time through the loop, all the variable are set correctly from here on,
1303     //    temp points to the end of the result string
1304     //    insertPoint points to the next occurrence of replace in text
1305     //    text points to the remainder of text after "end of replace"
1306     while (count--)
1307     {
1308         insertPoint = strstr(text, replace);
1309         lastReplacePos = (int)(insertPoint - text);
1310         temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
1311         temp = strcpy(temp, by) + byLen;
1312         text += lastReplacePos + replaceLen; // Move to next "end of replace"
1313     }
1314
1315     // Copy remaind text part after replacement to result (pointed by moving temp)
1316     strcpy(temp, text);
1317
1318     return result;
1319 }
1320
1321 // Insert text in a specific position, moves all text forward
1322 // WARNING: Allocated memory should be manually freed
1323 char *TextInsert(const char *text, const char *insert, int position)
1324 {
1325     int textLen = TextLength(text);
1326     int insertLen =  TextLength(insert);
1327
1328     char *result = (char *)RL_MALLOC(textLen + insertLen + 1);
1329
1330     for (int i = 0; i < position; i++) result[i] = text[i];
1331     for (int i = position; i < insertLen + position; i++) result[i] = insert[i];
1332     for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
1333
1334     result[textLen + insertLen] = '\0';     // Make sure text string is valid!
1335
1336     return result;
1337 }
1338
1339 // Join text strings with delimiter
1340 // REQUIRES: memset(), memcpy()
1341 const char *TextJoin(const char **textList, int count, const char *delimiter)
1342 {
1343     static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1344     memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
1345     char *textPtr = text;
1346
1347     int totalLength = 0;
1348     int delimiterLen = TextLength(delimiter);
1349
1350     for (int i = 0; i < count; i++)
1351     {
1352         int textLength = TextLength(textList[i]);
1353
1354         // Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
1355         if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
1356         {
1357             memcpy(textPtr, textList[i], textLength);
1358             totalLength += textLength;
1359             textPtr += textLength;
1360
1361             if ((delimiterLen > 0) && (i < (count - 1)))
1362             {
1363                 memcpy(textPtr, delimiter, delimiterLen);
1364                 totalLength += delimiterLen;
1365                 textPtr += delimiterLen;
1366             }
1367         }
1368     }
1369
1370     return text;
1371 }
1372
1373 // Split string into multiple strings
1374 // REQUIRES: memset()
1375 const char **TextSplit(const char *text, char delimiter, int *count)
1376 {
1377     // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
1378     // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
1379     // all used memory is static... it has some limitations:
1380     //      1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT
1381     //      2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
1382
1383     static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
1384     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1385     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
1386
1387     result[0] = buffer;
1388     int counter = 0;
1389
1390     if (text != NULL)
1391     {
1392         counter = 1;
1393
1394         // Count how many substrings we have on text and point to every one
1395         for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
1396         {
1397             buffer[i] = text[i];
1398             if (buffer[i] == '\0') break;
1399             else if (buffer[i] == delimiter)
1400             {
1401                 buffer[i] = '\0';   // Set an end of string at this point
1402                 result[counter] = buffer + i + 1;
1403                 counter++;
1404
1405                 if (counter == MAX_TEXTSPLIT_COUNT) break;
1406             }
1407         }
1408     }
1409
1410     *count = counter;
1411     return result;
1412 }
1413
1414 // Append text at specific position and move cursor!
1415 // REQUIRES: strcpy()
1416 void TextAppend(char *text, const char *append, int *position)
1417 {
1418     strcpy(text + *position, append);
1419     *position += TextLength(append);
1420 }
1421
1422 // Find first text occurrence within a string
1423 // REQUIRES: strstr()
1424 int TextFindIndex(const char *text, const char *find)
1425 {
1426     int position = -1;
1427
1428     char *ptr = strstr(text, find);
1429
1430     if (ptr != NULL) position = (int)(ptr - text);
1431
1432     return position;
1433 }
1434
1435 // Get upper case version of provided string
1436 // REQUIRES: toupper()
1437 const char *TextToUpper(const char *text)
1438 {
1439     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1440
1441     for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
1442     {
1443         if (text[i] != '\0')
1444         {
1445             buffer[i] = (char)toupper(text[i]);
1446             //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
1447
1448             // TODO: Support Utf8 diacritics!
1449             //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
1450         }
1451         else { buffer[i] = '\0'; break; }
1452     }
1453
1454     return buffer;
1455 }
1456
1457 // Get lower case version of provided string
1458 // REQUIRES: tolower()
1459 const char *TextToLower(const char *text)
1460 {
1461     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1462
1463     for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
1464     {
1465         if (text[i] != '\0')
1466         {
1467             buffer[i] = (char)tolower(text[i]);
1468             //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
1469         }
1470         else { buffer[i] = '\0'; break; }
1471     }
1472
1473     return buffer;
1474 }
1475
1476 // Get Pascal case notation version of provided string
1477 // REQUIRES: toupper()
1478 const char *TextToPascal(const char *text)
1479 {
1480     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1481
1482     buffer[0] = (char)toupper(text[0]);
1483
1484     for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++)
1485     {
1486         if (text[j] != '\0')
1487         {
1488             if (text[j] != '_') buffer[i] = text[j];
1489             else
1490             {
1491                 j++;
1492                 buffer[i] = (char)toupper(text[j]);
1493             }
1494         }
1495         else { buffer[i] = '\0'; break; }
1496     }
1497
1498     return buffer;
1499 }
1500
1501 // Encode text codepoint into utf8 text
1502 // REQUIRES: memcpy()
1503 // WARNING: Allocated memory should be manually freed
1504 char *TextToUtf8(int *codepoints, int length)
1505 {
1506     // We allocate enough memory fo fit all possible codepoints
1507     // NOTE: 5 bytes for every codepoint should be enough
1508     char *text = (char *)RL_CALLOC(length*5, 1);
1509     const char *utf8 = NULL;
1510     int size = 0;
1511
1512     for (int i = 0, bytes = 0; i < length; i++)
1513     {
1514         utf8 = CodepointToUtf8(codepoints[i], &bytes);
1515         memcpy(text + size, utf8, bytes);
1516         size += bytes;
1517     }
1518
1519     // Resize memory to text length + string NULL terminator
1520     void *ptr = RL_REALLOC(text, size + 1);
1521
1522     if (ptr != NULL) text = (char *)ptr;
1523
1524     return text;
1525 }
1526
1527 // Encode codepoint into utf8 text (char array length returned as parameter)
1528 RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
1529 {
1530     static char utf8[6] = { 0 };
1531     int length = 0;
1532
1533     if (codepoint <= 0x7f)
1534     {
1535         utf8[0] = (char)codepoint;
1536         length = 1;
1537     }
1538     else if (codepoint <= 0x7ff)
1539     {
1540         utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
1541         utf8[1] = (char)((codepoint & 0x3f) | 0x80);
1542         length = 2;
1543     }
1544     else if (codepoint <= 0xffff)
1545     {
1546         utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
1547         utf8[1] = (char)(((codepoint >>  6) & 0x3f) | 0x80);
1548         utf8[2] = (char)((codepoint & 0x3f) | 0x80);
1549         length = 3;
1550     }
1551     else if (codepoint <= 0x10ffff)
1552     {
1553         utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
1554         utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
1555         utf8[2] = (char)(((codepoint >>  6) & 0x3f) | 0x80);
1556         utf8[3] = (char)((codepoint & 0x3f) | 0x80);
1557         length = 4;
1558     }
1559
1560     *byteLength = length;
1561
1562     return utf8;
1563 }
1564
1565 // Get all codepoints in a string, codepoints count returned by parameters
1566 // REQUIRES: memset()
1567 int *GetCodepoints(const char *text, int *count)
1568 {
1569     static int codepoints[MAX_TEXT_UNICODE_CHARS] = { 0 };
1570     memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int));
1571
1572     int bytesProcessed = 0;
1573     int textLength = TextLength(text);
1574     int codepointsCount = 0;
1575
1576     for (int i = 0; i < textLength; codepointsCount++)
1577     {
1578         codepoints[codepointsCount] = GetNextCodepoint(text + i, &bytesProcessed);
1579         i += bytesProcessed;
1580     }
1581
1582     *count = codepointsCount;
1583
1584     return codepoints;
1585 }
1586
1587 // Returns total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found
1588 // NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead
1589 int GetCodepointsCount(const char *text)
1590 {
1591     unsigned int len = 0;
1592     char *ptr = (char *)&text[0];
1593
1594     while (*ptr != '\0')
1595     {
1596         int next = 0;
1597         int letter = GetNextCodepoint(ptr, &next);
1598
1599         if (letter == 0x3f) ptr += 1;
1600         else ptr += next;
1601
1602         len++;
1603     }
1604
1605     return len;
1606 }
1607 #endif      // SUPPORT_TEXT_MANIPULATION
1608
1609 // Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
1610 // When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
1611 // Total number of bytes processed are returned as a parameter
1612 // NOTE: the standard says U+FFFD should be returned in case of errors
1613 // but that character is not supported by the default font in raylib
1614 // TODO: Optimize this code for speed!!
1615 int GetNextCodepoint(const char *text, int *bytesProcessed)
1616 {
1617 /*
1618     UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt
1619
1620     Char. number range  |        UTF-8 octet sequence
1621       (hexadecimal)    |              (binary)
1622     --------------------+---------------------------------------------
1623     0000 0000-0000 007F | 0xxxxxxx
1624     0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1625     0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1626     0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1627 */
1628     // NOTE: on decode errors we return as soon as possible
1629
1630     int code = 0x3f;   // Codepoint (defaults to '?')
1631     int octet = (unsigned char)(text[0]); // The first UTF8 octet
1632     *bytesProcessed = 1;
1633
1634     if (octet <= 0x7f)
1635     {
1636         // Only one octet (ASCII range x00-7F)
1637         code = text[0];
1638     }
1639     else if ((octet & 0xe0) == 0xc0)
1640     {
1641         // Two octets
1642         // [0]xC2-DF    [1]UTF8-tail(x80-BF)
1643         unsigned char octet1 = text[1];
1644
1645         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
1646
1647         if ((octet >= 0xc2) && (octet <= 0xdf))
1648         {
1649             code = ((octet & 0x1f) << 6) | (octet1 & 0x3f);
1650             *bytesProcessed = 2;
1651         }
1652     }
1653     else if ((octet & 0xf0) == 0xe0)
1654     {
1655         // Three octets
1656         unsigned char octet1 = text[1];
1657         unsigned char octet2 = '\0';
1658
1659         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
1660
1661         octet2 = text[2];
1662
1663         if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
1664
1665         /*
1666             [0]xE0    [1]xA0-BF       [2]UTF8-tail(x80-BF)
1667             [0]xE1-EC [1]UTF8-tail    [2]UTF8-tail(x80-BF)
1668             [0]xED    [1]x80-9F       [2]UTF8-tail(x80-BF)
1669             [0]xEE-EF [1]UTF8-tail    [2]UTF8-tail(x80-BF)
1670         */
1671
1672         if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
1673             ((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
1674
1675         if ((octet >= 0xe0) && (0 <= 0xef))
1676         {
1677             code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
1678             *bytesProcessed = 3;
1679         }
1680     }
1681     else if ((octet & 0xf8) == 0xf0)
1682     {
1683         // Four octets
1684         if (octet > 0xf4) return code;
1685
1686         unsigned char octet1 = text[1];
1687         unsigned char octet2 = '\0';
1688         unsigned char octet3 = '\0';
1689
1690         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; }  // Unexpected sequence
1691
1692         octet2 = text[2];
1693
1694         if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; }  // Unexpected sequence
1695
1696         octet3 = text[3];
1697
1698         if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; }  // Unexpected sequence
1699
1700         /*
1701             [0]xF0       [1]x90-BF       [2]UTF8-tail  [3]UTF8-tail
1702             [0]xF1-F3    [1]UTF8-tail    [2]UTF8-tail  [3]UTF8-tail
1703             [0]xF4       [1]x80-8F       [2]UTF8-tail  [3]UTF8-tail
1704         */
1705
1706         if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) ||
1707             ((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence
1708
1709         if (octet >= 0xf0)
1710         {
1711             code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f);
1712             *bytesProcessed = 4;
1713         }
1714     }
1715
1716     if (code > 0x10ffff) code = 0x3f;     // Codepoints after U+10ffff are invalid
1717
1718     return code;
1719 }
1720
1721 //----------------------------------------------------------------------------------
1722 // Module specific Functions Definition
1723 //----------------------------------------------------------------------------------
1724 #if defined(SUPPORT_FILEFORMAT_FNT)
1725
1726 // Read a line from memory
1727 // REQUIRES: memcpy()
1728 // NOTE: Returns the number of bytes read
1729 static int GetLine(const char *origin, char *buffer, int maxLength)
1730 {
1731     int count = 0;
1732     for (; count < maxLength; count++) if (origin[count] == '\n') break;
1733     memcpy(buffer, origin, count);
1734     return count;
1735 }
1736
1737 // Load a BMFont file (AngelCode font file)
1738 // REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
1739 static Font LoadBMFont(const char *fileName)
1740 {
1741     #define MAX_BUFFER_SIZE     256
1742
1743     Font font = { 0 };
1744
1745     char buffer[MAX_BUFFER_SIZE] = { 0 };
1746     char *searchPoint = NULL;
1747
1748     int fontSize = 0;
1749     int charsCount = 0;
1750
1751     int imWidth = 0;
1752     int imHeight = 0;
1753     char imFileName[129];
1754
1755     int base = 0;   // Useless data
1756
1757     char *fileText = LoadFileText(fileName);
1758
1759     if (fileText == NULL) return font;
1760
1761     char *fileTextPtr = fileText;
1762
1763     // NOTE: We skip first line, it contains no useful information
1764     int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1765     fileTextPtr += (lineBytes + 1);
1766
1767     // Read line data
1768     lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1769     searchPoint = strstr(buffer, "lineHeight");
1770     sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight);
1771     fileTextPtr += (lineBytes + 1);
1772
1773     TRACELOGD("FONT: [%s] Loaded font info:", fileName);
1774     TRACELOGD("    > Base size: %i", fontSize);
1775     TRACELOGD("    > Texture scale: %ix%i", imWidth, imHeight);
1776
1777     lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1778     searchPoint = strstr(buffer, "file");
1779     sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName);
1780     fileTextPtr += (lineBytes + 1);
1781
1782     TRACELOGD("    > Texture filename: %s", imFileName);
1783
1784     lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1785     searchPoint = strstr(buffer, "count");
1786     sscanf(searchPoint, "count=%i", &charsCount);
1787     fileTextPtr += (lineBytes + 1);
1788
1789     TRACELOGD("    > Chars count: %i", charsCount);
1790
1791     // Compose correct path using route of .fnt file (fileName) and imFileName
1792     char *imPath = NULL;
1793     char *lastSlash = NULL;
1794
1795     lastSlash = strrchr(fileName, '/');
1796     if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');
1797
1798     if (lastSlash != NULL)
1799     {
1800         // NOTE: We need some extra space to avoid memory corruption on next allocations!
1801         imPath = RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
1802         memcpy(imPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
1803         memcpy(imPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
1804     }
1805     else imPath = imFileName;
1806
1807     TRACELOGD("    > Image loading path: %s", imPath);
1808
1809     Image imFont = LoadImage(imPath);
1810
1811     if (imFont.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
1812     {
1813         // Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
1814         Image imFontAlpha = {
1815             .data = calloc(imFont.width*imFont.height, 2),
1816             .width = imFont.width,
1817             .height = imFont.height,
1818             .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,
1819             .mipmaps = 1
1820         };
1821
1822         for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
1823         {
1824             ((unsigned char *)(imFontAlpha.data))[p] = 0xff;
1825             ((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i];
1826         }
1827
1828         UnloadImage(imFont);
1829         imFont = imFontAlpha;
1830     }
1831
1832     font.texture = LoadTextureFromImage(imFont);
1833
1834     if (lastSlash != NULL) RL_FREE(imPath);
1835
1836     // Fill font characters info data
1837     font.baseSize = fontSize;
1838     font.charsCount = charsCount;
1839     font.charsPadding = 0;
1840     font.chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo));
1841     font.recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle));
1842
1843     int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
1844
1845     for (int i = 0; i < charsCount; i++)
1846     {
1847         lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1848         sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
1849                        &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
1850         fileTextPtr += (lineBytes + 1);
1851
1852         // Get character rectangle in the font atlas texture
1853         font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
1854
1855         // Save data properly in sprite font
1856         font.chars[i].value = charId;
1857         font.chars[i].offsetX = charOffsetX;
1858         font.chars[i].offsetY = charOffsetY;
1859         font.chars[i].advanceX = charAdvanceX;
1860
1861         // Fill character image data from imFont data
1862         font.chars[i].image = ImageFromImage(imFont, font.recs[i]);
1863     }
1864
1865     UnloadImage(imFont);
1866     RL_FREE(fileText);
1867
1868     if (font.texture.id == 0)
1869     {
1870         UnloadFont(font);
1871         font = GetFontDefault();
1872         TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName);
1873     }
1874     else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully", fileName);
1875
1876     return font;
1877 }
1878 #endif