nanovg 0.5.2.0 → 0.6.0.0
raw patch · 14 files changed
+358/−94 lines, 14 filesdep ~basedep ~containers
Dependency ranges changed: base, containers
Files
- CHANGELOG.md +7/−0
- README.md +2/−1
- cbits/nanovg_gl.c +10/−0
- nanovg.cabal +24/−5
- nanovg/src/fontstash.h +54/−26
- nanovg/src/nanovg.c +18/−11
- nanovg/src/nanovg.h +8/−4
- nanovg/src/nanovg_gl.h +91/−34
- src/NanoVG.hs +20/−0
- src/NanoVG/Internal/Context.hs +10/−0
- src/NanoVG/Internal/CreateContext.chs +21/−0
- src/NanoVG/Internal/GL2.chs +40/−0
- src/NanoVG/Internal/GL3.chs +14/−13
- src/NanoVG/Internal/GLES3.chs +39/−0
CHANGELOG.md view
@@ -1,3 +1,10 @@+0.6.0.0+---++* GL2 support+* openGLES3 support+* Drop support for GHC 7.10+ 0.5.2.0 --- * MacOS support
README.md view
@@ -1,6 +1,7 @@ # NanoVG Haskell bindings -[](https://travis-ci.org/cocreature/nanovg-hs)+[](https://travis-ci.org/cocreature/nanovg-hs)+[](https://hackage.haskell.org/package/nanovg) Currently only the GL3 backend is supported.
cbits/nanovg_gl.c view
@@ -1,7 +1,17 @@+#if defined(GLES_3)+#define NANOVG_GLES3_IMPLEMENTATION+#elif defined(GL_2)+#define NANOVG_GL2_IMPLEMENTATION+#else #define NANOVG_GL3_IMPLEMENTATION+#endif // This is used to link the implementation #if defined(darwin_HOST_OS)+#if defined(GL_2)+#include <OpenGL/gl.h>+#else #include <OpenGL/gl3.h>+#endif #else #include "GL/glew.h" #endif
nanovg.cabal view
@@ -1,5 +1,5 @@ name: nanovg-version: 0.5.2.0+version: 0.6.0.0 synopsis: Haskell bindings for nanovg description: Raw bindings to the OpenGL vector graphics library NanoVG homepage: https://github.com/cocreature/nanovg-hs@@ -14,7 +14,7 @@ README.md CHANGELOG.md cabal-version: >=1.10-tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.1+tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.2 source-repository head type: git@@ -25,14 +25,27 @@ default: False manual: True +flag gles3+ description: Build for GLES3. This deactivates GL3 support.+ default: False+ manual: True++flag gl2+ description: Build for GL2. This deactivates GL3 support.+ default: False+ manual: True+ library exposed-modules: NanoVG NanoVG.Internal NanoVG.Internal.Color+ NanoVG.Internal.CreateContext NanoVG.Internal.Context NanoVG.Internal.FFIHelpers NanoVG.Internal.FixedVector NanoVG.Internal.GL3+ NanoVG.Internal.GL2+ NanoVG.Internal.GLES3 NanoVG.Internal.Image NanoVG.Internal.Paint NanoVG.Internal.Path@@ -42,11 +55,11 @@ NanoVG.Internal.Text NanoVG.Internal.Transformation NanoVG.Internal.Types- build-depends: base >= 4.7 && <5.0+ build-depends: base >= 4.8 && <5.0 , bytestring >= 0.10 && < 0.11 , containers >= 0.5 && < 0.6 , text >= 1.2 && < 1.3- , vector >= 0.11 && < 0.12+ , vector >= 0.11 && < 0.13 hs-source-dirs: src default-language: Haskell2010 include-dirs: nanovg/src@@ -67,7 +80,13 @@ cc-options: -Ddarwin_HOST_OS else extra-libraries: GLU, GL, m, GLEW- ghc-options: -pgml gcc "-optl-Wl,--whole-archive" "-optl-Wl,-lGLEW" "-optl-Wl,--no-whole-archive"+ pkgconfig-depends: glew+ if flag(gles3)+ cpp-options: -DGLES_3+ cc-options: -DGLES_3+ if flag(gl2)+ cpp-options: -DGL_2+ cc-options: -DGL_2 build-tools: c2hs executable example00
nanovg/src/fontstash.h view
@@ -38,6 +38,11 @@ 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 @@ const char* next; const char* end; unsigned int utf8state;+ int bitmapOption; }; typedef struct FONStextIter FONStextIter; @@ -122,7 +128,7 @@ 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@@ -873,7 +879,8 @@ 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.@@ -1029,7 +1036,7 @@ } 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 +1059,18 @@ 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 +1091,34 @@ 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 +1127,14 @@ 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 +1161,7 @@ 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 +1323,7 @@ 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 +1346,7 @@ } 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 +1386,7 @@ iter->end = end; iter->codepoint = 0; iter->prevGlyphIndex = -1;+ iter->bitmapOption = bitmapOption; return 1; }@@ -1380,7 +1407,8 @@ // 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 +1505,7 @@ 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;
nanovg/src/nanovg.c view
@@ -67,6 +67,7 @@ struct NVGstate { NVGcompositeOperationState compositeOperation;+ int shapeAntiAlias; NVGpaint fill; NVGpaint stroke; float strokeWidth;@@ -389,8 +390,7 @@ void nvgEndFrame(NVGcontext* ctx) {- NVGstate* state = nvg__getState(ctx);- ctx->params.renderFlush(ctx->params.userPtr, state->compositeOperation);+ ctx->params.renderFlush(ctx->params.userPtr); if (ctx->fontImageIdx != 0) { int fontImage = ctx->fontImages[ctx->fontImageIdx]; int i, j, iw, ih;@@ -646,6 +646,7 @@ nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255)); nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255)); state->compositeOperation = nvg__compositeOperationState(NVG_SOURCE_OVER);+ state->shapeAntiAlias = 1; state->strokeWidth = 1.0f; state->miterLimit = 10.0f; state->lineCap = NVG_BUTT;@@ -665,6 +666,12 @@ } // State setting+void nvgShapeAntiAlias(NVGcontext* ctx, int enabled)+{+ NVGstate* state = nvg__getState(ctx);+ state->shapeAntiAlias = enabled;+}+ void nvgStrokeWidth(NVGcontext* ctx, float width) { NVGstate* state = nvg__getState(ctx);@@ -2203,7 +2210,7 @@ int i; nvg__flattenPaths(ctx);- if (ctx->params.edgeAntiAlias)+ if (ctx->params.edgeAntiAlias && state->shapeAntiAlias) nvg__expandFill(ctx, ctx->fringeWidth, NVG_MITER, 2.4f); else nvg__expandFill(ctx, 0.0f, NVG_MITER, 2.4f);@@ -2212,7 +2219,7 @@ fillPaint.innerColor.a *= state->alpha; fillPaint.outerColor.a *= state->alpha; - ctx->params.renderFill(ctx->params.userPtr, &fillPaint, &state->scissor, ctx->fringeWidth,+ ctx->params.renderFill(ctx->params.userPtr, &fillPaint, state->compositeOperation, &state->scissor, ctx->fringeWidth, ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); // Count triangles@@ -2248,12 +2255,12 @@ nvg__flattenPaths(ctx); - if (ctx->params.edgeAntiAlias)+ if (ctx->params.edgeAntiAlias && state->shapeAntiAlias) nvg__expandStroke(ctx, strokeWidth*0.5f + ctx->fringeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); else nvg__expandStroke(ctx, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); - ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, &state->scissor, ctx->fringeWidth,+ ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, state->compositeOperation, &state->scissor, ctx->fringeWidth, strokeWidth, ctx->cache->paths, ctx->cache->npaths); // Count triangles@@ -2401,7 +2408,7 @@ paint.innerColor.a *= state->alpha; paint.outerColor.a *= state->alpha; - ctx->params.renderTriangles(ctx->params.userPtr, &paint, &state->scissor, verts, nverts);+ ctx->params.renderTriangles(ctx->params.userPtr, &paint, state->compositeOperation, &state->scissor, verts, nverts); ctx->drawCallCount++; ctx->textTriCount += nverts/3;@@ -2433,7 +2440,7 @@ 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];@@ -2471,7 +2478,7 @@ nvg__renderText(ctx, verts, nverts); - return iter.x;+ return iter.nextx / scale; } void nvgTextBox(NVGcontext* ctx, float x, float y, float breakRowWidth, const char* string, const char* end)@@ -2530,7 +2537,7 @@ 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?@@ -2596,7 +2603,7 @@ 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?
nanovg/src/nanovg.h view
@@ -141,6 +141,7 @@ NVG_IMAGE_REPEATY = 1<<2, // Repeat image in Y direction. NVG_IMAGE_FLIPY = 1<<3, // Flips (inverses) image in Y direction when rendered. NVG_IMAGE_PREMULTIPLIED = 1<<4, // Image data has premultiplied alpha.+ NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear }; // Begin drawing a new frame@@ -237,6 +238,9 @@ // // Current render style can be saved and restored using nvgSave() and nvgRestore(). +// Sets whether to draw antialias for nvgStroke() and nvgFill(). It's enabled by default.+void nvgShapeAntiAlias(NVGcontext* ctx, int enabled);+ // Sets current stroke style to a solid color. void nvgStrokeColor(NVGcontext* ctx, NVGcolor color); @@ -651,10 +655,10 @@ int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h); void (*renderViewport)(void* uptr, int width, int height, float devicePixelRatio); void (*renderCancel)(void* uptr);- void (*renderFlush)(void* uptr, NVGcompositeOperationState compositeOperation);- void (*renderFill)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);- void (*renderStroke)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);- void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts);+ void (*renderFlush)(void* uptr);+ void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths);+ void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths);+ void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts); void (*renderDelete)(void* uptr); }; typedef struct NVGparams NVGparams;
nanovg/src/nanovg_gl.h view
@@ -150,6 +150,15 @@ }; typedef struct GLNVGtexture GLNVGtexture; +struct GLNVGblend+{+ GLenum srcRGB;+ GLenum dstRGB;+ GLenum srcAlpha;+ GLenum dstAlpha;+};+typedef struct GLNVGblend GLNVGblend;+ enum GLNVGcallType { GLNVG_NONE = 0, GLNVG_FILL,@@ -166,6 +175,7 @@ int triangleOffset; int triangleCount; int uniformOffset;+ GLNVGblend blendFunc; }; typedef struct GLNVGcall GLNVGcall; @@ -256,6 +266,7 @@ GLenum stencilFunc; GLint stencilFuncRef; GLuint stencilFuncMask;+ GLNVGblend blendFunc; #endif }; typedef struct GLNVGcontext GLNVGcontext;@@ -316,7 +327,22 @@ glStencilFunc(func, ref, mask); #endif }+static void glnvg__blendFuncSeparate(GLNVGcontext* gl, const GLNVGblend* blend)+{+#if NANOVG_GL_USE_STATE_FILTER+ if ((gl->blendFunc.srcRGB != blend->srcRGB) ||+ (gl->blendFunc.dstRGB != blend->dstRGB) ||+ (gl->blendFunc.srcAlpha != blend->srcAlpha) ||+ (gl->blendFunc.dstAlpha != blend->dstAlpha)) { + gl->blendFunc = *blend;+ glBlendFuncSeparate(blend->srcRGB, blend->dstRGB, blend->srcAlpha,blend->dstAlpha);+ }+#else+ glBlendFuncSeparate(blend->srcRGB, blend->dstRGB, blend->srcAlpha,blend->dstAlpha);+#endif+}+ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) { GLNVGtexture* tex = NULL;@@ -600,6 +626,7 @@ " float scissor = scissorMask(fpos);\n" "#ifdef EDGE_AA\n" " float strokeAlpha = strokeMask();\n"+ " if (strokeAlpha < strokeThr) discard;\n" "#else\n" " float strokeAlpha = 1.0;\n" "#endif\n"@@ -639,9 +666,6 @@ " color *= scissor;\n" " result = color * innerCol;\n" " }\n"- "#ifdef EDGE_AA\n"- " if (strokeAlpha < strokeThr) discard;\n"- "#endif\n" "#ifdef NANOVG_GL3\n" " outColor = result;\n" "#else\n"@@ -739,12 +763,25 @@ #endif if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) {- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);+ if (imageFlags & NVG_IMAGE_NEAREST) {+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);+ } else {+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);+ } } else {- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);+ if (imageFlags & NVG_IMAGE_NEAREST) {+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);+ } else {+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);+ } }- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (imageFlags & NVG_IMAGE_NEAREST) {+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);+ } else {+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);+ }+ if (imageFlags & NVG_IMAGE_REPEATX) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); else@@ -908,10 +945,17 @@ } 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;@@ -947,6 +991,7 @@ 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;@@ -991,7 +1036,7 @@ // Draw fill glnvg__stencilFunc(gl, GL_NOTEQUAL, 0x0, 0xff); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);- glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount);+ glDrawArrays(GL_TRIANGLE_STRIP, call->triangleOffset, call->triangleCount); glDisable(GL_STENCIL_TEST); }@@ -1103,19 +1148,24 @@ return GL_INVALID_ENUM; } -static void glnvg__blendCompositeOperation(NVGcompositeOperationState op)+static GLNVGblend glnvg__blendCompositeOperation(NVGcompositeOperationState op) {- GLenum srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB);- GLenum dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB);- GLenum srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha);- GLenum dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha);- if (srcRGB == GL_INVALID_ENUM || dstRGB == GL_INVALID_ENUM || srcAlpha == GL_INVALID_ENUM || dstAlpha == GL_INVALID_ENUM)- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);- else- glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);+ GLNVGblend blend;+ blend.srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB);+ blend.dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB);+ blend.srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha);+ blend.dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha);+ if (blend.srcRGB == GL_INVALID_ENUM || blend.dstRGB == GL_INVALID_ENUM || blend.srcAlpha == GL_INVALID_ENUM || blend.dstAlpha == GL_INVALID_ENUM)+ {+ blend.srcRGB = GL_ONE;+ blend.dstRGB = GL_ONE_MINUS_SRC_ALPHA;+ blend.srcAlpha = GL_ONE;+ blend.dstAlpha = GL_ONE_MINUS_SRC_ALPHA;+ }+ return blend; } -static void glnvg__renderFlush(void* uptr, NVGcompositeOperationState compositeOperation)+static void glnvg__renderFlush(void* uptr) { GLNVGcontext* gl = (GLNVGcontext*)uptr; int i;@@ -1125,7 +1175,6 @@ // Setup require GL state. glUseProgram(gl->shader.prog); - glnvg__blendCompositeOperation(compositeOperation); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW);@@ -1144,6 +1193,10 @@ gl->stencilFunc = GL_ALWAYS; gl->stencilFuncRef = 0; gl->stencilFuncMask = 0xffffffff;+ gl->blendFunc.srcRGB = GL_INVALID_ENUM;+ gl->blendFunc.srcAlpha = GL_INVALID_ENUM;+ gl->blendFunc.dstRGB = GL_INVALID_ENUM;+ gl->blendFunc.dstAlpha = GL_INVALID_ENUM; #endif #if NANOVG_GL_USE_UNIFORMBUFFER@@ -1173,6 +1226,7 @@ for (i = 0; i < gl->ncalls; i++) { GLNVGcall* call = &gl->calls[i];+ glnvg__blendFuncSeparate(gl,&call->blendFunc); if (call->type == GLNVG_FILL) glnvg__fill(gl, call); else if (call->type == GLNVG_CONVEXFILL)@@ -1288,7 +1342,7 @@ vtx->v = v; } -static void glnvg__renderFill(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe,+static void glnvg__renderFill(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths) { GLNVGcontext* gl = (GLNVGcontext*)uptr;@@ -1300,16 +1354,21 @@ if (call == NULL) return; call->type = GLNVG_FILL;+ call->triangleCount = 4; call->pathOffset = glnvg__allocPaths(gl, npaths); if (call->pathOffset == -1) goto error; call->pathCount = npaths; call->image = paint->image;+ call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); if (npaths == 1 && paths[0].convex)+ { call->type = GLNVG_CONVEXFILL;+ call->triangleCount = 0; // Bounding box fill quad not needed for convex fill+ } // Allocate vertices for all the paths.- maxverts = glnvg__maxVertCount(paths, npaths) + 6;+ maxverts = glnvg__maxVertCount(paths, npaths) + call->triangleCount; offset = glnvg__allocVerts(gl, maxverts); if (offset == -1) goto error; @@ -1331,20 +1390,16 @@ } } - // Quad- call->triangleOffset = offset;- call->triangleCount = 6;- quad = &gl->verts[call->triangleOffset];- glnvg__vset(&quad[0], bounds[0], bounds[3], 0.5f, 1.0f);- glnvg__vset(&quad[1], bounds[2], bounds[3], 0.5f, 1.0f);- glnvg__vset(&quad[2], bounds[2], bounds[1], 0.5f, 1.0f);-- glnvg__vset(&quad[3], bounds[0], bounds[3], 0.5f, 1.0f);- glnvg__vset(&quad[4], bounds[2], bounds[1], 0.5f, 1.0f);- glnvg__vset(&quad[5], bounds[0], bounds[1], 0.5f, 1.0f);- // Setup uniforms for draw calls if (call->type == GLNVG_FILL) {+ // Quad+ call->triangleOffset = offset;+ quad = &gl->verts[call->triangleOffset];+ glnvg__vset(&quad[0], bounds[2], bounds[3], 0.5f, 1.0f);+ glnvg__vset(&quad[1], bounds[2], bounds[1], 0.5f, 1.0f);+ glnvg__vset(&quad[2], bounds[0], bounds[3], 0.5f, 1.0f);+ glnvg__vset(&quad[3], bounds[0], bounds[1], 0.5f, 1.0f);+ call->uniformOffset = glnvg__allocFragUniforms(gl, 2); if (call->uniformOffset == -1) goto error; // Simple shader for stencil@@ -1369,7 +1424,7 @@ if (gl->ncalls > 0) gl->ncalls--; } -static void glnvg__renderStroke(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe,+static void glnvg__renderStroke(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths) { GLNVGcontext* gl = (GLNVGcontext*)uptr;@@ -1383,6 +1438,7 @@ if (call->pathOffset == -1) goto error; call->pathCount = npaths; call->image = paint->image;+ call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); // Allocate vertices for all the paths. maxverts = glnvg__maxVertCount(paths, npaths);@@ -1424,7 +1480,7 @@ if (gl->ncalls > 0) gl->ncalls--; } -static void glnvg__renderTriangles(void* uptr, NVGpaint* paint, NVGscissor* scissor,+static void glnvg__renderTriangles(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts) { GLNVGcontext* gl = (GLNVGcontext*)uptr;@@ -1435,6 +1491,7 @@ call->type = GLNVG_TRIANGLES; call->image = paint->image;+ call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); // Allocate vertices for all the paths. call->triangleOffset = glnvg__allocVerts(gl, nverts);
src/NanoVG.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} module NanoVG ( FileName(..) , Context(..)@@ -116,10 +117,22 @@ , textBreakLines -- * GL , CreateFlags(..)+#if defined(GLES_3)+ , createGLES3+ , deleteGLES3+ , createImageFromHandleGLES3+ , imageHandleGLES3+#elif defined(GL_2)+ , createGL2+ , deleteGL2+ , createImageFromHandleGL2+ , imageHandleGL2+#else , createGL3 , deleteGL3 , createImageFromHandleGL3 , imageHandleGL3+#endif -- * Vector types , V2(..) , V3(..)@@ -137,7 +150,14 @@ import Foreign.Ptr import Foreign.Storable import NanoVG.Internal+import NanoVG.Internal.CreateContext+#if defined(GLES_3)+import NanoVG.Internal.GLES3+#elif defined(GL_2)+import NanoVG.Internal.GL2+#else import NanoVG.Internal.GL3+#endif import qualified NanoVG.Internal.Text as Internal import NanoVG.Internal.Text hiding (textBreakLines,textGlyphPositions,text)
src/NanoVG/Internal/Context.hs view
@@ -1,8 +1,18 @@ module NanoVG.Internal.Context (Context(..)+ , toPointer+ , fromPointer ) where import Foreign.Ptr -- | Opaque context that needs to be passed around newtype Context = Context (Ptr Context)++-- | In marshaller for c2hs+toPointer :: Context -> Ptr ()+toPointer (Context p) = castPtr p++-- | out marshaller for c2hs+fromPointer :: Ptr () -> Context+fromPointer p = Context (castPtr p)
+ src/NanoVG/Internal/CreateContext.chs view
@@ -0,0 +1,21 @@+module NanoVG.Internal.CreateContext where++import Foreign.C.Types+import Data.Word (Word32(..))++#include "nanovg.h"+#include "nanovg_gl.h"++{#pointer *NVGcontext as Context newtype nocode#}++{#enum NVGcreateFlags as CreateFlags+ {underscoreToCase} with prefix = "NVG_"+ deriving (Show,Read,Eq,Ord)#}++type GLuint = Word32++toCInt :: CreateFlags -> CInt+toCInt = fromIntegral . fromEnum++fromCInt :: CInt -> CreateFlags+fromCInt = toEnum . fromIntegral
+ src/NanoVG/Internal/GL2.chs view
@@ -0,0 +1,40 @@+module NanoVG.Internal.GL2 where++import qualified Data.Set as S+import Data.Word+import Foreign.C.Types++import NanoVG.Internal.CreateContext+import NanoVG.Internal.Types+import NanoVG.Internal.Context+import NanoVG.Internal.FFIHelpers++-- For now only the GL2 backends are supported+#define NANOVG_GL2++-- We need to include this to define GLuint+#if defined(darwin_HOST_OS)+#include <OpenGL/gl.h>+#else+#include "GL/glew.h"+#endif+#include "nanovg.h"+#include "nanovg_gl.h"++{#fun unsafe nvgCreateGL2 as createGL2+ {bitMask`S.Set CreateFlags'} -> `Context' fromPointer#}+{#fun unsafe nvgDeleteGL2 as deleteGL2+ { toPointer `Context' fromPointer} -> `()'#}++{#fun unsafe nvglCreateImageFromHandleGL2 as createImageFromHandleGL2+ { toPointer `Context' fromPointer+ , fromIntegral`GLuint'+ , `CInt'+ , `CInt'+ , toCInt `CreateFlags' fromCInt+ } -> `Image'Image#}++{#fun unsafe nvglImageHandleGL2 as imageHandleGL2+ { toPointer `Context' fromPointer+ , imageHandle`Image'+ } -> `GLuint'fromIntegral#}
src/NanoVG/Internal/GL3.chs view
@@ -4,12 +4,14 @@ import Data.Word import Foreign.C.Types +import NanoVG.Internal.CreateContext import NanoVG.Internal.Types import NanoVG.Internal.Context import NanoVG.Internal.FFIHelpers --- For now only the GL3 backend is supported+-- For now only the GL3 and the GLES3 backends are supported #define NANOVG_GL3+ -- We need to include this to define GLuint #if defined(darwin_HOST_OS) #include <OpenGL/gl3.h>@@ -19,21 +21,20 @@ #include "nanovg.h" #include "nanovg_gl.h" -{#pointer *NVGcontext as Context newtype nocode#}--{#enum NVGcreateFlags as CreateFlags- {underscoreToCase} with prefix = "NVG_"- deriving (Show,Read,Eq,Ord)#}- {#fun unsafe nvgCreateGL3 as createGL3- {bitMask`S.Set CreateFlags'} -> `Context'#}+ {bitMask`S.Set CreateFlags'} -> `Context' fromPointer#} {#fun unsafe nvgDeleteGL3 as deleteGL3- {`Context'} -> `()'#}--type GLuint = Word32+ { toPointer `Context' fromPointer} -> `()'#} {#fun unsafe nvglCreateImageFromHandleGL3 as createImageFromHandleGL3- {`Context',fromIntegral`GLuint',`CInt',`CInt',`CreateFlags'} -> `Image'Image#}+ { toPointer `Context' fromPointer+ , fromIntegral`GLuint'+ , `CInt'+ , `CInt'+ , toCInt `CreateFlags' fromCInt+ } -> `Image'Image#} {#fun unsafe nvglImageHandleGL3 as imageHandleGL3- {`Context',imageHandle`Image'} -> `GLuint'fromIntegral#}+ { toPointer `Context' fromPointer+ , imageHandle`Image'+ } -> `GLuint'fromIntegral#}
+ src/NanoVG/Internal/GLES3.chs view
@@ -0,0 +1,39 @@+module NanoVG.Internal.GLES3 where++import qualified Data.Set as S+import Data.Word+import Foreign.C.Types++import NanoVG.Internal.CreateContext+import NanoVG.Internal.Types+import NanoVG.Internal.Context+import NanoVG.Internal.FFIHelpers++-- For now only the GL3 and GLES3 backends are supported+#define NANOVG_GLES3+-- We need to include this to define GLuint+#if defined(darwin_HOST_OS)+#include <OpenGL/gl3.h>+#else+#include "GL/glew.h"+#endif+#include "nanovg.h"+#include "nanovg_gl.h"++{#fun unsafe nvgCreateGLES3 as createGLES3+ {bitMask`S.Set CreateFlags'} -> `Context' fromPointer#}+{#fun unsafe nvgDeleteGLES3 as deleteGLES3+ {toPointer `Context' fromPointer} -> `()'#}++{#fun unsafe nvglCreateImageFromHandleGLES3 as createImageFromHandleGLES3+ { toPointer `Context' fromPointer+ , fromIntegral`GLuint'+ , `CInt'+ , `CInt'+ , toCInt `CreateFlags' fromCInt+ } -> `Image'Image#}++{#fun unsafe nvglImageHandleGLES3 as imageHandleGLES3+ { toPointer `Context' fromPointer+ , imageHandle`Image'+ } -> `GLuint'fromIntegral#}