diff --git a/extension.js b/extension.js
index 327c67e..8fbe62d 100644
--- a/extension.js
+++ b/extension.js
@@ -61,6 +61,7 @@ class Extension {
new Me.imports.src.Matrix.Matrix(),
new Me.imports.src.Pixelate.Pixelate(),
new Me.imports.src.PixelWheel.PixelWheel(),
+ new Me.imports.src.PixelWipe.PixelWipe(),
new Me.imports.src.SnapOfDisintegration.SnapOfDisintegration(),
new Me.imports.src.TRexAttack.TRexAttack(),
new Me.imports.src.TVEffect.TVEffect(),
diff --git a/prefs.js b/prefs.js
index 7fb21d1..7e0b499 100644
--- a/prefs.js
+++ b/prefs.js
@@ -57,6 +57,7 @@ var PreferencesDialog = class PreferencesDialog {
new Me.imports.src.Matrix.Matrix(),
new Me.imports.src.Pixelate.Pixelate(),
new Me.imports.src.PixelWheel.PixelWheel(),
+ new Me.imports.src.PixelWipe.PixelWipe(),
new Me.imports.src.SnapOfDisintegration.SnapOfDisintegration(),
new Me.imports.src.TRexAttack.TRexAttack(),
new Me.imports.src.TVEffect.TVEffect(),
diff --git a/resources/shaders/pixel-wheel.frag b/resources/shaders/pixel-wheel.frag
index b48ac03..3cbeb5a 100644
--- a/resources/shaders/pixel-wheel.frag
+++ b/resources/shaders/pixel-wheel.frag
@@ -37,7 +37,8 @@ void main() {
}
// Progressively hide the spokes.
- if (mod(angle * uSpokeCount, 1.0) < progress) {
+ float threshold = mod(angle * uSpokeCount, 1.0);
+ if (progress > threshold) {
oColor.a = 0.0;
}
diff --git a/resources/shaders/pixel-wipe.frag b/resources/shaders/pixel-wipe.frag
new file mode 100644
index 0000000..1f2a8f5
--- /dev/null
+++ b/resources/shaders/pixel-wipe.frag
@@ -0,0 +1,51 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
+// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
+// |__/ //
+// Copyright (c) 2021 Simon Schneegans //
+// Released under the GPLv3 or later. See LICENSE file for details. //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// The content from common.glsl is automatically prepended to each shader effect.
+
+uniform float uPixelSize;
+uniform vec2 uStartPos;
+
+const float FADE_WIDTH = 1.0; // Width of the transition.
+
+void main() {
+
+ // Now we compute a 2D gradient in [0..1] which covers the entire window. The dark
+ // regions will be burned first, the bright regions in the end. We mix a radial gradient
+ // with some noise. The center of the radial gradient is positioned at uStartPos.
+ float circle = length(iTexCoord - uStartPos);
+
+ float progress = easeOutQuad(uProgress);
+ progress = ((1.0 - progress) * (1.0 + FADE_WIDTH) - 1.0 + circle) / FADE_WIDTH;
+ progress = smoothstep(0.0, 1.0, progress);
+
+ progress = uForOpening ? progress : 1.0 - progress;
+
+ // The current level of pixelation increases with the progress.
+ float pixelSize = ceil(uPixelSize * progress + 1.0);
+ vec2 pixelGrid = vec2(pixelSize) / uSize;
+ vec2 texcoord = iTexCoord.st - mod(iTexCoord.st, pixelGrid) + pixelGrid * 0.5;
+ vec4 oColor = getInputColor(texcoord);
+
+ // Hide pixels in the transition zone.
+ float random = simplex2DFractal(texcoord * uSize / 20.0) * 1.5 - 0.25;
+ if (progress > random) {
+ oColor.a *= max(0.0, 1.0 - (progress - random) * 10.0);
+ }
+
+ // These are pretty useful for understanding how this works.
+ // oColor = vec4(progress, 0.0, 0.0, 1.0);
+ // oColor = vec4(random, 0.0, 0.0, 1.0);
+
+ setOutputColor(oColor);
+}
\ No newline at end of file
diff --git a/resources/shaders/pixelate.frag b/resources/shaders/pixelate.frag
index 12e4557..5ef05ac 100644
--- a/resources/shaders/pixelate.frag
+++ b/resources/shaders/pixelate.frag
@@ -27,9 +27,9 @@ void main() {
vec4 oColor = getInputColor(texcoord);
// Hide selected pixels based on some random noise.
- float random = simplex2DFractal(texcoord * uNoise * uSize / 1000.0);
- if (random * 1.5 - 0.25 < progress) {
- oColor.a = 0.0;
+ float random = simplex2DFractal(texcoord * uNoise * uSize / 1000.0) * 1.5 - 0.25;
+ if (progress > random) {
+ oColor.a *= max(0.0, 1.0 - (progress - random) * 20.0);
}
setOutputColor(oColor);
diff --git a/resources/ui/gtk3/PixelWipe.ui b/resources/ui/gtk3/PixelWipe.ui
new file mode 100644
index 0000000..f3830f2
--- /dev/null
+++ b/resources/ui/gtk3/PixelWipe.ui
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/ui/gtk4/PixelWipe.ui b/resources/ui/gtk4/PixelWipe.ui
new file mode 100644
index 0000000..c7fca0b
--- /dev/null
+++ b/resources/ui/gtk4/PixelWipe.ui
@@ -0,0 +1,117 @@
+
+
+
+
+ vertical
+
+
+
+
+
+ none
+ 1
+
+
+
+
+ 0
+
+
+
+
+ Animation Time [ms]
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 5000
+ 100
+ 1
+ 100
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ Pixel Size
+ 0
+ start
+ center
+ 1
+
+
+
+
+ end
+ center
+ 1
+ 0
+ left
+ 300
+
+
+ 50
+ 1
+ 1
+ 10
+
+
+
+
+
+
+ edit-clear-symbolic
+ Reset to Default Value
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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 b862806..8426023 100644
--- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml
@@ -112,13 +112,41 @@
The noise of the effect.
-
+ 10Pixelate Pixel SizeThe size of the maximum pixelation.
+
+
+
+
+
+ false
+ Pixel Wipe Close Effect
+ Use the Pixel Wipe effect for window closing.
+
+
+
+ false
+ Pixel Wipe Open Effect
+ Use the Pixel Wipe effect for window opening.
+
+
+
+ 1000
+ Pixel Wipe Animation Time
+ The time the Pixel Wipe effect takes.
+
+
+
+ 10
+ Pixel Wipe Pixel Size
+ The size of the maximum pixelation.
+
+
diff --git a/src/PixelWipe.js b/src/PixelWipe.js
new file mode 100644
index 0000000..ec7a110
--- /dev/null
+++ b/src/PixelWipe.js
@@ -0,0 +1,127 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+// ) ( //
+// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
+// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
+// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
+// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
+// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 _ = imports.gettext.domain('burn-my-windows').gettext;
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = imports.misc.extensionUtils.getCurrentExtension();
+const utils = Me.imports.src.utils;
+const ShaderFactory = Me.imports.src.ShaderFactory.ShaderFactory;
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// This very simple effect pixelates the window texture and hides from left to right //
+// (or any other direction). //
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// The effect class 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 PixelWipe = class {
+
+ // The constructor creates a ShaderFactory which will be used by extension.js to create
+ // shader instances for this effect. The shaders will be automagically created using the
+ // GLSL file in resources/shaders/.glsl. The callback will be called for each
+ // newly created shader instance.
+ constructor() {
+ this.shaderFactory = new ShaderFactory(this.getNick(), (shader) => {
+ // Store uniform locations of newly created shaders.
+ shader._uPixelSize = shader.get_uniform_location('uPixelSize');
+ shader._uStartPos = shader.get_uniform_location('uStartPos');
+
+ // Write all uniform values at the start of each animation.
+ shader.connect('begin-animation', (shader, settings, forOpening, actor) => {
+ // Because the actor position may change after the begin-animation signal is
+ // called, we set the uDirection uniform during the update callback.
+ this._startPointerPos = global.get_pointer();
+ this._actor = actor;
+
+ // clang-format off
+ shader.set_uniform_float(shader._uPixelSize, 1, [settings.get_int('pixel-wipe-pixel-size')]);
+ // clang-format on
+ });
+
+ // We set the uDirection uniform during the update callback as the actor position
+ // may not be set up properly before the begin animation callback.
+ shader.connect('update-animation', (shader) => {
+ if (this._startPointerPos) {
+ const [x, y] = this._startPointerPos;
+ const [ok, localX, localY] = this._actor.transform_stage_point(x, y);
+
+ if (ok) {
+ let startPos = [
+ Math.max(0.0, Math.min(1.0, localX / this._actor.width)),
+ Math.max(0.0, Math.min(1.0, localY / this._actor.height))
+ ];
+ shader.set_uniform_float(shader._uStartPos, 2, startPos);
+ }
+ }
+ });
+
+ // Make sure to drop the reference to the actor.
+ shader.connect('end-animation', (shader) => {
+ shader._actor = null;
+ });
+ });
+ }
+
+ // ---------------------------------------------------------------------------- metadata
+
+ // The effect is available on all GNOME Shell versions supported by this extension.
+ 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. '*-close-effect'), and its animation time
+ // (e.g. '*-animation-time').
+ getNick() {
+ return 'pixel-wipe';
+ }
+
+ // 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.
+ getLabel() {
+ return _('Pixel Wipe');
+ }
+
+ // -------------------------------------------------------------------- API for prefs.js
+
+ // This is called by the preferences dialog. It loads the settings page for this effect,
+ // and binds all properties to the settings.
+ getPreferences(dialog) {
+
+ // Add the settings page to the builder.
+ dialog.getBuilder().add_from_resource(`/ui/${utils.getGTKString()}/PixelWipe.ui`);
+
+ // Bind all properties.
+ dialog.bindAdjustment('pixel-wipe-animation-time');
+ dialog.bindAdjustment('pixel-wipe-pixel-size');
+
+ // Finally, return the new settings page.
+ return dialog.getBuilder().get_object('pixel-wipe-prefs');
+ }
+
+ // ---------------------------------------------------------------- API for extension.js
+
+ // The getActorScale() is called from extension.js to adjust the actor's size during the
+ // animation. This is useful if the effect requires drawing something beyond the usual
+ // bounds of the actor. This only works for GNOME 3.38+.
+ getActorScale(settings) {
+ return {x: 1.0, y: 1.0};
+ }
+}
diff --git a/src/Pixelate.js b/src/Pixelate.js
index 248f39a..368e58a 100644
--- a/src/Pixelate.js
+++ b/src/Pixelate.js
@@ -46,7 +46,7 @@ var Pixelate = class {
shader.connect('begin-animation', (shader, settings) => {
// clang-format off
shader.set_uniform_float(shader._uNoise, 1, [settings.get_double('pixelate-noise')]);
- shader.set_uniform_float(shader._uPixelSize, 1, [settings.get_double('pixelate-pixel-size')]);
+ shader.set_uniform_float(shader._uPixelSize, 1, [settings.get_int('pixelate-pixel-size')]);
// clang-format on
});
});