Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
fontstash.h
Go to the documentation of this file.
1//
2// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
3//
4// This software is provided 'as-is', without any express or implied
5// warranty. In no event will the authors be held liable for any damages
6// arising from the use of this software.
7// Permission is granted to anyone to use this software for any purpose,
8// including commercial applications, and to alter it and redistribute it
9// freely, subject to the following restrictions:
10// 1. The origin of this software must not be misrepresented; you must not
11// claim that you wrote the original software. If you use this software
12// in a product, an acknowledgment in the product documentation would be
13// appreciated but is not required.
14// 2. Altered source versions must be plainly marked as such, and must not be
15// misrepresented as being the original software.
16// 3. This notice may not be removed or altered from any source distribution.
17//
18
19// Modified by Ionut Cava to work with the Divide Framework
20// Merged in SDF Pull request from: https://github.com/memononen/fontstash/pull/38/files?diff=unified
21
22#ifndef FONS_H
23#define FONS_H
24
25#ifdef __cplusplus
26extern "C" {
27#endif
28
29// To make the implementation private to the file that generates the implementation
30#ifdef FONS_STATIC
31#define FONS_DEF static
32#else
33#define FONS_DEF extern
34#endif
35
36#define FONS_INVALID -1
37
41};
42
44 // Horizontal align
45 FONS_ALIGN_LEFT = 1<<0, // Default
48 // Vertical align
52 FONS_ALIGN_BASELINE = 1<<6, // Default
53};
54
56{
57 float pos[2];
58 float tcoords[2];
59 unsigned char colours[4];
60};
61
63 // Font atlas is full.
65 // Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE.
67 // Calls to fonsPushState has created too large stack, if you need deep state stack bump up FONS_MAX_STATES.
69 // Trying to pop too many states fonsPopState().
71};
72
73struct FONSparams {
75 unsigned char flags;
76 void* userPtr;
77 int (*renderCreate)(void* uptr, int width, int height);
78 int (*renderResize)(void* uptr, int width, int height);
79 void (*renderUpdate)(void* uptr, int* rect, const unsigned char* data);
80 void (*renderDraw)(void* uptr, const FONSvert* verts, int nverts);
81 void (*renderDelete)(void* uptr);
82};
83typedef struct FONSparams FONSparams;
84
86{
87 float x0,y0,s0,t0;
88 float x1,y1,s1,t1;
89};
90typedef struct FONSquad FONSquad;
91
93 float x, y, nextx, nexty, scale, spacing;
94 unsigned int codepoint;
95 short isize, iblur;
96 struct FONSfont* font;
98 const char* str;
99 const char* next;
100 const char* end;
101 unsigned int utf8state;
102};
104
106{
107 unsigned char sdfEnabled;
108 unsigned char onedgeValue; // value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
109
110 int padding; // extra "pixels" around the character which are filled with the distance to the character (not 0),
111 // which allows effects like bit outlines
112
113 float pixelDistScale; // what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
114 // if positive, > onedge_value is inside; if negative, < onedge_value is inside
115};
117
118
120
121// Contructor and destructor.
124
125FONS_DEF void fonsSetErrorCallback(FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr);
126// Returns current atlas size.
127FONS_DEF void fonsGetAtlasSize(FONScontext* s, int* width, int* height);
128// Expands the atlas size.
129FONS_DEF int fonsExpandAtlas(FONScontext* s, int width, int height);
130// Resets the whole stash.
131FONS_DEF int fonsResetAtlas(FONScontext* stash, int width, int height);
132
133// Add fonts
134FONS_DEF int fonsAddFont(FONScontext* s, const char* name, const char* path);
135FONS_DEF int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData);
136#ifndef FONS_USE_FREETYPE
137FONS_DEF int fonsAddFontSdf(FONScontext* s, const char* name, const char* path, FONSsdfSettings sdfSettings);
138FONS_DEF int fonsAddFontSdfMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData, FONSsdfSettings sdfSettings);
139#endif
140FONS_DEF int fonsGetFontByName(FONScontext* s, const char* name);
141FONS_DEF int fonsAddFallbackFont(FONScontext* stash, int base, int fallback);
142
143// State handling
147
148// State setting
149FONS_DEF void fonsSetSize(FONScontext* s, float size);
150FONS_DEF void fonsSetColor(FONScontext* s, unsigned int color);
151FONS_DEF void fonsSetSpacing(FONScontext* s, float spacing);
152FONS_DEF void fonsSetBlur(FONScontext* s, float blur);
155FONS_DEF void fonsSetColour(FONScontext* s, unsigned char colourR, unsigned char colourG, unsigned char colourB, unsigned char colourA);
156
157// Draw text
158FONS_DEF float fonsDrawText(FONScontext* s, float x, float y, const char* string, const char* end);
159
160// Measure text
161FONS_DEF float fonsTextBounds(FONScontext* s, float x, float y, const char* string, const char* end, float* bounds);
162FONS_DEF void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy);
163FONS_DEF void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh);
164
165// Text iterator
166FONS_DEF int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end);
168
169// Pull texture changes
170FONS_DEF const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height);
172
173// Draws the stash texture for debugging
174FONS_DEF void fonsDrawDebug(FONScontext* s, float x, float y);
175
176
177FONS_DEF FONScontext* dummyfonsCreate( int width, int height, int flags );
179
180#ifdef __cplusplus
181}
182#endif
183
184#ifndef FONS_SCRATCH_BUF_SIZE
185# define FONS_SCRATCH_BUF_SIZE 64000
186#endif
187#ifndef FONS_HASH_LUT_SIZE
188# define FONS_HASH_LUT_SIZE 256
189#endif
190#ifndef FONS_INIT_FONTS
191# define FONS_INIT_FONTS 4
192#endif
193#ifndef FONS_INIT_GLYPHS
194# define FONS_INIT_GLYPHS 256
195#endif
196#ifndef FONS_INIT_ATLAS_NODES
197# define FONS_INIT_ATLAS_NODES 256
198#endif
199#ifndef FONS_VERTEX_COUNT
200# define FONS_VERTEX_COUNT 1024
201#endif
202#ifndef FONS_MAX_STATES
203# define FONS_MAX_STATES 20
204#endif
205#ifndef FONS_MAX_FALLBACKS
206# define FONS_MAX_FALLBACKS 20
207#endif
208
209
210#endif // FONS_H
211
212
213#ifdef FONTSTASH_IMPLEMENTATION
214
215#define FONS_NOTUSED(v) (void)sizeof(v)
216
217#ifdef FONS_USE_FREETYPE
218
219#include <ft2build.h>
220#include FT_FREETYPE_H
221#include FT_ADVANCES_H
222#include <math.h>
223
224struct FONSttFontImpl {
225 FT_Face font;
226};
227typedef struct FONSttFontImpl FONSttFontImpl;
228
229static FT_Library ftLibrary;
230
231static int fons__tt_init()
232{
233 FT_Error ftError;
234 FONS_NOTUSED(context);
235 ftError = FT_Init_FreeType(&ftLibrary);
236 return ftError == 0;
237}
238
239static int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize)
240{
241 FT_Error ftError;
242 FONS_NOTUSED(context);
243
244 //font->font.userdata = stash;
245 ftError = FT_New_Memory_Face(ftLibrary, (const FT_Byte*)data, dataSize, 0, &font->font);
246 return ftError == 0;
247}
248
249static void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
250{
251 *ascent = font->font->ascender;
252 *descent = font->font->descender;
253 *lineGap = font->font->height - (*ascent - *descent);
254}
255
256static float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
257{
258 return size / (font->font->ascender - font->font->descender);
259}
260
261static int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
262{
263 return FT_Get_Char_Index(font->font, codepoint);
264}
265
266static int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
267 int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1, const FONSsdfSettings* sdfSettings)
268{
269 FT_Error ftError;
270 FT_GlyphSlot ftGlyph;
271 FT_Fixed advFixed;
272 FONS_NOTUSED(scale);
273 FONS_NOTUSED(sdfSettings);
274
275 ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender)));
276 if (ftError) return 0;
277 ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER);
278 if (ftError) return 0;
279 ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
280 if (ftError) return 0;
281 ftGlyph = font->font->glyph;
282 *advance = (int)advFixed;
283 *lsb = (int)ftGlyph->metrics.horiBearingX;
284 *x0 = ftGlyph->bitmap_left;
285 *x1 = *x0 + ftGlyph->bitmap.width;
286 *y0 = -ftGlyph->bitmap_top;
287 *y1 = *y0 + ftGlyph->bitmap.rows;
288 return 1;
289}
290
291static void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
292 float scaleX, float scaleY, int glyph, const FONSsdfSettings* sdfSettings)
293{
294 FT_GlyphSlot ftGlyph = font->font->glyph;
295 int ftGlyphOffset = 0;
296 int x, y;
297 FONS_NOTUSED(outWidth);
298 FONS_NOTUSED(outHeight);
299 FONS_NOTUSED(scaleX);
300 FONS_NOTUSED(scaleY);
301 FONS_NOTUSED(glyph); // glyph has already been loaded by fons__tt_buildGlyphBitmap
302 FONS_NOTUSED(sdfSettings);
303
304 for ( y = 0; y < ftGlyph->bitmap.rows; y++ ) {
305 for ( x = 0; x < ftGlyph->bitmap.width; x++ ) {
306 output[(y * outStride) + x] = ftGlyph->bitmap.buffer[ftGlyphOffset++];
307 }
308 }
309}
310
311static int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
312{
313 FT_Vector ftKerning;
314 FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
315 return (int)((ftKerning.x + 32) >> 6); // Round up and convert to integer
316}
317
318#else
319
320#define STB_TRUETYPE_IMPLEMENTATION
321#define STBTT_STATIC
322static void* fons__tmpalloc(size_t size, void* up);
323static void fons__tmpfree(void* ptr, void* up);
324#define STBTT_malloc(x,u) fons__tmpalloc(x,u)
325#define STBTT_free(x,u) fons__tmpfree(x,u)
326
327
328#ifdef _MSC_VER
329#pragma warning(push)
330#pragma warning(disable:4505) //unreferenced local function has been removed
331#endif //_MSC_VER
332#include <stb_truetype.h>
333#ifdef _MSC_VER
334#pragma warning(pop)
335#endif //_MSC_VER
336
337struct FONSttFontImpl {
338 stbtt_fontinfo font;
339};
340typedef struct FONSttFontImpl FONSttFontImpl;
341
342static int fons__tt_init(FONScontext *context)
343{
344 FONS_NOTUSED(context);
345 return 1;
346}
347
348static int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize)
349{
350 FONS_NOTUSED(dataSize);
351
352 font->font.userdata = context;
353 int stbError = stbtt_InitFont(&font->font, data, 0);
354 return stbError;
355}
356
357static void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
358{
359 stbtt_GetFontVMetrics(&font->font, ascent, descent, lineGap);
360}
361
362static float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
363{
364 return stbtt_ScaleForPixelHeight(&font->font, size);
365}
366
367static int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
368{
369 return stbtt_FindGlyphIndex(&font->font, codepoint);
370}
371
372static int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
373 int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1, const FONSsdfSettings* sdfSettings)
374{
375 FONS_NOTUSED(size);
376 stbtt_GetGlyphHMetrics(&font->font, glyph, advance, lsb);
377 stbtt_GetGlyphBitmapBox(&font->font, glyph, scale, scale, x0, y0, x1, y1);
378
379 if (sdfSettings->sdfEnabled)
380 {
381 *x0 -= sdfSettings->padding;
382 *y0 -= sdfSettings->padding;
383 *x1 += sdfSettings->padding;
384 *y1 += sdfSettings->padding;
385 }
386
387 return 1;
388}
389
390static void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
391 float scaleX, float scaleY, int glyph, const FONSsdfSettings* sdfSettings)
392{
393 if (!sdfSettings->sdfEnabled)
394 {
395 stbtt_MakeGlyphBitmap(&font->font, output, outWidth, outHeight, outStride, scaleX, scaleY, glyph);
396 }
397 else
398 {
399 int w = 0, h = 0, xoff = 0, yoff = 0;
400 unsigned char* sdfData = stbtt_GetGlyphSDF(&font->font, scaleX, glyph, sdfSettings->padding, sdfSettings->onedgeValue, sdfSettings->pixelDistScale, &w, &h, &xoff, &yoff);
401
402 for (int y = 0; y < h; y++)
403 {
404 unsigned char* outRow = output + outStride*y;
405 unsigned char* inRow = sdfData + w*y;
406
407 memcpy(outRow, inRow, w);
408 }
409
410 if (sdfData)
411 stbtt_FreeSDF(sdfData, nullptr);
412 }
413}
414
415static int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
416{
417 return stbtt_GetGlyphKernAdvance(&font->font, glyph1, glyph2);
418}
419
420#endif
421
422static unsigned int fons__hashint(unsigned int a)
423{
424 a += ~(a<<15);
425 a ^= a>>10;
426 a += a<<3;
427 a ^= a>>6;
428 a += ~(a<<11);
429 a ^= a>>16;
430 return a;
431}
432
433static int fons__mini(int a, int b)
434{
435 return a < b ? a : b;
436}
437
438static int fons__maxi(int a, int b)
439{
440 return a > b ? a : b;
441}
442
443struct FONSglyph
444{
445 unsigned int codepoint;
446 int index;
447 int next;
448 short size, blur;
449 short x0,y0,x1,y1;
450 short xadv,xoff,yoff;
451};
452typedef struct FONSglyph FONSglyph;
453
454struct FONSfont
455{
456 FONSttFontImpl font;
457 char name[64];
458 unsigned char* data;
459 int dataSize;
460 unsigned char freeData;
461 float ascender;
462 float descender;
463 float lineh;
464 FONSglyph* glyphs;
465 int cglyphs;
466 int nglyphs;
467 int lut[FONS_HASH_LUT_SIZE];
468 int fallbacks[FONS_MAX_FALLBACKS];
469 int nfallbacks;
470 FONSsdfSettings sdfSettings;
471};
472typedef struct FONSfont FONSfont;
473
474struct FONSstate
475{
476 int font;
477 int align;
478 float size;
479 unsigned char colour[4];
480 float blur;
481 float spacing;
482};
483typedef struct FONSstate FONSstate;
484
485struct FONSatlasNode {
486 short x, y, width;
487};
488typedef struct FONSatlasNode FONSatlasNode;
489
490struct FONSatlas
491{
492 int width, height;
493 FONSatlasNode* nodes;
494 int nnodes;
495 int cnodes;
496};
497typedef struct FONSatlas FONSatlas;
498
499struct FONScontext
500{
501 FONSparams params;
502 float itw,ith;
503 unsigned char* texData;
504 int dirtyRect[4];
505 FONSfont** fonts;
506 FONSatlas* atlas;
507 int cfonts;
508 int nfonts;
510 int nverts;
511 unsigned char* scratch;
512 int nscratch;
513 FONSstate states[FONS_MAX_STATES];
514 int nstates;
515 void (*handleError)(void* uptr, int error, int val);
516 void* errorUptr;
517};
518
519#ifdef STB_TRUETYPE_IMPLEMENTATION
520
521static void* fons__tmpalloc(size_t size, void* up)
522{
523 FONScontext* stash = (FONScontext*)up;
524
525 // 16-byte align the returned pointer
526 size = size + 0xf & ~0xf;
527
528 if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE) {
529 if (stash->handleError)
530 stash->handleError(stash->errorUptr, FONS_SCRATCH_FULL, stash->nscratch+(int)size);
531 return nullptr;
532 }
533 unsigned char* ptr = stash->scratch + stash->nscratch;
534 stash->nscratch += (int)size;
535 return ptr;
536}
537
538static void fons__tmpfree(void* ptr, void* up)
539{
540 (void)ptr;
541 (void)up;
542 // empty
543}
544
545#endif // STB_TRUETYPE_IMPLEMENTATION
546
547// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
548// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
549
550#define FONS_UTF8_ACCEPT 0
551#define FONS_UTF8_REJECT 12
552
553static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
554{
555 constexpr unsigned char utf8d[] = {
556 // The first part of the table maps bytes to character classes that
557 // to reduce the size of the transition table and create bitmasks.
558 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
559 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
560 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
561 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
562 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
563 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
564 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
565 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
566
567 // The second part is a transition table that maps a combination
568 // of a state of the automaton and a character class to a state.
569 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
570 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
571 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
572 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
573 12,36,12,12,12,12,12,12,12,12,12,12,
574 };
575
576 const unsigned int type = utf8d[byte];
577
578 *codep = *state != FONS_UTF8_ACCEPT ?
579 (byte & 0x3fu) | (*codep << 6) :
580 (0xff >> type) & byte;
581
582 *state = utf8d[256 + *state + type];
583 return *state;
584}
585
586// Atlas based on Skyline Bin Packer by Jukka Jylänki
587
588static void fons__deleteAtlas(FONSatlas* atlas)
589{
590 if (atlas == nullptr) return;
591 if (atlas->nodes != nullptr) free(atlas->nodes);
592 free(atlas);
593}
594
595static FONSatlas* fons__allocAtlas(int w, int h, int nnodes)
596{
597 FONSatlas* atlas = nullptr;
598
599 // Allocate memory for the font stash.
600 atlas = (FONSatlas*)malloc(sizeof(FONSatlas));
601 if (atlas == nullptr) goto error;
602 memset(atlas, 0, sizeof(FONSatlas));
603
604 atlas->width = w;
605 atlas->height = h;
606
607 // Allocate space for skyline nodes
608 atlas->nodes = (FONSatlasNode*)malloc(sizeof(FONSatlasNode) * nnodes);
609 if (atlas->nodes == nullptr) goto error;
610 memset(atlas->nodes, 0, sizeof(FONSatlasNode) * nnodes);
611 atlas->nnodes = 0;
612 atlas->cnodes = nnodes;
613
614 // Init root node.
615 atlas->nodes[0].x = 0;
616 atlas->nodes[0].y = 0;
617 atlas->nodes[0].width = (short)w;
618 atlas->nnodes++;
619
620 return atlas;
621
622error:
623 if (atlas) fons__deleteAtlas(atlas);
624 return nullptr;
625}
626
627static int fons__atlasInsertNode(FONSatlas* atlas, int idx, int x, int y, int w)
628{
629 // Insert node
630 if (atlas->nnodes+1 > atlas->cnodes) {
631 atlas->cnodes = atlas->cnodes == 0 ? 8 : atlas->cnodes * 2;
632 atlas->nodes = (FONSatlasNode*)realloc(atlas->nodes, sizeof(FONSatlasNode) * atlas->cnodes);
633 if (atlas->nodes == nullptr)
634 return 0;
635 }
636
637 for (int i = atlas->nnodes; i > idx; i--)
638 {
639 atlas->nodes[i] = atlas->nodes[i-1];
640 }
641
642 atlas->nodes[idx].x = (short)x;
643 atlas->nodes[idx].y = (short)y;
644 atlas->nodes[idx].width = (short)w;
645 atlas->nnodes++;
646
647 return 1;
648}
649
650static void fons__atlasRemoveNode(FONSatlas* atlas, int idx)
651{
652 if (atlas->nnodes == 0) return;
653 for (int i = idx; i < atlas->nnodes-1; i++)
654 atlas->nodes[i] = atlas->nodes[i+1];
655 atlas->nnodes--;
656}
657
658static void fons__atlasExpand(FONSatlas* atlas, int w, int h)
659{
660 // Insert node for empty space
661 if (w > atlas->width)
662 fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width);
663 atlas->width = w;
664 atlas->height = h;
665}
666
667static void fons__atlasReset(FONSatlas* atlas, int w, int h)
668{
669 atlas->width = w;
670 atlas->height = h;
671 atlas->nnodes = 0;
672
673 // Init root node.
674 atlas->nodes[0].x = 0;
675 atlas->nodes[0].y = 0;
676 atlas->nodes[0].width = (short)w;
677 atlas->nnodes++;
678}
679
680static int fons__atlasAddSkylineLevel(FONSatlas* atlas, int idx, int x, int y, int w, int h)
681{
682 int i;
683
684 // Insert new node
685 if (fons__atlasInsertNode(atlas, idx, x, y+h, w) == 0)
686 return 0;
687
688 // Delete skyline segments that fall under the shadow of the new segment.
689 for (i = idx+1; i < atlas->nnodes; i++) {
690 if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) {
691 const int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x;
692 atlas->nodes[i].x += (short)shrink;
693 atlas->nodes[i].width -= (short)shrink;
694 if (atlas->nodes[i].width <= 0) {
695 fons__atlasRemoveNode(atlas, i);
696 i--;
697 } else {
698 break;
699 }
700 } else {
701 break;
702 }
703 }
704
705 // Merge same height skyline segments that are next to each other.
706 for (i = 0; i < atlas->nnodes-1; i++) {
707 if (atlas->nodes[i].y == atlas->nodes[i+1].y) {
708 atlas->nodes[i].width += atlas->nodes[i+1].width;
709 fons__atlasRemoveNode(atlas, i+1);
710 i--;
711 }
712 }
713
714 return 1;
715}
716
717static int fons__atlasRectFits(FONSatlas* atlas, int i, int w, int h)
718{
719 // Checks if there is enough space at the location of skyline span 'i',
720 // and return the max height of all skyline spans under that at that location,
721 // (think tetris block being dropped at that position). Or -1 if no space found.
722 const int x = atlas->nodes[i].x;
723 int y = atlas->nodes[i].y;
724 if (x + w > atlas->width)
725 {
726 return -1;
727 }
728 int spaceLeft = w;
729
730 while (spaceLeft > 0)
731 {
732 if (i == atlas->nnodes) return -1;
733 y = fons__maxi(y, atlas->nodes[i].y);
734 if (y + h > atlas->height) return -1;
735 spaceLeft -= atlas->nodes[i].width;
736 ++i;
737 }
738
739 return y;
740}
741
742static int fons__atlasAddRect(FONSatlas* atlas, int rw, int rh, int* rx, int* ry)
743{
744 int besth = atlas->height, bestw = atlas->width, besti = -1;
745 int bestx = -1, besty = -1;
746
747 // Bottom left fit heuristic.
748 for (int i = 0; i < atlas->nnodes; i++) {
749 const int y = fons__atlasRectFits(atlas, i, rw, rh);
750 if (y != -1) {
751 if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw))
752 {
753 besti = i;
754 bestw = atlas->nodes[i].width;
755 besth = y + rh;
756 bestx = atlas->nodes[i].x;
757 besty = y;
758 }
759 }
760 }
761
762 if (besti == -1)
763 return 0;
764
765 // Perform the actual packing.
766 if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0)
767 return 0;
768
769 *rx = bestx;
770 *ry = besty;
771
772 return 1;
773}
774
775static void fons__addWhiteRect(FONScontext* stash, int w, int h)
776{
777 int gx, gy;
778 if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
779 return;
780
781 // Rasterize
782 unsigned char* dst = &stash->texData[gx + gy * stash->params.width];
783 for (int y = 0; y < h; y++) {
784 for (int x = 0; x < w; x++)
785 dst[x] = 0xff;
786 dst += stash->params.width;
787 }
788
789 stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
790 stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
791 stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
792 stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
793}
794
796{
797 FONScontext* stash = nullptr;
798
799 // Allocate memory for the font stash.
800 stash = (FONScontext*)malloc(sizeof(FONScontext));
801 if (stash == nullptr) goto error;
802 memset(stash, 0, sizeof(FONScontext));
803
804 stash->params = *params;
805
806 // Allocate scratch buffer.
807 stash->scratch = (unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE);
808 if (stash->scratch == nullptr) goto error;
809
810 // Initialize implementation library
811 if (!fons__tt_init(stash)) goto error;
812
813 if (stash->params.renderCreate != nullptr) {
814 if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
815 goto error;
816 }
817
818 stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES);
819 if (stash->atlas == nullptr) goto error;
820
821 // Allocate space for fonts.
822 stash->fonts = (FONSfont**)malloc(sizeof(FONSfont*) * FONS_INIT_FONTS);
823 if (stash->fonts == nullptr) goto error;
824 memset(stash->fonts, 0, sizeof(FONSfont*) * FONS_INIT_FONTS);
825 stash->cfonts = FONS_INIT_FONTS;
826 stash->nfonts = 0;
827
828 // Create texture for the cache.
829 stash->itw = 1.0f/stash->params.width;
830 stash->ith = 1.0f/stash->params.height;
831 stash->texData = (unsigned char*)malloc(stash->params.width * stash->params.height);
832 if (stash->texData == nullptr) goto error;
833 memset(stash->texData, 0, stash->params.width * stash->params.height);
834
835 stash->dirtyRect[0] = stash->params.width;
836 stash->dirtyRect[1] = stash->params.height;
837 stash->dirtyRect[2] = 0;
838 stash->dirtyRect[3] = 0;
839
840 // Add white rect at 0,0 for debug drawing.
841 fons__addWhiteRect(stash, 2,2);
842
843 fonsPushState(stash);
844 fonsClearState(stash);
845
846 return stash;
847
848error:
849 fonsDeleteInternal(stash);
850 return nullptr;
851}
852
853static FONSstate* fons__getState(FONScontext* stash)
854{
855 return &stash->states[stash->nstates-1];
856}
857
858int fonsAddFallbackFont(FONScontext* stash, int base, int fallback)
859{
860 FONSfont* baseFont = stash->fonts[base];
861 if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
862 baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
863 return 1;
864 }
865 return 0;
866}
867
868void fonsSetSize(FONScontext* stash, float size)
869{
870 fons__getState(stash)->size = size;
871}
872
873void fonsSetColour(struct FONScontext* stash, unsigned char colourR, unsigned char colourG, unsigned char colourB, unsigned char colourA)
874{
875 fons__getState(stash)->colour[0] = colourR;
876 fons__getState(stash)->colour[1] = colourG;
877 fons__getState(stash)->colour[2] = colourB;
878 fons__getState(stash)->colour[3] = colourA;
879}
880void fonsSetSpacing(FONScontext* stash, float spacing)
881{
882 fons__getState(stash)->spacing = spacing;
883}
884
885void fonsSetBlur(FONScontext* stash, float blur)
886{
887 fons__getState(stash)->blur = blur;
888}
889
890void fonsSetAlign(FONScontext* stash, int align)
891{
892 fons__getState(stash)->align = align;
893}
894
895void fonsSetFont(FONScontext* stash, int font)
896{
897 fons__getState(stash)->font = font;
898}
899
900void fonsPushState(FONScontext* stash)
901{
902 if (stash->nstates >= FONS_MAX_STATES) {
903 if (stash->handleError)
904 stash->handleError(stash->errorUptr, FONS_STATES_OVERFLOW, 0);
905 return;
906 }
907 if (stash->nstates > 0)
908 memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(FONSstate));
909 stash->nstates++;
910}
911
912void fonsPopState(FONScontext* stash)
913{
914 if (stash->nstates <= 1) {
915 if (stash->handleError)
916 stash->handleError(stash->errorUptr, FONS_STATES_UNDERFLOW, 0);
917 return;
918 }
919 stash->nstates--;
920}
921
922void fonsClearState(FONScontext* stash)
923{
924 FONSstate* state = fons__getState(stash);
925 state->size = 12.0f;
926 state->colour[0] = 0xff;
927 state->colour[1] = 0xff;
928 state->colour[2] = 0xff;
929 state->colour[3] = 0xff;
930 state->font = 0;
931 state->blur = 0;
932 state->spacing = 0;
933 state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE;
934}
935
936static void fons__freeFont(FONSfont* font)
937{
938 if (font == nullptr) return;
939 if (font->glyphs) free(font->glyphs);
940 if (font->freeData && font->data) free(font->data);
941 free(font);
942}
943
944static int fons__allocFont(FONScontext* stash)
945{
946 FONSfont* font = nullptr;
947 if (stash->nfonts+1 > stash->cfonts) {
948 stash->cfonts = stash->cfonts == 0 ? 8 : stash->cfonts * 2;
949 stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts);
950 if (stash->fonts == nullptr)
951 return -1;
952 }
953 font = (FONSfont*)malloc(sizeof(FONSfont));
954 if (font == nullptr) goto error;
955 memset(font, 0, sizeof(FONSfont));
956
957 font->glyphs = (FONSglyph*)malloc(sizeof(FONSglyph) * FONS_INIT_GLYPHS);
958 if (font->glyphs == nullptr) goto error;
959 font->cglyphs = FONS_INIT_GLYPHS;
960 font->nglyphs = 0;
961
962 stash->fonts[stash->nfonts++] = font;
963 return stash->nfonts-1;
964
965error:
966 fons__freeFont(font);
967
968 return FONS_INVALID;
969}
970
971static FILE* fons__fopen(const char* filename, const char* mode)
972{
973#ifdef _WIN32
974 int len = 0;
975 const int fileLen = (int)strlen(filename);
976 const int modeLen = (int)strlen(mode);
977 wchar_t wpath[MAX_PATH];
978 wchar_t wmode[MAX_PATH];
979
980 if (fileLen == 0)
981 return nullptr;
982 if (modeLen == 0)
983 return nullptr;
984 len = MultiByteToWideChar(CP_UTF8, 0, filename, fileLen, wpath, fileLen);
985 if (len >= MAX_PATH)
986 return nullptr;
987 wpath[len] = L'\0';
988 len = MultiByteToWideChar(CP_UTF8, 0, mode, modeLen, wmode, modeLen);
989 if (len >= MAX_PATH)
990 return nullptr;
991 wmode[len] = L'\0';
992 FILE* f = _wfopen(wpath, wmode);
993 return f;
994#else
995 return fopen(filename, mode);
996#endif
997}
998
999int fonsAddFont(FONScontext* stash, const char* name, const char* path)
1000{
1001 FONSsdfSettings sdfSettings;
1002 memset(&sdfSettings, 0, sizeof(FONSsdfSettings));
1003 sdfSettings.sdfEnabled = 0;
1004
1005 return fonsAddFontSdf(stash, name, path, sdfSettings);
1006}
1007
1008
1009int fonsAddFontSdf(FONScontext* stash, const char* name, const char* path, FONSsdfSettings sdfSettings)
1010{
1011 FILE* fp = nullptr;
1012 int dataSize = 0, readed = 0;
1013 unsigned char* data = nullptr;
1014
1015 // Read in the font data.
1016 fp = fons__fopen(path, "rb");
1017 if (fp == nullptr) goto error;
1018 fseek(fp,0,SEEK_END);
1019 dataSize = (int)ftell(fp);
1020 fseek(fp,0,SEEK_SET);
1021 data = (unsigned char*)malloc(dataSize);
1022 if (data == nullptr) goto error;
1023 readed = (int)fread(data, 1, dataSize, fp);
1024 fclose(fp);
1025 fp = nullptr;
1026 if (readed != dataSize) goto error;
1027
1028 return fonsAddFontSdfMem(stash, name, data, dataSize, 1, sdfSettings);
1029
1030error:
1031 if (data) free(data);
1032 if (fp) fclose(fp);
1033 return FONS_INVALID;
1034}
1035
1036int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData)
1037{
1038 FONSsdfSettings sdfSettings;
1039 memset(&sdfSettings, 0, sizeof(FONSsdfSettings));
1040 sdfSettings.sdfEnabled = 0;
1041
1042 return fonsAddFontSdfMem(stash, name, data, dataSize, freeData, sdfSettings);
1043}
1044
1045int fonsAddFontSdfMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData, FONSsdfSettings sdfSettings)
1046{
1047 int ascent, descent, lineGap, fh;
1048
1049 const int idx = fons__allocFont(stash);
1050 if (idx == FONS_INVALID)
1051 return FONS_INVALID;
1052
1053 FONSfont* font = stash->fonts[idx];
1054 font->sdfSettings = sdfSettings;
1055
1056 strncpy(font->name, name, sizeof font->name);
1057 font->name[sizeof font->name-1] = '\0';
1058
1059 // Init hash lookup.
1060 for (int i = 0; i < FONS_HASH_LUT_SIZE; ++i)
1061 font->lut[i] = -1;
1062
1063 // Read in the font data.
1064 font->dataSize = dataSize;
1065 font->data = data;
1066 font->freeData = (unsigned char)freeData;
1067
1068 // Init font
1069 stash->nscratch = 0;
1070 if (!fons__tt_loadFont(stash, &font->font, data, dataSize)) goto error;
1071
1072 // Store normalized line height. The real line height is got
1073 // by multiplying the lineh by font size.
1074 fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);
1075 fh = ascent - descent;
1076 font->ascender = (float)ascent / (float)fh;
1077 font->descender = (float)descent / (float)fh;
1078 font->lineh = (float)(fh + lineGap) / (float)fh;
1079
1080 return idx;
1081
1082error:
1083 fons__freeFont(font);
1084 stash->nfonts--;
1085 return FONS_INVALID;
1086}
1087
1088int fonsGetFontByName(FONScontext* s, const char* name)
1089{
1090 for (int i = 0; i < s->nfonts; i++) {
1091 if (strcmp(s->fonts[i]->name, name) == 0)
1092 return i;
1093 }
1094 return FONS_INVALID;
1095}
1096
1097
1098static FONSglyph* fons__allocGlyph(FONSfont* font)
1099{
1100 if (font->nglyphs+1 > font->cglyphs) {
1101 font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2;
1102 font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs);
1103 if (font->glyphs == nullptr) return nullptr;
1104 }
1105 font->nglyphs++;
1106 return &font->glyphs[font->nglyphs-1];
1107}
1108
1109
1110// Based on Exponential blur, Jani Huhtanen, 2006
1111
1112#define APREC 16
1113#define ZPREC 7
1114
1115static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha)
1116{
1117 int x;
1118 for (int y = 0; y < h; y++) {
1119 int z = 0; // force zero border
1120 for (x = 1; x < w; x++) {
1121 z += alpha * (((int)dst[x] << ZPREC) - z) >> APREC;
1122 dst[x] = (unsigned char)(z >> ZPREC);
1123 }
1124 dst[w-1] = 0; // force zero border
1125 z = 0;
1126 for (x = w-2; x >= 0; x--) {
1127 z += alpha * (((int)dst[x] << ZPREC) - z) >> APREC;
1128 dst[x] = (unsigned char)(z >> ZPREC);
1129 }
1130 dst[0] = 0; // force zero border
1131 dst += dstStride;
1132 }
1133}
1134
1135static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha)
1136{
1137 int y;
1138 for (int x = 0; x < w; x++) {
1139 int z = 0; // force zero border
1140 for (y = dstStride; y < h*dstStride; y += dstStride) {
1141 z += alpha * (((int)dst[y] << ZPREC) - z) >> APREC;
1142 dst[y] = (unsigned char)(z >> ZPREC);
1143 }
1144 dst[(h-1)*dstStride] = 0; // force zero border
1145 z = 0;
1146 for (y = (h-2)*dstStride; y >= 0; y -= dstStride) {
1147 z += alpha * (((int)dst[y] << ZPREC) - z) >> APREC;
1148 dst[y] = (unsigned char)(z >> ZPREC);
1149 }
1150 dst[0] = 0; // force zero border
1151 dst++;
1152 }
1153}
1154
1155
1156static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur)
1157{
1158 (void)stash;
1159
1160 if (blur < 1)
1161 return;
1162 // Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity)
1163 float sigma = (float)blur * 0.57735f; // 1 / sqrt(3)
1164 int alpha = (int)((1 << APREC) * (1.0f - expf(-2.3f / (sigma + 1.0f))));
1165 fons__blurRows(dst, w, h, dstStride, alpha);
1166 fons__blurCols(dst, w, h, dstStride, alpha);
1167 fons__blurRows(dst, w, h, dstStride, alpha);
1168 fons__blurCols(dst, w, h, dstStride, alpha);
1169// fons__blurrows(dst, w, h, dstStride, alpha);
1170// fons__blurcols(dst, w, h, dstStride, alpha);
1171}
1172
1173static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
1174 short isize, short iblur)
1175{
1176 int advance, lsb, x0, y0, x1, y1, gx, gy;
1177 FONSglyph* glyph = nullptr;
1178 const float size = isize/10.0f;
1179 FONSfont* renderFont = font;
1180
1181 if (isize < 2) return nullptr;
1182 if (iblur > 20) iblur = 20;
1183 int pad = iblur + 2;
1184
1185 // Reset allocator.
1186 stash->nscratch = 0;
1187
1188 // Find code point and size.
1189 unsigned int h = fons__hashint(codepoint) & FONS_HASH_LUT_SIZE - 1;
1190 int i = font->lut[h];
1191 while (i != -1) {
1192 if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur)
1193 return &font->glyphs[i];
1194 i = font->glyphs[i].next;
1195 }
1196
1197 // Could not find glyph, create it.
1198 int g = fons__tt_getGlyphIndex(&font->font, codepoint);
1199 // Try to find the glyph in fallback fonts.
1200 if (g == 0) {
1201 for (i = 0; i < font->nfallbacks; ++i) {
1202 FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
1203 const int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
1204 if (fallbackIndex != 0) {
1205 g = fallbackIndex;
1206 renderFont = fallbackFont;
1207 break;
1208 }
1209 }
1210 // It is possible that we did not find a fallback glyph.
1211 // In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph.
1212 }
1213 float scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
1214 fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1, &renderFont->sdfSettings);
1215 int gw = x1 - x0 + pad * 2;
1216 int gh = y1 - y0 + pad * 2;
1217
1218 // Find free spot for the rect in the atlas
1219 int added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1220 if (added == 0 && stash->handleError != nullptr) {
1221 // Atlas is full, let the user to resize the atlas (or not), and try again.
1222 stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
1223 added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1224 }
1225 if (added == 0) return nullptr;
1226
1227 // Init glyph.
1228 glyph = fons__allocGlyph(font);
1229 glyph->codepoint = codepoint;
1230 glyph->size = isize;
1231 glyph->blur = iblur;
1232 glyph->index = g;
1233 glyph->x0 = (short)gx;
1234 glyph->y0 = (short)gy;
1235 glyph->x1 = (short)(glyph->x0+gw);
1236 glyph->y1 = (short)(glyph->y0+gh);
1237 glyph->xadv = (short)(scale * advance * 10.0f);
1238 glyph->xoff = (short)(x0 - pad);
1239 glyph->yoff = (short)(y0 - pad);
1240 glyph->next = 0;
1241
1242 // Insert char to hash lookup.
1243 glyph->next = font->lut[h];
1244 font->lut[h] = font->nglyphs-1;
1245
1246 // Rasterize
1247 unsigned char* dst = &stash->texData[glyph->x0 + pad + (glyph->y0 + pad) * stash->params.width];
1248 fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale,scale, g, &renderFont->sdfSettings);
1249
1250 // Make sure there is one pixel empty border.
1251 dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1252 for (int y = 0; y < gh; y++) {
1253 dst[y*stash->params.width] = 0;
1254 dst[gw-1 + y*stash->params.width] = 0;
1255 }
1256 for (int x = 0; x < gw; x++) {
1257 dst[x] = 0;
1258 dst[x + (gh-1)*stash->params.width] = 0;
1259 }
1260
1261 // Debug code to color the glyph background
1262/* unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1263 for (y = 0; y < gh; y++) {
1264 for (x = 0; x < gw; x++) {
1265 int a = (int)fdst[x+y*stash->params.width] + 20;
1266 if (a > 255) a = 255;
1267 fdst[x+y*stash->params.width] = a;
1268 }
1269 }*/
1270
1271 // Blur
1272 if (iblur > 0) {
1273 stash->nscratch = 0;
1274 unsigned char* bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1275 fons__blur(stash, bdst, gw,gh, stash->params.width, iblur);
1276 }
1277
1278 stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
1279 stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
1280 stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
1281 stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);
1282
1283 return glyph;
1284}
1285
1286static void fons__getQuad(FONScontext* stash, FONSfont* font,
1287 int prevGlyphIndex, FONSglyph* glyph,
1288 float scale, float spacing, float* x, float* y, FONSquad* q)
1289{
1290 float rx,ry;
1291
1292 if (prevGlyphIndex != -1) {
1293 const float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale;
1294 *x += (int)(adv + spacing + 0.5f);
1295 }
1296
1297 // Each glyph has 2px border to allow good interpolation,
1298 // one pixel to prevent leaking, and one to allow good interpolation for rendering.
1299 // Inset the texture region by one pixel for correct interpolation.
1300 float xoff = (short)(glyph->xoff + 1);
1301 float yoff = (short)(glyph->yoff + 1);
1302 float x0 = (float)(glyph->x0 + 1);
1303 float y0 = (float)(glyph->y0 + 1);
1304 float x1 = (float)(glyph->x1 - 1);
1305 float y1 = (float)(glyph->y1 - 1);
1306
1307 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1308 rx = (float)(int)(*x + xoff);
1309 ry = (float)(int)(*y + yoff);
1310
1311 q->x0 = rx;
1312 q->y0 = ry;
1313 q->x1 = rx + x1 - x0;
1314 q->y1 = ry + y1 - y0;
1315
1316 q->s0 = x0 * stash->itw;
1317 q->t0 = y0 * stash->ith;
1318 q->s1 = x1 * stash->itw;
1319 q->t1 = y1 * stash->ith;
1320 } else {
1321 rx = (float)(int)(*x + xoff);
1322 ry = (float)(int)(*y - yoff);
1323
1324 q->x0 = rx;
1325 q->y0 = ry;
1326 q->x1 = rx + x1 - x0;
1327 q->y1 = ry - y1 + y0;
1328
1329 q->s0 = x0 * stash->itw;
1330 q->t0 = y0 * stash->ith;
1331 q->s1 = x1 * stash->itw;
1332 q->t1 = y1 * stash->ith;
1333 }
1334
1335 *x += (int)(glyph->xadv / 10.0f + 0.5f);
1336}
1337
1338static void fons__flush(FONScontext* stash)
1339{
1340 // Flush texture
1341 if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1342 if (stash->params.renderUpdate != nullptr)
1343 stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData);
1344 // Reset dirty rect
1345 stash->dirtyRect[0] = stash->params.width;
1346 stash->dirtyRect[1] = stash->params.height;
1347 stash->dirtyRect[2] = 0;
1348 stash->dirtyRect[3] = 0;
1349 }
1350
1351 // Flush triangles
1352 if (stash->nverts > 0) {
1353 if (stash->params.renderDraw != nullptr)
1354 stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->nverts);
1355 stash->nverts = 0;
1356 }
1357}
1358
1359static __inline void fons__vertex(FONScontext* stash, float x, float y, float s, float t, unsigned char cR, unsigned char cG, unsigned char cB, unsigned char cA)
1360{
1361 stash->verts[stash->nverts].pos[0] = x;
1362 stash->verts[stash->nverts].pos[1] = y;
1363
1364 stash->verts[stash->nverts].tcoords[0] = s;
1365 stash->verts[stash->nverts].tcoords[1] = t;
1366
1367 stash->verts[stash->nverts].colours[0] = cR;
1368 stash->verts[stash->nverts].colours[1] = cG;
1369 stash->verts[stash->nverts].colours[2] = cB;
1370 stash->verts[stash->nverts].colours[3] = cA;
1371 stash->nverts++;
1372}
1373
1374static float fons__getVertAlign(FONScontext* stash, FONSfont* font, int align, short isize)
1375{
1376 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1377 if (align & FONS_ALIGN_TOP) {
1378 return font->ascender * (float)isize/10.0f;
1379 } else if (align & FONS_ALIGN_MIDDLE) {
1380 return (font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
1381 } else if (align & FONS_ALIGN_BASELINE) {
1382 return 0.0f;
1383 } else if (align & FONS_ALIGN_BOTTOM) {
1384 return font->descender * (float)isize/10.0f;
1385 }
1386 } else {
1387 if (align & FONS_ALIGN_TOP) {
1388 return -font->ascender * (float)isize/10.0f;
1389 } else if (align & FONS_ALIGN_MIDDLE) {
1390 return -(font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
1391 } else if (align & FONS_ALIGN_BASELINE) {
1392 return 0.0f;
1393 } else if (align & FONS_ALIGN_BOTTOM) {
1394 return -font->descender * (float)isize/10.0f;
1395 }
1396 }
1397 return 0.0;
1398}
1399
1400FONS_DEF float fonsDrawText(FONScontext* stash,
1401 float x, float y,
1402 const char* str, const char* end)
1403{
1404 FONSstate* state = fons__getState(stash);
1405 unsigned int codepoint;
1406 unsigned int utf8state = 0;
1407 FONSglyph* glyph = nullptr;
1408 FONSquad q;
1409 int prevGlyphIndex = -1;
1410 const short isize = (short)(state->size*10.0f);
1411 const short iblur = (short)state->blur;
1412 float width;
1413
1414 if (stash == nullptr) return x;
1415 if (state->font < 0 || state->font >= stash->nfonts) return x;
1416 FONSfont* font = stash->fonts[state->font];
1417 if (font->data == nullptr) return x;
1418
1419 float scale = fons__tt_getPixelHeightScale(&font->font, (float)isize / 10.0f);
1420
1421 if (end == nullptr)
1422 end = str + strlen(str);
1423
1424 // Align horizontally
1425 if (state->align & FONS_ALIGN_LEFT) {
1426 // empty
1427 } else if (state->align & FONS_ALIGN_RIGHT) {
1428 width = fonsTextBounds(stash, x,y, str, end, nullptr);
1429 x -= width;
1430 } else if (state->align & FONS_ALIGN_CENTER) {
1431 width = fonsTextBounds(stash, x,y, str, end, nullptr);
1432 x -= width * 0.5f;
1433 }
1434 // Align vertically.
1435 y += fons__getVertAlign(stash, font, state->align, isize);
1436
1437 for (; str != end; ++str) {
1438 if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
1439 continue;
1440 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
1441 if (glyph != nullptr) {
1442 fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1443
1444 if (stash->nverts+6 > FONS_VERTEX_COUNT)
1445 fons__flush(stash);
1446
1447 fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->colour[0], state->colour[1], state->colour[2], state->colour[3]);
1448 fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->colour[0], state->colour[1], state->colour[2], state->colour[3]);
1449 fons__vertex(stash, q.x1, q.y0, q.s1, q.t0, state->colour[0], state->colour[1], state->colour[2], state->colour[3]);
1450
1451 fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->colour[0], state->colour[1], state->colour[2], state->colour[3]);
1452 fons__vertex(stash, q.x0, q.y1, q.s0, q.t1, state->colour[0], state->colour[1], state->colour[2], state->colour[3]);
1453 fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->colour[0], state->colour[1], state->colour[2], state->colour[3]);
1454 }
1455 prevGlyphIndex = glyph != nullptr ? glyph->index : -1;
1456 }
1457 fons__flush(stash);
1458
1459 return x;
1460}
1461
1463 float x, float y, const char* str, const char* end)
1464{
1465 FONSstate* state = fons__getState(stash);
1466 float width;
1467
1468 memset(iter, 0, sizeof*iter);
1469
1470 if (stash == nullptr) return 0;
1471 if (state->font < 0 || state->font >= stash->nfonts) return 0;
1472 iter->font = stash->fonts[state->font];
1473 if (iter->font->data == nullptr) return 0;
1474
1475 iter->isize = (short)(state->size*10.0f);
1476 iter->iblur = (short)state->blur;
1477 iter->scale = fons__tt_getPixelHeightScale(&iter->font->font, (float)iter->isize/10.0f);
1478
1479 // Align horizontally
1480 if (state->align & FONS_ALIGN_LEFT) {
1481 // empty
1482 } else if (state->align & FONS_ALIGN_RIGHT) {
1483 width = fonsTextBounds(stash, x,y, str, end, nullptr);
1484 x -= width;
1485 } else if (state->align & FONS_ALIGN_CENTER) {
1486 width = fonsTextBounds(stash, x,y, str, end, nullptr);
1487 x -= width * 0.5f;
1488 }
1489 // Align vertically.
1490 y += fons__getVertAlign(stash, iter->font, state->align, iter->isize);
1491
1492 if (end == nullptr)
1493 end = str + strlen(str);
1494
1495 iter->x = iter->nextx = x;
1496 iter->y = iter->nexty = y;
1497 iter->spacing = state->spacing;
1498 iter->str = str;
1499 iter->next = str;
1500 iter->end = end;
1501 iter->codepoint = 0;
1502 iter->prevGlyphIndex = -1;
1503
1504 return 1;
1505}
1506
1508{
1509 FONSglyph* glyph = nullptr;
1510 const char* str = iter->next;
1511 iter->str = iter->next;
1512
1513 if (str == iter->end)
1514 return 0;
1515
1516 for (; str != iter->end; str++) {
1517 if (fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str))
1518 continue;
1519 str++;
1520 // Get glyph and quad
1521 iter->x = iter->nextx;
1522 iter->y = iter->nexty;
1523 glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur);
1524 if (glyph != nullptr)
1525 fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad);
1526 iter->prevGlyphIndex = glyph != nullptr ? glyph->index : -1;
1527 break;
1528 }
1529 iter->next = str;
1530
1531 return 1;
1532}
1533
1534FONS_DEF void fonsDrawDebug(FONScontext* stash, float x, float y)
1535{
1536 const int w = stash->params.width;
1537 const int h = stash->params.height;
1538 const float u = w == 0 ? 0 : 1.0f / w;
1539 const float v = h == 0 ? 0 : 1.0f / h;
1540
1541 if (stash->nverts+6+6 > FONS_VERTEX_COUNT)
1542 fons__flush(stash);
1543
1544 // Draw background
1545 fons__vertex(stash, x+0, y+0, u, v, 0xff, 0xff, 0xff, 0xff);
1546 fons__vertex(stash, x+w, y+h, u, v, 0xff, 0xff, 0xff, 0xff);
1547 fons__vertex(stash, x+w, y+0, u, v, 0xff, 0xff, 0xff, 0xff);
1548
1549 fons__vertex(stash, x+0, y+0, u, v, 0xff, 0xff, 0xff, 0xff);
1550 fons__vertex(stash, x+0, y+h, u, v, 0xff, 0xff, 0xff, 0xff);
1551 fons__vertex(stash, x+w, y+h, u, v, 0xff, 0xff, 0xff, 0xff);
1552
1553 // Draw texture
1554 fons__vertex(stash, x+0, y+0, 0, 0, 0xff, 0xff, 0xff, 0xff);
1555 fons__vertex(stash, x+w, y+h, 1, 1, 0xff, 0xff, 0xff, 0xff);
1556 fons__vertex(stash, x+w, y+0, 1, 0, 0xff, 0xff, 0xff, 0xff);
1557
1558 fons__vertex(stash, x+0, y+0, 0, 0, 0xff, 0xff, 0xff, 0xff);
1559 fons__vertex(stash, x+0, y+h, 0, 1, 0xff, 0xff, 0xff, 0xff);
1560 fons__vertex(stash, x+w, y+h, 1, 1, 0xff, 0xff, 0xff, 0xff);
1561
1562 // Drawbug draw atlas
1563 for (int i = 0; i < stash->atlas->nnodes; i++) {
1564 FONSatlasNode* n = &stash->atlas->nodes[i];
1565
1566 if (stash->nverts+6 > FONS_VERTEX_COUNT)
1567 fons__flush(stash);
1568
1569 fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc0, 0x00, 0x00, 0xff);
1570 fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc0, 0x00, 0x00, 0xff);
1571 fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc0, 0x00, 0x00, 0xff);
1572
1573 fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc0, 0x00, 0x00, 0xff);
1574 fons__vertex(stash, x+n->x+0, y+n->y+1, u, v, 0xc0, 0x00, 0x00, 0xff);
1575 fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc0, 0x00, 0x00, 0xff);
1576 }
1577
1578 fons__flush(stash);
1579}
1580
1582 float x, float y,
1583 const char* str, const char* end,
1584 float* bounds)
1585{
1586 FONSstate* state = fons__getState(stash);
1587 unsigned int codepoint;
1588 unsigned int utf8state = 0;
1589 FONSquad q;
1590 FONSglyph* glyph = nullptr;
1591 int prevGlyphIndex = -1;
1592 const short isize = (short)(state->size*10.0f);
1593 const short iblur = (short)state->blur;
1594 float maxx, maxy;
1595
1596 if (stash == nullptr) return 0;
1597 if (state->font < 0 || state->font >= stash->nfonts) return 0;
1598 FONSfont* font = stash->fonts[state->font];
1599 if (font->data == nullptr) return 0;
1600
1601 float scale = fons__tt_getPixelHeightScale(&font->font, (float)isize / 10.0f);
1602
1603 // Align vertically.
1604 y += fons__getVertAlign(stash, font, state->align, isize);
1605
1606 float minx = maxx = x;
1607 float miny = maxy = y;
1608 float startx = x;
1609
1610 if (end == nullptr)
1611 end = str + strlen(str);
1612
1613 for (; str != end; ++str) {
1614 if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
1615 continue;
1616 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
1617 if (glyph != nullptr) {
1618 fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1619 if (q.x0 < minx) minx = q.x0;
1620 if (q.x1 > maxx) maxx = q.x1;
1621 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1622 if (q.y0 < miny) miny = q.y0;
1623 if (q.y1 > maxy) maxy = q.y1;
1624 } else {
1625 if (q.y1 < miny) miny = q.y1;
1626 if (q.y0 > maxy) maxy = q.y0;
1627 }
1628 }
1629 prevGlyphIndex = glyph != nullptr ? glyph->index : -1;
1630 }
1631
1632 float advance = x - startx;
1633
1634 // Align horizontally
1635 if (state->align & FONS_ALIGN_LEFT) {
1636 // empty
1637 } else if (state->align & FONS_ALIGN_RIGHT) {
1638 minx -= advance;
1639 maxx -= advance;
1640 } else if (state->align & FONS_ALIGN_CENTER) {
1641 minx -= advance * 0.5f;
1642 maxx -= advance * 0.5f;
1643 }
1644
1645 if (bounds) {
1646 bounds[0] = minx;
1647 bounds[1] = miny;
1648 bounds[2] = maxx;
1649 bounds[3] = maxy;
1650 }
1651
1652 return advance;
1653}
1654
1656 float* ascender, float* descender, float* lineh)
1657{
1658 FONSstate* state = fons__getState(stash);
1659
1660 if (stash == nullptr) return;
1661 if (state->font < 0 || state->font >= stash->nfonts) return;
1662 FONSfont* font = stash->fonts[state->font];
1663 short isize = (short)(state->size * 10.0f);
1664 if (font->data == nullptr) return;
1665
1666 if (ascender)
1667 *ascender = font->ascender*isize/10.0f;
1668 if (descender)
1669 *descender = font->descender*isize/10.0f;
1670 if (lineh)
1671 *lineh = font->lineh*isize/10.0f;
1672}
1673
1674FONS_DEF void fonsLineBounds(FONScontext* stash, float y, float* miny, float* maxy)
1675{
1676 FONSstate* state = fons__getState(stash);
1677
1678 if (stash == nullptr) return;
1679 if (state->font < 0 || state->font >= stash->nfonts) return;
1680 FONSfont* font = stash->fonts[state->font];
1681 short isize = (short)(state->size * 10.0f);
1682 if (font->data == nullptr) return;
1683
1684 y += fons__getVertAlign(stash, font, state->align, isize);
1685
1686 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1687 *miny = y - font->ascender * (float)isize/10.0f;
1688 *maxy = *miny + font->lineh*isize/10.0f;
1689 } else {
1690 *maxy = y + font->descender * (float)isize/10.0f;
1691 *miny = *maxy - font->lineh*isize/10.0f;
1692 }
1693}
1694
1695FONS_DEF const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height)
1696{
1697 if (width != nullptr)
1698 *width = stash->params.width;
1699 if (height != nullptr)
1700 *height = stash->params.height;
1701 return stash->texData;
1702}
1703
1704FONS_DEF int fonsValidateTexture(FONScontext* stash, int* dirty)
1705{
1706 if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1707 dirty[0] = stash->dirtyRect[0];
1708 dirty[1] = stash->dirtyRect[1];
1709 dirty[2] = stash->dirtyRect[2];
1710 dirty[3] = stash->dirtyRect[3];
1711 // Reset dirty rect
1712 stash->dirtyRect[0] = stash->params.width;
1713 stash->dirtyRect[1] = stash->params.height;
1714 stash->dirtyRect[2] = 0;
1715 stash->dirtyRect[3] = 0;
1716 return 1;
1717 }
1718 return 0;
1719}
1720
1722{
1723 if (stash == nullptr) return;
1724
1725 if (stash->params.renderDelete)
1726 stash->params.renderDelete(stash->params.userPtr);
1727
1728 for (int i = 0; i < stash->nfonts; ++i)
1729 fons__freeFont(stash->fonts[i]);
1730
1731 if (stash->atlas) fons__deleteAtlas(stash->atlas);
1732 if (stash->fonts) free(stash->fonts);
1733 if (stash->texData) free(stash->texData);
1734 if (stash->scratch) free(stash->scratch);
1735 free(stash);
1736}
1737
1738FONS_DEF void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
1739{
1740 if (stash == nullptr) return;
1741 stash->handleError = callback;
1742 stash->errorUptr = uptr;
1743}
1744
1745FONS_DEF void fonsGetAtlasSize(FONScontext* stash, int* width, int* height)
1746{
1747 if (stash == nullptr) return;
1748 *width = stash->params.width;
1749 *height = stash->params.height;
1750}
1751
1752FONS_DEF int fonsExpandAtlas(FONScontext* stash, int width, int height)
1753{
1754 int i, maxy = 0;
1755 unsigned char* data = nullptr;
1756 if (stash == nullptr) return 0;
1757
1758 width = fons__maxi(width, stash->params.width);
1759 height = fons__maxi(height, stash->params.height);
1760
1761 if (width == stash->params.width && height == stash->params.height)
1762 return 1;
1763
1764 // Flush pending glyphs.
1765 fons__flush(stash);
1766
1767 // Create new texture
1768 if (stash->params.renderResize != nullptr) {
1769 if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1770 return 0;
1771 }
1772 // Copy old texture data over.
1773 data = (unsigned char*)malloc(width * height);
1774 if (data == nullptr)
1775 return 0;
1776 for (i = 0; i < stash->params.height; i++) {
1777 unsigned char* dst = &data[i*width];
1778 unsigned char* src = &stash->texData[i*stash->params.width];
1779 memcpy(dst, src, stash->params.width);
1780 if (width > stash->params.width)
1781 memset(dst+stash->params.width, 0, width - stash->params.width);
1782 }
1783 if (height > stash->params.height)
1784 memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width);
1785
1786 free(stash->texData);
1787 stash->texData = data;
1788
1789 // Increase atlas size
1790 fons__atlasExpand(stash->atlas, width, height);
1791
1792 // Add existing data as dirty.
1793 for (i = 0; i < stash->atlas->nnodes; i++)
1794 maxy = fons__maxi(maxy, stash->atlas->nodes[i].y);
1795 stash->dirtyRect[0] = 0;
1796 stash->dirtyRect[1] = 0;
1797 stash->dirtyRect[2] = stash->params.width;
1798 stash->dirtyRect[3] = maxy;
1799
1800 stash->params.width = width;
1801 stash->params.height = height;
1802 stash->itw = 1.0f/stash->params.width;
1803 stash->ith = 1.0f/stash->params.height;
1804
1805 return 1;
1806}
1807
1808FONS_DEF int fonsResetAtlas(FONScontext* stash, int width, int height)
1809{
1810 if (stash == nullptr) return 0;
1811
1812 // Flush pending glyphs.
1813 fons__flush(stash);
1814
1815 // Create new texture
1816 if (stash->params.renderResize != nullptr) {
1817 if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1818 return 0;
1819 }
1820
1821 // Reset atlas
1822 fons__atlasReset(stash->atlas, width, height);
1823
1824 // Clear texture data.
1825 stash->texData = (unsigned char*)realloc(stash->texData, width * height);
1826 if (stash->texData == nullptr) return 0;
1827 memset(stash->texData, 0, width * height);
1828
1829 // Reset dirty rect
1830 stash->dirtyRect[0] = width;
1831 stash->dirtyRect[1] = height;
1832 stash->dirtyRect[2] = 0;
1833 stash->dirtyRect[3] = 0;
1834
1835 // Reset cached glyphs
1836 for (int i = 0; i < stash->nfonts; i++) {
1837 FONSfont* font = stash->fonts[i];
1838 font->nglyphs = 0;
1839 for (int j = 0; j < FONS_HASH_LUT_SIZE; j++)
1840 font->lut[j] = -1;
1841 }
1842
1843 stash->params.width = width;
1844 stash->params.height = height;
1845 stash->itw = 1.0f/stash->params.width;
1846 stash->ith = 1.0f/stash->params.height;
1847
1848 // Add white rect at 0,0 for debug drawing.
1849 fons__addWhiteRect(stash, 2,2);
1850
1851 return 1;
1852}
1853
1854#endif // FONTSTASH_IMPLEMENTATION
FONSerrorCode
Definition: fontstash.h:62
@ FONS_STATES_OVERFLOW
Definition: fontstash.h:68
@ FONS_SCRATCH_FULL
Definition: fontstash.h:66
@ FONS_STATES_UNDERFLOW
Definition: fontstash.h:70
@ FONS_ATLAS_FULL
Definition: fontstash.h:64
int fonsGetFontByName(FONScontext *s, const char *name)
#define FONS_INIT_GLYPHS
Definition: fontstash.h:194
int fonsAddFontSdfMem(FONScontext *s, const char *name, unsigned char *data, int ndata, int freeData, FONSsdfSettings sdfSettings)
FONSflags
Definition: fontstash.h:38
@ FONS_ZERO_BOTTOMLEFT
Definition: fontstash.h:40
@ FONS_ZERO_TOPLEFT
Definition: fontstash.h:39
int fonsValidateTexture(FONScontext *s, int *dirty)
int fonsAddFallbackFont(FONScontext *stash, int base, int fallback)
#define FONS_DEF
Definition: fontstash.h:33
void fonsLineBounds(FONScontext *s, float y, float *miny, float *maxy)
#define FONS_MAX_STATES
Definition: fontstash.h:203
void fonsSetAlign(FONScontext *s, int align)
void fonsSetSpacing(FONScontext *s, float spacing)
void fonsDrawDebug(FONScontext *s, float x, float y)
int fonsExpandAtlas(FONScontext *s, int width, int height)
#define FONS_INIT_ATLAS_NODES
Definition: fontstash.h:197
void fonsGetAtlasSize(FONScontext *s, int *width, int *height)
int fonsTextIterInit(FONScontext *stash, FONStextIter *iter, float x, float y, const char *str, const char *end)
int fonsTextIterNext(FONScontext *stash, FONStextIter *iter, struct FONSquad *quad)
void fonsVertMetrics(FONScontext *s, float *ascender, float *descender, float *lineh)
void fonsSetBlur(FONScontext *s, float blur)
float fonsTextBounds(FONScontext *s, float x, float y, const char *string, const char *end, float *bounds)
void fonsPopState(FONScontext *s)
#define FONS_HASH_LUT_SIZE
Definition: fontstash.h:188
void fonsSetColor(FONScontext *s, unsigned int color)
void fonsSetColour(FONScontext *s, unsigned char colourR, unsigned char colourG, unsigned char colourB, unsigned char colourA)
#define FONS_VERTEX_COUNT
Definition: fontstash.h:200
const unsigned char * fonsGetTextureData(FONScontext *stash, int *width, int *height)
FONScontext * fonsCreateInternal(FONSparams *params)
FONSalign
Definition: fontstash.h:43
@ FONS_ALIGN_MIDDLE
Definition: fontstash.h:50
@ FONS_ALIGN_LEFT
Definition: fontstash.h:45
@ FONS_ALIGN_TOP
Definition: fontstash.h:49
@ FONS_ALIGN_RIGHT
Definition: fontstash.h:47
@ FONS_ALIGN_CENTER
Definition: fontstash.h:46
@ FONS_ALIGN_BASELINE
Definition: fontstash.h:52
@ FONS_ALIGN_BOTTOM
Definition: fontstash.h:51
FONScontext * dummyfonsCreate(int width, int height, int flags)
int fonsResetAtlas(FONScontext *stash, int width, int height)
#define FONS_INIT_FONTS
Definition: fontstash.h:191
void fonsPushState(FONScontext *s)
int fonsAddFontMem(FONScontext *s, const char *name, unsigned char *data, int ndata, int freeData)
int fonsAddFont(FONScontext *s, const char *name, const char *path)
void fonsSetErrorCallback(FONScontext *s, void(*callback)(void *uptr, int error, int val), void *uptr)
void fonsSetSize(FONScontext *s, float size)
float fonsDrawText(FONScontext *s, float x, float y, const char *string, const char *end)
#define FONS_INVALID
Definition: fontstash.h:36
void fonsDeleteInternal(FONScontext *s)
void fonsClearState(FONScontext *s)
struct FONScontext FONScontext
Definition: fontstash.h:119
#define FONS_SCRATCH_BUF_SIZE
Definition: fontstash.h:185
void fonsSetFont(FONScontext *s, int font)
int fonsAddFontSdf(FONScontext *s, const char *name, const char *path, FONSsdfSettings sdfSettings)
void dummyfonsDelete(FONScontext *ctx)
#define FONS_MAX_FALLBACKS
Definition: fontstash.h:206
uintptr_t uptr
Definition: Platform.h:64
int(* renderCreate)(void *uptr, int width, int height)
Definition: fontstash.h:77
unsigned char flags
Definition: fontstash.h:75
void(* renderDelete)(void *uptr)
Definition: fontstash.h:81
void * userPtr
Definition: fontstash.h:76
int(* renderResize)(void *uptr, int width, int height)
Definition: fontstash.h:78
void(* renderDraw)(void *uptr, const FONSvert *verts, int nverts)
Definition: fontstash.h:80
int height
Definition: fontstash.h:74
void(* renderUpdate)(void *uptr, int *rect, const unsigned char *data)
Definition: fontstash.h:79
int width
Definition: fontstash.h:74
float s1
Definition: fontstash.h:88
float s0
Definition: fontstash.h:87
float x0
Definition: fontstash.h:87
float x1
Definition: fontstash.h:88
float y1
Definition: fontstash.h:88
float t1
Definition: fontstash.h:88
float t0
Definition: fontstash.h:87
float y0
Definition: fontstash.h:87
unsigned char sdfEnabled
Definition: fontstash.h:107
float pixelDistScale
Definition: fontstash.h:113
unsigned char onedgeValue
Definition: fontstash.h:108
const char * next
Definition: fontstash.h:99
float nexty
Definition: fontstash.h:93
unsigned int utf8state
Definition: fontstash.h:101
float scale
Definition: fontstash.h:93
float nextx
Definition: fontstash.h:93
float spacing
Definition: fontstash.h:93
unsigned int codepoint
Definition: fontstash.h:94
short isize
Definition: fontstash.h:95
int prevGlyphIndex
Definition: fontstash.h:97
const char * end
Definition: fontstash.h:100
struct FONSfont * font
Definition: fontstash.h:96
short iblur
Definition: fontstash.h:95
const char * str
Definition: fontstash.h:98
unsigned char colours[4]
Definition: fontstash.h:59
float tcoords[2]
Definition: fontstash.h:58
float pos[2]
Definition: fontstash.h:57
#define SEEK_SET
Definition: zip.c:88
#define SEEK_END
Definition: zip.c:84