This commit updates the implmentation of global composite operation to follow the advices described at c4b865796d (r74248556)
			
			shared-context
		| @@ -66,6 +66,7 @@ enum NVGpointFlags | |||||
| }; | }; | ||||
| struct NVGstate { | struct NVGstate { | ||||
| NVGcompositeOperationState compositeOperation; | |||||
| NVGpaint fill; | NVGpaint fill; | ||||
| NVGpaint stroke; | NVGpaint stroke; | ||||
| float strokeWidth; | float strokeWidth; | ||||
| @@ -203,6 +204,79 @@ static void nvg__setDevicePixelRatio(NVGcontext* ctx, float ratio) | |||||
| ctx->devicePxRatio = 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) | NVGcontext* nvgCreateInternal(NVGparams* params) | ||||
| { | { | ||||
| FONSparams fontParams; | FONSparams fontParams; | ||||
| @@ -310,7 +384,8 @@ void nvgCancelFrame(NVGcontext* ctx) | |||||
| void nvgEndFrame(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) { | if (ctx->fontImageIdx != 0) { | ||||
| int fontImage = ctx->fontImages[ctx->fontImageIdx]; | int fontImage = ctx->fontImages[ctx->fontImageIdx]; | ||||
| int i, j, iw, ih; | int i, j, iw, ih; | ||||
| @@ -338,25 +413,6 @@ void nvgEndFrame(NVGcontext* ctx) | |||||
| } | } | ||||
| } | } | ||||
| NVGcompositeOperation nvgBlendFunc(int sfactor, int dfactor) | |||||
| { | |||||
| return nvgBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); | |||||
| } | |||||
| NVGcompositeOperation nvgBlendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) | |||||
| { | |||||
| NVGcompositeOperation operation; | |||||
| operation.srcRGB = srcRGB; | |||||
| operation.dstRGB = dstRGB; | |||||
| operation.srcAlpha = srcAlpha; | |||||
| operation.dstAlpha = dstAlpha; | |||||
| return operation; | |||||
| } | |||||
| void nvgGlobalCompositeOperation(NVGcontext* ctx, NVGcompositeOperation op) { | |||||
| ctx->params.renderCompositeOperation(ctx->params.userPtr, op); | |||||
| } | |||||
| NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b) | NVGcolor nvgRGB(unsigned char r, unsigned char g, unsigned char b) | ||||
| { | { | ||||
| return nvgRGBA(r,g,b,255); | return nvgRGBA(r,g,b,255); | ||||
| @@ -452,12 +508,6 @@ NVGcolor nvgHSLA(float h, float s, float l, unsigned char a) | |||||
| return col; | return col; | ||||
| } | } | ||||
| static NVGstate* nvg__getState(NVGcontext* ctx) | |||||
| { | |||||
| return &ctx->states[ctx->nstates-1]; | |||||
| } | |||||
| void nvgTransformIdentity(float* t) | void nvgTransformIdentity(float* t) | ||||
| { | { | ||||
| t[0] = 1.0f; t[1] = 0.0f; | t[0] = 1.0f; t[1] = 0.0f; | ||||
| @@ -590,6 +640,7 @@ void nvgReset(NVGcontext* ctx) | |||||
| nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255)); | nvg__setPaintColor(&state->fill, nvgRGBA(255,255,255,255)); | ||||
| nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255)); | nvg__setPaintColor(&state->stroke, nvgRGBA(0,0,0,255)); | ||||
| state->compositeOperation = nvg__compositeOperationState(NVG_SOURCE_OVER); | |||||
| state->strokeWidth = 1.0f; | state->strokeWidth = 1.0f; | ||||
| state->miterLimit = 10.0f; | state->miterLimit = 10.0f; | ||||
| state->lineCap = NVG_BUTT; | state->lineCap = NVG_BUTT; | ||||
| @@ -958,6 +1009,30 @@ void nvgResetScissor(NVGcontext* ctx) | |||||
| state->scissor.extent[1] = -1.0f; | 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) | static int nvg__ptEquals(float x1, float y1, float x2, float y2, float tol) | ||||
| { | { | ||||
| float dx = x2 - x1; | float dx = x2 - x1; | ||||
| @@ -97,26 +97,27 @@ enum NVGblendFactor { | |||||
| NVG_SRC_ALPHA_SATURATE = 1<<10, | NVG_SRC_ALPHA_SATURATE = 1<<10, | ||||
| }; | }; | ||||
| struct NVGcompositeOperation { | |||||
| struct NVGcompositeOperationState { | |||||
| int srcRGB; | int srcRGB; | ||||
| int dstRGB; | int dstRGB; | ||||
| int srcAlpha; | int srcAlpha; | ||||
| int dstAlpha; | int dstAlpha; | ||||
| }; | }; | ||||
| typedef struct NVGcompositeOperation NVGcompositeOperation; | |||||
| // Predefined composite operations. | |||||
| #define NVG_SOURCE_OVER nvgBlendFunc(NVG_ONE, NVG_ONE_MINUS_SRC_ALPHA) | |||||
| #define NVG_SOURCE_IN nvgBlendFunc(NVG_DST_ALPHA, NVG_ZERO) | |||||
| #define NVG_SOURCE_OUT nvgBlendFunc(NVG_ONE_MINUS_DST_ALPHA, NVG_ZERO) | |||||
| #define NVG_ATOP nvgBlendFunc(NVG_DST_ALPHA, NVG_ONE_MINUS_SRC_ALPHA) | |||||
| #define NVG_DESTINATION_OVER nvgBlendFunc(NVG_ONE_MINUS_DST_ALPHA, NVG_ONE) | |||||
| #define NVG_DESTINATION_IN nvgBlendFunc(NVG_ZERO, NVG_SRC_ALPHA) | |||||
| #define NVG_DESTINATION_OUT nvgBlendFunc(NVG_ZERO, NVG_ONE_MINUS_SRC_ALPHA) | |||||
| #define NVG_DESTINATION_ATOP nvgBlendFunc(NVG_ONE_MINUS_DST_ALPHA, NVG_SRC_ALPHA) | |||||
| #define NVG_LIGHTER nvgBlendFunc(NVG_ONE, NVG_ONE) | |||||
| #define NVG_COPY nvgBlendFunc(NVG_ONE, NVG_ZERO) | |||||
| #define NVG_XOR nvgBlendFunc(NVG_ONE_MINUS_DST_ALPHA NVG_ONE_MINUS_SRC_ALPHA) | |||||
| typedef struct NVGcompositeOperationState NVGcompositeOperationState; | |||||
| 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 NVGglyphPosition { | struct NVGglyphPosition { | ||||
| const char* str; // Position of the glyph in the input string. | const char* str; // Position of the glyph in the input string. | ||||
| @@ -162,17 +163,16 @@ void nvgEndFrame(NVGcontext* ctx); | |||||
| // Composite operation | // Composite operation | ||||
| // | // | ||||
| // Composite operation in NanoVG works between frames. The default composite | // Composite operation in NanoVG works between frames. The default composite | ||||
| // operation of NanoVG is NVG_SOURCE_OVER, and the value is reset whenever | |||||
| // calling nvgBeginFrame(). | |||||
| // operation of NanoVG is NVG_SOURCE_OVER. | |||||
| // Creates a composite operation with custom pixel arithmetic. The parameters should be one of NVGblendFactor. | |||||
| NVGcompositeOperation nvgBlendFunc(int sfactor, int dfactor); | |||||
| // Sets the composite operation. The op parameter should be one of NVGcompositeOperation. | |||||
| void nvgGlobalCompositeOperation(NVGcontext* ctx, int op); | |||||
| // Creates a composite operation with custom pixel arithmetic for RGB and alpha components separately. The parameters should be one of NVGblendFactor. | |||||
| NVGcompositeOperation nvgBlendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha); | |||||
| // 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 for the current frame. This function should be called between nvgBeginFrame() and nvgEndFrame(). The default composite operation of NanoVG is NVG_SOURCE_OVER. | |||||
| void nvgGlobalCompositeOperation(NVGcontext* ctx, NVGcompositeOperation op); | |||||
| // 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 | // Color utils | ||||
| @@ -641,8 +641,7 @@ struct NVGparams { | |||||
| int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h); | int (*renderGetTextureSize)(void* uptr, int image, int* w, int* h); | ||||
| void (*renderViewport)(void* uptr, int width, int height, float devicePixelRatio); | void (*renderViewport)(void* uptr, int width, int height, float devicePixelRatio); | ||||
| void (*renderCancel)(void* uptr); | void (*renderCancel)(void* uptr); | ||||
| void (*renderCompositeOperation)(void* uptr, NVGcompositeOperation op); | |||||
| 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 (*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 (*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 (*renderTriangles)(void* uptr, NVGpaint* paint, NVGscissor* scissor, const NVGvertex* verts, int nverts); | ||||
| @@ -219,7 +219,6 @@ struct GLNVGfragUniforms { | |||||
| typedef struct GLNVGfragUniforms GLNVGfragUniforms; | typedef struct GLNVGfragUniforms GLNVGfragUniforms; | ||||
| struct GLNVGcontext { | struct GLNVGcontext { | ||||
| NVGcompositeOperation compositeOperation; | |||||
| GLNVGshader shader; | GLNVGshader shader; | ||||
| GLNVGtexture* textures; | GLNVGtexture* textures; | ||||
| float view[2]; | float view[2]; | ||||
| @@ -945,7 +944,6 @@ static void glnvg__setUniforms(GLNVGcontext* gl, int uniformOffset, int image) | |||||
| static void glnvg__renderViewport(void* uptr, int width, int height, float devicePixelRatio) | static void glnvg__renderViewport(void* uptr, int width, int height, float devicePixelRatio) | ||||
| { | { | ||||
| GLNVGcontext* gl = (GLNVGcontext*)uptr; | GLNVGcontext* gl = (GLNVGcontext*)uptr; | ||||
| gl->compositeOperation = NVG_SOURCE_OVER; // resets composition | |||||
| gl->view[0] = (float)width; | gl->view[0] = (float)width; | ||||
| gl->view[1] = (float)height; | gl->view[1] = (float)height; | ||||
| } | } | ||||
| @@ -1100,18 +1098,12 @@ static GLenum glnvg_convertBlendFuncFactor(int factor) | |||||
| return GL_SRC_ALPHA_SATURATE; | return GL_SRC_ALPHA_SATURATE; | ||||
| } | } | ||||
| static void glnvg__blendCompositeOperation(NVGcompositeOperation operation) | |||||
| static void glnvg__blendCompositeOperation(NVGcompositeOperationState op) | |||||
| { | { | ||||
| glBlendFuncSeparate(glnvg_convertBlendFuncFactor(operation.srcRGB), glnvg_convertBlendFuncFactor(operation.dstRGB), glnvg_convertBlendFuncFactor(operation.srcAlpha), glnvg_convertBlendFuncFactor(operation.dstAlpha)); | |||||
| glBlendFuncSeparate(glnvg_convertBlendFuncFactor(op.srcRGB), glnvg_convertBlendFuncFactor(op.dstRGB), glnvg_convertBlendFuncFactor(op.srcAlpha), glnvg_convertBlendFuncFactor(op.dstAlpha)); | |||||
| } | } | ||||
| static void glnvg__renderCompositeOperation(void* uptr, NVGcompositeOperation op) | |||||
| { | |||||
| GLNVGcontext* gl = (GLNVGcontext*)uptr; | |||||
| gl->compositeOperation = op; | |||||
| } | |||||
| static void glnvg__renderFlush(void* uptr) | |||||
| static void glnvg__renderFlush(void* uptr, NVGcompositeOperationState compositeOperation) | |||||
| { | { | ||||
| GLNVGcontext* gl = (GLNVGcontext*)uptr; | GLNVGcontext* gl = (GLNVGcontext*)uptr; | ||||
| int i; | int i; | ||||
| @@ -1121,7 +1113,7 @@ static void glnvg__renderFlush(void* uptr) | |||||
| // Setup require GL state. | // Setup require GL state. | ||||
| glUseProgram(gl->shader.prog); | glUseProgram(gl->shader.prog); | ||||
| glnvg__blendCompositeOperation(gl->compositeOperation); | |||||
| glnvg__blendCompositeOperation(compositeOperation); | |||||
| glEnable(GL_CULL_FACE); | glEnable(GL_CULL_FACE); | ||||
| glCullFace(GL_BACK); | glCullFace(GL_BACK); | ||||
| glFrontFace(GL_CCW); | glFrontFace(GL_CCW); | ||||
| @@ -1512,7 +1504,6 @@ NVGcontext* nvgCreateGLES3(int flags) | |||||
| params.renderGetTextureSize = glnvg__renderGetTextureSize; | params.renderGetTextureSize = glnvg__renderGetTextureSize; | ||||
| params.renderViewport = glnvg__renderViewport; | params.renderViewport = glnvg__renderViewport; | ||||
| params.renderCancel = glnvg__renderCancel; | params.renderCancel = glnvg__renderCancel; | ||||
| params.renderCompositeOperation = glnvg__renderCompositeOperation; | |||||
| params.renderFlush = glnvg__renderFlush; | params.renderFlush = glnvg__renderFlush; | ||||
| params.renderFill = glnvg__renderFill; | params.renderFill = glnvg__renderFill; | ||||
| params.renderStroke = glnvg__renderStroke; | params.renderStroke = glnvg__renderStroke; | ||||