Browse Source

Updated fontstash

shared-context
Mikko Mononen 11 years ago
parent
commit
b47f256607
1 changed files with 243 additions and 12 deletions
  1. +243
    -12
      src/fontstash.h

+ 243
- 12
src/fontstash.h View File

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

enum FONSerrorCode {
// Font atlas is full.
FONS_ATLAS_FULL = 1,
// Scratch memory used to render glyphs is full, requested size reported in 'val', you may need to bump up FONS_SCRATCH_BUF_SIZE.
FONS_SCRATCH_FULL = 2,
// Calls to fonsPushState has craeted too large stack, if you need deep state stack bump up FONS_MAX_STATES.
FONS_STATES_OVERFLOW = 3,
// Trying to pop too many states fonsPopState().
FONS_STATES_UNDERFLOW = 4,
};

struct FONSparams {
int width, height;
unsigned char flags;
void* userPtr;
int (*renderCreate)(void* uptr, int width, int height);
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);
void (*renderDelete)(void* uptr);
@@ -68,6 +80,14 @@ struct FONStextIter {
struct FONScontext* fonsCreateInternal(struct FONSparams* params);
void fonsDeleteInternal(struct FONScontext* s);

void fonsSetErrorCallback(struct FONScontext* s, void (*callback)(void* uptr, int error, int val), void* uptr);
// Returns current atlas size.
void fonsGetAtlasSize(struct FONScontext* s, int* width, int* height);
// Expands the atlas size.
int fonsExpandAtlas(struct FONScontext* s, int width, int height);
// Reseta the whole stash.
int fonsResetAtlas(struct FONScontext* stash, int width, int height);

// Add fonts
int fonsAddFont(struct FONScontext* s, const char* name, const char* path);
int fonsAddFontMem(struct FONScontext* s, const char* name, unsigned char* data, int ndata, int freeData);
@@ -377,6 +397,8 @@ struct FONScontext
int nscratch;
struct FONSstate states[FONS_MAX_STATES];
int nstates;
void (*handleError)(void* uptr, int error, int val);
void* errorUptr;
};

static void* fons__tmpalloc(size_t size, void* up)
@@ -384,8 +406,11 @@ static void* fons__tmpalloc(size_t size, void* up)
unsigned char* ptr;

struct FONScontext* stash = (struct FONScontext*)up;
if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE)
if (stash->nscratch+(int)size > FONS_SCRATCH_BUF_SIZE) {
if (stash->handleError)
stash->handleError(stash->errorUptr, FONS_SCRATCH_FULL, stash->nscratch+(int)size);
return NULL;
}
ptr = stash->scratch + stash->nscratch;
stash->nscratch += (int)size;
return ptr;
@@ -507,6 +532,28 @@ static void fons__atlasRemoveNode(struct FONSatlas* atlas, int idx)
atlas->nnodes--;
}

static void fons__atlasExpand(struct FONSatlas* atlas, int w, int h)
{
// Insert node for empty space
if (w > atlas->width)
fons__atlasInsertNode(atlas, atlas->nnodes, atlas->width, 0, w - atlas->width);
atlas->width = w;
atlas->height = h;
}

static void fons__atlasReset(struct FONSatlas* atlas, int w, int h)
{
atlas->width = w;
atlas->height = h;
atlas->nnodes = 0;

// Init root node.
atlas->nodes[0].x = 0;
atlas->nodes[0].y = 0;
atlas->nodes[0].width = (short)w;
atlas->nnodes++;
}

static int fons__atlasAddSkylineLevel(struct FONSatlas* atlas, int idx, int x, int y, int w, int h)
{
int i;
@@ -597,6 +644,26 @@ static int fons__atlasAddRect(struct FONSatlas* atlas, int rw, int rh, int* rx,
return 1;
}

static void fons__addWhiteRect(struct FONScontext* stash, int w, int h)
{
int x, y, gx, gy;
unsigned char* dst;
if (fons__atlasAddRect(stash->atlas, w, h, &gx, &gy) == 0)
return;

// Rasterize
dst = &stash->texData[gx + gy * stash->params.width];
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++)
dst[x] = 0xff;
dst += stash->params.width;
}

stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], gx);
stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], gy);
stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], gx+w);
stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], gy+h);
}

