diff --git a/example/example.c b/example/example.c index da94d97..5adf371 100644 --- a/example/example.c +++ b/example/example.c @@ -97,11 +97,11 @@ void drawWindow(struct NVGcontext* vg, const char* title, float x, float y, floa nvgFontBlur(vg,2); nvgFillColor(vg, nvgRGBA(0,0,0,128)); - nvgText(vg, x+w/2,y+16+1, title); + nvgText(vg, x+w/2,y+16+1, title, NULL); nvgFontBlur(vg,0); nvgFillColor(vg, nvgRGBA(220,220,220,160)); - nvgText(vg, x+w/2,y+16, title); + nvgText(vg, x+w/2,y+16, title, NULL); nvgRestore(vg); } @@ -128,20 +128,20 @@ void drawSearchBox(struct NVGcontext* vg, const char* text, float x, float y, fl nvgFontFace(vg, "icons"); nvgFillColor(vg, nvgRGBA(255,255,255,64)); nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE); - nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon)); + nvgText(vg, x+h*0.55f, y+h*0.55f, cpToUTF8(ICON_SEARCH,icon), NULL); nvgFontSize(vg, 20.0f); nvgFontFace(vg, "sans"); nvgFillColor(vg, nvgRGBA(255,255,255,32)); nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - nvgText(vg, x+h*1.05f,y+h*0.5f,text); + nvgText(vg, x+h*1.05f,y+h*0.5f,text, NULL); nvgFontSize(vg, h*1.3f); nvgFontFace(vg, "icons"); nvgFillColor(vg, nvgRGBA(255,255,255,32)); nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE); - nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon)); + nvgText(vg, x+w-h*0.55f, y+h*0.55f, cpToUTF8(ICON_CIRCLED_CROSS,icon), NULL); } void drawDropDown(struct NVGcontext* vg, const char* text, float x, float y, float w, float h) @@ -165,13 +165,13 @@ void drawDropDown(struct NVGcontext* vg, const char* text, float x, float y, flo nvgFontFace(vg, "sans"); nvgFillColor(vg, nvgRGBA(255,255,255,160)); nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - nvgText(vg, x+h*0.3f,y+h*0.5f,text); + nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL); nvgFontSize(vg, h*1.3f); nvgFontFace(vg, "icons"); nvgFillColor(vg, nvgRGBA(255,255,255,64)); nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE); - nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon)); + nvgText(vg, x+w-h*0.5f, y+h*0.5f, cpToUTF8(ICON_CHEVRON_RIGHT,icon), NULL); } void drawLabel(struct NVGcontext* vg, const char* text, float x, float y, float w, float h) @@ -181,7 +181,7 @@ void drawLabel(struct NVGcontext* vg, const char* text, float x, float y, float nvgFillColor(vg, nvgRGBA(255,255,255,128)); nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - nvgText(vg, x,y+h*0.5f,text); + nvgText(vg, x,y+h*0.5f,text, NULL); } void drawEditBoxBase(struct NVGcontext* vg, float x, float y, float w, float h) @@ -209,7 +209,7 @@ void drawEditBox(struct NVGcontext* vg, const char* text, float x, float y, floa nvgFontFace(vg, "sans"); nvgFillColor(vg, nvgRGBA(255,255,255,64)); nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - nvgText(vg, x+h*0.3f,y+h*0.5f,text); + nvgText(vg, x+h*0.3f,y+h*0.5f,text, NULL); } void drawEditBoxNum(struct NVGcontext* vg, @@ -219,19 +219,19 @@ void drawEditBoxNum(struct NVGcontext* vg, drawEditBoxBase(vg, x,y, w,h); - nvgTextBounds(vg, units, &uw, NULL); + uw = nvgTextBounds(vg, units, NULL, NULL); nvgFontSize(vg, 18.0f); nvgFontFace(vg, "sans"); nvgFillColor(vg, nvgRGBA(255,255,255,64)); nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE); - nvgText(vg, x+w-h*0.3f,y+h*0.5f,units); + nvgText(vg, x+w-h*0.3f,y+h*0.5f,units, NULL); nvgFontSize(vg, 20.0f); nvgFontFace(vg, "sans"); nvgFillColor(vg, nvgRGBA(255,255,255,128)); nvgTextAlign(vg,NVG_ALIGN_RIGHT|NVG_ALIGN_MIDDLE); - nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text); + nvgText(vg, x+w-uw-h*0.5f,y+h*0.5f,text, NULL); } void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, float w, float h) @@ -244,7 +244,7 @@ void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, flo nvgFillColor(vg, nvgRGBA(255,255,255,160)); nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - nvgText(vg, x+28,y+h*0.5f,text); + nvgText(vg, x+28,y+h*0.5f,text, NULL); bg = nvgBoxGradient(vg, x+1,y+(int)(h*0.5f)-9+1, 18,18, 3,3, nvgRGBA(0,0,0,32), nvgRGBA(0,0,0,92)); nvgBeginPath(vg); @@ -256,7 +256,7 @@ void drawCheckBox(struct NVGcontext* vg, const char* text, float x, float y, flo nvgFontFace(vg, "icons"); nvgFillColor(vg, nvgRGBA(255,255,255,128)); nvgTextAlign(vg,NVG_ALIGN_CENTER|NVG_ALIGN_MIDDLE); - nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon)); + nvgText(vg, x+9+2, y+h*0.5f, cpToUTF8(ICON_CHECK,icon), NULL); } void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, float y, float w, float h, unsigned int col) @@ -283,11 +283,11 @@ void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, f nvgFontSize(vg, 20.0f); nvgFontFace(vg, "sans-bold"); - nvgTextBounds(vg, text, &tw, NULL); + tw = nvgTextBounds(vg, text, NULL, NULL); if (preicon != 0) { nvgFontSize(vg, h*1.3f); nvgFontFace(vg, "icons"); - nvgTextBounds(vg, cpToUTF8(preicon,icon), &iw, NULL); + iw = nvgTextBounds(vg, cpToUTF8(preicon,icon), NULL, NULL); iw += h*0.15f; } @@ -296,16 +296,16 @@ void drawButton(struct NVGcontext* vg, int preicon, const char* text, float x, f nvgFontFace(vg, "icons"); nvgFillColor(vg, nvgRGBA(255,255,255,96)); nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon)); + nvgText(vg, x+w*0.5f-tw*0.5f-iw*0.75f, y+h*0.5f, cpToUTF8(preicon,icon), NULL); } nvgFontSize(vg, 20.0f); nvgFontFace(vg, "sans-bold"); nvgTextAlign(vg,NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); nvgFillColor(vg, nvgRGBA(0,0,0,160)); - nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text); + nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f-1,text, NULL); nvgFillColor(vg, nvgRGBA(255,255,255,160)); - nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text); + nvgText(vg, x+w*0.5f-tw*0.5f+iw*0.25f,y+h*0.5f,text, NULL); } void drawSlider(struct NVGcontext* vg, float pos, float x, float y, float w, float h) diff --git a/src/fontstash.h b/src/fontstash.h index 0979001..1f1e6a7 100644 --- a/src/fontstash.h +++ b/src/fontstash.h @@ -26,7 +26,7 @@ enum FONSflags { FONS_ZERO_BOTTOMLEFT = 2, }; -enum FONSaling { +enum FONSalign { // Horizontal align FONS_ALIGN_LEFT = 1<<0, // Default FONS_ALIGN_CENTER = 1<<1, @@ -60,12 +60,13 @@ struct FONStextIter { struct FONSfont* font; struct FONSglyph* prevGlyph; const char* str; + const char* end; unsigned int utf8state; }; // Contructor and destructor. -struct FONScontext* fonsCreate(struct FONSparams* params); -void fonsDelete(struct FONScontext* s); +struct FONScontext* fonsCreateInternal(struct FONSparams* params); +void fonsDeleteInternal(struct FONScontext* s); // Add fonts int fonsAddFont(struct FONScontext* s, const char* name, const char* path); @@ -86,17 +87,17 @@ void fonsSetAlign(struct FONScontext* s, int align); void fonsSetFont(struct FONScontext* s, int font); // Draw text -void fonsDrawText(struct FONScontext* s, float x, float y, const char* string, float* dx); +float fonsDrawText(struct FONScontext* s, float x, float y, const char* string, const char* end); // Measure text -void fonsTextBounds(struct FONScontext* s, const char* string, float* width, float* bounds); +float fonsTextBounds(struct FONScontext* s, const char* string, const char* end, float* bounds); void fonsVertMetrics(struct FONScontext* s, float* ascender, float* descender, float* lineh); // Text iterator -int fonsTextIterInit(struct FONScontext* stash, struct FONStextIter* iter, float x, float y, const char* s); +int fonsTextIterInit(struct FONScontext* stash, struct FONStextIter* iter, float x, float y, const char* str, const char* end); int fonsTextIterNext(struct FONScontext* stash, struct FONStextIter* iter, struct FONSquad* quad); -// Pull texture data +// Pull texture changes const unsigned char* fonsGetTextureData(struct FONScontext* stash, int* width, int* height); int fonsValidateTexture(struct FONScontext* s, int* dirty); @@ -158,11 +159,6 @@ static int fons__maxi(int a, int b) return a > b ? a : b; } -struct FONSrow -{ - short x,y,h; -}; - struct FONSglyph { unsigned int codepoint; @@ -199,16 +195,27 @@ struct FONSstate float spacing; }; +struct FONSrow +{ + short x,y,h; +}; + +struct FONSatlas +{ + int width, height; + struct FONSrow* rows; + int crows; + int nrows; +}; + struct FONScontext { struct FONSparams params; float itw,ith; unsigned char* texData; int dirtyRect[4]; - struct FONSrow* rows; - int crows; - int nrows; struct FONSfont** fonts; + struct FONSatlas* atlas; int cfonts; int nfonts; float verts[FONS_VERTEX_COUNT*2]; @@ -223,10 +230,12 @@ struct FONScontext 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) return NULL; - unsigned char* ptr = stash->scratch + stash->nscratch; + ptr = stash->scratch + stash->nscratch; stash->nscratch += (int)size; return ptr; } @@ -275,7 +284,102 @@ static unsigned int fons__decutf8(unsigned int* state, unsigned int* codep, unsi return *state; } -struct FONScontext* fonsCreate(struct FONSparams* params) +static void fons__deleteAtlas(struct FONSatlas* atlas) +{ + if (atlas == NULL) return; + if (atlas->rows != NULL) free(atlas->rows); + free(atlas); +} + +static struct FONSatlas* fons__allocAtlas(int w, int h, int rows) +{ + struct FONSatlas* atlas = NULL; + + // Allocate memory for the font stash. + atlas = (struct FONSatlas*)malloc(sizeof(struct FONSatlas)); + if (atlas == NULL) goto error; + memset(atlas, 0, sizeof(struct FONSatlas)); + + atlas->width = w; + atlas->height = h; + + // Allocate space for rows + atlas->rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * rows); + if (atlas->rows == NULL) goto error; + memset(atlas->rows, 0, sizeof(struct FONSrow) * rows); + atlas->crows = rows; + atlas->nrows = 0; + + return atlas; + +error: + if (atlas) fons__deleteAtlas(atlas); + return NULL; +} + +static struct FONSrow* fons__atlasAllocRow(struct FONSatlas* atlas) +{ + struct FONSrow* rows = NULL; + if (atlas->nrows+1 > atlas->crows) { + atlas->crows *= 2; + rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * atlas->crows); + if (rows == NULL) return NULL; + memset(rows, 0, sizeof(struct FONSrow) * atlas->crows); + if (atlas->nrows > 0) + memcpy(rows, atlas->rows, sizeof(struct FONSrow) * atlas->nrows); + free(atlas->rows); + atlas->rows = rows; + } + atlas->nrows++; + return &atlas->rows[atlas->nrows-1]; +} + +static int fons__atlasAddRect(struct FONSatlas* atlas, int rw, int rh, int* rx, int* ry) +{ + int i, py; + struct FONSrow* br = NULL; + + // Round row height + rh = (rh+7) & ~7;; + + // Find row where the glyph can be fit. + for (i = 0; i < atlas->nrows; ++i) { + int rmax = atlas->rows[i].h, rmin = rmax - rmax/4; + if (rh >= rmin && rh <= rmax && (atlas->rows[i].x+rw+1) <= atlas->width) { + br = &atlas->rows[i]; + break; + } + } + + // If no row found, add new. + if (br == NULL) { + py = 0; + // Check that there is enough space. + if (atlas->nrows > 0) { + py = atlas->rows[atlas->nrows-1].y + atlas->rows[atlas->nrows-1].h+1; + if (py+rh > atlas->height) + return 0; + } + // Init and add row + br = fons__atlasAllocRow(atlas); + if (br == NULL) + return 0; + br->x = 0; + br->y = py; + br->h = rh; + } + + *rx = br->x; + *ry = br->y; + + // Advance row location. + br->x += rw+1; + + return 1; +} + + +struct FONScontext* fonsCreateInternal(struct FONSparams* params) { struct FONScontext* stash = NULL; @@ -286,15 +390,13 @@ struct FONScontext* fonsCreate(struct FONSparams* params) stash->params = *params; - if (stash->params.renderCreate != NULL) - if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0) goto error; + if (stash->params.renderCreate != NULL) { + if (stash->params.renderCreate(stash->params.userPtr, stash->params.width, stash->params.height) == 0) + goto error; + } - // Allocate space for rows - stash->rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * FONS_INIT_ROWS); - if (stash->rows == NULL) goto error; - memset(stash->rows, 0, sizeof(struct FONSrow) * FONS_INIT_ROWS); - stash->crows = FONS_INIT_ROWS; - stash->nrows = 0; + stash->atlas = fons__allocAtlas(stash->params.width, stash->params.height, FONS_INIT_ROWS); + if (stash->atlas == NULL) goto error; // Allocate space for fonts. stash->fonts = (struct FONSfont**)malloc(sizeof(struct FONSfont*) * FONS_INIT_FONTS); @@ -321,7 +423,7 @@ struct FONScontext* fonsCreate(struct FONSparams* params) return stash; error: - fonsDelete(stash); + fonsDeleteInternal(stash); return NULL; } @@ -387,34 +489,6 @@ void fonsClearState(struct FONScontext* stash) state->align = FONS_ALIGN_LEFT | FONS_ALIGN_BASELINE; } - - -int fonsAddFont(struct FONScontext* stash, const char* name, const char* path) -{ - FILE* fp = 0; - int dataSize = 0; - unsigned char* data = NULL; - - // Read in the font data. - fp = fopen(path, "rb"); - if (!fp) goto error; - fseek(fp,0,SEEK_END); - dataSize = (int)ftell(fp); - fseek(fp,0,SEEK_SET); - data = (unsigned char*)malloc(dataSize); - if (data == NULL) goto error; - fread(data, 1, dataSize, fp); - fclose(fp); - fp = 0; - - return fonsAddFontMem(stash, name, data, dataSize, 1); - -error: - if (data) free(data); - if (fp) fclose(fp); - return 0; -} - static void fons__freeFont(struct FONSfont* font) { if (font == NULL) return; @@ -456,6 +530,32 @@ error: return FONS_INVALID; } +int fonsAddFont(struct FONScontext* stash, const char* name, const char* path) +{ + FILE* fp = 0; + int dataSize = 0; + unsigned char* data = NULL; + + // Read in the font data. + fp = fopen(path, "rb"); + if (!fp) goto error; + fseek(fp,0,SEEK_END); + dataSize = (int)ftell(fp); + fseek(fp,0,SEEK_SET); + data = (unsigned char*)malloc(dataSize); + if (data == NULL) goto error; + fread(data, 1, dataSize, fp); + fclose(fp); + fp = 0; + + return fonsAddFontMem(stash, name, data, dataSize, 1); + +error: + if (data) free(data); + if (fp) fclose(fp); + return 0; +} + int fonsAddFontMem(struct FONScontext* stash, const char* name, unsigned char* data, int dataSize, int freeData) { int i, ascent, descent, fh, lineGap; @@ -510,48 +610,6 @@ int fonsGetFontByName(struct FONScontext* s, const char* name) return FONS_INVALID; } -const unsigned char* fonsGetTextureData(struct FONScontext* stash, int* width, int* height) -{ - if (width != NULL) - *width = stash->params.width; - if (height != NULL) - *height = stash->params.height; - return stash->texData; -} - -int fonsValidateTexture(struct FONScontext* stash, int* dirty) -{ - if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) { - dirty[0] = stash->dirtyRect[0]; - dirty[1] = stash->dirtyRect[1]; - dirty[2] = stash->dirtyRect[2]; - dirty[3] = stash->dirtyRect[3]; - // Reset dirty rect - stash->dirtyRect[0] = stash->params.width; - stash->dirtyRect[1] = stash->params.height; - stash->dirtyRect[2] = 0; - stash->dirtyRect[3] = 0; - return 1; - } - return 0; -} - -static struct FONSrow* fons__allocRow(struct FONScontext* stash) -{ - struct FONSrow* rows = NULL; - if (stash->nrows+1 > stash->crows) { - stash->crows *= 2; - rows = (struct FONSrow*)malloc(sizeof(struct FONSrow) * stash->crows); - if (rows == NULL) return NULL; - memset(rows, 0, sizeof(struct FONSrow) * stash->crows); - if (stash->nrows > 0) - memcpy(rows, stash->rows, sizeof(struct FONSrow) * stash->nrows); - free(stash->rows); - stash->rows = rows; - } - stash->nrows++; - return &stash->rows[stash->nrows-1]; -} static struct FONSglyph* fons__allocGlyph(struct FONSfont* font) { @@ -570,98 +628,81 @@ static struct FONSglyph* fons__allocGlyph(struct FONSfont* font) return &font->glyphs[font->nglyphs-1]; } -static int fons__clamp(int a, int amin, int amax) { return a < amin ? amin : (a > amax ? amax : a); } -static void fons__hblur(unsigned char* dst, int dstStride, unsigned char* src, int srcStride, - int w, int h, int blur, unsigned short* idx) -{ - int x,y,acc; - int d = 1 + 2*blur; - int w1 = w-1; - idx += blur; +// Based on Exponential blur, Jani Huhtanen, 2006 - for (x = -blur; x <= w+blur; x++) { - idx[x] = fons__clamp(x,0,w1); - } +#define APREC 16 +#define ZPREC 7 - for (y = 0; y < h; y++) { - // warm up accumulator - acc = 0; - for (x = -blur; x < blur; x++) - acc += src[idx[x]]; - for (x = 0; x < w; x++) { - acc += src[idx[x+blur]]; - dst[x] = (unsigned char)(acc / d); - acc -= src[idx[x-blur]]; +static void fons__blurCols(unsigned char* dst, int w, int h, int dstStride, int alpha) +{ + int x, y; + for (y = 0; y < h; y++) { + int z = 0; // force zero border + for (x = 1; x < w; x++) { + z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC; + dst[x] = (unsigned char)(z >> ZPREC); + } + dst[w-1] = 0; // force zero border + z = 0; + for (x = w-2; x >= 0; x--) { + z += (alpha * (((int)(dst[x]) << ZPREC) - z)) >> APREC; + dst[x] = (unsigned char)(z >> ZPREC); } - src += srcStride; + dst[0] = 0; // force zero border dst += dstStride; } - } -static void fons__vblur(unsigned char* dst, int dstStride, unsigned char* src, int srcStride, - int w, int h, int blur, unsigned short* idx) +static void fons__blurRows(unsigned char* dst, int w, int h, int dstStride, int alpha) { - int x,y,acc; - int d = 1 + 2*blur; - int h1 = h-1; - idx += blur; - - for (y = -blur; y <= h+blur; y++) - idx[y] = fons__clamp(y,0,h1) * srcStride; - - for (x = 0; x < w; x++) { - // warm up accumulator - acc = 0; - for (y = -blur; y < blur; y++) - acc += src[idx[y]]; - for (y = 0; y < h; y++) { - acc += src[idx[y+blur]]; - dst[y*dstStride] = (unsigned char)(acc / d); - acc -= src[idx[y-blur]]; + int x, y; + for (x = 0; x < w; x++) { + int z = 0; // force zero border + for (y = dstStride; y < h*dstStride; y += dstStride) { + z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC; + dst[y] = (unsigned char)(z >> ZPREC); + } + dst[(h-1)*dstStride] = 0; // force zero border + z = 0; + for (y = (h-2)*dstStride; y >= 0; y -= dstStride) { + z += (alpha * (((int)(dst[y]) << ZPREC) - z)) >> APREC; + dst[y] = (unsigned char)(z >> ZPREC); } - src++; + dst[0] = 0; // force zero border dst++; } } + static void fons__blur(struct FONScontext* stash, unsigned char* dst, int w, int h, int dstStride, int blur) { - // It is possible that our scratch is too small for blurring (16k scratch can handle about 120x120 blur). - int bufStride = w; - unsigned short* idx; - unsigned char* buf; - buf = (unsigned char*)fons__tmpalloc(w*h, stash); - if (buf == NULL) { - return; - } - idx = (unsigned short*)fons__tmpalloc((1+2*blur+fons__maxi(w,h))*sizeof(unsigned short), stash); - if (idx == NULL) { - return; - } + int alpha; + float sigma; - // Tent. - int b1 = (blur+1)/2, b2 = blur-b1; - fons__hblur(buf,bufStride, dst,dstStride, w,h, b1, idx); - fons__vblur(dst,dstStride, buf,bufStride, w,h, b1, idx); - if (b2 > 0) { - fons__hblur(buf,bufStride, dst,dstStride, w,h, b2, idx); - fons__vblur(dst,dstStride, buf,bufStride, w,h, b2, idx); - } + if (blur < 1) + return; + // Calculate the alpha such that 90% of the kernel is within the radius. (Kernel extends to infinity) + sigma = (float)blur * 0.57735f; // 1 / sqrt(3) + alpha = (int)((1<nrows; ++i) { - int rmax = stash->rows[i].h, rmin = rmax - rmax/4; - if (rh >= rmin && rh <= rmax && (stash->rows[i].x+gw) <= stash->params.width) { - br = &stash->rows[i]; - break; - } - } - - // If no row found, add new. - if (br == NULL) { - short py = 0; - // Check that there is enough space. - if (stash->nrows > 0) { - py = stash->rows[stash->nrows-1].y + stash->rows[stash->nrows-1].h; - if (py+rh > stash->params.height) - return NULL; - } - // Init and add row - br = fons__allocRow(stash); - if (br == NULL) - return NULL; - br->x = 0; - br->y = py; - br->h = rh; - } + // Find free spot for the rect in the atlas + if (fons__atlasAddRect(stash->atlas, gw, gh, &gx, &gy) == 0) + return NULL; // Init glyph. glyph = fons__allocGlyph(font); @@ -723,8 +739,8 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo glyph->size = isize; glyph->blur = iblur; glyph->index = g; - glyph->x0 = br->x; - glyph->y0 = br->y; + glyph->x0 = gx; + glyph->y0 = gy; glyph->x1 = glyph->x0+gw; glyph->y1 = glyph->y0+gh; glyph->xadv = (short)(scale * advance * 10.0f); @@ -732,9 +748,6 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo glyph->yoff = y0 - pad; glyph->next = 0; - // Advance row location. - br->x += gw+1; - // Insert char to hash lookup. glyph->next = font->lut[h]; font->lut[h] = font->nglyphs-1; @@ -754,27 +767,30 @@ static struct FONSglyph* fons__getGlyph(struct FONScontext* stash, struct FONSfo dst[x + (gh-1)*stash->params.width] = 0; } + /* // Debug code to color the glyph background -/* dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; + int x,y; + unsigned char* fdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; for (y = 0; y < gh; y++) { for (x = 0; x < gw; x++) { - int a = (int)dst[x+y*stash->params.width] + 20; + int a = (int)fdst[x+y*stash->params.width] + 20; if (a > 255) a = 255; - dst[x+y*stash->params.width] = a; + fdst[x+y*stash->params.width] = a; } - }*/ + } + */ // Blur if (iblur > 0) { stash->nscratch = 0; - dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; - fons__blur(stash, dst, gw,gh, stash->params.width, iblur); + bdst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; + fons__blur(stash, bdst, gw,gh, stash->params.width, iblur); } - stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], fons__maxi(0, glyph->x0-1)); - stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], fons__maxi(0, glyph->y0-1)); - stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], fons__mini(glyph->x1+1, stash->params.width)); - stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], fons__mini(glyph->y1+1, stash->params.height)); + stash->dirtyRect[0] = fons__mini(stash->dirtyRect[0], glyph->x0); + stash->dirtyRect[1] = fons__mini(stash->dirtyRect[1], glyph->y0); + stash->dirtyRect[2] = fons__maxi(stash->dirtyRect[2], glyph->x1); + stash->dirtyRect[3] = fons__maxi(stash->dirtyRect[3], glyph->y1); return glyph; } @@ -784,9 +800,10 @@ static void fons__getQuad(struct FONScontext* stash, struct FONSfont* font, float scale, float spacing, float* x, float* y, struct FONSquad* q) { int rx,ry,xoff,yoff,x0,y0,x1,y1; + if (prevGlyph) { float adv = stbtt_GetGlyphKernAdvance(&font->font, prevGlyph->index, glyph->index) * scale; - *x += (int)(adv+0.5f); + *x += adv; } // Each glyph has 2px border to allow good interpolation, @@ -851,7 +868,7 @@ static void fons__flush(struct FONScontext* stash) } } -static inline void fons__vertex(struct FONScontext* stash, float x, float y, float s, float t, unsigned int c) +static __inline void fons__vertex(struct FONScontext* stash, float x, float y, float s, float t, unsigned int c) { stash->verts[stash->nverts*2+0] = x; stash->verts[stash->nverts*2+1] = y; @@ -887,9 +904,9 @@ static float fons__getVertAlign(struct FONScontext* stash, struct FONSfont* font return 0.0; } -void fonsDrawText(struct FONScontext* stash, - float x, float y, - const char* s, float* dx) +float fonsDrawText(struct FONScontext* stash, + float x, float y, + const char* str, const char* end) { struct FONSstate* state = fons__getState(stash); unsigned int codepoint; @@ -901,33 +918,36 @@ void fonsDrawText(struct FONScontext* stash, short iblur = (short)state->blur; float scale; struct FONSfont* font; + float width; - if (stash == NULL) return; - if (state->font < 0 || state->font >= stash->nfonts) return; + if (stash == NULL) return x; + if (state->font < 0 || state->font >= stash->nfonts) return x; font = stash->fonts[state->font]; - if (!font->data) return; + if (!font->data) return x; scale = stbtt_ScaleForPixelHeight(&font->font, (float)isize/10.0f); - float width; // Align horizontally if (state->align & FONS_ALIGN_LEFT) { // empty } else if (state->align & FONS_ALIGN_RIGHT) { - fonsTextBounds(stash, s, &width, NULL); + width = fonsTextBounds(stash, str, end, NULL); x -= width; } else if (state->align & FONS_ALIGN_CENTER) { - fonsTextBounds(stash, s, &width, NULL); + width = fonsTextBounds(stash, str, end, NULL); x -= width * 0.5f; } // Align vertically. y += fons__getVertAlign(stash, font, state->align, isize); - for (; *s; ++s) { - if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)s)) + if (end == NULL) + end = str + strlen(str); + + for (; *str; ++str) { + if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) continue; glyph = fons__getGlyph(stash, font, codepoint, isize, iblur); - if (glyph != NULL) { + if (glyph) { fons__getQuad(stash, font, prevGlyph, glyph, scale, state->spacing, &x, &y, &q); if (stash->nverts+6 > FONS_VERTEX_COUNT) @@ -944,11 +964,12 @@ void fonsDrawText(struct FONScontext* stash, prevGlyph = glyph; } fons__flush(stash); - if (dx) *dx = x; + + return x; } int fonsTextIterInit(struct FONScontext* stash, struct FONStextIter* iter, - float x, float y, const char* s) + float x, float y, const char* str, const char* end) { struct FONSstate* state = fons__getState(stash); float width; @@ -968,19 +989,23 @@ int fonsTextIterInit(struct FONScontext* stash, struct FONStextIter* iter, if (state->align & FONS_ALIGN_LEFT) { // empty } else if (state->align & FONS_ALIGN_RIGHT) { - fonsTextBounds(stash, s, &width, NULL); + width = fonsTextBounds(stash, str, end, NULL); x -= width; } else if (state->align & FONS_ALIGN_CENTER) { - fonsTextBounds(stash, s, &width, NULL); + width = fonsTextBounds(stash, str, end, NULL); x -= width * 0.5f; } // Align vertically. y += fons__getVertAlign(stash, iter->font, state->align, iter->isize); + if (end == NULL) + end = str + strlen(str); + iter->x = x; iter->y = y; iter->spacing = state->spacing; - iter->str = s; + iter->str = str; + iter->end = end; return 1; } @@ -989,18 +1014,15 @@ int fonsTextIterNext(struct FONScontext* stash, struct FONStextIter* iter, struc { struct FONSglyph* glyph = NULL; unsigned int codepoint = 0; - const char* s = iter->str; + const char* str = iter->str; - if (*s == '\0') + if (*str == '\0') return 0; - for (; *s; s++) { - if (fons__decutf8(&iter->utf8state, &codepoint, *(const unsigned char*)s)) + for (; str != iter->end; str++) { + if (fons__decutf8(&iter->utf8state, &codepoint, *(const unsigned char*)str)) continue; - s++; - -// printf("%c", codepoint); - + str++; // Get glyph and quad glyph = fons__getGlyph(stash, iter->font, codepoint, iter->isize, iter->iblur); if (glyph != NULL) @@ -1008,7 +1030,7 @@ int fonsTextIterNext(struct FONScontext* stash, struct FONStextIter* iter, struc iter->prevGlyph = glyph; break; } - iter->str = s; + iter->str = str; return 1; } @@ -1027,13 +1049,11 @@ 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); - - fons__flush(stash); } -void fonsTextBounds(struct FONScontext* stash, - const char* s, - float* width, float* bounds) +float fonsTextBounds(struct FONScontext* stash, + const char* str, const char* end, + float* bounds) { struct FONSstate* state = fons__getState(stash); unsigned int codepoint; @@ -1047,10 +1067,10 @@ void fonsTextBounds(struct FONScontext* stash, struct FONSfont* font; float x = 0, y = 0, minx, miny, maxx, maxy; - if (stash == NULL) return; - if (state->font < 0 || state->font >= stash->nfonts) return; + if (stash == NULL) return 0; + if (state->font < 0 || state->font >= stash->nfonts) return 0; font = stash->fonts[state->font]; - if (!font->data) return; + if (!font->data) return 0; scale = stbtt_ScaleForPixelHeight(&font->font, (float)isize/10.0f); @@ -1060,12 +1080,15 @@ void fonsTextBounds(struct FONScontext* stash, minx = maxx = x; miny = maxy = y; - for (; *s; ++s) { - if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)s)) + if (end == NULL) + end = str + strlen(str); + + for (; *str; ++str) { + if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) continue; glyph = fons__getGlyph(stash, font, codepoint, isize, iblur); if (glyph) { - fons__getQuad(stash, font, prevGlyph, glyph, scale, state->spacing, &x, &y, &q); + fons__getQuad(stash, font, prevGlyph, glyph, state->spacing, scale, &x, &y, &q); if (q.x0 < minx) minx = q.x0; if (q.x1 > maxx) maxx = q.x1; if (q.y1 < miny) miny = q.y1; @@ -1073,9 +1096,6 @@ void fonsTextBounds(struct FONScontext* stash, } prevGlyph = glyph; } - if (width) { - *width = x; - } // Align horizontally if (state->align & FONS_ALIGN_LEFT) { @@ -1094,16 +1114,21 @@ void fonsTextBounds(struct FONScontext* stash, bounds[2] = maxx; bounds[3] = maxy; } + + return x; } void fonsVertMetrics(struct FONScontext* stash, float* ascender, float* descender, float* lineh) { + struct FONSfont* font; struct FONSstate* state = fons__getState(stash); + short isize; + if (stash == NULL) return; if (state->font < 0 || state->font >= stash->nfonts) return; - struct FONSfont* font = stash->fonts[state->font]; - short isize = (short)(state->size*10.0f); + font = stash->fonts[state->font]; + isize = (short)(state->size*10.0f); if (!font->data) return; if (ascender) @@ -1114,19 +1139,45 @@ void fonsVertMetrics(struct FONScontext* stash, *lineh = font->lineh*isize/10.0f; } -void fonsDelete(struct FONScontext* stash) +const unsigned char* fonsGetTextureData(struct FONScontext* stash, int* width, int* height) +{ + if (width != NULL) + *width = stash->params.width; + if (height != NULL) + *height = stash->params.height; + return stash->texData; +} + +int fonsValidateTexture(struct FONScontext* stash, int* dirty) +{ + if (stash->dirtyRect[0] < stash->dirtyRect[2] && stash->dirtyRect[1] < stash->dirtyRect[3]) { + dirty[0] = stash->dirtyRect[0]; + dirty[1] = stash->dirtyRect[1]; + dirty[2] = stash->dirtyRect[2]; + dirty[3] = stash->dirtyRect[3]; + // Reset dirty rect + stash->dirtyRect[0] = stash->params.width; + stash->dirtyRect[1] = stash->params.height; + stash->dirtyRect[2] = 0; + stash->dirtyRect[3] = 0; + return 1; + } + return 0; +} + +void fonsDeleteInternal(struct FONScontext* stash) { int i; if (stash == NULL) return; - if (stash->params.renderDelete != NULL) + if (stash->params.renderDelete) stash->params.renderDelete(stash->params.userPtr); for (i = 0; i < stash->nfonts; ++i) fons__freeFont(stash->fonts[i]); + if (stash->atlas) fons__deleteAtlas(stash->atlas); if (stash->fonts) free(stash->fonts); - if (stash->rows) free(stash->rows); if (stash->texData) free(stash->texData); free(stash); } diff --git a/src/glnanovg.h b/src/glnanovg.h index 7d7e63e..6015f73 100644 --- a/src/glnanovg.h +++ b/src/glnanovg.h @@ -195,6 +195,20 @@ static void glnvg__deleteShader(struct GLNVGshader* shader) glDeleteShader(shader->frag); } +static void glnvg__getUniforms(struct GLNVGshader* shader) +{ + shader->loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(shader->prog, "scissorMat"); + shader->loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(shader->prog, "scissorExt"); + shader->loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(shader->prog, "paintMat"); + shader->loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(shader->prog, "extent"); + shader->loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(shader->prog, "radius"); + shader->loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(shader->prog, "feather"); + shader->loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(shader->prog, "innerCol"); + shader->loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(shader->prog, "outerCol"); + shader->loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(shader->prog, "strokeMult"); + shader->loc[GLNVG_LOC_TEX] = glGetUniformLocation(shader->prog, "tex"); +} + static int glnvg__renderCreate(void* uptr) { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; @@ -273,38 +287,14 @@ static int glnvg__renderCreate(void* uptr) if (glnvg__createShader(&gl->gradShader, "grad", fillVertShader, fillFragGradShader) == 0) return 0; - - glnvg__checkError("grad"); - - gl->gradShader.loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(gl->gradShader.prog, "scissorMat"); - gl->gradShader.loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(gl->gradShader.prog, "scissorExt"); - gl->gradShader.loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(gl->gradShader.prog, "paintMat"); - gl->gradShader.loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(gl->gradShader.prog, "extent"); - gl->gradShader.loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(gl->gradShader.prog, "radius"); - gl->gradShader.loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(gl->gradShader.prog, "feather"); - gl->gradShader.loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(gl->gradShader.prog, "innerCol"); - gl->gradShader.loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(gl->gradShader.prog, "outerCol"); - gl->gradShader.loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(gl->gradShader.prog, "strokeMult"); - - glnvg__checkError("grad loc"); - if (glnvg__createShader(&gl->imgShader, "image", fillVertShader, fillFragImgShader) == 0) return 0; - glnvg__checkError("image"); + glnvg__checkError("uniform locations"); + glnvg__getUniforms(&gl->gradShader); + glnvg__getUniforms(&gl->imgShader); - gl->imgShader.loc[GLNVG_LOC_SCISSORMAT] = glGetUniformLocation(gl->imgShader.prog, "scissorMat"); - gl->imgShader.loc[GLNVG_LOC_SCISSOREXT] = glGetUniformLocation(gl->imgShader.prog, "scissorExt"); - gl->imgShader.loc[GLNVG_LOC_PAINTMAT] = glGetUniformLocation(gl->imgShader.prog, "paintMat"); - gl->imgShader.loc[GLNVG_LOC_EXTENT] = glGetUniformLocation(gl->imgShader.prog, "extent"); -// gl->gradShader.loc[GLNVG_LOC_RADIUS] = glGetUniformLocation(gl->gradShader.prog, "radius"); -// gl->gradShader.loc[GLNVG_LOC_FEATHER] = glGetUniformLocation(gl->gradShader.prog, "feather"); -// gl->gradShader.loc[GLNVG_LOC_INNERCOL] = glGetUniformLocation(gl->gradShader.prog, "innerCol"); -// gl->gradShader.loc[GLNVG_LOC_OUTERCOL] = glGetUniformLocation(gl->gradShader.prog, "outerCol"); - gl->imgShader.loc[GLNVG_LOC_STROKEMULT] = glGetUniformLocation(gl->imgShader.prog, "strokeMult"); - gl->imgShader.loc[GLNVG_LOC_TEX] = glGetUniformLocation(gl->imgShader.prog, "tex"); - - glnvg__checkError("image loc"); + glnvg__checkError("done"); return 1; } @@ -453,14 +443,10 @@ static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, st glUniform2f(gl->imgShader.loc[GLNVG_LOC_EXTENT], paint->extent[0], paint->extent[1]); glUniform1f(gl->imgShader.loc[GLNVG_LOC_STROKEMULT], width*0.5f + aasize*0.5f); glUniform1i(gl->imgShader.loc[GLNVG_LOC_TEX], 0); - - glnvg__checkError("tex paint loc"); - + glnvg__checkError("tex paint loc"); glBindTexture(GL_TEXTURE_2D, tex->tex); glEnable(GL_TEXTURE_2D); - - glnvg__checkError("tex paint tex"); - + glnvg__checkError("tex paint tex"); } else { glUseProgram(gl->gradShader.prog); glUniformMatrix3fv(gl->gradShader.loc[GLNVG_LOC_SCISSORMAT], 1, GL_FALSE, scissorMat); @@ -472,8 +458,7 @@ static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, st glUniform4fv(gl->gradShader.loc[GLNVG_LOC_INNERCOL], 1, innerCol); glUniform4fv(gl->gradShader.loc[GLNVG_LOC_OUTERCOL], 1, outerCol); glUniform1f(gl->gradShader.loc[GLNVG_LOC_STROKEMULT], width*0.5f + aasize*0.5f); - - glnvg__checkError("grad paint loc"); + glnvg__checkError("grad paint loc"); } return 1; } @@ -555,9 +540,6 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); -// glUseProgram(0); -// glColor4ub(255,0,0,128); - glBegin(GL_QUADS); glTexCoord2f(0.5f,1.0f); glVertex2f(bounds[0], bounds[3]); diff --git a/src/nanovg.c b/src/nanovg.c index 3ed85b9..139b938 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -109,6 +109,14 @@ struct NVGcontext { int textTriCount; }; +static float nvg__sqrtf(float a) { return sqrtf(a); } +static float nvg__modf(float a, float b) { return fmodf(a, b); } +static float nvg__sinf(float a) { return sinf(a); } +static float nvg__cosf(float a) { return cosf(a); } +static float nvg__tanf(float a) { return tanf(a); } +static float nvg__atan2f(float a,float b) { return atan2f(a, b); } +static float nvg__acosf(float a) { return acosf(a); } + static int nvg__mini(int a, int b) { return a < b ? a : b; } static int nvg__maxi(int a, int b) { return a > b ? a : b; } static float nvg__minf(float a, float b) { return a < b ? a : b; } @@ -119,7 +127,7 @@ static float nvg__cross(float dx0, float dy0, float dx1, float dy1) { return dx1 static float nvg__normalize(float *x, float* y) { - float d = sqrtf((*x)*(*x) + (*y)*(*y)); + float d = nvg__sqrtf((*x)*(*x) + (*y)*(*y)); if (d > 1e-6f) { d = 1.0f / d; *x *= d; @@ -201,7 +209,7 @@ struct NVGcontext* nvgCreateInternal(struct NVGparams* params) fontParams.renderDraw = NULL; fontParams.renderDelete = NULL; fontParams.userPtr = NULL; - ctx->fs = fonsCreate(&fontParams); + ctx->fs = fonsCreateInternal(&fontParams); if (ctx->fs == NULL) goto error; // Create font texture @@ -222,7 +230,7 @@ void nvgDeleteInternal(struct NVGcontext* ctx) if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache); if (ctx->fs) - fonsDelete(ctx->fs); + fonsDeleteInternal(ctx->fs); if (ctx->params.renderDelete != NULL) ctx->params.renderDelete(ctx->params.userPtr); @@ -282,7 +290,7 @@ static float nvg__hue(float h, float m1, float m2) unsigned int nvgHSLA(float h, float s, float l, unsigned char a) { - h = fmod(h, 1.0f); + h = nvg__modf(h, 1.0f); if (h < 0.0f) h += 1.0f; s = nvg__clampf(s, 0.0f, 1.0f); l = nvg__clampf(l, 0.0f, 1.0f); @@ -323,7 +331,7 @@ static void nvg__xformScale(float* t, float sx, float sy) static void nvg__xformRotate(float* t, float a) { - float cs = cosf(a), sn = sinf(a); + float cs = nvg__cosf(a), sn = nvg__sinf(a); t[0] = cs; t[1] = sn; t[2] = -sn; t[3] = cs; t[4] = 0.0f; t[5] = 0.0f; @@ -1280,8 +1288,8 @@ void nvgArcTo(struct NVGcontext* ctx, float x1, float y1, float x2, float y2, fl dy1 = y2-y1; nvg__normalize(&dx0,&dy0); nvg__normalize(&dx1,&dy1); - a = acosf(dx0*dx1 + dy0*dy1); - d = radius / tanf(a/2.0f); + a = nvg__acosf(dx0*dx1 + dy0*dy1); + d = radius / nvg__tanf(a/2.0f); if (d > 10000.0f) { nvgLineTo(ctx, x1,y1); @@ -1291,14 +1299,14 @@ void nvgArcTo(struct NVGcontext* ctx, float x1, float y1, float x2, float y2, fl if (nvg__cross(dx0,dy0, dx1,dy1) > 0.0f) { cx = x1 + dx0*d + dy0*radius; cy = y1 + dy0*d + -dx0*radius; - a0 = atan2f(dx0, -dy0); - a1 = atan2f(-dx1, dy1); + a0 = nvg__atan2f(dx0, -dy0); + a1 = nvg__atan2f(-dx1, dy1); dir = NVG_CW; } else { cx = x1 + dx0*d + -dy0*radius; cy = y1 + dy0*d + dx0*radius; - a0 = atan2f(-dx0, dy0); - a1 = atan2f(dx1, -dy1); + a0 = nvg__atan2f(-dx0, dy0); + a1 = nvg__atan2f(dx1, -dy1); dir = NVG_CCW; } @@ -1345,7 +1353,7 @@ void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float // Split arc into max 90 degree segments. ndivs = nvg__maxi(1, nvg__mini((int)(nvg__absf(da) / (NVG_PI*0.5f) + 0.5f), 5)); hda = (da / (float)ndivs) / 2.0f; - kappa = nvg__absf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + kappa = nvg__absf(4.0f / 3.0f * (1.0f - nvg__cosf(hda)) / nvg__sinf(hda)); if (dir == NVG_CCW) kappa = -kappa; @@ -1353,8 +1361,8 @@ void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float nvals = 0; for (i = 0; i <= ndivs; i++) { a = a0 + da * (i/(float)ndivs); - dx = cosf(a); - dy = sinf(a); + dx = nvg__cosf(a); + dy = nvg__sinf(a); x = cx + dx*r; y = cy + dy*r; tanx = -dy*r*kappa; @@ -1526,7 +1534,7 @@ void nvgFontFace(struct NVGcontext* ctx, const char* font) state->fontId = fonsGetFontByName(ctx->fs, font); } -void nvgText(struct NVGcontext* ctx, float x, float y, const char* string) +float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, const char* end) { struct NVGstate* state = nvg__getState(ctx); struct FONStextIter iter; @@ -1538,7 +1546,10 @@ void nvgText(struct NVGcontext* ctx, float x, float y, const char* string) int cverts = 0; int nverts = 0; - if (state->fontId == FONS_INVALID) return; + if (end == NULL) + end = string + strlen(string); + + if (state->fontId == FONS_INVALID) return x; fonsSetSize(ctx->fs, state->fontSize*scale); fonsSetSpacing(ctx->fs, state->letterSpacing*scale); @@ -1546,11 +1557,11 @@ void nvgText(struct NVGcontext* ctx, float x, float y, const char* string) fonsSetAlign(ctx->fs, state->textAlign); fonsSetFont(ctx->fs, state->fontId); - cverts = nvg__maxi(2, strlen(string)) * 6; // conservative estimate. + cverts = nvg__maxi(2, (int)(end - string)) * 6; // conservative estimate. verts = nvg__allocTempVerts(ctx, cverts); - if (verts == NULL) return; + if (verts == NULL) return x; - fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string); + fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end); while (fonsTextIterNext(ctx->fs, &iter, &q)) { // Trasnform corners. float c[4*2]; @@ -1587,12 +1598,14 @@ void nvgText(struct NVGcontext* ctx, float x, float y, const char* string) ctx->drawCallCount++; ctx->textTriCount += nverts/3; + + return iter.x; } -void nvgTextBounds(struct NVGcontext* ctx, const char* string, float* width, float* bounds) +float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, float* bounds) { struct NVGstate* state = nvg__getState(ctx); - if (state->fontId == FONS_INVALID) return; + if (state->fontId == FONS_INVALID) return 0; fonsSetSize(ctx->fs, state->fontSize); fonsSetSpacing(ctx->fs, state->letterSpacing); @@ -1600,7 +1613,7 @@ void nvgTextBounds(struct NVGcontext* ctx, const char* string, float* width, flo fonsSetAlign(ctx->fs, state->textAlign); fonsSetFont(ctx->fs, state->fontId); - fonsTextBounds(ctx->fs, string, width, bounds); + return fonsTextBounds(ctx->fs, string, end, bounds); } void nvgVertMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh) diff --git a/src/nanovg.h b/src/nanovg.h index 917c98b..e9ffa35 100644 --- a/src/nanovg.h +++ b/src/nanovg.h @@ -186,10 +186,10 @@ void nvgFontFaceId(struct NVGcontext* ctx, int font); void nvgFontFace(struct NVGcontext* ctx, const char* font); // Draw text -void nvgText(struct NVGcontext* ctx, float x, float y, const char* string); +float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, const char* end); // Measure text -void nvgTextBounds(struct NVGcontext* ctx, const char* string, float* width, float* bounds); +float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, float* bounds); void nvgVertMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh);