Browse Source

Improved rendering performance of convex shapes and on gl3 back-end

- set swap interval to 0 to better see performance
- draw convex shapes without stencil to speed things up
- improve vertex buffer upload for gl3
shared-context
Mikko Mononen 11 years ago
parent
commit
8b234ca953
6 changed files with 258 additions and 165 deletions
  1. +3
    -0
      example/example_gl2.c
  2. +2
    -0
      example/example_gl3.c
  3. +39
    -23
      src/nanovg.c
  4. +1
    -0
      src/nanovg.h
  5. +80
    -61
      src/nanovg_gl2.h
  6. +133
    -81
      src/nanovg_gl3.h

+ 3
- 0
example/example_gl2.c View File

@@ -87,7 +87,10 @@ int main()
if (loadDemoData(vg, &data) == -1) if (loadDemoData(vg, &data) == -1)
return -1; return -1;


glfwSwapInterval(0);

glfwSetTime(0); glfwSetTime(0);
prevt = glfwGetTime();


while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {


+ 2
- 0
example/example_gl3.c View File

@@ -91,6 +91,8 @@ int main()
if (loadDemoData(vg, &data) == -1) if (loadDemoData(vg, &data) == -1)
return -1; return -1;


glfwSwapInterval(0);

glfwSetTime(0); glfwSetTime(0);
prevt = glfwGetTime(); prevt = glfwGetTime();




+ 39
- 23
src/nanovg.c View File

@@ -941,7 +941,7 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m)
struct NVGpoint* p1; struct NVGpoint* p1;
struct NVGpoint* pts; struct NVGpoint* pts;
struct NVGpath* path; struct NVGpath* path;
int i, j;
int i, j, nleft;
float* cp1; float* cp1;
float* cp2; float* cp2;
float* p; float* p;
@@ -1035,6 +1035,7 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m)
path = &cache->paths[j]; path = &cache->paths[j];
pts = &cache->points[path->first]; pts = &cache->points[path->first];
path->nbevel = 0; path->nbevel = 0;
nleft = 0;


p0 = &pts[path->count-1]; p0 = &pts[path->count-1];
p1 = &pts[0]; p1 = &pts[0];
@@ -1058,12 +1059,15 @@ static void nvg__flattenPaths(struct NVGcontext* ctx, float m)
if ((dmr2 * m*m) < 1.0f) { if ((dmr2 * m*m) < 1.0f) {
cross = p1->dx * p0->dy - p0->dx * p1->dy; cross = p1->dx * p0->dy - p0->dx * p1->dy;
p1->flags |= NVG_BEVEL; p1->flags |= NVG_BEVEL;
if (cross < 0)
if (cross < 0) {
p1->flags |= NVG_LEFT; p1->flags |= NVG_LEFT;
nleft++;
}
path->nbevel++; path->nbevel++;
} }
p0 = p1++; 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* p0;
struct NVGpoint* p1; struct NVGpoint* p1;
int nstroke, cverts; int nstroke, cverts;
int convex = 0;
int i, j, s, e; int i, j, s, e;
float wo = 0; float wo = 0;


@@ -1101,6 +1106,7 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)
path = &cache->paths[i]; path = &cache->paths[i];
pts = &cache->points[path->first]; pts = &cache->points[path->first];
nstroke = (path->count + path->nbevel + 1) * 2; nstroke = (path->count + path->nbevel + 1) * 2;
convex = 0;


// Calculate shape vertices. // Calculate shape vertices.
if (feats & NVG_FILL) { if (feats & NVG_FILL) {
@@ -1138,6 +1144,8 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)
path->nfill = (int)(dst - verts); path->nfill = (int)(dst - verts);
verts += path->nfill; verts += path->nfill;


if (path->convex && cache->npaths == 1)
convex = 1;
} else { } else {
wo = 0.0f; wo = 0.0f;
path->fill = 0; path->fill = 0;
@@ -1146,11 +1154,19 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)


