From d224d14db19a370ea0c553509ae3261f022ae00b Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Wed, 11 May 2022 04:59:58 +0200 Subject: [PATCH] :wrench: Convert window texture alpha from premultiplied to straight --- src/Apparition.js | 9 +++++++-- src/BrokenGlass.js | 7 ++++++- src/EnergizeA.js | 7 ++++++- src/EnergizeB.js | 7 ++++++- src/Fire.js | 11 +++++++++-- src/Hexagon.js | 9 +++++++-- src/Matrix.js | 11 +++++++++-- src/SnapOfDisintegration.js | 23 ++++++++++++++--------- src/TRexAttack.js | 7 ++++++- src/TVEffect.js | 8 +++++++- src/Wisps.js | 7 ++++++- 11 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/Apparition.js b/src/Apparition.js index c13e08d..e7c31c4 100644 --- a/src/Apparition.js +++ b/src/Apparition.js @@ -176,7 +176,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -218,8 +218,13 @@ if (utils.isInShellProcess()) { float c = cos(angle); coords = vec2(dot(coords, vec2(c, -s)), dot(coords, vec2(s, c))); - // Fade out the window texture. + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. cogl_color_out = texture2D(uTexture, coords + center); + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + + // Fade out the window texture. cogl_color_out.a *= 1.0 - progress; `; diff --git a/src/BrokenGlass.js b/src/BrokenGlass.js index ba54dc6..fc22b7d 100644 --- a/src/BrokenGlass.js +++ b/src/BrokenGlass.js @@ -213,7 +213,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -277,6 +277,11 @@ if (utils.isInShellProcess()) { cogl_color_out = texture2D(uTexture, coords); } } + + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } `; this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, declarations, code, true); diff --git a/src/EnergizeA.js b/src/EnergizeA.js index aaafda9..0bd94b9 100644 --- a/src/EnergizeA.js +++ b/src/EnergizeA.js @@ -163,7 +163,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -220,6 +220,11 @@ if (utils.isInShellProcess()) { vec2 masks = getMasks(); vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (windowColor.a > 0) { + windowColor.rgb /= windowColor.a; + } + // Dissolve window to effect color / transparency. cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.2 * masks.y + 0.8); cogl_color_out.a = windowColor.a * masks.y; diff --git a/src/EnergizeB.js b/src/EnergizeB.js index adb20cd..331f00d 100644 --- a/src/EnergizeB.js +++ b/src/EnergizeB.js @@ -163,7 +163,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -237,6 +237,11 @@ if (utils.isInShellProcess()) { vec4 masks = getMasks(); vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (windowColor.a > 0) { + windowColor.rgb /= windowColor.a; + } + // Dissolve window to effect color / transparency. cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.5 * masks.w + 0.5); cogl_color_out.a = windowColor.a * masks.w; diff --git a/src/Fire.js b/src/Fire.js index 9e4dda3..8f8173f 100644 --- a/src/Fire.js +++ b/src/Fire.js @@ -290,7 +290,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { @@ -395,8 +395,15 @@ if (utils.isInShellProcess()) { // Map noise value to color. vec4 fire = getFireColor(noise); - // Get the window texture and fade it according to the effect mask. + // Get the window texture. cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); + + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + + // Fade the window according to the effect mask. cogl_color_out.a *= effectMask.x; // Add the fire to the window. diff --git a/src/Hexagon.js b/src/Hexagon.js index d44868e..34bd360 100644 --- a/src/Hexagon.js +++ b/src/Hexagon.js @@ -122,7 +122,7 @@ var Hexagon = class Hexagon { // This is called from extension.js if the extension is disabled. This should free all // static resources. static cleanUp() { - shaderInstance = null; + freeShaders = []; } } @@ -182,7 +182,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { @@ -273,6 +273,11 @@ if (utils.isInShellProcess()) { vec2 lookupOffset = tileProgress * hex.xy / texScale / (1.0 - tileProgress); cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st + lookupOffset); + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + vec4 glow = uGlowColor; vec4 line = uLineColor; diff --git a/src/Matrix.js b/src/Matrix.js index 31977ef..5aab908 100644 --- a/src/Matrix.js +++ b/src/Matrix.js @@ -194,7 +194,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. The technique for this effect was inspired by // https://www.shadertoy.com/view/ldccW4, however the implementation is quite // different as the letters drop only once and there is no need for a noise texture. @@ -274,8 +274,15 @@ if (utils.isInShellProcess()) { vec2 rainMask = getRain(coords); float textMask = getText(coords); - // Get the window texture and fade it according to the effect mask. + // Get the window texture. cogl_color_out = texture2D(uTexture, coords); + + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + + // Fade the window according to the effect mask. cogl_color_out.a *= rainMask.y; // This is used to fade out the remaining trails in the end. diff --git a/src/SnapOfDisintegration.js b/src/SnapOfDisintegration.js index 49abd06..45435ec 100644 --- a/src/SnapOfDisintegration.js +++ b/src/SnapOfDisintegration.js @@ -189,7 +189,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -265,17 +265,22 @@ if (utils.isInShellProcess()) { if (dustGroup == i) { - // Fade the window color to uDustColor. + // Get the window color. vec4 windowColor = texture2D(uTexture, coords + 0.5); + + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (windowColor.a > 0) { + windowColor.rgb /= windowColor.a; + } + + // Fade the window color to uDustColor. vec3 dustColor = mix(windowColor.rgb, uDustColor.rgb, uDustColor.a); - windowColor.rgb = mix(windowColor.rgb, dustColor*windowColor.a, progress); + windowColor.rgb = mix(windowColor.rgb, dustColor, progress); - // Dissolve the dust particles. - float dissolve = (dustMap.x - progress) > 0 ? 1 : 0; - windowColor *= dissolve; - - // Blend the layers. - cogl_color_out = mix(cogl_color_out, windowColor, windowColor.a); + // Dissolve and blend the layers. + if (dustMap.x - progress > 0) { + cogl_color_out = windowColor; + } } } `; diff --git a/src/TRexAttack.js b/src/TRexAttack.js index d453a75..b43ddcc 100644 --- a/src/TRexAttack.js +++ b/src/TRexAttack.js @@ -189,7 +189,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -273,6 +273,11 @@ if (utils.isInShellProcess()) { vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * progress * 0.5; cogl_color_out = texture2D(uTexture, coords + offset); + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + // Add colorful flashes. float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - progress) + 1; if (flashIntensity < 0 || flashIntensity >= 1) { diff --git a/src/TVEffect.js b/src/TVEffect.js index c544d37..f6463ef 100644 --- a/src/TVEffect.js +++ b/src/TVEffect.js @@ -162,7 +162,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -207,6 +207,12 @@ if (utils.isInShellProcess()) { float mask = tbMask * lrMask * ffMask; cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); + + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + cogl_color_out.rgb = mix(cogl_color_out.rgb, uColor * cogl_color_out.a, smoothstep(0, 1, progress)); cogl_color_out.a *= mask; diff --git a/src/Wisps.js b/src/Wisps.js index bca8018..42b14fa 100644 --- a/src/Wisps.js +++ b/src/Wisps.js @@ -169,7 +169,7 @@ if (utils.isInShellProcess()) { freeShaders.push(this); } - // This is called by the constructor. This is means it's only called when the effect + // This is called by the constructor. This means, it's only called when the effect // is used for the first time. vfunc_build_pipeline() { const declarations = ` @@ -236,6 +236,11 @@ if (utils.isInShellProcess()) { // Get the color of the window. cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st); + // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. + if (cogl_color_out.a > 0) { + cogl_color_out.rgb /= cogl_color_out.a; + } + // Compute several layers of moving wisps. vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, progress) + 0.5; uv /= uScale;