diff --git a/README.md b/README.md index 8fb4c96..44753ee 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ Effect | Preview **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+_ | **TV-Effect**
This is a very simple effect to demonstrate that this extension could also be used in a more professional environment. | -**Your Effect!**
The extension is very modular and with a bit of creativity and GLSL knowledge, you can easily create your own effects. | [A tutorial for creating custom effects is available here.](docs/how-to-create-new-effects.md) +**Wisps**
Let your windows be carried away to the realm of dreams by these little fairies! | +**Your Effect!**
The extension is very modular and with a bit of creativity and GLSL knowledge, [you can easily create your own effects](docs/how-to-create-new-effects.md). | [![Create your own effects](docs/pics/custom.jpg)](docs/how-to-create-new-effects.md) ## 💞 These People _love_ this Extension diff --git a/docs/changelog.md b/docs/changelog.md index d67f555..9ba7b60 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -7,6 +7,7 @@ #### 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: 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**. #### Other Enhancements @@ -16,6 +17,7 @@ * The **layout of the settings dialog** has been reworked to make it easier to expand it in the future. * The lower limit of the **animation time of the TV Effect** has been reduced. * The T-Rex-Attack effect is not shown in fully transparent regions of a window any more. +* The shaders now use a different noise implementation which produces better 3D noise. #### Fixes diff --git a/docs/pics/custom.jpg b/docs/pics/custom.jpg new file mode 100644 index 0000000..1e99b05 Binary files /dev/null and b/docs/pics/custom.jpg differ diff --git a/docs/pics/wisps.gif b/docs/pics/wisps.gif new file mode 100644 index 0000000..30efffb Binary files /dev/null and b/docs/pics/wisps.gif differ diff --git a/extension.js b/extension.js index 6fef4cd..21246a2 100644 --- a/extension.js +++ b/extension.js @@ -32,6 +32,7 @@ const ALL_EFFECTS = [ Me.imports.src.TOSTransporterEffect.TOSTransporterEffect, Me.imports.src.TNGTransporterEffect.TNGTransporterEffect, Me.imports.src.TVEffect.TVEffect, + Me.imports.src.WispsEffect.WispsEffect, ]; ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/prefs.js b/prefs.js index bae7cf7..f6fc891 100644 --- a/prefs.js +++ b/prefs.js @@ -27,6 +27,7 @@ const ALL_EFFECTS = [ Me.imports.src.TOSTransporterEffect.TOSTransporterEffect, Me.imports.src.TNGTransporterEffect.TNGTransporterEffect, Me.imports.src.TVEffect.TVEffect, + Me.imports.src.WispsEffect.WispsEffect, ]; ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/resources/ui/gtk3/wispsPage.ui b/resources/ui/gtk3/wispsPage.ui new file mode 100644 index 0000000..a680f97 --- /dev/null +++ b/resources/ui/gtk3/wispsPage.ui @@ -0,0 +1,127 @@ + + + + + 10000 + 500 + 10 + 100 + + + + 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 + wisps-animation-time + + + + + + + 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/gtk4/wispsPage.ui b/resources/ui/gtk4/wispsPage.ui new file mode 100644 index 0000000..3aee991 --- /dev/null +++ b/resources/ui/gtk4/wispsPage.ui @@ -0,0 +1,109 @@ + + + + + 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 + + + + + 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 fd546a4..0c399d7 100644 --- a/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml +++ b/schemas/org.gnome.shell.extensions.burn-my-windows.gschema.xml @@ -88,7 +88,7 @@ - 2000 + 3000 Matrix Animation Time The time the matrix effect takes. @@ -223,6 +223,28 @@ The color of the effect. + + + + + + false + Wisps Close Effect + Use the wisps effect for window closing. + + + + 2000 + Wisps Animation Time + The time the wisps effect takes. + + + + "rgb(255, 100, 200)" + Wisps Effect Color + The color of the wisps effect. + + \ No newline at end of file diff --git a/src/FireEffect.js b/src/FireEffect.js index a6542aa..3493692 100644 --- a/src/FireEffect.js +++ b/src/FireEffect.js @@ -323,9 +323,9 @@ if (utils.isInShellProcess()) { uv.y += uTime * FIRE_SPEED; #if ${settings.get_boolean('flame-3d-noise') ? 1 : 0} - float noise = noise3D(vec3(uv*7.5, uTime*FIRE_SPEED*3.0), 5); + float noise = simplex3DFractal(vec3(uv*4.0, uTime*FIRE_SPEED*1.5)); #else - float noise = noise2D(uv * 7.5, 5); + float noise = simplex2DFractal(uv * 4.0); #endif // Modulate noise by effect mask. diff --git a/src/MatrixEffect.js b/src/MatrixEffect.js index f4156e0..ae47a0f 100644 --- a/src/MatrixEffect.js +++ b/src/MatrixEffect.js @@ -165,7 +165,7 @@ if (utils.isInShellProcess()) { vec2 block = pixelCoords/LETTER_SIZE - uv; // Choose random letter. - uv += floor(hash2D(floor(hash2D(block)*vec2(12.9898,78.233) + LETTER_FLICKER_SPEED*uTime + 42.254))*LETTER_TILES); + uv += floor(hash22(floor(hash22(block)*vec2(12.9898,78.233) + LETTER_FLICKER_SPEED*uTime + 42.254))*LETTER_TILES); return texture2D(uFontTexture, uv/LETTER_TILES).r; } diff --git a/src/TRexEffect.js b/src/TRexEffect.js index 3773186..7268e80 100644 --- a/src/TRexEffect.js +++ b/src/TRexEffect.js @@ -159,7 +159,7 @@ if (utils.isInShellProcess()) { vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) { // Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. - vec2 coords = texCoords + hash2D(seed); + vec2 coords = texCoords + hash22(seed); coords *= uSizeX < uSizeY ? vec2(1.0, 1.0 * uSizeY / uSizeX) : vec2(1.0 * uSizeX / uSizeY, 1.0); // Apply global scale. @@ -172,10 +172,10 @@ if (utils.isInShellProcess()) { vec2 cellID = coords-cellUV + vec2(362.456); // Add random rotation, scale and offset to each grid cell. - float scale = mix(0.8, 1.0, hash(cellID*seed*134.451)); - float offsetX = mix(0.0, 1.0 - scale, hash(cellID*seed*54.4129)); - float offsetY = mix(0.0, 1.0 - scale, hash(cellID*seed*25.3089)); - float rotation = mix(0.0, 2.0 * 3.141, hash(cellID*seed*2.99837)); + float scale = mix(0.8, 1.0, hash12(cellID*seed*134.451)); + float offsetX = mix(0.0, 1.0 - scale, hash12(cellID*seed*54.4129)); + float offsetY = mix(0.0, 1.0 - scale, hash12(cellID*seed*25.3089)); + float rotation = mix(0.0, 2.0 * 3.141, hash12(cellID*seed*2.99837)); cellUV -= vec2(offsetX, offsetY); cellUV /= scale; diff --git a/src/WispsEffect.js b/src/WispsEffect.js new file mode 100644 index 0000000..95139c4 --- /dev/null +++ b/src/WispsEffect.js @@ -0,0 +1,220 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ 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 lets your windows be carried to the realm of dreams by some little // +// fairies. It's implemented with several overlaid grids of randomly moving points. // +////////////////////////////////////////////////////////////////////////////////////////// + +// 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 WispsEffect = class WispsEffect { + + // ---------------------------------------------------------------------------- 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 'wisps'; + } + + // 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 'Wisps'; + } + + // -------------------------------------------------------------------- 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()}/wispsPage.ui`); + + // Bind all properties. + dialog.bindAdjustment('wisps-animation-time'); + dialog.bindColorButton('wisps-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('wisps-prefs'), WispsEffect.getNick(), + WispsEffect.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('wisps-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 not faded but scaled down a + // tiny bit. + tweakTransition('opacity', 255); + tweakTransition('scale-x', 0.9); + tweakTransition('scale-y', 0.9); + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// 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('wisps-color'))[1]; + + this.set_shader_source(` + + // Inject some common shader snippets. + ${shaderSnippets.standardUniforms()} + ${shaderSnippets.noise()} + + const vec2 SEED = vec2(${Math.random()}, ${Math.random()}); + const float WISPS_RADIUS = 20.0; + const float WISPS_SPEED = 10.0; + const float WISPS_SPACING = 40 + WISPS_RADIUS; + const int WISPS_LAYERS = 8; + const float WISPS_IN_TIME = 0.5; + const float WINDOW_OUT_TIME = 1.0; + + // Returns a grid of randomly moving points. Each grid cell contains one point which + // moves on an ellipse. + float getWisps(vec2 texCoords, float gridSize, vec2 seed) { + + // Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio. + vec2 coords = (texCoords + hash22(seed)) * vec2(uSizeX, uSizeY); + + // Apply global scale. + coords /= gridSize; + + // Get grid cell coordinates in [0..1]. + vec2 cellUV = mod(coords, vec2(1)); + + // This is unique for each cell. + vec2 cellID = coords-cellUV + vec2(362.456); + + // Add random rotation, scale and offset to each grid cell. + float speed = mix(10.0, 15.0, hash12(cellID*seed*134.451)) / gridSize * WISPS_SPEED; + float rotation = mix( 0.0, 6.283, hash12(cellID*seed*54.4129)); + float radius = mix( 0.5, 1.0, hash12(cellID*seed*19.1249)) * WISPS_RADIUS; + float roundness = mix(-1.0, 1.0, hash12(cellID*seed*7.51949)); + + vec2 offset = vec2(sin(speed * (uTime+1)) * roundness, cos(speed * (uTime+1))); + offset *= 0.5 - 0.5 * radius / gridSize; + offset = vec2(offset.x * cos(rotation) - offset.y * sin(rotation), + offset.x * sin(rotation) + offset.y * cos(rotation)); + + cellUV += offset; + + // Use distance to center of shifted / rotated UV coordinates to draw a glaring point. + float dist = length(cellUV - 0.5) * gridSize / radius; + if (dist < 1.0) { + return min(10, 0.01 / pow(dist, 2.0)); + } + + return 0.0; + } + + void main() { + + // Get the color of the window. + vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); + vec4 effectColor = vec4(${color.red / 255}, + ${color.green / 255}, + ${color.blue / 255}, 1.0) * windowColor.a; + + // Compute several layers of moving wisps. + vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, uProgress) + 0.5; + float wisps = 0; + for (int i=0; i