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