From 48aa96312fb1cd5284110d25d0939055dc6e40f6 Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Sat, 21 May 2022 11:08:24 +0200 Subject: [PATCH] :tada: Add initial incinerate effect --- extension.js | 1 + prefs.js | 1 + resources/shaders/burn.glsl | 85 ++++++ resources/ui/gtk4/Burn.ui | 243 ++++++++++++++++++ ...ell.extensions.burn-my-windows.gschema.xml | 46 ++++ src/Burn.js | 120 +++++++++ 6 files changed, 496 insertions(+) create mode 100644 resources/shaders/burn.glsl create mode 100644 resources/ui/gtk4/Burn.ui create mode 100644 src/Burn.js diff --git a/extension.js b/extension.js index b61f168..2076973 100644 --- a/extension.js +++ b/extension.js @@ -52,6 +52,7 @@ class Extension { this._ALL_EFFECTS = [ new Me.imports.src.Apparition.Apparition(), new Me.imports.src.BrokenGlass.BrokenGlass(), + new Me.imports.src.Burn.Burn(), new Me.imports.src.EnergizeA.EnergizeA(), new Me.imports.src.EnergizeB.EnergizeB(), new Me.imports.src.Fire.Fire(), diff --git a/prefs.js b/prefs.js index bb45daa..f0dff01 100644 --- a/prefs.js +++ b/prefs.js @@ -49,6 +49,7 @@ var PreferencesDialog = class PreferencesDialog { this._ALL_EFFECTS = [ new Me.imports.src.Apparition.Apparition(), new Me.imports.src.BrokenGlass.BrokenGlass(), + new Me.imports.src.Burn.Burn(), new Me.imports.src.EnergizeA.EnergizeA(), new Me.imports.src.EnergizeB.EnergizeB(), new Me.imports.src.Fire.Fire(), diff --git a/resources/shaders/burn.glsl b/resources/shaders/burn.glsl new file mode 100644 index 0000000..7287eb1 --- /dev/null +++ b/resources/shaders/burn.glsl @@ -0,0 +1,85 @@ +// Inject some common shader snippets. It is only possible to include glsl files from the +// "common" directory. Also, the files in the "common" directory are not allowed to +// include any further files. +#include "common/uniforms.glsl" +#include "common/noise.glsl" +#include "common/easing.glsl" +#include "common/compositing.glsl" +#include "common/edgeMask.glsl" + +uniform vec2 uSeed; +uniform vec3 uColor; +uniform float uScale; +uniform float uWidth; +uniform float uTurbulence; + +vec4 getFireColor(float v) { + const float steps[3] = float[](0.0, 0.5, 1.0); + vec4 colors[3] = vec4[](vec4(1, 0, 0, 0), vec4(1, 0, 0, 0.5), vec4(1, 1, 0, 1)); + + if (v < steps[0]) { + return colors[0]; + } + + for (int i = 0; i < 2; ++i) { + if (v <= steps[i + 1]) { + return mix(colors[i], colors[i + 1], + vec4(v - steps[i]) / (steps[i + 1] - steps[i])); + } + } + + return colors[2]; +} + +void main() { + float progress = uProgress / 0.8; + + progress = uForOpening ? 1.0 - progress : progress; + + vec2 uv = 0.01 * cogl_tex_coord_in[0].st * uSize / uScale; + + float lfNoise = simplex2D(cogl_tex_coord_in[0].st + uSeed); + lfNoise = mix(lfNoise - 1.0, lfNoise + 1.0, progress); + + float hfNoise = simplex2DFractal(uv + uSeed); + hfNoise = mix(hfNoise - 1.0, hfNoise + 1.0, progress); + + float noise = mix(lfNoise, hfNoise, uTurbulence); + float fire = noise / (0.03 * uWidth) - progress / (0.03 * uWidth) + progress; + + 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; + } + + cogl_color_out = windowColor; + + if (fire >= 1) { + cogl_color_out.a = 0; + } else if (fire > 0) { + vec4 fire = getFireColor(fire); + fire.a *= cogl_color_out.a; + cogl_color_out = alphaOver(cogl_color_out, fire); + } + + if ((uForOpening && fire < 0) || (!uForOpening && fire > 1)) { + float smoke = (uForOpening ? -fire : fire - 1) * uWidth; + + vec2 uv = 0.01 * cogl_tex_coord_in[0].st * uSize / uScale; + vec2 smokeShift = vec2(0, smoke * 0.1); + smoke = clamp(smoke, 0, 1) * simplex2DFractal(uv + uSeed + smokeShift); + + smoke *= getRelativeEdgeMask(0.3); + + float fadeOutProgress = clamp((uProgress - 0.7) / 0.3, 0, 1); + smoke *= 1 - fadeOutProgress; + + cogl_color_out = alphaOver(cogl_color_out, vec4(vec3(0.2), smoke)); + } + + // if (cogl_tex_coord_in[0].s > 0.5) { + // cogl_color_out = vec4(vec3(noise), 1.0); + // } +} \ No newline at end of file diff --git a/resources/ui/gtk4/Burn.ui b/resources/ui/gtk4/Burn.ui new file mode 100644 index 0000000..1dab008 --- /dev/null +++ b/resources/ui/gtk4/Burn.ui @@ -0,0 +1,243 @@ + + + + + vertical + + + + + + none + 1 + + + + + 0 + + + + + Animation Time [ms] + 0 + start + center + 1 + + + + + end + center + 1 + 0 + left + 300 + + + 10000 + 100 + 1 + 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 + + + + + Width + 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 + + + + + Turbulence + 0 + start + center + 1 + + + + + end + center + 1 + 2 + left + 300 + + + 1 + 0 + 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/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml index f852dad..7df24ef 100644 --- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml +++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml @@ -325,6 +325,52 @@ Use additive blending for the line and the glow. + + + + + + false + Burn Close Effect + Use the Burn effect for window closing. + + + + false + Burn Open Effect + Use the Burn effect for window opening. + + + + 2000 + Burn Animation Time + The time the Burn effect takes. + + + + 1.0 + Burn Scale + The scale of the effect. + + + + 1.0 + Burn Width + The width of the effect. + + + + 0.15 + Burn Turbulence + The turbulence of the effect. + + + + "rgb(255, 200, 50)" + Burn Color + The color of the effect. + + diff --git a/src/Burn.js b/src/Burn.js new file mode 100644 index 0000000..2b44bcf --- /dev/null +++ b/src/Burn.js @@ -0,0 +1,120 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 effect looks a bit like the transporter effect from TOS. // +////////////////////////////////////////////////////////////////////////////////////////// + +// 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 Burn = 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) => { + // We import Clutter in this function as it is not available in the preferences + // process. This creator function of the ShaderFactory is only called within GNOME + // Shell's process. + const Clutter = imports.gi.Clutter; + + // Store uniform locations of newly created shaders. + shader._uSeed = shader.get_uniform_location('uSeed'); + shader._uColor = shader.get_uniform_location('uColor'); + shader._uWidth = shader.get_uniform_location('uWidth'); + shader._uScale = shader.get_uniform_location('uScale'); + shader._uTurbulence = shader.get_uniform_location('uTurbulence'); + + // Write all uniform values at the start of each animation. + shader.connect('begin-animation', (shader, settings) => { + const c = Clutter.Color.from_string(settings.get_string('burn-color'))[1]; + + // If we are currently performing integration test, the animation uses a fixed + // seed. + const testMode = settings.get_boolean('test-mode'); + + // clang-format off + shader.set_uniform_float(shader._uSeed, 2, [testMode ? 0 : Math.random(), testMode ? 0 : Math.random()]); + shader.set_uniform_float(shader._uColor, 3, [c.red / 255, c.green / 255, c.blue / 255]); + shader.set_uniform_float(shader._uWidth, 1, [settings.get_double('burn-width')]); + shader.set_uniform_float(shader._uScale, 1, [settings.get_double('burn-scale')]); + shader.set_uniform_float(shader._uTurbulence, 1, [settings.get_double('burn-turbulence')]); + // clang-format on + }); + }); + } + + // ---------------------------------------------------------------------------- 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 'burn'; + } + + // 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 _('Burn'); + } + + // -------------------------------------------------------------------- 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()}/Burn.ui`); + + // Bind all properties. + dialog.bindAdjustment('burn-animation-time'); + dialog.bindAdjustment('burn-width'); + dialog.bindAdjustment('burn-scale'); + dialog.bindAdjustment('burn-turbulence'); + dialog.bindColorButton('burn-color'); + + // Finally, return the new settings page. + return dialog.getBuilder().get_object('burn-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}; + } +} \ No newline at end of file