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