From fcbb561df65e6870d71c7a408b0b5388066c99d7 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Thu, 1 Mar 2018 21:58:38 -0500 Subject: [PATCH] fix composite ops --- nanovega.d | 117 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/nanovega.d b/nanovega.d index 512e9b9..a63774a 100644 --- a/nanovega.d +++ b/nanovega.d @@ -56,8 +56,6 @@ $(SIDE_BY_SIDE // we must create NanoVega context here, as it needs to initialize // internal OpenGL subsystem with valid OpenGL context. sdmain.visibleForTheFirstTime = delegate () { - sdmain.setAsCurrentOpenGlContext(); // make this window's OpenGL context active - // yes, that's all nvg = nvgCreateContext(); if (nvg is null) assert(0, "cannot initialize NanoVega"); @@ -1197,6 +1195,7 @@ public enum NVGCompositeOperation { /// Composite operation state. /// Group: composite_operation public struct NVGCompositeOperationState { + bool simple; /// `true`: use `glBlendFunc()` instead of `glBlendFuncSeparate()` NVGBlendFactor srcRGB; /// NVGBlendFactor dstRGB; /// NVGBlendFactor srcAlpha; /// @@ -1324,10 +1323,10 @@ struct NVGparams { bool function (void* uptr, int image, int* w, int* h) nothrow @trusted @nogc renderGetTextureSize; void function (void* uptr, int width, int height) nothrow @trusted @nogc renderViewport; void function (void* uptr) nothrow @trusted @nogc renderCancel; - void function (void* uptr, NVGCompositeOperationState compositeOperation) nothrow @trusted @nogc renderFlush; - void function (void* uptr, NVGPaint* paint, NVGscissor* scissor, float fringe, const(float)* bounds, const(NVGpath)* paths, int npaths, bool evenOdd) nothrow @trusted @nogc renderFill; - void function (void* uptr, NVGPaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const(NVGpath)* paths, int npaths) nothrow @trusted @nogc renderStroke; - void function (void* uptr, NVGPaint* paint, NVGscissor* scissor, const(NVGvertex)* verts, int nverts) nothrow @trusted @nogc renderTriangles; + void function (void* uptr) nothrow @trusted @nogc renderFlush; + void function (void* uptr, NVGCompositeOperationState compositeOperation, NVGPaint* paint, NVGscissor* scissor, float fringe, const(float)* bounds, const(NVGpath)* paths, int npaths, bool evenOdd) nothrow @trusted @nogc renderFill; + void function (void* uptr, NVGCompositeOperationState compositeOperation, NVGPaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const(NVGpath)* paths, int npaths) nothrow @trusted @nogc renderStroke; + void function (void* uptr, NVGCompositeOperationState compositeOperation, NVGPaint* paint, NVGscissor* scissor, const(NVGvertex)* verts, int nverts) nothrow @trusted @nogc renderTriangles; void function (void* uptr, in ref NVGMatrix mat) nothrow @trusted @nogc renderSetAffine; void function (void* uptr) nothrow @trusted @nogc renderDelete; } @@ -1665,7 +1664,9 @@ void nvg__setDevicePixelRatio (NVGContext ctx, float ratio) pure nothrow @safe @ } NVGCompositeOperationState nvg__compositeOperationState (NVGCompositeOperation op) pure nothrow @safe @nogc { + NVGCompositeOperationState state; NVGBlendFactor sfactor, dfactor; + if (op == NVGCompositeOperation.SourceOver) { sfactor = NVGBlendFactor.One; dfactor = NVGBlendFactor.OneMinusSrcAlpha;} else if (op == NVGCompositeOperation.SourceIn) { sfactor = NVGBlendFactor.DstAlpha; dfactor = NVGBlendFactor.Zero; } else if (op == NVGCompositeOperation.SourceOut) { sfactor = NVGBlendFactor.OneMinusDstAlpha; dfactor = NVGBlendFactor.Zero; } @@ -1676,12 +1677,17 @@ NVGCompositeOperationState nvg__compositeOperationState (NVGCompositeOperation o else if (op == NVGCompositeOperation.DestinationAtop) { sfactor = NVGBlendFactor.OneMinusDstAlpha; dfactor = NVGBlendFactor.SrcAlpha; } else if (op == NVGCompositeOperation.Lighter) { sfactor = NVGBlendFactor.One; dfactor = NVGBlendFactor.One; } else if (op == NVGCompositeOperation.Copy) { sfactor = NVGBlendFactor.One; dfactor = NVGBlendFactor.Zero; } - else if (op == NVGCompositeOperation.Xor) { sfactor = NVGBlendFactor.OneMinusDstAlpha; dfactor = NVGBlendFactor.OneMinusSrcAlpha; } + else if (op == NVGCompositeOperation.Xor) { + state.simple = false; + state.srcRGB = NVGBlendFactor.OneMinusDstColor; + state.srcAlpha = NVGBlendFactor.OneMinusDstAlpha; + state.dstRGB = NVGBlendFactor.OneMinusSrcColor; + state.dstAlpha = NVGBlendFactor.OneMinusSrcAlpha; + return state; + } else { sfactor = NVGBlendFactor.One; dfactor = NVGBlendFactor.OneMinusSrcAlpha;} // default value for invalid op: SourceOver - NVGCompositeOperationState state; - state.srcRGB = sfactor; - state.dstRGB = dfactor; + state.simple = true; state.srcAlpha = sfactor; state.dstAlpha = dfactor; return state; @@ -1879,7 +1885,7 @@ public void endFrame (NVGContext ctx) nothrow @trusted @nogc { ctx.mDeviceRatio = 0; // flush render queue NVGstate* state = nvg__getState(ctx); - ctx.params.renderFlush(ctx.params.userPtr, state.compositeOperation); + ctx.params.renderFlush(ctx.params.userPtr); if (ctx.fontImageIdx != 0) { auto fontImage = ctx.fontImages[ctx.fontImageIdx]; int j = 0, iw, ih; @@ -1991,7 +1997,7 @@ private: fillPaint.innerColor.applyTint(fillTint); fillPaint.outerColor.applyTint(fillTint); - ctx.params.renderFill(ctx.params.userPtr, &fillPaint, &state.scissor, cc.fringeWidth, cc.bounds.ptr, cc.paths, cc.npaths, cc.evenOddMode); + ctx.params.renderFill(ctx.params.userPtr, state.compositeOperation, &fillPaint, &state.scissor, cc.fringeWidth, cc.bounds.ptr, cc.paths, cc.npaths, cc.evenOddMode); // count triangles foreach (int i; 0..cc.npaths) { @@ -2015,7 +2021,7 @@ private: strokePaint.innerColor.applyTint(strokeTint); strokePaint.outerColor.applyTint(strokeTint); - ctx.params.renderStroke(ctx.params.userPtr, &strokePaint, &state.scissor, cc.fringeWidth, cc.strokeWidth, cc.paths, cc.npaths); + ctx.params.renderStroke(ctx.params.userPtr, state.compositeOperation, &strokePaint, &state.scissor, cc.fringeWidth, cc.strokeWidth, cc.paths, cc.npaths); // count triangles foreach (int i; 0..cc.npaths) { @@ -2286,6 +2292,7 @@ public void globalCompositeBlendFunc (NVGContext ctx, NVGBlendFactor sfactor, NV /// Group: composite_operation public void globalCompositeBlendFuncSeparate (NVGContext ctx, NVGBlendFactor srcRGB, NVGBlendFactor dstRGB, NVGBlendFactor srcAlpha, NVGBlendFactor dstAlpha) nothrow @trusted @nogc { NVGCompositeOperationState op; + op.simple = false; op.srcRGB = srcRGB; op.dstRGB = dstRGB; op.srcAlpha = srcAlpha; @@ -5138,7 +5145,7 @@ public void fill (NVGContext ctx) nothrow @trusted @nogc { if (ctx.recblockdraw) return; - ctx.params.renderFill(ctx.params.userPtr, &fillPaint, &state.scissor, ctx.fringeWidth, ctx.cache.bounds.ptr, ctx.cache.paths, ctx.cache.npaths, state.evenOddMode); + ctx.params.renderFill(ctx.params.userPtr, state.compositeOperation, &fillPaint, &state.scissor, ctx.fringeWidth, ctx.cache.bounds.ptr, ctx.cache.paths, ctx.cache.npaths, state.evenOddMode); // count triangles foreach (int i; 0..ctx.cache.npaths) { @@ -5175,7 +5182,7 @@ public void stroke (NVGContext ctx) nothrow @trusted @nogc { if (ctx.recblockdraw) return; - ctx.params.renderStroke(ctx.params.userPtr, &strokePaint, &state.scissor, ctx.fringeWidth, cache.strokeWidth, ctx.cache.paths, ctx.cache.npaths); + ctx.params.renderStroke(ctx.params.userPtr, state.compositeOperation, &strokePaint, &state.scissor, ctx.fringeWidth, cache.strokeWidth, ctx.cache.paths, ctx.cache.npaths); // count triangles foreach (int i; 0..ctx.cache.npaths) { @@ -7193,7 +7200,7 @@ void nvg__renderText (NVGContext ctx, NVGvertex* verts, int nverts) nothrow @tru paint.innerColor.a *= state.alpha; paint.outerColor.a *= state.alpha; - ctx.params.renderTriangles(ctx.params.userPtr, &paint, &state.scissor, verts, nverts); + ctx.params.renderTriangles(ctx.params.userPtr, state.compositeOperation, &paint, &state.scissor, verts, nverts); ++ctx.drawCallCount; ctx.textTriCount += nverts/3; @@ -10990,6 +10997,14 @@ struct GLNVGtexture { int nextfree; } +struct GLNVGblend { + bool simple; + GLenum srcRGB; + GLenum dstRGB; + GLenum srcAlpha; + GLenum dstAlpha; +} + alias GLNVGcallType = int; enum /*GLNVGcallType*/ { GLNVG_NONE = 0, @@ -11010,6 +11025,7 @@ struct GLNVGcall { int triangleCount; int uniformOffset; NVGMatrix affine; + GLNVGblend blendFunc; } struct GLNVGpath { @@ -11078,6 +11094,7 @@ struct GLNVGcontext { GLenum stencilFunc; GLint stencilFuncRef; GLuint stencilFuncMask; + GLNVGblend blendFunc; } } @@ -11787,7 +11804,7 @@ void glnvg__renderCancel (void* uptr) nothrow @trusted @nogc { gl.nuniforms = 0; } -GLenum glnvg_convertBlendFuncFactor (NVGBlendFactor factor) nothrow @trusted @nogc { +GLenum glnvg_convertBlendFuncFactor (NVGBlendFactor factor) pure nothrow @trusted @nogc { if (factor == NVGBlendFactor.Zero) return GL_ZERO; if (factor == NVGBlendFactor.One) return GL_ONE; if (factor == NVGBlendFactor.SrcColor) return GL_SRC_COLOR; @@ -11802,18 +11819,52 @@ GLenum glnvg_convertBlendFuncFactor (NVGBlendFactor factor) nothrow @trusted @no return GL_INVALID_ENUM; } -void glnvg__blendCompositeOperation (NVGCompositeOperationState op) nothrow @trusted @nogc { +GLNVGblend glnvg__buildBlendFunc (NVGCompositeOperationState op) pure nothrow @trusted @nogc { + GLNVGblend res; + res.simple = op.simple; + res.srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB); + res.dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB); + res.srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha); + res.dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha); + if (res.simple) { + if (res.srcAlpha == GL_INVALID_ENUM || res.dstAlpha == GL_INVALID_ENUM) { + res.srcRGB = res.srcAlpha = res.dstRGB = res.dstAlpha = GL_INVALID_ENUM; + } + } else { + if (res.srcRGB == GL_INVALID_ENUM || res.dstRGB == GL_INVALID_ENUM || res.srcAlpha == GL_INVALID_ENUM || res.dstAlpha == GL_INVALID_ENUM) { + res.simple = true; + res.srcRGB = res.srcAlpha = res.dstRGB = res.dstAlpha = GL_INVALID_ENUM; + } + } + return res; +} + +void glnvg__blendCompositeOperation() (GLNVGcontext* gl, in auto ref GLNVGblend op) nothrow @trusted @nogc { //glBlendFuncSeparate(glnvg_convertBlendFuncFactor(op.srcRGB), glnvg_convertBlendFuncFactor(op.dstRGB), glnvg_convertBlendFuncFactor(op.srcAlpha), glnvg_convertBlendFuncFactor(op.dstAlpha)); - GLenum srcRGB = glnvg_convertBlendFuncFactor(op.srcRGB); - GLenum dstRGB = glnvg_convertBlendFuncFactor(op.dstRGB); - GLenum srcAlpha = glnvg_convertBlendFuncFactor(op.srcAlpha); - GLenum dstAlpha = glnvg_convertBlendFuncFactor(op.dstAlpha); - if (srcRGB == GL_INVALID_ENUM || dstRGB == GL_INVALID_ENUM || srcAlpha == GL_INVALID_ENUM || dstAlpha == GL_INVALID_ENUM) { + static if (NANOVG_GL_USE_STATE_FILTER) { + if (gl.blendFunc.simple == op.simple) { + if (op.simple) { + if (gl.blendFunc.srcAlpha == op.srcAlpha && gl.blendFunc.dstAlpha == op.dstAlpha) return; + } else { + if (gl.blendFunc.srcRGB == op.srcRGB && gl.blendFunc.dstRGB == op.dstRGB && gl.blendFunc.srcAlpha == op.srcAlpha && gl.blendFunc.dstAlpha == op.dstAlpha) return; + } + } + gl.blendFunc = op; + } + if (op.simple) { + if (op.srcAlpha == GL_INVALID_ENUM || op.dstAlpha == GL_INVALID_ENUM) { + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(op.srcAlpha, op.dstAlpha); + } + } else { + if (op.srcRGB == GL_INVALID_ENUM || op.dstRGB == GL_INVALID_ENUM || op.srcAlpha == GL_INVALID_ENUM || op.dstAlpha == GL_INVALID_ENUM) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { - glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + glBlendFuncSeparate(op.srcRGB, op.dstRGB, op.srcAlpha, op.dstAlpha); } } +} void glnvg__renderSetAffine (void* uptr, in ref NVGMatrix mat) nothrow @trusted @nogc { GLNVGcontext* gl = cast(GLNVGcontext*)uptr; @@ -11829,14 +11880,18 @@ void glnvg__renderSetAffine (void* uptr, in ref NVGMatrix mat) nothrow @trusted call.affine.mat.ptr[0..6] = mat.mat.ptr[0..6]; } -void glnvg__renderFlush (void* uptr, NVGCompositeOperationState compositeOperation) nothrow @trusted @nogc { +void glnvg__renderFlush (void* uptr) nothrow @trusted @nogc { GLNVGcontext* gl = cast(GLNVGcontext*)uptr; if (gl.ncalls > 0) { // Setup require GL state. glUseProgram(gl.shader.prog); //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glnvg__blendCompositeOperation(compositeOperation); + static if (NANOVG_GL_USE_STATE_FILTER) { + gl.blendFunc.srcRGB = gl.blendFunc.dstRGB = gl.blendFunc.srcAlpha = gl.blendFunc.dstAlpha = GL_INVALID_ENUM; + //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } + //glnvg__blendCompositeOperation(gl, glnvg__buildBlendFunc(compositeOperation)); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glFrontFace(GL_CCW); @@ -11874,6 +11929,7 @@ void glnvg__renderFlush (void* uptr, NVGCompositeOperationState compositeOperati foreach (int i; 0..gl.ncalls) { GLNVGcall* call = &gl.calls[i]; + glnvg__blendCompositeOperation(gl, call.blendFunc); switch (call.type) { case GLNVG_FILL: glnvg__fill(gl, call); break; case GLNVG_CONVEXFILL: glnvg__convexFill(gl, call); break; @@ -11981,7 +12037,7 @@ void glnvg__vset (NVGvertex* vtx, float x, float y, float u, float v) nothrow @t vtx.v = v; } -void glnvg__renderFill (void* uptr, NVGPaint* paint, NVGscissor* scissor, float fringe, const(float)* bounds, const(NVGpath)* paths, int npaths, bool evenOdd) nothrow @trusted @nogc { +void glnvg__renderFill (void* uptr, NVGCompositeOperationState compositeOperation, NVGPaint* paint, NVGscissor* scissor, float fringe, const(float)* bounds, const(NVGpath)* paths, int npaths, bool evenOdd) nothrow @trusted @nogc { GLNVGcontext* gl = cast(GLNVGcontext*)uptr; GLNVGcall* call = glnvg__allocCall(gl); NVGvertex* quad; @@ -11992,6 +12048,7 @@ void glnvg__renderFill (void* uptr, NVGPaint* paint, NVGscissor* scissor, float call.type = GLNVG_FILL; call.evenOdd = evenOdd; + call.blendFunc = glnvg__buildBlendFunc(compositeOperation); call.triangleCount = 4; call.pathOffset = glnvg__allocPaths(gl, npaths); if (call.pathOffset == -1) goto error; @@ -12061,7 +12118,7 @@ error: if (gl.ncalls > 0) --gl.ncalls; } -void glnvg__renderStroke (void* uptr, NVGPaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const(NVGpath)* paths, int npaths) nothrow @trusted @nogc { +void glnvg__renderStroke (void* uptr, NVGCompositeOperationState compositeOperation, NVGPaint* paint, NVGscissor* scissor, float fringe, float strokeWidth, const(NVGpath)* paths, int npaths) nothrow @trusted @nogc { GLNVGcontext* gl = cast(GLNVGcontext*)uptr; GLNVGcall* call = glnvg__allocCall(gl); int maxverts, offset; @@ -12069,6 +12126,7 @@ void glnvg__renderStroke (void* uptr, NVGPaint* paint, NVGscissor* scissor, floa if (call is null || npaths < 1) return; call.type = GLNVG_STROKE; + call.blendFunc = glnvg__buildBlendFunc(compositeOperation); call.pathOffset = glnvg__allocPaths(gl, npaths); if (call.pathOffset == -1) goto error; call.pathCount = npaths; @@ -12113,7 +12171,7 @@ error: if (gl.ncalls > 0) --gl.ncalls; } -void glnvg__renderTriangles (void* uptr, NVGPaint* paint, NVGscissor* scissor, const(NVGvertex)* verts, int nverts) nothrow @trusted @nogc { +void glnvg__renderTriangles (void* uptr, NVGCompositeOperationState compositeOperation, NVGPaint* paint, NVGscissor* scissor, const(NVGvertex)* verts, int nverts) nothrow @trusted @nogc { GLNVGcontext* gl = cast(GLNVGcontext*)uptr; GLNVGcall* call = glnvg__allocCall(gl); GLNVGfragUniforms* frag; @@ -12121,6 +12179,7 @@ void glnvg__renderTriangles (void* uptr, NVGPaint* paint, NVGscissor* scissor, c if (call is null) return; call.type = GLNVG_TRIANGLES; + call.blendFunc = glnvg__buildBlendFunc(compositeOperation); call.image = paint.image.id; if (call.image > 0) glnvg__renderTextureIncRef(uptr, call.image);