- set swap interval to 0 to better see performance - draw convex shapes without stencil to speed things up - improve vertex buffer upload for gl3shared-context
@@ -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)) | ||||
{ | { | ||||
@@ -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(); | ||||
@@ -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); | ||||
@@ -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 { | ||||
@@ -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, | ||||
@@ -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); | ||||