🔀 Merge pull request #69 from Schneegans/feature/reverse

This commit is contained in:
Simon Schneegans
2022-01-27 21:01:10 +01:00
committed by GitHub
15 changed files with 720 additions and 319 deletions
+2
View File
@@ -6,6 +6,7 @@
#### New Features #### New Features
* **Effects for Window Opening.** You can now select effects which are applied on newly opened windows! I expect that there are some bugs left, so please [report any issue you find](https://github.com/Schneegans/Burn-My-Windows/issues)!
* **New Effect: Broken Glass.** Shatter your windows into a shower sharp shards! This effect can be configured so that the shards fly away from your mouse pointer position! * **New Effect: Broken Glass.** Shatter your windows into a shower sharp shards! This effect can be configured so that the shards fly away from your mouse pointer position!
* The effect-configuration pages of the preferences dialog now have **Preview Buttons** which con be used to, well, preview the current settings (without having to enable the effect first). * The effect-configuration pages of the preferences dialog now have **Preview Buttons** which con be used to, well, preview the current settings (without having to enable the effect first).
@@ -13,6 +14,7 @@
* Added a menu entry with a link to the guide for creating new effect types. * Added a menu entry with a link to the guide for creating new effect types.
* Added a new option to the Matrix Effect: **Vertical Overshooting**: This can add some vertical variation to the start and end position of the letter drops. * Added a new option to the Matrix Effect: **Vertical Overshooting**: This can add some vertical variation to the start and end position of the letter drops.
* Thanks to improved timing, the default animation time of several effects could be reduced.
## [Burn My Window 9](https://github.com/schneegans/Burn-My-Windows/releases/tag/v9) ## [Burn My Window 9](https://github.com/schneegans/Burn-My-Windows/releases/tag/v9)
+14 -6
View File
@@ -150,12 +150,20 @@ var SimpleFade = class SimpleFade {
return new Shader(settings); return new Shader(settings);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For each property, you can set a "from", "to", and a "mode". For this // The parameter 'forOpening' is set to true if this is called for a window-open
// effect, windows should neither be scaled nor faded. // transition, for a window-close transition it is set to false. The modes can be set to
static getCloseTransition(actor, settings) { // any value from here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode.
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}}; // This also determines how the uProgress uniform value will progress in the shader.
// Tweaking the actor's scale during the transition only works properly for GNOME 3.38+.
// For this effect, windows should neither be scaled nor faded.
static tweakTransition(actor, settings, forOpening) {
return {
'opacity': {from: 255, to: 255, mode: 4},
'scale-x': {from: 1.0, to: 1.0, mode: 4},
'scale-y': {from: 1.0, to: 1.0, mode: 4}
};
} }
} }
+327 -211
View File
@@ -15,6 +15,7 @@
const {Clutter, Gio, Meta} = imports.gi; const {Clutter, Gio, Meta} = imports.gi;
const Main = imports.ui.main;
const Workspace = imports.ui.workspace.Workspace; const Workspace = imports.ui.workspace.Workspace;
const WindowManager = imports.ui.windowManager.WindowManager; const WindowManager = imports.ui.windowManager.WindowManager;
@@ -43,13 +44,12 @@ const ALL_EFFECTS = [
]; ];
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// This extensions modifies the window-close animation to look like the window was set // // This extensions modifies the window-close and window-open animations with all kinds //
// on fire. There are also a few other effects available. All of them are implemented // // of effects. The effects are implemented using GLSL shaders which are applied to the //
// using GLSL shaders which are applied to the window's Clutter.Actor. The extension is // // window's Clutter.Actor. The extension is actually very simple, much of the //
// actually very simple, most of the complexity comes from the fact that GNOME Shell // // complexity comes from the fact that GNOME Shell usually does not show an animation //
// usually does not show an animation when a window is closed in the overview. Several // // when a window is closed in the overview. Several methods need to be monkey-patched //
// methods need to be monkey-patched to get this working. For more details, read the // // to get this working. For more details, read the other comments in this file... //
// other comments in this file... //
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
class Extension { class Extension {
@@ -67,111 +67,138 @@ class Extension {
// Store a reference to the settings object. // Store a reference to the settings object.
this._settings = ExtensionUtils.getSettings(); this._settings = ExtensionUtils.getSettings();
// This will store an item of ALL_EFFECTS which was used the last time a window was // This will store an item of ALL_EFFECTS array which was used the last time a window
// closed. // was opened / closed.
this._effect = 0; this._currentEffect = 0;
// We will monkey-patch these three methods. Let's store the original ones. // We will use extensionThis to refer to the extension inside the patched methods.
const extensionThis = this;
// We will monkey-patch these methods. Let's store the original ones.
this._origAddWindowClone = Workspace.prototype._addWindowClone;
this._origWindowRemoved = Workspace.prototype._windowRemoved; this._origWindowRemoved = Workspace.prototype._windowRemoved;
this._origDoRemoveWindow = Workspace.prototype._doRemoveWindow; this._origDoRemoveWindow = Workspace.prototype._doRemoveWindow;
this._origAddWindowClone = Workspace.prototype._addWindowClone;
this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor; this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor;
// We will also override these animation times. // We will also override these animation times.
this._origWindowTime = imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME; this._origWindowTime = imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME;
this._origDialogTime = imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME; this._origDialogTime = imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME;
// Reset the dialog destroy time if the corresponding setting gets disabled.
this._settings.connect('changed::destroy-dialogs', () => {
if (!this._settings.get_boolean('destroy-dialogs')) {
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME =
this._origDialogTime;
}
});
// We will use extensionThis to refer to the extension inside the patched methods of // ------------------------------------------------ patching the window-open animation
// the WorkspacesView.
const extensionThis = this;
// This class is only available in GNOME Shell 3.38+. So no transition tweaking in // Here we add an effect to the window-open animation. This is done whenever a new
// GNOME Shell 3.36, but this is not used by any effect available there anyways for // window is created.
// now... this._windowCreatedConnection =
if (WindowPreview) { global.display.connect('window-created', (d, metaWin) => {
this._origDeleteAll = WindowPreview.prototype._deleteAll; let actor = metaWin.get_compositor_private();
this._origRestack = WindowPreview.prototype._restack;
this._origInit = WindowPreview.prototype._init;
// This is required, else WindowPreview's _restack() which is called by the // If we are currently in the overview, we add the effect to the original window
// "this.overlayEnabled = false", sometimes tries to access an already delete // actor. The window preview in the overview is basically a Clutter.Clone which
// WindowPreview. // shows the original window.
WindowPreview.prototype._restack = function() { if (Main.overview.visible && !Main.overview.closing) {
if (!this._closeRequested) { const id = actor.connect('show', () => {
// Call the original method. extensionThis._setupEffect(actor, true);
extensionThis._origRestack.apply(this); actor.disconnect(id);
} });
};
// When a window is removed from the overview, we need adjust the transitions of the }
// window clone according to the chosen effect. We do this in the 'unmanaged' signal // If a window is created outside of the overview, the transitions are set up in
// of the WindowPreview's Meta.Window. This is not ideal, as it does not work for // the async _mapWindow of the WindowManager which can defer the actual showing
// dialogs which close themselves... Maybe there's a better way? // of the window significantly, especially when currently leaving the overview:
WindowPreview.prototype._init = function(...params) { // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1449
// Call the original method. // AFAIK, overriding this method is not possible as it's called by a signal to
extensionThis._origInit.apply(this, params); // which it is bound via the bind() method. To tweak the async transition
// anyways, we override the actors ease() method once - the next time it will be
// called by the _mapWindow(), we will intercept it!
else {
const orig = actor.ease;
actor.ease = function(...params) {
orig.apply(actor, params);
actor.ease = orig;
// When the user clicks the X in the overview, the window is not deleted extensionThis._setupEffect(actor, true);
// immediately. However, as soon as the window is really deleted, we need to };
// adjust the transition of its clone.
const connectionID = this.metaWindow.connect('unmanaged', () => {
if (this.window_container) {
// Hide the window's icon, name, and close button.
this.overlayEnabled = false;
this._icon.visible = false;
const transitionConfig = extensionThis._effect.getCloseTransition(
this.window_container, extensionThis._settings);
extensionThis._tweakTransitions(this.window_container, transitionConfig);
} }
}); });
// Make sure to not call the callback above if the Meta.Window was not unmanaged // Some of the effects require that the window's actor is enlarged to provide a bigger
// before leaving the overview. // canvas to draw the effects. Outside the overview we can simply increase the scale
this.connect('destroy', () => { // of the actor. However, if we are in the overview, we have to enlarge the clone of
this.metaWindow.disconnect(connectionID); // the window as well.
Workspace.prototype._addWindowClone = function(...params) {
const result = extensionThis._origAddWindowClone.apply(this, params);
// The parameters of this method changed a bit through the versions...
let realWindow, clone;
if (utils.shellVersionIs(3, 36)) {
clone = result[0];
realWindow = clone.realWindow;
} else if (utils.shellVersionIs(3, 38)) {
clone = result._windowContainer;
realWindow = params[0].get_compositor_private();
} else {
clone = result.window_container;
realWindow = params[0].get_compositor_private();
}
// Syncing the real window's scale with the scale of its clone only works on GNOME
// Shell 3.38+. So effects cannot scale windows in the overview of GNOME 3.36...
if (utils.shellVersionIsAtLeast(3, 38)) {
const xID = realWindow.connect('notify::scale-x', () => {
if (realWindow.scale_x > 0) {
clone.scale_x = realWindow.scale_x;
}
}); });
};
// The _deleteAll is called when the user clicks the X in the overview. We should const yID = realWindow.connect('notify::scale-y', () => {
// not attempt to close windows twice. Due to the animation in the overview, the if (realWindow.scale_y > 0) {
// close button can be clicked twice which normally would lead to a crash. clone.scale_y = realWindow.scale_y;
WindowPreview.prototype._deleteAll = function() { }
if (!this._closeRequested) { });
extensionThis._origDeleteAll.apply(this);
}
};
}
// On GNOME 3.36, the window clone's 'destroy' handler only calls _removeWindowClone clone.connect('destroy', () => {
// but not _doRemoveWindow. The latter is required to trigger the repositioning of the realWindow.disconnect(xID);
// overview window layout. Therefore we call this method in addition. realWindow.disconnect(yID);
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/gnome-3-36/js/ui/workspace.js#L1877 });
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1415 }
if (utils.shellVersionIs(3, 36)) {
Workspace.prototype._addWindowClone = function(...params) { // This is actually need for the window-close animation on GNOME Shell 3.36.
const [clone, overlay] = extensionThis._origAddWindowClone.apply(this, params); // On GNOME 3.36, the window clone's 'destroy' handler only calls _removeWindowClone
// but not _doRemoveWindow. The latter is required to trigger the repositioning of
// the overview window layout. Therefore we call this method in addition.
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/gnome-3-36/js/ui/workspace.js#L1877
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1415
if (utils.shellVersionIs(3, 36)) {
clone.connect('destroy', () => this._doRemoveWindow(clone.metaWindow)); clone.connect('destroy', () => this._doRemoveWindow(clone.metaWindow));
return [clone, overlay]; }
};
}
// These three method overrides are mega-hacky! They are only required to make the return result;
// fire animation work in the overview. Usually, windows are not faded when closed };
// from the overview (why?). With these overrides we make sure that they are actually
// faded out. To do this, _windowRemoved and _doRemoveWindow now check whether there
// is a transition ongoing (via extensionThis._shouldDestroy). If that's the case, // ----------------------------------------------- patching the window-close animation
// these methods do nothing. Are the actors removed in the end? I hope so. The
// _destroyWindow of the WindowManager sets the transitions up and should take care of // The signal handler below is all which is required outside of the overview. All
// removing the actors at the end of the transitions. // other hacks further below are just required to defer the window-hiding in the
// overview until the effect is finished.
// The close animation is set up in WindowManager's _destroyWindow:
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1549
// As we cannot monkey-patch the _destroyWindow itself, we connect to the 'destroy'
// signal of the window manager and tweak the animation to our needs.
this._destroyConnection = global.window_manager.connect('destroy', (wm, actor) => {
this._setupEffect(actor, false);
});
// These three method overrides are mega-hacky! Usually, windows are not faded when
// closed from the overview (why?). With these overrides we make sure that they are
// actually faded out. To do this, _windowRemoved and _doRemoveWindow now check
// whether there is a transition ongoing (via extensionThis._shouldDestroy). If that's
// the case, these methods do nothing. Are the actors removed in the end? I hope so.
// The _destroyWindow of the WindowManager sets the transitions up and should take
// care of removing the actors at the end of the transitions.
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1299 // https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1299
Workspace.prototype._windowRemoved = function(ws, metaWin) { Workspace.prototype._windowRemoved = function(ws, metaWin) {
if (extensionThis._shouldDestroy(this, metaWin)) { if (extensionThis._shouldDestroy(this, metaWin)) {
@@ -200,98 +227,54 @@ class Extension {
return extensionThis._origShouldAnimateActor.apply(this, params); return extensionThis._origShouldAnimateActor.apply(this, params);
}; };
// The close animation is set up in WindowManager's _destroyWindow: // With the code below, we hide the window-overlay (icon, label, close button) in the
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1549 // overview once the close-animation is running. As the WindowPreview class is only
// As we cannot monkey-patch the _destroyWindow itself, we connect to the 'destroy' // available on GNOME 3.38 and beyond, we cannot hide the overlay on GNOME 3.36.
// signal of the window manager and tweak the animation to our needs. if (WindowPreview) {
this._destroyConnection = global.window_manager.connect('destroy', (wm, actor) => {
// The _destroyWindow method of WindowManager, which was called right before this
// one, set up the window close animation. This usually fades-out the window and
// scales it a bit down. If no transition is in progress, something unexpected
// happened. We rather try not to burn the window!
const transition = actor.get_transition('scale-y');
if (!transition) {
return;
}
// We do nothing if a dialog got closed and we should not burn them. // We will monkey-patch these methods.
const shouldDestroyDialogs = this._settings.get_boolean('destroy-dialogs'); this._origDeleteAll = WindowPreview.prototype._deleteAll;
const isDialogWindow = this._origRestack = WindowPreview.prototype._restack;
actor.meta_window.window_type == Meta.WindowType.MODAL_DIALOG || this._origInit = WindowPreview.prototype._init;
actor.meta_window.window_type == Meta.WindowType.DIALOG;
// If an effect is to be previewed, we have to affect dialogs es well. This is // Whenever a WindowPreview is created, we connect to the referenced Meta.Window's
// because the preview window is a dialog window... // 'unmanaged' signal to hide the overlay.
const previewNick = this._settings.get_string('close-preview-effect'); WindowPreview.prototype._init = function(...params) {
extensionThis._origInit.apply(this, params);
if (isDialogWindow && !shouldDestroyDialogs && previewNick == '') { // Hide the window's icon, name, and close button.
return; const connectionID = this.metaWindow.connect('unmanaged', () => {
} if (this.window_container) {
this.overlayEnabled = false;
// Now we have to choose an effect. this._icon.visible = false;
this._effect = null; }
// First we check if an effect is to be previewed.
if (previewNick != '') {
this._effect = ALL_EFFECTS.find(Effect => {
return Effect.getNick() == previewNick;
}); });
// Only preview the effect once. // Make sure to not call the callback above if the Meta.Window was not unmanaged
this._settings.set_string('close-preview-effect', ''); // before leaving the overview.
this.connect('destroy', () => {
} else { this.metaWindow.disconnect(connectionID);
// Else we choose a random effect from all enabled effects. Therefore, we first
// create a list of all currently enabled effects.
const enabled = ALL_EFFECTS.filter(Effect => {
return this._settings.get_boolean(`${Effect.getNick()}-close-effect`);
}); });
};
// And then choose a random effect. // The _deleteAll is called when the user clicks the X in the overview. We should
if (enabled.length > 0) { // not attempt to close windows twice. Due to the animation in the overview, the
this._effect = enabled[Math.floor(Math.random() * enabled.length)]; // close button can be clicked twice which normally would lead to a crash.
WindowPreview.prototype._deleteAll = function() {
if (!this._closeRequested) {
extensionThis._origDeleteAll.apply(this);
} }
} };
// If nothing was enabled, we have to do nothing :) // This is required, else WindowPreview's _restack() which is called by the
if (this._effect == null) { // "this.overlayEnabled = false", sometimes tries to access an already delete
return; // WindowPreview.
} WindowPreview.prototype._restack = function() {
if (!this._closeRequested) {
// The effect usually will choose to override the present transitions on the actor. extensionThis._origRestack.apply(this);
const transitionConfig = this._effect.getCloseTransition(actor, this._settings); }
this._tweakTransitions(actor, transitionConfig); };
}
// Add a cool shader to our window actor!
const shader = this._effect.createShader(actor, this._settings);
if (shader) {
actor.add_effect(shader);
// Update uniforms at each frame.
transition.connect('new-frame', (t) => {
shader.set_uniform_value('uProgress', t.get_progress());
shader.set_uniform_value('uTime', 0.001 * t.get_elapsed_time());
shader.set_uniform_value('uSizeX', actor.width);
shader.set_uniform_value('uSizeY', actor.height);
});
}
// The code below is not necessary for Burn-My-Windows to function. However, there
// are some extensions such as "Show Application View When Workspace Empty"
// https://extensions.gnome.org/extension/2036/show-application-view-when-workspace-empty/
// which do something *after* a window was closed. As the window-close animation
// duration depends on the used effect, this may vary each time a window is closed.
// We set the currently used time here, so that others can get an idea how long this
// will take...
const duration = transition.get_duration();
if (isDialogWindow && shouldDestroyDialogs) {
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME = duration;
} else {
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = duration;
}
});
} }
// This function could be called after the extension is uninstalled, disabled in GNOME // This function could be called after the extension is uninstalled, disabled in GNOME
@@ -301,12 +284,13 @@ class Extension {
// Unregister our resources. // Unregister our resources.
Gio.resources_unregister(this._resources); Gio.resources_unregister(this._resources);
// Restore the original behavior. // Restore the original window-open and window-close animations.
global.window_manager.disconnect(this._destroyConnection); global.window_manager.disconnect(this._destroyConnection);
global.display.disconnect(this._windowCreatedConnection);
Workspace.prototype._addWindowClone = this._origAddWindowClone;
Workspace.prototype._windowRemoved = this._origWindowRemoved; Workspace.prototype._windowRemoved = this._origWindowRemoved;
Workspace.prototype._doRemoveWindow = this._origDoRemoveWindow; Workspace.prototype._doRemoveWindow = this._origDoRemoveWindow;
Workspace.prototype._addWindowClone = this._origAddWindowClone;
WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor; WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor;
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = this._origWindowTime; imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = this._origWindowTime;
@@ -323,6 +307,174 @@ class Extension {
// ----------------------------------------------------------------------- private stuff // ----------------------------------------------------------------------- private stuff
// This method adds one of the configured effects to the given actor. If forOpening is
// set to true, a effect from the enabled window-open animations is chosen, else an
// enabled window-close animation is used. This will also tweak the transitions of the
// given actor (e.g. scale it up if required).
_setupEffect(actor, forOpening) {
// Only add effects to normal windows and dialog windows.
const isNormalWindow = actor.meta_window.window_type == Meta.WindowType.NORMAL;
const isDialogWindow =
actor.meta_window.window_type == Meta.WindowType.MODAL_DIALOG ||
actor.meta_window.window_type == Meta.WindowType.DIALOG;
if (!isNormalWindow && !isDialogWindow) {
return;
}
// We do nothing if a dialog got closed and we should not burn them.
const shouldDestroyDialogs = this._settings.get_boolean('destroy-dialogs');
// If an effect is to be previewed however, we have to affect dialogs es well. This is
// because the preview window is a dialog window...
const action = forOpening ? 'open' : 'close';
const previewNick = this._settings.get_string(action + '-preview-effect');
if (isDialogWindow && !shouldDestroyDialogs && previewNick == '') {
this._fixAnimationTimes(isDialogWindow, forOpening, null);
return;
}
// ------------------------------------------------------------------ choose an effect
// Now we chose a random effect from all enabled effects.
this._currentEffect = null;
// First we check if an effect is to be previewed.
if (previewNick != '') {
this._currentEffect = ALL_EFFECTS.find(Effect => {
return Effect.getNick() == previewNick;
});
// Only preview the effect once.
this._settings.set_string(action + '-preview-effect', '');
}
// Else we choose a random effect from all enabled effects.
else {
// Therefore, we first create a list of all currently enabled effects.
const enabled = ALL_EFFECTS.filter(Effect => {
return this._settings.get_boolean(`${Effect.getNick()}-${action}-effect`);
});
// And then choose a random effect.
if (enabled.length > 0) {
this._currentEffect = enabled[Math.floor(Math.random() * enabled.length)];
}
}
// If nothing was enabled, we have to do nothing :)
if (this._currentEffect == null) {
this._fixAnimationTimes(isDialogWindow, forOpening, null);
return;
}
// ----------------------------------------------------------- tweak actor transitions
// The following is used to tweak the ongoing transitions of a window actor. Usually
// windows are faded in / out scaled up / down slightly by GNOME Shell. Here, we allow
// modifications to this behavior by the effects.
const config = this._currentEffect.tweakTransition(actor, this._settings, forOpening);
const duration =
this._settings.get_int(this._currentEffect.getNick() + '-animation-time');
// All animations are relative to the window's center.
actor.set_pivot_point(0.5, 0.5);
// This goes through all properties given in the config object and tweaks any ongoing
// transitions accordingly. If there is no ongoing transition for a given property, a
// new one is set up.
for (const property in config) {
let transition = actor.get_transition(property);
// If there is currently no ongoing transition, we create a new one. Clutter does
// not like to create transitions with the same start and end value - however, we
// need at least one transition for our progress value in the shader. So we trick
// Clutter by creating an arbitrary transition first and then modifying the start
// and end values according to our config object.
if (!transition) {
actor.set_property(property, 0);
actor.save_easing_state();
actor.set_easing_duration(1000);
actor.set_property(property, 1);
actor.restore_easing_state();
// Now there should be a transition!
transition = actor.get_transition(property);
}
// For some reason, there are rare cases, where no transition is set up. We do not
// try to continue here...
if (!transition) {
utils.debug('Failed to set up transitions.');
this._fixAnimationTimes(isDialogWindow, forOpening, null);
return;
}
// Tweak the transition according to the config object.
transition.set_duration(duration);
transition.set_to(config[property].to);
transition.set_from(config[property].from);
transition.set_progress_mode(config[property].mode);
}
// There should always be a scale-y transitions. Once this is finished, we restore the
// original actor size.
const transition = actor.get_transition('scale-y');
transition.connect('completed', () => {
actor.scale_x = 1.0;
actor.scale_y = 1.0;
});
// -------------------------------------------------------------------- add the shader
// Now add a cool shader to our window actor!
const shader = this._currentEffect.createShader(actor, this._settings, forOpening);
if (shader) {
// First remove any old effect.
actor.remove_effect_by_name(`burn-my-windows-effect`);
actor.add_effect_with_name(`burn-my-windows-effect`, shader);
// Update uniforms at each frame.
transition.connect('new-frame', (t) => {
shader.set_uniform_value('uProgress', t.get_progress());
shader.set_uniform_value('uTime', 0.001 * t.get_elapsed_time());
shader.set_uniform_value('uSizeX', actor.width);
shader.set_uniform_value('uSizeY', actor.height);
});
transition.connect('completed', () => {
actor.remove_effect_by_name(`burn-my-windows-effect`);
});
}
// Finally, ensure that all animation times are set properly so that other extensions
// may guess how long it will take until windows are gone :)
this._fixAnimationTimes(isDialogWindow, forOpening, duration);
}
// The code below is not necessary for Burn-My-Windows to function. However, there
// are some extensions such as "Show Application View When Workspace Empty"
// https://extensions.gnome.org/extension/2036/show-application-view-when-workspace-empty/
// which do something *after* a window was closed. As the window-close animation
// duration depends on the used effect, this may vary each time a window is
// closed. We set the currently used time here, so that others can get an idea how
// long this will take...
_fixAnimationTimes(isDialogWindow, forOpening, duration) {
if (!forOpening) {
if (isDialogWindow) {
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME =
duration != null ? duration : this._origDialogTime;
} else {
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME =
duration != null ? duration : this._origWindowTime;
}
}
}
// This is required to enable window-close animations in the overview. See the comment // This is required to enable window-close animations in the overview. See the comment
// for Workspace.prototype._windowRemoved above for an explanation. // for Workspace.prototype._windowRemoved above for an explanation.
_shouldDestroy(workspace, metaWindow) { _shouldDestroy(workspace, metaWindow) {
@@ -340,42 +492,6 @@ class Extension {
return false; return false;
} }
// This is used to tweak the ongoing transitions of a window actor. This is either the
// actual actor of the Meta.Window or a clone in the overview. Usually windows are faded
// to transparency and scaled down slightly by GNOME Shell. Here, we allow modifications
// to this behavior by the effects.
_tweakTransitions(actor, config) {
const duration = this._settings.get_int(this._effect.getNick() + '-animation-time');
for (const property in config) {
const from = config[property].from;
const to = config[property].to;
const mode = config[property].mode;
const transition = actor.get_transition(property);
if (transition) {
transition.set_duration(duration);
if (to != undefined) transition.set_to(to);
if (from != undefined) transition.set_from(from);
if (mode != undefined) transition.set_progress_mode(mode);
} else {
if (from != undefined) actor[property] = from;
if (to != undefined) {
actor.save_easing_state();
actor.set_easing_duration(duration)
if (mode != undefined) actor.set_easing_mode(mode);
actor[property] = to;
actor.restore_easing_state();
}
}
}
}
} }
// This function is called once when the extension is loaded, not enabled. // This function is called once when the extension is loaded, not enabled.
+37 -3
View File
@@ -138,6 +138,28 @@ var PreferencesDialog = class PreferencesDialog {
// clang-format on // clang-format on
} }
// Populate the open-effects drop-down menu.
{
const menu = this._builder.get_object('open-effect-menu');
const group = Gio.SimpleActionGroup.new();
window.insert_action_group('open-effects', group);
ALL_EFFECTS.forEach(Effect => {
const [minMajor, minMinor] = Effect.getMinShellVersion();
if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
const nick = Effect.getNick();
const label = Effect.getLabel();
const actionName = nick + '-open-effect';
const fullName = 'open-effects.' + actionName;
const action = this._settings.create_action(actionName);
group.add_action(action);
menu.append_item(Gio.MenuItem.new(label, fullName));
}
});
}
// Populate the close-effects drop-down menu. // Populate the close-effects drop-down menu.
{ {
const menu = this._builder.get_object('close-effect-menu'); const menu = this._builder.get_object('close-effect-menu');
@@ -282,6 +304,7 @@ var PreferencesDialog = class PreferencesDialog {
// Each effect page is based on a template widget. This template contains the title // Each effect page is based on a template widget. This template contains the title
// and the preview button. // and the preview button.
// clang-format off // clang-format off
if (GObject.type_from_name('BurnMyWindowsEffectPage') == null) {
BurnMyWindowsEffectPage = BurnMyWindowsEffectPage =
GObject.registerClass({ GObject.registerClass({
GTypeName: 'BurnMyWindowsEffectPage', GTypeName: 'BurnMyWindowsEffectPage',
@@ -299,8 +322,12 @@ var PreferencesDialog = class PreferencesDialog {
this._button.connect('clicked', () => { this._button.connect('clicked', () => {
// Set the to-be-previewed effect. // Set the to-be-previewed effect.
dialog.getSettings().set_string('open-preview-effect', Effect.getNick());
dialog.getSettings().set_string('close-preview-effect', Effect.getNick()); dialog.getSettings().set_string('close-preview-effect', Effect.getNick());
// Make sure that the window.show() firther below "sees" this change.
Gio.Settings.sync();
// Create the preview-window. // Create the preview-window.
const window = new Gtk.Window({ const window = new Gtk.Window({
title: `Preview for ${Effect.getLabel()}`, title: `Preview for ${Effect.getLabel()}`,
@@ -311,6 +338,12 @@ var PreferencesDialog = class PreferencesDialog {
this._button.get_toplevel() this._button.get_toplevel()
}); });
// Add a header bar to the window.
if (utils.isGTK4()) {
const header = Gtk.HeaderBar.new();
window.set_titlebar(header);
}
const box = new Gtk.Box({ const box = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
valign: Gtk.Align.CENTER, valign: Gtk.Align.CENTER,
@@ -330,15 +363,16 @@ var PreferencesDialog = class PreferencesDialog {
if (utils.isGTK4()) { if (utils.isGTK4()) {
window.set_child(box); window.set_child(box);
window.show();
} else { } else {
window.add(box); window.add(box);
window.show_all();
} }
window.show();
}); });
} }
}); });
// clang-format on // clang-format on
}
} }
} }
+66 -1
View File
@@ -3,6 +3,7 @@
<requires lib="gtk" version="3.0" /> <requires lib="gtk" version="3.0" />
<menu id="close-effect-menu"></menu> <menu id="close-effect-menu"></menu>
<menu id="open-effect-menu"></menu>
<object class="GtkMenuButton" id="menu-button"> <object class="GtkMenuButton" id="menu-button">
<property name="menu-model">main-menu</property> <property name="menu-model">main-menu</property>
@@ -68,6 +69,70 @@
<object class="GtkListBox"> <object class="GtkListBox">
<property name="selection-mode">none</property> <property name="selection-mode">none</property>
<child>
<object class="GtkListBoxRow">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="spacing">8</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Open Window Animation</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">If multiple are selected, one is chosen randomly.</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
<style>
<class name="dim-label" />
<class name="caption" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton" id="open-effect-button">
<property name="menu-model">open-effect-menu</property>
<child>
<object class="GtkBox">
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Choose Effects</property>
</object>
</child>
<child>
<object class="GtkImage">
<property name="icon-name">pan-down-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child> <child>
<object class="GtkListBoxRow"> <object class="GtkListBoxRow">
<property name="margin-start">10</property> <property name="margin-start">10</property>
@@ -144,7 +209,7 @@
<property name="spacing">8</property> <property name="spacing">8</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="label" translatable="yes">Also Burn Dialogs</property> <property name="label" translatable="yes">Also Add Effects to Dialogs</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="valign">center</property> <property name="valign">center</property>
+46 -1
View File
@@ -3,6 +3,7 @@
<requires lib="gtk" version="4.0" /> <requires lib="gtk" version="4.0" />
<menu id="close-effect-menu"></menu> <menu id="close-effect-menu"></menu>
<menu id="open-effect-menu"></menu>
<object class="GtkMenuButton" id="menu-button"> <object class="GtkMenuButton" id="menu-button">
<property name="menu-model">main-menu</property> <property name="menu-model">main-menu</property>
@@ -70,6 +71,50 @@
</style> </style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Open Window Animation</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">If multiple are selected, one is chosen randomly.</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
<style>
<class name="dim-label" />
<class name="caption" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton" id="open-effect-button">
<property name="label">Choose Effects</property>
<property name="menu-model">open-effect-menu</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child> <child>
<object class="GtkListBoxRow"> <object class="GtkListBoxRow">
<property name="activatable">0</property> <property name="activatable">0</property>
@@ -121,7 +166,7 @@
<object class="GtkBox"> <object class="GtkBox">
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="label" translatable="yes">Also Burn Dialogs</property> <property name="label" translatable="yes">Also Add Effects to Dialogs</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="valign">center</property> <property name="valign">center</property>
@@ -19,6 +19,12 @@
<description>The effect with this nick will be used for the next window-close animation.</description> <description>The effect with this nick will be used for the next window-close animation.</description>
</key> </key>
<key name="open-preview-effect" type="s">
<default>""</default>
<summary>Open Preview Effect</summary>
<description>The effect with this nick will be used for the next window-open animation.</description>
</key>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Fire Options --> <!-- Fire Options -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
@@ -29,6 +35,12 @@
<description>Use the fire effect for window closing.</description> <description>Use the fire effect for window closing.</description>
</key> </key>
<key name="fire-open-effect" type="b">
<default>false</default>
<summary>Fire Open Effect</summary>
<description>Use the fire effect for window opening.</description>
</key>
<key name="fire-animation-time" type="i"> <key name="fire-animation-time" type="i">
<default>1500</default> <default>1500</default>
<summary>Fire Animation Time</summary> <summary>Fire Animation Time</summary>
@@ -93,8 +105,14 @@
<description>Use the matrix effect for window closing.</description> <description>Use the matrix effect for window closing.</description>
</key> </key>
<key name="matrix-open-effect" type="b">
<default>false</default>
<summary>Matrix Open Effect</summary>
<description>Use the matrix effect for window opening.</description>
</key>
<key name="matrix-animation-time" type="i"> <key name="matrix-animation-time" type="i">
<default>3000</default> <default>1500</default>
<summary>Matrix Animation Time</summary> <summary>Matrix Animation Time</summary>
<description>The time the matrix effect takes.</description> <description>The time the matrix effect takes.</description>
</key> </key>
@@ -139,6 +157,12 @@
<description>Use the tv effect for window closing.</description> <description>Use the tv effect for window closing.</description>
</key> </key>
<key name="tv-open-effect" type="b">
<default>false</default>
<summary>TV Open Effect</summary>
<description>Use the tv effect for window opening.</description>
</key>
<key name="tv-animation-time" type="i"> <key name="tv-animation-time" type="i">
<default>400</default> <default>400</default>
<summary>TV Animation Time</summary> <summary>TV Animation Time</summary>
@@ -161,8 +185,14 @@
<description>Use the trex effect for window closing.</description> <description>Use the trex effect for window closing.</description>
</key> </key>
<key name="trex-open-effect" type="b">
<default>false</default>
<summary>T-Rex Open Effect</summary>
<description>Use the trex effect for window opening.</description>
</key>
<key name="trex-animation-time" type="i"> <key name="trex-animation-time" type="i">
<default>1500</default> <default>1000</default>
<summary>T-Rex Animation Time</summary> <summary>T-Rex Animation Time</summary>
<description>The time the trex effect takes.</description> <description>The time the trex effect takes.</description>
</key> </key>
@@ -201,6 +231,12 @@
<description>Use the Energize A effect for window closing.</description> <description>Use the Energize A effect for window closing.</description>
</key> </key>
<key name="energize-a-open-effect" type="b">
<default>false</default>
<summary>Energize A Open Effect</summary>
<description>Use the Energize A effect for window opening.</description>
</key>
<key name="energize-a-animation-time" type="i"> <key name="energize-a-animation-time" type="i">
<default>2000</default> <default>2000</default>
<summary>Energize A Animation Time</summary> <summary>Energize A Animation Time</summary>
@@ -229,8 +265,14 @@
<description>Use the Energize B effect for window closing.</description> <description>Use the Energize B effect for window closing.</description>
</key> </key>
<key name="energize-b-open-effect" type="b">
<default>false</default>
<summary>Energize B Open Effect</summary>
<description>Use the Energize B effect for window opening.</description>
</key>
<key name="energize-b-animation-time" type="i"> <key name="energize-b-animation-time" type="i">
<default>2000</default> <default>1500</default>
<summary>Energize B Animation Time</summary> <summary>Energize B Animation Time</summary>
<description>The time the Energize B effect takes.</description> <description>The time the Energize B effect takes.</description>
</key> </key>
@@ -257,8 +299,14 @@
<description>Use the wisps effect for window closing.</description> <description>Use the wisps effect for window closing.</description>
</key> </key>
<key name="wisps-open-effect" type="b">
<default>false</default>
<summary>Wisps Open Effect</summary>
<description>Use the wisps effect for window opening.</description>
</key>
<key name="wisps-animation-time" type="i"> <key name="wisps-animation-time" type="i">
<default>2000</default> <default>1500</default>
<summary>Wisps Animation Time</summary> <summary>Wisps Animation Time</summary>
<description>The time the wisps effect takes.</description> <description>The time the wisps effect takes.</description>
</key> </key>
@@ -285,8 +333,14 @@
<description>Use the broken glass effect for window closing.</description> <description>Use the broken glass effect for window closing.</description>
</key> </key>
<key name="broken-glass-open-effect" type="b">
<default>false</default>
<summary>Broken Glass Open Effect</summary>
<description>Use the broken glass effect for window opening.</description>
</key>
<key name="broken-glass-animation-time" type="i"> <key name="broken-glass-animation-time" type="i">
<default>1500</default> <default>1000</default>
<summary>Broken Glass Animation Time</summary> <summary>Broken Glass Animation Time</summary>
<description>The time the broken glass effect takes.</description> <description>The time the broken glass effect takes.</description>
</key> </key>
+20 -13
View File
@@ -79,17 +79,21 @@ var BrokenGlass = class BrokenGlass {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(actor, settings); return new Shader(actor, settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, windows are set to twice their original size, so that // forOpening is set to true if this is called for a window-open transition, for a
// window-close transition it is set to false. The modes can be set to any value from
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
// determines how the uProgress uniform value will progress in the shader.
// For this effect, windows are set to twice their original size, so that
// we have some space to draw the shards. We also set the animation mode to "Linear". // we have some space to draw the shards. We also set the animation mode to "Linear".
static getCloseTransition(actor, settings) { static tweakTransition(actor, settings, forOpening) {
return { return {
'opacity': {to: 255, mode: 1}, 'opacity': {from: 255, to: 255, mode: 1},
'scale-x': {from: 2.0, to: 2.0, mode: 1}, 'scale-x': {from: 2.0, to: 2.0, mode: 1},
'scale-y': {from: 2.0, to: 2.0, mode: 1} 'scale-y': {from: 2.0, to: 2.0, mode: 1}
}; };
@@ -118,7 +122,7 @@ if (utils.isInShellProcess()) {
// resources/img/shards.png. The red channel of the texture contains the distance to the // resources/img/shards.png. The red channel of the texture contains the distance to the
// shard edges. This information is used to fade out the shards. // shard edges. This information is used to fade out the shards.
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(actor, settings) { _init(actor, settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the shards texture. As the shader is re-created for each window animation, // Load the shards texture. As the shader is re-created for each window animation,
@@ -151,16 +155,19 @@ if (utils.isInShellProcess()) {
const vec2 SEED = vec2(${Math.random()}, ${Math.random()}); const vec2 SEED = vec2(${Math.random()}, ${Math.random()});
const float SHARD_SCALE = ${settings.get_double('broken-glass-scale')}; const float SHARD_SCALE = ${settings.get_double('broken-glass-scale')};
const float SHARD_LAYERS = 5; const float SHARD_LAYERS = 5;
const float GRAVITY = ${settings.get_double('broken-glass-gravity')};
const float BLOW_FORCE = ${settings.get_double('broken-glass-blow-force')}; const float BLOW_FORCE = ${settings.get_double('broken-glass-blow-force')};
const float ACTOR_SCALE = 2.0; const float ACTOR_SCALE = 2.0;
const float PADDING = ACTOR_SCALE / 2.0 - 0.5; const float PADDING = ACTOR_SCALE / 2.0 - 0.5;
const vec2 EPICENTER = vec2(${epicenterX}, ${epicenterY}); const vec2 EPICENTER = vec2(${epicenterX}, ${epicenterY});
const float GRAVITY = ${forOpening ? '-1.0' : '1.0'} *
${settings.get_double('broken-glass-gravity')};
void main() { void main() {
cogl_color_out = vec4(0, 0, 0, 0); cogl_color_out = vec4(0, 0, 0, 0);
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
// Draw the individual shard layers. // Draw the individual shard layers.
for (float i=0; i<SHARD_LAYERS; ++i) { for (float i=0; i<SHARD_LAYERS; ++i) {
@@ -173,15 +180,15 @@ if (utils.isInShellProcess()) {
coords -= EPICENTER; coords -= EPICENTER;
// Scale each layer a bit differently. // Scale each layer a bit differently.
coords /= mix(1.0, 1.0 + BLOW_FORCE*(i+2)/SHARD_LAYERS, uProgress); coords /= mix(1.0, 1.0 + BLOW_FORCE*(i+2)/SHARD_LAYERS, progress);
// Rotate each layer a bit differently. // Rotate each layer a bit differently.
float rotation = (mod(i, 2.0)-0.5)*0.2*uProgress; float rotation = (mod(i, 2.0)-0.5)*0.2*progress;
coords = vec2(coords.x * cos(rotation) - coords.y * sin(rotation), coords = vec2(coords.x * cos(rotation) - coords.y * sin(rotation),
coords.x * sin(rotation) + coords.y * cos(rotation)); coords.x * sin(rotation) + coords.y * cos(rotation));
// Move down each layer a bit. // Move down each layer a bit.
float gravity = GRAVITY*0.1*(i+1)*uProgress*uProgress; float gravity = GRAVITY*0.1*(i+1)*progress*progress;
coords += vec2(0, gravity); coords += vec2(0, gravity);
// Restore correct position. // Restore correct position.
@@ -200,7 +207,7 @@ if (utils.isInShellProcess()) {
vec4 windowColor = texture2D(uTexture, coords); vec4 windowColor = texture2D(uTexture, coords);
// Dissolve the shard by using distance information from the red channel. // Dissolve the shard by using distance information from the red channel.
float dissolve = (shardMap.x - pow(uProgress+0.1, 2)) > 0 ? 1: 0; float dissolve = (shardMap.x - pow(progress+0.1, 2)) > 0 ? 1: 0;
cogl_color_out = mix(cogl_color_out, windowColor, dissolve); cogl_color_out = mix(cogl_color_out, windowColor, dissolve);
} }
} }
+20 -8
View File
@@ -74,15 +74,23 @@ var EnergizeA = class EnergizeA {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(settings); return new Shader(settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, windows should neither be scaled nor faded. // forOpening is set to true if this is called for a window-open transition, for a
static getCloseTransition(actor, settings) { // window-close transition it is set to false. The modes can be set to any value from
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}}; // here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
// determines how the uProgress uniform value will progress in the shader.
// For this effect, windows should neither be scaled nor faded.
static tweakTransition(actor, settings, forOpening) {
return {
'opacity': {from: 255, to: 255, mode: 3},
'scale-x': {from: 1.0, to: 1.0, mode: 3},
'scale-y': {from: 1.0, to: 1.0, mode: 3}
};
} }
} }
@@ -99,7 +107,7 @@ if (utils.isInShellProcess()) {
const shaderSnippets = Me.imports.src.shaderSnippets; const shaderSnippets = Me.imports.src.shaderSnippets;
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(settings) { _init(settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
const color = Clutter.Color.from_string(settings.get_string('energize-a-color'))[1]; const color = Clutter.Color.from_string(settings.get_string('energize-a-color'))[1];
@@ -144,6 +152,10 @@ if (utils.isInShellProcess()) {
// Compute fading window opacity. // Compute fading window opacity.
float windowMask = pow(1.0 - fadeOutProgress, 2.0); float windowMask = pow(1.0 - fadeOutProgress, 2.0);
#if ${forOpening ? '1' : '0'}
windowMask = 1.0 - windowMask;
#endif
return vec2(atomMask, windowMask); return vec2(atomMask, windowMask);
} }
+20 -8
View File
@@ -74,15 +74,23 @@ var EnergizeB = class EnergizeB {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(settings); return new Shader(settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, windows should neither be scaled nor faded. // forOpening is set to true if this is called for a window-open transition, for a
static getCloseTransition(actor, settings) { // window-close transition it is set to false. The modes can be set to any value from
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}}; // here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
// determines how the uProgress uniform value will progress in the shader.
// For this effect, windows should neither be scaled nor faded.
static tweakTransition(actor, settings, forOpening) {
return {
'opacity': {from: 255, to: 255, mode: 3},
'scale-x': {from: 1.0, to: 1.0, mode: 3},
'scale-y': {from: 1.0, to: 1.0, mode: 3}
};
} }
} }
@@ -99,7 +107,7 @@ if (utils.isInShellProcess()) {
const shaderSnippets = Me.imports.src.shaderSnippets; const shaderSnippets = Me.imports.src.shaderSnippets;
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(settings) { _init(settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
const color = Clutter.Color.from_string(settings.get_string('energize-b-color'))[1]; const color = Clutter.Color.from_string(settings.get_string('energize-b-color'))[1];
@@ -162,6 +170,10 @@ if (utils.isInShellProcess()) {
// Compute fading window opacity. // Compute fading window opacity.
float windowMask = pow(1.0 - fadeProgress, 2.0); float windowMask = pow(1.0 - fadeProgress, 2.0);
#if ${forOpening ? '1' : '0'}
windowMask = 1.0 - windowMask;
#endif
return vec4(showerMask, streakMask, atomMask, windowMask); return vec4(showerMask, streakMask, atomMask, windowMask);
} }
+22 -10
View File
@@ -96,15 +96,23 @@ var Fire = class Fire {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(settings); return new Shader(settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, windows should neither be scaled nor faded. // forOpening is set to true if this is called for a window-open transition, for a
static getCloseTransition(actor, settings) { // window-close transition it is set to false. The modes can be set to any value from
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 1.0}}; // here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
// determines how the uProgress uniform value will progress in the shader.
// For this effect, windows should neither be scaled nor faded.
static tweakTransition(actor, settings, forOpening) {
return {
'opacity': {from: 255, to: 255, mode: 3},
'scale-x': {from: 1.0, to: 1.0, mode: 3},
'scale-y': {from: 1.0, to: 1.0, mode: 3}
};
} }
// ----------------------------------------------------------------------- private stuff // ----------------------------------------------------------------------- private stuff
@@ -210,7 +218,7 @@ if (utils.isInShellProcess()) {
const shaderSnippets = Me.imports.src.shaderSnippets; const shaderSnippets = Me.imports.src.shaderSnippets;
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(settings) { _init(settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the gradient values from the settings. We directly inject the values in the // Load the gradient values from the settings. We directly inject the values in the
@@ -233,7 +241,7 @@ if (utils.isInShellProcess()) {
${shaderSnippets.edgeMask()} ${shaderSnippets.edgeMask()}
// These may be configurable in the future. // These may be configurable in the future.
const float EDGE_FADE = 90; const float EDGE_FADE = 70;
const float FADE_WIDTH = 0.1; const float FADE_WIDTH = 0.1;
const float HIDE_TIME = 0.4; const float HIDE_TIME = 0.4;
const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')}; const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')};
@@ -295,6 +303,10 @@ if (utils.isInShellProcess()) {
// Fade at window borders. // Fade at window borders.
effectMask *= getAbsoluteEdgeMask(edgeFadeWidth); effectMask *= getAbsoluteEdgeMask(edgeFadeWidth);
#if ${forOpening ? '1' : '0'}
windowMask = 1.0 - windowMask;
#endif
return vec2(windowMask, effectMask); return vec2(windowMask, effectMask);
} }
@@ -322,7 +334,7 @@ if (utils.isInShellProcess()) {
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x; cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x;
// Add the fire to the window. // Add the fire to the window.
cogl_color_out += fire; cogl_color_out = mix(cogl_color_out, fire, fire.a);
// These are pretty useful for understanding how this works. // These are pretty useful for understanding how this works.
// cogl_color_out = vec4(vec3(noise), 1); // cogl_color_out = vec4(vec3(noise), 1);
+19 -10
View File
@@ -81,19 +81,24 @@ var Matrix = class Matrix {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(settings); return new Shader(settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, windows should neither be scaled nor faded. // forOpening is set to true if this is called for a window-open transition, for a
static getCloseTransition(actor, settings) { // window-close transition it is set to false. The modes can be set to any value from
// here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
// determines how the uProgress uniform value will progress in the shader.
// For this effect, windows should not be faded but scaled vertically to allow for some
// overshooting.
static tweakTransition(actor, settings, forOpening) {
const yScale = 1.0 + settings.get_double('matrix-overshoot'); const yScale = 1.0 + settings.get_double('matrix-overshoot');
return { return {
'opacity': {to: 255}, 'opacity': {from: 255, to: 255, mode: 1},
'scale-x': {to: 1.0}, 'scale-x': {from: 1.0, to: 1.0, mode: 1},
'scale-y': {from: yScale, to: yScale} 'scale-y': {from: yScale, to: yScale, mode: 1}
}; };
} }
} }
@@ -111,7 +116,7 @@ if (utils.isInShellProcess()) {
const shaderSnippets = Me.imports.src.shaderSnippets; const shaderSnippets = Me.imports.src.shaderSnippets;
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(settings) { _init(settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the font texture. As the shader is re-created for each window animation, // Load the font texture. As the shader is re-created for each window animation,
@@ -187,6 +192,10 @@ if (utils.isInShellProcess()) {
rainAlpha *= smoothstep(0, 1, clamp(cogl_tex_coord_in[0].y / shorten, 0, 1)); rainAlpha *= smoothstep(0, 1, clamp(cogl_tex_coord_in[0].y / shorten, 0, 1));
rainAlpha *= smoothstep(0, 1, clamp((1.0 - cogl_tex_coord_in[0].y) / shorten, 0, 1)); rainAlpha *= smoothstep(0, 1, clamp((1.0 - cogl_tex_coord_in[0].y) / shorten, 0, 1));
#if ${forOpening ? '1' : '0'}
windowAlpha = 1.0 - windowAlpha;
#endif
return vec2(rainAlpha, windowAlpha); return vec2(rainAlpha, windowAlpha);
} }
+23 -18
View File
@@ -78,20 +78,23 @@ var TRexAttack = class TRexAttack {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(settings); return new Shader(settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, we slightly increase the window's scale as part of the // forOpening is set to true if this is called for a window-open transition, for a
// warp effect. // window-close transition it is set to false. The modes can be set to any value from
static getCloseTransition(actor, settings) { // here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
const warp = 0.5 * settings.get_double('claw-scratch-warp'); // determines how the uProgress uniform value will progress in the shader.
// For this effect, we slightly increase the window's scale as part of the warp effect.
static tweakTransition(actor, settings, forOpening) {
const warp = 1.0 + 0.5 * settings.get_double('claw-scratch-warp');
return { return {
'opacity': {to: 255}, 'opacity': {from: 255, to: 255, mode: 3},
'scale-x': {to: 1.0 + warp}, 'scale-x': {from: forOpening ? warp : 1.0, to: forOpening ? 1.0 : warp, mode: 3},
'scale-y': {to: 1.0 + warp} 'scale-y': {from: forOpening ? warp : 1.0, to: forOpening ? 1.0 : warp, mode: 3}
}; };
} }
} }
@@ -109,7 +112,7 @@ if (utils.isInShellProcess()) {
const shaderSnippets = Me.imports.src.shaderSnippets; const shaderSnippets = Me.imports.src.shaderSnippets;
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(settings) { _init(settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the claw texture. As the shader is re-created for each window animation, // Load the claw texture. As the shader is re-created for each window animation,
@@ -180,11 +183,13 @@ if (utils.isInShellProcess()) {
void main() { void main() {
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
// Warp the texture coordinates to create a blow-up effect. // Warp the texture coordinates to create a blow-up effect.
vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0; vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0;
float dist = length(coords); float dist = length(coords);
coords = (coords/dist * pow(dist, WARP_INTENSITY)) * 0.5 + 0.5; coords = (coords/dist * pow(dist, WARP_INTENSITY)) * 0.5 + 0.5;
coords = mix(cogl_tex_coord_in[0].st, coords, uProgress); coords = mix(cogl_tex_coord_in[0].st, coords, progress);
// Accumulate several random scratches. The color in the scratch map refers to the // Accumulate several random scratches. The color in the scratch map refers to the
// relative time when the respective part will become invisible. Therefore we can // relative time when the respective part will become invisible. Therefore we can
@@ -198,11 +203,11 @@ if (utils.isInShellProcess()) {
// Get the window texture. We shift the texture lookup by the local derivative of // Get the window texture. We shift the texture lookup by the local derivative of
// the claw texture in order to mimic some folding distortion. // the claw texture in order to mimic some folding distortion.
vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * uProgress * 0.5; vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * progress * 0.5;
cogl_color_out = texture2D(uTexture, coords + offset); cogl_color_out = texture2D(uTexture, coords + offset);
// Add colorful flashes. // Add colorful flashes.
float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - uProgress) + 1; float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - progress) + 1;
if (flashIntensity < 0 || flashIntensity >= 1) { if (flashIntensity < 0 || flashIntensity >= 1) {
flashIntensity = 0; flashIntensity = 0;
} }
@@ -211,16 +216,16 @@ if (utils.isInShellProcess()) {
flashIntensity *= cogl_color_out.a; flashIntensity *= cogl_color_out.a;
// Hide scratched out parts. // Hide scratched out parts.
cogl_color_out *= (scratchMap > uProgress ? 1 : 0); cogl_color_out *= (scratchMap > progress ? 1 : 0);
vec3 flashColor = vec3(${color.red / 255}, vec3 flashColor = vec3(${color.red / 255},
${color.green / 255}, ${color.green / 255},
${color.blue / 255}) * ${color.alpha / 255}; ${color.blue / 255}) * ${color.alpha / 255};
cogl_color_out.rgb += flashIntensity * mix(flashColor, vec3(0), uProgress); cogl_color_out.rgb += flashIntensity * mix(flashColor, vec3(0), progress);
// Fade out the remaining shards. // Fade out the remaining shards.
float fade = smoothstep(0, 1, 1 - clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1)); float fade = smoothstep(0, 1, 1 - clamp((progress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
cogl_color_out *= fade; cogl_color_out *= fade;
// These are pretty useful for understanding how this works. // These are pretty useful for understanding how this works.
+22 -12
View File
@@ -75,15 +75,23 @@ var TVEffect = class TVEffect {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(settings); return new Shader(settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, windows are scaled down vertically. // forOpening is set to true if this is called for a window-open transition, for a
static getCloseTransition(actor, settings) { // window-close transition it is set to false. The modes can be set to any value from
return {'opacity': {to: 255}, 'scale-x': {to: 1.0}, 'scale-y': {to: 0.5}}; // here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
// determines how the uProgress uniform value will progress in the shader.
// For this effect, windows are scaled down vertically.
static tweakTransition(actor, settings, forOpening) {
return {
'opacity': {from: 255, to: 255, mode: 3},
'scale-x': {from: 1.0, to: 1.0, mode: 3},
'scale-y': {from: forOpening ? 0.5 : 1.0, to: forOpening ? 1.0 : 0.5, mode: 3}
};
} }
} }
@@ -100,7 +108,7 @@ if (utils.isInShellProcess()) {
const shaderSnippets = Me.imports.src.shaderSnippets; const shaderSnippets = Me.imports.src.shaderSnippets;
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(settings) { _init(settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
const color = Clutter.Color.from_string(settings.get_string('tv-effect-color'))[1]; const color = Clutter.Color.from_string(settings.get_string('tv-effect-color'))[1];
@@ -118,13 +126,15 @@ if (utils.isInShellProcess()) {
void main() { void main() {
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
// All of these are in [0..1] during the different stages of the animation. // All of these are in [0..1] during the different stages of the animation.
// tb refers to the top-bottom animation. // tb refers to the top-bottom animation.
// lr refers to the left-right animation. // lr refers to the left-right animation.
// ff refers to the final fade animation. // ff refers to the final fade animation.
float tbProgress = smoothstep(0, 1, clamp(uProgress/TB_TIME, 0, 1)); float tbProgress = smoothstep(0, 1, clamp(progress/TB_TIME, 0, 1));
float lrProgress = smoothstep(0, 1, clamp((uProgress - LR_DELAY)/LR_TIME, 0, 1)); float lrProgress = smoothstep(0, 1, clamp((progress - LR_DELAY)/LR_TIME, 0, 1));
float ffProgress = smoothstep(0, 1, clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1)); float ffProgress = smoothstep(0, 1, clamp((progress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
// This is a top-center-bottom gradient in [0..1..0] // This is a top-center-bottom gradient in [0..1..0]
float tb = cogl_tex_coord_in[0].t * 2; float tb = cogl_tex_coord_in[0].t * 2;
@@ -147,7 +157,7 @@ if (utils.isInShellProcess()) {
${color.green / 255}, ${color.green / 255},
${color.blue / 255}, 1.0) * windowColor.a; ${color.blue / 255}, 1.0) * windowColor.a;
windowColor.rgb = mix(windowColor.rgb, effectColor.rgb, smoothstep(0, 1, uProgress)); windowColor.rgb = mix(windowColor.rgb, effectColor.rgb, smoothstep(0, 1, progress));
cogl_color_out = windowColor * mask; cogl_color_out = windowColor * mask;
+23 -13
View File
@@ -75,15 +75,23 @@ var Wisps = class Wisps {
// ---------------------------------------------------------------- API for extension.js // ---------------------------------------------------------------- API for extension.js
// This is called from extension.js whenever a window is closed with this effect. // This is called from extension.js whenever a window is closed with this effect.
static createShader(actor, settings) { static createShader(actor, settings, forOpening) {
return new Shader(settings); return new Shader(settings, forOpening);
} }
// This is also called from extension.js. It is used to tweak the ongoing transition of // This is also called from extension.js. It is used to tweak a window's open / close
// the actor - usually windows are faded to transparency and scaled down slightly by // transitions - usually windows are faded in / out and scaled up / down by GNOME Shell.
// GNOME Shell. For this effect, windows should be scaled down slightly but not faded. // forOpening is set to true if this is called for a window-open transition, for a
static getCloseTransition(actor, settings) { // window-close transition it is set to false. The modes can be set to any value from
return {'opacity': {to: 255}, 'scale-x': {to: 0.9}, 'scale-y': {to: 0.9}}; // here: https://gjs-docs.gnome.org/clutter8~8_api/clutter.animationmode. This also
// determines how the uProgress uniform value will progress in the shader.
// For this effect, windows should be scaled down slightly but not faded.
static tweakTransition(actor, settings, forOpening) {
return {
'opacity': {from: 255, to: 255, mode: 3},
'scale-x': {from: forOpening ? 0.9 : 1.0, to: forOpening ? 1.0 : 0.9, mode: 3},
'scale-y': {from: forOpening ? 0.9 : 1.0, to: forOpening ? 1.0 : 0.9, mode: 3}
};
} }
} }
@@ -100,7 +108,7 @@ if (utils.isInShellProcess()) {
const shaderSnippets = Me.imports.src.shaderSnippets; const shaderSnippets = Me.imports.src.shaderSnippets;
Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect { Shader = GObject.registerClass({}, class Shader extends Clutter.ShaderEffect {
_init(settings) { _init(settings, forOpening) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER}); super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
const color = Clutter.Color.from_string(settings.get_string('wisps-color'))[1]; const color = Clutter.Color.from_string(settings.get_string('wisps-color'))[1];
@@ -160,6 +168,8 @@ if (utils.isInShellProcess()) {
void main() { void main() {
float progress = ${forOpening ? '1.0-uProgress' : 'uProgress'};
// Get the color of the window. // Get the color of the window.
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st); vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
vec4 effectColor = vec4(${color.red / 255}, vec4 effectColor = vec4(${color.red / 255},
@@ -167,7 +177,7 @@ if (utils.isInShellProcess()) {
${color.blue / 255}, 1.0) * windowColor.a; ${color.blue / 255}, 1.0) * windowColor.a;
// Compute several layers of moving wisps. // Compute several layers of moving wisps.
vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, uProgress) + 0.5; vec2 uv = (cogl_tex_coord_in[0].st-0.5) / mix(1.0, 0.5, progress) + 0.5;
uv /= ${settings.get_double('wisps-scale')}; uv /= ${settings.get_double('wisps-scale')};
float wisps = 0; float wisps = 0;
for (int i=0; i<WISPS_LAYERS; ++i) { for (int i=0; i<WISPS_LAYERS; ++i) {
@@ -175,12 +185,12 @@ if (utils.isInShellProcess()) {
} }
// Compute shrinking edge mask. // Compute shrinking edge mask.
float mask = getRelativeEdgeMask(mix(0.01, 0.5, uProgress)); float mask = getRelativeEdgeMask(mix(0.01, 0.5, progress));
// Compute three different progress values. // Compute three different progress values.
float wispsIn = smoothstep(0, 1, clamp(uProgress/WISPS_IN_TIME, 0, 1)); float wispsIn = smoothstep(0, 1, clamp(progress/WISPS_IN_TIME, 0, 1));
float wispsOut = smoothstep(0, 1, clamp((uProgress - WISPS_IN_TIME)/(1.0 - WISPS_IN_TIME), 0, 1)); float wispsOut = smoothstep(0, 1, clamp((progress - WISPS_IN_TIME)/(1.0 - WISPS_IN_TIME), 0, 1));
float windowOut = smoothstep(0, 1, clamp(uProgress/WINDOW_OUT_TIME, 0, 1)); float windowOut = smoothstep(0, 1, clamp(progress/WINDOW_OUT_TIME, 0, 1));
// Use a noise function to dissolve the window. // Use a noise function to dissolve the window.
float noise = smoothstep(1.0, 0.0, abs(2.0 * simplex2DFractal(uv * vec2(uSizeX, uSizeY) / 250) - 1.0)); float noise = smoothstep(1.0, 0.0, abs(2.0 * simplex2DFractal(uv * vec2(uSizeX, uSizeY) / 250) - 1.0));