diff --git a/src/nanovg_gl3buf.h b/src/nanovg_gl3buf.h index 815b57d..fa82977 100644 --- a/src/nanovg_gl3buf.h +++ b/src/nanovg_gl3buf.h @@ -60,8 +60,8 @@ void nvgDeleteGL3(struct NVGcontext* ctx); #include "nanovg.h" enum GLNVGuniformLoc { - GLNVG_LOC_UBOVIEW, - GLNVG_LOC_UBOFRAG, + GLNVG_LOC_VIEW, + GLNVG_LOC_FRAG, GLNVG_MAX_LOCS }; @@ -73,8 +73,8 @@ enum GLNVGshaderType { }; enum GLNVGuniformBindings { - GLNVG_UBO_VIEW_BINDING = 0, - GLNVG_UBO_FRAG_BINDING = 1, + GLNVG_VIEW_BINDING = 0, + GLNVG_FRAG_BINDING = 1, }; struct GLNVGshader { @@ -100,14 +100,12 @@ enum GLNVGcallType { struct GLNVGcall { int type; + int image; int pathOffset; int pathCount; - struct NVGpaint paint; - struct NVGscissor scissor; - float strokeWidth; int triangleOffset; int triangleCount; - int uboOffset; + int uniformOffset; }; struct GLNVGpath { @@ -117,7 +115,7 @@ struct GLNVGpath { int strokeCount; }; -struct GLNVGuboFrag { +struct GLNVGfragUniforms { float scissorMat[12]; // matrices are actually 3 vec4s float paintMat[12]; float innerCol[4]; @@ -141,11 +139,12 @@ struct GLNVGcontext { int textureId; GLuint vertArr; GLuint vertBuf; - GLuint uboViewBuf; - GLuint uboFragBuf; - int uboPosAlignment; + GLuint viewBuf; + GLuint fragBuf; + int fragSize; int edgeAntiAlias; + // Per frame buffers struct GLNVGcall* calls; int ccalls; int ncalls; @@ -155,6 +154,9 @@ struct GLNVGcontext { struct NVGvertex* verts; int cverts; int nverts; + unsigned char* uniforms; + int cuniforms; + int nuniforms; }; @@ -237,18 +239,23 @@ static int glnvg__checkError(const char* str) return 0; } -static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* vshader, const char* fshader) +static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* header, const char* opts, const char* vshader, const char* fshader) { GLint status; GLuint prog, vert, frag; + const char* str[3]; + str[0] = header; + str[1] = opts != NULL ? opts : ""; memset(shader, 0, sizeof(*shader)); prog = glCreateProgram(); vert = glCreateShader(GL_VERTEX_SHADER); frag = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(vert, 1, &vshader, 0); - glShaderSource(frag, 1, &fshader, 0); + str[2] = vshader; + glShaderSource(vert, 3, str, 0); + str[2] = fshader; + glShaderSource(frag, 3, str, 0); glCompileShader(vert); glGetShaderiv(vert, GL_COMPILE_STATUS, &status); @@ -296,22 +303,25 @@ static void glnvg__deleteShader(struct GLNVGshader* shader) static void glnvg__getUniforms(struct GLNVGshader* shader) { - shader->loc[GLNVG_LOC_UBOVIEW] = glGetUniformBlockIndex(shader->prog, "uboView"); - shader->loc[GLNVG_LOC_UBOFRAG] = glGetUniformBlockIndex(shader->prog, "uboFrag"); + shader->loc[GLNVG_LOC_VIEW] = glGetUniformBlockIndex(shader->prog, "view"); + shader->loc[GLNVG_LOC_FRAG] = glGetUniformBlockIndex(shader->prog, "frag"); } static int glnvg__renderCreate(void* uptr) { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; + int align = 1; - static const char* fillVertShader = + static const char* shaderHeader = #ifdef NANOVG_GLES3 "#version 300 es\n" - "precision mediump float;\n" + "precision mediump float;\n"; #else - "#version 150 core\n" + "#version 150 core\n"; #endif - "layout(std140) uniform uboView {\n" + + static const char* fillVertShader = + "layout(std140) uniform view {\n" " vec2 viewSize;\n" "};\n" "in vec2 vertex;\n" @@ -325,13 +335,7 @@ static int glnvg__renderCreate(void* uptr) "}\n"; static const char* fillFragShaderEdgeAA = -#ifdef NANOVG_GLES3 - "#version 300 es\n" - "precision mediump float;\n" -#else - "#version 150 core\n" -#endif - "layout(std140) uniform uboFrag {\n" + "layout(std140) uniform frag {\n" " mat3 scissorMat;\n" " mat3 paintMat;\n" " vec4 innerCol;\n" @@ -362,16 +366,21 @@ static int glnvg__renderCreate(void* uptr) " sc = vec2(0.5,0.5) - sc * scissorScale;\n" " return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n" "}\n" - "\n" + "#ifdef EDGE_AA\n" "// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.\n" "float strokeMask() {\n" " return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * ftcoord.y;\n" "}\n" + "#endif\n" "\n" "void main(void) {\n" " if (type == 0) { // Gradient\n" " float scissor = scissorMask(fpos);\n" + "#ifdef EDGE_AA\n" " float strokeAlpha = strokeMask();\n" + "#else\n" + " float strokeAlpha = 1.0f;\n" + "#endif\n" " // Calculate gradient color using box gradient\n" " vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n" " float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n" @@ -381,7 +390,11 @@ static int glnvg__renderCreate(void* uptr) " outColor = color;\n" " } else if (type == 1) { // Image\n" " float scissor = scissorMask(fpos);\n" + "#ifdef EDGE_AA\n" " float strokeAlpha = strokeMask();\n" + "#else\n" + " float strokeAlpha = 1.0f;\n" + "#endif\n" " // Calculate color fron texture\n" " vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n" " vec4 color = texture(tex, pt);\n" @@ -392,75 +405,10 @@ static int glnvg__renderCreate(void* uptr) " } else if (type == 2) { // Stencil fill\n" " outColor = vec4(1,1,1,1);\n" " } else if (type == 3) { // Textured tris\n" - " vec4 color = texture(tex, ftcoord);\n" - " color = texType == 0 ? color : vec4(1,1,1,color.x);\n" - " outColor = color * innerCol;\n" - " }\n" - "}\n"; - - static const char* fillFragShader = -#ifdef NANOVG_GLES3 - "#version 300 es\n" - "precision mediump float;\n" -#else - "#version 150 core\n" -#endif - "layout(std140) uniform uboFrag {\n" - " mat3 scissorMat;\n" - " mat3 paintMat;\n" - " vec4 innerCol;\n" - " vec4 outerCol;\n" - " vec2 scissorExt;\n" - " vec2 scissorScale;\n" - " vec2 extent;\n" - " float radius;\n" - " float feather;\n" - " float strokeMult;\n" - " int texType;\n" - " int type;\n" - "};\n" - "uniform sampler2D tex;\n" - "in vec2 ftcoord;\n" - "in vec2 fpos;\n" - "out vec4 outColor;\n" - "\n" - "float sdroundrect(vec2 pt, vec2 ext, float rad) {\n" - " vec2 ext2 = ext - vec2(rad,rad);\n" - " vec2 d = abs(pt) - ext2;\n" - " return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;\n" - "}\n" - "\n" - "// Scissoring\n" - "float scissorMask(vec2 p) {\n" - " vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\n" - " sc = vec2(0.5,0.5) - sc * scissorScale;\n" - " return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n" - "}\n" - "\n" - "void main(void) {\n" - " if (type == 0) { // Gradient\n" - " float scissor = scissorMask(fpos);\n" - " // Calculate gradient color using box gradient\n" - " vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n" - " float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n" - " vec4 color = mix(innerCol,outerCol,d);\n" - " // Combine alpha\n" - " color.w *= scissor;\n" - " outColor = color;\n" - " } else if (type == 1) { // Image\n" " float scissor = scissorMask(fpos);\n" - " // Calculate color fron texture\n" - " vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n" - " vec4 color = texture(tex, pt);\n" - " color = texType == 0 ? color : vec4(1,1,1,color.x);\n" - " // Combine alpha\n" - " color.w *= scissor;\n" - " outColor = color;\n" - " } else if (type == 2) { // Stencil fill\n" - " outColor = vec4(1,1,1,1);\n" - " } else if (type == 3) { // Textured tris\n" " vec4 color = texture(tex, ftcoord);\n" " color = texType == 0 ? color : vec4(1,1,1,color.x);\n" + " color.w *= scissor;\n" " outColor = color * innerCol;\n" " }\n" "}\n"; @@ -468,10 +416,10 @@ static int glnvg__renderCreate(void* uptr) glnvg__checkError("init"); if (gl->edgeAntiAlias) { - if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShaderEdgeAA) == 0) + if (glnvg__createShader(&gl->shader, "shader", shaderHeader, "#define EDGE_AA 1\n", fillVertShader, fillFragShaderEdgeAA) == 0) return 0; } else { - if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0) + if (glnvg__createShader(&gl->shader, "shader", shaderHeader, NULL, fillVertShader, fillFragShaderEdgeAA) == 0) return 0; } @@ -483,12 +431,12 @@ static int glnvg__renderCreate(void* uptr) glGenBuffers(1, &gl->vertBuf); // Create UBOs - glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_UBOVIEW], GLNVG_UBO_VIEW_BINDING); - glGenBuffers(1, &gl->uboViewBuf); - glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_UBOFRAG], GLNVG_UBO_FRAG_BINDING); - glGenBuffers(1, &gl->uboFragBuf); - glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &gl->uboPosAlignment); - gl->uboPosAlignment = sizeof(struct GLNVGuboFrag) + gl->uboPosAlignment - sizeof(struct GLNVGuboFrag) % gl->uboPosAlignment; + glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_VIEW], GLNVG_VIEW_BINDING); + glGenBuffers(1, &gl->viewBuf); + glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_FRAG], GLNVG_FRAG_BINDING); + glGenBuffers(1, &gl->fragBuf); + glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align); + gl->fragSize = sizeof(struct GLNVGfragUniforms) + align - sizeof(struct GLNVGfragUniforms) % align; glnvg__checkError("done"); @@ -613,60 +561,55 @@ static void glnvg__xformToMat3x4(float* m3, float* t) m3[11] = 0.0f; } -static int glnvg__setupPaintUBO(struct GLNVGcontext* gl, struct NVGpaint* paint, struct NVGscissor* scissor, float width, struct GLNVGuboFrag* uboBuff) +static int glnvg__convertPaint(struct GLNVGcontext* gl, struct GLNVGfragUniforms* frag, struct NVGpaint* paint, struct NVGscissor* scissor, float width) { - struct GLNVGuboFrag ubo; - glnvg__toFloatColor(ubo.innerCol, paint->innerColor); - glnvg__toFloatColor(ubo.outerCol, paint->outerColor); struct GLNVGtexture* tex = NULL; float invxform[6]; + glnvg__toFloatColor(frag->innerCol, paint->innerColor); + glnvg__toFloatColor(frag->outerCol, paint->outerColor); + glnvg__xformInverse(invxform, paint->xform); - glnvg__xformToMat3x4(ubo.paintMat, invxform); + glnvg__xformToMat3x4(frag->paintMat, invxform); if (scissor->extent[0] < 0.5f || scissor->extent[1] < 0.5f) { - memset(ubo.scissorMat, 0, sizeof(ubo.scissorMat)); - ubo.scissorExt[0] = 1.0f; - ubo.scissorExt[1] = 1.0f; - ubo.scissorScale[0] = 1.0f; - ubo.scissorScale[1] = 1.0f; + memset(frag->scissorMat, 0, sizeof(frag->scissorMat)); + frag->scissorExt[0] = 1.0f; + frag->scissorExt[1] = 1.0f; + frag->scissorScale[0] = 1.0f; + frag->scissorScale[1] = 1.0f; } else { glnvg__xformInverse(invxform, scissor->xform); - glnvg__xformToMat3x4(ubo.scissorMat, invxform); - ubo.scissorExt[0] = scissor->extent[0]; - ubo.scissorExt[1] = scissor->extent[1]; - ubo.scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]); - ubo.scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]); + glnvg__xformToMat3x4(frag->scissorMat, invxform); + frag->scissorExt[0] = scissor->extent[0]; + frag->scissorExt[1] = scissor->extent[1]; + frag->scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]); + frag->scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]); } - memcpy( ubo.extent, paint->extent, sizeof( ubo.extent ) ); - ubo.strokeMult = width*0.5f + 0.5f; + memcpy(frag->extent, paint->extent, sizeof(frag->extent)); + frag->strokeMult = width*0.5f + 0.5f; if (paint->image != 0) { tex = glnvg__findTexture(gl, paint->image); if (tex == NULL) return 0; - ubo.type = NSVG_SHADER_FILLIMG; - ubo.texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; - glnvg__checkError("tex paint loc"); + frag->type = NSVG_SHADER_FILLIMG; + frag->texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; } else { - ubo.type = NSVG_SHADER_FILLGRAD; - ubo.radius = paint->radius; - ubo.feather = paint->feather; - glnvg__checkError("grad paint loc"); + frag->type = NSVG_SHADER_FILLGRAD; + frag->radius = paint->radius; + frag->feather = paint->feather; } - *uboBuff = ubo; return 1; } -static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, int uboOffset) +static void glnvg__setUniforms(struct GLNVGcontext* gl, int uniformOffset, int image) { - glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, uboOffset, sizeof(struct GLNVGuboFrag)); - if (paint->image != 0) { - struct GLNVGtexture* tex = glnvg__findTexture(gl, paint->image); - if (tex == NULL) return 0; - glBindTexture(GL_TEXTURE_2D, tex->tex); + glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_FRAG_BINDING, gl->fragBuf, uniformOffset, sizeof(struct GLNVGfragUniforms)); + if (image != 0) { + struct GLNVGtexture* tex = glnvg__findTexture(gl, image); + glBindTexture(GL_TEXTURE_2D, tex != NULL ? tex->tex : 0); glnvg__checkError("tex paint tex"); } - return 1; } static void glnvg__renderViewport(void* uptr, int width, int height) @@ -679,7 +622,7 @@ static void glnvg__renderViewport(void* uptr, int width, int height) static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) { struct GLNVGpath* paths = &gl->paths[call->pathOffset]; - int npaths = call->pathCount, i; + int i, npaths = call->pathCount; // Draw shapes glDisable(GL_BLEND); @@ -689,8 +632,8 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // set bindpoint for solid loc - glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, call->uboOffset, sizeof(struct GLNVGuboFrag)); - glnvg__checkError("fill solid loc"); + glnvg__setUniforms(gl, call->uniformOffset, 0); + glnvg__checkError("fill simple"); glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); @@ -703,7 +646,8 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_BLEND); - glnvg__setupPaint(gl, &call->paint, call->uboOffset + gl->uboPosAlignment); + glnvg__setUniforms(gl, call->uniformOffset + gl->fragSize, call->image); + glnvg__checkError("fill fill"); if (gl->edgeAntiAlias) { glStencilFunc(GL_EQUAL, 0x00, 0xff); @@ -724,9 +668,10 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) static void glnvg__convexFill(struct GLNVGcontext* gl, struct GLNVGcall* call) { struct GLNVGpath* paths = &gl->paths[call->pathOffset]; - int npaths = call->pathCount, i; + int i, npaths = call->pathCount; - glnvg__setupPaint(gl, &call->paint, call->uboOffset); + glnvg__setUniforms(gl, call->uniformOffset, call->image); + glnvg__checkError("convex fill"); for (i = 0; i < npaths; i++) glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); @@ -742,7 +687,8 @@ static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call) struct GLNVGpath* paths = &gl->paths[call->pathOffset]; int npaths = call->pathCount, i; - glnvg__setupPaint(gl, &call->paint, call->uboOffset); + glnvg__setUniforms(gl, call->uniformOffset, call->image); + glnvg__checkError("stroke fill"); // Draw Strokes for (i = 0; i < npaths; i++) @@ -751,57 +697,25 @@ static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call) static void glnvg__triangles(struct GLNVGcontext* gl, struct GLNVGcall* call) { - struct GLNVGtexture* tex = glnvg__findTexture(gl, call->paint.image); - if (tex != NULL) - glBindTexture(GL_TEXTURE_2D, tex->tex); - - glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, call->uboOffset, sizeof(struct GLNVGuboFrag)); + glnvg__setUniforms(gl, call->uniformOffset, call->image); + glnvg__checkError("triangles fill"); - glnvg__checkError("tris solid img loc"); glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); } static void glnvg__renderFlush(void* uptr) { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; - int i, offset; - char* buff; + int i; if (gl->ncalls > 0) { glUseProgram(gl->shader.prog); glEnable(GL_CULL_FACE); - // upload ubo for frag shaders - maximum ubos is 2x num calls - glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf); - glBufferData(GL_UNIFORM_BUFFER, 2 * gl->ncalls * gl->uboPosAlignment, 0, GL_STREAM_DRAW); - buff = (char*)glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY); - offset = 0; - for (i = 0; i < gl->ncalls; i++) { - struct GLNVGcall* call = &gl->calls[i]; - struct GLNVGuboFrag* ubo = (struct GLNVGuboFrag*)&buff[offset]; - call->uboOffset = offset; - if (call->type == GLNVG_FILL) { - ubo->type = NSVG_SHADER_SIMPLE; - offset += gl->uboPosAlignment; - ubo = (struct GLNVGuboFrag*)&buff[offset]; - glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, 1.0001f, ubo); - offset += gl->uboPosAlignment; - } else if (call->type == GLNVG_CONVEXFILL) { - glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, 1.0001f, ubo); - offset += gl->uboPosAlignment; - } else if (call->type == GLNVG_STROKE) { - glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, call->strokeWidth, ubo); - offset += gl->uboPosAlignment; - } else if (call->type == GLNVG_TRIANGLES) { - struct GLNVGtexture* tex = glnvg__findTexture(gl, call->paint.image); - glnvg__toFloatColor(ubo->innerCol, call->paint.innerColor); - ubo->texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; - ubo->type = NSVG_SHADER_IMG; - offset += gl->uboPosAlignment; - } - } - glUnmapBuffer(GL_UNIFORM_BUFFER); + // Upload ubo for frag shaders + glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf); + glBufferData(GL_UNIFORM_BUFFER, gl->nuniforms * gl->fragSize, gl->uniforms, GL_STREAM_DRAW); // Upload vertex data glBindVertexArray(gl->vertArr); @@ -813,12 +727,12 @@ static void glnvg__renderFlush(void* uptr) glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(0 + 2*sizeof(float))); // once per frame set ubo for view - glBindBuffer(GL_UNIFORM_BUFFER, gl->uboViewBuf); + glBindBuffer(GL_UNIFORM_BUFFER, gl->viewBuf); glBufferData(GL_UNIFORM_BUFFER, sizeof(gl->view), 0, GL_STREAM_DRAW); glBufferData(GL_UNIFORM_BUFFER, sizeof(gl->view), gl->view, GL_STREAM_DRAW); - glBindBufferBase(GL_UNIFORM_BUFFER, GLNVG_UBO_VIEW_BINDING, gl->uboViewBuf); + glBindBufferBase(GL_UNIFORM_BUFFER, GLNVG_VIEW_BINDING, gl->viewBuf); - glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf); + glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf); for (i = 0; i < gl->ncalls; i++) { struct GLNVGcall* call = &gl->calls[i]; @@ -841,6 +755,7 @@ static void glnvg__renderFlush(void* uptr) gl->nverts = 0; gl->npaths = 0; gl->ncalls = 0; + gl->nuniforms = 0; } static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths) @@ -891,6 +806,23 @@ static int glnvg__allocVerts(struct GLNVGcontext* gl, int n) return ret; } +static int glnvg__allocFragUniforms(struct GLNVGcontext* gl, int n) +{ + int ret = 0, structSize = gl->fragSize; + if (gl->nuniforms+n > gl->cuniforms) { + gl->cuniforms = gl->cuniforms == 0 ? glnvg__maxi(n, 32) : gl->cuniforms * 2; + gl->uniforms = (unsigned char*)realloc(gl->uniforms, gl->cuniforms * structSize); + } + ret = gl->nuniforms * structSize; + gl->nuniforms += n; + return ret; +} + +static struct GLNVGfragUniforms* nvg__fragUniformPtr(struct GLNVGcontext* gl, int i) +{ + return (struct GLNVGfragUniforms*)&gl->uniforms[i]; +} + static void glnvg__vset(struct NVGvertex* vtx, float x, float y, float u, float v) { vtx->x = x; @@ -905,41 +837,41 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; struct GLNVGcall* call = glnvg__allocCall(gl); struct NVGvertex* quad; - int i, maxverts, vertsoff; + struct GLNVGfragUniforms* frag; + int i, maxverts, offset; call->type = GLNVG_FILL; call->pathOffset = glnvg__allocPaths(gl, npaths); call->pathCount = npaths; - call->paint = *paint; - call->scissor = *scissor; + call->image = paint->image; if (npaths == 1 && paths[0].convex) call->type = GLNVG_CONVEXFILL; // Allocate vertices for all the paths. maxverts = glnvg__maxVertCount(paths, npaths); - vertsoff = glnvg__allocVerts(gl, maxverts + 6); + offset = glnvg__allocVerts(gl, maxverts + 6); for (i = 0; i < npaths; i++) { struct GLNVGpath* copy = &gl->paths[call->pathOffset + i]; const struct NVGpath* path = &paths[i]; memset(copy, 0, sizeof(struct GLNVGpath)); if (path->nfill) { - copy->fillOffset = vertsoff; + copy->fillOffset = offset; copy->fillCount = path->nfill; - memcpy(&gl->verts[vertsoff], path->fill, sizeof(struct NVGvertex) * path->nfill); - vertsoff += path->nfill; + memcpy(&gl->verts[offset], path->fill, sizeof(struct NVGvertex) * path->nfill); + offset += path->nfill; } if (path->nstroke) { - copy->strokeOffset = vertsoff; + copy->strokeOffset = offset; copy->strokeCount = path->nstroke; - memcpy(&gl->verts[vertsoff], path->stroke, sizeof(struct NVGvertex) * path->nstroke); - vertsoff += path->nstroke; + memcpy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke); + offset += path->nstroke; } } // Quad - call->triangleOffset = vertsoff; + call->triangleOffset = offset; call->triangleCount = 6; quad = &gl->verts[call->triangleOffset]; glnvg__vset(&quad[0], bounds[0], bounds[3], 0.5f, 1.0f); @@ -949,37 +881,53 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis 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) { + call->uniformOffset = glnvg__allocFragUniforms(gl, 2); + // Simple shader for stencil + frag = nvg__fragUniformPtr(gl, call->uniformOffset); + frag->type = NSVG_SHADER_SIMPLE; + // Fill shader + glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, 1.0001f); + } else { + call->uniformOffset = glnvg__allocFragUniforms(gl, 1); + // Fill shader + glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, 1.0001f); + } } static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, - float width, const struct NVGpath* paths, int npaths) + float strokeWidth, const struct NVGpath* paths, int npaths) { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; struct GLNVGcall* call = glnvg__allocCall(gl); - int i, maxverts, vertsoff; + int i, maxverts, offset; call->type = GLNVG_STROKE; call->pathOffset = glnvg__allocPaths(gl, npaths); call->pathCount = npaths; - call->paint = *paint; - call->scissor = *scissor; - call->strokeWidth = width; + call->image = paint->image; // Allocate vertices for all the paths. maxverts = glnvg__maxVertCount(paths, npaths); - vertsoff = glnvg__allocVerts(gl, maxverts + 6); + offset = glnvg__allocVerts(gl, maxverts + 6); for (i = 0; i < npaths; i++) { struct GLNVGpath* copy = &gl->paths[call->pathOffset + i]; const struct NVGpath* path = &paths[i]; memset(copy, 0, sizeof(struct GLNVGpath)); if (path->nstroke) { - copy->strokeOffset = vertsoff; + copy->strokeOffset = offset; copy->strokeCount = path->nstroke; - memcpy(&gl->verts[vertsoff], path->stroke, sizeof(struct NVGvertex) * path->nstroke); - vertsoff += path->nstroke; + memcpy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke); + offset += path->nstroke; } } + + // Fill shader + call->uniformOffset = glnvg__allocFragUniforms(gl, 1); + glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, strokeWidth); } static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, @@ -987,15 +935,21 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; struct GLNVGcall* call = glnvg__allocCall(gl); + struct GLNVGfragUniforms* frag; call->type = GLNVG_TRIANGLES; - call->paint = *paint; - call->scissor = *scissor; + call->image = paint->image; // Allocate vertices for all the paths. call->triangleOffset = glnvg__allocVerts(gl, nverts); call->triangleCount = nverts; memcpy(&gl->verts[call->triangleOffset], verts, sizeof(struct NVGvertex) * nverts); + + // Fill shader + call->uniformOffset = glnvg__allocFragUniforms(gl, 1); + frag = nvg__fragUniformPtr(gl, call->uniformOffset); + glnvg__convertPaint(gl, frag, paint, scissor, 1.0f); + frag->type = NSVG_SHADER_IMG; } static void glnvg__renderDelete(void* uptr) @@ -1006,6 +960,15 @@ static void glnvg__renderDelete(void* uptr) glnvg__deleteShader(&gl->shader); + if (gl->vertArr != 0) + glDeleteVertexArrays(1, &gl->vertArr); + if (gl->vertBuf != 0) + glDeleteBuffers(1, &gl->vertBuf); + if (gl->viewBuf != 0) + glDeleteBuffers(1, &gl->viewBuf); + if (gl->fragBuf != 0) + glDeleteBuffers(1, &gl->fragBuf); + for (i = 0; i < gl->ntextures; i++) { if (gl->textures[i].tex != 0) glDeleteTextures(1, &gl->textures[i].tex);