]> git.sesse.net Git - pistorm/blob - raylib_pi4_test/text.c
Update raylib files and Makefile for Pi 4 testing
[pistorm] / raylib_pi4_test / 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     if (font.texture.id == 0) font = GetFontDefault();  // Security check in case of not valid font
852     
853     int length = TextLength(text);  // Total length in bytes of the text, scanned by codepoints in loop
854
855     int textOffsetY = 0;            // Offset between lines (on line break '\n')
856     float textOffsetX = 0.0f;       // Offset X to next character to draw
857
858     float scaleFactor = fontSize/font.baseSize;         // Character quad scaling factor
859
860     for (int i = 0; i < length;)
861     {
862         // Get next codepoint from byte string and glyph index in font
863         int codepointByteCount = 0;
864         int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
865         int index = GetGlyphIndex(font, codepoint);
866
867         // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
868         // but we need to draw all of the bad bytes using the '?' symbol moving one byte
869         if (codepoint == 0x3f) codepointByteCount = 1;
870
871         if (codepoint == '\n')
872         {
873             // NOTE: Fixed line spacing of 1.5 line-height
874             // TODO: Support custom line spacing defined by user
875             textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
876             textOffsetX = 0.0f;
877         }
878         else
879         {
880             if ((codepoint != ' ') && (codepoint != '\t'))
881             {
882                 DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
883             }
884
885             if (font.chars[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
886             else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing);
887         }
888
889         i += codepointByteCount;   // Move text bytes counter to next codepoint
890     }
891 }
892
893 // Draw text using font inside rectangle limits
894 void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint)
895 {
896     DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE);
897 }
898
899 // Draw text using font inside rectangle limits with support for text selection
900 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)
901 {
902     int length = TextLength(text);  // Total length in bytes of the text, scanned by codepoints in loop
903
904     int textOffsetY = 0;            // Offset between lines (on line break '\n')
905     float textOffsetX = 0.0f;       // Offset X to next character to draw
906
907     float scaleFactor = fontSize/font.baseSize;     // Character quad scaling factor
908
909     // Word/character wrapping mechanism variables
910     enum { MEASURE_STATE = 0, DRAW_STATE = 1 };
911     int state = wordWrap? MEASURE_STATE : DRAW_STATE;
912
913     int startLine = -1;         // Index where to begin drawing (where a line begins)
914     int endLine = -1;           // Index where to stop drawing (where a line ends)
915     int lastk = -1;             // Holds last value of the character position
916
917     for (int i = 0, k = 0; i < length; i++, k++)
918     {
919         // Get next codepoint from byte string and glyph index in font
920         int codepointByteCount = 0;
921         int codepoint = GetNextCodepoint(&text[i], &codepointByteCount);
922         int index = GetGlyphIndex(font, codepoint);
923
924         // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
925         // but we need to draw all of the bad bytes using the '?' symbol moving one byte
926         if (codepoint == 0x3f) codepointByteCount = 1;
927         i += (codepointByteCount - 1);
928
929         int glyphWidth = 0;
930         if (codepoint != '\n')
931         {
932             glyphWidth = (font.chars[index].advanceX == 0)?
933                          (int)(font.recs[index].width*scaleFactor + spacing):
934                          (int)(font.chars[index].advanceX*scaleFactor + spacing);
935         }
936
937         // NOTE: When wordWrap is ON we first measure how much of the text we can draw before going outside of the rec container
938         // We store this info in startLine and endLine, then we change states, draw the text between those two variables
939         // and change states again and again recursively until the end of the text (or until we get outside of the container).
940         // When wordWrap is OFF we don't need the measure state so we go to the drawing state immediately
941         // and begin drawing on the next line before we can get outside the container.
942         if (state == MEASURE_STATE)
943         {
944             // TODO: There are multiple types of spaces in UNICODE, maybe it's a good idea to add support for more
945             // Ref: http://jkorpela.fi/chars/spaces.html
946             if ((codepoint == ' ') || (codepoint == '\t') || (codepoint == '\n')) endLine = i;
947
948             if ((textOffsetX + glyphWidth + 1) >= rec.width)
949             {
950                 endLine = (endLine < 1)? i : endLine;
951                 if (i == endLine) endLine -= codepointByteCount;
952                 if ((startLine + codepointByteCount) == endLine) endLine = (i - codepointByteCount);
953
954                 state = !state;
955             }
956             else if ((i + 1) == length)
957             {
958                 endLine = i;
959
960                 state = !state;
961             }
962             else if (codepoint == '\n') state = !state;
963
964             if (state == DRAW_STATE)
965             {
966                 textOffsetX = 0;
967                 i = startLine;
968                 glyphWidth = 0;
969
970                 // Save character position when we switch states
971                 int tmp = lastk;
972                 lastk = k - 1;
973                 k = tmp;
974             }
975         }
976         else
977         {
978             if (codepoint == '\n')
979             {
980                 if (!wordWrap)
981                 {
982                     textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
983                     textOffsetX = 0;
984                 }
985             }
986             else
987             {
988                 if (!wordWrap && ((textOffsetX + glyphWidth + 1) >= rec.width))
989                 {
990                     textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
991                     textOffsetX = 0;
992                 }
993
994                 // When text overflows rectangle height limit, just stop drawing
995                 if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break;
996
997                 // Draw selection background
998                 bool isGlyphSelected = false;
999                 if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
1000                 {
1001                     DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, (float)glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint);
1002                     isGlyphSelected = true;
1003                 }
1004
1005                 // Draw current character glyph
1006                 if ((codepoint != ' ') && (codepoint != '\t'))
1007                 {
1008                     DrawTextCodepoint(font, codepoint, (Vector2){ rec.x + textOffsetX, rec.y + textOffsetY }, fontSize, isGlyphSelected? selectTint : tint);
1009                 }
1010             }
1011
1012             if (wordWrap && (i == endLine))
1013             {
1014                 textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
1015                 textOffsetX = 0;
1016                 startLine = endLine;
1017                 endLine = -1;
1018                 glyphWidth = 0;
1019                 selectStart += lastk - k;
1020                 k = lastk;
1021
1022                 state = !state;
1023             }
1024         }
1025
1026         textOffsetX += glyphWidth;
1027     }
1028 }
1029
1030 // Draw one character (codepoint)
1031 void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint)
1032 {
1033     // Character index position in sprite font
1034     // NOTE: In case a codepoint is not available in the font, index returned points to '?'
1035     int index = GetGlyphIndex(font, codepoint);
1036     float scaleFactor = fontSize/font.baseSize;     // Character quad scaling factor
1037
1038     // Character destination rectangle on screen
1039     // NOTE: We consider charsPadding on drawing
1040     Rectangle dstRec = { position.x + font.chars[index].offsetX*scaleFactor - (float)font.charsPadding*scaleFactor,
1041                       position.y + font.chars[index].offsetY*scaleFactor - (float)font.charsPadding*scaleFactor,
1042                       (font.recs[index].width + 2.0f*font.charsPadding)*scaleFactor,
1043                       (font.recs[index].height + 2.0f*font.charsPadding)*scaleFactor };
1044
1045     // Character source rectangle from font texture atlas
1046     // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
1047     Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding,
1048                          font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding };
1049
1050     // Draw the character texture on the screen
1051     DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
1052 }
1053
1054 // Measure string width for default font
1055 int MeasureText(const char *text, int fontSize)
1056 {
1057     Vector2 vec = { 0.0f, 0.0f };
1058
1059     // Check if default font has been loaded
1060     if (GetFontDefault().texture.id != 0)
1061     {
1062         int defaultFontSize = 10;   // Default Font chars height in pixel
1063         if (fontSize < defaultFontSize) fontSize = defaultFontSize;
1064         int spacing = fontSize/defaultFontSize;
1065
1066         vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing);
1067     }
1068
1069     return (int)vec.x;
1070 }
1071
1072 // Measure string size for Font
1073 Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
1074 {
1075     int len = TextLength(text);
1076     int tempLen = 0;                // Used to count longer text line num chars
1077     int lenCounter = 0;
1078
1079     float textWidth = 0.0f;
1080     float tempTextWidth = 0.0f;     // Used to count longer text line width
1081
1082     float textHeight = (float)font.baseSize;
1083     float scaleFactor = fontSize/(float)font.baseSize;
1084
1085     int letter = 0;                 // Current character
1086     int index = 0;                  // Index position in sprite font
1087
1088     for (int i = 0; i < len; i++)
1089     {
1090         lenCounter++;
1091
1092         int next = 0;
1093         letter = GetNextCodepoint(&text[i], &next);
1094         index = GetGlyphIndex(font, letter);
1095
1096         // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
1097         // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
1098         if (letter == 0x3f) next = 1;
1099         i += next - 1;
1100
1101         if (letter != '\n')
1102         {
1103             if (font.chars[index].advanceX != 0) textWidth += font.chars[index].advanceX;
1104             else textWidth += (font.recs[index].width + font.chars[index].offsetX);
1105         }
1106         else
1107         {
1108             if (tempTextWidth < textWidth) tempTextWidth = textWidth;
1109             lenCounter = 0;
1110             textWidth = 0;
1111             textHeight += ((float)font.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
1112         }
1113
1114         if (tempLen < lenCounter) tempLen = lenCounter;
1115     }
1116
1117     if (tempTextWidth < textWidth) tempTextWidth = textWidth;
1118
1119     Vector2 vec = { 0 };
1120     vec.x = tempTextWidth*scaleFactor + (float)((tempLen - 1)*spacing); // Adds chars spacing to measure
1121     vec.y = textHeight*scaleFactor;
1122
1123     return vec;
1124 }
1125
1126 // Returns index position for a unicode character on spritefont
1127 int GetGlyphIndex(Font font, int codepoint)
1128 {
1129 #ifndef GLYPH_NOTFOUND_CHAR_FALLBACK
1130     #define GLYPH_NOTFOUND_CHAR_FALLBACK     63      // Character used if requested codepoint is not found: '?'
1131 #endif
1132
1133 // Support charsets with any characters order
1134 #define SUPPORT_UNORDERED_CHARSET
1135 #if defined(SUPPORT_UNORDERED_CHARSET)
1136     int index = GLYPH_NOTFOUND_CHAR_FALLBACK;
1137
1138     for (int i = 0; i < font.charsCount; i++)
1139     {
1140         if (font.chars[i].value == codepoint)
1141         {
1142             index = i;
1143             break;
1144         }
1145     }
1146
1147     return index;
1148 #else
1149     return (codepoint - 32);
1150 #endif
1151 }
1152
1153 //----------------------------------------------------------------------------------
1154 // Text strings management functions
1155 //----------------------------------------------------------------------------------
1156 // Get text length in bytes, check for \0 character
1157 unsigned int TextLength(const char *text)
1158 {
1159     unsigned int length = 0; //strlen(text)
1160
1161     if (text != NULL)
1162     {
1163         while (*text++) length++;
1164     }
1165
1166     return length;
1167 }
1168
1169 // Formatting of text with variables to 'embed'
1170 // WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
1171 const char *TextFormat(const char *text, ...)
1172 {
1173 #ifndef MAX_TEXTFORMAT_BUFFERS
1174     #define MAX_TEXTFORMAT_BUFFERS 4        // Maximum number of static buffers for text formatting
1175 #endif
1176
1177     // We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
1178     static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
1179     static int  index = 0;
1180
1181     char *currentBuffer = buffers[index];
1182     memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH);   // Clear buffer before using
1183
1184     va_list args;
1185     va_start(args, text);
1186     vsnprintf(currentBuffer, MAX_TEXT_BUFFER_LENGTH, text, args);
1187     va_end(args);
1188
1189     index += 1;     // Move to next buffer for next function call
1190     if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
1191
1192     return currentBuffer;
1193 }
1194
1195 // Get integer value from text
1196 // NOTE: This function replaces atoi() [stdlib.h]
1197 int TextToInteger(const char *text)
1198 {
1199     int value = 0;
1200     int sign = 1;
1201
1202     if ((text[0] == '+') || (text[0] == '-'))
1203     {
1204         if (text[0] == '-') sign = -1;
1205         text++;
1206     }
1207
1208     for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
1209
1210     return value*sign;
1211 }
1212
1213 #if defined(SUPPORT_TEXT_MANIPULATION)
1214 // Copy one string to another, returns bytes copied
1215 int TextCopy(char *dst, const char *src)
1216 {
1217     int bytes = 0;
1218
1219     if (dst != NULL)
1220     {
1221         while (*src != '\0')
1222         {
1223             *dst = *src;
1224             dst++;
1225             src++;
1226
1227             bytes++;
1228         }
1229
1230         *dst = '\0';
1231     }
1232
1233     return bytes;
1234 }
1235
1236 // Check if two text string are equal
1237 // REQUIRES: strcmp()
1238 bool TextIsEqual(const char *text1, const char *text2)
1239 {
1240     bool result = false;
1241
1242     if (strcmp(text1, text2) == 0) result = true;
1243
1244     return result;
1245 }
1246
1247 // Get a piece of a text string
1248 const char *TextSubtext(const char *text, int position, int length)
1249 {
1250     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1251
1252     int textLength = TextLength(text);
1253
1254     if (position >= textLength)
1255     {
1256         position = textLength - 1;
1257         length = 0;
1258     }
1259
1260     if (length >= textLength) length = textLength;
1261
1262     for (int c = 0 ; c < length ; c++)
1263     {
1264         *(buffer + c) = *(text + position);
1265         text++;
1266     }
1267
1268     *(buffer + length) = '\0';
1269
1270     return buffer;
1271 }
1272
1273 // Replace text string
1274 // REQUIRES: strstr(), strncpy(), strcpy()
1275 // WARNING: Internally allocated memory must be freed by the user (if return != NULL)
1276 char *TextReplace(char *text, const char *replace, const char *by)
1277 {
1278     // Sanity checks and initialization
1279     if (!text || !replace || !by) return NULL;
1280
1281     char *result;
1282
1283     char *insertPoint;      // Next insert point
1284     char *temp;             // Temp pointer
1285     int replaceLen;         // Replace string length of (the string to remove)
1286     int byLen;              // Replacement length (the string to replace replace by)
1287     int lastReplacePos;     // Distance between replace and end of last replace
1288     int count;              // Number of replacements
1289
1290     replaceLen = TextLength(replace);
1291     if (replaceLen == 0) return NULL;  // Empty replace causes infinite loop during count
1292
1293     byLen = TextLength(by);
1294
1295     // Count the number of replacements needed
1296     insertPoint = text;
1297     for (count = 0; (temp = strstr(insertPoint, replace)); count++) insertPoint = temp + replaceLen;
1298
1299     // Allocate returning string and point temp to it
1300     temp = result = RL_MALLOC(TextLength(text) + (byLen - replaceLen)*count + 1);
1301
1302     if (!result) return NULL;   // Memory could not be allocated
1303
1304     // First time through the loop, all the variable are set correctly from here on,
1305     //    temp points to the end of the result string
1306     //    insertPoint points to the next occurrence of replace in text
1307     //    text points to the remainder of text after "end of replace"
1308     while (count--)
1309     {
1310         insertPoint = strstr(text, replace);
1311         lastReplacePos = (int)(insertPoint - text);
1312         temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
1313         temp = strcpy(temp, by) + byLen;
1314         text += lastReplacePos + replaceLen; // Move to next "end of replace"
1315     }
1316
1317     // Copy remaind text part after replacement to result (pointed by moving temp)
1318     strcpy(temp, text);
1319
1320     return result;
1321 }
1322
1323 // Insert text in a specific position, moves all text forward
1324 // WARNING: Allocated memory should be manually freed
1325 char *TextInsert(const char *text, const char *insert, int position)
1326 {
1327     int textLen = TextLength(text);
1328     int insertLen =  TextLength(insert);
1329
1330     char *result = (char *)RL_MALLOC(textLen + insertLen + 1);
1331
1332     for (int i = 0; i < position; i++) result[i] = text[i];
1333     for (int i = position; i < insertLen + position; i++) result[i] = insert[i];
1334     for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
1335
1336     result[textLen + insertLen] = '\0';     // Make sure text string is valid!
1337
1338     return result;
1339 }
1340
1341 // Join text strings with delimiter
1342 // REQUIRES: memset(), memcpy()
1343 const char *TextJoin(const char **textList, int count, const char *delimiter)
1344 {
1345     static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1346     memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
1347     char *textPtr = text;
1348
1349     int totalLength = 0;
1350     int delimiterLen = TextLength(delimiter);
1351
1352     for (int i = 0; i < count; i++)
1353     {
1354         int textLength = TextLength(textList[i]);
1355
1356         // Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
1357         if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
1358         {
1359             memcpy(textPtr, textList[i], textLength);
1360             totalLength += textLength;
1361             textPtr += textLength;
1362
1363             if ((delimiterLen > 0) && (i < (count - 1)))
1364             {
1365                 memcpy(textPtr, delimiter, delimiterLen);
1366                 totalLength += delimiterLen;
1367                 textPtr += delimiterLen;
1368             }
1369         }
1370     }
1371
1372     return text;
1373 }
1374
1375 // Split string into multiple strings
1376 // REQUIRES: memset()
1377 const char **TextSplit(const char *text, char delimiter, int *count)
1378 {
1379     // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
1380     // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
1381     // all used memory is static... it has some limitations:
1382     //      1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT
1383     //      2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
1384
1385     static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
1386     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1387     memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
1388
1389     result[0] = buffer;
1390     int counter = 0;
1391
1392     if (text != NULL)
1393     {
1394         counter = 1;
1395
1396         // Count how many substrings we have on text and point to every one
1397         for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
1398         {
1399             buffer[i] = text[i];
1400             if (buffer[i] == '\0') break;
1401             else if (buffer[i] == delimiter)
1402             {
1403                 buffer[i] = '\0';   // Set an end of string at this point
1404                 result[counter] = buffer + i + 1;
1405                 counter++;
1406
1407                 if (counter == MAX_TEXTSPLIT_COUNT) break;
1408             }
1409         }
1410     }
1411
1412     *count = counter;
1413     return result;
1414 }
1415
1416 // Append text at specific position and move cursor!
1417 // REQUIRES: strcpy()
1418 void TextAppend(char *text, const char *append, int *position)
1419 {
1420     strcpy(text + *position, append);
1421     *position += TextLength(append);
1422 }
1423
1424 // Find first text occurrence within a string
1425 // REQUIRES: strstr()
1426 int TextFindIndex(const char *text, const char *find)
1427 {
1428     int position = -1;
1429
1430     char *ptr = strstr(text, find);
1431
1432     if (ptr != NULL) position = (int)(ptr - text);
1433
1434     return position;
1435 }
1436
1437 // Get upper case version of provided string
1438 // REQUIRES: toupper()
1439 const char *TextToUpper(const char *text)
1440 {
1441     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1442
1443     for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
1444     {
1445         if (text[i] != '\0')
1446         {
1447             buffer[i] = (char)toupper(text[i]);
1448             //if ((text[i] >= 'a') && (text[i] <= 'z')) buffer[i] = text[i] - 32;
1449
1450             // TODO: Support Utf8 diacritics!
1451             //if ((text[i] >= 'à') && (text[i] <= 'ý')) buffer[i] = text[i] - 32;
1452         }
1453         else { buffer[i] = '\0'; break; }
1454     }
1455
1456     return buffer;
1457 }
1458
1459 // Get lower case version of provided string
1460 // REQUIRES: tolower()
1461 const char *TextToLower(const char *text)
1462 {
1463     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1464
1465     for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
1466     {
1467         if (text[i] != '\0')
1468         {
1469             buffer[i] = (char)tolower(text[i]);
1470             //if ((text[i] >= 'A') && (text[i] <= 'Z')) buffer[i] = text[i] + 32;
1471         }
1472         else { buffer[i] = '\0'; break; }
1473     }
1474
1475     return buffer;
1476 }
1477
1478 // Get Pascal case notation version of provided string
1479 // REQUIRES: toupper()
1480 const char *TextToPascal(const char *text)
1481 {
1482     static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
1483
1484     buffer[0] = (char)toupper(text[0]);
1485
1486     for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++)
1487     {
1488         if (text[j] != '\0')
1489         {
1490             if (text[j] != '_') buffer[i] = text[j];
1491             else
1492             {
1493                 j++;
1494                 buffer[i] = (char)toupper(text[j]);
1495             }
1496         }
1497         else { buffer[i] = '\0'; break; }
1498     }
1499
1500     return buffer;
1501 }
1502
1503 // Encode text codepoint into utf8 text
1504 // REQUIRES: memcpy()
1505 // WARNING: Allocated memory should be manually freed
1506 char *TextToUtf8(int *codepoints, int length)
1507 {
1508     // We allocate enough memory fo fit all possible codepoints
1509     // NOTE: 5 bytes for every codepoint should be enough
1510     char *text = (char *)RL_CALLOC(length*5, 1);
1511     const char *utf8 = NULL;
1512     int size = 0;
1513
1514     for (int i = 0, bytes = 0; i < length; i++)
1515     {
1516         utf8 = CodepointToUtf8(codepoints[i], &bytes);
1517         memcpy(text + size, utf8, bytes);
1518         size += bytes;
1519     }
1520
1521     // Resize memory to text length + string NULL terminator
1522     void *ptr = RL_REALLOC(text, size + 1);
1523
1524     if (ptr != NULL) text = (char *)ptr;
1525
1526     return text;
1527 }
1528
1529 // Encode codepoint into utf8 text (char array length returned as parameter)
1530 RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
1531 {
1532     static char utf8[6] = { 0 };
1533     int length = 0;
1534
1535     if (codepoint <= 0x7f)
1536     {
1537         utf8[0] = (char)codepoint;
1538         length = 1;
1539     }
1540     else if (codepoint <= 0x7ff)
1541     {
1542         utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
1543         utf8[1] = (char)((codepoint & 0x3f) | 0x80);
1544         length = 2;
1545     }
1546     else if (codepoint <= 0xffff)
1547     {
1548         utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
1549         utf8[1] = (char)(((codepoint >>  6) & 0x3f) | 0x80);
1550         utf8[2] = (char)((codepoint & 0x3f) | 0x80);
1551         length = 3;
1552     }
1553     else if (codepoint <= 0x10ffff)
1554     {
1555         utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
1556         utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
1557         utf8[2] = (char)(((codepoint >>  6) & 0x3f) | 0x80);
1558         utf8[3] = (char)((codepoint & 0x3f) | 0x80);
1559         length = 4;
1560     }
1561
1562     *byteLength = length;
1563
1564     return utf8;
1565 }
1566
1567 // Get all codepoints in a string, codepoints count returned by parameters
1568 // REQUIRES: memset()
1569 int *GetCodepoints(const char *text, int *count)
1570 {
1571     static int codepoints[MAX_TEXT_UNICODE_CHARS] = { 0 };
1572     memset(codepoints, 0, MAX_TEXT_UNICODE_CHARS*sizeof(int));
1573
1574     int bytesProcessed = 0;
1575     int textLength = TextLength(text);
1576     int codepointsCount = 0;
1577
1578     for (int i = 0; i < textLength; codepointsCount++)
1579     {
1580         codepoints[codepointsCount] = GetNextCodepoint(text + i, &bytesProcessed);
1581         i += bytesProcessed;
1582     }
1583
1584     *count = codepointsCount;
1585
1586     return codepoints;
1587 }
1588
1589 // Returns total number of characters(codepoints) in a UTF8 encoded text, until '\0' is found
1590 // NOTE: If an invalid UTF8 sequence is encountered a '?'(0x3f) codepoint is counted instead
1591 int GetCodepointsCount(const char *text)
1592 {
1593     unsigned int len = 0;
1594     char *ptr = (char *)&text[0];
1595
1596     while (*ptr != '\0')
1597     {
1598         int next = 0;
1599         int letter = GetNextCodepoint(ptr, &next);
1600
1601         if (letter == 0x3f) ptr += 1;
1602         else ptr += next;
1603
1604         len++;
1605     }
1606
1607     return len;
1608 }
1609 #endif      // SUPPORT_TEXT_MANIPULATION
1610
1611 // Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
1612 // When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
1613 // Total number of bytes processed are returned as a parameter
1614 // NOTE: the standard says U+FFFD should be returned in case of errors
1615 // but that character is not supported by the default font in raylib
1616 // TODO: Optimize this code for speed!!
1617 int GetNextCodepoint(const char *text, int *bytesProcessed)
1618 {
1619 /*
1620     UTF8 specs from https://www.ietf.org/rfc/rfc3629.txt
1621
1622     Char. number range  |        UTF-8 octet sequence
1623       (hexadecimal)    |              (binary)
1624     --------------------+---------------------------------------------
1625     0000 0000-0000 007F | 0xxxxxxx
1626     0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1627     0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1628     0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1629 */
1630     // NOTE: on decode errors we return as soon as possible
1631
1632     int code = 0x3f;   // Codepoint (defaults to '?')
1633     int octet = (unsigned char)(text[0]); // The first UTF8 octet
1634     *bytesProcessed = 1;
1635
1636     if (octet <= 0x7f)
1637     {
1638         // Only one octet (ASCII range x00-7F)
1639         code = text[0];
1640     }
1641     else if ((octet & 0xe0) == 0xc0)
1642     {
1643         // Two octets
1644         // [0]xC2-DF    [1]UTF8-tail(x80-BF)
1645         unsigned char octet1 = text[1];
1646
1647         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
1648
1649         if ((octet >= 0xc2) && (octet <= 0xdf))
1650         {
1651             code = ((octet & 0x1f) << 6) | (octet1 & 0x3f);
1652             *bytesProcessed = 2;
1653         }
1654     }
1655     else if ((octet & 0xf0) == 0xe0)
1656     {
1657         // Three octets
1658         unsigned char octet1 = text[1];
1659         unsigned char octet2 = '\0';
1660
1661         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence
1662
1663         octet2 = text[2];
1664
1665         if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence
1666
1667         /*
1668             [0]xE0    [1]xA0-BF       [2]UTF8-tail(x80-BF)
1669             [0]xE1-EC [1]UTF8-tail    [2]UTF8-tail(x80-BF)
1670             [0]xED    [1]x80-9F       [2]UTF8-tail(x80-BF)
1671             [0]xEE-EF [1]UTF8-tail    [2]UTF8-tail(x80-BF)
1672         */
1673
1674         if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
1675             ((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
1676
1677         if ((octet >= 0xe0) && (0 <= 0xef))
1678         {
1679             code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
1680             *bytesProcessed = 3;
1681         }
1682     }
1683     else if ((octet & 0xf8) == 0xf0)
1684     {
1685         // Four octets
1686         if (octet > 0xf4) return code;
1687
1688         unsigned char octet1 = text[1];
1689         unsigned char octet2 = '\0';
1690         unsigned char octet3 = '\0';
1691
1692         if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; }  // Unexpected sequence
1693
1694         octet2 = text[2];
1695
1696         if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; }  // Unexpected sequence
1697
1698         octet3 = text[3];
1699
1700         if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; }  // Unexpected sequence
1701
1702         /*
1703             [0]xF0       [1]x90-BF       [2]UTF8-tail  [3]UTF8-tail
1704             [0]xF1-F3    [1]UTF8-tail    [2]UTF8-tail  [3]UTF8-tail
1705             [0]xF4       [1]x80-8F       [2]UTF8-tail  [3]UTF8-tail
1706         */
1707
1708         if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) ||
1709             ((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence
1710
1711         if (octet >= 0xf0)
1712         {
1713             code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f);
1714             *bytesProcessed = 4;
1715         }
1716     }
1717
1718     if (code > 0x10ffff) code = 0x3f;     // Codepoints after U+10ffff are invalid
1719
1720     return code;
1721 }
1722
1723 //----------------------------------------------------------------------------------
1724 // Module specific Functions Definition
1725 //----------------------------------------------------------------------------------
1726 #if defined(SUPPORT_FILEFORMAT_FNT)
1727
1728 // Read a line from memory
1729 // REQUIRES: memcpy()
1730 // NOTE: Returns the number of bytes read
1731 static int GetLine(const char *origin, char *buffer, int maxLength)
1732 {
1733     int count = 0;
1734     for (; count < maxLength; count++) if (origin[count] == '\n') break;
1735     memcpy(buffer, origin, count);
1736     return count;
1737 }
1738
1739 // Load a BMFont file (AngelCode font file)
1740 // REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
1741 static Font LoadBMFont(const char *fileName)
1742 {
1743     #define MAX_BUFFER_SIZE     256
1744
1745     Font font = { 0 };
1746
1747     char buffer[MAX_BUFFER_SIZE] = { 0 };
1748     char *searchPoint = NULL;
1749
1750     int fontSize = 0;
1751     int charsCount = 0;
1752
1753     int imWidth = 0;
1754     int imHeight = 0;
1755     char imFileName[129];
1756
1757     int base = 0;   // Useless data
1758
1759     char *fileText = LoadFileText(fileName);
1760
1761     if (fileText == NULL) return font;
1762
1763     char *fileTextPtr = fileText;
1764
1765     // NOTE: We skip first line, it contains no useful information
1766     int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1767     fileTextPtr += (lineBytes + 1);
1768
1769     // Read line data
1770     lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1771     searchPoint = strstr(buffer, "lineHeight");
1772     sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight);
1773     fileTextPtr += (lineBytes + 1);
1774
1775     TRACELOGD("FONT: [%s] Loaded font info:", fileName);
1776     TRACELOGD("    > Base size: %i", fontSize);
1777     TRACELOGD("    > Texture scale: %ix%i", imWidth, imHeight);
1778
1779     lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1780     searchPoint = strstr(buffer, "file");
1781     sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName);
1782     fileTextPtr += (lineBytes + 1);
1783
1784     TRACELOGD("    > Texture filename: %s", imFileName);
1785
1786     lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1787     searchPoint = strstr(buffer, "count");
1788     sscanf(searchPoint, "count=%i", &charsCount);
1789     fileTextPtr += (lineBytes + 1);
1790
1791     TRACELOGD("    > Chars count: %i", charsCount);
1792
1793     // Compose correct path using route of .fnt file (fileName) and imFileName
1794     char *imPath = NULL;
1795     char *lastSlash = NULL;
1796
1797     lastSlash = strrchr(fileName, '/');
1798     if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');
1799
1800     if (lastSlash != NULL)
1801     {
1802         // NOTE: We need some extra space to avoid memory corruption on next allocations!
1803         imPath = RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
1804         memcpy(imPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
1805         memcpy(imPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
1806     }
1807     else imPath = imFileName;
1808
1809     TRACELOGD("    > Image loading path: %s", imPath);
1810
1811     Image imFont = LoadImage(imPath);
1812
1813     if (imFont.format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE)
1814     {
1815         // Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
1816         Image imFontAlpha = {
1817             .data = calloc(imFont.width*imFont.height, 2),
1818             .width = imFont.width,
1819             .height = imFont.height,
1820             .format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,
1821             .mipmaps = 1
1822         };
1823
1824         for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
1825         {
1826             ((unsigned char *)(imFontAlpha.data))[p] = 0xff;
1827             ((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i];
1828         }
1829
1830         UnloadImage(imFont);
1831         imFont = imFontAlpha;
1832     }
1833
1834     font.texture = LoadTextureFromImage(imFont);
1835
1836     if (lastSlash != NULL) RL_FREE(imPath);
1837
1838     // Fill font characters info data
1839     font.baseSize = fontSize;
1840     font.charsCount = charsCount;
1841     font.charsPadding = 0;
1842     font.chars = (CharInfo *)RL_MALLOC(charsCount*sizeof(CharInfo));
1843     font.recs = (Rectangle *)RL_MALLOC(charsCount*sizeof(Rectangle));
1844
1845     int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
1846
1847     for (int i = 0; i < charsCount; i++)
1848     {
1849         lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
1850         sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
1851                        &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
1852         fileTextPtr += (lineBytes + 1);
1853
1854         // Get character rectangle in the font atlas texture
1855         font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
1856
1857         // Save data properly in sprite font
1858         font.chars[i].value = charId;
1859         font.chars[i].offsetX = charOffsetX;
1860         font.chars[i].offsetY = charOffsetY;
1861         font.chars[i].advanceX = charAdvanceX;
1862
1863         // Fill character image data from imFont data
1864         font.chars[i].image = ImageFromImage(imFont, font.recs[i]);
1865     }
1866
1867     UnloadImage(imFont);
1868     RL_FREE(fileText);
1869
1870     if (font.texture.id == 0)
1871     {
1872         UnloadFont(font);
1873         font = GetFontDefault();
1874         TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load texture, reverted to default font", fileName);
1875     }
1876     else TRACELOG(LOG_INFO, "FONT: [%s] Font loaded successfully", fileName);
1877
1878     return font;
1879 }
1880 #endif