Browse Source

Merge pull request #431 from olliwang/font

Resets font atlas when it is full.
shared-context
Mikko Mononen GitHub 7 years ago
parent
commit
364911b596
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 28 deletions
  1. +52
    -25
      src/fontstash.h
  2. +3
    -3
      src/nanovg.c

+ 52
- 25
src/fontstash.h View File

@@ -38,6 +38,11 @@ enum FONSalign {
FONS_ALIGN_BASELINE = 1<<6, // Default FONS_ALIGN_BASELINE = 1<<6, // Default
}; };


enum FONSglyphBitmap {
FONS_GLYPH_BITMAP_OPTIONAL = 1,
FONS_GLYPH_BITMAP_REQUIRED = 2,
};

enum FONSerrorCode { enum FONSerrorCode {
// Font atlas is full. // Font atlas is full.
FONS_ATLAS_FULL = 1, FONS_ATLAS_FULL = 1,
@@ -78,6 +83,7 @@ struct FONStextIter {
const char* next; const char* next;
const char* end; const char* end;
unsigned int utf8state; unsigned int utf8state;
int bitmapOption;
}; };
typedef struct FONStextIter FONStextIter; typedef struct FONStextIter FONStextIter;


@@ -122,7 +128,7 @@ void fonsLineBounds(FONScontext* s, float y, float* miny, float* maxy);
void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh); void fonsVertMetrics(FONScontext* s, float* ascender, float* descender, float* lineh);


// Text iterator // Text iterator
int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end);
int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, float x, float y, const char* str, const char* end, int bitmapOption);
int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, struct FONSquad* quad); int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, struct FONSquad* quad);


// Pull texture changes // Pull texture changes
@@ -1030,7 +1036,7 @@ static void fons__blur(FONScontext* stash, unsigned char* dst, int w, int h, int
} }


static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint, static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned int codepoint,
short isize, short iblur)
short isize, short iblur, int bitmapOption)
{ {
int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y; int i, g, advance, lsb, x0, y0, x1, y1, gw, gh, gx, gy, x, y;
float scale; float scale;
@@ -1053,12 +1059,18 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1); h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1);
i = font->lut[h]; i = font->lut[h];
while (i != -1) { while (i != -1) {
if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur)
return &font->glyphs[i];
if (font->glyphs[i].codepoint == codepoint && font->glyphs[i].size == isize && font->glyphs[i].blur == iblur) {
glyph = &font->glyphs[i];
if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL || (glyph->x0 >= 0 && glyph->y0 >= 0)) {
return glyph;
}
// At this point, glyph exists but the bitmap data is not yet created.
break;
}
i = font->glyphs[i].next; i = font->glyphs[i].next;
} }


// Could not find glyph, create it.
// Create a new glyph or rasterize bitmap data for a cached glyph.
g = fons__tt_getGlyphIndex(&font->font, codepoint); g = fons__tt_getGlyphIndex(&font->font, codepoint);
// Try to find the glyph in fallback fonts. // Try to find the glyph in fallback fonts.
if (g == 0) { if (g == 0) {
@@ -1079,20 +1091,34 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
gw = x1-x0 + pad*2; gw = x1-x0 + pad*2;
gh = y1-y0 + pad*2; gh = y1-y0 + pad*2;


// Find free spot for the rect in the atlas
added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
if (added == 0 && stash->handleError != NULL) {
// Atlas is full, let the user to resize the atlas (or not), and try again.
stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
// Determines the spot to draw glyph in the atlas.
if (bitmapOption == FONS_GLYPH_BITMAP_REQUIRED) {
// Find free spot for the rect in the atlas
added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy); added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
if (added == 0 && stash->handleError != NULL) {
// Atlas is full, let the user to resize the atlas (or not), and try again.
stash->handleError(stash->errorUptr, FONS_ATLAS_FULL, 0);
added = fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy);
}
if (added == 0) return NULL;
} else {
// Negative coordinate indicates there is no bitmap data created.
gx = -1;
gy = -1;
} }
if (added == 0) return NULL;


// Init glyph. // Init glyph.
glyph = fons__allocGlyph(font);
glyph->codepoint = codepoint;
glyph->size = isize;
glyph->blur = iblur;
if (glyph == NULL) {
glyph = fons__allocGlyph(font);
glyph->codepoint = codepoint;
glyph->size = isize;
glyph->blur = iblur;
glyph->next = 0;

// Insert char to hash lookup.
glyph->next = font->lut[h];
font->lut[h] = font->nglyphs-1;
}
glyph->index = g; glyph->index = g;
glyph->x0 = (short)gx; glyph->x0 = (short)gx;
glyph->y0 = (short)gy; glyph->y0 = (short)gy;
@@ -1101,15 +1127,14 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
glyph->xadv = (short)(scale * advance * 10.0f); glyph->xadv = (short)(scale * advance * 10.0f);
glyph->xoff = (short)(x0 - pad); glyph->xoff = (short)(x0 - pad);
glyph->yoff = (short)(y0 - pad); glyph->yoff = (short)(y0 - pad);
glyph->next = 0;


