Browse Source

Merge pull request #298 from olliwang/blend

Implements composite operation for blending renderings.
shared-context
Mikko Mononen GitHub 8 years ago
parent
commit
71774e0afe
3 changed files with 195 additions and 18 deletions
  1. +101
    -7
      src/nanovg.c
  2. +61
    -9
      src/nanovg.h
  3. +33
    -2
      src/nanovg_gl.h

+ 101
- 7
src/nanovg.c View File

@@ -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;
@@ -433,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;
@@ -571,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;
@@ -939,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;


+ 61
- 9
src/nanovg.h View File

@@ -79,10 +79,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.
@@ -123,6 +159,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
//
@@ -183,7 +235,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);
@@ -231,7 +283,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);
@@ -368,7 +420,7 @@ 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 various
// user interface cases like rendering a text edit or a timeline.
// 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.
@@ -423,7 +475,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,
@@ -440,7 +492,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.
@@ -503,7 +555,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.
@@ -590,7 +642,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);


+ 33
- 2
src/nanovg_gl.h View File

@@ -1072,7 +1072,38 @@ static void glnvg__renderCancel(void* uptr) {
gl->nuniforms = 0;
}

static void glnvg__renderFlush(void* uptr)
static GLenum glnvg_convertBlendFuncFactor(int factor)
{
if (factor == NVG_ZERO)
return GL_ZERO;
if (factor == NVG_ONE)
return GL_ONE;
if (factor == NVG_SRC_COLOR)
return GL_SRC_COLOR;
if (factor == NVG_ONE_MINUS_SRC_COLOR)
return GL_ONE_MINUS_SRC_COLOR;
if (factor == NVG_DST_COLOR)
return GL_DST_COLOR;
if (factor == NVG_ONE_MINUS_DST_COLOR)
return GL_ONE_MINUS_DST_COLOR;
if (factor == NVG_SRC_ALPHA)
return GL_SRC_ALPHA;
if (factor == NVG_ONE_MINUS_SRC_ALPHA)
return GL_ONE_MINUS_SRC_ALPHA;
if (factor == NVG_DST_ALPHA)
return GL_DST_ALPHA;
if (factor == NVG_ONE_MINUS_DST_ALPHA)
return GL_ONE_MINUS_DST_ALPHA;
if (factor == NVG_SRC_ALPHA_SATURATE)
return GL_SRC_ALPHA_SATURATE;
}

static void glnvg__blendCompositeOperation(NVGcompositeOperationState op)
{
glBlendFuncSeparate(glnvg_convertBlendFuncFactor(op.srcRGB), glnvg_convertBlendFuncFactor(op.dstRGB), glnvg_convertBlendFuncFactor(op.srcAlpha), glnvg_convertBlendFuncFactor(op.dstAlpha));
}

static void glnvg__renderFlush(void* uptr, NVGcompositeOperationState compositeOperation)
{
GLNVGcontext* gl = (GLNVGcontext*)uptr;
int i;
@@ -1082,7 +1113,7 @@ static void glnvg__renderFlush(void* uptr)
// Setup require GL state.
glUseProgram(gl->shader.prog);

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glnvg__blendCompositeOperation(compositeOperation);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);


Loading…
Cancel
Save