comparison DPF-Prymula-audioplugins/dpf/dgl/src/nanovg/fontstash.h @ 3:84e66ea83026

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