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