- added option to turn off AA fringe generation - added examples which use no AA fringes and MSAAshared-context
| @@ -61,6 +61,9 @@ int main() | |||
| glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); | |||
| glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); | |||
| #ifdef DEMO_MSAA | |||
| glfwWindowHint(GLFW_SAMPLES, 4); | |||
| #endif | |||
| window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL); | |||
| // window = glfwCreateWindow(1000, 600, "NanoVG", glfwGetPrimaryMonitor(), NULL); | |||
| @@ -79,7 +82,11 @@ int main() | |||
| } | |||
| #endif | |||
| vg = nvgCreateGL2(512,512); | |||
| #ifdef DEMO_MSAA | |||
| vg = nvgCreateGL2(512, 512, 0); | |||
| #else | |||
| vg = nvgCreateGL2(512, 512, NVG_ANTIALIAS); | |||
| #endif | |||
| if (vg == NULL) { | |||
| printf("Could not init nanovg.\n"); | |||
| return -1; | |||
| @@ -65,6 +65,9 @@ int main() | |||
| glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); | |||
| glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |||
| glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |||
| #ifdef DEMO_MSAA | |||
| glfwWindowHint(GLFW_SAMPLES, 4); | |||
| #endif | |||
| window = glfwCreateWindow(1000, 600, "NanoVG", NULL, NULL); | |||
| // window = glfwCreateWindow(1000, 600, "NanoVG", glfwGetPrimaryMonitor(), NULL); | |||
| @@ -84,7 +87,11 @@ int main() | |||
| } | |||
| #endif | |||
| vg = nvgCreateGL3(512,512); | |||
| #ifdef DEMO_MSAA | |||
| vg = nvgCreateGL3(512, 512, 0); | |||
| #else | |||
| vg = nvgCreateGL3(512, 512, NVG_ANTIALIAS); | |||
| #endif | |||
| if (vg == NULL) { | |||
| printf("Could not init nanovg.\n"); | |||
| return -1; | |||
| @@ -83,7 +83,7 @@ int main() | |||
| } | |||
| #endif | |||
| vg = nvgCreateGL2(512,512); | |||
| vg = nvgCreateGL2(512, 512, NVG_ANTIALIAS); | |||
| if (vg == NULL) { | |||
| printf("Could not init nanovg.\n"); | |||
| return -1; | |||
| @@ -67,6 +67,62 @@ solution "nanovg" | |||
| defines { "NDEBUG" } | |||
| flags { "Optimize", "ExtraWarnings"} | |||
| project "example_gl2_msaa" | |||
| kind "ConsoleApp" | |||
| language "C" | |||
| defines { "DEMO_MSAA" } | |||
| files { "example/example_gl2.c", "example/demo.c" } | |||
| includedirs { "src", "example" } | |||
| targetdir("build") | |||
| links { "nanovg" } | |||
| configuration { "linux" } | |||
| links { "X11","Xrandr", "rt", "GL", "GLU", "pthread", "m", "glfw3", "GLEW" } | |||
| defines { "NANOVG_GLEW" } | |||
| configuration { "windows" } | |||
| links { "glu32","opengl32", "gdi32", "winmm", "user32" } | |||
| configuration { "macosx" } | |||
| links { "glfw3" } | |||
| linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" } | |||
| configuration "Debug" | |||
| defines { "DEBUG" } | |||
| flags { "Symbols", "ExtraWarnings"} | |||
| configuration "Release" | |||
| defines { "NDEBUG" } | |||
| flags { "Optimize", "ExtraWarnings"} | |||
| project "example_gl3_msaa" | |||
| kind "ConsoleApp" | |||
| language "C" | |||
| defines { "DEMO_MSAA" } | |||
| files { "example/example_gl3.c", "example/demo.c" } | |||
| includedirs { "src", "example" } | |||
| targetdir("build") | |||
| links { "nanovg" } | |||
| configuration { "linux" } | |||
| links { "X11","Xrandr", "rt", "GL", "GLU", "pthread", "m", "glfw3", "GLEW" } | |||
| defines { "NANOVG_GLEW" } | |||
| configuration { "windows" } | |||
| links { "glu32","opengl32", "gdi32", "winmm", "user32" } | |||
| configuration { "macosx" } | |||
| links { "glfw3" } | |||
| linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" } | |||
| configuration "Debug" | |||
| defines { "DEBUG" } | |||
| flags { "Symbols", "ExtraWarnings"} | |||
| configuration "Release" | |||
| defines { "NDEBUG" } | |||
| flags { "Optimize", "ExtraWarnings"} | |||
| project "example_gles2" | |||
| kind "ConsoleApp" | |||
| language "C" | |||
| @@ -1114,31 +1114,38 @@ static int nvg__expandStrokeAndFill(struct NVGcontext* ctx, int feats, float w) | |||
| dst = verts; | |||
| path->fill = dst; | |||
| // Looping | |||
| p0 = &pts[path->count-1]; | |||
| p1 = &pts[0]; | |||
| for (j = 0; j < path->count; ++j) { | |||
| if (p1->flags & NVG_BEVEL) { | |||
| float dlx0 = p0->dy; | |||
| float dly0 = -p0->dx; | |||
| float dlx1 = p1->dy; | |||
| float dly1 = -p1->dx; | |||
| if (p1->flags & NVG_LEFT) { | |||
| float lx = p1->x - p1->dmx * wo; | |||
| float ly = p1->y - p1->dmy * wo; | |||
| nvg__vset(dst, lx, ly, 0.5f,1); dst++; | |||
| if (w == 0.0f) { | |||
| for (j = 0; j < path->count; ++j) { | |||
| nvg__vset(dst, pts[j].x, pts[j].y, 0.5f,1); | |||
| dst++; | |||
| } | |||
| } else { | |||
| // Looping | |||
| p0 = &pts[path->count-1]; | |||
| p1 = &pts[0]; | |||
| for (j = 0; j < path->count; ++j) { | |||
| if (p1->flags & NVG_BEVEL) { | |||
| float dlx0 = p0->dy; | |||
| float dly0 = -p0->dx; | |||
| float dlx1 = p1->dy; | |||
| float dly1 = -p1->dx; | |||
| if (p1->flags & NVG_LEFT) { | |||
| float lx = p1->x - p1->dmx * wo; | |||
| float ly = p1->y - p1->dmy * wo; | |||
| nvg__vset(dst, lx, ly, 0.5f,1); dst++; | |||
| } else { | |||
| float lx0 = p1->x - dlx0 * wo; | |||
| float ly0 = p1->y - dly0 * wo; | |||
| float lx1 = p1->x - dlx1 * wo; | |||
| float ly1 = p1->y - dly1 * wo; | |||
| nvg__vset(dst, lx0, ly0, 0.5f,1); dst++; | |||
| nvg__vset(dst, lx1, ly1, 0.5f,1); dst++; | |||
| } | |||
| } else { | |||
| float lx0 = p1->x - dlx0 * wo; | |||
| float ly0 = p1->y - dly0 * wo; | |||
| float lx1 = p1->x - dlx1 * wo; | |||
| float ly1 = p1->y - dly1 * wo; | |||
| nvg__vset(dst, lx0, ly0, 0.5f,1); dst++; | |||
| nvg__vset(dst, lx1, ly1, 0.5f,1); dst++; | |||
| nvg__vset(dst, p1->x - (p1->dmx * wo), p1->y - (p1->dmy * wo), 0.5f,1); dst++; | |||
| } | |||
| } else { | |||
| nvg__vset(dst, p1->x - (p1->dmx * wo), p1->y - (p1->dmy * wo), 0.5f,1); dst++; | |||
| p0 = p1++; | |||
| } | |||
| p0 = p1++; | |||
| } | |||
| path->nfill = (int)(dst - verts); | |||
| @@ -1480,7 +1487,10 @@ void nvgFill(struct NVGcontext* ctx) | |||
| int i; | |||
| nvg__flattenPaths(ctx, state->miterLimit); | |||
| nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, NVG_AA); | |||
| if (ctx->params.edgeAntiAlias) | |||
| nvg__expandStrokeAndFill(ctx, NVG_FILL|NVG_STROKE, NVG_AA); | |||
| else | |||
| nvg__expandStrokeAndFill(ctx, NVG_FILL, 0.0f); | |||
| ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor, NVG_AA, | |||
| ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); | |||
| @@ -1503,7 +1513,10 @@ void nvgStroke(struct NVGcontext* ctx) | |||
| int i; | |||
| nvg__flattenPaths(ctx, state->miterLimit); | |||
| nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + NVG_AA/2.0f); | |||
| if (ctx->params.edgeAntiAlias) | |||
| nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f + NVG_AA/2.0f); | |||
| else | |||
| nvg__expandStrokeAndFill(ctx, NVG_STROKE|NVG_CAPS, strokeWidth*0.5f); | |||
| ctx->params.renderStroke(ctx->params.userPtr, &state->stroke, &state->scissor, NVG_AA, | |||
| strokeWidth, ctx->cache->paths, ctx->cache->npaths); | |||
| @@ -1651,7 +1664,7 @@ float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, cons | |||
| float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, float* bounds) | |||
| { | |||
| struct NVGstate* state = nvg__getState(ctx); | |||
| float scale = nvg__getFontScale(state); | |||
| float scale = 1.0f; // nvg__getFontScale(state); | |||
| if (state->fontId == FONS_INVALID) return 0; | |||
| @@ -1667,7 +1680,7 @@ float nvgTextBounds(struct NVGcontext* ctx, const char* string, const char* end, | |||
| void nvgVertMetrics(struct NVGcontext* ctx, float* ascender, float* descender, float* lineh) | |||
| { | |||
| struct NVGstate* state = nvg__getState(ctx); | |||
| float scale = nvg__getFontScale(state); | |||
| float scale = 1.0f; // nvg__getFontScale(state); | |||
| if (state->fontId == FONS_INVALID) return; | |||
| @@ -396,6 +396,7 @@ struct NVGpath { | |||
| struct NVGparams { | |||
| void* userPtr; | |||
| int atlasWidth, atlasHeight; | |||
| int edgeAntiAlias; | |||
| int (*renderCreate)(void* uptr); | |||
| int (*renderCreateTexture)(void* uptr, int type, int w, int h, const unsigned char* data); | |||
| int (*renderDeleteTexture)(void* uptr, int image); | |||
| @@ -22,7 +22,9 @@ | |||
| extern "C" { | |||
| #endif | |||
| struct NVGcontext* nvgCreateGL2(); | |||
| #define NVG_ANTIALIAS 1 | |||
| struct NVGcontext* nvgCreateGL2(int atlasw, int atlash, int edgeaa); | |||
| void nvgDeleteGL2(struct NVGcontext* ctx); | |||
| #ifdef __cplusplus | |||
| @@ -83,6 +85,7 @@ struct GLNVGcontext { | |||
| int ctextures; | |||
| int textureId; | |||
| GLuint vertBuf; | |||
| int edgeAntiAlias; | |||
| }; | |||
| static struct GLNVGtexture* glnvg__allocTexture(struct GLNVGcontext* gl) | |||
| @@ -258,7 +261,7 @@ static int glnvg__renderCreate(void* uptr) | |||
| " gl_Position = vec4(2.0*vertex.x/viewSize.x - 1.0, 1.0 - 2.0*vertex.y/viewSize.y, 0, 1);\n" | |||
| "}\n"; | |||
| static const char* fillFragShader = | |||
| static const char* fillFragShaderEdgeAA = | |||
| "uniform mat3 scissorMat;\n" | |||
| "uniform vec2 scissorExt;\n" | |||
| "uniform mat3 paintMat;\n" | |||
| @@ -322,10 +325,72 @@ static int glnvg__renderCreate(void* uptr) | |||
| " }\n" | |||
| "}\n"; | |||
| static const char* fillFragShader = | |||
| "uniform mat3 scissorMat;\n" | |||
| "uniform vec2 scissorExt;\n" | |||
| "uniform mat3 paintMat;\n" | |||
| "uniform vec2 extent;\n" | |||
| "uniform float radius;\n" | |||
| "uniform float feather;\n" | |||
| "uniform vec4 innerCol;\n" | |||
| "uniform vec4 outerCol;\n" | |||
| "uniform float strokeMult;\n" | |||
| "uniform sampler2D tex;\n" | |||
| "uniform int texType;\n" | |||
| "uniform int type;\n" | |||
| "varying vec2 ftcoord;\n" | |||
| "varying vec4 fcolor;\n" | |||
| "varying vec2 fpos;\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 = vec2(0.5,0.5) - (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\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) {\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" | |||
| " gl_FragColor = color;\n" | |||
| " } else if (type == 1) {\n" | |||
| " float scissor = scissorMask(fpos);\n" | |||
| " // Calculate color fron texture\n" | |||
| " vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n" | |||
| " vec4 color = texture2D(tex, pt);\n" | |||
| " color = texType == 0 ? color : vec4(1,1,1,color.x);\n" | |||
| " // Combine alpha\n" | |||
| " color.w *= scissor;\n" | |||
| " gl_FragColor = color;\n" | |||
| " } else if (type == 2) {\n" | |||
| " gl_FragColor = vec4(1,1,1,1);\n" | |||
| " } else if (type == 3) {\n" | |||
| " vec4 color = texture2D(tex, ftcoord);\n" | |||
| " color = texType == 0 ? color : vec4(1,1,1,color.x);\n" | |||
| " gl_FragColor = color * fcolor;\n" | |||
| " }\n" | |||
| "}\n"; | |||
| glnvg__checkError("init"); | |||
| if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0) | |||
| return 0; | |||
| if (gl->edgeAntiAlias) { | |||
| if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShaderEdgeAA) == 0) | |||
| return 0; | |||
| } else { | |||
| if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0) | |||
| return 0; | |||
| } | |||
| glnvg__checkError("uniform locations"); | |||
| glnvg__getUniforms(&gl->shader); | |||
| @@ -578,15 +643,17 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis | |||
| 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; | |||
| if (gl->edgeAntiAlias) { | |||
| // 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(0); | |||
| @@ -631,22 +698,23 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis | |||
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||
| glEnable(GL_BLEND); | |||
| glStencilFunc(GL_EQUAL, 0x00, 0xff); | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | |||
| glEnableVertexAttribArray(1); | |||
| glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); | |||
| // 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; | |||
| if (gl->edgeAntiAlias) { | |||
| glStencilFunc(GL_EQUAL, 0x00, 0xff); | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | |||
| // 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 | |||
| @@ -767,7 +835,7 @@ static void glnvg__renderDelete(void* uptr) | |||
| } | |||
| struct NVGcontext* nvgCreateGL2(int atlasw, int atlash) | |||
| struct NVGcontext* nvgCreateGL2(int atlasw, int atlash, int edgeaa) | |||
| { | |||
| struct NVGparams params; | |||
| struct NVGcontext* ctx = NULL; | |||
| @@ -789,6 +857,9 @@ struct NVGcontext* nvgCreateGL2(int atlasw, int atlash) | |||
| params.userPtr = gl; | |||
| params.atlasWidth = atlasw; | |||
| params.atlasHeight = atlash; | |||
| params.edgeAntiAlias = edgeaa; | |||
| gl->edgeAntiAlias = edgeaa; | |||
| ctx = nvgCreateInternal(¶ms); | |||
| if (ctx == NULL) goto error; | |||
| @@ -22,7 +22,9 @@ | |||
| extern "C" { | |||
| #endif | |||
| struct NVGcontext* nvgCreateGL3(); | |||
| #define NVG_ANTIALIAS 1 | |||
| struct NVGcontext* nvgCreateGL3(int atlasw, int atlash, int edgeaa); | |||
| void nvgDeleteGL3(struct NVGcontext* ctx); | |||
| #ifdef __cplusplus | |||
| @@ -84,6 +86,7 @@ struct GLNVGcontext { | |||
| int textureId; | |||
| GLuint vertArr; | |||
| GLuint vertBuf; | |||
| int edgeAntiAlias; | |||
| }; | |||
| static struct GLNVGtexture* glnvg__allocTexture(struct GLNVGcontext* gl) | |||
| @@ -260,7 +263,7 @@ static int glnvg__renderCreate(void* uptr) | |||
| " gl_Position = vec4(2.0*vertex.x/viewSize.x - 1.0, 1.0 - 2.0*vertex.y/viewSize.y, 0, 1);\n" | |||
| "}\n"; | |||
| static const char* fillFragShader = | |||
| static const char* fillFragShaderEdgeAA = | |||
| "#version 150 core\n" | |||
| "uniform mat3 scissorMat;\n" | |||
| "uniform vec2 scissorExt;\n" | |||
| @@ -297,7 +300,7 @@ static int glnvg__renderCreate(void* uptr) | |||
| "}\n" | |||
| "\n" | |||
| "void main(void) {\n" | |||
| " if (type == 0) {\n" | |||
| " if (type == 0) { // Gradient\n" | |||
| " float scissor = scissorMask(fpos);\n" | |||
| " float strokeAlpha = strokeMask();\n" | |||
| " // Calculate gradient color using box gradient\n" | |||
| @@ -307,7 +310,7 @@ static int glnvg__renderCreate(void* uptr) | |||
| " // Combine alpha\n" | |||
| " color.w *= strokeAlpha * scissor;\n" | |||
| " outColor = color;\n" | |||
| " } else if (type == 1) {\n" | |||
| " } else if (type == 1) { // Image\n" | |||
| " float scissor = scissorMask(fpos);\n" | |||
| " float strokeAlpha = strokeMask();\n" | |||
| " // Calculate color fron texture\n" | |||
| @@ -317,9 +320,68 @@ static int glnvg__renderCreate(void* uptr) | |||
| " // Combine alpha\n" | |||
| " color.w *= strokeAlpha * scissor;\n" | |||
| " outColor = color;\n" | |||
| " } else if (type == 2) {\n" | |||
| " } else if (type == 2) { // Stencil fill\n" | |||
| " outColor = vec4(1,1,1,1);\n" | |||
| " } else if (type == 3) {\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 * fcolor;\n" | |||
| " }\n" | |||
| "}\n"; | |||
| static const char* fillFragShader = | |||
| "#version 150 core\n" | |||
| "uniform mat3 scissorMat;\n" | |||
| "uniform vec2 scissorExt;\n" | |||
| "uniform mat3 paintMat;\n" | |||
| "uniform vec2 extent;\n" | |||
| "uniform float radius;\n" | |||
| "uniform float feather;\n" | |||
| "uniform vec4 innerCol;\n" | |||
| "uniform vec4 outerCol;\n" | |||
| "uniform float strokeMult;\n" | |||
| "uniform sampler2D tex;\n" | |||
| "uniform int texType;\n" | |||
| "uniform int type;\n" | |||
| "in vec2 ftcoord;\n" | |||
| "in vec4 fcolor;\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 = vec2(0.5,0.5) - (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\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" | |||
| " outColor = color * fcolor;\n" | |||
| @@ -328,8 +390,13 @@ static int glnvg__renderCreate(void* uptr) | |||
| glnvg__checkError("init"); | |||
| if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0) | |||
| return 0; | |||
| if (gl->edgeAntiAlias) { | |||
| if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShaderEdgeAA) == 0) | |||
| return 0; | |||
| } else { | |||
| if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0) | |||
| return 0; | |||
| } | |||
| glnvg__checkError("uniform locations"); | |||
| glnvg__getUniforms(&gl->shader); | |||
| @@ -584,15 +651,17 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis | |||
| 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; | |||
| if (gl->edgeAntiAlias) { | |||
| // 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(0); | |||
| @@ -638,22 +707,23 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis | |||
| glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); | |||
| glEnable(GL_BLEND); | |||
| glStencilFunc(GL_EQUAL, 0x00, 0xff); | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | |||
| glEnableVertexAttribArray(1); | |||
| glnvg__setupPaint(gl, paint, scissor, 1.0001f, aasize); | |||
| // 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; | |||
| if (gl->edgeAntiAlias) { | |||
| glStencilFunc(GL_EQUAL, 0x00, 0xff); | |||
| glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); | |||
| // 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 | |||
| @@ -776,7 +846,7 @@ static void glnvg__renderDelete(void* uptr) | |||
| } | |||
| struct NVGcontext* nvgCreateGL3(int atlasw, int atlash) | |||
| struct NVGcontext* nvgCreateGL3(int atlasw, int atlash, int edgeaa) | |||
| { | |||
| struct NVGparams params; | |||
| struct NVGcontext* ctx = NULL; | |||
| @@ -798,6 +868,9 @@ struct NVGcontext* nvgCreateGL3(int atlasw, int atlash) | |||
| params.userPtr = gl; | |||
| params.atlasWidth = atlasw; | |||
| params.atlasHeight = atlash; | |||
| params.edgeAntiAlias = edgeaa; | |||
| gl->edgeAntiAlias = edgeaa; | |||
| ctx = nvgCreateInternal(¶ms); | |||
| if (ctx == NULL) goto error; | |||