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