diff --git a/README.md b/README.md index 44753ee..6c542a7 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ For a list of things changed in previous releases, you can have a look at the [c Effect | Preview -----|-------- +**Energize A**
Beam your windows away! | +**Energize B**
Using different transporter technology results in an alternative visual effect. | **Fire**
The classic effect inspired by Compiz. However, this is implemented using a GLSL shader and not with a particle system like in the old days. | **Matrix**
Turn your windows into a shower of green letters! The color is actually configurable.

_Only available in GNOME Shell 40+_ | **T-Rex Attack**
Destroy your windows with a series of violent slashes!

_Only available in GNOME Shell 40+_ | diff --git a/docs/changelog.md b/docs/changelog.md index 9ba7b60..76a30b8 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,6 +7,8 @@ #### New Features * **Random effects!** You can now select a set of effects of which one will be chosen randomly whenever you close a window. **This changes how effects are selected, so you will have to re-select your desired effect(s)**. +* **New Effect: Energize A.** Beam your windows away! +* **New Effect: Energize B.** Using different transporter technology results in an alternative visual effect. * **New Effect: Wisps.** These little fairies carry your windows to the realm of dreams! * Each effect has its own "Animation Time" setting now. The global animation time has been replaced by those, so **you may have to adjust the sliders to match your previous settings**. diff --git a/docs/pics/energizeA.gif b/docs/pics/energizeA.gif new file mode 100644 index 0000000..08db34b Binary files /dev/null and b/docs/pics/energizeA.gif differ diff --git a/docs/pics/energizeB.gif b/docs/pics/energizeB.gif new file mode 100644 index 0000000..f3eaba1 Binary files /dev/null and b/docs/pics/energizeB.gif differ diff --git a/extension.js b/extension.js index 51a4292..a7a0b44 100644 --- a/extension.js +++ b/extension.js @@ -25,6 +25,8 @@ const utils = Me.imports.src.utils; // New effects must be registered here and in prefs.js. const ALL_EFFECTS = [ + Me.imports.src.EnergizeA.EnergizeA, + Me.imports.src.EnergizeB.EnergizeB, Me.imports.src.Fire.Fire, Me.imports.src.Matrix.Matrix, Me.imports.src.TRexAttack.TRexAttack, diff --git a/prefs.js b/prefs.js index 1c10224..4a67280 100644 --- a/prefs.js +++ b/prefs.js @@ -21,6 +21,8 @@ const utils = Me.imports.src.utils; // New effects must be registered here and in extension.js. const ALL_EFFECTS = [ + Me.imports.src.EnergizeA.EnergizeA, + Me.imports.src.EnergizeB.EnergizeB, Me.imports.src.Fire.Fire, Me.imports.src.Matrix.Matrix, Me.imports.src.TRexAttack.TRexAttack, diff --git a/resources/ui/gtk3/energizeAPage.ui b/resources/ui/gtk3/energizeAPage.ui new file mode 100644 index 0000000..b292863 --- /dev/null +++ b/resources/ui/gtk3/energizeAPage.ui @@ -0,0 +1,183 @@ + + + + + 10000 + 500 + 10 + 100 + + + + 10 + 0.1 + 0.01 + 0.1 + + + + vertical + 60 + 60 + 60 + 60 + + + + + + none + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + energize-a-animation-time + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Scale + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + energize-a-scale + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + + + Color + 0 + start + center + 1 + + + + + 0 + 1 + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/ui/gtk3/energizeBPage.ui b/resources/ui/gtk3/energizeBPage.ui new file mode 100644 index 0000000..080d2b6 --- /dev/null +++ b/resources/ui/gtk3/energizeBPage.ui @@ -0,0 +1,183 @@ + + + + + 10000 + 500 + 10 + 100 + + + + 10 + 0.1 + 0.01 + 0.1 + + + + vertical + 60 + 60 + 60 + 60 + + + + + + none + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + energize-b-animation-time + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Scale + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + energize-b-scale + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + 10 + 10 + 10 + 10 + 0 + + + + + Color + 0 + start + center + 1 + + + + + 0 + 1 + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/ui/gtk3/wispsPage.ui b/resources/ui/gtk3/wispsPage.ui index a680f97..c14f1ff 100644 --- a/resources/ui/gtk3/wispsPage.ui +++ b/resources/ui/gtk3/wispsPage.ui @@ -8,6 +8,13 @@ 100 + + 10 + 0.1 + 0.01 + 0.1 + + vertical 60 @@ -73,6 +80,55 @@ + + + 10 + 10 + 10 + 10 + 0 + + + 8 + + + Scale + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + wisps-scale + + + + + + + edit-clear-symbolic + 1 + + + Reset to Default Value + + + + + + + + 10 diff --git a/resources/ui/gtk4/energizeAPage.ui b/resources/ui/gtk4/energizeAPage.ui new file mode 100644 index 0000000..92911d9 --- /dev/null +++ b/resources/ui/gtk4/energizeAPage.ui @@ -0,0 +1,155 @@ + + + + + vertical + 60 + 60 + 60 + 60 + + + + + + none + 1 + + + + + 0 + + + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + + + 10000 + 500 + 10 + 100 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Scale + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + + + 10 + 0.1 + 0.01 + 0.1 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Color + 0 + start + center + 1 + + + + + 0 + 1 + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/ui/gtk4/energizeBPage.ui b/resources/ui/gtk4/energizeBPage.ui new file mode 100644 index 0000000..77f1e4d --- /dev/null +++ b/resources/ui/gtk4/energizeBPage.ui @@ -0,0 +1,155 @@ + + + + + vertical + 60 + 60 + 60 + 60 + + + + + + none + 1 + + + + + 0 + + + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + + + 10000 + 500 + 10 + 100 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Scale + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + + + 10 + 0.1 + 0.01 + 0.1 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + 0 + + + + + Color + 0 + start + center + 1 + + + + + 0 + 1 + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/ui/gtk4/wispsPage.ui b/resources/ui/gtk4/wispsPage.ui index 3aee991..fc89c31 100644 --- a/resources/ui/gtk4/wispsPage.ui +++ b/resources/ui/gtk4/wispsPage.ui @@ -64,6 +64,52 @@ + + + 0 + + + + + Scale + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + + + 10 + 0.1 + 0.01 + 0.1 + + + + + + + edit-clear-symbolic + Reset to Default Value + + + + + + + + 0 diff --git a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml index 9f010ae..a7df45e 100644 --- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml +++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml @@ -179,6 +179,62 @@ Number of claw scratches drawn on top of each other. + + + + + + false + Energize A Close Effect + Use the Energize A effect for window closing. + + + + 2000 + Energize A Animation Time + The time the Energize A effect takes. + + + + 1.0 + Energize A Scale + The size of the effect. + + + + "rgb(255, 200, 50)" + Energize A Color + The color of the effect. + + + + + + + + false + Energize B Close Effect + Use the Energize B effect for window closing. + + + + 2000 + Energize B Animation Time + The time the Energize B effect takes. + + + + 1.0 + Energize B Scale + The size of the effect. + + + + "rgb(160, 180, 255)" + Energize B Color + The color of the effect. + + @@ -195,6 +251,12 @@ The time the wisps effect takes. + + 1.0 + Wisps Scale + The size of the wisps. + + "rgb(255, 100, 200)" Wisps Effect Color diff --git a/src/EnergizeA.js b/src/EnergizeA.js new file mode 100644 index 0000000..3dab7bd --- /dev/null +++ b/src/EnergizeA.js @@ -0,0 +1,202 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // +// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // +// |__/ // +// Copyright (c) 2021 Simon Schneegans // +// Released under the GPLv3 or later. See LICENSE file for details. // +////////////////////////////////////////////////////////////////////////////////////////// + +'use strict'; + +const GObject = imports.gi.GObject; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const utils = Me.imports.src.utils; + +////////////////////////////////////////////////////////////////////////////////////////// +// This effect looks a bit like the transporter effect from TOS. // +////////////////////////////////////////////////////////////////////////////////////////// + +// The shader class for this effect is registered further down in this file. +let Shader = null; + +// The effect class is completely static. It can be used to get some metadata (like the +// effect's name or supported GNOME Shell versions), to initialize the respective page of +// the settings dialog, as well as to create the actual shader for the effect. +var EnergizeA = class EnergizeA { + + // ---------------------------------------------------------------------------- metadata + + // The effect is available on all GNOME Shell versions supported by this extension. + static getMinShellVersion() { + return [3, 36]; + } + + // This will be called in various places where a unique identifier for this effect is + // required. It should match the prefix of the settings keys which store whether the + // effect is enabled currently (e.g. the '*-close-effect'). + static getNick() { + return 'energize-a'; + } + + // This will be shown in the sidebar of the preferences dialog as well as in the + // drop-down menus where the user can choose the effect. + static getLabel() { + return 'Energize A'; + } + + // -------------------------------------------------------------------- API for prefs.js + + // This is called by the preferences dialog. It loads the settings page for this effect, + // binds all properties to the settings and appends the page to the main stack of the + // preferences dialog. + static initPreferences(dialog) { + + // Add the settings page to the builder. + dialog.getBuilder().add_from_resource(`/ui/${utils.getGTKString()}/energizeAPage.ui`); + + // Bind all properties. + dialog.bindAdjustment('energize-a-animation-time'); + dialog.bindAdjustment('energize-a-scale'); + dialog.bindColorButton('energize-a-color'); + + // Finally, append the settings page to the main stack. + const stack = dialog.getBuilder().get_object('main-stack'); + stack.add_titled( + dialog.getBuilder().get_object('energize-a-prefs'), EnergizeA.getNick(), + EnergizeA.getLabel()); + } + + // ---------------------------------------------------------------- API for extension.js + + // This is called from extension.js whenever a window is closed with this effect. + static createShader(settings) { + return new Shader(settings); + } + + // This is also called from extension.js. It is used to tweak the ongoing transitions of + // the actor - usually windows are faded to transparency and scaled down slightly by + // GNOME Shell. Here, we modify this behavior as well as the transition duration. + static tweakTransitions(actor, settings) { + const animationTime = settings.get_int('energize-a-animation-time'); + + const tweakTransition = (property, value) => { + const transition = actor.get_transition(property); + if (transition) { + transition.set_to(value); + transition.set_duration(animationTime); + } + }; + + // We re-target these transitions so that the window is neither scaled nor faded. + tweakTransition('opacity', 255); + tweakTransition('scale-x', 1); + tweakTransition('scale-y', 1); + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// The shader class for this effect will only be registered in GNOME Shell's process // +// (not in the preferences process). It's done this way as Clutter may not be installed // +// on the system and therefore the preferences would crash. // +////////////////////////////////////////////////////////////////////////////////////////// + +if (utils.isInShellProcess()) { + + const Clutter = imports.gi.Clutter; + const shaderSnippets = Me.imports.src.shaderSnippets; + + Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { + _init(settings) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + const color = Clutter.Color.from_string(settings.get_string('energize-a-color'))[1]; + + this.set_shader_source(` + + // Inject some common shader snippets. + ${shaderSnippets.standardUniforms()} + ${shaderSnippets.noise()} + ${shaderSnippets.edgeMask()} + + const vec2 SEED = vec2(${Math.random()}, ${Math.random()}); + const float FADE_IN_TIME = 0.3; + const float FADE_OUT_TIME = 0.6; + const float HEART_FADE_TIME = 0.3; + const float EDGE_FADE_WIDTH = 50; + + // This method returns two values: + // result.x: A mask for the particles. + // result.y: The opacity of the fading window. + vec2 getMasks() { + float fadeInProgress = clamp(uProgress/FADE_IN_TIME, 0, 1); + float fadeOutProgress = clamp((uProgress-FADE_IN_TIME)/FADE_OUT_TIME, 0, 1); + float heartProgress = clamp((uProgress-(1.0-HEART_FADE_TIME))/HEART_FADE_TIME, 0, 1); + + // Compute mask for the "atom" particles. + float dist = length(cogl_tex_coord_in[0].st - 0.5) * 4.0; + float atomMask = smoothstep(0.0, 1.0, (fadeInProgress * 2.0 - dist + 1.0)); + atomMask *= fadeInProgress; + atomMask *= smoothstep(1.0, 0.0, fadeOutProgress); + + // Fade-out the masks at the window edges. + float edgeFade = getAbsoluteEdgeMask(EDGE_FADE_WIDTH); + atomMask *= edgeFade; + + float heartMask = getRelativeEdgeMask(0.5); + heartMask = 3.0 * pow(heartMask, 5); + heartMask *= fadeOutProgress; + heartMask *= 1.0 - heartProgress; + atomMask = clamp(heartMask+atomMask, 0, 1); + + // Compute fading window opacity. + float windowMask = pow(1.0 - fadeOutProgress, 2.0); + + return vec2(atomMask, windowMask); + } + + void main() { + + vec2 masks = getMasks(); + vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + vec3 effectColor = vec3(${color.red / 255}, + ${color.green / 255}, + ${color.blue / 255}); + + // Dissolve window to effect color / transparency. + cogl_color_out = mix(vec4(effectColor, 1.0) * windowColor.a, windowColor, 0.2 * masks.y + 0.8) * masks.y; + + vec2 scaledUV = (cogl_tex_coord_in[0].st-0.5) * (1.0 + 0.1*uProgress); + scaledUV /= ${settings.get_double('energize-a-scale')}; + + // Add molecule particles. + vec2 uv = scaledUV + vec2(0, 0.1*uTime); + uv *= 0.010598 * vec2(0.5*uSizeX, uSizeY); + float particles = 0.2 * pow((simplex3D(vec3(uv, 0.0*uTime))), 3.0); + + // Add more molecule particles. + for (int i=1; i<=3;++i) { + vec2 uv = scaledUV * 0.12154 / pow(1.5, i) * vec2(uSizeX, uSizeY); + float atoms = simplex3D(vec3(uv, 2.0*uTime/i)); + particles += 0.5 * pow(0.2 * (1.0 / (1.0 - atoms)-1.0), 2); + } + + cogl_color_out.rgb += effectColor * particles * masks.x; + + // These are pretty useful for understanding how this works. + // cogl_color_out = vec4(masks, 0.0, 1.0); + // cogl_color_out = vec4(vec3(masks.x), 1.0); + // cogl_color_out = vec4(vec3(masks.y), 1.0); + // cogl_color_out = vec4(vec3(particles), 1.0); + } + `); + }; + }); +} \ No newline at end of file diff --git a/src/EnergizeB.js b/src/EnergizeB.js new file mode 100644 index 0000000..a9848d6 --- /dev/null +++ b/src/EnergizeB.js @@ -0,0 +1,225 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< // +// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ // +// |__/ // +// Copyright (c) 2021 Simon Schneegans // +// Released under the GPLv3 or later. See LICENSE file for details. // +////////////////////////////////////////////////////////////////////////////////////////// + +'use strict'; + +const GObject = imports.gi.GObject; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = imports.misc.extensionUtils.getCurrentExtension(); +const utils = Me.imports.src.utils; + +////////////////////////////////////////////////////////////////////////////////////////// +// This effect looks a bit like the transporter effect from TNG. // +////////////////////////////////////////////////////////////////////////////////////////// + +// The shader class for this effect is registered further down in this file. +let Shader = null; + +// The effect class is completely static. It can be used to get some metadata (like the +// effect's name or supported GNOME Shell versions), to initialize the respective page of +// the settings dialog, as well as to create the actual shader for the effect. +var EnergizeB = class EnergizeB { + + // ---------------------------------------------------------------------------- metadata + + // The effect is available on all GNOME Shell versions supported by this extension. + static getMinShellVersion() { + return [3, 36]; + } + + // This will be called in various places where a unique identifier for this effect is + // required. It should match the prefix of the settings keys which store whether the + // effect is enabled currently (e.g. the '*-close-effect'). + static getNick() { + return 'energize-b'; + } + + // This will be shown in the sidebar of the preferences dialog as well as in the + // drop-down menus where the user can choose the effect. + static getLabel() { + return 'Energize B'; + } + + // -------------------------------------------------------------------- API for prefs.js + + // This is called by the preferences dialog. It loads the settings page for this effect, + // binds all properties to the settings and appends the page to the main stack of the + // preferences dialog. + static initPreferences(dialog) { + + // Add the settings page to the builder. + dialog.getBuilder().add_from_resource(`/ui/${utils.getGTKString()}/energizeBPage.ui`); + + // Bind all properties. + dialog.bindAdjustment('energize-b-animation-time'); + dialog.bindAdjustment('energize-b-scale'); + dialog.bindColorButton('energize-b-color'); + + // Finally, append the settings page to the main stack. + const stack = dialog.getBuilder().get_object('main-stack'); + stack.add_titled( + dialog.getBuilder().get_object('energize-b-prefs'), EnergizeB.getNick(), + EnergizeB.getLabel()); + } + + // ---------------------------------------------------------------- API for extension.js + + // This is called from extension.js whenever a window is closed with this effect. + static createShader(settings) { + return new Shader(settings); + } + + // This is also called from extension.js. It is used to tweak the ongoing transitions of + // the actor - usually windows are faded to transparency and scaled down slightly by + // GNOME Shell. Here, we modify this behavior as well as the transition duration. + static tweakTransitions(actor, settings) { + const animationTime = settings.get_int('energize-b-animation-time'); + + const tweakTransition = (property, value) => { + const transition = actor.get_transition(property); + if (transition) { + transition.set_to(value); + transition.set_duration(animationTime); + } + }; + + // We re-target these transitions so that the window is neither scaled nor faded. + tweakTransition('opacity', 255); + tweakTransition('scale-x', 1); + tweakTransition('scale-y', 1); + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// The shader class for this effect will only be registered in GNOME Shell's process // +// (not in the preferences process). It's done this way as Clutter may not be installed // +// on the system and therefore the preferences would crash. // +////////////////////////////////////////////////////////////////////////////////////////// + +if (utils.isInShellProcess()) { + + const Clutter = imports.gi.Clutter; + const shaderSnippets = Me.imports.src.shaderSnippets; + + Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { + _init(settings) { + super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); + + const color = Clutter.Color.from_string(settings.get_string('energize-b-color'))[1]; + + this.set_shader_source(` + + // Inject some common shader snippets. + ${shaderSnippets.standardUniforms()} + ${shaderSnippets.noise()} + ${shaderSnippets.edgeMask()} + + const vec2 SEED = vec2(${Math.random()}, ${Math.random()}); + const float SHOWER_TIME = 0.2; + const float SHOWER_WIDTH = 0.3; + const float STREAK_TIME = 0.6; + const float EDGE_FADE = 50; + const float SCALE = ${settings.get_double('energize-b-scale')}; + + // This method returns four values: + // result.x: A mask for the particles which lead the shower. + // result.y: A mask for the streaks which follow the shower particles. + // result.z: A mask for the final "atom" particles. + // result.w: The opacity of the fading window. + vec4 getMasks() { + float showerProgress = uProgress/SHOWER_TIME; + float streakProgress = clamp((uProgress-SHOWER_TIME)/STREAK_TIME, 0, 1); + float fadeProgress = clamp((uProgress-SHOWER_TIME)/(1.0 - SHOWER_TIME), 0, 1); + + // Gradient from top to bottom. + float t = cogl_tex_coord_in[0].t; + + // A smooth gradient which moves to the bottom within the showerProgress. + float showerMask = smoothstep(1, 0, abs(showerProgress - t - SHOWER_WIDTH) / SHOWER_WIDTH); + + // This is 1 above the streak mask. + float streakMask = (showerProgress - t - SHOWER_WIDTH) > 0 ? 1 : 0; + + // Compute mask for the "atom" particles. + float atomMask = getRelativeEdgeMask(0.2); + atomMask = max(0, atomMask - showerMask); + atomMask *= streakMask; + atomMask *= (1.0 - fadeProgress); + + // Make some particles visible in the streaks. + showerMask += 0.05 * streakMask; + + // Add shower mask to streak mask. + streakMask = max(streakMask, showerMask); + + // Fade-out the masks at the window edges. + float edgeFade = getAbsoluteEdgeMask(EDGE_FADE); + streakMask *= edgeFade; + showerMask *= edgeFade; + + // Fade-out the masks from top to bottom. + float fade = smoothstep(0.0, 1.0, 1.0 + t - 2.0 * streakProgress); + streakMask *= fade; + showerMask *= fade; + + // Compute fading window opacity. + float windowMask = pow(1.0 - fadeProgress, 2.0); + + return vec4(showerMask, streakMask, atomMask, windowMask); + } + + void main() { + + vec4 masks = getMasks(); + vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + vec3 effectColor = vec3(${color.red / 255}, + ${color.green / 255}, + ${color.blue / 255}); + + // Dissolve window to effect color / transparency. + cogl_color_out = mix(vec4(effectColor, 1.0) * windowColor.a, windowColor, 0.5 * masks.w + 0.5) * masks.w; + + // Add leading shower particles. + vec2 showerUV = cogl_tex_coord_in[0].st + vec2(0, -0.7*uProgress/SHOWER_TIME); + showerUV *= 0.02 * vec2(uSizeX, uSizeY) / SCALE; + float shower = pow(simplex2D(showerUV), 10.0); + cogl_color_out.rgb += effectColor * shower * masks.x; + + // Add trailing streak lines. + vec2 streakUV = cogl_tex_coord_in[0].st + vec2(0, -uProgress/SHOWER_TIME); + streakUV *= vec2(0.05 * uSizeX, 0.001 * uSizeY) / SCALE; + float streaks = simplex2DFractal(streakUV) * 0.5; + cogl_color_out.rgb += effectColor * streaks * masks.y; + + // Add glimmering atoms. + vec2 atomUV = cogl_tex_coord_in[0].st + vec2(0, -0.025*uProgress/SHOWER_TIME); + atomUV *= 0.2 * vec2(uSizeX, uSizeY) / SCALE; + float atoms = pow((simplex3D(vec3(atomUV, uTime))), 5.0); + cogl_color_out.rgb += effectColor * atoms * masks.z; + + // These are pretty useful for understanding how this works. + // cogl_color_out = vec4(masks.rgb, 1.0); + // cogl_color_out = vec4(vec3(masks.x), 1.0); + // cogl_color_out = vec4(vec3(masks.y), 1.0); + // cogl_color_out = vec4(vec3(masks.z), 1.0); + // cogl_color_out = vec4(vec3(masks.w), 1.0); + // cogl_color_out = vec4(vec3(shower), 1.0); + // cogl_color_out = vec4(vec3(streaks), 1.0); + // cogl_color_out = vec4(vec3(atoms), 1.0); + } + `); + }; + }); +} \ No newline at end of file diff --git a/src/Wisps.js b/src/Wisps.js index 411a793..a04e2c8 100644 --- a/src/Wisps.js +++ b/src/Wisps.js @@ -64,6 +64,7 @@ var Wisps = class Wisps { // Bind all properties. dialog.bindAdjustment('wisps-animation-time'); + dialog.bindAdjustment('wisps-scale'); dialog.bindColorButton('wisps-color'); // Finally, append the settings page to the main stack. @@ -182,6 +183,7 @@ if (utils.isInShellProcess()) { // Compute several layers of moving wisps. vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, uProgress) + 0.5; + uv /= ${settings.get_double('wisps-scale')}; float wisps = 0; for (int i=0; i