diff --git a/example/example_gl2.c b/example/example_gl2.c index 2ab8e0d..4627882 100644 --- a/example/example_gl2.c +++ b/example/example_gl2.c @@ -87,7 +87,10 @@ int main() if (loadDemoData(vg, &data) == -1) return -1; + glfwSwapInterval(0); + glfwSetTime(0); + prevt = glfwGetTime(); while (!glfwWindowShouldClose(window)) { diff --git a/example/example_gl3.c b/example/example_gl3.c index c135b07..3a53d84 100644 --- a/example/example_gl3.c +++ b/example/example_gl3.c @@ -91,6 +91,8 @@ int main() if (loadDemoData(vg, &data) == -1) return -1; + glfwSwapInterval(0); + glfwSetTime(0); prevt = glfwGetTime(); diff --git a/src/nanovg.c b/src/nanovg.c index af72815..9453404 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -941,7 +941,7 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m) struct NVGpoint* p1; struct NVGpoint* pts; struct NVGpath* path; - int i, j; + int i, j, nleft; float* cp1; float* cp2; float* p; @@ -1035,6 +1035,7 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m) path = &cache->paths[j]; pts = &cache->points[path->first]; path->nbevel = 0; + nleft = 0; p0 = &pts[path->count-1]; p1 = &pts[0]; @@ -1058,12 +1059,15 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m) if ((dmr2 * m*m) < 1.0f) { cross = p1->dx * p0->dy - p0->dx * p1->dy; p1->flags |= NVG_BEVEL; - if (cross < 0) + if (cross < 0) { p1->flags |= NVG_LEFT; + nleft++; + } path->nbevel++; } p0 = p1++; } + path->convex = nleft == 0 ? 1 : 0; } } @@ -1077,6 +1081,7 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) struct NVGpoint* p0; struct NVGpoint* p1; int nstroke, cverts; + int convex = 0; int i, j, s, e; float wo = 0; @@ -1101,6 +1106,7 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) path = &cache->paths[i]; pts = &cache->points[path->first]; nstroke = (path->count + path->nbevel + 1) * 2; + convex = 0; // Calculate shape vertices. if (feats & NVG_FILL) { @@ -1138,6 +1144,8 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) path->nfill = (int)(dst - verts); verts += path->nfill; + if (path->convex && cache->npaths == 1) + convex = 1; } else { wo = 0.0f; path->fill = 0; @@ -1146,11 +1154,19 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) // Calculate fringe if (feats & NVG_STROKE) { - float lw = w + wo; float rw = w - wo; + float lw = w + wo, rw = w - wo; + float u0 = 0, u1 = 1; int loop = ((feats & NVG_CAPS) && path->closed == 0) ? 0 : 1; dst = verts; path->stroke = dst; + // Create only half a fringe for convex shapes so that + // the shape can be rendered without stenciling. + if (convex) { + lw = wo; // This should generate the same vertex as fill inset above. + u1 = 0.5f; // Set outline fade at middle. + } + if (loop) { // Looping p0 = &pts[path->count-1]; @@ -1173,10 +1189,10 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) nvg__normalize(&dx, &dy); dlx = dy; dly = -dx; - nvg__vset(dst, p0->x + dlx*rw - dx*NVG_AA, p0->y + dly*rw - dy*NVG_AA, 0,0); dst++; - nvg__vset(dst, p0->x - dlx*lw - dx*NVG_AA, p0->y - dly*lw - dy*NVG_AA, 1,0); dst++; - nvg__vset(dst, p0->x + dlx*rw, p0->y + dly * rw, 0,1); dst++; - nvg__vset(dst, p0->x - dlx*lw, p0->y - dly * lw, 1,1); dst++; + nvg__vset(dst, p0->x + dlx*rw - dx*NVG_AA, p0->y + dly*rw - dy*NVG_AA, u0,0); dst++; + nvg__vset(dst, p0->x - dlx*lw - dx*NVG_AA, p0->y - dly*lw - dy*NVG_AA, u1,0); dst++; + nvg__vset(dst, p0->x + dlx*rw, p0->y + dly * rw, u0,1); dst++; + nvg__vset(dst, p0->x - dlx*lw, p0->y - dly * lw, u1,1); dst++; } for (j = s; j < e; ++j) { @@ -1192,10 +1208,10 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) float ry1 = p1->y + dly1 * rw; float lx = p1->x - p1->dmx * lw; float ly = p1->y - p1->dmy * lw; - nvg__vset(dst, rx0, ry0, 0,1); dst++; - nvg__vset(dst, lx, ly, 1,1); dst++; - nvg__vset(dst, rx1, ry1, 0,1); dst++; - nvg__vset(dst, lx, ly, 1,1); dst++; + nvg__vset(dst, rx0, ry0, u0,1); dst++; + nvg__vset(dst, lx, ly, u1,1); dst++; + nvg__vset(dst, rx1, ry1, u0,1); dst++; + nvg__vset(dst, lx, ly, u1,1); dst++; } else { float rx = p1->x + p1->dmx * rw; float ry = p1->y + p1->dmy * rw; @@ -1203,22 +1219,22 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) float ly0 = p1->y - dly0 * lw; float lx1 = p1->x - dlx1 * lw; float ly1 = p1->y - dly1 * lw; - nvg__vset(dst, rx, ry, 0,1); dst++; - nvg__vset(dst, lx0, ly0, 1,1); dst++; - nvg__vset(dst, rx, ry, 0,1); dst++; - nvg__vset(dst, lx1, ly1, 1,1); dst++; + nvg__vset(dst, rx, ry, u0,1); dst++; + nvg__vset(dst, lx0, ly0, u1,1); dst++; + nvg__vset(dst, rx, ry, u0,1); dst++; + nvg__vset(dst, lx1, ly1, u1,1); dst++; } } else { - nvg__vset(dst, p1->x + (p1->dmx * rw), p1->y + (p1->dmy * rw), 0,1); dst++; - nvg__vset(dst, p1->x - (p1->dmx * lw), p1->y - (p1->dmy * lw), 1,1); dst++; + nvg__vset(dst, p1->x + (p1->dmx * rw), p1->y + (p1->dmy * rw), u0,1); dst++; + nvg__vset(dst, p1->x - (p1->dmx * lw), p1->y - (p1->dmy * lw), u1,1); dst++; } p0 = p1++; } if (loop) { // Loop it - nvg__vset(dst, verts[0].x, verts[0].y, 0,1); dst++; - nvg__vset(dst, verts[1].x, verts[1].y, 1,1); dst++; + nvg__vset(dst, verts[0].x, verts[0].y, u0,1); dst++; + nvg__vset(dst, verts[1].x, verts[1].y, u1,1); dst++; } else { // Add cap float dx, dy, dlx, dly; @@ -1227,10 +1243,10 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) nvg__normalize(&dx, &dy); dlx = dy; dly = -dx; - nvg__vset(dst, p1->x + dlx*rw, p1->y + dly * rw, 0,1); dst++; - nvg__vset(dst, p1->x - dlx*lw, p1->y - dly * lw, 1,1); dst++; - nvg__vset(dst, p1->x + dlx*rw + dx*NVG_AA, p1->y + dly*rw + dy*NVG_AA, 0,0); dst++; - nvg__vset(dst, p1->x - dlx*lw + dx*NVG_AA, p1->y - dly*lw + dy*NVG_AA, 1,0); dst++; + nvg__vset(dst, p1->x + dlx*rw, p1->y + dly * rw, u0,1); dst++; + nvg__vset(dst, p1->x - dlx*lw, p1->y - dly * lw, u1,1); dst++; + nvg__vset(dst, p1->x + dlx*rw + dx*NVG_AA, p1->y + dly*rw + dy*NVG_AA, u0,0); dst++; + nvg__vset(dst, p1->x - dlx*lw + dx*NVG_AA, p1->y - dly*lw + dy*NVG_AA, u1,0); dst++; } path->nstroke = (int)(dst - verts); diff --git a/src/nanovg.h b/src/nanovg.h index f408b59..fabe79c 100644 --- a/src/nanovg.h +++ b/src/nanovg.h @@ -387,6 +387,7 @@ struct NVGpath { struct NVGvertex* stroke; int nstroke; int winding; + int convex; }; struct NVGparams { diff --git a/src/nanovg_gl2.h b/src/nanovg_gl2.h index 8473c75..25272e8 100644 --- a/src/nanovg_gl2.h +++ b/src/nanovg_gl2.h @@ -486,85 +486,104 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis if (gl->gradShader.prog == 0) return; - glEnable(GL_CULL_FACE); + if (npaths == 1 && paths[0].convex) { - glEnableClientState(GL_VERTEX_ARRAY); + glEnable(GL_CULL_FACE); - // Draw shapes - glDisable(GL_BLEND); - glEnable(GL_STENCIL_TEST); - glStencilMask(0xff); - glStencilFunc(GL_ALWAYS, 0, ~0); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glEnableClientState(GL_VERTEX_ARRAY); - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glDisable(GL_CULL_FACE); - for (i = 0; i < npaths; i++) { - path = &paths[i]; - glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x); - glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); - } + glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); -/* glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glCullFace(GL_BACK); + // Fill + glDisable(GL_CULL_FACE); + glTexCoord2f(0.5f,1.0f); + for (i = 0; i < npaths; i++) { + path = &paths[i]; + glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x); + glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); + } - for (i = 0; i < npaths; i++) { - path = &paths[i]; - glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x); - glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); - } + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnable(GL_CULL_FACE); - glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glCullFace(GL_FRONT); + // Draw fringes + for (i = 0; i < npaths; i++) { + path = &paths[i]; + glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].x); + glTexCoordPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].u); + glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke); + } - for (i = 0; i < npaths; i++) { - path = &paths[i]; - glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x); - glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); - } - glCullFace(GL_BACK);*/ + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glEnable(GL_CULL_FACE); + glUseProgram(0); + + glDisable(GL_TEXTURE_2D); + + } else { + + glEnable(GL_CULL_FACE); + + glEnableClientState(GL_VERTEX_ARRAY); + + // Draw shapes + glDisable(GL_BLEND); + glEnable(GL_STENCIL_TEST); + glStencilMask(0xff); + glStencilFunc(GL_ALWAYS, 0, ~0); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); + glDisable(GL_CULL_FACE); + for (i = 0; i < npaths; i++) { + path = &paths[i]; + glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->fill[0].x); + glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); + } - // Draw aliased off-pixels - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glEnable(GL_BLEND); + glEnable(GL_CULL_FACE); - glStencilFunc(GL_EQUAL, 0x00, 0xff); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + // Draw aliased off-pixels + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glEnable(GL_BLEND); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glStencilFunc(GL_EQUAL, 0x00, 0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); - // Draw fringes - for (i = 0; i < npaths; i++) { - path = &paths[i]; - glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].x); - glTexCoordPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].u); - glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke); - } + glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + // Draw fringes + for (i = 0; i < npaths; i++) { + path = &paths[i]; + glVertexPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].x); + glTexCoordPointer(2, GL_FLOAT, sizeof(struct NVGvertex), &path->stroke[0].u); + glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke); + } - // Draw fill - glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glBegin(GL_QUADS); - glTexCoord2f(0.5f,1.0f); - glVertex2f(bounds[0], bounds[3]); - glVertex2f(bounds[2], bounds[3]); - glVertex2f(bounds[2], bounds[1]); - glVertex2f(bounds[0], bounds[1]); - glEnd(); + // Draw fill + glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - glUseProgram(0); + glBegin(GL_QUADS); + glTexCoord2f(0.5f,1.0f); + glVertex2f(bounds[0], bounds[3]); + glVertex2f(bounds[2], bounds[3]); + glVertex2f(bounds[2], bounds[1]); + glVertex2f(bounds[0], bounds[1]); + glEnd(); - glDisable(GL_TEXTURE_2D); - glDisable(GL_STENCIL_TEST); + glUseProgram(0); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_STENCIL_TEST); + } } static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize, diff --git a/src/nanovg_gl3.h b/src/nanovg_gl3.h index 7134567..1975f5c 100644 --- a/src/nanovg_gl3.h +++ b/src/nanovg_gl3.h @@ -231,15 +231,6 @@ static void glnvg__getUniforms(struct GLNVGshader* shader) shader->loc[GLNVG_LOC_TEXTYPE] = glGetUniformLocation(shader->prog, "texType"); } - -static void glnvg__resizeVertexBuffer(struct GLNVGcontext* gl, int size) -{ - glBindVertexArray(gl->vertArr); - glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); - glBufferData(GL_ARRAY_BUFFER, size * sizeof(struct NVGvertex), 0, GL_STREAM_DRAW); - gl->vertArrSize = size; -} - static int glnvg__renderCreate(void* uptr) { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; @@ -577,97 +568,159 @@ static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths) { int i, count = 0; for (i = 0; i < npaths; i++) { - if (paths[i].nfill > count) count = paths[i].nfill; - if (paths[i].nstroke > count) count = paths[i].nstroke; + count += paths[i].nfill; + count += paths[i].nstroke; } return count; } +static void glnvg__uploadPaths(const struct NVGpath* paths, int npaths) +{ + const struct NVGpath* path; + int i, n = 0; + for (i = 0; i < npaths; i++) { + path = &paths[i]; + if (path->nfill > 0) { + glBufferSubData(GL_ARRAY_BUFFER, n*sizeof(struct NVGvertex), path->nfill * sizeof(struct NVGvertex), &path->fill[0].x); + n += path->nfill; + } + if (path->nstroke > 0) { + glBufferSubData(GL_ARRAY_BUFFER, n*sizeof(struct NVGvertex), path->nstroke * sizeof(struct NVGvertex), &path->stroke[0].x); + n += path->nstroke; + } + } +} + static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize, const float* bounds, const struct NVGpath* paths, int npaths) { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; const struct NVGpath* path; - int i, maxCount; - - maxCount = glnvg__maxVertCount(paths, npaths); - if (maxCount > gl->vertArrSize) - glnvg__resizeVertexBuffer(gl, maxCount); + int i, n, offset, maxCount; if (gl->gradShader.prog == 0) return; - glEnable(GL_CULL_FACE); - + maxCount = glnvg__maxVertCount(paths, npaths); glBindVertexArray(gl->vertArr); glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); + glBufferData(GL_ARRAY_BUFFER, maxCount * sizeof(struct NVGvertex), NULL, GL_STREAM_DRAW); + glnvg__uploadPaths(paths, npaths); + + if (npaths == 1 && paths[0].convex) { + + glEnable(GL_CULL_FACE); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); + + glDisable(GL_CULL_FACE); + n = 0; + for (i = 0; i < npaths; i++) { + path = &paths[i]; + offset = n * sizeof(struct NVGvertex); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float))); + glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); + n += path->nfill + path->nstroke; + } - // Draw shapes - glDisable(GL_BLEND); - glEnable(GL_STENCIL_TEST); - glStencilMask(0xff); - glStencilFunc(GL_ALWAYS, 0, ~0); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glEnable(GL_CULL_FACE); + + // Draw fringes + n = 0; + for (i = 0; i < npaths; i++) { + path = &paths[i]; + offset = (n + path->nfill) * sizeof(struct NVGvertex); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float))); + glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke); + n += path->nfill + path->nstroke; + } - glUseProgram(gl->solidShader.prog); - glUniform2f(gl->solidShader.loc[GLNVG_LOC_VIEWPOS], 0, 0); - glUniform2f(gl->solidShader.loc[GLNVG_LOC_VIEWSIZE], gl->viewWidth, gl->viewHeight); - glnvg__checkError("fill solid loc"); + glUseProgram(0); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); - glEnableVertexAttribArray(0); + } else { - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glDisable(GL_CULL_FACE); - for (i = 0; i < npaths; i++) { - path = &paths[i]; - glBufferSubData(GL_ARRAY_BUFFER, 0, path->nfill * sizeof(struct NVGvertex), &path->fill[0].x); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)0); - glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); - } + glEnable(GL_CULL_FACE); + + glBindVertexArray(gl->vertArr); + glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); + + // Draw shapes + glDisable(GL_BLEND); + glEnable(GL_STENCIL_TEST); + glStencilMask(0xff); + glStencilFunc(GL_ALWAYS, 0, ~0); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + glUseProgram(gl->solidShader.prog); + glUniform2f(gl->solidShader.loc[GLNVG_LOC_VIEWPOS], 0, 0); + glUniform2f(gl->solidShader.loc[GLNVG_LOC_VIEWSIZE], gl->viewWidth, gl->viewHeight); + glnvg__checkError("fill solid loc"); + + glEnableVertexAttribArray(0); + + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); + glDisable(GL_CULL_FACE); + n = 0; + for (i = 0; i < npaths; i++) { + path = &paths[i]; + offset = n * sizeof(struct NVGvertex); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset); + glDrawArrays(GL_TRIANGLE_FAN, 0, path->nfill); + n += path->nfill + path->nstroke; + } - glEnable(GL_CULL_FACE); + glEnable(GL_CULL_FACE); - // Draw aliased off-pixels - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glEnable(GL_BLEND); + // Draw aliased off-pixels + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glEnable(GL_BLEND); - glStencilFunc(GL_EQUAL, 0x00, 0xff); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_EQUAL, 0x00, 0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glEnableVertexAttribArray(1); + glEnableVertexAttribArray(1); - glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); + glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); - // Draw fringes - for (i = 0; i < npaths; i++) { - path = &paths[i]; - glBufferSubData(GL_ARRAY_BUFFER, 0, path->nstroke * sizeof(struct NVGvertex), &path->stroke[0].x); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(2 * sizeof(float))); - glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke); - } + // Draw fringes + n = 0; + for (i = 0; i < npaths; i++) { + path = &paths[i]; + offset = (n + path->nfill) * sizeof(struct NVGvertex); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float))); + glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke); + n += path->nfill + path->nstroke; + } - // Draw fill - glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + // Draw fill + glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - glDisableVertexAttribArray(1); + glDisableVertexAttribArray(1); - float quad[6*2] = { - bounds[0], bounds[3], bounds[2], bounds[3], bounds[2], bounds[1], - bounds[0], bounds[3], bounds[2], bounds[1], bounds[0], bounds[1], - }; - glBufferSubData(GL_ARRAY_BUFFER, 0, 6 * 2*sizeof(float), quad); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (const GLvoid*)0); - glVertexAttrib2f(1, 0.5f, 1.0f); - glDrawArrays(GL_TRIANGLES, 0, 6); + float quad[6*2] = { + bounds[0], bounds[3], bounds[2], bounds[3], bounds[2], bounds[1], + bounds[0], bounds[3], bounds[2], bounds[1], bounds[0], bounds[1], + }; + glBufferSubData(GL_ARRAY_BUFFER, 0, 6 * 2*sizeof(float), quad); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (const GLvoid*)0); + glVertexAttrib2f(1, 0.5f, 1.0f); + glDrawArrays(GL_TRIANGLES, 0, 6); - glUseProgram(0); + glUseProgram(0); - glDisableVertexAttribArray(0); + glDisableVertexAttribArray(0); - glDisable(GL_STENCIL_TEST); + glDisable(GL_STENCIL_TEST); + } } static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize, @@ -675,11 +728,7 @@ static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGsc { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; const struct NVGpath* path; - int i, maxCount; - - maxCount = glnvg__maxVertCount(paths, npaths); - if (maxCount > gl->vertArrSize) - glnvg__resizeVertexBuffer(gl, maxCount); + int i, n, offset, maxCount; if (gl->gradShader.prog == 0) return; @@ -688,19 +737,24 @@ static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGsc glEnable(GL_CULL_FACE); + maxCount = glnvg__maxVertCount(paths, npaths); glBindVertexArray(gl->vertArr); glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); + glBufferData(GL_ARRAY_BUFFER, maxCount * sizeof(struct NVGvertex), NULL, GL_STREAM_DRAW); + glnvg__uploadPaths(paths, npaths); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); // Draw Strokes + n = 0; for (i = 0; i < npaths; i++) { path = &paths[i]; - glBufferSubData(GL_ARRAY_BUFFER, 0, path->nstroke * sizeof(struct NVGvertex), &path->stroke[0].x); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(2 * sizeof(float))); + offset = (n + path->nfill) * sizeof(struct NVGvertex); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(size_t)offset); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(offset + 2*sizeof(float))); glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke); + n += path->nfill + path->nstroke; } glDisableVertexAttribArray(0); @@ -716,9 +770,6 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV struct GLNVGtexture* tex = glnvg__findTexture(gl, image); float color[4]; - if (nverts > gl->vertArrSize) - glnvg__resizeVertexBuffer(gl, nverts); - if (tex != NULL) { glBindTexture(GL_TEXTURE_2D, tex->tex); } @@ -733,7 +784,8 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV glBindVertexArray(gl->vertArr); glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); - glBufferSubData(GL_ARRAY_BUFFER, 0, nverts * sizeof(struct NVGvertex), verts); + glBufferData(GL_ARRAY_BUFFER, nverts * sizeof(struct NVGvertex), verts, GL_STREAM_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(2 * sizeof(float))); glEnableVertexAttribArray(0);