28#define FONS_DEF static
30#define FONS_DEF extern
33#define FONS_INVALID -1
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);
153#ifdef FONTSTASH_IMPLEMENTATION
155#define FONS_NOTUSED(v) (void)(v)
157#ifdef FONS_USE_FREETYPE
160#include FT_FREETYPE_H
161#include FT_ADVANCES_H
164struct FONSttFontImpl {
167typedef struct FONSttFontImpl FONSttFontImpl;
169static FT_Library ftLibrary;
171static int fons__tt_init()
174 FONS_NOTUSED(context);
175 ftError = FT_Init_FreeType(&ftLibrary);
179static int fons__tt_loadFont(
FONScontext *context, FONSttFontImpl *font,
unsigned char *data,
int dataSize)
182 FONS_NOTUSED(context);
185 ftError = FT_New_Memory_Face(ftLibrary, (
const FT_Byte*)data, dataSize, 0, &font->font);
189static void fons__tt_getFontVMetrics(FONSttFontImpl *font,
int *ascent,
int *descent,
int *lineGap)
191 *ascent = font->font->ascender;
192 *descent = font->font->descender;
193 *lineGap = font->font->height - (*ascent - *descent);
196static float fons__tt_getPixelHeightScale(FONSttFontImpl *font,
float size)
198 return size / (font->font->ascender - font->font->descender);
201static int fons__tt_getGlyphIndex(FONSttFontImpl *font,
int codepoint)
203 return FT_Get_Char_Index(font->font, codepoint);
206static int fons__tt_buildGlyphBitmap(FONSttFontImpl *font,
int glyph,
float size,
float scale,
207 int *advance,
int *lsb,
int *x0,
int *y0,
int *x1,
int *y1)
210 FT_GlyphSlot ftGlyph;
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;
230static void fons__tt_renderGlyphBitmap(FONSttFontImpl *font,
unsigned char *output,
int outWidth,
int outHeight,
int outStride,
231 float scaleX,
float scaleY,
int glyph)
233 FT_GlyphSlot ftGlyph = font->font->glyph;
234 int ftGlyphOffset = 0;
236 FONS_NOTUSED(outWidth);
237 FONS_NOTUSED(outHeight);
238 FONS_NOTUSED(scaleX);
239 FONS_NOTUSED(scaleY);
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++];
249static int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font,
int glyph1,
int glyph2)
252 FT_Get_Kerning(font->font, glyph1, glyph2, FT_KERNING_DEFAULT, &ftKerning);
253 return (
int)((ftKerning.x + 32) >> 6);
258#define STB_TRUETYPE_IMPLEMENTATION
260static void* fons__tmpalloc(
size_t size,
void* up);
261static void fons__tmpfree(
void* ptr,
void* up);
262#define STBTT_malloc(x,u) fons__tmpalloc(x,u)
263#define STBTT_free(x,u) fons__tmpfree(x,u)
266struct FONSttFontImpl {
269typedef struct FONSttFontImpl FONSttFontImpl;
273 FONS_NOTUSED(context);
277static int fons__tt_loadFont(
FONScontext *context, FONSttFontImpl *font,
unsigned char *data,
int dataSize)
280 FONS_NOTUSED(dataSize);
282 font->font.userdata = context;
287static void fons__tt_getFontVMetrics(FONSttFontImpl *font,
int *ascent,
int *descent,
int *lineGap)
292static float fons__tt_getPixelHeightScale(FONSttFontImpl *font,
float size)
297static int fons__tt_getGlyphIndex(FONSttFontImpl *font,
int codepoint)
302static int fons__tt_buildGlyphBitmap(FONSttFontImpl *font,
int glyph,
float size,
float scale,
303 int *advance,
int *lsb,
int *x0,
int *y0,
int *x1,
int *y1)
311static void fons__tt_renderGlyphBitmap(FONSttFontImpl *font,
unsigned char *output,
int outWidth,
int outHeight,
int outStride,
312 float scaleX,
float scaleY,
int glyph)
317static int fons__tt_getGlyphKernAdvance(FONSttFontImpl *font,
int glyph1,
int glyph2)
324#ifndef FONS_SCRATCH_BUF_SIZE
325# define FONS_SCRATCH_BUF_SIZE 64000
327#ifndef FONS_HASH_LUT_SIZE
328# define FONS_HASH_LUT_SIZE 256
330#ifndef FONS_INIT_FONTS
331# define FONS_INIT_FONTS 4
333#ifndef FONS_INIT_GLYPHS
334# define FONS_INIT_GLYPHS 256
336#ifndef FONS_INIT_ATLAS_NODES
337# define FONS_INIT_ATLAS_NODES 256
339#ifndef FONS_VERTEX_COUNT
340# define FONS_VERTEX_COUNT 1024
342#ifndef FONS_MAX_STATES
343# define FONS_MAX_STATES 20
345#ifndef FONS_MAX_FALLBACKS
346# define FONS_MAX_FALLBACKS 20
349static unsigned int fons__hashint(
unsigned int a)
360static int fons__mini(
int a,
int b)
362 return a < b ? a : b;
365static int fons__maxi(
int a,
int b)
367 return a > b ? a : b;
372 unsigned int codepoint;
377 short xadv,xoff,yoff;
379typedef struct FONSglyph FONSglyph;
387 unsigned char freeData;
394 int lut[FONS_HASH_LUT_SIZE];
395 int fallbacks[FONS_MAX_FALLBACKS];
398typedef struct FONSfont FONSfont;
409typedef struct FONSstate FONSstate;
411struct FONSatlasNode {
414typedef struct FONSatlasNode FONSatlasNode;
419 FONSatlasNode* nodes;
423typedef struct FONSatlas FONSatlas;
429 unsigned char* texData;
435 float verts[FONS_VERTEX_COUNT*2];
436 float tcoords[FONS_VERTEX_COUNT*2];
437 unsigned int colors[FONS_VERTEX_COUNT];
439 unsigned char* scratch;
441 FONSstate states[FONS_MAX_STATES];
443 void (*handleError)(
void* uptr,
int error,
int val);
447#ifdef STB_TRUETYPE_IMPLEMENTATION
449static void* fons__tmpalloc(
size_t size,
void* up)
455 size = (size + 0xf) & ~0xf;
457 if (stash->nscratch+(
int)size > FONS_SCRATCH_BUF_SIZE) {
458 if (stash->handleError)
459 stash->handleError(stash->errorUptr,
FONS_SCRATCH_FULL, stash->nscratch+(
int)size);
462 ptr = stash->scratch + stash->nscratch;
463 stash->nscratch += (int)size;
467static void fons__tmpfree(
void* ptr,
void* up)
479#define FONS_UTF8_ACCEPT 0
480#define FONS_UTF8_REJECT 12
482static unsigned int fons__decutf8(
unsigned int* state,
unsigned int* codep,
unsigned int byte)
484 static const unsigned char utf8d[] = {
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,
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,
505 unsigned int type = utf8d[byte];
507 *codep = (*state != FONS_UTF8_ACCEPT) ?
508 (
byte & 0x3fu) | (*codep << 6) :
509 (0xff >> type) & (byte);
511 *state = utf8d[256 + *state + type];
517static void fons__deleteAtlas(FONSatlas* atlas)
519 if (atlas == NULL)
return;
520 if (atlas->nodes != NULL) free(atlas->nodes);
524static FONSatlas* fons__allocAtlas(
int w,
int h,
int nnodes)
526 FONSatlas* atlas = NULL;
529 atlas = (FONSatlas*)malloc(
sizeof(FONSatlas));
530 if (atlas == NULL)
goto error;
531 memset(atlas, 0,
sizeof(FONSatlas));
537 atlas->nodes = (FONSatlasNode*)malloc(
sizeof(FONSatlasNode) * nnodes);
538 if (atlas->nodes == NULL)
goto error;
539 memset(atlas->nodes, 0,
sizeof(FONSatlasNode) * nnodes);
541 atlas->cnodes = nnodes;
544 atlas->nodes[0].x = 0;
545 atlas->nodes[0].y = 0;
546 atlas->nodes[0].width = (short)w;
552 if (atlas) fons__deleteAtlas(atlas);
556static int fons__atlasInsertNode(FONSatlas* atlas,
int idx,
int x,
int y,
int w)
560 if (atlas->nnodes+1 > atlas->cnodes) {
561 atlas->cnodes = atlas->cnodes == 0 ? 8 : atlas->cnodes * 2;
562 atlas->nodes = (FONSatlasNode*)realloc(atlas->nodes,
sizeof(FONSatlasNode) * atlas->cnodes);
563 if (atlas->nodes == NULL)
566 for (i = atlas->nnodes; i > idx; i--)
567 atlas->nodes[i] = atlas->nodes[i-1];
568 atlas->nodes[idx].x = (short)x;
569 atlas->nodes[idx].y = (short)y;
570 atlas->nodes[idx].width = (short)w;
576static void fons__atlasRemoveNode(FONSatlas* atlas,
int idx)
579 if (atlas->nnodes == 0)
return;
580 for (i = idx; i < atlas->nnodes-1; i++)
581 atlas->nodes[i] = atlas->nodes[i+1];
585static void fons__atlasExpand(FONSatlas* atlas,
int w,
int h)
588 if (w > atlas->width)
589 fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width);
594static void fons__atlasReset(FONSatlas* atlas,
int w,
int h)
601 atlas->nodes[0].x = 0;
602 atlas->nodes[0].y = 0;
603 atlas->nodes[0].width = (short)w;
607static int fons__atlasAddSkylineLevel(FONSatlas* atlas,
int idx,
int x,
int y,
int w,
int h)
612 if (fons__atlasInsertNode(atlas, idx, x, y+h, w) == 0)
616 for (i = idx+1; i < atlas->nnodes; i++) {
617 if (atlas->nodes[i].x < atlas->nodes[i-1].x + atlas->nodes[i-1].width) {
618 int shrink = atlas->nodes[i-1].x + atlas->nodes[i-1].width - atlas->nodes[i].x;
619 atlas->nodes[i].x += (short)shrink;
620 atlas->nodes[i].width -= (short)shrink;
621 if (atlas->nodes[i].width <= 0) {
622 fons__atlasRemoveNode(atlas, i);
633 for (i = 0; i < atlas->nnodes-1; i++) {
634 if (atlas->nodes[i].y == atlas->nodes[i+1].y) {
635 atlas->nodes[i].width += atlas->nodes[i+1].width;
636 fons__atlasRemoveNode(atlas, i+1);
644static int fons__atlasRectFits(FONSatlas* atlas,
int i,
int w,
int h)
649 int x = atlas->nodes[i].x;
650 int y = atlas->nodes[i].y;
652 if (x + w > atlas->width)
655 while (spaceLeft > 0) {
656 if (i == atlas->nnodes)
return -1;
657 y = fons__maxi(y, atlas->nodes[i].y);
658 if (y + h > atlas->height)
return -1;
659 spaceLeft -= atlas->nodes[i].width;
665static int fons__atlasAddRect(FONSatlas* atlas,
int rw,
int rh,
int* rx,
int* ry)
667 int besth = atlas->height, bestw = atlas->width, besti = -1;
668 int bestx = -1, besty = -1, i;
671 for (i = 0; i < atlas->nnodes; i++) {
672 int y = fons__atlasRectFits(atlas, i, rw, rh);
674 if (y + rh < besth || (y + rh == besth && atlas->nodes[i].width < bestw)) {
676 bestw = atlas->nodes[i].width;
678 bestx = atlas->nodes[i].x;
688 if (fons__atlasAddSkylineLevel(atlas, besti, bestx, besty, rw, rh) == 0)
697static void fons__addWhiteRect(
FONScontext* stash,
int w,
int h)
701 if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
705 dst = &stash->texData[gx + gy * stash->params.width];
706 for (y = 0; y < h; y++) {
707 for (x = 0; x < w; x++)
709 dst += stash->params.width;
712 stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
713 stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
714 stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
715 stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
724 if (stash == NULL)
goto error;
727 stash->params = *params;
730 stash->scratch = (
unsigned char*)malloc(FONS_SCRATCH_BUF_SIZE);
731 if (stash->scratch == NULL)
goto error;
734 if (!fons__tt_init(stash))
goto error;
736 if (stash->params.renderCreate != NULL) {
737 if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0)
741 stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ATLAS_NODES);
742 if (stash->atlas == NULL)
goto error;
745 stash->fonts = (FONSfont**)malloc(
sizeof(FONSfont*) * FONS_INIT_FONTS);
746 if (stash->fonts == NULL)
goto error;
747 memset(stash->fonts, 0,
sizeof(FONSfont*) * FONS_INIT_FONTS);
748 stash->cfonts = FONS_INIT_FONTS;
752 stash->itw = 1.0f/stash->params.width;
753 stash->ith = 1.0f/stash->params.height;
754 stash->texData = (
unsigned char*)malloc(stash->params.width * stash->params.height);
755 if (stash->texData == NULL)
goto error;
756 memset(stash->texData, 0, stash->params.width * stash->params.height);
758 stash->dirtyRect[0] = stash->params.width;
759 stash->dirtyRect[1] = stash->params.height;
760 stash->dirtyRect[2] = 0;
761 stash->dirtyRect[3] = 0;
764 fons__addWhiteRect(stash, 2,2);
776static FONSstate* fons__getState(
FONScontext* stash)
778 return &stash->states[stash->nstates-1];
781int fonsAddFallbackFont(
FONScontext* stash,
int base,
int fallback)
783 FONSfont* baseFont = stash->fonts[base];
784 if (baseFont->nfallbacks < FONS_MAX_FALLBACKS) {
785 baseFont->fallbacks[baseFont->nfallbacks++] = fallback;
793 fons__getState(stash)->size = size;
798 fons__getState(stash)->color = color;
803 fons__getState(stash)->spacing = spacing;
808 fons__getState(stash)->blur = blur;
813 fons__getState(stash)->align = align;
818 fons__getState(stash)->font = font;
823 if (stash->nstates >= FONS_MAX_STATES) {
824 if (stash->handleError)
828 if (stash->nstates > 0)
829 memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1],
sizeof(FONSstate));
835 if (stash->nstates <= 1) {
836 if (stash->handleError)
845 FONSstate* state = fons__getState(stash);
847 state->color = 0xffffffff;
854static void fons__freeFont(FONSfont* font)
856 if (font == NULL)
return;
857 if (font->glyphs) free(font->glyphs);
858 if (font->freeData && font->data) free(font->data);
864 FONSfont* font = NULL;
865 if (stash->nfonts+1 > stash->cfonts) {
866 stash->cfonts = stash->cfonts == 0 ? 8 : stash->cfonts * 2;
867 stash->fonts = (FONSfont**)realloc(stash->fonts,
sizeof(FONSfont*) * stash->cfonts);
868 if (stash->fonts == NULL)
871 font = (FONSfont*)malloc(
sizeof(FONSfont));
872 if (font == NULL)
goto error;
873 memset(font, 0,
sizeof(FONSfont));
875 font->glyphs = (FONSglyph*)malloc(
sizeof(FONSglyph) * FONS_INIT_GLYPHS);
876 if (font->glyphs == NULL)
goto error;
877 font->cglyphs = FONS_INIT_GLYPHS;
880 stash->fonts[stash->nfonts++] = font;
881 return stash->nfonts-1;
884 fons__freeFont(font);
892 int dataSize = 0, readed;
893 unsigned char* data = NULL;
896 fp = fopen(path,
"rb");
897 if (fp == NULL)
goto error;
898 fseek(fp,0,SEEK_END);
899 dataSize = (int)ftell(fp);
900 fseek(fp,0,SEEK_SET);
901 data = (
unsigned char*)malloc(dataSize);
902 if (data == NULL)
goto error;
903 readed = (int)fread(data, 1, dataSize, fp);
906 if (readed != dataSize)
goto error;
911 if (data) free(data);
918 int i, ascent, descent, fh, lineGap;
921 int idx = fons__allocFont(stash);
925 font = stash->fonts[idx];
927 strncpy(font->name, name,
sizeof(font->name));
928 font->name[
sizeof(font->name)-1] =
'\0';
931 for (i = 0; i < FONS_HASH_LUT_SIZE; ++i)
935 font->dataSize = dataSize;
937 font->freeData = (
unsigned char)freeData;
941 if (!fons__tt_loadFont(stash, &font->font, data, dataSize))
goto error;
945 fons__tt_getFontVMetrics( &font->font, &ascent, &descent, &lineGap);
946 fh = ascent - descent;
947 font->ascender = (float)ascent / (
float)fh;
948 font->descender = (float)descent / (
float)fh;
949 font->lineh = (float)(fh + lineGap) / (float)fh;
954 fons__freeFont(font);
962 for (i = 0; i < s->nfonts; i++) {
963 if (strcmp(s->fonts[i]->name, name) == 0)
970static FONSglyph* fons__allocGlyph(FONSfont* font)
972 if (font->nglyphs+1 > font->cglyphs) {
973 font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2;
974 font->glyphs = (FONSglyph*)realloc(font->glyphs,
sizeof(FONSglyph) * font->cglyphs);
975 if (font->glyphs == NULL)
return NULL;
978 return &font->glyphs[font->nglyphs-1];
987static void fons__blurCols(
unsigned char* dst,
int w,
int h,
int dstStride,
int alpha)
990 for (y = 0; y < h; y++) {
992 for (x = 1; x < w; x++) {
993 z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
994 dst[x] = (
unsigned char)(z >> ZPREC);
998 for (x = w-2; x >= 0; x--) {
999 z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC;
1000 dst[x] = (
unsigned char)(z >> ZPREC);
1007static void fons__blurRows(
unsigned char* dst,
int w,
int h,
int dstStride,
int alpha)
1010 for (x = 0; x < w; x++) {
1012 for (y = dstStride; y < h*dstStride; y += dstStride) {
1013 z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
1014 dst[y] = (
unsigned char)(z >> ZPREC);
1016 dst[(h-1)*dstStride] = 0;
1018 for (y = (h-2)*dstStride; y >= 0; y -= dstStride) {
1019 z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC;
1020 dst[y] = (
unsigned char)(z >> ZPREC);
1028static void fons__blur(
FONScontext* stash,
unsigned char* dst,
int w,
int h,
int dstStride,
int blur)
1037 sigma = (float)blur * 0.57735f;
1038 alpha = (int)((1<<APREC) * (1.0f - expf(-2.3f / (sigma+1.0f))));
1039 fons__blurRows(dst, w, h, dstStride, alpha);
1040 fons__blurCols(dst, w, h, dstStride, alpha);
1041 fons__blurRows(dst, w, h, dstStride, alpha);
1042 fons__blurCols(dst, w, h, dstStride, alpha);
1047static FONSglyph* fons__getGlyph(
FONScontext* stash, FONSfont* font,
unsigned int codepoint,
1048 short isize,
short iblur)
1050 int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
1052 FONSglyph* glyph = NULL;
1054 float size = isize/10.0f;
1056 unsigned char* bdst;
1058 FONSfont* renderFont = font;
1060 if (isize < 2)
return NULL;
1061 if (iblur > 20) iblur = 20;
1065 stash->nscratch = 0;
1068 h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
1071 if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur)
1072 return &font->glyphs[i];
1073 i = font->glyphs[i].next;
1077 g = fons__tt_getGlyphIndex(&font->font, codepoint);
1080 for (i = 0; i < font->nfallbacks; ++i) {
1081 FONSfont* fallbackFont = stash->fonts[font->fallbacks[i]];
1082 int fallbackIndex = fons__tt_getGlyphIndex(&fallbackFont->font, codepoint);
1083 if (fallbackIndex != 0) {
1085 renderFont = fallbackFont;
1092 scale = fons__tt_getPixelHeightScale(&renderFont->font, size);
1093 fons__tt_buildGlyphBitmap(&renderFont->font, g, size, scale, &advance, &lsb, &x0, &y0, &x1, &y1);
1098 added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1099 if (added == 0 && stash->handleError != NULL) {
1102 added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
1104 if (added == 0)
return NULL;
1107 glyph = fons__allocGlyph(font);
1108 glyph->codepoint = codepoint;
1109 glyph->size = isize;
1110 glyph->blur = iblur;
1112 glyph->x0 = (short)gx;
1113 glyph->y0 = (short)gy;
1114 glyph->x1 = (short)(glyph->x0+gw);
1115 glyph->y1 = (short)(glyph->y0+gh);
1116 glyph->xadv = (short)(scale * advance * 10.0f);
1117 glyph->xoff = (short)(x0 - pad);
1118 glyph->yoff = (short)(y0 - pad);
1122 glyph->next = font->lut[h];
1123 font->lut[h] = font->nglyphs-1;
1126 dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
1127 fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale,scale, g);
1130 dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1131 for (y = 0; y < gh; y++) {
1132 dst[y*stash->params.width] = 0;
1133 dst[gw-1 + y*stash->params.width] = 0;
1135 for (x = 0; x < gw; x++) {
1137 dst[x + (gh-1)*stash->params.width] = 0;
1152 stash->nscratch = 0;
1153 bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
1154 fons__blur(stash, bdst, gw,gh, stash->params.width, iblur);
1157 stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
1158 stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0);
1159 stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1);
1160 stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1);
1165static void fons__getQuad(
FONScontext* stash, FONSfont* font,
1166 int prevGlyphIndex, FONSglyph* glyph,
1167 float scale,
float spacing,
float* x,
float* y,
FONSquad* q)
1169 float rx,ry,xoff,yoff,x0,y0,x1,y1;
1171 if (prevGlyphIndex != -1) {
1172 float adv = fons__tt_getGlyphKernAdvance(&font->font, prevGlyphIndex, glyph->index) * scale;
1173 *x += (int)(adv + spacing + 0.5f);
1179 xoff = (short)(glyph->xoff+1);
1180 yoff = (short)(glyph->yoff+1);
1181 x0 = (float)(glyph->x0+1);
1182 y0 = (float)(glyph->y0+1);
1183 x1 = (float)(glyph->x1-1);
1184 y1 = (float)(glyph->y1-1);
1187 rx = (float)(
int)(*x + xoff);
1188 ry = (float)(
int)(*y + yoff);
1192 q->
x1 = rx + x1 - x0;
1193 q->
y1 = ry + y1 - y0;
1195 q->
s0 = x0 * stash->itw;
1196 q->
t0 = y0 * stash->ith;
1197 q->
s1 = x1 * stash->itw;
1198 q->
t1 = y1 * stash->ith;
1200 rx = (float)(
int)(*x + xoff);
1201 ry = (float)(
int)(*y - yoff);
1205 q->
x1 = rx + x1 - x0;
1206 q->
y1 = ry - y1 + y0;
1208 q->
s0 = x0 * stash->itw;
1209 q->
t0 = y0 * stash->ith;
1210 q->
s1 = x1 * stash->itw;
1211 q->
t1 = y1 * stash->ith;
1214 *x += (int)(glyph->xadv / 10.0f + 0.5f);
1220 if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1221 if (stash->params.renderUpdate != NULL)
1222 stash->params.renderUpdate(stash->params.userPtr, stash->dirtyRect, stash->texData);
1224 stash->dirtyRect[0] = stash->params.width;
1225 stash->dirtyRect[1] = stash->params.height;
1226 stash->dirtyRect[2] = 0;
1227 stash->dirtyRect[3] = 0;
1231 if (stash->nverts > 0) {
1232 if (stash->params.renderDraw != NULL)
1233 stash->params.renderDraw(stash->params.userPtr, stash->verts, stash->tcoords, stash->colors, stash->nverts);
1238static __inline
void fons__vertex(
FONScontext* stash,
float x,
float y,
float s,
float t,
unsigned int c)
1240 stash->verts[stash->nverts*2+0] = x;
1241 stash->verts[stash->nverts*2+1] = y;
1242 stash->tcoords[stash->nverts*2+0] = s;
1243 stash->tcoords[stash->nverts*2+1] = t;
1244 stash->colors[stash->nverts] = c;
1248static float fons__getVertAlign(
FONScontext* stash, FONSfont* font,
int align,
short isize)
1252 return font->ascender * (float)isize/10.0f;
1254 return (font->ascender + font->descender) / 2.0f * (float)isize/10.0f;
1258 return font->descender * (float)isize/10.0f;
1262 return -font->ascender * (float)isize/10.0f;
1264 return -(font->ascender + font->descender) / 2.0f * (
float)isize/10.0f;
1268 return -font->descender * (float)isize/10.0f;
1276 const char* str,
const char* end)
1278 FONSstate* state = fons__getState(stash);
1279 unsigned int codepoint;
1280 unsigned int utf8state = 0;
1281 FONSglyph* glyph = NULL;
1283 int prevGlyphIndex = -1;
1284 short isize = (short)(state->size*10.0f);
1285 short iblur = (short)state->blur;
1290 if (stash == NULL)
return x;
1291 if (state->font < 0 || state->font >= stash->nfonts)
return x;
1292 font = stash->fonts[state->font];
1293 if (font->data == NULL)
return x;
1295 scale = fons__tt_getPixelHeightScale(&font->font, (
float)isize/10.0f);
1298 end = str + strlen(str);
1311 y += fons__getVertAlign(stash, font, state->align, isize);
1313 for (; str != end; ++str) {
1314 if (fons__decutf8(&utf8state, &codepoint, *(
const unsigned char*)str))
1316 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
1317 if (glyph != NULL) {
1318 fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1320 if (stash->nverts+6 > FONS_VERTEX_COUNT)
1323 fons__vertex(stash, q.
x0, q.
y0, q.
s0, q.
t0, state->color);
1324 fons__vertex(stash, q.
x1, q.
y1, q.
s1, q.
t1, state->color);
1325 fons__vertex(stash, q.
x1, q.
y0, q.
s1, q.
t0, state->color);
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);
1331 prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1339 float x,
float y,
const char* str,
const char* end)
1341 FONSstate* state = fons__getState(stash);
1344 memset(iter, 0,
sizeof(*iter));
1346 if (stash == NULL)
return 0;
1347 if (state->font < 0 || state->font >= stash->nfonts)
return 0;
1348 iter->
font = stash->fonts[state->font];
1349 if (iter->
font->data == NULL)
return 0;
1351 iter->
isize = (short)(state->size*10.0f);
1352 iter->
iblur = (short)state->blur;
1353 iter->
scale = fons__tt_getPixelHeightScale(&iter->
font->font, (
float)iter->
isize/10.0f);
1366 y += fons__getVertAlign(stash, iter->
font, state->align, iter->
isize);
1369 end = str + strlen(str);
1371 iter->
x = iter->
nextx = x;
1372 iter->
y = iter->
nexty = y;
1373 iter->
spacing = state->spacing;
1385 FONSglyph* glyph = NULL;
1386 const char* str = iter->
next;
1389 if (str == iter->
end)
1392 for (; str != iter->
end; str++) {
1413 int w = stash->params.width;
1414 int h = stash->params.height;
1415 float u = w == 0 ? 0 : (1.0f / w);
1416 float v = h == 0 ? 0 : (1.0f / h);
1418 if (stash->nverts+6+6 > FONS_VERTEX_COUNT)
1422 fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
1423 fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
1424 fons__vertex(stash, x+w, y+0, u, v, 0x0fffffff);
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);
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);
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);
1440 for (i = 0; i < stash->atlas->nnodes; i++) {
1441 FONSatlasNode* n = &stash->atlas->nodes[i];
1443 if (stash->nverts+6 > FONS_VERTEX_COUNT)
1446 fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
1447 fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
1448 fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc00000ff);
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);
1460 const char* str,
const char* end,
1463 FONSstate* state = fons__getState(stash);
1464 unsigned int codepoint;
1465 unsigned int utf8state = 0;
1467 FONSglyph* glyph = NULL;
1468 int prevGlyphIndex = -1;
1469 short isize = (short)(state->size*10.0f);
1470 short iblur = (short)state->blur;
1473 float startx, advance;
1474 float minx, miny, maxx, maxy;
1476 if (stash == NULL)
return 0;
1477 if (state->font < 0 || state->font >= stash->nfonts)
return 0;
1478 font = stash->fonts[state->font];
1479 if (font->data == NULL)
return 0;
1481 scale = fons__tt_getPixelHeightScale(&font->font, (
float)isize/10.0f);
1484 y += fons__getVertAlign(stash, font, state->align, isize);
1491 end = str + strlen(str);
1493 for (; str != end; ++str) {
1494 if (fons__decutf8(&utf8state, &codepoint, *(
const unsigned char*)str))
1496 glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
1497 if (glyph != NULL) {
1498 fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
1499 if (q.
x0 < minx) minx = q.
x0;
1500 if (q.
x1 > maxx) maxx = q.
x1;
1502 if (q.
y0 < miny) miny = q.
y0;
1503 if (q.
y1 > maxy) maxy = q.
y1;
1505 if (q.
y1 < miny) miny = q.
y1;
1506 if (q.
y0 > maxy) maxy = q.
y0;
1509 prevGlyphIndex = glyph != NULL ? glyph->index : -1;
1512 advance = x - startx;
1521 minx -= advance * 0.5f;
1522 maxx -= advance * 0.5f;
1536 float* ascender,
float* descender,
float* lineh)
1539 FONSstate* state = fons__getState(stash);
1542 if (stash == NULL)
return;
1543 if (state->font < 0 || state->font >= stash->nfonts)
return;
1544 font = stash->fonts[state->font];
1545 isize = (short)(state->size*10.0f);
1546 if (font->data == NULL)
return;
1549 *ascender = font->ascender*isize/10.0f;
1551 *descender = font->descender*isize/10.0f;
1553 *lineh = font->lineh*isize/10.0f;
1559 FONSstate* state = fons__getState(stash);
1562 if (stash == NULL)
return;
1563 if (state->font < 0 || state->font >= stash->nfonts)
return;
1564 font = stash->fonts[state->font];
1565 isize = (short)(state->size*10.0f);
1566 if (font->data == NULL)
return;
1568 y += fons__getVertAlign(stash, font, state->align, isize);
1571 *miny = y - font->ascender * (float)isize/10.0f;
1572 *maxy = *miny + font->lineh*isize/10.0f;
1574 *maxy = y + font->descender * (float)isize/10.0f;
1575 *miny = *maxy - font->lineh*isize/10.0f;
1582 *width = stash->params.width;
1584 *height = stash->params.height;
1585 return stash->texData;
1590 if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) {
1591 dirty[0] = stash->dirtyRect[0];
1592 dirty[1] = stash->dirtyRect[1];
1593 dirty[2] = stash->dirtyRect[2];
1594 dirty[3] = stash->dirtyRect[3];
1596 stash->dirtyRect[0] = stash->params.width;
1597 stash->dirtyRect[1] = stash->params.height;
1598 stash->dirtyRect[2] = 0;
1599 stash->dirtyRect[3] = 0;
1608 if (stash == NULL)
return;
1610 if (stash->params.renderDelete)
1611 stash->params.renderDelete(stash->params.userPtr);
1613 for (i = 0; i < stash->nfonts; ++i)
1614 fons__freeFont(stash->fonts[i]);
1616 if (stash->atlas) fons__deleteAtlas(stash->atlas);
1617 if (stash->fonts) free(stash->fonts);
1618 if (stash->texData) free(stash->texData);
1619 if (stash->scratch) free(stash->scratch);
1625 if (stash == NULL)
return;
1626 stash->handleError = callback;
1627 stash->errorUptr = uptr;
1632 if (stash == NULL)
return;
1633 *width = stash->params.width;
1634 *height = stash->params.height;
1640 unsigned char* data = NULL;
1641 if (stash == NULL)
return 0;
1643 width = fons__maxi(width, stash->params.width);
1644 height = fons__maxi(height, stash->params.height);
1646 if (width == stash->params.width && height == stash->params.height)
1653 if (stash->params.renderResize != NULL) {
1654 if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1658 data = (
unsigned char*)malloc(width * height);
1661 for (i = 0; i < stash->params.height; i++) {
1662 unsigned char* dst = &data[i*width];
1663 unsigned char* src = &stash->texData[i*stash->params.width];
1664 memcpy(dst, src, stash->params.width);
1665 if (width > stash->params.width)
1666 memset(dst+stash->params.width, 0, width - stash->params.width);
1668 if (height > stash->params.height)
1669 memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width);
1671 free(stash->texData);
1672 stash->texData = data;
1675 fons__atlasExpand(stash->atlas, width, height);
1678 for (i = 0; i < stash->atlas->nnodes; i++)
1679 maxy = fons__maxi(maxy, stash->atlas->nodes[i].y);
1680 stash->dirtyRect[0] = 0;
1681 stash->dirtyRect[1] = 0;
1682 stash->dirtyRect[2] = stash->params.width;
1683 stash->dirtyRect[3] = maxy;
1685 stash->params.width = width;
1686 stash->params.height = height;
1687 stash->itw = 1.0f/stash->params.width;
1688 stash->ith = 1.0f/stash->params.height;
1696 if (stash == NULL)
return 0;
1702 if (stash->params.renderResize != NULL) {
1703 if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
1708 fons__atlasReset(stash->atlas, width, height);
1711 stash->texData = (
unsigned char*)realloc(stash->texData, width * height);
1712 if (stash->texData == NULL)
return 0;
1713 memset(stash->texData, 0, width * height);
1716 stash->dirtyRect[0] = width;
1717 stash->dirtyRect[1] = height;
1718 stash->dirtyRect[2] = 0;
1719 stash->dirtyRect[3] = 0;
1722 for (i = 0; i < stash->nfonts; i++) {
1723 FONSfont* font = stash->fonts[i];
1725 for (j = 0; j < FONS_HASH_LUT_SIZE; j++)
1729 stash->params.width = width;
1730 stash->params.height = height;
1731 stash->itw = 1.0f/stash->params.width;
1732 stash->ith = 1.0f/stash->params.height;
1735 fons__addWhiteRect(stash, 2,2);
FONS_DEF int fonsExpandAtlas(FONScontext *s, int width, int height)
FONS_DEF void fonsDrawDebug(FONScontext *s, float x, float y)
FONS_DEF void fonsSetSize(FONScontext *s, float size)
FONS_DEF void fonsPushState(FONScontext *s)
FONS_DEF int fonsValidateTexture(FONScontext *s, int *dirty)
FONS_DEF void fonsPopState(FONScontext *s)
FONS_DEF void fonsGetAtlasSize(FONScontext *s, int *width, int *height)
FONS_DEF int fonsGetFontByName(FONScontext *s, const char *name)
FONS_DEF void fonsClearState(FONScontext *s)
FONS_DEF int fonsTextIterInit(FONScontext *stash, FONStextIter *iter, float x, float y, const char *str, const char *end)
FONS_DEF void fonsSetSpacing(FONScontext *s, float spacing)
FONS_DEF float fonsDrawText(FONScontext *s, float x, float y, const char *string, const char *end)
FONS_DEF float fonsTextBounds(FONScontext *s, float x, float y, const char *string, const char *end, float *bounds)
FONS_DEF void fonsSetColor(FONScontext *s, unsigned int color)
FONS_DEF void fonsSetErrorCallback(FONScontext *s, void(*callback)(void *uptr, int error, int val), void *uptr)
FONS_DEF int fonsResetAtlas(FONScontext *stash, int width, int height)
FONS_DEF void fonsDeleteInternal(FONScontext *s)
FONS_DEF void fonsSetBlur(FONScontext *s, float blur)
FONS_DEF void fonsSetAlign(FONScontext *s, int align)
FONS_DEF int fonsAddFontMem(FONScontext *s, const char *name, unsigned char *data, int ndata, int freeData)
FONS_DEF void fonsLineBounds(FONScontext *s, float y, float *miny, float *maxy)
FONS_DEF void fonsSetFont(FONScontext *s, int font)
FONS_DEF int fonsTextIterNext(FONScontext *stash, FONStextIter *iter, struct FONSquad *quad)
FONS_DEF int fonsAddFont(FONScontext *s, const char *name, const char *path)
FONS_DEF const unsigned char * fonsGetTextureData(FONScontext *stash, int *width, int *height)
FONS_DEF void fonsVertMetrics(FONScontext *s, float *ascender, float *descender, float *lineh)
FONS_DEF FONScontext * fonsCreateInternal(FONSparams *params)
struct FONScontext FONScontext
@ error
throw a parse_error exception in case of a tag
STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)
STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels)
STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
int(* renderCreate)(void *uptr, int width, int height)
void(* renderDelete)(void *uptr)
int(* renderResize)(void *uptr, int width, int height)
void(* renderUpdate)(void *uptr, int *rect, const unsigned char *data)
void(* renderDraw)(void *uptr, const float *verts, const float *tcoords, const unsigned int *colors, int nverts)