| @@ -49,6 +49,7 @@ enum NVGcreateFlags { | |||
| # define NANOVG_GL_IMPLEMENTATION 1 | |||
| #endif | |||
| #define NANOVG_GL_USE_STATE_FILTER (1) | |||
| // Creates NanoVG contexts for different OpenGL (ES) versions. | |||
| // Flags should be combination of the create flags above. | |||
| @@ -231,6 +232,15 @@ struct GLNVGcontext { | |||
| unsigned char* uniforms; | |||
| int cuniforms; | |||
| int nuniforms; | |||
| // cached state | |||
| #if NANOVG_GL_USE_STATE_FILTER | |||
| GLuint boundTexture; | |||
| GLuint stencilMask; | |||
| GLenum stencilFunc; | |||
| GLint stencilFuncRef; | |||
| GLuint stencilFuncMask; | |||
| #endif | |||
| }; | |||
| typedef struct GLNVGcontext GLNVGcontext; | |||
| @@ -250,6 +260,47 @@ static unsigned int glnvg__nearestPow2(unsigned int num) | |||
| } | |||
| #endif | |||
| static void glnvg__bindTexture(GLNVGcontext* gl, GLuint tex) | |||
| { | |||
| #if NANOVG_GL_USE_STATE_FILTER | |||
| if (gl->boundTexture != tex) { | |||
| gl->boundTexture = tex; | |||
| glBindTexture(GL_TEXTURE_2D, tex); | |||
| } | |||
| #else | |||
| glBindTexture(GL_TEXTURE_2D, tex); | |||
| #endif | |||
| } | |||
| static void glnvg__stencilMask(GLNVGcontext* gl, GLuint mask) | |||
| { | |||
| #if NANOVG_GL_USE_STATE_FILTER | |||
| if (gl->stencilMask != mask) { | |||
| gl->stencilMask = mask; | |||
| glStencilMask(mask); | |||
| } | |||
| #else | |||
| glStencilMask(mask); | |||
| #endif | |||
| } | |||
| static void glnvg__stencilFunc(GLNVGcontext* gl, GLenum func, GLint ref, GLuint mask) | |||
| { | |||
| #if NANOVG_GL_USE_STATE_FILTER | |||
| if ((gl->stencilFunc != func) || | |||
| (gl->stencilFuncRef != ref) || | |||
| (gl->stencilFuncMask != mask)) { | |||
| gl->stencilFunc = func; | |||
| gl->stencilFuncRef = ref; | |||
| gl->stencilFuncMask = mask; | |||
| glStencilFunc(func, ref, mask); | |||
| } | |||
| #else | |||
| glStencilFunc(func, ref, mask); | |||
| #endif | |||
| } | |||
| static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) | |||
| { | |||
| GLNVGtexture* tex = NULL; | |||
| @@ -661,7 +712,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||
| tex->height = h; | |||
| tex->type = type; | |||
| tex->flags = imageFlags; | |||
| glBindTexture(GL_TEXTURE_2D, tex->tex); | |||
| glnvg__bindTexture(gl, tex->tex); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT,1); | |||
| #ifndef NANOVG_GLES2 | |||
| @@ -720,8 +771,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||
| #endif | |||
| glnvg__checkError(gl, "create tex"); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glnvg__bindTexture(gl, 0); | |||
| return tex->id; | |||
| } | |||
| @@ -739,7 +789,7 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w | |||
| GLNVGtexture* tex = glnvg__findTexture(gl, image); | |||
| if (tex == NULL) return 0; | |||
| glBindTexture(GL_TEXTURE_2D, tex->tex); | |||
| glnvg__bindTexture(gl, tex->tex); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT,1); | |||
| @@ -773,7 +823,7 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w | |||
| glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); | |||
| #endif | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glnvg__bindTexture(gl, 0); | |||
| return 1; | |||
| } | |||
| @@ -917,10 +967,10 @@ static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image) | |||
| if (image != 0) { | |||
| GLNVGtexture* tex = glnvg__findTexture(gl, image); | |||
| glBindTexture(GL_TEXTURE_2D, tex != NULL ? tex->tex : 0); | |||
| glnvg__bindTexture(gl, tex != NULL ? tex->tex : 0); | |||
| glnvg__checkError(gl, "tex paint tex"); | |||
| } else { | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glnvg__bindTexture(gl, 0); | |||
| } | |||
| } | |||
| @@ -938,8 +988,8 @@ static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call) | |||
| // Draw shapes | |||
| glEnable(GL_STENCIL_TEST); | |||
| glStencilMask(0xff); | |||
| glStencilFunc(GL_ALWAYS, 0, 0xff); | |||
| glnvg__stencilMask(gl, 0xff); | |||
| glnvg__stencilFunc(gl, GL_ALWAYS, 0, 0xff); | |||
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); | |||
| // set bindpoint for solid loc | |||
| @@ -960,7 +1010,7 @@ static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call) | |||
| glnvg__checkError(gl, "fill fill"); | |||
| if (gl->flags & NVG_ANTIALIAS) { | |||
| glStencilFunc(GL_EQUAL, 0x00, 0xff); | |||
| glnvg__stencilFunc(gl, GL_EQUAL, 0x00, 0xff); | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | |||
| // Draw fringes | |||
| for (i = 0; i < npaths; i++) | |||
| @@ -968,7 +1018,7 @@ static void glnvg__fill(GLNVGcontext* gl, GLNVGcall* call) | |||
| } | |||
| // Draw fill | |||
| glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); | |||
| glnvg__stencilFunc(gl, GL_NOTEQUAL, 0x0, 0xff); | |||
| glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); | |||
| glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); | |||
| @@ -1000,10 +1050,10 @@ static void glnvg__stroke(GLNVGcontext* gl, GLNVGcall* call) | |||
| if (gl->flags & NVG_STENCIL_STROKES) { | |||
| glEnable(GL_STENCIL_TEST); | |||
| glStencilMask(0xff); | |||
| glnvg__stencilMask(gl, 0xff); | |||
| // Fill the stroke base without overlap | |||
| glStencilFunc(GL_EQUAL, 0x0, 0xff); | |||
| glnvg__stencilFunc(gl, GL_EQUAL, 0x0, 0xff); | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); | |||
| glnvg__setUniforms(gl, call->uniformOffset + gl->fragSize, call->image); | |||
| glnvg__checkError(gl, "stroke fill 0"); | |||
| @@ -1012,14 +1062,14 @@ static void glnvg__stroke(GLNVGcontext* gl, GLNVGcall* call) | |||
| // Draw anti-aliased pixels. | |||
| glnvg__setUniforms(gl, call->uniformOffset, call->image); | |||
| glStencilFunc(GL_EQUAL, 0x00, 0xff); | |||
| glnvg__stencilFunc(gl, GL_EQUAL, 0x00, 0xff); | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | |||
| for (i = 0; i < npaths; i++) | |||
| glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); | |||
| // Clear stencil buffer. | |||
| glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); | |||
| glStencilFunc(GL_ALWAYS, 0x0, 0xff); | |||
| glnvg__stencilFunc(gl, GL_ALWAYS, 0x0, 0xff); | |||
| glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); | |||
| glnvg__checkError(gl, "stroke fill 1"); | |||
| for (i = 0; i < npaths; i++) | |||
| @@ -1069,6 +1119,14 @@ static void glnvg__renderFlush(void* uptr) | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | |||
| glStencilFunc(GL_ALWAYS, 0, 0xffffffff); | |||
| glActiveTexture(GL_TEXTURE0); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| #if NANOVG_GL_USE_STATE_FILTER | |||
| gl->boundTexture = 0; | |||
| gl->stencilMask = 0xffffffff; | |||
| gl->stencilFunc = GL_ALWAYS; | |||
| gl->stencilFuncRef = 0; | |||
| gl->stencilFuncMask = 0xffffffff; | |||
| #endif | |||
| #if NANOVG_GL_USE_UNIFORMBUFFER | |||
| // Upload ubo for frag shaders | |||
| @@ -1115,7 +1173,7 @@ static void glnvg__renderFlush(void* uptr) | |||
| glDisable(GL_CULL_FACE); | |||
| glBindBuffer(GL_ARRAY_BUFFER, 0); | |||
| glUseProgram(0); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glnvg__bindTexture(gl, 0); | |||
| } | |||
| // Reset calls | |||