struct FONScontext* fonsCreateInternal(struct FONSparams* params)
{
@@ -639,6 +706,9 @@ struct FONScontext* fonsCreateInternal(struct FONSparams* params)
stash->dirtyRect[2] = 0;
stash->dirtyRect[3] = 0;

// Add white rect at 0,0 for debug drawing.
fons__addWhiteRect(stash, 2,2);

fonsPushState(stash);
fonsClearState(stash);

@@ -686,8 +756,11 @@ void fonsSetFont(struct FONScontext* stash, int font)

void fonsPushState(struct FONScontext* stash)
{
if (stash->nstates >= FONS_MAX_STATES)
if (stash->nstates >= FONS_MAX_STATES) {
if (stash->handleError)
stash->handleError(stash->errorUptr, FONS_STATES_OVERFLOW, 0);
return;
}
if (stash->nstates > 0)
memcpy(&stash->states[stash->nstates], &stash->states[stash->nstates-1], sizeof(struct FONSstate));
stash->nstates++;
@@ -695,8 +768,11 @@ void fonsPushState(struct FONScontext* stash)

void fonsPopState(struct FONScontext* stash)
{
if (stash->nstates <= 1)
if (stash->nstates <= 1) {
if (stash->handleError)
stash->handleError(stash->errorUptr, FONS_STATES_UNDERFLOW, 0);
return;
}
stash->nstates--;
}

@@ -911,7 +987,7 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo
struct FONSglyph* glyph = NULL;
unsigned int h;
float size = isize/10.0f;
int pad;
int pad, added;
unsigned char* bdst;
unsigned char* dst;

@@ -939,8 +1015,13 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo
gh = y1-y0 + pad*2;

// Find free spot for the rect in the atlas
if (fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy) == 0)
return NULL;
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;

// Init glyph.
glyph = fons__allocGlyph(font);
@@ -1133,6 +1214,9 @@ float fonsDrawText(struct FONScontext* stash,

scale = fons__tt_getPixelHeightScale(&font->font, (float)isize/10.0f);

if (end == NULL)
end = str + strlen(str);

// Align horizontally
if (state->align & FONS_ALIGN_LEFT) {
// empty
@@ -1146,10 +1230,7 @@ float fonsDrawText(struct FONScontext* stash,
// Align vertically.
y += fons__getVertAlign(stash, font, state->align, isize);

if (end == NULL)
end = str + strlen(str);

for (; *str; ++str) {
for (; str != end; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
@@ -1243,11 +1324,25 @@ int fonsTextIterNext(struct FONScontext* stash, struct FONStextIter* iter, struc

void fonsDrawDebug(struct FONScontext* stash, float x, float y)
{
int i;
int w = stash->params.width;
int h = stash->params.height;
if (stash->nverts+6 > FONS_VERTEX_COUNT)
float u = w == 0 ? 0 : (1.0f / w);
float v = h == 0 ? 0 : (1.0f / h);

if (stash->nverts+6+6 > FONS_VERTEX_COUNT)
fons__flush(stash);

// Draw background
fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);
fons__vertex(stash, x+w, y+0, u, v, 0x0fffffff);

fons__vertex(stash, x+0, y+0, u, v, 0x0fffffff);
fons__vertex(stash, x+0, y+h, u, v, 0x0fffffff);
fons__vertex(stash, x+w, y+h, u, v, 0x0fffffff);

// Draw texture
fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);
fons__vertex(stash, x+w, y+0, 1, 0, 0xffffffff);
@@ -1255,6 +1350,24 @@ void fonsDrawDebug(struct FONScontext* stash, float x, float y)
fons__vertex(stash, x+0, y+0, 0, 0, 0xffffffff);
fons__vertex(stash, x+0, y+h, 0, 1, 0xffffffff);
fons__vertex(stash, x+w, y+h, 1, 1, 0xffffffff);

// Drawbug draw atlas
for (i = 0; i < stash->atlas->nnodes; i++) {
struct FONSatlasNode* n = &stash->atlas->nodes[i];

if (stash->nverts+6 > FONS_VERTEX_COUNT)
fons__flush(stash);

fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
fons__vertex(stash, x+n->x+n->width, y+n->y+0, u, v, 0xc00000ff);

fons__vertex(stash, x+n->x+0, y+n->y+0, u, v, 0xc00000ff);
fons__vertex(stash, x+n->x+0, y+n->y+1, u, v, 0xc00000ff);
fons__vertex(stash, x+n->x+n->width, y+n->y+1, u, v, 0xc00000ff);
}

fons__flush(stash);
}

float fonsTextBounds(struct FONScontext* stash,
@@ -1289,7 +1402,7 @@ float fonsTextBounds(struct FONScontext* stash,
if (end == NULL)
end = str + strlen(str);

for (; *str; ++str) {
for (; str != end; ++str) {
if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str))
continue;
glyph = fons__getGlyph(stash, font, codepoint, isize, iblur);
@@ -1388,4 +1501,122 @@ void fonsDeleteInternal(struct FONScontext* stash)
free(stash);
}

void fonsSetErrorCallback(struct FONScontext* stash, void (*callback)(void* uptr, int error, int val), void* uptr)
{
if (stash == NULL) return;
stash->handleError = callback;
stash->errorUptr = uptr;
}

void fonsGetAtlasSize(struct FONScontext* stash, int* width, int* height)
{
if (stash == NULL) return;
*width = stash->params.width;
*height = stash->params.height;
}

int fonsExpandAtlas(struct FONScontext* stash, int width, int height)
{
int i, maxy = 0;
unsigned char* data = NULL;
if (stash == NULL) return 0;

width = fons__maxi(width, stash->params.width);
height = fons__maxi(height, stash->params.height);

if (width == stash->params.width && height == stash->params.height)
return 1;

// Flush pending glyphs.
fons__flush(stash);

// Create new texture
if (stash->params.renderResize != NULL) {
if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
return 0;
}
// Copy old texture data over.
data = (unsigned char*)malloc(width * height);
if (data == NULL)
return 0;
for (i = 0; i < stash->params.height; i++) {
unsigned char* dst = &data[i*width];
unsigned char* src = &stash->texData[i*stash->params.width];
memcpy(dst, src, stash->params.width);
if (width > stash->params.width)
memset(dst+stash->params.width, 0, width - stash->params.width);
}
if (height > stash->params.height)
memset(&data[stash->params.height * width], 0, (height - stash->params.height) * width);

free(stash->texData);
stash->texData = data;

// Increase atlas size
fons__atlasExpand(stash->atlas, width, height);

// Add axisting data as dirty.
for (i = 0; i < stash->atlas->nnodes; i++)
maxy = fons__maxi(maxy, stash->atlas->nodes[i].y);
stash->dirtyRect[0] = 0;
stash->dirtyRect[1] = 0;
stash->dirtyRect[2] = stash->params.width;
stash->dirtyRect[3] = maxy;

stash->params.width = width;
stash->params.height = height;
stash->itw = 1.0f/stash->params.width;
stash->ith = 1.0f/stash->params.height;

return 1;
}

int fonsResetAtlas(struct FONScontext* stash, int width, int height)
{
int i, j;
if (stash == NULL) return 0;

// Flush pending glyphs.
fons__flush(stash);

// Create new texture
if (stash->params.renderResize != NULL) {
if (stash->params.renderResize(stash->params.userPtr, width, height) == 0)
return 0;
}

// Reset atlas
fons__atlasReset(stash->atlas, width, height);

// Clear texture data.
stash->texData = (unsigned char*)realloc(stash->texData, width * height);
if (stash->texData == NULL) return 0;
memset(stash->texData, 0, width * height);

// Reset dirty rect
stash->dirtyRect[0] = width;
stash->dirtyRect[1] = height;
stash->dirtyRect[2] = 0;
stash->dirtyRect[3] = 0;

// Reset cached glyphs
for (i = 0; i < stash->nfonts; i++) {
struct FONSfont* font = stash->fonts[i];
font->nglyphs = 0;
for (j = 0; j < FONS_HASH_LUT_SIZE; j++)
font->lut[j] = -1;
}

stash->params.width = width;
stash->params.height = height;
stash->itw = 1.0f/stash->params.width;
stash->ith = 1.0f/stash->params.height;

// Add white rect at 0,0 for debug drawing.
fons__addWhiteRect(stash, 2,2);

return 1;
}


#endif

Loading…
Cancel
Save