diff --git a/example/demo.c b/example/demo.c index 2e3e58e..94abc70 100644 --- a/example/demo.c +++ b/example/demo.c @@ -24,6 +24,11 @@ #define ICON_LOGIN 0xE740 #define ICON_TRASH 0xE729 +static float minf(float a, float b) { return a < b ? a : b; } +static float maxf(float a, float b) { return a > b ? a : b; } +static float absf(float a) { return a >= 0.0f ? a : -a; } +static float clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } + // Returns 1 if col.rgba is 0.0f,0.0f,0.0f,0.0f, 0 otherwise int isBlack( struct NVGcolor col ) { @@ -492,6 +497,32 @@ void drawGraph(struct NVGcontext* vg, float x, float y, float w, float h, float nvgStrokeWidth(vg, 1.0f); } +void drawSpinner(struct NVGcontext* vg, float cx, float cy, float r, float t) +{ + float a0 = 0.0f + t*6; + float a1 = NVG_PI + t*6; + float r0 = r; + float r1 = r * 0.75f; + float ax,ay, bx,by; + struct NVGpaint paint; + + nvgSave(vg); + + nvgBeginPath(vg); + nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW); + nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW); + nvgClosePath(vg); + ax = cx + cosf(a0) * (r0+r1)*0.5f; + ay = cy + sinf(a0) * (r0+r1)*0.5f; + bx = cx + cosf(a1) * (r0+r1)*0.5f; + by = cy + sinf(a1) * (r0+r1)*0.5f; + paint = nvgLinearGradient(vg, ax,ay, bx,by, nvgRGBA(0,0,0,0), nvgRGBA(0,0,0,128)); + nvgFillPaint(vg, paint); + nvgFill(vg); + + nvgRestore(vg); +} + void drawThumbnails(struct NVGcontext* vg, float x, float y, float w, float h, const int* images, int nimages, float t) { float cornerRadius = 3.0f; @@ -503,7 +534,8 @@ void drawThumbnails(struct NVGcontext* vg, float x, float y, float w, float h, c float stackh = (nimages/2) * (thumb+10) + 10; int i; float u = (1+cosf(t*0.5f))*0.5f; - float scrollh; + float u2 = (1-cosf(t*0.2f))*0.5f; + float scrollh, dv; nvgSave(vg); // nvgClearState(vg); @@ -530,8 +562,10 @@ void drawThumbnails(struct NVGcontext* vg, float x, float y, float w, float h, c nvgScissor(vg, x,y,w,h); nvgTranslate(vg, 0, -(stackh - h)*u); + dv = 1.0f / (float)(nimages-1); + for (i = 0; i < nimages; i++) { - float tx, ty; + float tx, ty, v, a; tx = x+10; ty = y+10; tx += (i%2) * (thumb+10); @@ -548,7 +582,14 @@ void drawThumbnails(struct NVGcontext* vg, float x, float y, float w, float h, c ix = -(iw-thumb)*0.5f; iy = 0; } - imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], 0); + + v = i * dv; + a = clampf((u2-v) / dv, 0, 1); + + if (a < 1.0f) + drawSpinner(vg, tx+thumb/2,ty+thumb/2, thumb*0.25f, t); + + imgPaint = nvgImagePattern(vg, tx+ix, ty+iy, iw,ih, 0.0f/180.0f*NVG_PI, images[i], NVG_NOREPEAT, a); nvgBeginPath(vg); nvgRoundedRect(vg, tx,ty, thumb,thumb, 5); nvgFillPaint(vg, imgPaint); @@ -819,6 +860,7 @@ void drawParagraph(struct NVGcontext* vg, float x, float y, float width, float h float lineh; float caretx, px; float bounds[4]; + float a; float gx,gy; int gutter = 0; NVG_NOTUSED(height); @@ -900,6 +942,14 @@ void drawParagraph(struct NVGcontext* vg, float x, float y, float width, float h nvgTextLineHeight(vg, 1.2f); nvgTextBoxBounds(vg, x,y, 150, "Hover your mouse over the text to see calculated caret position.", NULL, bounds); + + // Fade the tooltip out when close to it. + gx = fabsf((mx - (bounds[0]+bounds[2])*0.5f) / (bounds[0] - bounds[2])); + gy = fabsf((my - (bounds[1]+bounds[3])*0.5f) / (bounds[1] - bounds[3])); + a = maxf(gx, gy) - 0.5f; + a = clampf(a, 0, 1); + nvgGlobalAlpha(vg, a); + nvgBeginPath(vg); nvgFillColor(vg, nvgRGBA(220,220,220,255)); nvgRoundedRect(vg, bounds[0]-2,bounds[1]-2, (int)(bounds[2]-bounds[0])+4, (int)(bounds[3]-bounds[1])+4, 3); diff --git a/example/example_gl3.c b/example/example_gl3.c index 2c1f932..6239057 100644 --- a/example/example_gl3.c +++ b/example/example_gl3.c @@ -179,7 +179,7 @@ int main() renderGraph(vg, 5+200+5+200+5,5, &gpuGraph); if (fb != NULL) { - struct NVGpaint img = nvgImagePattern(vg, 0, 0, 150, 150, 0, fb->image, 0); + struct NVGpaint img = nvgImagePattern(vg, 0, 0, 150, 150, 0, fb->image, NVG_NOREPEAT, 1.0f); nvgBeginPath(vg); nvgTranslate(vg, 540, 300); nvgRect(vg, 0, 0, 150, 150); diff --git a/src/nanovg.c b/src/nanovg.c index 78f535e..23b2896 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -59,6 +59,7 @@ struct NVGstate { float miterLimit; int lineJoin; int lineCap; + float alpha; float xform[6]; struct NVGscissor scissor; float fontSize; @@ -519,6 +520,7 @@ void nvgReset(struct NVGcontext* ctx) state->miterLimit = 10.0f; state->lineCap = NVG_BUTT; state->lineJoin = NVG_MITER; + state->alpha = 1.0f; nvgTransformIdentity(state->xform); state->scissor.extent[0] = 0.0f; @@ -557,6 +559,11 @@ void nvgLineJoin(struct NVGcontext* ctx, int join) state->lineJoin = join; } +void nvgGlobalAlpha(struct NVGcontext* ctx, float alpha) +{ + struct NVGstate* state = nvg__getState(ctx); + state->alpha = alpha; +} void nvgTransform(struct NVGcontext* ctx, float a, float b, float c, float d, float e, float f) { @@ -786,7 +793,7 @@ struct NVGpaint nvgBoxGradient(struct NVGcontext* ctx, struct NVGpaint nvgImagePattern(struct NVGcontext* ctx, float cx, float cy, float w, float h, float angle, - int image, int repeat) + int image, int repeat, float alpha) { struct NVGpaint p; NVG_NOTUSED(ctx); @@ -802,6 +809,8 @@ struct NVGpaint nvgImagePattern(struct NVGcontext* ctx, p.image = image; p.repeat = repeat; + p.innerColor = p.outerColor = nvgRGBAf(1,1,1,alpha); + return p; } @@ -1981,6 +1990,7 @@ void nvgFill(struct NVGcontext* ctx) { struct NVGstate* state = nvg__getState(ctx); const struct NVGpath* path; + struct NVGpaint fillPaint = state->fill; int i; nvg__flattenPaths(ctx); @@ -1989,7 +1999,11 @@ void nvgFill(struct NVGcontext* ctx) else nvg__expandFill(ctx, 0.0f, NVG_MITER, 2.4f); - ctx->params.renderFill(ctx->params.userPtr, &state->fill, &state->scissor, ctx->fringeWidth, + // Apply global alpha + fillPaint.innerColor.a *= state->alpha; + fillPaint.outerColor.a *= state->alpha; + + ctx->params.renderFill(ctx->params.userPtr, &fillPaint, &state->scissor, ctx->fringeWidth, ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); // Count triangles @@ -2019,6 +2033,10 @@ void nvgStroke(struct NVGcontext* ctx) strokeWidth = ctx->fringeWidth; } + // Apply global alpha + strokePaint.innerColor.a *= state->alpha; + strokePaint.outerColor.a *= state->alpha; + nvg__flattenPaths(ctx); if (ctx->params.edgeAntiAlias) @@ -2171,6 +2189,11 @@ float nvgText(struct NVGcontext* ctx, float x, float y, const char* string, cons // Render triangles. paint = state->fill; paint.image = ctx->fontImage; + + // Apply global alpha + paint.innerColor.a *= state->alpha; + paint.outerColor.a *= state->alpha; + ctx->params.renderTriangles(ctx->params.userPtr, &paint, &state->scissor, verts, nverts); ctx->drawCallCount++; diff --git a/src/nanovg.h b/src/nanovg.h index 03e09ae..4fab654 100644 --- a/src/nanovg.h +++ b/src/nanovg.h @@ -66,6 +66,7 @@ enum NVGlineCap { }; enum NVGpatternRepeat { + NVG_NOREPEAT = 0, NVG_REPEATX = 0x01, // Repeat image pattern in X direction NVG_REPEATY = 0x02, // Repeat image pattern in Y direction }; @@ -208,6 +209,10 @@ void nvgLineCap(struct NVGcontext* ctx, int cap); // Can be one of NVG_MITER (default), NVG_ROUND, NVG_BEVEL. void nvgLineJoin(struct NVGcontext* ctx, int join); +// Sets the transparency applied to all rendered shapes. +// Alreade transparent paths will get proportionally more transparent as well. +void nvgGlobalAlpha(struct NVGcontext* ctx, float alpha); + // // Transforms // @@ -354,7 +359,7 @@ struct NVGpaint nvgRadialGradient(struct NVGcontext* ctx, float cx, float cy, fl // and repeat is combination of NVG_REPEATX and NVG_REPEATY which tells if the image should be repeated across x or y. // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). struct NVGpaint nvgImagePattern(struct NVGcontext* ctx, float ox, float oy, float ex, float ey, - float angle, int image, int repeat); + float angle, int image, int repeat, float alpha); // // Scissoring diff --git a/src/nanovg_gl.h b/src/nanovg_gl.h index fc8905c..df0907e 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -524,6 +524,8 @@ static int glnvg__renderCreate(void* uptr) " vec4 color = texture2D(tex, pt);\n" "#endif\n" " color = texType == 0 ? color : vec4(1,1,1,color.x);\n" + " // Apply color tint and alpha.\n" + " color *= innerCol;\n" " // Combine alpha\n" " color.w *= strokeAlpha * scissor;\n" " result = color;\n"