diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+0.6.0.0
+---
+
+* GL2 support
+* openGLES3 support
+* Drop support for GHC 7.10
+
 0.5.2.0
 ---
 * MacOS support
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
 # NanoVG Haskell bindings
 
-[![Build Status](https://travis-ci.org/cocreature/nanovg-hs.svg?branch=master)](https://travis-ci.org/cocreature/nanovg-hs)
+[![Build Status](https://img.shields.io/travis/cocreature/nanovg-hs.svg)](https://travis-ci.org/cocreature/nanovg-hs)
+[![Hackage](https://img.shields.io/hackage/v/nanovg.svg)](https://hackage.haskell.org/package/nanovg)
 
 Currently only the GL3 backend is supported.
 
diff --git a/cbits/nanovg_gl.c b/cbits/nanovg_gl.c
--- a/cbits/nanovg_gl.c
+++ b/cbits/nanovg_gl.c
@@ -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
diff --git a/nanovg.cabal b/nanovg.cabal
--- a/nanovg.cabal
+++ b/nanovg.cabal
@@ -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
diff --git a/nanovg/src/fontstash.h b/nanovg/src/fontstash.h
--- a/nanovg/src/fontstash.h
+++ b/nanovg/src/fontstash.h
@@ -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;
diff --git a/nanovg/src/nanovg.c b/nanovg/src/nanovg.c
--- a/nanovg/src/nanovg.c
+++ b/nanovg/src/nanovg.c
@@ -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?
diff --git a/nanovg/src/nanovg.h b/nanovg/src/nanovg.h
--- a/nanovg/src/nanovg.h
+++ b/nanovg/src/nanovg.h
@@ -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;
diff --git a/nanovg/src/nanovg_gl.h b/nanovg/src/nanovg_gl.h
--- a/nanovg/src/nanovg_gl.h
+++ b/nanovg/src/nanovg_gl.h
@@ -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);
diff --git a/src/NanoVG.hs b/src/NanoVG.hs
--- a/src/NanoVG.hs
+++ b/src/NanoVG.hs
@@ -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)
 
diff --git a/src/NanoVG/Internal/Context.hs b/src/NanoVG/Internal/Context.hs
--- a/src/NanoVG/Internal/Context.hs
+++ b/src/NanoVG/Internal/Context.hs
@@ -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)
diff --git a/src/NanoVG/Internal/CreateContext.chs b/src/NanoVG/Internal/CreateContext.chs
new file mode 100644
--- /dev/null
+++ b/src/NanoVG/Internal/CreateContext.chs
@@ -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
diff --git a/src/NanoVG/Internal/GL2.chs b/src/NanoVG/Internal/GL2.chs
new file mode 100644
--- /dev/null
+++ b/src/NanoVG/Internal/GL2.chs
@@ -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#}
diff --git a/src/NanoVG/Internal/GL3.chs b/src/NanoVG/Internal/GL3.chs
--- a/src/NanoVG/Internal/GL3.chs
+++ b/src/NanoVG/Internal/GL3.chs
@@ -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#}
diff --git a/src/NanoVG/Internal/GLES3.chs b/src/NanoVG/Internal/GLES3.chs
new file mode 100644
--- /dev/null
+++ b/src/NanoVG/Internal/GLES3.chs
@@ -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#}
