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