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 { | |||
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; | |||
@@ -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); | |||
@@ -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; | |||