// Calculate fringe // Calculate fringe
if (feats & NVG_STROKE) { 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; int loop = ((feats & NVG_CAPS) && path->closed == 0) ? 0 : 1;
dst = verts; dst = verts;
path->stroke = dst; 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) { if (loop) {
// Looping // Looping
p0 = &pts[path->count-1]; p0 = &pts[path->count-1];
@@ -1173,10 +1189,10 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)
nvg__normalize(&dx, &dy); nvg__normalize(&dx, &dy);
dlx = dy; dlx = dy;
dly = -dx; 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) { 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 ry1 = p1->y + dly1 * rw;
float lx = p1->x - p1->dmx * lw; float lx = p1->x - p1->dmx * lw;
float ly = p1->y - p1->dmy * 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 { } else {
float rx = p1->x + p1->dmx * rw; float rx = p1->x + p1->dmx * rw;
float ry = p1->y + p1->dmy * 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 ly0 = p1->y - dly0 * lw;
float lx1 = p1->x - dlx1 * lw; float lx1 = p1->x - dlx1 * lw;
float ly1 = p1->y - dly1 * 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 { } 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++; p0 = p1++;
} }


if (loop) { if (loop) {
// Loop it // 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 { } else {
// Add cap // Add cap
float dx, dy, dlx, dly; float dx, dy, dlx, dly;
@@ -1227,10 +1243,10 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w)
nvg__normalize(&dx, &dy); nvg__normalize(&dx, &dy);
dlx = dy; dlx = dy;
dly = -dx; 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); path->nstroke = (int)(dst - verts);


+ 1
- 0
src/nanovg.h View File

@@ -387,6 +387,7 @@ struct NVGpath {
struct NVGvertex* stroke; struct NVGvertex* stroke;
int nstroke; int nstroke;
int winding; int winding;
int convex;
}; };


struct NVGparams { struct NVGparams {


+ 80
- 61
src/nanovg_gl2.h View File

@@ -486,85 +486,104 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
if (gl->gradShader.prog == 0) if (gl->gradShader.prog == 0)
return; 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, static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize,


+ 133
- 81
src/nanovg_gl3.h View File

@@ -231,15 +231,6 @@ static void glnvg__getUniforms(struct GLNVGshader* shader)
shader->loc[GLNVG_LOC_TEXTYPE] = glGetUniformLocation(shader->prog, "texType"); 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) static int glnvg__renderCreate(void* uptr)
{ {
struct GLNVGcontext* gl = (struct GLNVGcontext*)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; int i, count = 0;
for (i = 0; i < npaths; i++) { 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; 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, static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float aasize,
const float* bounds, const struct NVGpath* paths, int npaths) const float* bounds, const struct NVGpath* paths, int npaths)
{ {
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
const struct NVGpath* path; 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) if (gl->gradShader.prog == 0)
return; return;


glEnable(GL_CULL_FACE);

maxCount = glnvg__maxVertCount(paths, npaths);
glBindVertexArray(gl->vertArr); glBindVertexArray(gl->vertArr);
glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); 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, 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; struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
const struct NVGpath* path; 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) if (gl->gradShader.prog == 0)
return; return;
@@ -688,19 +737,24 @@ static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGsc


glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);


maxCount = glnvg__maxVertCount(paths, npaths);
glBindVertexArray(gl->vertArr); glBindVertexArray(gl->vertArr);
glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); 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(0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);


// Draw Strokes // Draw Strokes
n = 0;
for (i = 0; i < npaths; i++) { for (i = 0; i < npaths; i++) {
path = &paths[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); glDrawArrays(GL_TRIANGLE_STRIP, 0, path->nstroke);
n += path->nfill + path->nstroke;
} }


glDisableVertexAttribArray(0); glDisableVertexAttribArray(0);
@@ -716,9 +770,6 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV
struct GLNVGtexture* tex = glnvg__findTexture(gl, image); struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
float color[4]; float color[4];


if (nverts > gl->vertArrSize)
glnvg__resizeVertexBuffer(gl, nverts);

if (tex != NULL) { if (tex != NULL) {
glBindTexture(GL_TEXTURE_2D, tex->tex); glBindTexture(GL_TEXTURE_2D, tex->tex);
} }
@@ -733,7 +784,8 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV


glBindVertexArray(gl->vertArr); glBindVertexArray(gl->vertArr);
glBindBuffer(GL_ARRAY_BUFFER, gl->vertBuf); 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(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))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(2 * sizeof(float)));
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);


Loading…
Cancel
Save