Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
fontstash.h
Go to the documentation of this file.
1//
2// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
3//
4// This software is provided 'as-is', without any express or implied
5// warranty. In no event will the authors be held liable for any damages
6// arising from the use of this software.
7// Permission is granted to anyone to use this software for any purpose,
8// including commercial applications, and to alter it and redistribute it
9// freely, subject to the following restrictions:
10// 1. The origin of this software must not be misrepresented; you must not
11// claim that you wrote the original software. If you use this software
12// in a product, an acknowledgment in the product documentation would be
13// appreciated but is not required.
14// 2. Altered source versions must be plainly marked as such, and must not be
15// misrepresented as being the original software.
16// 3. This notice may not be removed or altered from any source distribution.
17//
18
19#ifndef FONS_H
20#define FONS_H
21
22#ifdef __cplusplus
23extern "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
39
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
63struct FONSparams {
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};
73typedef struct FONSparams FONSparams;
74
76{
77 float x0,y0,s0,t0;
78 float x1,y1,s1,t1;
79};
80typedef struct FONSquad FONSquad;
81
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};
94
95typedef struct FONScontext FONScontext;
96
97// Contructor and destructor.
100
101FONS_DEF void fonsSetErrorCallback(FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr);
102// Returns current atlas size.
103FONS_DEF void fonsGetAtlasSize(FONScontext* s, int* width, int* height);
104// Expands the atlas size.
105FONS_DEF int fonsExpandAtlas(FONScontext* s, int width, int height);
106// Resets the whole stash.
107FONS_DEF int fonsResetAtlas(FONScontext* stash, int width, int height);
108
109// Add fonts
110FONS_DEF int fonsAddFont(FONScontext* s, const char* name, const char* path);
111FONS_DEF int fonsAddFontMem(FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData);
112FONS_DEF int fonsGetFontByName(FONScontext* s, const char* name);
113
114// State handling
118
119// State setting
120FONS_DEF void fonsSetSize(FONScontext* s, float size);
121FONS_DEF void fonsSetColor(FONScontext* s, unsigned int color);
122FONS_DEF void fonsSetSpacing(FONScontext* s, float spacing);
123FONS_DEF void fonsSetBlur(FONScontext* s, float blur);
126
127// Draw text
128FONS_DEF float fonsDrawText(FONScontext* s, float x, float y, const char* string, const char* end);
129
130// Measure text
131FONS_DEF float fonsTextBounds(FONScontext* s, float x, float y, const char* string, const char* end, float* bounds);
132FONS_DEF void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy);
133FONS_DEF void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh);
134
135// Text iterator
136FONS_DEF int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end);
138
139// Pull texture changes
140FONS_DEF const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height);
142
143// Draws the stash texture for debugging
144FONS_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
164struct FONSttFontImpl {
165 FT_Face font;
166};
167typedef struct FONSttFontImpl FONSttFontImpl;
168
169static FT_Library ftLibrary;
170
171static 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
179static 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
189static 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
196static float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
197{
198 return size / (font->font->ascender - font->font->descender);
199}
200
201static int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
202{
203 return FT_Get_Char_Index(font->font, codepoint);
204}
205
206static 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
230static 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
249static 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
260static void* fons__tmpalloc(size_t size, void* up);
261static 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
266struct FONSttFontImpl {
267 stbtt_fontinfo font;
268};
269typedef struct FONSttFontImpl FONSttFontImpl;
270
271static int fons__tt_init(FONScontext *context)
272{
273 FONS_NOTUSED(context);
274 return 1;
275}
276
277static 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
287static void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
288{
289 stbtt_GetFontVMetrics(&font->font, ascent, descent, lineGap);
290}
291
292static float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
293{
294 return stbtt_ScaleForPixelHeight(&font->font, size);
295}
296
297static int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
298{
299 return stbtt_FindGlyphIndex(&font->font, codepoint);
300}
301
302static 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
311static 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
317static 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
349static 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
360static int fons__mini(int a, int b)
361{
362 return a < b ? a : b;
363}
364
365static int fons__maxi(int a, int b)
366{
367 return a > b ? a : b;
368}
369
370struct 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};
379typedef struct FONSglyph FONSglyph;
380
381struct 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};
398typedef struct FONSfont FONSfont;
399
400struct FONSstate
401{
402 int font;
403 int align;
404 float size;
405 unsigned int color;
406 float blur;
407 float spacing;
408};
409typedef struct FONSstate FONSstate;
410
411struct FONSatlasNode {
412 short x, y, width;
413};
414typedef struct FONSatlasNode FONSatlasNode;
415
416struct FONSatlas
417{
418 int width, height;
419 FONSatlasNode* nodes;
420 int nnodes;
421 int cnodes;
422};
423typedef struct FONSatlas FONSatlas;
424
425struct 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
449static 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
467static 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
482static 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
517static void fons__deleteAtlas(FONSatlas* atlas)
518{
519 if (atlas == NULL) return;
520 if (atlas->nodes != NULL) free(atlas->nodes);
521 free(atlas);
522}
523
524static 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
551error:
552 if (atlas) fons__deleteAtlas(atlas);
553 return NULL;
554}
555
556static 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
576static 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
585static 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
594static 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
607static 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
644static 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
665static 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
697static 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
771error:
772 fonsDeleteInternal(stash);
773 return NULL;
774}
775
776static FONSstate* fons__getState(FONScontext* stash)
777{
778 return &stash->states[stash->nstates-1];
779}
780
781int 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
791void fonsSetSize(FONScontext* stash, float size)
792{
793 fons__getState(stash)->size = size;
794}
795
796void fonsSetColor(FONScontext* stash, unsigned int color)
797{
798 fons__getState(stash)->color = color;
799}
800
801void fonsSetSpacing(FONScontext* stash, float spacing)
802{
803 fons__getState(stash)->spacing = spacing;
804}
805
806void fonsSetBlur(FONScontext* stash, float blur)
807{
808 fons__getState(stash)->blur = blur;
809}
810
811void fonsSetAlign(FONScontext* stash, int align)
812{
813 fons__getState(stash)->align = align;
814}
815
816void fonsSetFont(FONScontext* stash, int font)
817{
818 fons__getState(stash)->font = font;
819}
820
821void 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
833void 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
843void 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
854static 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
862static 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
883error:
884 fons__freeFont(font);
885
886 return FONS_INVALID;
887}
888
889int 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
910error:
911 if (data) free(data);
912 if (fp) fclose(fp);
913 return FONS_INVALID;
914}
915
916int 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
953error:
954 fons__freeFont(font);
955 stash->nfonts--;
956 return FONS_INVALID;
957}
958
959int 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
970static 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
987static 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
1007static 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
1028static 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
1047static 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
1165static 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
1217static 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
1238static __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
1248static 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
1274FONS_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
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
1410FONS_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
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
1556FONS_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
1579FONS_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
1588FONS_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
1623FONS_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
1630FONS_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
1637FONS_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
1693FONS_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 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)
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 const unsigned char * fonsGetTextureData(FONScontext *stash, int *width, int *height)
FONS_DEF void fonsVertMetrics(FONScontext *s, float *ascender, float *descender, float *lineh)
FONS_DEF FONScontext * fonsCreateInternal(FONSparams *params)
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
void(* renderUpdate)(void *uptr, int *rect, const unsigned char *data)
Definition fontstash.h:69
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