// Insert char to hash lookup.
glyph->next = font->lut[h];
font->lut[h] = font->nglyphs-1;
if (bitmapOption == FONS_GLYPH_BITMAP_OPTIONAL) {
return glyph;
}


// Rasterize // Rasterize
dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width]; dst = &stash->texData[(glyph->x0+pad) + (glyph->y0+pad) * stash->params.width];
fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale,scale, g);
fons__tt_renderGlyphBitmap(&renderFont->font, dst, gw-pad*2,gh-pad*2, stash->params.width, scale, scale, g);


// Make sure there is one pixel empty border. // Make sure there is one pixel empty border.
dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
@@ -1136,7 +1161,7 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in
if (iblur > 0) { if (iblur > 0) {
stash->nscratch = 0; stash->nscratch = 0;
bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width];
fons__blur(stash, bdst, gw,gh, stash->params.width, iblur);
fons__blur(stash, bdst, gw, gh, stash->params.width, iblur);
} }


stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0); stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0);
@@ -1298,7 +1323,7 @@ float fonsDrawText(FONScontext* stash,
for (; str != end; ++str) { for (; str != end; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue; continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_REQUIRED);
if (glyph != NULL) { if (glyph != NULL) {
fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q); fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);


@@ -1321,7 +1346,7 @@ float fonsDrawText(FONScontext* stash,
} }


int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
float x, float y, const char* str, const char* end)
float x, float y, const char* str, const char* end, int bitmapOption)
{ {
FONSstate* state = fons__getState(stash); FONSstate* state = fons__getState(stash);
float width; float width;
@@ -1361,6 +1386,7 @@ int fonsTextIterInit(FONScontext* stash, FONStextIter* iter,
iter->end = end; iter->end = end;
iter->codepoint = 0; iter->codepoint = 0;
iter->prevGlyphIndex = -1; iter->prevGlyphIndex = -1;
iter->bitmapOption = bitmapOption;


return 1; return 1;
} }
@@ -1381,7 +1407,8 @@ int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad)
// Get glyph and quad // Get glyph and quad
iter->x = iter->nextx; iter->x = iter->nextx;
iter->y = iter->nexty; iter->y = iter->nexty;
glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur);
glyph = fons__getGlyph(stash, iter->font, iter->codepoint, iter->isize, iter->iblur, iter->bitmapOption);
// If the iterator was initialized with FONS_GLYPH_BITMAP_OPTIONAL, then the UV coordinates of the quad will be invalid.
if (glyph != NULL) if (glyph != NULL)
fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad); fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad);
iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1; iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1;
@@ -1478,7 +1505,7 @@ float fonsTextBounds(FONScontext* stash,
for (; str != end; ++str) { for (; str != end; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue; continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_OPTIONAL);
if (glyph != NULL) { if (glyph != NULL) {
fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q); fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q);
if (q.x0 < minx) minx = q.x0; if (q.x0 < minx) minx = q.x0;


+ 3
- 3
src/nanovg.c View File

@@ -2440,7 +2440,7 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char*
verts = nvg__allocTempVerts(ctx, cverts); verts = nvg__allocTempVerts(ctx, cverts);
if (verts == NULL) return x; if (verts == NULL) return x;


fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end);
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_REQUIRED);
prevIter = iter; prevIter = iter;
while (fonsTextIterNext(ctx->fs, &iter, &q)) { while (fonsTextIterNext(ctx->fs, &iter, &q)) {
float c[4*2]; float c[4*2];
@@ -2537,7 +2537,7 @@ int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string,
fonsSetAlign(ctx->fs, state->textAlign); fonsSetAlign(ctx->fs, state->textAlign);
fonsSetFont(ctx->fs, state->fontId); fonsSetFont(ctx->fs, state->fontId);


fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end);
fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL);
prevIter = iter; prevIter = iter;
while (fonsTextIterNext(ctx->fs, &iter, &q)) { while (fonsTextIterNext(ctx->fs, &iter, &q)) {
if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph?
@@ -2603,7 +2603,7 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa


breakRowWidth *= scale; breakRowWidth *= scale;


fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end);
fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL);
prevIter = iter; prevIter = iter;
while (fonsTextIterNext(ctx->fs, &iter, &q)) { while (fonsTextIterNext(ctx->fs, &iter, &q)) {
if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph?


Loading…
Cancel
Save