From 3228106ddf9a06eb0fc0ec38fcb36156166ed261 Mon Sep 17 00:00:00 2001 From: Simon Schneegans Date: Thu, 13 Jan 2022 04:49:28 +0100 Subject: [PATCH] :tada: Add initial attempt on a transporter effect --- extension.js | 1 + prefs.js | 1 + ...ell.extensions.burn-my-windows.gschema.xml | 22 ++ src/TOSTransporterEffect.js | 218 ++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 src/TOSTransporterEffect.js diff --git a/extension.js b/extension.js index 172755c..69f91ce 100644 --- a/extension.js +++ b/extension.js @@ -29,6 +29,7 @@ const ALL_EFFECTS = [ Me.imports.src.FireEffect.FireEffect, Me.imports.src.MatrixEffect.MatrixEffect, Me.imports.src.TRexEffect.TRexEffect, + Me.imports.src.TOSTransporterEffect.TOSTransporterEffect, Me.imports.src.TVEffect.TVEffect, ]; diff --git a/prefs.js b/prefs.js index 7ab28f9..882a275 100644 --- a/prefs.js +++ b/prefs.js @@ -24,6 +24,7 @@ const ALL_EFFECTS = [ Me.imports.src.FireEffect.FireEffect, Me.imports.src.MatrixEffect.MatrixEffect, Me.imports.src.TRexEffect.TRexEffect, + Me.imports.src.TOSTransporterEffect.TOSTransporterEffect, Me.imports.src.TVEffect.TVEffect, ]; 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 be346ba..7797aeb 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,28 @@ Number of claw scratches drawn on top of each other. + + + + + + false + TOS Transporter Close Effect + Use the TOS Transporter effect for window closing. + + + + 5000 + TOS Transporter Animation Time + The time the TOS Transporter effect takes. + + + + "rgb(255, 200, 50)" + TOS Transporter Color + The color of the effect. + + \ No newline at end of file diff --git a/src/TOSTransporterEffect.js b/src/TOSTransporterEffect.js new file mode 100644 index 0000000..e9f7a5e --- /dev/null +++ b/src/TOSTransporterEffect.js @@ -0,0 +1,218 @@ +////////////////////////////////////////////////////////////////////////////////////////// +// ) ( // +// ( /( ( ( ) ( ( ( ( )\ ) ( ( // +// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( // +// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ // +// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) // +// | '_ \ || | '_| ' \)) | ' \()| || | \ 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; + +////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////// + +// 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 TOSTransporterEffect = class TOSTransporterEffect { + + // ---------------------------------------------------------------------------- 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 'tos-transporter'; + } + + // 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 'TOS Transporter Effect'; + } + + // -------------------------------------------------------------------- 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()}/tvPage.ui`); + + // Bind all properties. + // dialog.bindAdjustment('tv-animation-time'); + // dialog.bindColorButton('tv-effect-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('tv-prefs'), TOSTransporterEffect.getNick(), + // TOSTransporterEffect.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('tos-transporter-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('tos-transporter-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 SPARK_RADIUS = 15.0; + const float SPARK_SPEED = 10.0; + const float SPARK_SPACING = 50 + SPARK_RADIUS; + const int SPARK_LAYERS = 15; + + float getSparks(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 + hash2D(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, hash(cellID*seed*134.451)) / gridSize * SPARK_SPEED; + float rotation = mix( 0.0, 6.283, hash(cellID*seed*54.4129)); + float radius = mix( 0.5, 1.0, hash(cellID*seed*19.1249)) * SPARK_RADIUS; + float roundness = mix(-1.0, 1.0, hash(cellID*seed*7.51949)); + + vec2 offset = vec2(sin(speed * (uTime+10)) * roundness, cos(speed * (uTime+10))); + offset *= (0.5 - radius / gridSize); + + offset = vec2(offset.x * cos(rotation) - offset.y * sin(rotation), + offset.x * sin(rotation) + offset.y * cos(rotation)); + + cellUV += offset; + + float dist = length(cellUV - 0.5) * gridSize / radius; + + if (dist < 1.0) { + return 5.0 * exp(-10.0 * dist); + return 0.05 / pow(dist, 2.0); + } + + return 0; + } + + void main() { + + 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; + + cogl_color_out = windowColor + effectColor; + + vec2 uv = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY) / 20 + vec2(0, uTime); + float sparks = noise3D(vec3(uv, uTime*15.0), 5) * 0.25; + + for (int i=0; i