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 @@
+
+
+
+
+
+
+
+
+
+
\ 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
+
+
vertical60
@@ -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