diff --git a/examples/common/nanovg/nanovg.cpp b/examples/common/nanovg/nanovg.cpp index c7433cdc4..8d4e6ee8d 100644 --- a/examples/common/nanovg/nanovg.cpp +++ b/examples/common/nanovg/nanovg.cpp @@ -110,6 +110,7 @@ enum NVGpointFlags }; struct NVGstate { + NVGcompositeOperationState compositeOperation; NVGpaint fill; NVGpaint stroke; float strokeWidth; @@ -247,6 +248,79 @@ static void nvg__setDevicePixelRatio(NVGcontext* ctx, float ratio) ctx->devicePxRatio = ratio; } +static NVGcompositeOperationState nvg__compositeOperationState(int op) +{ + int sfactor, dfactor; + + if (op == NVG_SOURCE_OVER) + { + sfactor = NVG_ONE; + dfactor = NVG_ONE_MINUS_SRC_ALPHA; + } + else if (op == NVG_SOURCE_IN) + { + sfactor = NVG_DST_ALPHA; + dfactor = NVG_ZERO; + } + else if (op == NVG_SOURCE_OUT) + { + sfactor = NVG_ONE_MINUS_DST_ALPHA; + dfactor = NVG_ZERO; + } + else if (op == NVG_ATOP) + { + sfactor = NVG_DST_ALPHA; + dfactor = NVG_ONE_MINUS_SRC_ALPHA; + } + else if (op == NVG_DESTINATION_OVER) + { + sfactor = NVG_ONE_MINUS_DST_ALPHA; + dfactor = NVG_ONE; + } + else if (op == NVG_DESTINATION_IN) + { + sfactor = NVG_ZERO; + dfactor = NVG_SRC_ALPHA; + } + else if (op == NVG_DESTINATION_OUT) + { + sfactor = NVG_ZERO; + dfactor = NVG_ONE_MINUS_SRC_ALPHA; + } + else if (op == NVG_DESTINATION_ATOP) + { + sfactor = NVG_ONE_MINUS_DST_ALPHA; + dfactor = NVG_SRC_ALPHA; + } + else if (op == NVG_LIGHTER) + { + sfactor = NVG_ONE; + dfactor = NVG_ONE; + } + else if (op == NVG_COPY) + { + sfactor = NVG_ONE; + dfactor = NVG_ZERO; + } + else if (op == NVG_XOR) + { + sfactor = NVG_ONE_MINUS_DST_ALPHA; + dfactor = NVG_ONE_MINUS_SRC_ALPHA; + } + + NVGcompositeOperationState state; + state.srcRGB = sfactor; + state.dstRGB = dfactor; + state.srcAlpha = sfactor; + state.dstAlpha = dfactor; + return state; +} + +static NVGstate* nvg__getState(NVGcontext* ctx) +{ + return &ctx->states[ctx->nstates-1]; +} + NVGcontext* nvgCreateInternal(NVGparams* params) { FONSparams fontParams; @@ -354,7 +428,8 @@ void nvgCancelFrame(NVGcontext* ctx) void nvgEndFrame(NVGcontext* ctx) { - ctx->params.renderFlush(ctx->params.userPtr); + NVGstate* state = nvg__getState(ctx); + ctx->params.renderFlush(ctx->params.userPtr, state->compositeOperation); if (ctx->fontImageIdx != 0) { int fontImage = ctx->fontImages[ctx->fontImageIdx]; int i, j, iw, ih; @@ -430,7 +505,7 @@ NVGcolor nvgLerpRGBA(NVGcolor c0, NVGcolor c1, float u) { int i; float oneminu; - NVGcolor cint; + NVGcolor cint = {0}; u = nvg__clampf(u, 0.0f, 1.0f); oneminu = 1.0f - u; @@ -477,12 +552,6 @@ NVGcolor nvgHSLA(float h, float s, float l, unsigned char a) return col; } - -static NVGstate* nvg__getState(NVGcontext* ctx) -{ - return &ctx->states[ctx->nstates-1]; -} - void nvgTransformIdentity(float* t) { t[0] = 1.0f; t[1] = 0.0f; @@ -615,6 +684,7 @@ void nvgReset(NVGcontext* ctx) nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255)); nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255)); + state->compositeOperation = nvg__compositeOperationState(NVG_SOURCE_OVER); state->strokeWidth = 1.0f; state->miterLimit = 10.0f; state->lineCap = NVG_BUTT; @@ -983,6 +1053,30 @@ void nvgResetScissor(NVGcontext* ctx) state->scissor.extent[1] = -1.0f; } +// Global composite operation. +void nvgGlobalCompositeOperation(NVGcontext* ctx, int op) +{ + NVGstate* state = nvg__getState(ctx); + state->compositeOperation = nvg__compositeOperationState(op); +} + +void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor) +{ + nvgGlobalCompositeBlendFuncSeparate(ctx, sfactor, dfactor, sfactor, dfactor); +} + +void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) +{ + NVGcompositeOperationState op; + op.srcRGB = srcRGB; + op.dstRGB = dstRGB; + op.srcAlpha = srcAlpha; + op.dstAlpha = dstAlpha; + + NVGstate* state = nvg__getState(ctx); + state->compositeOperation = op; +} + static int nvg__ptEquals(float x1, float y1, float x2, float y2, float tol) { float dx = x2 - x1; diff --git a/examples/common/nanovg/nanovg.h b/examples/common/nanovg/nanovg.h index 984c1935e..99797e21f 100644 --- a/examples/common/nanovg/nanovg.h +++ b/examples/common/nanovg/nanovg.h @@ -81,10 +81,46 @@ enum NVGalign { // Vertical align NVG_ALIGN_TOP = 1<<3, // Align text vertically to top. NVG_ALIGN_MIDDLE = 1<<4, // Align text vertically to middle. - NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom. - NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline. + NVG_ALIGN_BOTTOM = 1<<5, // Align text vertically to bottom. + NVG_ALIGN_BASELINE = 1<<6, // Default, align text vertically to baseline. }; +enum NVGblendFactor { + NVG_ZERO = 1<<0, + NVG_ONE = 1<<1, + NVG_SRC_COLOR = 1<<2, + NVG_ONE_MINUS_SRC_COLOR = 1<<3, + NVG_DST_COLOR = 1<<4, + NVG_ONE_MINUS_DST_COLOR = 1<<5, + NVG_SRC_ALPHA = 1<<6, + NVG_ONE_MINUS_SRC_ALPHA = 1<<7, + NVG_DST_ALPHA = 1<<8, + NVG_ONE_MINUS_DST_ALPHA = 1<<9, + NVG_SRC_ALPHA_SATURATE = 1<<10, +}; + +enum NVGcompositeOperation { + NVG_SOURCE_OVER, + NVG_SOURCE_IN, + NVG_SOURCE_OUT, + NVG_ATOP, + NVG_DESTINATION_OVER, + NVG_DESTINATION_IN, + NVG_DESTINATION_OUT, + NVG_DESTINATION_ATOP, + NVG_LIGHTER, + NVG_COPY, + NVG_XOR, +}; + +struct NVGcompositeOperationState { + int srcRGB; + int dstRGB; + int srcAlpha; + int dstAlpha; +}; +typedef struct NVGcompositeOperationState NVGcompositeOperationState; + struct NVGglyphPosition { const char* str; // Position of the glyph in the input string. float x; // The x-coordinate of the logical glyph position. @@ -125,6 +161,22 @@ void nvgCancelFrame(NVGcontext* ctx); // Ends drawing flushing remaining render state. void nvgEndFrame(NVGcontext* ctx); +// +// Composite operation +// +// The composite operations in NanoVG are modeled after HTML Canvas API, and +// the blend func is based on OpenGL (see corresponding manuals for more info). +// The colors in the blending state have premultiplied alpha. + +// Sets the composite operation. The op parameter should be one of NVGcompositeOperation. +void nvgGlobalCompositeOperation(NVGcontext* ctx, int op); + +// Sets the composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor. +void nvgGlobalCompositeBlendFunc(NVGcontext* ctx, int sfactor, int dfactor); + +// Sets the composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor. +void nvgGlobalCompositeBlendFuncSeparate(NVGcontext* ctx, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha); + // // Color utils // @@ -185,7 +237,7 @@ void nvgReset(NVGcontext* ctx); // Solid color is simply defined as a color value, different kinds of paints can be created // using nvgLinearGradient(), nvgBoxGradient(), nvgRadialGradient() and nvgImagePattern(). // -// Current render style can be saved and restored using nvgSave() and nvgRestore(). +// Current render style can be saved and restored using nvgSave() and nvgRestore(). // Sets current stroke style to a solid color. void nvgStrokeColor(NVGcontext* ctx, NVGcolor color); @@ -215,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); // @@ -233,7 +285,7 @@ void nvgGlobalAlpha(NVGcontext* ctx, float alpha); // Apart from nvgResetTransform(), each transformation function first creates // specific transformation matrix and pre-multiplies the current transformation by it. // -// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore(). +// Current coordinate system (transformation) can be saved and restored using nvgSave() and nvgRestore(). // Resets current transform to a identity matrix. void nvgResetTransform(NVGcontext* ctx); @@ -347,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(). @@ -369,8 +421,8 @@ NVGpaint nvgImagePattern(NVGcontext* ctx, float ox, float oy, float ex, float ey // // Scissoring // -// Scissoring allows you to clip the rendering into a rectangle. This is useful for varius -// user interface cases like rendering a text edit or a timeline. +// Scissoring allows you to clip the rendering into a rectangle. This is useful for various +// user interface cases like rendering a text edit or a timeline. // Sets the current scissor rectangle. // The scissor rectangle is transformed by the current transform. @@ -425,7 +477,7 @@ void nvgArcTo(NVGcontext* ctx, float x1, float y1, float x2, float y2, float rad // Closes current sub-path with a line segment. void nvgClosePath(NVGcontext* ctx); -// Sets the current sub-path winding, see NVGwinding and NVGsolidity. +// Sets the current sub-path winding, see NVGwinding and NVGsolidity. void nvgPathWinding(NVGcontext* ctx, int dir); // Creates new circle arc shaped sub-path. The arc center is at cx,cy, the arc radius is r, @@ -442,7 +494,7 @@ void nvgRoundedRect(NVGcontext* ctx, float x, float y, float w, float h, float r // Creates new ellipse shaped sub-path. void nvgEllipse(NVGcontext* ctx, float cx, float cy, float rx, float ry); -// Creates new circle shaped sub-path. +// Creates new circle shaped sub-path. void nvgCircle(NVGcontext* ctx, float cx, float cy, float r); // Fills the current path with current fill style. @@ -489,7 +541,7 @@ void nvgStroke(NVGcontext* ctx); // Returns handle to the font. int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename); -// Creates image by loading it from the specified memory chunk. +// Creates font by loading it from the specified memory chunk. // Returns handle to the font. int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData); @@ -505,7 +557,7 @@ void nvgFontBlur(NVGcontext* ctx, float blur); // Sets the letter spacing of current text style. void nvgTextLetterSpacing(NVGcontext* ctx, float spacing); -// Sets the proportional line height of current text style. The line height is specified as multiple of font size. +// Sets the proportional line height of current text style. The line height is specified as multiple of font size. void nvgTextLineHeight(NVGcontext* ctx, float lineHeight); // Sets the text align of current text style, see NVGalign for options. @@ -592,7 +644,7 @@ 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); + 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); diff --git a/examples/common/nanovg/nanovg_bgfx.cpp b/examples/common/nanovg/nanovg_bgfx.cpp index d50e6b93f..b7216d0fb 100644 --- a/examples/common/nanovg/nanovg_bgfx.cpp +++ b/examples/common/nanovg/nanovg_bgfx.cpp @@ -537,7 +537,6 @@ namespace static void nvgRenderViewport(void* _userPtr, int width, int height, float devicePixelRatio) { struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr; - gl->state = 0; gl->view[0] = (float)width; gl->view[1] = (float)height; bgfx::setViewRect(gl->m_viewId, 0, 0, width * devicePixelRatio, height * devicePixelRatio); @@ -694,7 +693,42 @@ namespace } } - static void nvgRenderFlush(void* _userPtr) + static uint64_t glnvg_convertBlendFuncFactor(int factor) + { + if (factor == NVG_ZERO) + return BGFX_STATE_BLEND_ZERO; + if (factor == NVG_ONE) + return BGFX_STATE_BLEND_ONE; + if (factor == NVG_SRC_COLOR) + return BGFX_STATE_BLEND_SRC_COLOR; + if (factor == NVG_ONE_MINUS_SRC_COLOR) + return BGFX_STATE_BLEND_INV_SRC_COLOR; + if (factor == NVG_DST_COLOR) + return BGFX_STATE_BLEND_DST_COLOR; + if (factor == NVG_ONE_MINUS_DST_COLOR) + return BGFX_STATE_BLEND_INV_DST_COLOR; + if (factor == NVG_SRC_ALPHA) + return BGFX_STATE_BLEND_SRC_ALPHA; + if (factor == NVG_ONE_MINUS_SRC_ALPHA) + return BGFX_STATE_BLEND_INV_SRC_ALPHA; + if (factor == NVG_DST_ALPHA) + return BGFX_STATE_BLEND_DST_ALPHA; + if (factor == NVG_ONE_MINUS_DST_ALPHA) + return BGFX_STATE_BLEND_INV_DST_ALPHA; + if (factor == NVG_SRC_ALPHA_SATURATE) + return BGFX_STATE_BLEND_SRC_ALPHA_SAT; + } + + static uint64_t 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)); + } + + static void nvgRenderFlush(void* _userPtr, NVGcompositeOperationState compositeOperation) { struct GLNVGcontext* gl = (struct GLNVGcontext*)_userPtr; @@ -712,12 +746,7 @@ namespace memcpy(gl->tvb.data, gl->verts, gl->nverts * sizeof(struct NVGvertex) ); - if (0 == gl->state) - { - gl->state = BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_ALPHA); - } - - gl->state |= 0 + gl->state = glnvg__blendCompositeOperation(compositeOperation) | BGFX_STATE_RGB_WRITE | BGFX_STATE_ALPHA_WRITE ; @@ -1078,13 +1107,6 @@ void nvgDelete(struct NVGcontext* ctx) nvgDeleteInternal(ctx); } -void nvgState(struct NVGcontext* ctx, uint64_t state) -{ - struct NVGparams* params = nvgInternalParams(ctx); - struct GLNVGcontext* gl = (struct GLNVGcontext*)params->userPtr; - gl->state = state; -} - uint8_t nvgViewId(struct NVGcontext* ctx) { struct NVGparams* params = nvgInternalParams(ctx); @@ -1144,9 +1166,9 @@ void nvgluBindFramebuffer(NVGLUframebuffer* framebuffer) { void nvgluDeleteFramebuffer(NVGLUframebuffer* framebuffer) { if (framebuffer == NULL) return; - if (framebuffer->image >= 0) - nvgDeleteImage(framebuffer->ctx, framebuffer->image); if (bgfx::isValid(framebuffer->handle)) bgfx::destroyFrameBuffer(framebuffer->handle); + if (framebuffer->image > 0) + nvgDeleteImage(framebuffer->ctx, framebuffer->image); delete framebuffer; } diff --git a/examples/common/nanovg/nanovg_bgfx.h b/examples/common/nanovg/nanovg_bgfx.h index 2268e900f..61b0e3e06 100644 --- a/examples/common/nanovg/nanovg_bgfx.h +++ b/examples/common/nanovg/nanovg_bgfx.h @@ -23,7 +23,6 @@ typedef struct NVGLUframebuffer NVGLUframebuffer; NVGcontext* nvgCreate(int edgeaa, unsigned char _viewId, bx::AllocatorI* _allocator); NVGcontext* nvgCreate(int edgeaa, unsigned char _viewId); void nvgDelete(struct NVGcontext* ctx); -void nvgState(struct NVGcontext* ctx, uint64_t state); uint8_t nvgViewId(struct NVGcontext* ctx); void nvgViewId(struct NVGcontext* ctx, unsigned char _viewId);