🔀 Merge pull request #169 from Schneegans/feature/kde
This commit is contained in:
@@ -6,8 +6,8 @@ on:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
extension_bundle:
|
||||
name: Extension Bundle
|
||||
gnome_bundle:
|
||||
name: Bundle GNOME Shell Extension
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
@@ -26,3 +26,24 @@ jobs:
|
||||
file: burn-my-windows@schneegans.github.com.zip
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
kwin_bundle:
|
||||
name: Bundle KWin Effect
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install clang-format
|
||||
- name: Create Release
|
||||
run: |
|
||||
./kwin/build.sh
|
||||
- name: Upload Release
|
||||
uses: svenstaro/upload-release-action@2.2.1
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: kwin/burn_my_windows_kwin4.tar.gz
|
||||
tag: ${{ github.ref }}
|
||||
overwrite: true
|
||||
|
||||
+3
-1
@@ -6,4 +6,6 @@
|
||||
/locale
|
||||
/schemas/gschemas.compiled
|
||||
/resources/burn-my-windows.gresource
|
||||
/resources/burn-my-windows.gresource.xml
|
||||
/resources/burn-my-windows.gresource.xml
|
||||
kwin/_build
|
||||
kwin/*.tar.gz
|
||||
@@ -3,6 +3,7 @@
|
||||
</p>
|
||||
|
||||
<h1 align="center">🔥 Set GNOME Shell on Fire!</h1>
|
||||
<p align="center">(and KWin as well)</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://extensions.gnome.org/extension/4679/burn-my-windows/"><img src="https://img.shields.io/badge/Download-extensions.gnome.org-e67f4d.svg?logo=gnome&logoColor=lightgrey&labelColor=303030" /></a><br/>
|
||||
@@ -13,27 +14,52 @@
|
||||
<a href="scripts/cloc.sh"><img src="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/Schneegans/8cf45f23253ff09b21196e7271378762/raw/comments.json" /></a>
|
||||
</p>
|
||||
|
||||
When I released the [Desktop Cube Extension](https://github.com/Schneegans/Desktop-Cube/), many people requested to revive one of the most useless features of Linux desktop history: Setting windows on fire!
|
||||
When I released the [Desktop Cube Extension](https://github.com/Schneegans/Desktop-Cube/) for GNOME, many people requested to revive one of the most useless features of Linux desktop history: Setting windows on fire!
|
||||
This extension is not only more useless than the cube, but it is also much more hacky. So I expect some bug! [Let's incinerate them all](https://github.com/Schneegans/Burn-My-Windows/issues)!
|
||||
|
||||
For a list of things changed in previous releases, you can have a look at the [changelog](docs/changelog.md)!
|
||||
|
||||
Burn-My-Windows is not only available for **GNOME** but also includes some basic support for **KDE Plasma's KWin**.
|
||||
Further down in this file you'll find installation instructions for both.
|
||||
|
||||
Effect | Preview
|
||||
-----|--------
|
||||
**Apparition** <br> This effect hides your windows by violently sucking them into the void of magic! <br><br> _Only available in GNOME Shell 3.38+_ | <img src ="docs/pics/apparition.gif" />
|
||||
**Broken Glass** <br> Shatter your windows into a shower sharp shards! This effect can be configured so that the shards fly away from your mouse pointer position! <br><br> _Only available in GNOME Shell 40+_ | <img src ="docs/pics/glass.gif" />
|
||||
**Apparition** <br> This effect hides your windows by violently sucking them into the void of magic! | <img src ="docs/pics/apparition.gif" />
|
||||
**Broken Glass** <br> Shatter your windows into a shower sharp shards! This effect can be configured so that the shards fly away from your mouse pointer position!| <img src ="docs/pics/glass.gif" />
|
||||
**Energize A** <br> Beam your windows away! | <img src ="docs/pics/energizeA.gif" />
|
||||
**Energize B** <br> Using different transporter technology results in an alternative visual effect. | <img src ="docs/pics/energizeB.gif" />
|
||||
**Fire** <br> The classic effect inspired by Compiz. However, this is implemented using a GLSL shader and not with a particle system like in the old days. | <img src ="docs/pics/fire.gif" />
|
||||
**Hexagon** <br> With glowing lines and hexagon-shaped tiles, this effect looks very sci-fi. | <img src ="docs/pics/hexagon.gif" />
|
||||
**Matrix** <br> Turn your windows into a shower of green letters! The color is actually configurable. <br><br> _Only available in GNOME Shell 40+_ | <img src ="docs/pics/matrix.gif" />
|
||||
**Snap of Disintegration** <br> Dissolve your windows into a cloud of dust. <br><br> _Only available in GNOME Shell 40+_ | <img src ="docs/pics/snap.gif" />
|
||||
**T-Rex Attack** <br> Destroy your windows with a series of violent slashes! <br><br> _Only available in GNOME Shell 40+_ | <img src ="docs/pics/trex.gif" />
|
||||
**Matrix** <br> Turn your windows into a shower of green letters! The color is actually configurable.| <img src ="docs/pics/matrix.gif" />
|
||||
**Snap of Disintegration** <br> Dissolve your windows into a cloud of dust.| <img src ="docs/pics/snap.gif" />
|
||||
**T-Rex Attack** <br> Destroy your windows with a series of violent slashes!| <img src ="docs/pics/trex.gif" />
|
||||
**TV-Effect** <br> This is a very simple effect to demonstrate that this extension could also be used in a more professional environment. | <img src ="docs/pics/tv.gif" />
|
||||
**Wisps** <br> Let your windows be carried away to the realm of dreams by these little fairies! | <img src ="docs/pics/wisps.gif" />
|
||||
**Your Effect!** <br> 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). | [](docs/how-to-create-new-effects.md)
|
||||
|
||||
## ✅ Supported Versions
|
||||
|
||||
Not every effect is available on each version of GNOME or KWin.
|
||||
Below is a table which summarizes the current availability for all effects.
|
||||
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td colspan="5"><strong>GNOME</strong></td>
|
||||
<td colspan="1"><strong>KWin</strong></td>
|
||||
</tr>
|
||||
<tr><td></td> <td>3.36</td><td>3.38</td><td>40</td><td>41</td><td>42</td><td>5.25</td></tr>
|
||||
<tr><td>Apparition</td> <td> </td> <td>✅</td> <td>✅</td><td>✅</td><td>✅</td><td> </td></tr>
|
||||
<tr><td>Broken Glass</td> <td> </td> <td> </td> <td>✅</td><td>✅</td><td>✅</td><td> </td></tr>
|
||||
<tr><td>Energize A</td> <td>✅</td> <td>✅</td> <td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
||||
<tr><td>Energize B</td> <td>✅</td> <td>✅</td> <td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
||||
<tr><td>Fire</td> <td>✅</td> <td>✅</td> <td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
||||
<tr><td>Hexagon</td> <td>✅</td> <td>✅</td> <td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
||||
<tr><td>Matrix</td> <td> </td> <td> </td> <td>✅</td><td>✅</td><td>✅</td><td> </td></tr>
|
||||
<tr><td>Snap of Disintegration</td> <td> </td> <td> </td> <td>✅</td><td>✅</td><td>✅</td><td> </td></tr>
|
||||
<tr><td>T-Rex Attack</td> <td> </td> <td> </td> <td>✅</td><td>✅</td><td>✅</td><td> </td></tr>
|
||||
<tr><td>TV-Effect</td> <td>✅</td> <td>✅</td> <td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
||||
<tr><td>Wisps</td> <td>✅</td> <td>✅</td> <td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
## 💞 These People _love_ this Extension
|
||||
|
||||
@@ -68,9 +94,9 @@ While [coding new features](docs/how-to-create-new-effects.md) or [translating t
|
||||
|
||||
|
||||
Do you want to show that you love it too? You may <a href="https://github.com/sponsors/Schneegans">become a sponsor for as little as 1$ / month</a>!
|
||||
If you like this extension, you may also want to try one of my other extensions: [🧊 Desktop-Cube](https://github.com/Schneegans/Desktop-Cube) or [🍰 Fly-Pie](https://github.com/Schneegans/Fly-Pie/)!
|
||||
If you like this extension, you may also want to try one of my other GNOME extensions: [🧊 Desktop-Cube](https://github.com/Schneegans/Desktop-Cube) or [🍰 Fly-Pie](https://github.com/Schneegans/Fly-Pie/)!
|
||||
|
||||
## ⬇️ Installation
|
||||
## ⬇️ Installation (GNOME)
|
||||
|
||||
You can either install the Burn-My-Windows extension from extensions.gnome.org (a), download a stable release
|
||||
from GitHub (b) or clone the latest version directly with `git` (c).
|
||||
@@ -129,6 +155,50 @@ Then you can enable the extension with the *Gnome Tweak Tool*, the *Extensions*
|
||||
gnome-extensions enable burn-my-windows@schneegans.github.com
|
||||
```
|
||||
|
||||
## ⬇️ Installation (KWin)
|
||||
|
||||
|
||||
You can either download a stable version from GitHub (a) or clone the latest version directly with `git` (b).
|
||||
|
||||
### a) Downloading a Stable Release
|
||||
|
||||
Execute this command to download the latest stable release:
|
||||
|
||||
```bash
|
||||
wget https://github.com/Schneegans/Burn-My-Windows/releases/latest/download/burn_my_windows_kwin4.tar.gz
|
||||
```
|
||||
|
||||
Install it by executing the following commands.
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.local/share/kwin/effects
|
||||
tar -xf burn_my_windows_kwin4.tar.gz -C ~/.local/share/kwin/effects
|
||||
```
|
||||
|
||||
Then select the desired effects in the system settings under "Desktop Effects".
|
||||
|
||||
|
||||
### b) Cloning the Latest Version with `git`
|
||||
|
||||
Execute the clone command below where you want to have the source code of the extension.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Schneegans/Burn-My-Windows.git
|
||||
cd Burn-My-Windows
|
||||
```
|
||||
|
||||
Now you will have to build the effects and copy them to your KWin effect directory.
|
||||
|
||||
```bash
|
||||
./kwin/build.sh
|
||||
mkdir -p ~/.local/share/kwin/effects
|
||||
cp -r kwin/_build/* ~/.local/share/kwin/effects
|
||||
```
|
||||
|
||||
That's it!
|
||||
You can now select the desired effects in the system settings under "Desktop Effects".
|
||||
|
||||
|
||||
## :octocat: I want to contribute!
|
||||
|
||||
That's great!
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#### New Features
|
||||
|
||||
* **Initial KDE Support.** Thanks to the [awesome work](https://invent.kde.org/plasma/kwin/-/merge_requests/2227) of Martin Flöser, it has become possible to port some of its effects to KDE Plasma! For now, only the most simple effects can be ported, but hopefully this list can be improved in the future.
|
||||
* An option has been added which allows to automatically disable all effects if running on battery power.
|
||||
|
||||
#### Enhancements
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
The extension is very modular and with a bit of creativity and GLSL knowledge, you can easily create your own effects.
|
||||
If you are happy with your results, please open a pull request so that we can include your effect in the next version of Burn-My-Windows!
|
||||
|
||||
_:warning: For now, this guide is only for GNOME Shell (and not for KWin). As soon as the API for KWin is more stable, this guide will be updated._
|
||||
|
||||
### Before you Start
|
||||
|
||||
First you should [fork the repository](https://github.com/Schneegans/Burn-My-Windows/fork) and clone it to your PC.
|
||||
@@ -86,28 +88,31 @@ Please study this code carefully, all of it is explained with inline comments.
|
||||
|
||||
```glsl
|
||||
// The content from common.glsl is automatically prepended to each shader effect. This
|
||||
// provides some standard uniforms which will be updated during the animation.
|
||||
// bool uForOpening: True if a window-open animation is ongoing, false otherwise.
|
||||
// sampler2D uTexture: Contains the texture of the window.
|
||||
// float uProgress: A value which transitions from 0 to 1 during the entire animation.
|
||||
// float uTime: A steadily increasing value in seconds.
|
||||
// vec2 uSize: The size of uTexture in pixels.
|
||||
// float uPadding: The empty area around the actual window (e.g. where the shadow is drawn).
|
||||
// provides the standard input:
|
||||
|
||||
// vec2 iTexCoord: Texture coordinates for retrieving the window input color.
|
||||
// bool uForOpening: True if a window-open animation is ongoing, false otherwise.
|
||||
// float uProgress: A value which transitions from 0 to 1 during the animation.
|
||||
// float uDuration: The duration of the current animation in seconds.
|
||||
// vec2 uSize: The size of uTexture in pixels.
|
||||
// float uPadding: The empty area around the actual window (e.g. where the shadow
|
||||
// is drawn). For now, this will only be set on GNOME.
|
||||
|
||||
// Furthermore, there are two global methods for reading the window input color and
|
||||
// setting the shader output color. Both methods assume straight alpha:
|
||||
|
||||
// vec4 getInputColor(vec2 coords)
|
||||
// void setOutputColor(vec4 outColor)
|
||||
|
||||
// The width of the fading effect is loaded from the settings.
|
||||
uniform float uFadeWidth;
|
||||
|
||||
void main() {
|
||||
// Get the color from the window texture.
|
||||
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
vec4 oColor = getInputColor(iTexCoord.st);
|
||||
|
||||
// Radial distance from window edge to the window's center.
|
||||
float dist = length(cogl_tex_coord_in[0].st - 0.5) * 2.0 / sqrt(2.0);
|
||||
float dist = length(iTexCoord.st - 0.5) * 2.0 / sqrt(2.0);
|
||||
|
||||
// This gradually dissolves from [1..0] from the outside to the center. We
|
||||
// switch the direction for opening and closing.
|
||||
@@ -118,7 +123,9 @@ void main() {
|
||||
mask = smoothstep(0, 1, mask);
|
||||
|
||||
// Apply the mask to the output.
|
||||
cogl_color_out.a *= mask;
|
||||
oColor.a *= mask;
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+3
-3
@@ -502,14 +502,14 @@ class Extension {
|
||||
actor.add_effect_with_name('burn-my-windows-effect', shader);
|
||||
|
||||
// Set one-time uniforms.
|
||||
shader.beginAnimation(this._settings, forOpening, actor);
|
||||
shader.beginAnimation(this._settings, forOpening, duration * 0.001, actor);
|
||||
|
||||
// Set other uniforms each frame.
|
||||
transition.connect('new-frame', (t) => {
|
||||
if (testMode) {
|
||||
shader.updateAnimation(0.5, 0.001 * duration * 0.5);
|
||||
shader.updateAnimation(0.5);
|
||||
} else {
|
||||
shader.updateAnimation(t.get_progress(), 0.001 * t.get_elapsed_time());
|
||||
shader.updateAnimation(t.get_progress());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BMWConfigForm</class>
|
||||
<widget class="QWidget" name="BMWConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Randomness">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_Duration">
|
||||
<property name="suffix">
|
||||
<string> milliseconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Suction:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Twirl:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Randomness:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Shake:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Suction">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Twirl">
|
||||
<property name="minimum">
|
||||
<double>-10.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Shake">
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources />
|
||||
<connections />
|
||||
</ui>
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="" />
|
||||
<group name="">
|
||||
<entry name="Duration" type="UInt">
|
||||
<default>300</default>
|
||||
</entry>
|
||||
<entry name="Shake" type="Double">
|
||||
<default>3</default>
|
||||
</entry>
|
||||
<entry name="Twirl" type="Double">
|
||||
<default>5</default>
|
||||
</entry>
|
||||
<entry name="Suction" type="Double">
|
||||
<default>0.75</default>
|
||||
</entry>
|
||||
<entry name="Randomness" type="Double">
|
||||
<default>0.5</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,4 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever a window is closed or opened.
|
||||
|
||||
effect.setUniform(this.shader, 'uSeed', [Math.random(), Math.random()]);
|
||||
@@ -0,0 +1,8 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever the user changes something in the configuration of
|
||||
// the effect.
|
||||
|
||||
effect.setUniform(this.shader, 'uShake', effect.readConfig('Shake', 1.0));
|
||||
effect.setUniform(this.shader, 'uTwirl', effect.readConfig('Twirl', 1.0));
|
||||
effect.setUniform(this.shader, 'uSuction', effect.readConfig('Suction', 1.0));
|
||||
effect.setUniform(this.shader, 'uRandomness', effect.readConfig('Randomness', 1.0));
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
# ) ( #
|
||||
# ( /( ( ( ) ( ( ( ( )\ ) ( ( #
|
||||
# )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( #
|
||||
# ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ #
|
||||
# | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) #
|
||||
# | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< #
|
||||
# |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ #
|
||||
# |__/ #
|
||||
# Copyright (c) 2021 Simon Schneegans #
|
||||
# Released under the GPLv3 or later. See LICENSE file for details. #
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
# This scripts takes the shaders of Burn-My-Windows as well as some other input files from
|
||||
# the directories next to this script and creates effect for KDE's Kwin.
|
||||
|
||||
# Exit the script when one command fails.
|
||||
set -e
|
||||
|
||||
# Go to the script's directory.
|
||||
cd "$( cd "$( dirname "$0" )" && pwd )" || \
|
||||
{ echo "ERROR: Could not find kwin directory."; exit 1; }
|
||||
|
||||
# We will store the effect directories in this directory.
|
||||
BUILD_DIR="_build"
|
||||
|
||||
# Create it if it's not there yet.
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
# This method is called one for each effect. The parameters are as follows:
|
||||
# $1: The nick of the effect (e.g. "energize-a")
|
||||
# $2: The name of the effect (e.g. "Energize A")
|
||||
# $3: A short description of the effect (e.g. "Beam your windows away")
|
||||
generate() {
|
||||
|
||||
# We use the nick for the effect's directory name by replacing dashes with underscoares.
|
||||
DIR_NAME="kwin4_effect_$(echo "$1" | tr '-' '_')"
|
||||
|
||||
# We transform the nick to CamelCase for the JavaScript class name.
|
||||
EFFECT_CLASS="BurnMyWindows$(sed -r 's/(^|-)(\w)/\U\2/g' <<<"$1")Effect"
|
||||
|
||||
# Now create all required resource directories.
|
||||
mkdir -p "$BUILD_DIR/$DIR_NAME/contents/shaders"
|
||||
mkdir -p "$BUILD_DIR/$DIR_NAME/contents/code"
|
||||
mkdir -p "$BUILD_DIR/$DIR_NAME/contents/config"
|
||||
mkdir -p "$BUILD_DIR/$DIR_NAME/contents/ui"
|
||||
|
||||
# Copy the config file if it exists.
|
||||
if [ -f "$1/main.xml" ]; then
|
||||
cp "$1/main.xml" "$BUILD_DIR/$DIR_NAME/contents/config"
|
||||
fi
|
||||
|
||||
# Copy the ui file if it exists.
|
||||
if [ -f "$1/config.ui" ]; then
|
||||
cp "$1/config.ui" "$BUILD_DIR/$DIR_NAME/contents/ui"
|
||||
fi
|
||||
|
||||
# Now we create the effect's JavaScript source file. This is done by taking main.js.in
|
||||
# and replacing some placeholders with effect-specific files and values.
|
||||
ON_SETTINGS_CHANGE=""
|
||||
ON_ANIMATION_BEGIN=""
|
||||
|
||||
# If the effect's directory contains a onSettingsChanged.js, we replace the
|
||||
# corresponding placeholder with it's content. We replace all occurences of / temporily
|
||||
# so that the REGEX works.
|
||||
if [ -f "$1/onSettingsChanged.js" ]; then
|
||||
ON_SETTINGS_CHANGE=$(tr '/' '\f' < "$1/onSettingsChanged.js")
|
||||
fi
|
||||
|
||||
# Similarily, we will inject the contents of onAnimationBegin.js.
|
||||
if [ -f "$1/onAnimationBegin.js" ]; then
|
||||
ON_ANIMATION_BEGIN=$(tr '/' '\f' < "$1/onAnimationBegin.js")
|
||||
fi
|
||||
|
||||
cp main.js.in "$BUILD_DIR/$DIR_NAME/contents/code/main.js"
|
||||
perl -pi -e "s/%ON_SETTINGS_CHANGE%/$ON_SETTINGS_CHANGE/g;" "$BUILD_DIR/$DIR_NAME/contents/code/main.js"
|
||||
perl -pi -e "s/%ON_ANIMATION_BEGIN%/$ON_ANIMATION_BEGIN/g;" "$BUILD_DIR/$DIR_NAME/contents/code/main.js"
|
||||
perl -pi -e "s/%EFFECT_CLASS%/$EFFECT_CLASS/g;" "$BUILD_DIR/$DIR_NAME/contents/code/main.js"
|
||||
perl -pi -e "s/%SHADER_NAME%/$1/g;" "$BUILD_DIR/$DIR_NAME/contents/code/main.js"
|
||||
perl -pi -e "s/\f/\//g;" "$BUILD_DIR/$DIR_NAME/contents/code/main.js"
|
||||
|
||||
# Now create the metadata.desktop file. Again, we replace some placeholders.
|
||||
cp metadata.desktop.in "$BUILD_DIR/$DIR_NAME/metadata.desktop"
|
||||
perl -pi -e "s/%ICON%/$1/g;" "$BUILD_DIR/$DIR_NAME/metadata.desktop"
|
||||
perl -pi -e "s/%NAME%/$2/g;" "$BUILD_DIR/$DIR_NAME/metadata.desktop"
|
||||
perl -pi -e "s/%DESCRIPTION%/$3/g;" "$BUILD_DIR/$DIR_NAME/metadata.desktop"
|
||||
perl -pi -e "s/%DIR_NAME%/$DIR_NAME/g;" "$BUILD_DIR/$DIR_NAME/metadata.desktop"
|
||||
|
||||
# Now create the two required shader files. We prepend the common.glsl to each shader.
|
||||
# We also define KWIN and KWIN_LEGACY. The code in common.glsl takes some different
|
||||
# paths based on these defines.
|
||||
{
|
||||
echo "#version 140"
|
||||
echo "#define KWIN"
|
||||
echo ""
|
||||
echo "// This file is automatically generated during the build process."
|
||||
echo ""
|
||||
cat "../resources/shaders/common.glsl"
|
||||
cat "../resources/shaders/$1.frag"
|
||||
} > "$BUILD_DIR/$DIR_NAME/contents/shaders/$1_core.frag"
|
||||
|
||||
{
|
||||
echo "#define KWIN_LEGACY"
|
||||
echo ""
|
||||
echo "// This file is automatically generated during the build process."
|
||||
echo ""
|
||||
cat "../resources/shaders/common.glsl"
|
||||
cat "../resources/shaders/$1.frag"
|
||||
} > "$BUILD_DIR/$DIR_NAME/contents/shaders/$1.frag"
|
||||
|
||||
# If clang-format is installed, try to beauty the code a bit.
|
||||
if command -v clang-format &> /dev/null
|
||||
then
|
||||
clang-format -i "$BUILD_DIR/$DIR_NAME/contents/code/main.js"
|
||||
fi
|
||||
}
|
||||
|
||||
# Now run the above method for all supported effects.
|
||||
|
||||
# The apparition effect is disabled for now. I have not yet found a way to upscale the
|
||||
# window canvas during the animation.
|
||||
#generate "apparition" "[BMW] Apparition" "This effect hides your windows by violently sucking them into the void of magic"
|
||||
|
||||
generate "energize-a" "[BMW] Energize A" "Beam your windows away"
|
||||
generate "energize-b" "[BMW] Energize B" "Using different transporter technology results in an alternative visual effect"
|
||||
generate "fire" "[BMW] Fire" "The classic effect inspired by Compiz"
|
||||
generate "hexagon" "[BMW] Hexagon" "With glowing lines and hexagon-shaped tiles, this effect looks very sci-fi"
|
||||
generate "tv" "[BMW] TV Effect" "Make windows close like turning off a TV"
|
||||
generate "wisps" "[BMW] Wisps" "Let your windows be carried away to the realm of dreams by these little fairies"
|
||||
|
||||
# Finally, create an archive for the effects.
|
||||
# shellcheck disable=SC2046
|
||||
tar -cjf "burn_my_windows_kwin4.tar.gz" -C "$BUILD_DIR" $(ls "$BUILD_DIR")
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BMWConfigForm</class>
|
||||
<widget class="QWidget" name="BMWConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_Color</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="KColorButton" name="kcfg_Color">
|
||||
<property name="alphaChannelEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Scale:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_Color</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Scale">
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_Duration">
|
||||
<property name="suffix">
|
||||
<string> milliseconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources />
|
||||
<connections />
|
||||
</ui>
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="" />
|
||||
<group name="">
|
||||
<entry name="Duration" type="UInt">
|
||||
<default>2000</default>
|
||||
</entry>
|
||||
<entry name="Scale" type="Double">
|
||||
<default>1</default>
|
||||
</entry>
|
||||
<entry name="Color" type="Color">
|
||||
<default>#FFC832</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,7 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever the user changes something in the configuration of
|
||||
// the effect.
|
||||
|
||||
effect.setUniform(this.shader, 'uDuration', this.duration * 0.001);
|
||||
effect.setUniform(this.shader, 'uColor', this.readRGBConfig('Color'));
|
||||
effect.setUniform(this.shader, 'uScale', effect.readConfig('Scale', 1.0));
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BMWConfigForm</class>
|
||||
<widget class="QWidget" name="BMWConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_Color</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="KColorButton" name="kcfg_Color">
|
||||
<property name="alphaChannelEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Scale:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_Color</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Scale">
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_Duration">
|
||||
<property name="suffix">
|
||||
<string> milliseconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources />
|
||||
<connections />
|
||||
</ui>
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="" />
|
||||
<group name="">
|
||||
<entry name="Duration" type="UInt">
|
||||
<default>1000</default>
|
||||
</entry>
|
||||
<entry name="Scale" type="Double">
|
||||
<default>1</default>
|
||||
</entry>
|
||||
<entry name="Color" type="Color">
|
||||
<default>#A0B4FF</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,7 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever the user changes something in the configuration of
|
||||
// the effect.
|
||||
|
||||
effect.setUniform(this.shader, 'uDuration', this.duration * 0.001);
|
||||
effect.setUniform(this.shader, 'uColor', this.readRGBConfig('Color'));
|
||||
effect.setUniform(this.shader, 'uScale', effect.readConfig('Scale', 1.0));
|
||||
Executable
+132
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BMWConfigForm</class>
|
||||
<widget class="QWidget" name="BMWConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Line Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_LineWidth">
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Scale">
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_Duration">
|
||||
<property name="suffix">
|
||||
<string> milliseconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Glow Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Line Width:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Scale:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="kcfg_AdditiveBlending">
|
||||
<property name="text">
|
||||
<string>Additive Blending</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="KColorButton" name="kcfg_GlowColor">
|
||||
<property name="alphaChannelEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="KColorButton" name="kcfg_LineColor">
|
||||
<property name="alphaChannelEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources />
|
||||
<connections />
|
||||
</ui>
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="" />
|
||||
<group name="">
|
||||
<entry name="Duration" type="UInt">
|
||||
<default>1500</default>
|
||||
</entry>
|
||||
<entry name="Scale" type="Double">
|
||||
<default>1</default>
|
||||
</entry>
|
||||
<entry name="MovementSpeed" type="Double">
|
||||
<default>0.5</default>
|
||||
</entry>
|
||||
<entry name="Gradient1" type="Color">
|
||||
<default>#004c3319</default>
|
||||
</entry>
|
||||
<entry name="Gradient2" type="Color">
|
||||
<default>#a0b4371e</default>
|
||||
</entry>
|
||||
<entry name="Gradient3" type="Color">
|
||||
<default>#b5ff4c26</default>
|
||||
</entry>
|
||||
<entry name="Gradient4" type="Color">
|
||||
<default>#ffffa619</default>
|
||||
</entry>
|
||||
<entry name="Gradient5" type="Color">
|
||||
<default>#ffffffff</default>
|
||||
</entry>
|
||||
<entry name="3DNoise" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,14 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever the user changes something in the configuration of
|
||||
// the effect.
|
||||
|
||||
effect.setUniform(this.shader, 'uDuration', this.duration * 0.001);
|
||||
effect.setUniform(this.shader, 'u3DNoise',
|
||||
effect.readConfig('3DNoise', true) ? 1.0 : 0.0);
|
||||
effect.setUniform(this.shader, 'uScale', effect.readConfig('Scale', 1.0));
|
||||
effect.setUniform(this.shader, 'uMovementSpeed', effect.readConfig('MovementSpeed', 1.0));
|
||||
effect.setUniform(this.shader, 'uGradient1', this.readRGBAConfig('Gradient1'));
|
||||
effect.setUniform(this.shader, 'uGradient2', this.readRGBAConfig('Gradient2'));
|
||||
effect.setUniform(this.shader, 'uGradient3', this.readRGBAConfig('Gradient3'));
|
||||
effect.setUniform(this.shader, 'uGradient4', this.readRGBAConfig('Gradient4'));
|
||||
effect.setUniform(this.shader, 'uGradient5', this.readRGBAConfig('Gradient5'));
|
||||
Executable
+132
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BMWConfigForm</class>
|
||||
<widget class="QWidget" name="BMWConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Line Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_LineWidth">
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Scale">
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_Duration">
|
||||
<property name="suffix">
|
||||
<string> milliseconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Glow Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Line Width:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Scale:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="kcfg_AdditiveBlending">
|
||||
<property name="text">
|
||||
<string>Additive Blending</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="KColorButton" name="kcfg_GlowColor">
|
||||
<property name="alphaChannelEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="KColorButton" name="kcfg_LineColor">
|
||||
<property name="alphaChannelEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources />
|
||||
<connections />
|
||||
</ui>
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="" />
|
||||
<group name="">
|
||||
<entry name="Duration" type="UInt">
|
||||
<default>1500</default>
|
||||
</entry>
|
||||
<entry name="Scale" type="Double">
|
||||
<default>3</default>
|
||||
</entry>
|
||||
<entry name="LineWidth" type="Double">
|
||||
<default>2</default>
|
||||
</entry>
|
||||
<entry name="LineColor" type="Color">
|
||||
<default>#80C8FFFF</default>
|
||||
</entry>
|
||||
<entry name="GlowColor" type="Color">
|
||||
<default>#801450FF</default>
|
||||
</entry>
|
||||
<entry name="AdditiveBlending" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,4 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever a window is closed or opened.
|
||||
|
||||
effect.setUniform(this.shader, 'uSeed', [Math.random(), Math.random()]);
|
||||
@@ -0,0 +1,10 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever the user changes something in the configuration of
|
||||
// the effect.
|
||||
|
||||
effect.setUniform(this.shader, 'uAdditiveBlending',
|
||||
effect.readConfig('AdditiveBlending', true) ? 1.0 : 0.0);
|
||||
effect.setUniform(this.shader, 'uScale', effect.readConfig('Scale', 1.0));
|
||||
effect.setUniform(this.shader, 'uLineWidth', effect.readConfig('LineWidth', 1.0));
|
||||
effect.setUniform(this.shader, 'uGlowColor', this.readRGBAConfig('GlowColor'));
|
||||
effect.setUniform(this.shader, 'uLineColor', this.readRGBAConfig('LineColor'));
|
||||
Executable
+202
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
This file is part of the Burn-My-Windows project.
|
||||
|
||||
SPDX-FileCopyrightText: 2018, 2021, 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>, Martin Flöser <mgraesslin@kde.org>, Simon Schneegans <code@simonschneegans.de>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const blacklist = [
|
||||
// The logout screen has to be animated only by the logout effect.
|
||||
"ksmserver ksmserver",
|
||||
"ksmserver-logout-greeter ksmserver-logout-greeter",
|
||||
|
||||
// KDE Plasma splash screen has to be animated only by the login effect.
|
||||
"ksplashqml ksplashqml"
|
||||
];
|
||||
|
||||
class %EFFECT_CLASS% {
|
||||
constructor() {
|
||||
effect.configChanged.connect(this.loadConfig.bind(this));
|
||||
effect.animationEnded.connect(this.cleanupForcedRoles.bind(this));
|
||||
effects.windowAdded.connect(this.slotWindowAdded.bind(this));
|
||||
effects.windowClosed.connect(this.slotWindowClosed.bind(this));
|
||||
effects.windowDataChanged.connect(this.slotWindowDataChanged.bind(this));
|
||||
|
||||
this.shader = effect.addFragmentShader(Effect.MapTexture, "%SHADER_NAME%.frag");
|
||||
|
||||
this.loadConfig();
|
||||
}
|
||||
|
||||
// A small helper which can be used to read a hex color string (e.g. #ff3244) from the
|
||||
// settings. This method will return an array of four floating point values
|
||||
// [r, g, b, a]. If the settings key only refers to an rgb value, the alpha component
|
||||
// will be set to 1.0.
|
||||
readRGBAConfig(key) {
|
||||
const color = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?([a-f\d]{2})?$/i
|
||||
.exec(effect.readConfig(key, '#ffffff'))
|
||||
.slice(1)
|
||||
.filter(x => x !== undefined)
|
||||
.map(x => parseInt(x, 16) / 255);
|
||||
return color.length == 3 ? [color[0], color[1], color[2], 1.0] :
|
||||
[color[1], color[2], color[3], color[0]];
|
||||
}
|
||||
|
||||
// A small helper which can be used to read a hex color string (e.g. #ff3244) from the
|
||||
// settings. This method will return an array of three floating point values [r, g, b]
|
||||
// regardless of whether the settings key actually refers to an argb hex string.
|
||||
readRGBConfig(key) {
|
||||
const color = this.readRGBAConfig(key);
|
||||
color.pop();
|
||||
return color;
|
||||
}
|
||||
|
||||
loadConfig() {
|
||||
this.duration = animationTime(effect.readConfig('Duration', 1000));
|
||||
|
||||
%ON_SETTINGS_CHANGE%
|
||||
}
|
||||
|
||||
static isScaleWindow(window) {
|
||||
// We don't want to animate most of plasmashell's windows, yet, some
|
||||
// of them we want to, for example, Task Manager Settings window.
|
||||
// The problem is that all those window share single window class.
|
||||
// So, the only way to decide whether a window should be animated is
|
||||
// to use a heuristic: if a window has decoration, then it's most
|
||||
// likely a dialog or a settings window so we have to animate it.
|
||||
if (window.windowClass == "plasmashell plasmashell"
|
||||
|| window.windowClass == "plasmashell org.kde.plasmashell") {
|
||||
return window.hasDecoration;
|
||||
}
|
||||
|
||||
if (blacklist.indexOf(window.windowClass) != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (window.hasDecoration) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't animate combobox popups, tooltips, popup menus, etc.
|
||||
if (window.popupWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dont't animate the outline and the screenlocker as it looks bad.
|
||||
if (window.lockScreen || window.outline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Override-redirect windows are usually used for user interface
|
||||
// concepts that are not expected to be animated by this effect.
|
||||
if (!window.managed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return window.normalWindow || window.dialog;
|
||||
}
|
||||
|
||||
setupForcedRoles(window) {
|
||||
window.setData(Effect.WindowForceBackgroundContrastRole, true);
|
||||
window.setData(Effect.WindowForceBlurRole, true);
|
||||
}
|
||||
|
||||
cleanupForcedRoles(window) {
|
||||
window.setData(Effect.WindowForceBackgroundContrastRole, null);
|
||||
window.setData(Effect.WindowForceBlurRole, null);
|
||||
}
|
||||
|
||||
slotWindowAdded(window) {
|
||||
if (effects.hasActiveFullScreenEffect) {
|
||||
return;
|
||||
}
|
||||
if (!%EFFECT_CLASS%.isScaleWindow(window)) {
|
||||
return;
|
||||
}
|
||||
if (!window.visible) {
|
||||
return;
|
||||
}
|
||||
if (effect.isGrabbed(window, Effect.WindowAddedGrabRole)) {
|
||||
return;
|
||||
}
|
||||
this.setupForcedRoles(window);
|
||||
|
||||
effect.setUniform(this.shader, 'uForOpening', 1.0);
|
||||
|
||||
%ON_ANIMATION_BEGIN%
|
||||
|
||||
window.scaleInAnimation = animate({
|
||||
window: window,
|
||||
curve: QEasingCurve.Linear,
|
||||
duration: this.duration,
|
||||
animations: [
|
||||
{
|
||||
type: Effect.ShaderUniform,
|
||||
fragmentShader: this.shader,
|
||||
uniform: "uProgress",
|
||||
from: 0.0,
|
||||
to: 1.0
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
slotWindowClosed(window) {
|
||||
if (effects.hasActiveFullScreenEffect) {
|
||||
return;
|
||||
}
|
||||
if (!%EFFECT_CLASS%.isScaleWindow(window)) {
|
||||
return;
|
||||
}
|
||||
if (!window.visible || window.skipsCloseAnimation) {
|
||||
return;
|
||||
}
|
||||
if (effect.isGrabbed(window, Effect.WindowClosedGrabRole)) {
|
||||
return;
|
||||
}
|
||||
if (window.scaleInAnimation) {
|
||||
cancel(window.scaleInAnimation);
|
||||
delete window.scaleInAnimation;
|
||||
}
|
||||
this.setupForcedRoles(window);
|
||||
|
||||
effect.setUniform(this.shader, 'uForOpening', 0.0);
|
||||
|
||||
%ON_ANIMATION_BEGIN%
|
||||
|
||||
window.scaleOutAnimation = animate({
|
||||
window: window,
|
||||
curve: QEasingCurve.Linear,
|
||||
duration: this.duration,
|
||||
animations: [
|
||||
{
|
||||
type: Effect.ShaderUniform,
|
||||
fragmentShader: this.shader,
|
||||
uniform: "uProgress",
|
||||
from: 0.0,
|
||||
to: 1.0
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
slotWindowDataChanged(window, role) {
|
||||
if (role == Effect.WindowAddedGrabRole) {
|
||||
if (window.scaleInAnimation && effect.isGrabbed(window, role)) {
|
||||
cancel(window.scaleInAnimation);
|
||||
delete window.scaleInAnimation;
|
||||
this.cleanupForcedRoles(window);
|
||||
}
|
||||
} else if (role == Effect.WindowClosedGrabRole) {
|
||||
if (window.scaleOutAnimation && effect.isGrabbed(window, role)) {
|
||||
cancel(window.scaleOutAnimation);
|
||||
delete window.scaleOutAnimation;
|
||||
this.cleanupForcedRoles(window);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new %EFFECT_CLASS%();
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
[Desktop Entry]
|
||||
Name=%NAME%
|
||||
Icon=preferences-system-windows-effect-%ICON%
|
||||
Comment=%DESCRIPTION%
|
||||
|
||||
Type=Service
|
||||
X-KDE-ServiceTypes=KWin/Effect,KCModule
|
||||
X-KDE-PluginInfo-Author=Vlad Zahorodnii, Martin Flöser, Simon Schneegans
|
||||
X-KDE-PluginInfo-Email=vlad.zahorodnii@kde.org, mgraesslin@kde.org, code@simonschneegans.de
|
||||
X-KDE-PluginInfo-Name=%DIR_NAME%
|
||||
X-KDE-PluginInfo-Version=1
|
||||
X-KDE-PluginInfo-Category=Window Open/Close Animation
|
||||
X-KDE-PluginInfo-License=GPLv3
|
||||
X-KDE-PluginInfo-EnabledByDefault=false
|
||||
X-KDE-Ordering=60
|
||||
X-Plasma-API=javascript
|
||||
X-Plasma-MainScript=code/main.js
|
||||
X-KDE-PluginKeyword=%DIR_NAME%
|
||||
X-KDE-Library=kcm_kwin4_genericscripted
|
||||
X-KWin-Config-TranslationDomain=kwin_effects
|
||||
X-KWin-Exclusive-Category=toplevel-open-close-animation
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BMWConfigForm</class>
|
||||
<widget class="QWidget" name="BMWConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_Duration">
|
||||
<property name="suffix">
|
||||
<string> milliseconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="KColorButton" name="kcfg_Color">
|
||||
<property name="alphaChannelEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>kcfg_Color</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources />
|
||||
<connections />
|
||||
</ui>
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="" />
|
||||
<group name="">
|
||||
<entry name="Duration" type="UInt">
|
||||
<default>400</default>
|
||||
</entry>
|
||||
<entry name="Color" type="Color">
|
||||
<default>#ffffff</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,5 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever the user changes something in the configuration of
|
||||
// the effect.
|
||||
|
||||
effect.setUniform(this.shader, 'uColor', this.readRGBConfig('Color'));
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BMWConfigForm</class>
|
||||
<widget class="QWidget" name="BMWConfigForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>562</width>
|
||||
<height>365</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="kcfg_Scale">
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="kcfg_Duration">
|
||||
<property name="suffix">
|
||||
<string> milliseconds</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Color:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Duration:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Scale:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="KColorButton" name="kcfg_Color"></widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>KColorButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>kcolorbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources />
|
||||
<connections />
|
||||
</ui>
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
|
||||
<kcfgfile name="" />
|
||||
<group name="">
|
||||
<entry name="Duration" type="UInt">
|
||||
<default>1500</default>
|
||||
</entry>
|
||||
<entry name="Scale" type="Double">
|
||||
<default>1</default>
|
||||
</entry>
|
||||
<entry name="Color" type="Color">
|
||||
<default>#ff64c8</default>
|
||||
</entry>
|
||||
</group>
|
||||
</kcfg>
|
||||
@@ -0,0 +1,4 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever a window is closed or opened.
|
||||
|
||||
effect.setUniform(this.shader, 'uSeed', [Math.random(), Math.random()]);
|
||||
@@ -0,0 +1,7 @@
|
||||
// This part is automatically included in the effect's source during the build process.
|
||||
// The code below is called whenever the user changes something in the configuration of
|
||||
// the effect.
|
||||
|
||||
effect.setUniform(this.shader, 'uDuration', this.duration * 0.001);
|
||||
effect.setUniform(this.shader, 'uScale', effect.readConfig('Scale', 1.0));
|
||||
effect.setUniform(this.shader, 'uColor', this.readRGBConfig('Color'));
|
||||
@@ -30,7 +30,7 @@ void main() {
|
||||
|
||||
// Choose a random suction center.
|
||||
vec2 center = uSeed * uRandomness + 0.5 * (1.0 - uRandomness);
|
||||
vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING - center;
|
||||
vec2 coords = iTexCoord.st * ACTOR_SCALE - PADDING - center;
|
||||
|
||||
// Add some shaking.
|
||||
coords.x +=
|
||||
@@ -39,7 +39,7 @@ void main() {
|
||||
progress * 0.05 * uShake * cos((progress + uSeed.y) * (1.0 + uSeed.y) * uShake);
|
||||
|
||||
// "Suck" the texture into the center.
|
||||
float dist = length(coords) / sqrt(2);
|
||||
float dist = length(coords) / sqrt(2.0);
|
||||
coords += progress * coords / dist * 0.5 * uSuction;
|
||||
|
||||
// Apply some whirling.
|
||||
@@ -48,12 +48,8 @@ void main() {
|
||||
float c = cos(angle);
|
||||
coords = vec2(dot(coords, vec2(c, -s)), dot(coords, vec2(s, c)));
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
cogl_color_out = texture2D(uTexture, coords + center);
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
|
||||
// Fade out the window texture.
|
||||
cogl_color_out.a *= 1.0 - progress;
|
||||
vec4 oColor = getInputColor(coords + center);
|
||||
oColor.a *= 1.0 - progress;
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
@@ -20,12 +20,12 @@ uniform float uShardScale;
|
||||
uniform float uBlowForce;
|
||||
uniform float uGravity;
|
||||
|
||||
const float SHARD_LAYERS = 5;
|
||||
const float SHARD_LAYERS = 5.0;
|
||||
const float ACTOR_SCALE = 2.0;
|
||||
const float PADDING = ACTOR_SCALE / 2.0 - 0.5;
|
||||
|
||||
void main() {
|
||||
cogl_color_out = vec4(0, 0, 0, 0);
|
||||
vec4 oColor = vec4(0.0);
|
||||
|
||||
float progress = uForOpening ? 1.0 - uProgress : uProgress;
|
||||
|
||||
@@ -35,13 +35,13 @@ void main() {
|
||||
// To enable drawing shards outside of the window bounds, the actor was scaled
|
||||
// by ACTOR_SCALE. Here we scale and move the texture coordinates so that the
|
||||
// window gets drawn at the correct position again.
|
||||
vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING;
|
||||
vec2 coords = iTexCoord.st * ACTOR_SCALE - PADDING;
|
||||
|
||||
// Scale and rotate around our epicenter.
|
||||
coords -= uEpicenter;
|
||||
|
||||
// Scale each layer a bit differently.
|
||||
coords /= mix(1.0, 1.0 + uBlowForce * (i + 2) / SHARD_LAYERS, progress);
|
||||
coords /= mix(1.0, 1.0 + uBlowForce * (i + 2.0) / SHARD_LAYERS, progress);
|
||||
|
||||
// Rotate each layer a bit differently.
|
||||
float rotation = (mod(i, 2.0) - 0.5) * 0.2 * progress;
|
||||
@@ -65,13 +65,10 @@ void main() {
|
||||
// the bin of the current shard.
|
||||
float shardGroup = floor(shardMap.g * SHARD_LAYERS * 0.999);
|
||||
|
||||
if (shardGroup == i && (shardMap.x - pow(progress + 0.1, 2)) > 0) {
|
||||
cogl_color_out = texture2D(uTexture, coords);
|
||||
if (shardGroup == i && (shardMap.x - pow(progress + 0.1, 2)) > 0.0) {
|
||||
oColor = getInputColor(coords);
|
||||
}
|
||||
}
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
+101
-16
@@ -17,19 +17,104 @@
|
||||
|
||||
// --------------------------------------------------------------------- standard uniforms
|
||||
|
||||
// uForOpening: True if a window-open animation is ongoing, false otherwise.
|
||||
// uTexture: Contains the texture of the window.
|
||||
// uProgress: A value which transitions from 0 to 1 during the entire animation.
|
||||
// uTime: A steadily increasing value in seconds.
|
||||
// uSize: The size of uTexture in pixels.
|
||||
// uPadding: The empty area around the actual window (e.g. where the shadow is drawn).
|
||||
// Each shader can access these standard input values:
|
||||
|
||||
// vec2 iTexCoord: Texture coordinates for retrieving the window input color.
|
||||
// bool uForOpening: True if a window-open animation is ongoing, false otherwise.
|
||||
// float uProgress: A value which transitions from 0 to 1 during the animation.
|
||||
// float uDuration: The duration of the current animation in seconds.
|
||||
// vec2 uSize: The size of uTexture in pixels.
|
||||
// float uPadding: The empty area around the actual window (e.g. where the shadow
|
||||
// is drawn). For now, this will only be set on GNOME.
|
||||
|
||||
// Furthermore, there are two global methods for reading the window input color and
|
||||
// setting the shader output color. Both methods assume straight alpha:
|
||||
|
||||
// vec4 getInputColor(vec2 coords)
|
||||
// void setOutputColor(vec4 outColor)
|
||||
|
||||
uniform bool uForOpening;
|
||||
uniform sampler2D uTexture;
|
||||
uniform float uProgress;
|
||||
uniform float uTime;
|
||||
uniform float uDuration;
|
||||
|
||||
#if defined(KWIN) // --------------------------------------------------------------------
|
||||
|
||||
uniform sampler2D sampler;
|
||||
uniform int textureWidth;
|
||||
uniform int textureHeight;
|
||||
|
||||
in vec2 texcoord0;
|
||||
out vec4 fragColor;
|
||||
|
||||
vec2 uSize = vec2(textureWidth, textureHeight);
|
||||
vec2 iTexCoord = vec2(texcoord0.x, 1.0 - texcoord0.y);
|
||||
float uPadding = 0.0;
|
||||
|
||||
vec4 getInputColor(vec2 coords) {
|
||||
vec4 color = texture2D(sampler, vec2(coords.x, 1.0 - coords.y));
|
||||
|
||||
if (color.a > 0.0) {
|
||||
color.rgb /= color.a;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void setOutputColor(vec4 outColor) {
|
||||
fragColor = vec4(outColor.rgb * outColor.a, outColor.a);
|
||||
}
|
||||
|
||||
#elif defined(KWIN_LEGACY) // -----------------------------------------------------------
|
||||
|
||||
uniform sampler2D sampler;
|
||||
uniform int textureWidth;
|
||||
uniform int textureHeight;
|
||||
|
||||
varying vec2 texcoord0;
|
||||
|
||||
vec2 uSize = vec2(textureWidth, textureHeight);
|
||||
vec2 iTexCoord = vec2(texcoord0.x, 1.0 - texcoord0.y);
|
||||
float uPadding = 0.0;
|
||||
|
||||
vec4 getInputColor(vec2 coords) {
|
||||
vec4 color = texture2D(sampler, vec2(coords.x, 1.0 - coords.y));
|
||||
|
||||
if (color.a > 0.0) {
|
||||
color.rgb /= color.a;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void setOutputColor(vec4 outColor) {
|
||||
gl_FragColor = vec4(outColor.rgb * outColor.a, outColor.a);
|
||||
}
|
||||
|
||||
#else // GNOME --------------------------------------------------------------------------
|
||||
|
||||
// On GNOME, the uniforms are just normal uniforms.
|
||||
uniform sampler2D uTexture;
|
||||
uniform vec2 uSize;
|
||||
uniform float uPadding;
|
||||
|
||||
// On GNOME, we set iTexCoord to be an alias for the cogl variables.
|
||||
#define iTexCoord cogl_tex_coord_in[0]
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
vec4 getInputColor(vec2 coords) {
|
||||
vec4 color = texture2D(uTexture, coords);
|
||||
|
||||
if (color.a > 0.0) {
|
||||
color.rgb /= color.a;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void setOutputColor(vec4 outColor) { cogl_color_out = outColor; }
|
||||
|
||||
#endif // -------------------------------------------------------------------------------
|
||||
|
||||
// ----------------------------------------------------------------- compositing operators
|
||||
|
||||
// The Shell.GLSLEffect uses straight alpha blending. This helper method allows
|
||||
@@ -45,7 +130,7 @@ vec4 alphaOver(vec4 under, vec4 over) {
|
||||
// Taken from here:
|
||||
// https://gitlab.gnome.org/GNOME/mutter/-/blob/main/clutter/clutter/clutter-easing.c
|
||||
|
||||
float easeOutQuad(float x) { return -1.0 * x * (x - 2); }
|
||||
float easeOutQuad(float x) { return -1.0 * x * (x - 2.0); }
|
||||
|
||||
// --------------------------------------------------------------------- edge mask helpers
|
||||
|
||||
@@ -54,10 +139,10 @@ float easeOutQuad(float x) { return -1.0 * x * (x - 2); }
|
||||
// pixels and one which takes this as a percentage.
|
||||
float getEdgeMask(vec2 uv, vec2 maxUV, float fadeWidth) {
|
||||
float mask = 1.0;
|
||||
mask *= smoothstep(0, 1, clamp(uv.x / fadeWidth, 0, 1));
|
||||
mask *= smoothstep(0, 1, clamp(uv.y / fadeWidth, 0, 1));
|
||||
mask *= smoothstep(0, 1, clamp((maxUV.x - uv.x) / fadeWidth, 0, 1));
|
||||
mask *= smoothstep(0, 1, clamp((maxUV.y - uv.y) / fadeWidth, 0, 1));
|
||||
mask *= smoothstep(0.0, 1.0, clamp(uv.x / fadeWidth, 0.0, 1.0));
|
||||
mask *= smoothstep(0.0, 1.0, clamp(uv.y / fadeWidth, 0.0, 1.0));
|
||||
mask *= smoothstep(0.0, 1.0, clamp((maxUV.x - uv.x) / fadeWidth, 0.0, 1.0));
|
||||
mask *= smoothstep(0.0, 1.0, clamp((maxUV.y - uv.y) / fadeWidth, 0.0, 1.0));
|
||||
|
||||
return mask;
|
||||
}
|
||||
@@ -70,8 +155,8 @@ float getEdgeMask(vec2 uv, vec2 maxUV, float fadeWidth) {
|
||||
// (offset = 0), ontop the window borders (offset = 0.5) or outside the window borders
|
||||
// (offset = 1).
|
||||
float getAbsoluteEdgeMask(float fadePixels, float offset) {
|
||||
float padding = max(0, uPadding - fadePixels * offset);
|
||||
vec2 uv = cogl_tex_coord_in[0].st * uSize - padding;
|
||||
float padding = max(0.0, uPadding - fadePixels * offset);
|
||||
vec2 uv = iTexCoord.st * uSize - padding;
|
||||
return getEdgeMask(uv, uSize - 2.0 * padding, fadePixels);
|
||||
}
|
||||
|
||||
@@ -79,7 +164,7 @@ float getAbsoluteEdgeMask(float fadePixels, float offset) {
|
||||
// the fade zone is given relative to the actor size. This neither uses uSize and
|
||||
// uPadding.
|
||||
float getRelativeEdgeMask(float fadeAmount) {
|
||||
vec2 uv = cogl_tex_coord_in[0].st;
|
||||
vec2 uv = iTexCoord.st;
|
||||
return getEdgeMask(uv, vec2(1.0), fadeAmount);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,19 +19,19 @@ uniform float uScale;
|
||||
const float FADE_IN_TIME = 0.3;
|
||||
const float FADE_OUT_TIME = 0.6;
|
||||
const float HEART_FADE_TIME = 0.3;
|
||||
const float EDGE_FADE_WIDTH = 50;
|
||||
const float EDGE_FADE_WIDTH = 50.0;
|
||||
|
||||
// This method returns two values:
|
||||
// result.x: A mask for the particles.
|
||||
// result.y: The opacity of the fading window.
|
||||
vec2 getMasks(float progress) {
|
||||
float fadeInProgress = clamp(progress / FADE_IN_TIME, 0, 1);
|
||||
float fadeOutProgress = clamp((progress - FADE_IN_TIME) / FADE_OUT_TIME, 0, 1);
|
||||
float fadeInProgress = clamp(progress / FADE_IN_TIME, 0.0, 1.0);
|
||||
float fadeOutProgress = clamp((progress - FADE_IN_TIME) / FADE_OUT_TIME, 0.0, 1.0);
|
||||
float heartProgress =
|
||||
clamp((progress - (1.0 - HEART_FADE_TIME)) / HEART_FADE_TIME, 0, 1);
|
||||
clamp((progress - (1.0 - HEART_FADE_TIME)) / HEART_FADE_TIME, 0.0, 1.0);
|
||||
|
||||
// Compute mask for the "atom" particles.
|
||||
float dist = length(cogl_tex_coord_in[0].st - 0.5) * 4.0;
|
||||
float dist = length(iTexCoord.st - 0.5) * 4.0;
|
||||
float atomMask = smoothstep(0.0, 1.0, (fadeInProgress * 2.0 - dist + 1.0));
|
||||
atomMask *= fadeInProgress;
|
||||
atomMask *= smoothstep(1.0, 0.0, fadeOutProgress);
|
||||
@@ -41,10 +41,10 @@ vec2 getMasks(float progress) {
|
||||
atomMask *= edgeFade;
|
||||
|
||||
float heartMask = getRelativeEdgeMask(0.5);
|
||||
heartMask = 3.0 * pow(heartMask, 5);
|
||||
heartMask = 3.0 * pow(heartMask, 5.0);
|
||||
heartMask *= fadeOutProgress;
|
||||
heartMask *= 1.0 - heartProgress;
|
||||
atomMask = clamp(heartMask + atomMask, 0, 1);
|
||||
atomMask = clamp(heartMask + atomMask, 0.0, 1.0);
|
||||
|
||||
// Compute fading window opacity.
|
||||
float windowMask = pow(1.0 - fadeOutProgress, 2.0);
|
||||
@@ -59,39 +59,36 @@ vec2 getMasks(float progress) {
|
||||
void main() {
|
||||
float progress = easeOutQuad(uProgress);
|
||||
|
||||
vec2 masks = getMasks(progress);
|
||||
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (windowColor.a > 0) {
|
||||
windowColor.rgb /= windowColor.a;
|
||||
}
|
||||
vec2 masks = getMasks(progress);
|
||||
vec4 oColor = getInputColor(iTexCoord.st);
|
||||
|
||||
// Dissolve window to effect color / transparency.
|
||||
cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.2 * masks.y + 0.8);
|
||||
cogl_color_out.a = windowColor.a * masks.y;
|
||||
oColor.rgb = mix(uColor, oColor.rgb, 0.2 * masks.y + 0.8);
|
||||
oColor.a = oColor.a * masks.y;
|
||||
|
||||
vec2 scaledUV = (cogl_tex_coord_in[0].st - 0.5) * (1.0 + 0.1 * progress);
|
||||
vec2 scaledUV = (iTexCoord.st - 0.5) * (1.0 + 0.1 * progress);
|
||||
scaledUV /= uScale;
|
||||
|
||||
// Add molecule particles.
|
||||
vec2 uv = scaledUV + vec2(0, 0.1 * uTime);
|
||||
vec2 uv = scaledUV + vec2(0.0, 0.1 * uProgress * uDuration);
|
||||
uv *= 0.010598 * vec2(0.5 * uSize.x, uSize.y);
|
||||
float particles = 0.2 * pow((simplex3D(vec3(uv, 0.0 * uTime))), 3.0);
|
||||
float particles = 0.2 * pow((simplex3D(vec3(uv, 0.0 * uProgress * uDuration))), 3.0);
|
||||
|
||||
// Add more molecule particles.
|
||||
for (int i = 1; i <= 3; ++i) {
|
||||
for (float i = 1.0; i <= 3.0; ++i) {
|
||||
vec2 uv = scaledUV * 0.12154 / pow(1.5, i) * uSize;
|
||||
float atoms = simplex3D(vec3(uv, 2.0 * uTime / i));
|
||||
particles += 0.5 * pow(0.2 * (1.0 / (1.0 - atoms) - 1.0), 2);
|
||||
float atoms = simplex3D(vec3(uv, 2.0 * uProgress * uDuration / i));
|
||||
particles += 0.5 * pow(0.2 * (1.0 / (1.0 - atoms) - 1.0), 2.0);
|
||||
}
|
||||
|
||||
cogl_color_out.rgb += uColor * particles * masks.x;
|
||||
cogl_color_out.a += particles * masks.x;
|
||||
oColor.rgb += uColor * particles * masks.x;
|
||||
oColor.a += particles * masks.x;
|
||||
|
||||
// These are pretty useful for understanding how this works.
|
||||
// cogl_color_out = vec4(masks, 0.0, 1.0);
|
||||
// cogl_color_out = vec4(vec3(masks.x), 1.0);
|
||||
// cogl_color_out = vec4(vec3(masks.y), 1.0);
|
||||
// cogl_color_out = vec4(vec3(particles), 1.0);
|
||||
// oColor = vec4(masks, 0.0, 1.0);
|
||||
// oColor = vec4(vec3(masks.x), 1.0);
|
||||
// oColor = vec4(vec3(masks.y), 1.0);
|
||||
// oColor = vec4(vec3(particles), 1.0);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
@@ -19,7 +19,7 @@ uniform float uScale;
|
||||
const float SHOWER_TIME = 0.3;
|
||||
const float SHOWER_WIDTH = 0.3;
|
||||
const float STREAK_TIME = 0.6;
|
||||
const float EDGE_FADE = 50;
|
||||
const float EDGE_FADE = 50.0;
|
||||
|
||||
// This method returns four values:
|
||||
// result.x: A mask for the particles which lead the shower.
|
||||
@@ -28,24 +28,24 @@ const float EDGE_FADE = 50;
|
||||
// result.w: The opacity of the fading window.
|
||||
vec4 getMasks(float progress) {
|
||||
float showerProgress = progress / SHOWER_TIME;
|
||||
float streakProgress = clamp((progress - SHOWER_TIME) / STREAK_TIME, 0, 1);
|
||||
float fadeProgress = clamp((progress - SHOWER_TIME) / (1.0 - SHOWER_TIME), 0, 1);
|
||||
float streakProgress = clamp((progress - SHOWER_TIME) / STREAK_TIME, 0.0, 1.0);
|
||||
float fadeProgress = clamp((progress - SHOWER_TIME) / (1.0 - SHOWER_TIME), 0.0, 1.0);
|
||||
|
||||
// Gradient from top to bottom.
|
||||
float t = cogl_tex_coord_in[0].t;
|
||||
float t = iTexCoord.t;
|
||||
|
||||
// A smooth gradient which moves to the bottom within the showerProgress.
|
||||
float showerMask =
|
||||
smoothstep(1, 0, abs(showerProgress - t - SHOWER_WIDTH) / SHOWER_WIDTH);
|
||||
smoothstep(1.0, 0.0, abs(showerProgress - t - SHOWER_WIDTH) / SHOWER_WIDTH);
|
||||
|
||||
// This is 1 above the streak mask.
|
||||
float streakMask = (showerProgress - t - SHOWER_WIDTH) > 0 ? 1 : 0;
|
||||
float streakMask = (showerProgress - t - SHOWER_WIDTH) > 0.0 ? 1.0 : 0.0;
|
||||
|
||||
// Compute mask for the "atom" particles.
|
||||
float atomMask = getRelativeEdgeMask(0.2);
|
||||
atomMask = max(0, atomMask - showerMask);
|
||||
atomMask = max(0.0, atomMask - showerMask);
|
||||
atomMask *= streakMask;
|
||||
atomMask *= sqrt(1 - fadeProgress * fadeProgress);
|
||||
atomMask *= sqrt(1.0 - fadeProgress * fadeProgress);
|
||||
|
||||
// Make some particles visible in the streaks.
|
||||
showerMask += 0.05 * streakMask;
|
||||
@@ -76,46 +76,43 @@ vec4 getMasks(float progress) {
|
||||
void main() {
|
||||
float progress = easeOutQuad(uProgress);
|
||||
|
||||
vec4 masks = getMasks(progress);
|
||||
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (windowColor.a > 0) {
|
||||
windowColor.rgb /= windowColor.a;
|
||||
}
|
||||
vec4 masks = getMasks(progress);
|
||||
vec4 oColor = getInputColor(iTexCoord.st);
|
||||
|
||||
// Dissolve window to effect color / transparency.
|
||||
cogl_color_out.rgb = mix(uColor, windowColor.rgb, 0.5 * masks.w + 0.5);
|
||||
cogl_color_out.a = windowColor.a * masks.w;
|
||||
oColor.rgb = mix(uColor, oColor.rgb, 0.5 * masks.w + 0.5);
|
||||
oColor.a = oColor.a * masks.w;
|
||||
|
||||
// Add leading shower particles.
|
||||
vec2 showerUV = cogl_tex_coord_in[0].st + vec2(0, -0.7 * progress / SHOWER_TIME);
|
||||
vec2 showerUV = iTexCoord.st + vec2(0.0, -0.7 * progress / SHOWER_TIME);
|
||||
showerUV *= 0.02 * uSize / uScale;
|
||||
float shower = pow(simplex2D(showerUV), 10.0);
|
||||
cogl_color_out.rgb += uColor * shower * masks.x;
|
||||
cogl_color_out.a += shower * masks.x;
|
||||
oColor.rgb += uColor * shower * masks.x;
|
||||
oColor.a += shower * masks.x;
|
||||
|
||||
// Add trailing streak lines.
|
||||
vec2 streakUV = cogl_tex_coord_in[0].st + vec2(0, -progress / SHOWER_TIME);
|
||||
vec2 streakUV = iTexCoord.st + vec2(0.0, -progress / SHOWER_TIME);
|
||||
streakUV *= vec2(0.05 * uSize.x, 0.001 * uSize.y) / uScale;
|
||||
float streaks = simplex2DFractal(streakUV) * 0.5;
|
||||
cogl_color_out.rgb += uColor * streaks * masks.y;
|
||||
cogl_color_out.a += streaks * masks.y;
|
||||
oColor.rgb += uColor * streaks * masks.y;
|
||||
oColor.a += streaks * masks.y;
|
||||
|
||||
// Add glimmering atoms.
|
||||
vec2 atomUV = cogl_tex_coord_in[0].st + vec2(0, -0.025 * progress / SHOWER_TIME);
|
||||
vec2 atomUV = iTexCoord.st + vec2(0.0, -0.025 * progress / SHOWER_TIME);
|
||||
atomUV *= 0.2 * uSize / uScale;
|
||||
float atoms = pow((simplex3D(vec3(atomUV, uTime))), 5.0);
|
||||
cogl_color_out.rgb += uColor * atoms * masks.z;
|
||||
cogl_color_out.a += atoms * masks.z;
|
||||
float atoms = pow((simplex3D(vec3(atomUV, uProgress * uDuration))), 5.0);
|
||||
oColor.rgb += uColor * atoms * masks.z;
|
||||
oColor.a += atoms * masks.z;
|
||||
|
||||
// These are pretty useful for understanding how this works.
|
||||
// cogl_color_out = vec4(masks.rgb, 1.0);
|
||||
// cogl_color_out = vec4(vec3(masks.x), 1.0);
|
||||
// cogl_color_out = vec4(vec3(masks.y), 1.0);
|
||||
// cogl_color_out = vec4(vec3(masks.z), 1.0);
|
||||
// cogl_color_out = vec4(vec3(masks.w), 1.0);
|
||||
// cogl_color_out = vec4(vec3(shower), 1.0);
|
||||
// cogl_color_out = vec4(vec3(streaks), 1.0);
|
||||
// cogl_color_out = vec4(vec3(atoms), 1.0);
|
||||
// oColor = vec4(masks.rgb, 1.0);
|
||||
// oColor = vec4(vec3(masks.x), 1.0);
|
||||
// oColor = vec4(vec3(masks.y), 1.0);
|
||||
// oColor = vec4(vec3(masks.z), 1.0);
|
||||
// oColor = vec4(vec3(masks.w), 1.0);
|
||||
// oColor = vec4(vec3(shower), 1.0);
|
||||
// oColor = vec4(vec3(streaks), 1.0);
|
||||
// oColor = vec4(vec3(atoms), 1.0);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
+35
-25
@@ -23,14 +23,25 @@ uniform vec4 uGradient4;
|
||||
uniform vec4 uGradient5;
|
||||
|
||||
// These may be configurable in the future.
|
||||
const float EDGE_FADE = 70;
|
||||
const float EDGE_FADE = 70.0;
|
||||
const float FADE_WIDTH = 0.1;
|
||||
const float HIDE_TIME = 0.4;
|
||||
|
||||
// This maps the input value from [0..1] to a color from the gradient.
|
||||
vec4 getFireColor(float v) {
|
||||
const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8);
|
||||
vec4 colors[5] = vec4[](uGradient1, uGradient2, uGradient3, uGradient4, uGradient5);
|
||||
float steps[5];
|
||||
steps[0] = 0.0;
|
||||
steps[1] = 0.2;
|
||||
steps[2] = 0.35;
|
||||
steps[3] = 0.5;
|
||||
steps[4] = 0.8;
|
||||
|
||||
vec4 colors[5];
|
||||
colors[0] = uGradient1;
|
||||
colors[1] = uGradient2;
|
||||
colors[2] = uGradient3;
|
||||
colors[3] = uGradient4;
|
||||
colors[4] = uGradient5;
|
||||
|
||||
if (v < steps[0]) {
|
||||
return colors[0];
|
||||
@@ -59,22 +70,22 @@ vec4 getFireColor(float v) {
|
||||
vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) {
|
||||
float progress = easeOutQuad(uProgress);
|
||||
|
||||
float burnProgress = clamp(progress / hideTime, 0, 1);
|
||||
float afterBurnProgress = clamp((progress - hideTime) / (1 - hideTime), 0, 1);
|
||||
float burnProgress = clamp(progress / hideTime, 0.0, 1.0);
|
||||
float afterBurnProgress = clamp((progress - hideTime) / (1.0 - hideTime), 0.0, 1.0);
|
||||
|
||||
// Gradient from top to bottom.
|
||||
float t = cogl_tex_coord_in[0].t * (1 - fadeWidth);
|
||||
float t = iTexCoord.t * (1.0 - fadeWidth);
|
||||
|
||||
// Visible part of the window. Gradually dissolves towards the bottom.
|
||||
float windowMask = 1 - clamp((burnProgress - t) / fadeWidth, 0, 1);
|
||||
float windowMask = 1.0 - clamp((burnProgress - t) / fadeWidth, 0.0, 1.0);
|
||||
|
||||
// Gradient from top burning window.
|
||||
float effectMask = clamp(t * (1 - windowMask) / burnProgress, 0, 1);
|
||||
float effectMask = clamp(t * (1.0 - windowMask) / burnProgress, 0.0, 1.0);
|
||||
|
||||
// Fade-out when the window burned down.
|
||||
if (progress > hideTime) {
|
||||
float fade = sqrt(1 - afterBurnProgress * afterBurnProgress);
|
||||
effectMask *= mix(1, 1 - t, afterBurnProgress) * fade;
|
||||
float fade = sqrt(1.0 - afterBurnProgress * afterBurnProgress);
|
||||
effectMask *= mix(1.0, 1.0 - t, afterBurnProgress) * fade;
|
||||
}
|
||||
|
||||
// Fade at window borders.
|
||||
@@ -89,11 +100,13 @@ vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) {
|
||||
|
||||
void main() {
|
||||
// Get a noise value which moves vertically in time.
|
||||
vec2 uv = cogl_tex_coord_in[0].st * uSize / vec2(400, 600) / uScale;
|
||||
uv.y += uTime * uMovementSpeed;
|
||||
vec2 uv = iTexCoord.st * uSize / vec2(400, 600) / uScale;
|
||||
uv.y += uProgress * uDuration * uMovementSpeed;
|
||||
|
||||
float noise = u3DNoise ? simplex3DFractal(vec3(uv * 4.0, uTime * uMovementSpeed * 1.5))
|
||||
: simplex2DFractal(uv * 4.0);
|
||||
float noise =
|
||||
u3DNoise
|
||||
? simplex3DFractal(vec3(uv * 4.0, uProgress * uDuration * uMovementSpeed * 1.5))
|
||||
: simplex2DFractal(uv * 4.0);
|
||||
|
||||
// Modulate noise by effect mask.
|
||||
vec2 effectMask = effectMask(HIDE_TIME, FADE_WIDTH, EDGE_FADE);
|
||||
@@ -103,21 +116,18 @@ void main() {
|
||||
vec4 fire = getFireColor(noise);
|
||||
|
||||
// Get the window texture.
|
||||
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
vec4 oColor = getInputColor(iTexCoord.st);
|
||||
|
||||
// Fade the window according to the effect mask.
|
||||
cogl_color_out.a *= effectMask.x;
|
||||
oColor.a *= effectMask.x;
|
||||
|
||||
// Add the fire to the window.
|
||||
cogl_color_out = alphaOver(cogl_color_out, fire);
|
||||
oColor = alphaOver(oColor, fire);
|
||||
|
||||
// These are pretty useful for understanding how this works.
|
||||
// cogl_color_out = vec4(vec3(noise), 1);
|
||||
// cogl_color_out = vec4(vec3(effectMask.x), 1);
|
||||
// cogl_color_out = vec4(vec3(effectMask.y), 1);
|
||||
// oColor = vec4(vec3(noise), 1);
|
||||
// oColor = vec4(vec3(effectMask.x), 1);
|
||||
// oColor = vec4(vec3(effectMask.y), 1);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
@@ -20,7 +20,7 @@ uniform float uLineWidth;
|
||||
uniform vec4 uGlowColor;
|
||||
uniform vec4 uLineColor;
|
||||
|
||||
// This methods generates a procedural hexagonal pattern. It returns four values:
|
||||
// This method generates a procedural hexagonal pattern. It returns four values:
|
||||
// result.xy: This contains cell-relative coordinates for the given point.
|
||||
// [0, 0] is in the center of a cell, [0, 1] at the upper edge,
|
||||
// [sqrt(4.0 / 3.0), 0] at the right tip and so on.
|
||||
@@ -31,10 +31,10 @@ uniform vec4 uLineColor;
|
||||
vec4 getHexagons(vec2 p) {
|
||||
|
||||
// Length of a cell's edge.
|
||||
const float edgeLength = sqrt(4.0 / 3.0);
|
||||
float edgeLength = sqrt(4.0 / 3.0);
|
||||
|
||||
// The hexgrid repeats after this distance.
|
||||
const vec2 scale = vec2(3.0 * edgeLength, 2.0);
|
||||
vec2 scale = vec2(3.0 * edgeLength, 2.0);
|
||||
|
||||
// This is a repeating grid of scale-sized cells. Y-values are in the
|
||||
// interval [-1...1], X-value in [-1.5*edgeLength...1.5*edgeLength].
|
||||
@@ -68,33 +68,26 @@ void main() {
|
||||
|
||||
// Add some smooth noise to the progress so that not every tile behaves the
|
||||
// same.
|
||||
float noise = simplex2D(cogl_tex_coord_in[0].st + uSeed);
|
||||
float noise = simplex2D(iTexCoord.st + uSeed);
|
||||
progress = clamp(mix(noise - 1.0, noise + 1.0, progress), 0.0, 1.0);
|
||||
|
||||
// glowProgress fades in in the first half of the animation, tileProgress fades
|
||||
// in in the second half.
|
||||
float glowProgress = smoothstep(0, 1, clamp(progress / 0.5, 0, 1));
|
||||
float tileProgress = smoothstep(0, 1, clamp((progress - 0.5) / 0.5, 0, 1));
|
||||
float glowProgress = smoothstep(0.0, 1.0, clamp(progress / 0.5, 0.0, 1.0));
|
||||
float tileProgress = smoothstep(0.0, 1.0, clamp((progress - 0.5) / 0.5, 0.0, 1.0));
|
||||
|
||||
vec2 texScale = 0.1 * uSize / uScale;
|
||||
vec4 hex = getHexagons(cogl_tex_coord_in[0].st * texScale);
|
||||
vec4 hex = getHexagons(iTexCoord.st * texScale);
|
||||
|
||||
if (tileProgress > hex.z) {
|
||||
vec4 oColor = vec4(0.0);
|
||||
|
||||
// Crop outer parts of the shrinking tiles.
|
||||
cogl_color_out.a = 0.0;
|
||||
|
||||
} else {
|
||||
// Crop outer parts of the shrinking tiles.
|
||||
if (tileProgress < hex.z) {
|
||||
|
||||
// Make the tiles shrink by offsetting the texture lookup towards the edge
|
||||
// of the cell.
|
||||
vec2 lookupOffset = tileProgress * hex.xy / texScale / (1.0 - tileProgress);
|
||||
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st + lookupOffset);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
oColor = getInputColor(iTexCoord.st + lookupOffset);
|
||||
|
||||
vec4 glow = uGlowColor;
|
||||
vec4 line = uLineColor;
|
||||
@@ -111,15 +104,17 @@ void main() {
|
||||
line.a *= glowProgress;
|
||||
|
||||
// Do not add the hexagon lines onto transparent parts of the window.
|
||||
glow *= cogl_color_out.a;
|
||||
line *= cogl_color_out.a;
|
||||
glow *= oColor.a;
|
||||
line *= oColor.a;
|
||||
|
||||
if (uAdditiveBlending) {
|
||||
cogl_color_out.rgb += glow.rgb * glow.a;
|
||||
cogl_color_out.rgb += line.rgb * line.a;
|
||||
oColor.rgb += glow.rgb * glow.a;
|
||||
oColor.rgb += line.rgb * line.a;
|
||||
} else {
|
||||
cogl_color_out.rgb = mix(cogl_color_out.rgb, glow.rgb, glow.a);
|
||||
cogl_color_out.rgb = mix(cogl_color_out.rgb, line.rgb, line.a);
|
||||
oColor.rgb = mix(oColor.rgb, glow.rgb, glow.a);
|
||||
oColor.rgb = mix(oColor.rgb, line.rgb, line.a);
|
||||
}
|
||||
}
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
@@ -21,8 +21,8 @@ uniform float uRandomness;
|
||||
uniform float uOverShoot;
|
||||
|
||||
// These may be configurable in the future.
|
||||
const float EDGE_FADE = 30;
|
||||
const float FADE_WIDTH = 150;
|
||||
const float EDGE_FADE = 30.0;
|
||||
const float FADE_WIDTH = 150.0;
|
||||
const float TRAIL_LENGTH = 0.2;
|
||||
const float FINAL_FADE_START_TIME = 0.8;
|
||||
const float LETTER_TILES = 16.0;
|
||||
@@ -36,7 +36,7 @@ float getText(vec2 fragCoord) {
|
||||
|
||||
// Choose random letter.
|
||||
uv += floor(hash22(floor(hash22(block) * vec2(12.9898, 78.233) +
|
||||
LETTER_FLICKER_SPEED * uTime + 42.254)) *
|
||||
LETTER_FLICKER_SPEED * uProgress * uDuration + 42.254)) *
|
||||
LETTER_TILES);
|
||||
|
||||
return texture2D(uFontTexture, uv / LETTER_TILES).r;
|
||||
@@ -47,16 +47,16 @@ float getText(vec2 fragCoord) {
|
||||
// to one below each drop and to zero above it. This second value is used for fading
|
||||
// the window texture.
|
||||
vec2 getRain(vec2 fragCoord) {
|
||||
float column = cogl_tex_coord_in[0].x * uSize.x;
|
||||
float column = iTexCoord.x * uSize.x;
|
||||
column -= mod(column, uLetterSize);
|
||||
|
||||
float delay = fract(sin(column) * 78.233) * mix(0.0, 1.0, uRandomness);
|
||||
float speed = fract(cos(column) * 12.989) * mix(0.0, 0.3, uRandomness) + 1.5;
|
||||
|
||||
float distToDrop = (uProgress * 2 - delay) * speed - cogl_tex_coord_in[0].y;
|
||||
float distToDrop = (uProgress * 2 - delay) * speed - iTexCoord.y;
|
||||
|
||||
float rainAlpha = distToDrop >= 0 ? exp(-distToDrop / TRAIL_LENGTH) : 0;
|
||||
float windowAlpha = 1 - clamp(uSize.y * distToDrop, 0, FADE_WIDTH) / FADE_WIDTH;
|
||||
float rainAlpha = distToDrop >= 0.0 ? exp(-distToDrop / TRAIL_LENGTH) : 0.0;
|
||||
float windowAlpha = 1.0 - clamp(uSize.y * distToDrop, 0.0, FADE_WIDTH) / FADE_WIDTH;
|
||||
|
||||
// Fade at window borders.
|
||||
rainAlpha *= getAbsoluteEdgeMask(EDGE_FADE, 0.5);
|
||||
@@ -64,8 +64,8 @@ vec2 getRain(vec2 fragCoord) {
|
||||
// Add some variation to the drop start and end position.
|
||||
float shorten =
|
||||
fract(sin(column + 42.0) * 33.423) * mix(0.0, uOverShoot * 0.25, uRandomness);
|
||||
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.0, 1.0, clamp(iTexCoord.y / shorten, 0.0, 1.0));
|
||||
rainAlpha *= smoothstep(0.0, 1.0, clamp((1.0 - iTexCoord.y) / shorten, 0.0, 1.0));
|
||||
|
||||
if (uForOpening) {
|
||||
windowAlpha = 1.0 - windowAlpha;
|
||||
@@ -75,7 +75,7 @@ vec2 getRain(vec2 fragCoord) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 coords = cogl_tex_coord_in[0].st;
|
||||
vec2 coords = iTexCoord.st;
|
||||
coords.y = coords.y * (uOverShoot + 1.0) - uOverShoot * 0.5;
|
||||
|
||||
// Get a cool matrix effect. See comments for those methods above.
|
||||
@@ -83,28 +83,26 @@ void main() {
|
||||
float textMask = getText(coords);
|
||||
|
||||
// Get the window texture.
|
||||
cogl_color_out = texture2D(uTexture, coords);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
vec4 oColor = getInputColor(coords);
|
||||
|
||||
// Fade the window according to the effect mask.
|
||||
cogl_color_out.a *= rainMask.y;
|
||||
oColor.a *= rainMask.y;
|
||||
|
||||
// This is used to fade out the remaining trails in the end.
|
||||
float finalFade =
|
||||
1 - clamp((uProgress - FINAL_FADE_START_TIME) / (1 - FINAL_FADE_START_TIME), 0, 1);
|
||||
1 -
|
||||
clamp((uProgress - FINAL_FADE_START_TIME) / (1.0 - FINAL_FADE_START_TIME), 0.0, 1.0);
|
||||
float rainAlpha = finalFade * rainMask.x;
|
||||
|
||||
// Add the matrix effect to the window.
|
||||
vec4 text = vec4(mix(uTrailColor, uTipColor, min(1, pow(rainAlpha + 0.1, 4))),
|
||||
vec4 text = vec4(mix(uTrailColor, uTipColor, min(1.0, pow(rainAlpha + 0.1, 4.0))),
|
||||
rainAlpha * textMask);
|
||||
cogl_color_out = alphaOver(cogl_color_out, text);
|
||||
oColor = alphaOver(oColor, text);
|
||||
|
||||
// These are pretty useful for understanding how this works.
|
||||
// cogl_color_out = vec4(vec3(textMask), 1);
|
||||
// cogl_color_out = vec4(vec3(rainMask.x), 1);
|
||||
// cogl_color_out = vec4(vec3(rainMask.y), 1);
|
||||
// oColor = vec4(vec3(textMask), 1);
|
||||
// oColor = vec4(vec3(rainMask.x), 1);
|
||||
// oColor = vec4(vec3(rainMask.y), 1);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
+19
-23
@@ -18,7 +18,7 @@ uniform vec4 uDustColor;
|
||||
uniform vec2 uSeed;
|
||||
uniform float uDustScale;
|
||||
|
||||
const float DUST_LAYERS = 4;
|
||||
const float DUST_LAYERS = 4.0;
|
||||
const float GROW_INTENSITY = 0.05;
|
||||
const float SHRINK_INTENSITY = 0.05;
|
||||
const float WIND_INTENSITY = 0.05;
|
||||
@@ -29,42 +29,38 @@ void main() {
|
||||
// We simply inverse the progress for opening windows.
|
||||
float progress = uForOpening ? uProgress : 1.0 - uProgress;
|
||||
|
||||
float gradient = cogl_tex_coord_in[0].t * ACTOR_SCALE - PADDING;
|
||||
float gradient = iTexCoord.t * ACTOR_SCALE - PADDING;
|
||||
progress = 2.0 - gradient - 2.0 * progress;
|
||||
progress = progress + 0.25 - 0.5 * simplex2D((cogl_tex_coord_in[0].st + uSeed) * 2.0);
|
||||
progress = pow(max(0, progress), 2.0);
|
||||
progress = progress + 0.25 - 0.5 * simplex2D((iTexCoord.st + uSeed) * 2.0);
|
||||
progress = pow(max(0.0, progress), 2.0);
|
||||
|
||||
// This may help you to understand how this effect works.
|
||||
// cogl_color_out = vec4(progress, 0, 0, 0);
|
||||
// return;
|
||||
|
||||
cogl_color_out = vec4(0, 0, 0, 0);
|
||||
vec4 oColor = vec4(0.0);
|
||||
|
||||
for (float i = 0; i < DUST_LAYERS; ++i) {
|
||||
|
||||
// Create a random direction.
|
||||
float factor = DUST_LAYERS == 1 ? 0 : i / (DUST_LAYERS - 1);
|
||||
float factor = DUST_LAYERS == 1.0 ? 0.0 : i / (DUST_LAYERS - 1.0);
|
||||
float angle = 123.123 * (uSeed.x + factor);
|
||||
vec2 direction = vec2(1.0, 0.0);
|
||||
direction = rotate(direction, angle);
|
||||
|
||||
// Flip direction for one side of the window.
|
||||
vec2 coords = cogl_tex_coord_in[0].st * ACTOR_SCALE - PADDING - 0.5;
|
||||
if (getWinding(direction, coords) > 0) {
|
||||
direction *= -1;
|
||||
vec2 coords = iTexCoord.st * ACTOR_SCALE - PADDING - 0.5;
|
||||
if (getWinding(direction, coords) > 0.0) {
|
||||
direction *= -1.0;
|
||||
}
|
||||
|
||||
// Flip direction for half the layers.
|
||||
if (factor > 0.5) {
|
||||
direction *= -1;
|
||||
direction *= -1.0;
|
||||
}
|
||||
|
||||
// We grow the layer along the random direction, shrink it orthogonally to it
|
||||
// and scale it up slightly.
|
||||
float dist = distToLine(vec2(0.0), direction, coords);
|
||||
vec2 grow = direction * dist * mix(0, GROW_INTENSITY, progress);
|
||||
vec2 grow = direction * dist * mix(0.0, GROW_INTENSITY, progress);
|
||||
vec2 shrink =
|
||||
vec2(direction.y, -direction.x) * dist * mix(0, SHRINK_INTENSITY, progress);
|
||||
vec2(direction.y, -direction.x) * dist * mix(0.0, SHRINK_INTENSITY, progress);
|
||||
float scale = mix(1.0, 1.05, factor * progress);
|
||||
coords = (coords + grow + shrink) / scale;
|
||||
|
||||
@@ -80,12 +76,7 @@ void main() {
|
||||
if (dustGroup == i) {
|
||||
|
||||
// Get the window color.
|
||||
vec4 windowColor = texture2D(uTexture, coords + 0.5);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (windowColor.a > 0) {
|
||||
windowColor.rgb /= windowColor.a;
|
||||
}
|
||||
vec4 windowColor = getInputColor(coords + 0.5);
|
||||
|
||||
// Fade the window color to uDustColor.
|
||||
vec3 dustColor = mix(windowColor.rgb, uDustColor.rgb, uDustColor.a);
|
||||
@@ -93,8 +84,13 @@ void main() {
|
||||
|
||||
// Dissolve and blend the layers.
|
||||
if (dustMap.x - progress > 0) {
|
||||
cogl_color_out = windowColor;
|
||||
oColor = windowColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This may help you to understand how this effect works.
|
||||
// oColor = vec4(progress, 0, 0, 0);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
+19
-22
@@ -41,7 +41,7 @@ vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) {
|
||||
coords *= gridScale;
|
||||
|
||||
// Get grid cell coordinates in [0..1].
|
||||
vec2 cellUV = mod(coords, vec2(1));
|
||||
vec2 cellUV = mod(coords, vec2(1.0));
|
||||
|
||||
// This is unique for each cell.
|
||||
vec2 cellID = coords - cellUV + vec2(362.456);
|
||||
@@ -61,17 +61,17 @@ vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) {
|
||||
cellUV += 0.5;
|
||||
|
||||
// Clamp resulting coordinates.
|
||||
return clamp(cellUV, vec2(0), vec2(1));
|
||||
return clamp(cellUV, vec2(0.0), vec2(1.0));
|
||||
}
|
||||
|
||||
void main() {
|
||||
float progress = uForOpening ? 1.0 - easeOutQuad(uProgress) : easeOutQuad(uProgress);
|
||||
|
||||
// Warp the texture coordinates to create a blow-up effect.
|
||||
vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0;
|
||||
vec2 coords = iTexCoord.st * 2.0 - 1.0;
|
||||
float dist = length(coords);
|
||||
coords = (coords / dist * pow(dist, 1.0 + uWarpIntensity)) * 0.5 + 0.5;
|
||||
coords = mix(cogl_tex_coord_in[0].st, coords, progress);
|
||||
coords = mix(iTexCoord.st, coords, progress);
|
||||
|
||||
// Scale down the window according to the warp.
|
||||
float scale = 0.5 * uWarpIntensity * (1.0 - progress);
|
||||
@@ -84,40 +84,37 @@ void main() {
|
||||
for (int i = 0; i < uNumClaws; ++i) {
|
||||
vec2 uv = getClawUV(coords, 1.0 / uClawSize, uSeed * (i + 1));
|
||||
float delay = i / uNumClaws * MAX_SPAWN_TIME;
|
||||
scratchMap = min(scratchMap, clamp(texture2D(uClawTexture, uv).r + delay, 0, 1));
|
||||
scratchMap = min(scratchMap, clamp(texture2D(uClawTexture, uv).r + delay, 0.0, 1.0));
|
||||
}
|
||||
|
||||
// Get the window texture. We shift the texture lookup by the local derivative of
|
||||
// the claw texture in order to mimic some folding distortion.
|
||||
vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * progress * 0.5;
|
||||
cogl_color_out = texture2D(uTexture, coords + offset);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * progress * 0.5;
|
||||
vec4 oColor = getInputColor(coords + offset);
|
||||
|
||||
// Add colorful flashes.
|
||||
float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - progress) + 1;
|
||||
if (flashIntensity < 0 || flashIntensity >= 1) {
|
||||
flashIntensity = 0;
|
||||
float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - progress) + 1.0;
|
||||
if (flashIntensity < 0.0 || flashIntensity >= 1.0) {
|
||||
flashIntensity = 0.0;
|
||||
}
|
||||
|
||||
// Hide flashes where there is now window.
|
||||
vec4 flash = uFlashColor;
|
||||
flash.a *= flashIntensity * cogl_color_out.a * (1.0 - progress);
|
||||
flash.a *= flashIntensity * oColor.a * (1.0 - progress);
|
||||
|
||||
// Hide scratched out parts.
|
||||
cogl_color_out.a *= (scratchMap > progress ? 1 : 0);
|
||||
oColor.a *= (scratchMap > progress ? 1.0 : 0.0);
|
||||
|
||||
// Add flash color.
|
||||
cogl_color_out = alphaOver(cogl_color_out, flash);
|
||||
oColor = alphaOver(oColor, flash);
|
||||
|
||||
// Fade out the remaining shards.
|
||||
float fadeProgress = smoothstep(0, 1, (progress - 1.0 + FF_TIME) / FF_TIME);
|
||||
cogl_color_out.a *= sqrt(1 - fadeProgress * fadeProgress);
|
||||
float fadeProgress = smoothstep(0.0, 1.0, (progress - 1.0 + FF_TIME) / FF_TIME);
|
||||
oColor.a *= sqrt(1.0 - fadeProgress * fadeProgress);
|
||||
|
||||
// These are pretty useful for understanding how this works.
|
||||
// cogl_color_out = vec4(vec3(flashIntensity), 1);
|
||||
// cogl_color_out = vec4(vec3(scratchMap), 1);
|
||||
// oColor = vec4(vec3(flashIntensity), 1);
|
||||
// oColor = vec4(vec3(scratchMap), 1);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
+22
-27
@@ -23,51 +23,46 @@ const float FF_TIME = 0.1; // Relative time for the final fade to transpare
|
||||
const float SCALING = 0.5; // Additional vertical scaling of the window.
|
||||
|
||||
void main() {
|
||||
float progress = uForOpening ? 1.0 - easeOutQuad(uProgress) : easeOutQuad(uProgress);
|
||||
float prog = uForOpening ? 1.0 - easeOutQuad(uProgress) : easeOutQuad(uProgress);
|
||||
|
||||
// Scale down the window vertically.
|
||||
float scale = 1.0 / mix(1.0, SCALING, progress) - 1.0;
|
||||
vec2 coords = cogl_tex_coord_in[0].st;
|
||||
float scale = 1.0 / mix(1.0, SCALING, prog) - 1.0;
|
||||
vec2 coords = iTexCoord.st;
|
||||
coords.y = coords.y * (scale + 1.0) - scale * 0.5;
|
||||
|
||||
// All of these are in [0..1] during the different stages of the animation.
|
||||
// tb refers to the top-bottom animation.
|
||||
// lr refers to the left-right animation.
|
||||
// ff refers to the final fade animation.
|
||||
float tbProgress = smoothstep(0, 1, clamp(progress / TB_TIME, 0, 1));
|
||||
float lrProgress = smoothstep(0, 1, clamp((progress - LR_DELAY) / LR_TIME, 0, 1));
|
||||
float ffProgress = smoothstep(0, 1, clamp((progress - 1.0 + FF_TIME) / FF_TIME, 0, 1));
|
||||
float tbProg = smoothstep(0.0, 1.0, clamp(prog / TB_TIME, 0.0, 1.0));
|
||||
float lrProg = smoothstep(0.0, 1.0, clamp((prog - LR_DELAY) / LR_TIME, 0.0, 1.0));
|
||||
float ffProg = smoothstep(0.0, 1.0, clamp((prog - 1.0 + FF_TIME) / FF_TIME, 0.0, 1.0));
|
||||
|
||||
// This is a top-center-bottom gradient in [0..1..0]
|
||||
float tb = coords.y * 2;
|
||||
tb = tb < 1 ? tb : 2 - tb;
|
||||
float tb = coords.y * 2.0;
|
||||
tb = tb < 1.0 ? tb : 2.0 - tb;
|
||||
|
||||
// This is a left-center-right gradient in [0..1..0]
|
||||
float lr = coords.x * 2;
|
||||
lr = lr < 1 ? lr : 2 - lr;
|
||||
float lr = coords.x * 2.0;
|
||||
lr = lr < 1.0 ? lr : 2.0 - lr;
|
||||
|
||||
// Combine the progress values with the gradients to create the alpha masks.
|
||||
float tbMask = 1 - smoothstep(0, 1, clamp((tbProgress - tb) / BLUR_WIDTH, 0, 1));
|
||||
float lrMask = 1 - smoothstep(0, 1, clamp((lrProgress - lr) / BLUR_WIDTH, 0, 1));
|
||||
float ffMask = 1 - smoothstep(0, 1, ffProgress);
|
||||
float tbMask = 1.0 - smoothstep(0.0, 1.0, clamp((tbProg - tb) / BLUR_WIDTH, 0.0, 1.0));
|
||||
float lrMask = 1.0 - smoothstep(0.0, 1.0, clamp((lrProg - lr) / BLUR_WIDTH, 0.0, 1.0));
|
||||
float ffMask = 1.0 - smoothstep(0.0, 1.0, ffProg);
|
||||
|
||||
// Assemble the final alpha value.
|
||||
float mask = tbMask * lrMask * ffMask;
|
||||
|
||||
cogl_color_out = texture2D(uTexture, coords);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
|
||||
cogl_color_out.rgb =
|
||||
mix(cogl_color_out.rgb, uColor * cogl_color_out.a, smoothstep(0, 1, progress));
|
||||
cogl_color_out.a *= mask;
|
||||
vec4 oColor = getInputColor(coords);
|
||||
oColor.rgb = mix(oColor.rgb, uColor * oColor.a, smoothstep(0.0, 1.0, prog));
|
||||
oColor.a *= mask;
|
||||
|
||||
// These are pretty useful for understanding how this works.
|
||||
// cogl_color_out = vec4(vec3(tbMask), 1);
|
||||
// cogl_color_out = vec4(vec3(lrMask), 1);
|
||||
// cogl_color_out = vec4(vec3(ffMask), 1);
|
||||
// cogl_color_out = vec4(vec3(mask), 1);
|
||||
// oColor = vec4(vec3(tbMask), 1);
|
||||
// oColor = vec4(vec3(lrMask), 1);
|
||||
// oColor = vec4(vec3(ffMask), 1);
|
||||
// oColor = vec4(vec3(mask), 1);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
@@ -19,8 +19,8 @@ uniform float uScale;
|
||||
|
||||
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_SPACING = 40.0 + WISPS_RADIUS;
|
||||
const float WISPS_LAYERS = 8.0;
|
||||
const float WISPS_IN_TIME = 0.5;
|
||||
const float WINDOW_OUT_TIME = 1.0;
|
||||
const float SCALING = 0.9;
|
||||
@@ -36,7 +36,7 @@ float getWisps(vec2 texCoords, float gridSize, vec2 seed) {
|
||||
coords /= gridSize;
|
||||
|
||||
// Get grid cell coordinates in [0..1].
|
||||
vec2 cellUV = mod(coords, vec2(1));
|
||||
vec2 cellUV = mod(coords, vec2(1.0));
|
||||
|
||||
// This is unique for each cell.
|
||||
vec2 cellID = coords - cellUV + vec2(362.456);
|
||||
@@ -47,7 +47,8 @@ float getWisps(vec2 texCoords, float gridSize, vec2 seed) {
|
||||
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)));
|
||||
vec2 offset = vec2(sin(speed * (uProgress * uDuration + 1.0)) * roundness,
|
||||
cos(speed * (uProgress * uDuration + 1.0)));
|
||||
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));
|
||||
@@ -57,7 +58,7 @@ float getWisps(vec2 texCoords, float gridSize, vec2 seed) {
|
||||
// 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(5, 0.01 / pow(dist, 2.0));
|
||||
return min(5.0, 0.01 / pow(dist, 2.0));
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
@@ -68,46 +69,44 @@ void main() {
|
||||
|
||||
// Scale down the window slightly.
|
||||
float scale = 1.0 / mix(1.0, SCALING, progress) - 1.0;
|
||||
vec2 coords = cogl_tex_coord_in[0].st * (scale + 1.0) - scale * 0.5;
|
||||
vec2 coords = iTexCoord.st * (scale + 1.0) - scale * 0.5;
|
||||
|
||||
// Get the color of the window.
|
||||
cogl_color_out = texture2D(uTexture, coords);
|
||||
|
||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
||||
if (cogl_color_out.a > 0) {
|
||||
cogl_color_out.rgb /= cogl_color_out.a;
|
||||
}
|
||||
vec4 oColor = getInputColor(coords);
|
||||
|
||||
// Compute several layers of moving wisps.
|
||||
vec2 uv = (cogl_tex_coord_in[0].st - 0.5) / mix(1.0, 0.5, progress) + 0.5;
|
||||
vec2 uv = (iTexCoord.st - 0.5) / mix(1.0, 0.5, progress) + 0.5;
|
||||
uv /= uScale;
|
||||
float wisps = 0;
|
||||
for (int i = 0; i < WISPS_LAYERS; ++i) {
|
||||
wisps += getWisps(uv * 0.3, WISPS_SPACING, uSeed * (i + 1));
|
||||
float wisps = 0.0;
|
||||
for (float i = 0.0; i < WISPS_LAYERS; ++i) {
|
||||
wisps += getWisps(uv * 0.3, WISPS_SPACING, uSeed * (i + 1.0));
|
||||
}
|
||||
|
||||
// Compute shrinking edge mask.
|
||||
float mask = getRelativeEdgeMask(mix(0.01, 0.5, progress));
|
||||
|
||||
// Compute three different progress values.
|
||||
float wispsIn = smoothstep(0, 1, clamp(progress / 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(progress / WINDOW_OUT_TIME, 0, 1));
|
||||
float wispsIn = smoothstep(0.0, 1.0, clamp(progress / WISPS_IN_TIME, 0.0, 1.0));
|
||||
float wispsOut = smoothstep(
|
||||
0.0, 1.0, clamp((progress - WISPS_IN_TIME) / (1.0 - WISPS_IN_TIME), 0.0, 1.0));
|
||||
float windowOut = smoothstep(0.0, 1.0, clamp(progress / WINDOW_OUT_TIME, 0.0, 1.0));
|
||||
|
||||
// Use a noise function to dissolve the window.
|
||||
float noise = smoothstep(1.0, 0.0, abs(2.0 * simplex2DFractal(uv * uSize / 250) - 1.0));
|
||||
float noise =
|
||||
smoothstep(1.0, 0.0, abs(2.0 * simplex2DFractal(uv * uSize / 250.0) - 1.0));
|
||||
float windowMask = 1.0 - (windowOut < 0.5 ? mix(0.0, noise, windowOut * 2.0)
|
||||
: mix(noise, 1.0, windowOut * 2.0 - 1.0));
|
||||
cogl_color_out.a *= windowMask * mask;
|
||||
oColor.a *= windowMask * mask;
|
||||
|
||||
// Add the wisps.
|
||||
vec4 wispColor = wisps * vec4(uColor, min(wispsIn, 1.0 - wispsOut) * mask);
|
||||
cogl_color_out = alphaOver(cogl_color_out, wispColor);
|
||||
oColor = alphaOver(oColor, wispColor);
|
||||
|
||||
// These are pretty useful for understanding how this works.
|
||||
// cogl_color_out = vec4(vec3(windowMask), 1.0);
|
||||
// cogl_color_out = vec4(vec3(wisps), 1.0);
|
||||
// cogl_color_out = vec4(vec3(noise), 1.0);
|
||||
// cogl_color_out = vec4(vec3(mask*min(wispsIn, 1.0 - wispsOut)), 1.0);
|
||||
// oColor = vec4(vec3(windowMask), 1.0);
|
||||
// oColor = vec4(vec3(wisps), 1.0);
|
||||
// oColor = vec4(vec3(noise), 1.0);
|
||||
// oColor = vec4(vec3(mask*min(wispsIn, 1.0 - wispsOut)), 1.0);
|
||||
|
||||
setOutputColor(oColor);
|
||||
}
|
||||
+10
-11
@@ -48,7 +48,7 @@ var Shader = GObject.registerClass(
|
||||
Signals: {
|
||||
'begin-animation':
|
||||
{param_types: [Gio.Settings.$gtype, GObject.TYPE_BOOLEAN, Clutter.Actor.$gtype]},
|
||||
'update-animation': {param_types: [GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE]}
|
||||
'update-animation': {param_types: [GObject.TYPE_DOUBLE]}
|
||||
}
|
||||
},
|
||||
class Shader extends Shell.GLSLEffect { // --------------------------------------------
|
||||
@@ -68,17 +68,16 @@ var Shader = GObject.registerClass(
|
||||
// Store standard uniform locations.
|
||||
this._uForOpening = this.get_uniform_location('uForOpening');
|
||||
this._uProgress = this.get_uniform_location('uProgress');
|
||||
this._uTime = this.get_uniform_location('uTime');
|
||||
this._uDuration = this.get_uniform_location('uDuration');
|
||||
this._uSize = this.get_uniform_location('uSize');
|
||||
this._uPadding = this.get_uniform_location('uPadding');
|
||||
}
|
||||
|
||||
// This is called once each time the shader is used.
|
||||
beginAnimation(settings, forOpening, actor) {
|
||||
beginAnimation(settings, forOpening, duration, actor) {
|
||||
|
||||
// Reset progress values.
|
||||
// Reset progress value.
|
||||
this._progress = 0;
|
||||
this._time = 0;
|
||||
|
||||
// This is not necessarily symmetric, but I haven't figured out a way to
|
||||
// get the actual values...
|
||||
@@ -86,17 +85,18 @@ var Shader = GObject.registerClass(
|
||||
|
||||
this.set_uniform_float(this._uPadding, 1, [padding]);
|
||||
this.set_uniform_float(this._uForOpening, 1, [forOpening]);
|
||||
this.set_uniform_float(this._uDuration, 1, [duration]);
|
||||
this.set_uniform_float(this._uSize, 2, [actor.width, actor.height]);
|
||||
|
||||
this.emit('begin-animation', settings, forOpening, actor);
|
||||
}
|
||||
|
||||
// This is called at each frame during the animation.
|
||||
updateAnimation(progress, time) {
|
||||
// Store the current time and progress values. The corresponding signal is emitted
|
||||
// each frame in vfunc_paint_target.
|
||||
updateAnimation(progress) {
|
||||
// Store the current progress value. The corresponding signal is emitted each frame
|
||||
// in vfunc_paint_target. We do not emit it here, as the pipeline which may be used
|
||||
// by handlers must not have been created yet.
|
||||
this._progress = progress;
|
||||
this._time = time;
|
||||
}
|
||||
|
||||
// This is called by the constructor. This means, it's only called when the
|
||||
@@ -121,9 +121,8 @@ var Shader = GObject.registerClass(
|
||||
// We use this vfunc to trigger the update as it allows calling this.get_pipeline() in
|
||||
// the handler. This could still be null if called from the updateAnimation() above.
|
||||
vfunc_paint_target(...params) {
|
||||
this.emit('update-animation', this._progress, this._time);
|
||||
this.emit('update-animation', this._progress);
|
||||
this.set_uniform_float(this._uProgress, 1, [this._progress]);
|
||||
this.set_uniform_float(this._uTime, 1, [this._time]);
|
||||
super.vfunc_paint_target(...params);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user