🚚 Move fire shader to its own file

This commit is contained in:
Simon Schneegans
2021-12-22 05:40:42 +01:00
parent e32b11a010
commit 3149371a04
5 changed files with 212 additions and 141 deletions
+8 -140
View File
@@ -21,7 +21,8 @@ const WINDOW_REPOSITIONING_DELAY = imports.ui.workspace.WINDOW_REPOSITIONING_DEL
const ExtensionUtils = imports.misc.extensionUtils;
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 //
@@ -125,149 +126,16 @@ class Extension {
tweakTransition('scale-x', 1);
tweakTransition('scale-y', 1);
// Instead, we add a cool fire shader to our window actor! The noise implementation
// is from https://www.shadertoy.com/view/3tcBzH (CC-BY-NC-SA).
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;
}
`);
// Instead, we add a cool shader to our window actor!
const shader = new FireShader(this._settings);
actor.add_effect(shader);
// Update uniforms at each frame.
transition.connect('new-frame', (t) => {
shader.set_uniform_value('progress', t.get_progress());
shader.set_uniform_value('time', 0.001 * t.get_elapsed_time());
shader.set_uniform_value('sizeX', actor.width);
shader.set_uniform_value('sizeY', actor.height);
shader.set_uniform_value('uProgress', t.get_progress());
shader.set_uniform_value('uTime', 0.001 * t.get_elapsed_time());
shader.set_uniform_value('uSizeX', actor.width);
shader.set_uniform_value('uSizeY', actor.height);
});
});
}