From 43aeba25a416d50b28f200ecac6adee10c593946 Mon Sep 17 00:00:00 2001 From: Olli Wang Date: Mon, 31 Jul 2017 23:46:24 +0800 Subject: [PATCH 1/9] Adds link of the Metal port. I just implmeneted the native Metal port of NanoVG. ;) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ae5cc79..c2e0863 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,8 @@ See the header file [nanovg.h](/src/nanovg.h) for API reference. ## Ports - [DX11 port](https://github.com/cmaughan/nanovg) by [Chris Maughan](https://github.com/cmaughan) -- [bgfx port](https://github.com/bkaradzic/bgfx/tree/master/examples/20-nanovg) by [Branimir Karadžić](https://github.com/bkaradzic) +- [Metal port](https://github.com/ollix/MetalNanoVG) by [Olli Wang](https://github.com/olliwang) +- [bgfx port](https://github.com/bkaradzic/bgfx/tree/master/examples/20-nanovg) by [Branimir Karadžić](https://github.com/bkaradzic) ## Projects using NanoVG From 3b54182b02d5b0a42907f59f4645b0de41724b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag=20=C3=85gren?= Date: Sun, 3 Sep 2017 01:22:50 +0300 Subject: [PATCH 2/9] Remove unused variable. --- src/nanovg.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nanovg.c b/src/nanovg.c index d018034..61fcd14 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -390,7 +390,6 @@ void nvgCancelFrame(NVGcontext* ctx) void nvgEndFrame(NVGcontext* ctx) { - NVGstate* state = nvg__getState(ctx); ctx->params.renderFlush(ctx->params.userPtr); if (ctx->fontImageIdx != 0) { int fontImage = ctx->fontImages[ctx->fontImageIdx]; From b124bbbaf5e2b96c33cbcef12de558c1f22de5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag=20=C3=85gren?= Date: Sun, 3 Sep 2017 01:32:00 +0300 Subject: [PATCH 3/9] Fix implicit conversion warning. --- src/fontstash.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fontstash.h b/src/fontstash.h index 78abb95..560b10b 100644 --- a/src/fontstash.h +++ b/src/fontstash.h @@ -873,7 +873,8 @@ error: int fonsAddFont(FONScontext* stash, const char* name, const char* path) { FILE* fp = 0; - int dataSize = 0, readed; + int dataSize = 0; + size_t readed; unsigned char* data = NULL; // Read in the font data. From ac6a6568983a1e925b81ff2b1d14de197937bc01 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Tue, 5 Sep 2017 14:42:27 +0100 Subject: [PATCH 4/9] Fix MSVC 2017 compiler warning --- src/nanovg_gl.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/nanovg_gl.h b/src/nanovg_gl.h index a8b788d..a6d5fac 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -945,10 +945,17 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai } frag->type = NSVG_SHADER_FILLIMG; + #if NANOVG_GL_USE_UNIFORMBUFFER if (tex->type == NVG_TEXTURE_RGBA) frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1; else frag->texType = 2; + #else + if (tex->type == NVG_TEXTURE_RGBA) + frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f; + else + frag->texType = 2.0f; + #endif // printf("frag->texType = %d\n", frag->texType); } else { frag->type = NSVG_SHADER_FILLGRAD; From ee6b7346ccb20c304ae6aef3c9c839dba8eb36cb Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 22 Sep 2017 14:22:48 -0400 Subject: [PATCH 5/9] Add GL_DEPTH24_STENCIL8 as a fallback when creating render buffer object for nvgluCreateFramebuffer --- src/nanovg_gl_utils.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/nanovg_gl_utils.h b/src/nanovg_gl_utils.h index 1323e90..4155a66 100644 --- a/src/nanovg_gl_utils.h +++ b/src/nanovg_gl_utils.h @@ -90,7 +90,15 @@ NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imag glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) goto error; + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + // If GL_STENCIL_INDEX8 is not supported, try GL_DEPTH24_STENCIL8 as a fallback. + // Some graphics cards require a depth buffer along with a stencil. + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) goto error; + } glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); glBindRenderbuffer(GL_RENDERBUFFER, defaultRBO); From 448af072d6e7a16ef86c1968ee6b3c05b16017de Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Sat, 23 Sep 2017 10:32:17 -0400 Subject: [PATCH 6/9] Only apply fallback if GL_DEPTH24_STENCIL8 is defined --- src/nanovg_gl_utils.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nanovg_gl_utils.h b/src/nanovg_gl_utils.h index 4155a66..f7384d8 100644 --- a/src/nanovg_gl_utils.h +++ b/src/nanovg_gl_utils.h @@ -91,13 +91,16 @@ NVGLUframebuffer* nvgluCreateFramebuffer(NVGcontext* ctx, int w, int h, int imag glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { +#ifdef GL_DEPTH24_STENCIL8 // If GL_STENCIL_INDEX8 is not supported, try GL_DEPTH24_STENCIL8 as a fallback. // Some graphics cards require a depth buffer along with a stencil. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb->texture, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rbo); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) goto error; + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) +#endif // GL_DEPTH24_STENCIL8 + goto error; } glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); From 645861c8047ef69602340c9248d7596048e34c50 Mon Sep 17 00:00:00 2001 From: Olli Wang Date: Sun, 5 Nov 2017 17:11:27 +0800 Subject: [PATCH 7/9] =?UTF-8?q?Renders=20glyph=E2=80=99s=20bitmap=20data?= =?UTF-8?q?=20on=20demand.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates font stash to render glyph's bitmap data on demand. This change is intended to fix the issue that `nvgTextBounds()` may return an unreliable result when font atlas is full. This situation usually happens when auto scaling a large font text to fit a small rectangle. The `fons__getGlyph()` function now accepts a new parameter indicating whether bitmap data is optional, and only `nvgText()` requires it. All of `nvgTextGlyphPositions()`, `nvgTextBreakLines()`, `nvgTextBounds()` and `nvgTextBoxBounds()` functions are changed to work without glyph’s bitmap data. --- src/fontstash.h | 77 +++++++++++++++++++++++++++++++++---------------- src/nanovg.c | 6 ++-- 2 files changed, 55 insertions(+), 28 deletions(-) diff --git a/src/fontstash.h b/src/fontstash.h index 78abb95..9becfc3 100644 --- a/src/fontstash.h +++ b/src/fontstash.h @@ -38,6 +38,11 @@ enum FONSalign { FONS_ALIGN_BASELINE = 1<<6, // Default }; +enum FONSglyphBitmap { + FONS_GLYPH_BITMAP_OPTIONAL = 1, + FONS_GLYPH_BITMAP_REQUIRED = 2, +}; + enum FONSerrorCode { // Font atlas is full. FONS_ATLAS_FULL = 1, @@ -78,6 +83,7 @@ struct FONStextIter { const char* next; const char* end; unsigned int utf8state; + int bitmapOption; }; 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); // 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); // Pull texture changes @@ -1029,7 +1035,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, - 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; float scale; @@ -1052,12 +1058,18 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in h = fons__hashint(codepoint) & (FONS_HASH_LUT_SIZE-1); i = font->lut[h]; 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; } - // 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); // Try to find the glyph in fallback fonts. if (g == 0) { @@ -1078,20 +1090,34 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in gw = x1-x0 + 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); + 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. - 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->x0 = (short)gx; glyph->y0 = (short)gy; @@ -1100,15 +1126,14 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in glyph->xadv = (short)(scale * advance * 10.0f); glyph->xoff = (short)(x0 - 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 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. dst = &stash->texData[glyph->x0 + glyph->y0 * stash->params.width]; @@ -1135,7 +1160,7 @@ static FONSglyph* fons__getGlyph(FONScontext* stash, FONSfont* font, unsigned in if (iblur > 0) { stash->nscratch = 0; 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); @@ -1297,7 +1322,7 @@ float fonsDrawText(FONScontext* stash, for (; str != end; ++str) { if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) continue; - glyph = fons__getGlyph(stash, font, codepoint, isize, iblur); + glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_REQUIRED); if (glyph != NULL) { fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q); @@ -1320,7 +1345,7 @@ float fonsDrawText(FONScontext* stash, } 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); float width; @@ -1360,6 +1385,7 @@ int fonsTextIterInit(FONScontext* stash, FONStextIter* iter, iter->end = end; iter->codepoint = 0; iter->prevGlyphIndex = -1; + iter->bitmapOption = bitmapOption; return 1; } @@ -1380,7 +1406,8 @@ int fonsTextIterNext(FONScontext* stash, FONStextIter* iter, FONSquad* quad) // Get glyph and quad iter->x = iter->nextx; 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) fons__getQuad(stash, iter->font, iter->prevGlyphIndex, glyph, iter->scale, iter->spacing, &iter->nextx, &iter->nexty, quad); iter->prevGlyphIndex = glyph != NULL ? glyph->index : -1; @@ -1477,7 +1504,7 @@ float fonsTextBounds(FONScontext* stash, for (; str != end; ++str) { if (fons__decutf8(&utf8state, &codepoint, *(const unsigned char*)str)) continue; - glyph = fons__getGlyph(stash, font, codepoint, isize, iblur); + glyph = fons__getGlyph(stash, font, codepoint, isize, iblur, FONS_GLYPH_BITMAP_OPTIONAL); if (glyph != NULL) { fons__getQuad(stash, font, prevGlyphIndex, glyph, scale, state->spacing, &x, &y, &q); if (q.x0 < minx) minx = q.x0; diff --git a/src/nanovg.c b/src/nanovg.c index 5ddb541..a443bee 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -2441,7 +2441,7 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* verts = nvg__allocTempVerts(ctx, cverts); 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; while (fonsTextIterNext(ctx->fs, &iter, &q)) { float c[4*2]; @@ -2538,7 +2538,7 @@ int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, fonsSetAlign(ctx->fs, state->textAlign); 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; while (fonsTextIterNext(ctx->fs, &iter, &q)) { if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? @@ -2604,7 +2604,7 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa breakRowWidth *= scale; - fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end); + fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL); prevIter = iter; while (fonsTextIterNext(ctx->fs, &iter, &q)) { if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? From 5022b370e4b137178f72c0f34740f3ad50d540c0 Mon Sep 17 00:00:00 2001 From: Gavin Howard Date: Mon, 18 Dec 2017 16:13:16 -0700 Subject: [PATCH 8/9] Mark devicePixelRatio unused in glnvg_renderViewport --- src/nanovg_gl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nanovg_gl.h b/src/nanovg_gl.h index a6d5fac..75bdae2 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -991,6 +991,7 @@ static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image) static void glnvg__renderViewport(void* uptr, int width, int height, float devicePixelRatio) { + NVG_NOTUSED(devicePixelRatio); GLNVGcontext* gl = (GLNVGcontext*)uptr; gl->view[0] = (float)width; gl->view[1] = (float)height; From 6ce863cc5725935563e3deba97fdf810e00b45a3 Mon Sep 17 00:00:00 2001 From: JonathanS Date: Thu, 29 Mar 2018 22:07:56 +0200 Subject: [PATCH 9/9] Use GLES2 glTex[Sub]Image2D code paths also for GL2 --- src/nanovg_gl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nanovg_gl.h b/src/nanovg_gl.h index 75bdae2..e9924b3 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -754,7 +754,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im if (type == NVG_TEXTURE_RGBA) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); else -#if defined(NANOVG_GLES2) +#if defined(NANOVG_GLES2) || defined (NANOVG_GL2) glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); #elif defined(NANOVG_GLES3) glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); @@ -846,7 +846,7 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w if (tex->type == NVG_TEXTURE_RGBA) glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data); else -#ifdef NANOVG_GLES2 +#if defined(NANOVG_GLES2) || defined(NANOVG_GL2) glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); #else glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data);