🚚 Move fire shader to its own file
This commit is contained in:
@@ -30,7 +30,7 @@ burn-my-windows@schneegans.github.com.zip: schemas/gschemas.compiled resources/b
|
|||||||
|
|
||||||
@echo "Packing zip file..."
|
@echo "Packing zip file..."
|
||||||
@rm --force burn-my-windows@schneegans.github.com.zip
|
@rm --force burn-my-windows@schneegans.github.com.zip
|
||||||
@zip -r burn-my-windows@schneegans.github.com.zip -- *.js resources/burn-my-windows.gresource schemas/gschemas.compiled metadata.json LICENSE
|
@zip -r burn-my-windows@schneegans.github.com.zip -- *.js src/*/*.js resources/burn-my-windows.gresource schemas/gschemas.compiled metadata.json LICENSE
|
||||||
|
|
||||||
@#Check if the zip size is too big to be uploaded
|
@#Check if the zip size is too big to be uploaded
|
||||||
@if [[ "$$(stat -c %s burn-my-windows@schneegans.github.com.zip)" -gt 4096000 ]]; then \
|
@if [[ "$$(stat -c %s burn-my-windows@schneegans.github.com.zip)" -gt 4096000 ]]; then \
|
||||||
|
|||||||
+8
-140
@@ -21,7 +21,8 @@ const WINDOW_REPOSITIONING_DELAY = imports.ui.workspace.WINDOW_REPOSITIONING_DEL
|
|||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
const Me = imports.misc.extensionUtils.getCurrentExtension();
|
const Me = imports.misc.extensionUtils.getCurrentExtension();
|
||||||
const utils = Me.imports.utils;
|
const utils = Me.imports.src.common.utils;
|
||||||
|
const FireShader = Me.imports.src.extension.FireShader.FireShader;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// This extensions modifies the window-close animation to look like the window was set //
|
// This extensions modifies the window-close animation to look like the window was set //
|
||||||
@@ -125,149 +126,16 @@ class Extension {
|
|||||||
tweakTransition('scale-x', 1);
|
tweakTransition('scale-x', 1);
|
||||||
tweakTransition('scale-y', 1);
|
tweakTransition('scale-y', 1);
|
||||||
|
|
||||||
// Instead, we add a cool fire shader to our window actor! The noise implementation
|
// Instead, we add a cool shader to our window actor!
|
||||||
// is from https://www.shadertoy.com/view/3tcBzH (CC-BY-NC-SA).
|
const shader = new FireShader(this._settings);
|
||||||
const shader = new Clutter.ShaderEffect({
|
|
||||||
shader_type: Clutter.ShaderType.FRAGMENT_SHADER,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load the gradient values from the settings. We directly inject the values in the
|
|
||||||
// GLSL code below. The shader is compiled once for each window-closing anyways. In
|
|
||||||
// the future, we my want to prevent this frequent recompilations of shaders,
|
|
||||||
// though.
|
|
||||||
const gradient = [];
|
|
||||||
for (let i = 1; i <= 5; i++) {
|
|
||||||
const color =
|
|
||||||
Clutter.Color.from_string(this._settings.get_string('fire-color-' + i))[1];
|
|
||||||
gradient.push(`vec4(${color.red / 255}, ${color.green / 255}, ${
|
|
||||||
color.blue / 255}, ${color.alpha / 255})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
shader.set_shader_source(`
|
|
||||||
uniform sampler2D texture;
|
|
||||||
uniform float progress;
|
|
||||||
uniform float time;
|
|
||||||
uniform int sizeX;
|
|
||||||
uniform int sizeY;
|
|
||||||
|
|
||||||
// These may be configurable in the future.
|
|
||||||
const float EDGE_BLEND = 70;
|
|
||||||
const float BURN_RANGE = 0.1;
|
|
||||||
const float BURN_TIME = 0.2;
|
|
||||||
const vec2 FIRE_SCALE = vec2(400, 600) * ${
|
|
||||||
this._settings.get_double('flame-scale')};
|
|
||||||
const float FIRE_SPEED = ${this._settings.get_double('flame-movement-speed')};
|
|
||||||
|
|
||||||
float rand(vec2 co) {
|
|
||||||
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
|
||||||
}
|
|
||||||
|
|
||||||
float hermite(float t) {
|
|
||||||
return t * t * (3.0 - 2.0 * t);
|
|
||||||
}
|
|
||||||
|
|
||||||
float noiseImpl(vec2 co, float frequency) {
|
|
||||||
vec2 v = vec2(co.x * frequency, co.y * frequency);
|
|
||||||
|
|
||||||
float ix1 = floor(v.x);
|
|
||||||
float iy1 = floor(v.y);
|
|
||||||
float ix2 = floor(v.x + 1.0);
|
|
||||||
float iy2 = floor(v.y + 1.0);
|
|
||||||
|
|
||||||
float fx = hermite(fract(v.x));
|
|
||||||
float fy = hermite(fract(v.y));
|
|
||||||
|
|
||||||
float fade1 = mix(rand(vec2(ix1, iy1)), rand(vec2(ix2, iy1)), fx);
|
|
||||||
float fade2 = mix(rand(vec2(ix1, iy2)), rand(vec2(ix2, iy2)), fx);
|
|
||||||
|
|
||||||
return mix(fade1, fade2, fy);
|
|
||||||
}
|
|
||||||
|
|
||||||
float pNoise(vec2 co, float freq, int steps, float persistence) {
|
|
||||||
float value = 0.0;
|
|
||||||
float ampl = 1.0;
|
|
||||||
float sum = 0.0;
|
|
||||||
for(int i=0 ; i<steps ; i++) {
|
|
||||||
sum += ampl;
|
|
||||||
value += noiseImpl(co, freq) * ampl;
|
|
||||||
freq *= 2.0;
|
|
||||||
ampl *= persistence;
|
|
||||||
}
|
|
||||||
return value / sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 getFireColor(float v) {
|
|
||||||
const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8);
|
|
||||||
const vec4 colors[5] = vec4[](
|
|
||||||
${gradient[0]},
|
|
||||||
${gradient[1]},
|
|
||||||
${gradient[2]},
|
|
||||||
${gradient[3]},
|
|
||||||
${gradient[4]}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (v < steps[0]) {
|
|
||||||
return colors[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<4; ++i) {
|
|
||||||
if (v <= steps[i+1]) {
|
|
||||||
return mix(colors[i], colors[i+1], vec4(v - steps[i])/(steps[i+1]-steps[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return colors[4];
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
float burnProgress = clamp(progress/BURN_TIME, 0, 1);
|
|
||||||
float afterBurnProgress = clamp((progress-BURN_TIME)/(1-BURN_TIME), 0, 1);
|
|
||||||
|
|
||||||
// Gradient from top to bottom.
|
|
||||||
float t = cogl_tex_coord_in[0].t * (1 - BURN_RANGE);
|
|
||||||
|
|
||||||
// Visible part of the window. Gradually dissolves towards the bottom.
|
|
||||||
float alpha = 1 - clamp((burnProgress - t) / BURN_RANGE, 0, 1);
|
|
||||||
|
|
||||||
// Get window texture.
|
|
||||||
cogl_color_out = texture2D(texture, cogl_tex_coord_in[0].st) * alpha;
|
|
||||||
|
|
||||||
// Gradient from top burning window.
|
|
||||||
float mask = clamp(t*(1-alpha)/burnProgress, 0, 1);
|
|
||||||
|
|
||||||
// Fade-out when the window burned down.
|
|
||||||
if (progress > BURN_TIME) {
|
|
||||||
mask *= mix(1, 1-t, afterBurnProgress) * pow(1-afterBurnProgress, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fade at window borders.
|
|
||||||
vec2 pos = cogl_tex_coord_in[0].st * vec2(sizeX, sizeY);
|
|
||||||
mask *= clamp(pos.x / EDGE_BLEND, 0, 1);
|
|
||||||
mask *= clamp(pos.y / EDGE_BLEND, 0, 1);
|
|
||||||
mask *= clamp((sizeX - pos.x) / EDGE_BLEND, 0, 1);
|
|
||||||
mask *= clamp((sizeY - pos.y) / EDGE_BLEND, 0, 1);
|
|
||||||
|
|
||||||
vec2 firePos = pos / FIRE_SCALE;
|
|
||||||
firePos.y += time * FIRE_SPEED;
|
|
||||||
float noise = pNoise(firePos, 10.0, 5, 0.5);
|
|
||||||
|
|
||||||
// Modulate noise by mask and map to color.
|
|
||||||
vec4 color = getFireColor(noise*mask);
|
|
||||||
color.rgb *= color.a;
|
|
||||||
|
|
||||||
// cogl_color_out = vec4(mask);
|
|
||||||
cogl_color_out += color;
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
|
|
||||||
actor.add_effect(shader);
|
actor.add_effect(shader);
|
||||||
|
|
||||||
// Update uniforms at each frame.
|
// Update uniforms at each frame.
|
||||||
transition.connect('new-frame', (t) => {
|
transition.connect('new-frame', (t) => {
|
||||||
shader.set_uniform_value('progress', t.get_progress());
|
shader.set_uniform_value('uProgress', t.get_progress());
|
||||||
shader.set_uniform_value('time', 0.001 * t.get_elapsed_time());
|
shader.set_uniform_value('uTime', 0.001 * t.get_elapsed_time());
|
||||||
shader.set_uniform_value('sizeX', actor.width);
|
shader.set_uniform_value('uSizeX', actor.width);
|
||||||
shader.set_uniform_value('sizeY', actor.height);
|
shader.set_uniform_value('uSizeY', actor.height);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ) ( //
|
||||||
|
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
|
||||||
|
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
|
||||||
|
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
|
||||||
|
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
|
||||||
|
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
|
||||||
|
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
|
||||||
|
// |__/ //
|
||||||
|
// Copyright (c) 2021 Simon Schneegans //
|
||||||
|
// Released under the GPLv3 or later. See LICENSE file for details. //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {Clutter, GObject} = imports.gi;
|
||||||
|
|
||||||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
|
const Me = imports.misc.extensionUtils.getCurrentExtension();
|
||||||
|
const shaderSnippets = Me.imports.src.extension.shaderSnippets;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
var FireShader = GObject.registerClass({Properties: {}, Signals: {}},
|
||||||
|
class FireShader extends Clutter.ShaderEffect {
|
||||||
|
_init(settings) {
|
||||||
|
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
|
||||||
|
|
||||||
|
// Load the gradient values from the settings. We directly inject the values in the
|
||||||
|
// GLSL code below. The shader is compiled once for each window-closing anyways. In
|
||||||
|
// the future, we my want to prevent this frequent recompilations of shaders,
|
||||||
|
// though.
|
||||||
|
const gradient = [];
|
||||||
|
for (let i = 1; i <= 5; i++) {
|
||||||
|
const color = Clutter.Color.from_string(settings.get_string('fire-color-' + i))[1];
|
||||||
|
gradient.push(`vec4(${color.red / 255}, ${color.green / 255}, ${
|
||||||
|
color.blue / 255}, ${color.alpha / 255})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.set_shader_source(`
|
||||||
|
${shaderSnippets.standardUniforms()}
|
||||||
|
${shaderSnippets.noise()}
|
||||||
|
${shaderSnippets.effectMask()}
|
||||||
|
|
||||||
|
// These may be configurable in the future.
|
||||||
|
const float EDGE_FADE = 70;
|
||||||
|
const float FADE_WIDTH = 0.1;
|
||||||
|
const float HIDE_TIME = 0.2;
|
||||||
|
const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')};
|
||||||
|
const float FIRE_SPEED = ${settings.get_double('flame-movement-speed')};
|
||||||
|
|
||||||
|
vec4 getFireColor(float v) {
|
||||||
|
const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8);
|
||||||
|
const vec4 colors[5] = vec4[](
|
||||||
|
${gradient[0]},
|
||||||
|
${gradient[1]},
|
||||||
|
${gradient[2]},
|
||||||
|
${gradient[3]},
|
||||||
|
${gradient[4]}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (v < steps[0]) {
|
||||||
|
return colors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<4; ++i) {
|
||||||
|
if (v <= steps[i+1]) {
|
||||||
|
return mix(colors[i], colors[i+1], vec4(v -
|
||||||
|
steps[i])/(steps[i+1]-steps[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors[4];
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
|
||||||
|
// Get a noise value.
|
||||||
|
vec2 uv = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY) / FIRE_SCALE;
|
||||||
|
uv.y += uTime * FIRE_SPEED;
|
||||||
|
float noise = perlinNoise(uv, 10.0, 5, 0.5);
|
||||||
|
|
||||||
|
// Modulate noise by mask.
|
||||||
|
vec2 effectMask = effectMask(HIDE_TIME, FADE_WIDTH, EDGE_FADE);
|
||||||
|
noise *= effectMask.y;
|
||||||
|
|
||||||
|
// Map noise value to color.
|
||||||
|
vec4 fire = getFireColor(noise);
|
||||||
|
fire.rgb *= fire.a;
|
||||||
|
|
||||||
|
// Get window texture.
|
||||||
|
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x;
|
||||||
|
|
||||||
|
// Add fire.
|
||||||
|
cogl_color_out += fire;
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ) ( //
|
||||||
|
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
|
||||||
|
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
|
||||||
|
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
|
||||||
|
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
|
||||||
|
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
|
||||||
|
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
|
||||||
|
// |__/ //
|
||||||
|
// Copyright (c) 2021 Simon Schneegans //
|
||||||
|
// Released under the GPLv3 or later. See LICENSE file for details. //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function standardUniforms() {
|
||||||
|
return `
|
||||||
|
uniform sampler2D uTexture;
|
||||||
|
uniform float uProgress;
|
||||||
|
uniform float uTime;
|
||||||
|
uniform int uSizeX;
|
||||||
|
uniform int uSizeY;
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The noise implementation is from https://www.shadertoy.com/view/3tcBzH
|
||||||
|
// (CC-BY-NC-SA).
|
||||||
|
function noise() {
|
||||||
|
return `
|
||||||
|
float rand(vec2 co) {
|
||||||
|
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||||
|
}
|
||||||
|
|
||||||
|
float hermite(float t) {
|
||||||
|
return t * t * (3.0 - 2.0 * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
float noiseImpl(vec2 co, float frequency) {
|
||||||
|
vec2 v = vec2(co.x * frequency, co.y * frequency);
|
||||||
|
|
||||||
|
float ix1 = floor(v.x);
|
||||||
|
float iy1 = floor(v.y);
|
||||||
|
float ix2 = floor(v.x + 1.0);
|
||||||
|
float iy2 = floor(v.y + 1.0);
|
||||||
|
|
||||||
|
float fx = hermite(fract(v.x));
|
||||||
|
float fy = hermite(fract(v.y));
|
||||||
|
|
||||||
|
float fade1 = mix(rand(vec2(ix1, iy1)), rand(vec2(ix2, iy1)), fx);
|
||||||
|
float fade2 = mix(rand(vec2(ix1, iy2)), rand(vec2(ix2, iy2)), fx);
|
||||||
|
|
||||||
|
return mix(fade1, fade2, fy);
|
||||||
|
}
|
||||||
|
|
||||||
|
float perlinNoise(vec2 co, float freq, int steps, float persistence) {
|
||||||
|
float value = 0.0;
|
||||||
|
float ampl = 1.0;
|
||||||
|
float sum = 0.0;
|
||||||
|
|
||||||
|
for(int i=0 ; i<steps ; i++) {
|
||||||
|
sum += ampl;
|
||||||
|
value += noiseImpl(co, freq) * ampl;
|
||||||
|
freq *= 2.0;
|
||||||
|
ampl *= persistence;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value / sum;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function effectMask() {
|
||||||
|
return `
|
||||||
|
vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) {
|
||||||
|
float burnProgress = clamp(uProgress/hideTime, 0, 1);
|
||||||
|
float afterBurnProgress = clamp((uProgress-hideTime)/(1-hideTime), 0, 1);
|
||||||
|
|
||||||
|
// Gradient from top to bottom.
|
||||||
|
float t = cogl_tex_coord_in[0].t * (1 - fadeWidth);
|
||||||
|
|
||||||
|
// Visible part of the window. Gradually dissolves towards the bottom.
|
||||||
|
float windowMask = 1 - clamp((burnProgress - t) / fadeWidth, 0, 1);
|
||||||
|
|
||||||
|
// Gradient from top burning window.
|
||||||
|
float effectMask = clamp(t*(1-windowMask)/burnProgress, 0, 1);
|
||||||
|
|
||||||
|
// Fade-out when the window burned down.
|
||||||
|
if (uProgress > hideTime) {
|
||||||
|
effectMask *= mix(1, 1-t, afterBurnProgress) * pow(1-afterBurnProgress, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fade at window borders.
|
||||||
|
vec2 pos = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY);
|
||||||
|
effectMask *= clamp(pos.x / edgeFadeWidth, 0, 1);
|
||||||
|
effectMask *= clamp(pos.y / edgeFadeWidth, 0, 1);
|
||||||
|
effectMask *= clamp((uSizeX - pos.x) / edgeFadeWidth, 0, 1);
|
||||||
|
effectMask *= clamp((uSizeY - pos.y) / edgeFadeWidth, 0, 1);
|
||||||
|
|
||||||
|
return vec2(windowMask, effectMask);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user