diff --git a/src/nanovg.c b/src/nanovg.c index 2ac3503..734e12d 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -66,6 +66,7 @@ enum NVGpointFlags }; struct NVGstate { + NVGcompositeOperationState compositeOperation; NVGpaint fill; NVGpaint stroke; float strokeWidth; @@ -203,6 +204,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; @@ -310,7 +384,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; @@ -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) { return nvgRGBA(r,g,b,255); @@ -452,12 +508,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; @@ -590,6 +640,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; @@ -958,6 +1009,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/src/nanovg.h b/src/nanovg.h index 3c2c4a4..32c6837 100644 --- a/src/nanovg.h +++ b/src/nanovg.h @@ -97,26 +97,27 @@ enum NVGblendFactor { NVG_SRC_ALPHA_SATURATE = 1<<10, }; -struct NVGcompositeOperation { +struct NVGcompositeOperationState { int srcRGB; int dstRGB; int srcAlpha; 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 { const char* str; // Position of the glyph in the input string. @@ -162,17 +163,16 @@ void nvgEndFrame(NVGcontext* ctx); // Composite operation // // 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 @@ -641,8 +641,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 (*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 (*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/src/nanovg_gl.h b/src/nanovg_gl.h index b368319..fa3c992 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -219,7 +219,6 @@ struct GLNVGfragUniforms { typedef struct GLNVGfragUniforms GLNVGfragUniforms; struct GLNVGcontext { - NVGcompositeOperation compositeOperation; GLNVGshader shader; GLNVGtexture* textures; 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) { GLNVGcontext* gl = (GLNVGcontext*)uptr; - gl->compositeOperation = NVG_SOURCE_OVER; // resets composition gl->view[0] = (float)width; gl->view[1] = (float)height; } @@ -1100,18 +1098,12 @@ static GLenum glnvg_convertBlendFuncFactor(int factor) 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; int i; @@ -1121,7 +1113,7 @@ static void glnvg__renderFlush(void* uptr) // Setup require GL state. glUseProgram(gl->shader.prog); - glnvg__blendCompositeOperation(gl->compositeOperation); + glnvg__blendCompositeOperation(compositeOperation); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); @@ -1512,7 +1504,6 @@ NVGcontext* nvgCreateGLES3(int flags) params.renderGetTextureSize = glnvg__renderGetTextureSize; params.renderViewport = glnvg__renderViewport; params.renderCancel = glnvg__renderCancel; - params.renderCompositeOperation = glnvg__renderCompositeOperation; params.renderFlush = glnvg__renderFlush; params.renderFill = glnvg__renderFill; params.renderStroke = glnvg__renderStroke;