diff --git a/examples/common/nanovg/nanovg.cpp b/examples/common/nanovg/nanovg.cpp index ae696b3b4..f64b805c5 100644 --- a/examples/common/nanovg/nanovg.cpp +++ b/examples/common/nanovg/nanovg.cpp @@ -432,7 +432,7 @@ void nvgCancelFrame(NVGcontext* ctx) void nvgEndFrame(NVGcontext* ctx) { NVGstate* state = nvg__getState(ctx); - ctx->params.renderFlush(ctx->params.userPtr, state->compositeOperation); + ctx->params.renderFlush(ctx->params.userPtr); if (ctx->fontImageIdx != 0) { int fontImage = ctx->fontImages[ctx->fontImageIdx]; int i, j, iw, ih; @@ -2166,22 +2166,31 @@ void nvgRect(NVGcontext* ctx, float x, float y, float w, float h) void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r) { - if (r < 0.1f) { - nvgRect(ctx, x,y,w,h); + nvgRoundedRectVarying(ctx, x, y, w, h, r, r, r, r); +} + +void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft) +{ + if(radTopLeft < 0.1f && radTopRight < 0.1f && radBottomRight < 0.1f && radBottomLeft < 0.1f) { + nvgRect(ctx, x, y, w, h); return; - } - else { - float rx = nvg__minf(r, nvg__absf(w)*0.5f) * nvg__signf(w), ry = nvg__minf(r, nvg__absf(h)*0.5f) * nvg__signf(h); + } else { + float halfw = nvg__absf(w)*0.5f; + float halfh = nvg__absf(h)*0.5f; + float rxBL = nvg__minf(radBottomLeft, halfw) * nvg__signf(w), ryBL = nvg__minf(radBottomLeft, halfh) * nvg__signf(h); + float rxBR = nvg__minf(radBottomRight, halfw) * nvg__signf(w), ryBR = nvg__minf(radBottomRight, halfh) * nvg__signf(h); + float rxTR = nvg__minf(radTopRight, halfw) * nvg__signf(w), ryTR = nvg__minf(radTopRight, halfh) * nvg__signf(h); + float rxTL = nvg__minf(radTopLeft, halfw) * nvg__signf(w), ryTL = nvg__minf(radTopLeft, halfh) * nvg__signf(h); float vals[] = { - NVG_MOVETO, x, y+ry, - NVG_LINETO, x, y+h-ry, - NVG_BEZIERTO, x, y+h-ry*(1-NVG_KAPPA90), x+rx*(1-NVG_KAPPA90), y+h, x+rx, y+h, - NVG_LINETO, x+w-rx, y+h, - NVG_BEZIERTO, x+w-rx*(1-NVG_KAPPA90), y+h, x+w, y+h-ry*(1-NVG_KAPPA90), x+w, y+h-ry, - NVG_LINETO, x+w, y+ry, - NVG_BEZIERTO, x+w, y+ry*(1-NVG_KAPPA90), x+w-rx*(1-NVG_KAPPA90), y, x+w-rx, y, - NVG_LINETO, x+rx, y, - NVG_BEZIERTO, x+rx*(1-NVG_KAPPA90), y, x, y+ry*(1-NVG_KAPPA90), x, y+ry, + NVG_MOVETO, x, y + ryTL, + NVG_LINETO, x, y + h - ryBL, + NVG_BEZIERTO, x, y + h - ryBL*(1 - NVG_KAPPA90), x + rxBL*(1 - NVG_KAPPA90), y + h, x + rxBL, y + h, + NVG_LINETO, x + w - rxBR, y + h, + NVG_BEZIERTO, x + w - rxBR*(1 - NVG_KAPPA90), y + h, x + w, y + h - ryBR*(1 - NVG_KAPPA90), x + w, y + h - ryBR, + NVG_LINETO, x + w, y + ryTR, + NVG_BEZIERTO, x + w, y + ryTR*(1 - NVG_KAPPA90), x + w - rxTR*(1 - NVG_KAPPA90), y, x + w - rxTR, y, + NVG_LINETO, x + rxTL, y, + NVG_BEZIERTO, x + rxTL*(1 - NVG_KAPPA90), y, x, y + ryTL*(1 - NVG_KAPPA90), x, y + ryTL, NVG_CLOSE }; nvg__appendCommands(ctx, vals, NVG_COUNTOF(vals)); @@ -2245,7 +2254,7 @@ void nvgFill(NVGcontext* ctx) fillPaint.innerColor.a *= state->alpha; fillPaint.outerColor.a *= state->alpha; - ctx->params.renderFill(ctx->params.userPtr, &fillPaint, &state->scissor, ctx->fringeWidth, + ctx->params.renderFill(ctx->params.userPtr, &fillPaint, state->compositeOperation, &state->scissor, ctx->fringeWidth, ctx->cache->bounds, ctx->cache->paths, ctx->cache->npaths); // Count triangles @@ -2286,7 +2295,7 @@ void nvgStroke(NVGcontext* ctx) else nvg__expandStroke(ctx, strokeWidth*0.5f, state->lineCap, state->lineJoin, state->miterLimit); - ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, &state->scissor, ctx->fringeWidth, + ctx->params.renderStroke(ctx->params.userPtr, &strokePaint, state->compositeOperation, &state->scissor, ctx->fringeWidth, strokeWidth, ctx->cache->paths, ctx->cache->npaths); // Count triangles @@ -2434,7 +2443,7 @@ static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts) paint.innerColor.a *= state->alpha; paint.outerColor.a *= state->alpha; - ctx->params.renderTriangles(ctx->params.userPtr, &paint, &state->scissor, verts, nverts); + ctx->params.renderTriangles(ctx->params.userPtr, &paint, state->compositeOperation, &state->scissor, verts, nverts); ctx->drawCallCount++; ctx->textTriCount += nverts/3; diff --git a/examples/common/nanovg/nanovg.h b/examples/common/nanovg/nanovg.h index 31109efad..3914ea0d1 100644 --- a/examples/common/nanovg/nanovg.h +++ b/examples/common/nanovg/nanovg.h @@ -267,7 +267,7 @@ void nvgLineCap(NVGcontext* ctx, int cap); void nvgLineJoin(NVGcontext* ctx, int join); // Sets the transparency applied to all rendered shapes. -// Alreade transparent paths will get proportionally more transparent as well. +// Already transparent paths will get proportionally more transparent as well. void nvgGlobalAlpha(NVGcontext* ctx, float alpha); // @@ -399,7 +399,7 @@ NVGpaint nvgLinearGradient(NVGcontext* ctx, float sx, float sy, float ex, float NVGcolor icol, NVGcolor ocol); // Creates and returns a box gradient. Box gradient is a feathered rounded rectangle, it is useful for rendering -// drop shadows or hilights for boxes. Parameters (x,y) define the top-left corner of the rectangle, +// drop shadows or highlights for boxes. Parameters (x,y) define the top-left corner of the rectangle, // (w,h) define the size of the rectangle, r defines the corner radius, and f feather. Feather defines how blurry // the border of the rectangle is. Parameter icol specifies the inner color and ocol the outer color of the gradient. // The gradient is transformed by the current transform when it is passed to nvgFillPaint() or nvgStrokePaint(). @@ -491,6 +491,9 @@ void nvgRect(NVGcontext* ctx, float x, float y, float w, float h); // Creates new rounded rectangle shaped sub-path. void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r); +// Creates new rounded rectangle shaped sub-path with varying radii for each corner. +void nvgRoundedRectVarying(NVGcontext* ctx, float x, float y, float w, float h, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft); + // Creates new ellipse shaped sub-path. void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry); @@ -650,10 +653,10 @@ struct NVGparams { int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h); void (*renderViewport)(void* uptr, int width, int height, float devicePixelRatio); void (*renderCancel)(void* uptr); - void (*renderFlush)(void* uptr, NVGcompositeOperationState compositeOperation); - void (*renderFill)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths); - void (*renderStroke)(void* uptr, NVGpaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths); - void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts); + void (*renderFlush)(void* uptr); + void (*renderFill)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths, int npaths); + void (*renderStroke)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths, int npaths); + void (*renderTriangles)(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, const NVGvertex* verts, int nverts); void (*renderDelete)(void* uptr); }; typedef struct NVGparams NVGparams; diff --git a/examples/common/nanovg/nanovg_bgfx.cpp b/examples/common/nanovg/nanovg_bgfx.cpp index cd5ce323b..702f04ccd 100644 --- a/examples/common/nanovg/nanovg_bgfx.cpp +++ b/examples/common/nanovg/nanovg_bgfx.cpp @@ -72,6 +72,14 @@ namespace int flags; }; + struct GLNVGblend + { + uint64_t srcRGB; + uint64_t dstRGB; + uint64_t srcAlpha; + uint64_t dstAlpha; + }; + enum GLNVGcallType { GLNVG_FILL, @@ -89,6 +97,7 @@ namespace int vertexOffset; int vertexCount; int uniformOffset; + GLNVGblend blendFunc; }; struct GLNVGpath @@ -705,16 +714,24 @@ namespace return s_blend[idx]; } - static uint64_t glnvg__blendCompositeOperation(NVGcompositeOperationState op) + static GLNVGblend glnvg__blendCompositeOperation(NVGcompositeOperationState op) { - return BGFX_STATE_BLEND_FUNC_SEPARATE( - glnvg_convertBlendFuncFactor(op.srcRGB), - glnvg_convertBlendFuncFactor(op.dstRGB), - glnvg_convertBlendFuncFactor(op.srcAlpha), - glnvg_convertBlendFuncFactor(op.dstAlpha)); + GLNVGblend blend; + blend.srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB); + blend.dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB); + blend.srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha); + blend.dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha); + if (blend.srcRGB == BGFX_STATE_NONE || blend.dstRGB == BGFX_STATE_NONE || blend.srcAlpha == BGFX_STATE_NONE || blend.dstAlpha == BGFX_STATE_NONE) + { + blend.srcRGB = BGFX_STATE_BLEND_ONE; + blend.dstRGB = BGFX_STATE_BLEND_INV_SRC_ALPHA; + blend.srcAlpha = BGFX_STATE_BLEND_ONE; + blend.dstAlpha = BGFX_STATE_BLEND_INV_SRC_ALPHA; + } + return blend; } - static void nvgRenderFlush(void* _userPtr, NVGcompositeOperationState compositeOperation) + static void nvgRenderFlush(void* _userPtr) { struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr; @@ -732,16 +749,16 @@ namespace bx::memCopy(gl->tvb.data, gl->verts, gl->nverts * sizeof(struct NVGvertex) ); - gl->state = glnvg__blendCompositeOperation(compositeOperation) - | BGFX_STATE_RGB_WRITE - | BGFX_STATE_ALPHA_WRITE - ; - bgfx::setUniform(gl->u_viewSize, gl->view); for (uint32_t ii = 0, num = gl->ncalls; ii < num; ++ii) { struct GLNVGcall* call = &gl->calls[ii]; + const GLNVGblend* blend = &call->blendFunc; + gl->state = BGFX_STATE_BLEND_FUNC_SEPARATE(blend->srcRGB, blend->dstRGB, blend->srcAlpha, blend->dstAlpha) + | BGFX_STATE_RGB_WRITE + | BGFX_STATE_ALPHA_WRITE + ; switch (call->type) { case GLNVG_FILL: @@ -850,8 +867,8 @@ namespace vtx->v = v; } - static void nvgRenderFill(void* _userPtr, struct NVGpaint* paint, struct NVGscissor* scissor, float fringe, - const float* bounds, const struct NVGpath* paths, int npaths) + static void nvgRenderFill(void* _userPtr, NVGpaint* paint, NVGcompositeOperationState compositeOperation, NVGscissor* scissor, + float fringe, const float* bounds, const NVGpath* paths, int npaths) { struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr; @@ -864,6 +881,7 @@ namespace call->pathOffset = glnvg__allocPaths(gl, npaths); call->pathCount = npaths; call->image = paint->image; + call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); if (npaths == 1 && paths[0].convex) { @@ -927,7 +945,7 @@ namespace } } - static void nvgRenderStroke(void* _userPtr, struct NVGpaint* paint, struct NVGscissor* scissor, float fringe, + static void nvgRenderStroke(void* _userPtr, struct NVGpaint* paint, NVGcompositeOperationState compositeOperation, struct NVGscissor* scissor, float fringe, float strokeWidth, const struct NVGpath* paths, int npaths) { struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr; @@ -939,6 +957,7 @@ namespace call->pathOffset = glnvg__allocPaths(gl, npaths); call->pathCount = npaths; call->image = paint->image; + call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); // Allocate vertices for all the paths. maxverts = glnvg__maxVertCount(paths, npaths); @@ -963,7 +982,7 @@ namespace glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, strokeWidth, fringe); } - static void nvgRenderTriangles(void* _userPtr, struct NVGpaint* paint, struct NVGscissor* scissor, + static void nvgRenderTriangles(void* _userPtr, struct NVGpaint* paint, NVGcompositeOperationState compositeOperation, struct NVGscissor* scissor, const struct NVGvertex* verts, int nverts) { struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr; @@ -972,6 +991,7 @@ namespace call->type = GLNVG_TRIANGLES; call->image = paint->image; + call->blendFunc = glnvg__blendCompositeOperation(compositeOperation); // Allocate vertices for all the paths. call->vertexOffset = glnvg__allocVerts(gl, nverts);