Cleanup
[carla.git] / source / modules / dgl / src / nanovg / fontstash.h
blob37ecafc0f9ecf768ac4ced74390d9b52d2d83783
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.
19 #ifndef FONS_H
20 #define FONS_H
22 #define FONS_INVALID -1
24 enum FONSflags {
25 FONS_ZERO_TOPLEFT = 1,
26 FONS_ZERO_BOTTOMLEFT = 2,
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
41 enum FONSglyphBitmap {
42 FONS_GLYPH_BITMAP_OPTIONAL = 1,
43 FONS_GLYPH_BITMAP_REQUIRED = 2,
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,
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);
67 typedef struct FONSparams FONSparams;
69 struct FONSquad
71 float x0,y0,s0,t0;
72 float x1,y1,s1,t1;
74 typedef struct FONSquad FONSquad;
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;
88 typedef struct FONStextIter FONStextIter;
90 typedef struct FONScontext FONScontext;
92 // Constructor and destructor.
93 FONScontext* fonsCreateInternal(FONSparams* params);
94 void fonsDeleteInternal(FONScontext* s);
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);
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);
109 // State handling
110 void fonsPushState(FONScontext* s);
111 void fonsPopState(FONScontext* s);
112 void fonsClearState(FONScontext* s);
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);
122 // Draw text
123 float fonsDrawText(FONScontext* s, float x, float y, const char* string, const char* end);
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);
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);
134 // Pull texture changes
135 const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height);
136 int fonsValidateTexture(FONScontext* s, int* dirty);
138 // Draws the stash texture for debugging
139 void fonsDrawDebug(FONScontext* s, float x, float y);
141 #endif // FONTSTASH_H
144 #ifdef FONTSTASH_IMPLEMENTATION
146 #define FONS_NOTUSED(v) (void)sizeof(v)
148 #ifdef FONS_USE_FREETYPE
150 #include <ft2build.h>
151 #include FT_FREETYPE_H
152 #include FT_ADVANCES_H
153 #include <math.h>
155 struct FONSttFontImpl {
156 FT_Face font;
158 typedef struct FONSttFontImpl FONSttFontImpl;
160 #else
162 #define STB_TRUETYPE_IMPLEMENTATION
163 static void* fons__tmpalloc(size_t size, void* up);
164 static void fons__tmpfree(void* ptr, void* up);
165 #define STBTT_malloc(x,u) fons__tmpalloc(x,u)
166 #define STBTT_free(x,u) fons__tmpfree(x,u)
167 #include "stb_truetype.h"
169 struct FONSttFontImpl {
170 stbtt_fontinfo font;
172 typedef struct FONSttFontImpl FONSttFontImpl;
174 #endif
176 #ifndef FONS_SCRATCH_BUF_SIZE
177 # define FONS_SCRATCH_BUF_SIZE 96000
178 #endif
179 #ifndef FONS_HASH_LUT_SIZE
180 # define FONS_HASH_LUT_SIZE 256
181 #endif
182 #ifndef FONS_INIT_FONTS
183 # define FONS_INIT_FONTS 4
184 #endif
185 #ifndef FONS_INIT_GLYPHS
186 # define FONS_INIT_GLYPHS 256
187 #endif
188 #ifndef FONS_INIT_ATLAS_NODES
189 # define FONS_INIT_ATLAS_NODES 256
190 #endif
191 #ifndef FONS_VERTEX_COUNT
192 # define FONS_VERTEX_COUNT 1024
193 #endif
194 #ifndef FONS_MAX_STATES
195 # define FONS_MAX_STATES 20
196 #endif
197 #ifndef FONS_MAX_FALLBACKS
198 # define FONS_MAX_FALLBACKS 20
199 #endif
201 static unsigned int fons__hashint(unsigned int a)
203 a += ~(a<<15);
204 a ^= (a>>10);
205 a += (a<<3);
206 a ^= (a>>6);
207 a += ~(a<<11);
208 a ^= (a>>16);
209 return a;
212 static int fons__mini(int a, int b)
214 return a < b ? a : b;
217 static int fons__maxi(int a, int b)
219 return a > b ? a : b;
222 struct FONSglyph
224 unsigned int codepoint;
225 int index;
226 int next;
227 short size, blur;
228 short x0,y0,x1,y1;
229 short xadv,xoff,yoff;
231 typedef struct FONSglyph FONSglyph;
233 struct FONSfont
235 FONSttFontImpl font;
236 char name[64];
237 unsigned char* data;
238 int dataSize;
239 unsigned char freeData;
240 float ascender;
241 float descender;
242 float lineh;
243 FONSglyph* glyphs;
244 int cglyphs;
245 int nglyphs;
246 int lut[FONS_HASH_LUT_SIZE];
247 int fallbacks[FONS_MAX_FALLBACKS];
248 int nfallbacks;
250 typedef struct FONSfont FONSfont;
252 struct FONSstate
254 int font;
255 int align;
256 float size;
257 unsigned int color;
258 float blur;
259 float spacing;
261 typedef struct FONSstate FONSstate;
263 struct FONSatlasNode {
264 short x, y, width;
266 typedef struct FONSatlasNode FONSatlasNode;
268 struct FONSatlas
270 int width, height;
271 FONSatlasNode* nodes;
272 int nnodes;
273 int cnodes;
275 typedef struct FONSatlas FONSatlas;
277 struct FONScontext
279 FONSparams params;
280 float itw,ith;
281 unsigned char* texData;
282 int dirtyRect[4];
283 FONSfont** fonts;
284 FONSatlas* atlas;
285 int cfonts;
286 int nfonts;
287 float verts[FONS_VERTEX_COUNT*2];
288 float tcoords[FONS_VERTEX_COUNT*2];
289 unsigned int colors[FONS_VERTEX_COUNT];
290 int nverts;
291 unsigned char* scratch;
292 int nscratch;
293 FONSstate states[FONS_MAX_STATES];
294 int nstates;
295 void (*handleError)(void* uptr, int error, int val);
296 void* errorUptr;
297 #ifdef FONS_USE_FREETYPE
298 FT_Library ftLibrary;
299 #endif
302 #ifdef FONS_USE_FREETYPE
304 int fons__tt_init(FONScontext *context)
306 FT_Error ftError;
307 ftError = FT_Init_FreeType(&context->ftLibrary);
308 return ftError == 0;
311 int fons__tt_done(FONScontext *context)
313 FT_Error ftError;
314 ftError = FT_Done_FreeType(context->ftLibrary);
315 return ftError == 0;
318 int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
320 FT_Error ftError;
322 //font->font.userdata = stash;
323 ftError = FT_New_Memory_Face(context->ftLibrary, (const FT_Byte*)data, dataSize, fontIndex, &font->font);
324 return ftError == 0;
327 void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
329 *ascent = font->font->ascender;
330 *descent = font->font->descender;
331 *lineGap = font->font->height - (*ascent - *descent);
334 float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
336 #if 1
337 // Note(DPF) maintain pixel-based units for compat after nanovg update
338 return size / (font->font->ascender - font->font->descender);
339 #else
340 return size / font->font->units_per_EM;
341 #endif
344 int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
346 return FT_Get_Char_Index(font->font, codepoint);
349 int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
350 int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
352 FT_Error ftError;
353 FT_GlyphSlot ftGlyph;
354 FT_Fixed advFixed;
355 FONS_NOTUSED(scale);
357 #if 1
358 // Note(DPF) maintain pixel-based units for compat after nanovg update
359 ftError = FT_Set_Pixel_Sizes(font->font, 0, (FT_UInt)(size * (float)font->font->units_per_EM / (float)(font->font->ascender - font->font->descender)));
360 #else
361 ftError = FT_Set_Pixel_Sizes(font->font, 0, size);
362 #endif
363 if (ftError) return 0;
364 #if 1
365 // Note(DPF) maintain pixel-based units for compat after nanovg update
366 ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER);
367 #else
368 ftError = FT_Load_Glyph(font->font, glyph, FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT);
369 #endif
370 if (ftError) return 0;
371 ftError = FT_Get_Advance(font->font, glyph, FT_LOAD_NO_SCALE, &advFixed);
372 if (ftError) return 0;
373 ftGlyph = font->font->glyph;
374 *advance = (int)advFixed;
375 *lsb = (int)ftGlyph->metrics.horiBearingX;
376 *x0 = ftGlyph->bitmap_left;
377 *x1 = *x0 + ftGlyph->bitmap.width;
378 *y0 = -ftGlyph->bitmap_top;
379 *y1 = *y0 + ftGlyph->bitmap.rows;
380 return 1;
383 void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
384 float scaleX, float scaleY, int glyph)
386 FT_GlyphSlot ftGlyph = font->font->glyph;
387 int ftGlyphOffset = 0;
388 unsigned int x, y;
389 FONS_NOTUSED(outWidth);
390 FONS_NOTUSED(outHeight);
391 FONS_NOTUSED(scaleX);
392 FONS_NOTUSED(scaleY);
393 FONS_NOTUSED(glyph); // glyph has already been loaded by fons__tt_buildGlyphBitmap
395 for ( y = 0; y < ftGlyph->bitmap.rows; y++ ) {
396 for ( x = 0; x < ftGlyph->bitmap.width; x++ ) {
397 output[(y * outStride) + x] = ftGlyph->bitmap.buffer[ftGlyphOffset++];
402 int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
404 FT_Vector ftKerning;
405 FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
406 return (int)((ftKerning.x + 32) >> 6); // Round up and convert to integer
409 #else
411 int fons__tt_init(FONScontext *context)
413 FONS_NOTUSED(context);
414 return 1;
417 int fons__tt_done(FONScontext *context)
419 FONS_NOTUSED(context);
420 return 1;
423 int fons__tt_loadFont(FONScontext *context, FONSttFontImpl *font, unsigned char *data, int dataSize, int fontIndex)
425 int offset, stbError;
426 FONS_NOTUSED(dataSize);
428 font->font.userdata = context;
429 offset = stbtt_GetFontOffsetForIndex(data, fontIndex);
430 if (offset == -1) {
431 stbError = 0;
432 } else {
433 stbError = stbtt_InitFont(&font->font, data, offset);
435 return stbError;
438 void fons__tt_getFontVMetrics(FONSttFontImpl *font, int *ascent, int *descent, int *lineGap)
440 stbtt_GetFontVMetrics(&font->font, ascent, descent, lineGap);
443 float fons__tt_getPixelHeightScale(FONSttFontImpl *font, float size)
445 #if 1
446 // Note(DPF) maintain pixel-based units for compat after nanovg update
447 return stbtt_ScaleForPixelHeight(&font->font, size);
448 #else
449 return stbtt_ScaleForMappingEmToPixels(&font->font, size);
450 #endif
453 int fons__tt_getGlyphIndex(FONSttFontImpl *font, int codepoint)
455 return stbtt_FindGlyphIndex(&font->font, codepoint);
458 int fons__tt_buildGlyphBitmap(FONSttFontImpl *font, int glyph, float size, float scale,
459 int *advance, int *lsb, int *x0, int *y0, int *x1, int *y1)
461 FONS_NOTUSED(size);
462 stbtt_GetGlyphHMetrics(&font->font, glyph, advance, lsb);
463 stbtt_GetGlyphBitmapBox(&font->font, glyph, scale, scale, x0, y0, x1, y1);
464 return 1;
467 void fons__tt_renderGlyphBitmap(FONSttFontImpl *font, unsigned char *output, int outWidth, int outHeight, int outStride,
468 float scaleX, float scaleY, int glyph)
470 stbtt_MakeGlyphBitmap(&font->font, output, outWidth, outHeight, outStride, scaleX, scaleY, glyph);
473 int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font, int glyph1, int glyph2)
475 return stbtt_GetGlyphKernAdvance(&font->font, glyph1, glyph2);
478 #endif
480 #ifdef STB_TRUETYPE_IMPLEMENTATION
482 static void* fons__tmpalloc(size_t size, void* up)
484 unsigned char* ptr;
485 FONScontext* stash = (FONScontext*)up;
487 // 16-byte align the returned pointer
488 size = (size + 0xf) & ~0xf;
490 if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE) {
491 if (stash->handleError)
492 stash->handleError(stash->errorUptr, FONS_SCRATCH_FULL, stash->nscratch+(int)size);
493 return NULL;
495 ptr = stash->scratch + stash->nscratch;
496 stash->nscratch += (int)size;
497 return ptr;
500 static void fons__tmpfree(void* ptr, void* up)
502 (void)ptr;
503 (void)up;
504 // empty
507 #endif // STB_TRUETYPE_IMPLEMENTATION
509 // Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
510 // See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
512 #define FONS_UTF8_ACCEPT 0
513 #define FONS_UTF8_REJECT 12
515 static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
517 static const unsigned char utf8d[] = {
518 // The first part of the table maps bytes to character classes that
519 // to reduce the size of the transition table and create bitmasks.
520 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
521 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
522 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
523 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
524 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
525 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
526 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
527 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
529 // The second part is a transition table that maps a combination
530 // of a state of the automaton and a character class to a state.
531 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
532 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
533 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
534 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
535 12,36,12,12,12,12,12,12,12,12,12,12,
538 unsigned int type = utf8d[byte];
540 *codep = (*state != FONS_UTF8_ACCEPT) ?
541 (byte & 0x3fu) | (*codep << 6) :
542 (0xff >> type) & (byte);
544 *state = utf8d[256 + *state + type];
545 return *state;
548 // Atlas based on Skyline Bin Packer by Jukka Jylänki
550 static void fons__deleteAtlas(FONSatlas* atlas)
552 if (atlas == NULL) return;
553 if (atlas->nodes != NULL) free(atlas->nodes);
554 free(atlas);
557 static FONSatlas* fons__allocAtlas(int w, int h, int nnodes)
559 FONSatlas* atlas = NULL;
561 // Allocate memory for the font stash.
562 atlas = (FONSatlas*)malloc(sizeof(FONSatlas));
563 if (atlas == NULL) goto error;
564 memset(atlas, 0, sizeof(FONSatlas));
566 atlas->width = w;
567 atlas->height = h;
569 // Allocate space for skyline nodes
570 atlas->nodes = (FONSatlasNode*)malloc(sizeof(FONSatlasNode) * nnodes);
571 if (atlas->nodes == NULL) goto error;
572 memset(atlas->nodes, 0, sizeof(FONSatlasNode) * nnodes);
573 atlas->nnodes = 0;
574 atlas->cnodes = nnodes;
576 // Init root node.
577 atlas->nodes[0].x = 0;
578 atlas->nodes[0].y = 0;
579 atlas->nodes[0].width = (short)w;
580 atlas->nnodes++;
582 return atlas;
584 error:
585 if (atlas) fons__deleteAtlas(atlas);
586 return NULL;
589 static int fons__atlasInsertNode(FONSatlas* atlas, int idx, int x, int y, int w)
591 int i;
592 // Insert node
593 if (atlas->nnodes+1 > atlas->cnodes) {
594 atlas->cnodes = atlas->cnodes == 0 ? 8 : atlas->cnodes * 2;
595 atlas->nodes = (FONSatlasNode*)realloc(atlas->nodes, sizeof(FONSatlasNode) * atlas->cnodes);
596 if (atlas->nodes == NULL)
597 return 0;
599 for (i = atlas->nnodes; i > idx; i--)
600 atlas->nodes[i] = atlas->nodes[i-1];
601 atlas->nodes[idx].x = (short)x;
602 atlas->nodes[idx].y = (short)y;
603 atlas->nodes[idx].width = (short)w;
604 atlas->nnodes++;
606 return 1;
609 static void fons__atlasRemoveNode(FONSatlas* atlas, int idx)
611 int i;
612 if (atlas->nnodes == 0) return;
613 for (i = idx; i < atlas->nnodes-1; i++)
614 atlas->nodes[i] = atlas->nodes[i+1];
615 atlas->nnodes--;
618 static void fons__atlasExpand(FONSatlas* atlas, int w, int h)
620 // Insert node for empty space
621 if (w > atlas->width)
622 fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width);
623 atlas->width = w;
624 atlas->height = h;
627 static void fons__atlasReset(FONSatlas* atlas, int w, int h)
629 atlas->width = w;
630 atlas->height = h;
631 atlas->nnodes = 0;
633 // Init root node.
634 atlas->nodes[0].x = 0;
635 atlas->nodes[0].y = 0;
636 atlas->nodes[0].width = (short)w;
637 atlas->nnodes++;
640 static int fons__atlasAddSkylineLevel(FONSatlas* atlas, int idx, int x, int y, int w, int h)
642 int i;
644 // Insert new node
645 if (fons__atlasInsertNode(atlas, idx, x, y+h, w) == 0)
646 return 0;
648 // Delete skyline segments that fall under the shadow of the new segment.
649 for (i = idx+1; i < atlas->nnodes; i++) {
650 if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) {
651 int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x;
652 atlas->nodes[i].x += (short)shrink;
653 atlas->nodes[i].width -= (short)shrink;
654 if (atlas->nodes[i].width <= 0) {
655 fons__atlasRemoveNode(atlas, i);
656 i--;
657 } else {
658 break;
660 } else {
661 break;
665 // Merge same height skyline segments that are next to each other.
666 for (i = 0; i < atlas->nnodes-1; i++) {
667 if (atlas->nodes[i].y == atlas->nodes[i+1].y) {
668 atlas->nodes[i].width += atlas->nodes[i+1].width;
669 fons__atlasRemoveNode(atlas, i+1);
670 i--;
674 return 1;
677 static int fons__atlasRectFits(FONSatlas* atlas, int i, int w, int h)
679 // Checks if there is enough space at the location of skyline span 'i',
680 // and return the max height of all skyline spans under that at that location,
681 // (think tetris block being dropped at that position). Or -1 if no space found.
682 int x = atlas->nodes[i].x;
683 int y = atlas->nodes[i].y;
684 int spaceLeft;
685 if (x + w > atlas->width)
686 return -1;
687 spaceLeft = w;
688 while (spaceLeft > 0) {
689 if (i == atlas->nnodes) return -1;
690 y = fons__maxi(y, atlas->nodes[i].y);
691 if (y + h > atlas->height) return -1;
692 spaceLeft -= atlas->nodes[i].width;
693 ++i;
695 return y;
698 static int fons__atlasAddRect(FONSatlas* atlas, int rw, int rh, int* rx, int* ry)
700 int besth = atlas->height, bestw = atlas->width, besti = -1;
701 int bestx = -1, besty = -1, i;
703 // Bottom left fit heuristic.
704 for (i = 0; i < atlas->nnodes; i++) {
705 int y = fons__atlasRectFits(atlas, i, rw, rh);
706 if (y != -1) {
707 if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw)) {
708 besti = i;
709 bestw = atlas->nodes[i].width;
710 besth = y + rh;
711 bestx = atlas->nodes[i].x;
712 besty = y;
717 if (besti == -1)
718 return 0;
720 // Perform the actual packing.
721 if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0)
722 return 0;
724 *rx = bestx;
725 *ry = besty;
727 return 1;
730 static void fons__addWhiteRect(FONScontext* stash, int w, int h)
732 int x, y, gx, gy;
733 unsigned char* dst;
734 if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
735 return;
737 // Rasterize
738 dst = &stash->texData[gx + gy * stash->params.width];
739 for (y = 0; y < h; y++) {
740 for (x = 0; x < w; x++)
741 dst[x] = 0xff;
742 dst += stash->params.width;
745 stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
746 stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
747 stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
748 stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
751 FONScontext* fonsCreateInternal(FONSparams* params)
753 FONScontext* stash = NULL;
755 // Allocate memory for the font stash.
756 stash = (FONScontext*)malloc(sizeof(FONScontext));
757 if (stash == NULL) goto error;
758 memset(stash, 0, sizeof(FONScontext));
760 stash->params = *params;
762 // Allocate scratch buffer.
763 stash->scratch = (unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE);
764 if (stash->scratch == NULL) goto error;
766 // Initialize implementation library
767 if (!fons__tt_init(stash)) goto error;
769 if (stash->params.renderCreate != NULL) {
770 if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
771 goto error;
774 stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES);
775 if (stash->atlas == NULL) goto error;
777 // Allocate space for fonts.
778 stash->fonts = (FONSfont**)malloc(sizeof(FONSfont*) * FONS_INIT_FONTS);
779 if (stash->fonts == NULL) goto error;
780 memset(stash->fonts, 0, sizeof(FONSfont*) * FONS_INIT_FONTS);
781 stash->cfonts = FONS_INIT_FONTS;
782 stash->nfonts = 0;
784 // Create texture for the cache.
785 stash->itw = 1.0f/stash->params.width;
786 stash->ith = 1.0f/stash->params.height;
787 stash->texData = (unsigned char*)malloc(stash->params.width * stash->params.height);
788 if (stash->texData == NULL) goto error;
789 memset(stash->texData, 0, stash->params.width * stash->params.height);
791 stash->dirtyRect[0] = stash->params.width;
792 stash->dirtyRect[1] = stash->params.height;
793 stash->dirtyRect[2] = 0;
794 stash->dirtyRect[3] = 0;
796 // Add white rect at 0,0 for debug drawing.
797 fons__addWhiteRect(stash, 2,2);
799 fonsPushState(stash);
800 fonsClearState(stash);
802 return stash;
804 error:
805 fonsDeleteInternal(stash);
806 return NULL;
809 static FONSstate* fons__getState(FONScontext* stash)
811 return &stash->states[stash->nstates-1];
814 int fonsAddFallbackFont(FONScontext* stash, int base, int fallback)
816 FONSfont* baseFont = stash->fonts[base];
817 if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
818 baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
819 return 1;
821 return 0;
824 void fonsResetFallbackFont(FONScontext* stash, int base)
826 int i;
828 FONSfont* baseFont = stash->fonts[base];
829 baseFont->nfallbacks = 0;
830 baseFont->nglyphs = 0;
831 for (i = 0; i < FONS_HASH_LUT_SIZE; i++)
832 baseFont->lut[i] = -1;
835 void fonsSetSize(FONScontext* stash, float size)
837 fons__getState(stash)->size = size;
840 void fonsSetColor(FONScontext* stash, unsigned int color)
842 fons__getState(stash)->color = color;
845 void fonsSetSpacing(FONScontext* stash, float spacing)
847 fons__getState(stash)->spacing = spacing;
850 void fonsSetBlur(FONScontext* stash, float blur)
852 fons__getState(stash)->blur = blur;
855 void fonsSetAlign(FONScontext* stash, int align)
857 fons__getState(stash)->align = align;
860 void fonsSetFont(FONScontext* stash, int font)
862 fons__getState(stash)->font = font;
865 void fonsPushState(FONScontext* stash)
867 if (stash->nstates >= FONS_MAX_STATES) {
868 if (stash->handleError)
869 stash->handleError(stash->errorUptr, FONS_STATES_OVERFLOW, 0);
870 return;
872 if (stash->nstates > 0)
873 memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(FONSstate));
874 stash->nstates++;
877 void fonsPopState(FONScontext* stash)
879 if (stash->nstates <= 1) {
880 if (stash->handleError)
881 stash->handleError(stash->errorUptr, FONS_STATES_UNDERFLOW, 0);
882 return;
884 stash->nstates--;
887 void fonsClearState(FONScontext* stash)
889 FONSstate* state = fons__getState(stash);
890 state->size = 12.0f;
891 state->color = 0xffffffff;
892 state->font = 0;
893 state->blur = 0;
894 state->spacing = 0;
895 state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE;
898 static void fons__freeFont(FONSfont* font)
900 if (font == NULL) return;
901 if (font->glyphs) free(font->glyphs);
902 if (font->freeData && font->data) free(font->data);
903 free(font);
906 static int fons__allocFont(FONScontext* stash)
908 FONSfont* font = NULL;
909 if (stash->nfonts+1 > stash->cfonts) {
910 stash->cfonts = stash->cfonts == 0 ? 8 : stash->cfonts * 2;
911 stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts);
912 if (stash->fonts == NULL)
913 return -1;
914 for (int i=stash->nfonts; i<stash->cfonts; ++i)
915 stash->fonts[i] = NULL;
917 font = (FONSfont*)malloc(sizeof(FONSfont));
918 if (font == NULL) goto error;
919 memset(font, 0, sizeof(FONSfont));
921 font->glyphs = (FONSglyph*)malloc(sizeof(FONSglyph) * FONS_INIT_GLYPHS);
922 if (font->glyphs == NULL) goto error;
923 font->cglyphs = FONS_INIT_GLYPHS;
924 font->nglyphs = 0;
926 stash->fonts[stash->nfonts++] = font;
927 return stash->nfonts-1;
929 error:
930 fons__freeFont(font);
932 return FONS_INVALID;
935 int fonsAddFont(FONScontext* stash, const char* name, const char* path, int fontIndex)
937 FILE* fp = 0;
938 int dataSize = 0;
939 size_t readed;
940 unsigned char* data = NULL;
942 // Read in the font data.
943 fp = fopen(path, "rb");
944 if (fp == NULL) goto error;
945 fseek(fp,0,SEEK_END);
946 dataSize = (int)ftell(fp);
947 fseek(fp,0,SEEK_SET);
948 data = (unsigned char*)malloc(dataSize);
949 if (data == NULL) goto error;
950 readed = fread(data, 1, dataSize, fp);
951 fclose(fp);
952 fp = 0;
953 if (readed != (size_t)dataSize) goto error;
955 return fonsAddFontMem(stash, name, data, dataSize, 1, fontIndex);
957 error:
958 if (data) free(data);
959 if (fp) fclose(fp);
960 return FONS_INVALID;
963 int fonsAddFontMem(FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData, int fontIndex)
965 int i, ascent, descent, fh, lineGap;
966 FONSfont* font;
968 int idx = fons__allocFont(stash);
969 if (idx == FONS_INVALID)
971 if (freeData && data) free(data);
972 return FONS_INVALID;
975 font = stash->fonts[idx];
977 strncpy(font->name, name, sizeof(font->name));
978 font->name[sizeof(font->name)-1] = '\0';
980 // Init hash lookup.
981 for (i = 0; i < FONS_HASH_LUT_SIZE; ++i)
982 font->lut[i] = -1;
984 // Read in the font data.
985 font->dataSize = dataSize;
986 font->data = data;
987 font->freeData = (unsigned char)freeData;
989 // Init font
990 stash->nscratch = 0;
991 if (!fons__tt_loadFont(stash, &font->font, data, dataSize, fontIndex)) goto error;
993 // Store normalized line height. The real line height is got
994 // by multiplying the lineh by font size.
995 fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);
996 ascent += lineGap;
997 fh = ascent - descent;
998 font->ascender = (float)ascent / (float)fh;
999 font->descender = (float)descent / (float)fh;
1000 font->lineh = font->ascender - font->descender;
1002 return idx;
1004 error:
1005 fons__freeFont(font);
1006 stash->nfonts--;
1007 return FONS_INVALID;
1010 int fonsGetFontByName(FONScontext* s, const char* name)
1012 int i;
1013 for (i = 0; i < s->nfonts; i++) {
1014 if (strcmp(s->fonts[i]->name, name) == 0)
1015 return i;
1017 return FONS_INVALID;
1021 static FONSglyph* fons__allocGlyph(FONSfont* font)
1023 if (font->nglyphs+1 > font->cglyphs) {
1024 font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2;
1025 font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs);
1026 if (font->glyphs == NULL) return NULL;
1027 for (int i=font->nglyphs; i<font->cglyphs; ++i)
1028 memset(&font->glyphs[i], 0, sizeof(*font->glyphs));
1030 font->nglyphs++;
1031 return &font->glyphs[font->nglyphs-1];
1035 // Based on Exponential blur, Jani Huhtanen, 2006
1037 #define APREC 16
1038 #define ZPREC 7
1040 static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha)
1042 int x, y;
1043 for (y = 0; y < h; y++) {
1044 int z = 0; // force zero border
1045 for (x = 1; x < w; x++) {
1046 z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
1047 dst[x] = (unsigned char)(z >> ZPREC);
1049 dst[w-1] = 0; // force zero border
1050 z = 0;
1051 for (x = w-2; x >= 0; x--) {
1052 z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
1053 dst[x] = (unsigned char)(z >> ZPREC);
1055 dst[0] = 0; // force zero border
1056 dst += dstStride;
1060 static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha)
1062 int x, y;
1063 for (x = 0; x < w; x++) {
1064 int z = 0; // force zero border
1065 for (y = dstStride; y < h*dstStride; y += dstStride) {
1066 z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
1067 dst[y] = (unsigned char)(z >> ZPREC);
1069 dst[(h-1)*dstStride] = 0; // force zero border
1070 z = 0;
1071 for (y = (h-2)*dstStride; y >= 0; y -= dstStride) {
1072 z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
1073 dst[y] = (unsigned char)(z >> ZPREC);
1075 dst[0] = 0; // force zero border
1076 dst++;
1081 static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur)
1083 int alpha;
1084 float sigma;
1085 (void)stash;
1087 if (blur < 1)
1088 return;
1089 // Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity)
1090 sigma = (float)blur * 0.57735f; // 1 / sqrt(3)
1091 alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma+1.0f))));
1092 fons__blurRows(dst, w, h, dstStride, alpha);
1093 fons__blurCols(dst, w, h, dstStride, alpha);
1094 fons__blurRows(dst, w, h, dstStride, alpha);
1095 fons__blurCols(dst, w, h, dstStride, alpha);
1096 // fons__blurrows(dst, w, h, dstStride, alpha);
1097 // fons__blurcols(dst, w, h, dstStride, alpha);
1100 static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
1101 short isize, short iblur, int bitmapOption)
1103 int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
1104 float scale;
1105 FONSglyph* glyph = NULL;
1106 unsigned int h;
1107 float size = isize/10.0f;
1108 int pad, added;
1109 unsigned char* bdst;
1110 unsigned char* dst;
1111 FONSfont* renderFont = font;
1113 if (isize < 2) return NULL;
1114 if (iblur > 20) iblur = 20;
1115 pad = iblur+2;
1117 // Reset allocator.
1118 stash->nscratch = 0;
1120 // Find code point and size.
1121 h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
1122 i = font->lut[h];
1123 while (i != -1) {
1124 if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur) {
1125 glyph = &font->glyphs[i];
1126 if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL || (glyph->x0 >= 0 && glyph->y0 >= 0)) {
1127 return glyph;
1129 // At this point, glyph exists but the bitmap data is not yet created.
1130 break;
1132 i = font->glyphs[i].next;
1135 // Create a new glyph or rasterize bitmap data for a cached glyph.
1136 g = fons__tt_getGlyphIndex(&font->font, codepoint);
1137 // Try to find the glyph in fallback fonts.
1138 if (g == 0) {
1139 for (i = 0; i < font->nfallbacks; ++i) {
1140 FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
1141 int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
1142 if (fallbackIndex != 0) {
1143 g = fallbackIndex;
1144 renderFont = fallbackFont;
1145 break;
1148 // It is possible that we did not find a fallback glyph.
1149 // In that case the glyph index 'g' is 0, and we'll proceed below and cache empty glyph.
1151 scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
1152 fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
1153 gw = x1-x0 + pad*2;
1154 gh = y1-y0 + pad*2;
1156 // Determines the spot to draw glyph in the atlas.
1157 if (bitmapOption == FONS_GLYPH_BITMAP_REQUIRED) {
1158 // Find free spot for the rect in the atlas
1159 added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1160 if (added == 0 && stash->handleError != NULL) {
1161 // Atlas is full, let the user to resize the atlas (or not), and try again.
1162 stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
1163 added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1165 if (added == 0) return NULL;
1166 } else {
1167 // Negative coordinate indicates there is no bitmap data created.
1168 gx = -1;
1169 gy = -1;
1172 // Init glyph.
1173 if (glyph == NULL) {
1174 glyph = fons__allocGlyph(font);
1175 glyph->codepoint = codepoint;
1176 glyph->size = isize;
1177 glyph->blur = iblur;
1178 glyph->next = 0;
1180 // Insert char to hash lookup.
1181 glyph->next = font->lut[h];
1182 font->lut[h] = font->nglyphs-1;
1184 glyph->index = g;
1185 glyph->x0 = (short)gx;
1186 glyph->y0 = (short)gy;
1187 glyph->x1 = (short)(glyph->x0+gw);
1188 glyph->y1 = (short)(glyph->y0+gh);
1189 glyph->xadv = (short)(scale * advance * 10.0f);
1190 glyph->xoff = (short)(x0 - pad);
1191 glyph->yoff = (short)(y0 - pad);
1193 if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL) {
1194 return glyph;
1197 // Rasterize
1198 dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
1199 fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale, scale, g);
1201 // Make sure there is one pixel empty border.
1202 dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1203 for (y = 0; y < gh; y++) {
1204 dst[y*stash->params.width] = 0;
1205 dst[gw-1 + y*stash->params.width] = 0;
1207 for (x = 0; x < gw; x++) {
1208 dst[x] = 0;
1209 dst[x + (gh-1)*stash->params.width] = 0;
1212 // Debug code to color the glyph background
1213 /* unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1214 for (y = 0; y < gh; y++) {
1215 for (x = 0; x < gw; x++) {
1216 int a = (int)fdst[x+y*stash->params.width] + 20;
1217 if (a > 255) a = 255;
1218 fdst[x+y*stash->params.width] = a;
1222 // Blur
1223 if (iblur > 0) {
1224 stash->nscratch = 0;
1225 bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1226 fons__blur(stash, bdst, gw, gh, stash->params.width, iblur);
1229 stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
1230 stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
1231 stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
1232 stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);
1234 return glyph;
1237 static void fons__getQuad(FONScontext* stash, FONSfont* font,
1238 int prevGlyphIndex, FONSglyph* glyph,
1239 float scale, float spacing, float* x, float* y, FONSquad* q)
1241 float rx,ry,xoff,yoff,x0,y0,x1,y1;
1243 if (prevGlyphIndex != -1) {
1244 float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale;
1245 *x += (int)(adv + spacing + 0.5f);
1248 // Each glyph has 2px border to allow good interpolation,
1249 // one pixel to prevent leaking, and one to allow good interpolation for rendering.
1250 // Inset the texture region by one pixel for correct interpolation.
1251 xoff = (short)(glyph->xoff+1);
1252 yoff = (short)(glyph->yoff+1);
1253 x0 = (float)(glyph->x0+1);
1254 y0 = (float)(glyph->y0+1);
1255 x1 = (float)(glyph->x1-1);
1256 y1 = (float)(glyph->y1-1);
1258 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1259 rx = floorf(*x + xoff);
1260 ry = floorf(*y + yoff);
1262 q->x0 = rx;
1263 q->y0 = ry;
1264 q->x1 = rx + x1 - x0;
1265 q->y1 = ry + y1 - y0;
1267 q->s0 = x0 * stash->itw;
1268 q->t0 = y0 * stash->ith;
1269 q->s1 = x1 * stash->itw;
1270 q->t1 = y1 * stash->ith;
1271 } else {
1272 rx = floorf(*x + xoff);
1273 ry = floorf(*y - yoff);
1275 q->x0 = rx;
1276 q->y0 = ry;
1277 q->x1 = rx + x1 - x0;
1278 q->y1 = ry - y1 + y0;
1280 q->s0 = x0 * stash->itw;
1281 q->t0 = y0 * stash->ith;
1282 q->s1 = x1 * stash->itw;
1283 q->t1 = y1 * stash->ith;
1286 *x += (int)(glyph->xadv / 10.0f + 0.5f);
1289 static void fons__flush(FONScontext* stash)
1291 // Flush texture
1292 if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1293 if (stash->params.renderUpdate != NULL)
1294 stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData);
1295 // Reset dirty rect
1296 stash->dirtyRect[0] = stash->params.width;
1297 stash->dirtyRect[1] = stash->params.height;
1298 stash->dirtyRect[2] = 0;
1299 stash->dirtyRect[3] = 0;
1302 // Flush triangles
1303 if (stash->nverts > 0) {
1304 if (stash->params.renderDraw != NULL)
1305 stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->tcoords, stash->colors, stash->nverts);
1306 stash->nverts = 0;
1310 static __inline void fons__vertex(FONScontext* stash, float x, float y, float s, float t, unsigned int c)
1312 stash->verts[stash->nverts*2+0] = x;
1313 stash->verts[stash->nverts*2+1] = y;
1314 stash->tcoords[stash->nverts*2+0] = s;
1315 stash->tcoords[stash->nverts*2+1] = t;
1316 stash->colors[stash->nverts] = c;
1317 stash->nverts++;
1320 static float fons__getVertAlign(FONScontext* stash, FONSfont* font, int align, short isize)
1322 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1323 if (align & FONS_ALIGN_TOP) {
1324 return font->ascender * (float)isize/10.0f;
1325 } else if (align & FONS_ALIGN_MIDDLE) {
1326 return (font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
1327 } else if (align & FONS_ALIGN_BASELINE) {
1328 return 0.0f;
1329 } else if (align & FONS_ALIGN_BOTTOM) {
1330 return font->descender * (float)isize/10.0f;
1332 } else {
1333 if (align & FONS_ALIGN_TOP) {
1334 return -font->ascender * (float)isize/10.0f;
1335 } else if (align & FONS_ALIGN_MIDDLE) {
1336 return -(font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
1337 } else if (align & FONS_ALIGN_BASELINE) {
1338 return 0.0f;
1339 } else if (align & FONS_ALIGN_BOTTOM) {
1340 return -font->descender * (float)isize/10.0f;
1343 return 0.0;
1346 float fonsDrawText(FONScontext* stash,
1347 float x, float y,
1348 const char* str, const char* end)
1350 FONSstate* state = fons__getState(stash);
1351 unsigned int codepoint;
1352 unsigned int utf8state = 0;
1353 FONSglyph* glyph = NULL;
1354 FONSquad q;
1355 int prevGlyphIndex = -1;
1356 short isize = (short)(state->size*10.0f);
1357 short iblur = (short)state->blur;
1358 float scale;
1359 FONSfont* font;
1360 float width;
1362 if (stash == NULL) return x;
1363 if (state->font < 0 || state->font >= stash->nfonts) return x;
1364 font = stash->fonts[state->font];
1365 if (font->data == NULL) return x;
1367 scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
1369 if (end == NULL)
1370 end = str + strlen(str);
1372 // Align horizontally
1373 if (state->align & FONS_ALIGN_LEFT) {
1374 // empty
1375 } else if (state->align & FONS_ALIGN_RIGHT) {
1376 width = fonsTextBounds(stash, x,y, str, end, NULL);
1377 x -= width;
1378 } else if (state->align & FONS_ALIGN_CENTER) {
1379 width = fonsTextBounds(stash, x,y, str, end, NULL);
1380 x -= width * 0.5f;
1382 // Align vertically.
1383 y += fons__getVertAlign(stash, font, state->align, isize);
1385 for (; str != end; ++str) {
1386 if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
1387 continue;
1388 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_REQUIRED);
1389 if (glyph != NULL) {
1390 fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1392 if (stash->nverts+6 > FONS_VERTEX_COUNT)
1393 fons__flush(stash);
1395 fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
1396 fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
1397 fons__vertex(stash, q.x1, q.y0, q.s1, q.t0, state->color);
1399 fons__vertex(stash, q.x0, q.y0, q.s0, q.t0, state->color);
1400 fons__vertex(stash, q.x0, q.y1, q.s0, q.t1, state->color);
1401 fons__vertex(stash, q.x1, q.y1, q.s1, q.t1, state->color);
1403 prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1405 fons__flush(stash);
1407 return x;
1410 int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
1411 float x, float y, const char* str, const char* end, int bitmapOption)
1413 FONSstate* state = fons__getState(stash);
1414 float width;
1416 memset(iter, 0, sizeof(*iter));
1418 if (stash == NULL) return 0;
1419 if (state->font < 0 || state->font >= stash->nfonts) return 0;
1420 iter->font = stash->fonts[state->font];
1421 if (iter->font->data == NULL) return 0;
1423 iter->isize = (short)(state->size*10.0f);
1424 iter->iblur = (short)state->blur;
1425 iter->scale = fons__tt_getPixelHeightScale(&iter->font->font, (float)iter->isize/10.0f);
1427 // Align horizontally
1428 if (state->align & FONS_ALIGN_LEFT) {
1429 // empty
1430 } else if (state->align & FONS_ALIGN_RIGHT) {
1431 width = fonsTextBounds(stash, x,y, str, end, NULL);
1432 x -= width;
1433 } else if (state->align & FONS_ALIGN_CENTER) {
1434 width = fonsTextBounds(stash, x,y, str, end, NULL);
1435 x -= width * 0.5f;
1437 // Align vertically.
1438 y += fons__getVertAlign(stash, iter->font, state->align, iter->isize);
1440 if (end == NULL)
1441 end = str + strlen(str);
1443 iter->x = iter->nextx = x;
1444 iter->y = iter->nexty = y;
1445 iter->spacing = state->spacing;
1446 iter->str = str;
1447 iter->next = str;
1448 iter->end = end;
1449 iter->codepoint = 0;
1450 iter->prevGlyphIndex = -1;
1451 iter->bitmapOption = bitmapOption;
1453 return 1;
1456 int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
1458 FONSglyph* glyph = NULL;
1459 const char* str = iter->next;
1460 iter->str = iter->next;
1462 if (str == iter->end)
1463 return 0;
1465 for (; str != iter->end; str++) {
1466 if (fons__decutf8(&iter->utf8state, &iter->codepoint, *(const unsigned char*)str))
1467 continue;
1468 str++;
1469 // Get glyph and quad
1470 iter->x = iter->nextx;
1471 iter->y = iter->nexty;
1472 glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur, iter->bitmapOption);
1473 // If the iterator was initialized with FONS_GLYPH_BITMAP_OPTIONAL, then the UV coordinates of the quad will be invalid.
1474 if (glyph != NULL)
1475 fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad);
1476 iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1477 break;
1479 iter->next = str;
1481 return 1;
1484 void fonsDrawDebug(FONScontext* stash, float x, float y)
1486 int i;
1487 int w = stash->params.width;
1488 int h = stash->params.height;
1489 float u = w == 0 ? 0 : (1.0f / w);
1490 float v = h == 0 ? 0 : (1.0f / h);
1492 if (stash->nverts+6+6 > FONS_VERTEX_COUNT)
1493 fons__flush(stash);
1495 // Draw background
1496 fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
1497 fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
1498 fons__vertex(stash, x+w, y+0, u, v, 0x0fffffff);
1500 fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
1501 fons__vertex(stash, x+0, y+h, u, v, 0x0fffffff);
1502 fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
1504 // Draw texture
1505 fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
1506 fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
1507 fons__vertex(stash, x+w, y+0, 1, 0, 0xffffffff);
1509 fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
1510 fons__vertex(stash, x+0, y+h, 0, 1, 0xffffffff);
1511 fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
1513 // Drawbug draw atlas
1514 for (i = 0; i < stash->atlas->nnodes; i++) {
1515 FONSatlasNode* n = &stash->atlas->nodes[i];
1517 if (stash->nverts+6 > FONS_VERTEX_COUNT)
1518 fons__flush(stash);
1520 fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
1521 fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
1522 fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc00000ff);
1524 fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
1525 fons__vertex(stash, x+n->x+0, y+n->y+1, u, v, 0xc00000ff);
1526 fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
1529 fons__flush(stash);
1532 float fonsTextBounds(FONScontext* stash,
1533 float x, float y,
1534 const char* str, const char* end,
1535 float* bounds)
1537 FONSstate* state = fons__getState(stash);
1538 unsigned int codepoint;
1539 unsigned int utf8state = 0;
1540 FONSquad q;
1541 FONSglyph* glyph = NULL;
1542 int prevGlyphIndex = -1;
1543 short isize = (short)(state->size*10.0f);
1544 short iblur = (short)state->blur;
1545 float scale;
1546 FONSfont* font;
1547 float startx, advance;
1548 float minx, miny, maxx, maxy;
1550 if (stash == NULL) return 0;
1551 if (state->font < 0 || state->font >= stash->nfonts) return 0;
1552 font = stash->fonts[state->font];
1553 if (font->data == NULL) return 0;
1555 scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);
1557 // Align vertically.
1558 y += fons__getVertAlign(stash, font, state->align, isize);
1560 minx = maxx = x;
1561 miny = maxy = y;
1562 startx = x;
1564 if (end == NULL)
1565 end = str + strlen(str);
1567 for (; str != end; ++str) {
1568 if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
1569 continue;
1570 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_OPTIONAL);
1571 if (glyph != NULL) {
1572 fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1573 if (q.x0 < minx) minx = q.x0;
1574 if (q.x1 > maxx) maxx = q.x1;
1575 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1576 if (q.y0 < miny) miny = q.y0;
1577 if (q.y1 > maxy) maxy = q.y1;
1578 } else {
1579 if (q.y1 < miny) miny = q.y1;
1580 if (q.y0 > maxy) maxy = q.y0;
1583 prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1586 advance = x - startx;
1588 // Align horizontally
1589 if (state->align & FONS_ALIGN_LEFT) {
1590 // empty
1591 } else if (state->align & FONS_ALIGN_RIGHT) {
1592 minx -= advance;
1593 maxx -= advance;
1594 } else if (state->align & FONS_ALIGN_CENTER) {
1595 minx -= advance * 0.5f;
1596 maxx -= advance * 0.5f;
1599 if (bounds) {
1600 bounds[0] = minx;
1601 bounds[1] = miny;
1602 bounds[2] = maxx;
1603 bounds[3] = maxy;
1606 return advance;
1609 void fonsVertMetrics(FONScontext* stash,
1610 float* ascender, float* descender, float* lineh)
1612 FONSfont* font;
1613 FONSstate* state = fons__getState(stash);
1614 short isize;
1616 if (stash == NULL) return;
1617 if (state->font < 0 || state->font >= stash->nfonts) return;
1618 font = stash->fonts[state->font];
1619 isize = (short)(state->size*10.0f);
1620 if (font->data == NULL) return;
1622 if (ascender)
1623 *ascender = font->ascender*isize/10.0f;
1624 if (descender)
1625 *descender = font->descender*isize/10.0f;
1626 if (lineh)
1627 *lineh = font->lineh*isize/10.0f;
1630 void fonsLineBounds(FONScontext* stash, float y, float* miny, float* maxy)
1632 FONSfont* font;
1633 FONSstate* state = fons__getState(stash);
1634 short isize;
1636 if (stash == NULL) return;
1637 if (state->font < 0 || state->font >= stash->nfonts) return;
1638 font = stash->fonts[state->font];
1639 isize = (short)(state->size*10.0f);
1640 if (font->data == NULL) return;
1642 y += fons__getVertAlign(stash, font, state->align, isize);
1644 if (stash->params.flags & FONS_ZERO_TOPLEFT) {
1645 *miny = y - font->ascender * (float)isize/10.0f;
1646 *maxy = *miny + font->lineh*isize/10.0f;
1647 } else {
1648 *maxy = y + font->descender * (float)isize/10.0f;
1649 *miny = *maxy - font->lineh*isize/10.0f;
1653 const unsigned char* fonsGetTextureData(FONScontext* stash, int* width, int* height)
1655 if (width != NULL)
1656 *width = stash->params.width;
1657 if (height != NULL)
1658 *height = stash->params.height;
1659 return stash->texData;
1662 int fonsValidateTexture(FONScontext* stash, int* dirty)
1664 if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1665 dirty[0] = stash->dirtyRect[0];
1666 dirty[1] = stash->dirtyRect[1];
1667 dirty[2] = stash->dirtyRect[2];
1668 dirty[3] = stash->dirtyRect[3];
1669 // Reset dirty rect
1670 stash->dirtyRect[0] = stash->params.width;
1671 stash->dirtyRect[1] = stash->params.height;
1672 stash->dirtyRect[2] = 0;
1673 stash->dirtyRect[3] = 0;
1674 return 1;
1676 return 0;
1679 void fonsDeleteInternal(FONScontext* stash)
1681 int i;
1682 if (stash == NULL) return;
1684 if (stash->params.renderDelete)
1685 stash->params.renderDelete(stash->params.userPtr);
1687 for (i = 0; i < stash->nfonts; ++i)
1688 fons__freeFont(stash->fonts[i]);
1690 if (stash->atlas) fons__deleteAtlas(stash->atlas);
1691 if (stash->fonts) free(stash->fonts);
1692 if (stash->texData) free(stash->texData);
1693 if (stash->scratch) free(stash->scratch);
1694 fons__tt_done(stash);
1695 free(stash);
1698 void fonsSetErrorCallback(FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
1700 if (stash == NULL) return;
1701 stash->handleError = callback;
1702 stash->errorUptr = uptr;
1705 void fonsGetAtlasSize(FONScontext* stash, int* width, int* height)
1707 if (stash == NULL) return;
1708 *width = stash->params.width;
1709 *height = stash->params.height;
1712 int fonsExpandAtlas(FONScontext* stash, int width, int height)
1714 int i, maxy = 0;
1715 unsigned char* data = NULL;
1716 if (stash == NULL) return 0;
1718 width = fons__maxi(width, stash->params.width);
1719 height = fons__maxi(height, stash->params.height);
1721 if (width == stash->params.width && height == stash->params.height)
1722 return 1;
1724 // Flush pending glyphs.
1725 fons__flush(stash);
1727 // Create new texture
1728 if (stash->params.renderResize != NULL) {
1729 if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1730 return 0;
1732 // Copy old texture data over.
1733 data = (unsigned char*)malloc(width * height);
1734 if (data == NULL)
1735 return 0;
1736 for (i = 0; i < stash->params.height; i++) {
1737 unsigned char* dst = &data[i*width];
1738 unsigned char* src = &stash->texData[i*stash->params.width];
1739 memcpy(dst, src, stash->params.width);
1740 if (width > stash->params.width)
1741 memset(dst+stash->params.width, 0, width - stash->params.width);
1743 if (height > stash->params.height)
1744 memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width);
1746 free(stash->texData);
1747 stash->texData = data;
1749 // Increase atlas size
1750 fons__atlasExpand(stash->atlas, width, height);
1752 // Add existing data as dirty.
1753 for (i = 0; i < stash->atlas->nnodes; i++)
1754 maxy = fons__maxi(maxy, stash->atlas->nodes[i].y);
1755 stash->dirtyRect[0] = 0;
1756 stash->dirtyRect[1] = 0;
1757 stash->dirtyRect[2] = stash->params.width;
1758 stash->dirtyRect[3] = maxy;
1760 stash->params.width = width;
1761 stash->params.height = height;
1762 stash->itw = 1.0f/stash->params.width;
1763 stash->ith = 1.0f/stash->params.height;
1765 return 1;
1768 int fonsResetAtlas(FONScontext* stash, int width, int height)
1770 int i, j;
1771 if (stash == NULL) return 0;
1773 // Flush pending glyphs.
1774 fons__flush(stash);
1776 // Create new texture
1777 if (stash->params.renderResize != NULL) {
1778 if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1779 return 0;
1782 // Reset atlas
1783 fons__atlasReset(stash->atlas, width, height);
1785 // Clear texture data.
1786 stash->texData = (unsigned char*)realloc(stash->texData, width * height);
1787 if (stash->texData == NULL) return 0;
1788 memset(stash->texData, 0, width * height);
1790 // Reset dirty rect
1791 stash->dirtyRect[0] = width;
1792 stash->dirtyRect[1] = height;
1793 stash->dirtyRect[2] = 0;
1794 stash->dirtyRect[3] = 0;
1796 // Reset cached glyphs
1797 for (i = 0; i < stash->nfonts; i++) {
1798 FONSfont* font = stash->fonts[i];
1799 font->nglyphs = 0;
1800 for (j = 0; j < FONS_HASH_LUT_SIZE; j++)
1801 font->lut[j] = -1;
1804 stash->params.width = width;
1805 stash->params.height = height;
1806 stash->itw = 1.0f/stash->params.width;
1807 stash->ith = 1.0f/stash->params.height;
1809 // Add white rect at 0,0 for debug drawing.
1810 fons__addWhiteRect(stash, 2,2);
1812 return 1;
1816 #endif