|
|
@@ -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 |
|
|
|