From 9d5be1660d8f74038ebed3d74fdbc809e43787ae Mon Sep 17 00:00:00 2001 From: Nippy Date: Fri, 9 Oct 2026 17:23:53 +0200 Subject: gnome fix --- .../blur-my-shell@aunetx/effects/color.glsl | 16 +- .../blur-my-shell@aunetx/effects/color.js | 76 +- .../blur-my-shell@aunetx/effects/corner.glsl | 33 +- .../blur-my-shell@aunetx/effects/corner.js | 105 +-- .../blur-my-shell@aunetx/effects/derivative.glsl | 57 +- .../blur-my-shell@aunetx/effects/derivative.js | 73 +- .../blur-my-shell@aunetx/effects/downscale.glsl | 36 +- .../blur-my-shell@aunetx/effects/downscale.js | 80 +- .../blur-my-shell@aunetx/effects/effect_groups.js | 31 + .../blur-my-shell@aunetx/effects/effects.js | 175 ++++- .../effects/gaussian_blur.glsl | 29 +- .../blur-my-shell@aunetx/effects/gaussian_blur.js | 59 +- .../blur-my-shell@aunetx/effects/hsl_to_rgb.glsl | 5 +- .../blur-my-shell@aunetx/effects/hsl_to_rgb.js | 59 +- .../blur-my-shell@aunetx/effects/luminosity.glsl | 11 +- .../blur-my-shell@aunetx/effects/luminosity.js | 64 +- .../effects/monte_carlo_blur.glsl | 20 +- .../effects/monte_carlo_blur.js | 58 +- .../effects/native_dynamic_gaussian_blur.js | 54 +- .../effects/native_static_gaussian_blur.js | 19 +- .../blur-my-shell@aunetx/effects/noise.glsl | 12 +- .../blur-my-shell@aunetx/effects/noise.js | 58 +- .../blur-my-shell@aunetx/effects/pixelize.js | 49 +- .../blur-my-shell@aunetx/effects/refraction.glsl | 412 ++++++++++ .../blur-my-shell@aunetx/effects/refraction.js | 849 +++++++++++++++++++++ .../blur-my-shell@aunetx/effects/rgb_to_hsl.glsl | 5 +- .../blur-my-shell@aunetx/effects/rgb_to_hsl.js | 59 +- .../blur-my-shell@aunetx/effects/upscale.glsl | 26 +- .../blur-my-shell@aunetx/effects/upscale.js | 78 +- 29 files changed, 2168 insertions(+), 440 deletions(-) create mode 100644 raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effect_groups.js create mode 100644 raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.glsl create mode 100644 raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.js (limited to 'raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects') diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.glsl index 5df6512..af9b1df 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.glsl @@ -3,6 +3,7 @@ uniform float red; uniform float green; uniform float blue; uniform float blend; +uniform float opacity_factor; uniform int mode; const int NORMAL = 0; @@ -53,7 +54,7 @@ float soft_light_channel(float base, float _blend) { vec3 get_blend(vec3 base, vec3 _blend) { if (mode == MULTIPLY) return base * _blend; - if (mode == SCREEN) return 1 - (1 - base) * (1 - _blend); + if (mode == SCREEN) return 1.0 - (1.0 - base) * (1.0 - _blend); if (mode == OVERLAY) { vec3 result; result.r = base.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r)); @@ -63,10 +64,10 @@ vec3 get_blend(vec3 base, vec3 _blend) { } if (mode == DARKEN) return min(base, _blend); if (mode == LIGHTEN) return max(base, _blend); - if (mode == PLUS_DARKER) return base + _blend - 1; + if (mode == PLUS_DARKER) return base + _blend - vec3(1.0); if (mode == PLUS_LIGHTER) return base + _blend; - if (mode == COLOR_DODGE) return base / (1 - _blend); - if (mode == COLOR_BURN) return 1 - (1 - base) / _blend; + if (mode == COLOR_DODGE) return base / max(vec3(1e-6), 1.0 - _blend); + if (mode == COLOR_BURN) return 1.0 - (1.0 - base) / max(vec3(1e-6), _blend); if (mode == HARD_LIGHT) { vec3 result; result.r = _blend.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r)); @@ -78,7 +79,7 @@ vec3 get_blend(vec3 base, vec3 _blend) { return vec3(soft_light_channel(base.r, _blend.r), soft_light_channel(base.g, _blend.g), soft_light_channel(base.b, _blend.b)); } if (mode == DIFFERENCE) return abs(base - _blend); - if (mode == EXCLUSION) return 0.5 - 2 * (base - 0.5) * (_blend - 0.5); + if (mode == EXCLUSION) return 0.5 - 2.0 * (base - 0.5) * (_blend - 0.5); if (mode == HUE) { vec3 base_hsl = rgb_to_hsl(base); vec3 blend_hsl = rgb_to_hsl(_blend); @@ -106,6 +107,7 @@ void main() { vec4 c = texture2D(tex, cogl_tex_coord_in[0].st); vec3 pix_color = c.xyz; vec3 color = get_blend(pix_color, vec3(red, green, blue)); + float amount = blend * opacity_factor; - cogl_color_out = vec4(mix(pix_color, color, blend), 1.); -} \ No newline at end of file + cogl_color_out = vec4(mix(pix_color, color, amount), c.a); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.js index 1f4bdf4..95ce4c1 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/color.js @@ -1,20 +1,21 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'color.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { color: [0.0, 0.0, 0.0, 0.0], - blend_mode: 0 + blend_mode: 0, + opacity_factor: 1 }; -export const ColorEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const COLOR_EFFECT_META = { GTypeName: "ColorEffect", Properties: { 'red': GObject.ParamSpec.double( @@ -56,31 +57,37 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ? GObject.ParamFlags.READWRITE, 0, 17, 0, + ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, ) } - // Normal (0), Multiply (1), Screen (2), Overlay (3), Darken (4), Lighten (5), Plus darker (6), Plus lighter (7), Color dodge (8), - // Color burn (9), Hard light (10), Soft light (11), Difference (12), Exclusion (13), Hue (14), Saturation (15), Color (16), - // Luminosity (17) - }, class ColorEffect extends Clutter.ShaderEffect { +}; + +const ColorEffectClass = utils.IS_IN_PREFERENCES ? null : class ColorEffect extends Clutter.ShaderEffect { + constructor(params) { - // initialize without color as a parameter - const { color, ...parent_params } = params; - super(parent_params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); + this._red = null; this._green = null; this._blue = null; this._blend = null; this._blend_mode = null; - - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + this._opacity_factor = null; // set params; utils.setup_params doesn't work here with color - this.color = 'color' in params ? color : this.constructor.default_params.color; + this.color = 'color' in params ? params.color : this.constructor.default_params.color; this.blend_mode = 'blend_mode' in params ? params.blend_mode : this.constructor.default_params.blend_mode; + this.opacity_factor = 'opacity_factor' in params ? params.opacity_factor : this.constructor.default_params.opacity_factor; } static get default_params() { @@ -95,7 +102,7 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ? if (this._red !== value) { this._red = value; - this.set_uniform_value('red', parseFloat(this._red - 1e-6)); + uniforms.set_uniform(this, 'red', parseFloat(this._red - 1e-6)); } } @@ -107,7 +114,7 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ? if (this._green !== value) { this._green = value; - this.set_uniform_value('green', parseFloat(this._green - 1e-6)); + uniforms.set_uniform(this, 'green', parseFloat(this._green - 1e-6)); } } @@ -119,7 +126,7 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ? if (this._blue !== value) { this._blue = value; - this.set_uniform_value('blue', parseFloat(this._blue - 1e-6)); + uniforms.set_uniform(this, 'blue', parseFloat(this._blue - 1e-6)); } } @@ -131,7 +138,7 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ? if (this._blend !== value) { this._blend = value; - this.set_uniform_value('blend', parseFloat(this._blend - 1e-6)); + uniforms.set_uniform(this, 'blend', parseFloat(this._blend - 1e-6)); this.set_enabled(this.blend > 0); } } @@ -144,7 +151,19 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ? if (this._blend_mode !== value) { this._blend_mode = value; - this.set_uniform_value('mode', this._blend_mode); + uniforms.set_uniform(this, 'mode', this._blend_mode); + } + } + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); } } @@ -164,5 +183,16 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ? set(params) { this.color = params.color; this.blend_mode = params.blend_mode; + if ('opacity_factor' in params) + this.opacity_factor = params.opacity_factor; } - }); \ No newline at end of file + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + super.vfunc_paint_target(paint_node, paint_context); + } +}; + +export const ColorEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(COLOR_EFFECT_META, ColorEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.glsl index 0b7b0fb..fa5f45c 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.glsl @@ -5,9 +5,9 @@ uniform sampler2D tex; uniform float radius; uniform float width; uniform float height; -uniform bool corners_top; -uniform bool corners_bottom; -uniform bool straight_corners; +uniform int corners_top; +uniform int corners_bottom; +uniform int straight_corners; uniform float clip_x0; uniform float clip_y0; @@ -30,17 +30,20 @@ float circle_bounds(vec2 p, vec2 center, float clip_radius) { } vec4 getTexture(vec2 uv) { - if (uv.x < 2. / width) - uv.x = 2. / width; + float w = max(1.0, width); + float h = max(1.0, height); - if (uv.y < 2. / height) - uv.y = 2. / height; + if (uv.x < 2. / w) + uv.x = 2. / w; - if (uv.x > 1. - 3. / width) - uv.x = 1. - 3. / width; + if (uv.y < 2. / h) + uv.y = 2. / h; - if (uv.y > 1. - 3. / height) - uv.y = 1. - 3. / height; + if (uv.x > 1. - 3. / w) + uv.x = 1. - 3. / w; + + if (uv.y > 1. - 3. / h) + uv.y = 1. - 3. / h; return texture2D(tex, uv); } @@ -66,11 +69,11 @@ float rounded_rect_coverage(vec2 p, vec4 bounds, float clip_radius) { float center_top = bounds.y + clip_radius; float center_bottom = bounds.w - clip_radius; - if (straight_corners) + if (straight_corners != 0) return 1.0; - else if (corners_top && p.y < center_top) + else if (corners_top != 0 && p.y < center_top) center.y = center_top + 2.; - else if (corners_bottom && p.y > center_bottom) + else if (corners_bottom != 0 && p.y > center_bottom) center.y = center_bottom - 1.; else return 1.0; @@ -93,4 +96,4 @@ void main(void) { float alpha = rounded_rect_coverage(pos, bounds, radius); cogl_color_out = vec4(c.rgb * alpha, min(alpha, c.a)); -} \ No newline at end of file +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.js index 1727e30..6a44430 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/corner.js @@ -1,21 +1,24 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const St = await utils.import_in_shell_only('gi://St'); const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'corner.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { radius: 12, width: 0, height: 0, corners_top: true, corners_bottom: true, - clip: [0, 0, -1, -1] + clip: [0, 0, -1, -1], + // Reset on reuse: `EffectsManager` pools `CornerEffect` instances, and a + // pooled instance could otherwise keep rendering square (see corner.glsl). + straight_corners: false, }; -export const CornerEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const CORNER_EFFECT_META = { GTypeName: "CornerEffect", Properties: { 'radius': GObject.ParamSpec.double( @@ -56,20 +59,15 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? GObject.ParamFlags.READWRITE, true, ), - // FIXME this works but it logs an error, because I'm not a double... - // I don't want to fiddle with GVariants again - 'clip': GObject.ParamSpec.double( - `clip`, - `Clip`, - `Clip`, - GObject.ParamFlags.READWRITE, - 0.0, Number.MAX_SAFE_INTEGER, - 0.0, - ), } - }, class CornerEffect extends Clutter.ShaderEffect { +}; + +const CornerEffectClass = utils.IS_IN_PREFERENCES ? null : class CornerEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); this._clip_x0 = null; this._clip_y0 = null; @@ -77,12 +75,6 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? this._clip_height = null; utils.setup_params(this, params); - this.straight_corners = false; - - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); const theme_context = St.ThemeContext.get_for_stage(global.stage); theme_context.connectObject('notify::scale-factor', _ => this.update_radius(), this); @@ -113,7 +105,7 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? if (this._clip_width >= 0 || this._clip_height >= 0) radius = Math.min(radius, this._clip_width / 2, this._clip_height / 2); - this.set_uniform_value('radius', parseFloat(radius - 1e-6)); + uniforms.set_uniform(this, 'radius', parseFloat(radius - 1e-6)); } get width() { @@ -121,10 +113,11 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? } set width(value) { - if (this._width !== value) { - this._width = value; + const v = Math.max(1, value || 1); + if (this._width !== v) { + this._width = v; - this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); + uniforms.set_uniform(this, 'width', parseFloat(this._width + 3.0 - 1e-6)); this.update_radius(); } } @@ -134,10 +127,11 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? } set height(value) { - if (this._height !== value) { - this._height = value; + const v = Math.max(1, value || 1); + if (this._height !== v) { + this._height = v; - this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); + uniforms.set_uniform(this, 'height', parseFloat(this._height + 3.0 - 1e-6)); this.update_radius(); } } @@ -150,7 +144,7 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? if (this._corners_top !== value) { this._corners_top = value; - this.set_uniform_value('corners_top', this._corners_top ? 1 : 0); + uniforms.set_uniform(this, 'corners_top', this._corners_top ? 1 : 0); } } @@ -162,7 +156,7 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? if (this._corners_bottom !== value) { this._corners_bottom = value; - this.set_uniform_value('corners_bottom', this._corners_bottom ? 1 : 0); + uniforms.set_uniform(this, 'corners_bottom', this._corners_bottom ? 1 : 0); } } @@ -174,20 +168,37 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? if (this._straight_corners !== value) { this._straight_corners = value; - this.set_uniform_value('straight_corners', this._straight_corners ? 1 : 0); + uniforms.set_uniform(this, 'straight_corners', this._straight_corners ? 1 : 0); } } + detach_actor_clip_sync(actor = this.get_actor()) { + if (!actor || !this._actor_connection_clip_rect_id) + return; + + actor.disconnect(this._actor_connection_clip_rect_id); + + this._actor_connection_clip_rect_id = null; + } + + sync_actor_clip(actor) { + this.detach_actor_clip_sync(actor); + this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; + this._actor_connection_clip_rect_id = actor.connect('notify::clip-rect', _ => { + this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; + }); + } + get clip() { return [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height]; } set clip(value) { [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height] = value; - this.set_uniform_value('clip_x0', parseFloat(this._clip_x0 - 1e-6)); - this.set_uniform_value('clip_y0', parseFloat(this._clip_y0 - 1e-6)); - this.set_uniform_value('clip_width', parseFloat(this._clip_width + 3 - 1e-6)); - this.set_uniform_value('clip_height', parseFloat(this._clip_height + 3 - 1e-6)); + uniforms.set_uniform(this, 'clip_x0', parseFloat(this._clip_x0 - 1e-6)); + uniforms.set_uniform(this, 'clip_y0', parseFloat(this._clip_y0 - 1e-6)); + uniforms.set_uniform(this, 'clip_width', parseFloat(this._clip_width <= 0 ? -1 : this._clip_width + 3 - 1e-6)); + uniforms.set_uniform(this, 'clip_height', parseFloat(this._clip_height <= 0 ? -1 : this._clip_height + 3 - 1e-6)); this.update_radius(); } @@ -196,10 +207,7 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? let old_actor = this.get_actor(); old_actor?.disconnect(this._actor_connection_size_id); } - if (this._actor_connection_clip_rect_id) { - let old_actor = this.get_actor(); - old_actor?.disconnect(this._actor_connection_clip_rect_id); - } + this.detach_actor_clip_sync(); if (actor) { this.width = actor.width; @@ -209,16 +217,21 @@ export const CornerEffect = utils.IS_IN_PREFERENCES ? this.height = actor.height; }); - this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; - this._actor_connection_clip_rect_id = actor.connect('notify::clip-rect', _ => { - this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; - }); + this.sync_actor_clip(actor); } else { this._actor_connection_size_id = null; - this._actor_connection_clip_rect_id = null; } super.vfunc_set_actor(actor); } - }); \ No newline at end of file + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + super.vfunc_paint_target(paint_node, paint_context); + } +}; + +export const CornerEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(CORNER_EFFECT_META, CornerEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.glsl index 64c1682..b497b69 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.glsl @@ -2,21 +2,22 @@ uniform sampler2D tex; uniform int operation; uniform float width; uniform float height; +uniform float opacity_factor; #define CORRECTION 2.25 -#define SIZE_ADDITION 3 +#define SIZE_ADDITION 3.0 vec4 get_texture_at_position(vec2 position) { vec2 raw_position = position + vec2(CORRECTION, CORRECTION); - vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + vec2 raw_uv = raw_position / vec2(max(1.0, width + SIZE_ADDITION), max(1.0, height + SIZE_ADDITION)); return texture2D(tex, raw_uv); } vec4 try_get_texture_at_position(vec2 position, inout int count) { if (any(greaterThanEqual(position, vec2(width, height))) || - any(lessThan(position, vec2(0, 0)))) { - return vec4(0); + any(lessThan(position, vec2(0.0, 0.0)))) { + return vec4(0.0); } else { count++; return get_texture_at_position(position); @@ -31,41 +32,45 @@ ivec2 get_corrected_position() { void main() { ivec2 corrected_position = get_corrected_position(); + vec4 source_color = get_texture_at_position(vec2(corrected_position)); + vec4 effect_color = source_color; // 1-step derivative if (operation == 0) { - vec4 color = vec4(0); + vec4 color = vec4(0.0); int c = 0; - color += try_get_texture_at_position(corrected_position + vec2(0, 1), c); - color -= try_get_texture_at_position(corrected_position + vec2(0, 0), c); - color += try_get_texture_at_position(corrected_position + vec2(1, 0), c); - color -= try_get_texture_at_position(corrected_position + vec2(0, 0), c); + color += try_get_texture_at_position(vec2(corrected_position) + vec2(0.0, 1.0), c); + color -= try_get_texture_at_position(vec2(corrected_position) + vec2(0.0, 0.0), c); + color += try_get_texture_at_position(vec2(corrected_position) + vec2(1.0, 0.0), c); + color -= try_get_texture_at_position(vec2(corrected_position) + vec2(0.0, 0.0), c); if (c < 4) { - color = vec4(0); + color = vec4(0.0); } - cogl_color_out = vec4(color.xyz, 1); + effect_color = vec4(color.xyz, source_color.a); } else // 2-step derivative if (operation == 1) { - vec4 color = vec4(0); + vec4 color = vec4(0.0); int c = 0; - color += try_get_texture_at_position(corrected_position + vec2(0, 1), c); - color -= try_get_texture_at_position(corrected_position + vec2(0, -1), c); - color += try_get_texture_at_position(corrected_position + vec2(1, 0), c); - color -= try_get_texture_at_position(corrected_position + vec2(-1, 0), c); + color += try_get_texture_at_position(vec2(corrected_position) + vec2(0.0, 1.0), c); + color -= try_get_texture_at_position(vec2(corrected_position) + vec2(0.0, -1.0), c); + color += try_get_texture_at_position(vec2(corrected_position) + vec2(1.0, 0.0), c); + color -= try_get_texture_at_position(vec2(corrected_position) + vec2(-1.0, 0.0), c); if (c < 4) { - color = vec4(0); + color = vec4(0.0); } - cogl_color_out = vec4(color.xyz / 2, 1); + effect_color = vec4(color.xyz / 2.0, source_color.a); } else // laplacian if (operation == 2) { - vec4 color = vec4(0); - color = -4 * get_texture_at_position(corrected_position); - color += get_texture_at_position(corrected_position + vec2(0, 1)); - color += get_texture_at_position(corrected_position + vec2(0, -1)); - color += get_texture_at_position(corrected_position + vec2(1, 0)); - color += get_texture_at_position(corrected_position + vec2(-1, 0)); - cogl_color_out = vec4(color.xyz, 1); + vec4 color = vec4(0.0); + color = -4.0 * get_texture_at_position(vec2(corrected_position)); + color += get_texture_at_position(vec2(corrected_position) + vec2(0.0, 1.0)); + color += get_texture_at_position(vec2(corrected_position) + vec2(0.0, -1.0)); + color += get_texture_at_position(vec2(corrected_position) + vec2(1.0, 0.0)); + color += get_texture_at_position(vec2(corrected_position) + vec2(-1.0, 0.0)); + effect_color = vec4(color.xyz, source_color.a); } -} \ No newline at end of file + + cogl_color_out = mix(source_color, effect_color, opacity_factor); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.js index 04d6100..a2d2bef 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/derivative.js @@ -1,18 +1,18 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'derivative.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { - operation: 0, width: 0, height: 0 + operation: 0, opacity_factor: 1, width: 0, height: 0 }; -export const DerivativeEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const DERIVATIVE_EFFECT_META = { GTypeName: "DerivativeEffect", Properties: { 'operation': GObject.ParamSpec.int( @@ -23,6 +23,14 @@ export const DerivativeEffect = utils.IS_IN_PREFERENCES ? 0, 2, 0, ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), 'width': GObject.ParamSpec.double( `width`, `Width`, @@ -40,16 +48,17 @@ export const DerivativeEffect = utils.IS_IN_PREFERENCES ? 0.0, ) } - }, class DerivativeEffect extends Clutter.ShaderEffect { +}; + +const DerivativeEffectClass = utils.IS_IN_PREFERENCES ? null : class DerivativeEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); - utils.setup_params(this, params); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + utils.setup_params(this, params); } static get default_params() { @@ -64,7 +73,19 @@ export const DerivativeEffect = utils.IS_IN_PREFERENCES ? if (this._operation !== value) { this._operation = value; - this.set_uniform_value('operation', this._operation); + uniforms.set_uniform(this, 'operation', this._operation); + } + } + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); } } @@ -73,10 +94,11 @@ export const DerivativeEffect = utils.IS_IN_PREFERENCES ? } set width(value) { - if (this._width !== value) { - this._width = value; + const v = Math.max(1, value || 1); + if (this._width !== v) { + this._width = v; - this.set_uniform_value('width', parseFloat(this._width - 1e-6)); + uniforms.set_uniform(this, 'width', parseFloat(this._width - 1e-6)); } } @@ -85,10 +107,11 @@ export const DerivativeEffect = utils.IS_IN_PREFERENCES ? } set height(value) { - if (this._height !== value) { - this._height = value; + const v = Math.max(1, value || 1); + if (this._height !== v) { + this._height = v; - this.set_uniform_value('height', parseFloat(this._height - 1e-6)); + uniforms.set_uniform(this, 'height', parseFloat(this._height - 1e-6)); } } @@ -112,9 +135,17 @@ export const DerivativeEffect = utils.IS_IN_PREFERENCES ? } vfunc_paint_target(paint_node, paint_context) { - // force setting nearest-neighbour texture filtering - this.get_pipeline().set_layer_filters(0, 9728, 9728); + uniforms.upload_uniforms(this); + + const pipeline = this.get_pipeline(); + if (pipeline) { + pipeline.set_layer_filters(0, 9728, 9728); + } super.vfunc_paint_target(paint_node, paint_context); } - }); \ No newline at end of file +}; + +export const DerivativeEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(DERIVATIVE_EFFECT_META, DerivativeEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.glsl index 9871268..8b57367 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.glsl @@ -3,13 +3,14 @@ uniform int divider; uniform float width; uniform float height; uniform int downsampling_mode; +uniform float opacity_factor; #define CORRECTION 2.25 -#define SIZE_ADDITION 3 +#define SIZE_ADDITION 3.0 vec4 get_texture_at_position(vec2 position) { vec2 raw_position = position + vec2(CORRECTION, CORRECTION); - vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + vec2 raw_uv = raw_position / vec2(max(1.0, width + SIZE_ADDITION), max(1.0, height + SIZE_ADDITION)); return texture2D(tex, raw_uv); } @@ -21,11 +22,14 @@ vec2 get_corrected_position() { } void main() { + vec4 source_color = texture2D(tex, cogl_tex_coord0_in.st); + vec4 effect_color = vec4(0.0); ivec2 corrected_position = ivec2(get_corrected_position()); - vec2 multiplied_position = corrected_position * divider; + vec2 multiplied_position = vec2(corrected_position) * float(divider); if (any(greaterThan(multiplied_position, vec2(width, height)))) { - discard; + cogl_color_out = mix(source_color, effect_color, opacity_factor); + return; } // mode 0: boxcar downsampling @@ -35,15 +39,15 @@ void main() { int count = 0; for (int i = 0; i < divider; i++) { for (int j = 0; j < divider; j++) { - vec2 lookup_position = multiplied_position + vec2(i, j); - if (all(greaterThanEqual(lookup_position, vec2(0, 0))) && + vec2 lookup_position = multiplied_position + vec2(float(i), float(j)); + if (all(greaterThanEqual(lookup_position, vec2(0.0, 0.0))) && all(lessThan(lookup_position, vec2(width, height)))) { color += get_texture_at_position(lookup_position); count += 1; } } } - cogl_color_out = color / count; + effect_color = color / max(1.0, float(count)); } else // mode 1: triangular downsampling @@ -54,23 +58,25 @@ void main() { int force = 1; for (int i = 0; i < divider; i++) { for (int j = 0; j < divider; j++) { - vec2 lookup_position = multiplied_position + vec2(i, j); - if (all(greaterThanEqual(lookup_position, vec2(0, 0))) && + vec2 lookup_position = multiplied_position + vec2(float(i), float(j)); + if (all(greaterThanEqual(lookup_position, vec2(0.0, 0.0))) && all(lessThan(lookup_position, vec2(width, height)))) { - force = 1 + divider - int(abs(divider - i - j)); - color += get_texture_at_position(lookup_position) * force; + force = 1 + divider - int(abs(float(divider - i - j))); + color += get_texture_at_position(lookup_position) * float(force); count += force; } } } - cogl_color_out = color / count; + effect_color = color / max(1.0, float(count)); } else // mode 2: Dirac downsampling if (downsampling_mode == 2) { - vec2 lookup_position = min(multiplied_position + vec2(divider, divider) / 2, vec2(width - 1, height - 1)); - cogl_color_out = get_texture_at_position(lookup_position); + vec2 lookup_position = min(multiplied_position + vec2(float(divider)) * 0.5, vec2(width - 1.0, height - 1.0)); + effect_color = get_texture_at_position(lookup_position); } -} \ No newline at end of file + + cogl_color_out = mix(source_color, effect_color, opacity_factor); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.js index 8103486..b6e08c4 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/downscale.js @@ -1,18 +1,18 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'downscale.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { - divider: 8, downsampling_mode: 0, width: 0, height: 0 + divider: 8, downsampling_mode: 0, opacity_factor: 1, width: 0, height: 0 }; -export const DownscaleEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const DOWNSCALE_EFFECT_META = { GTypeName: "DownscaleEffect", Properties: { 'divider': GObject.ParamSpec.int( @@ -31,6 +31,14 @@ export const DownscaleEffect = utils.IS_IN_PREFERENCES ? 0, 2, 0, ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), 'width': GObject.ParamSpec.double( `width`, `Width`, @@ -48,16 +56,17 @@ export const DownscaleEffect = utils.IS_IN_PREFERENCES ? 0.0, ) } - }, class DownscaleEffect extends Clutter.ShaderEffect { +}; + +const DownscaleEffectClass = utils.IS_IN_PREFERENCES ? null : class DownscaleEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); - utils.setup_params(this, params); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + utils.setup_params(this, params); } static get default_params() { @@ -69,10 +78,11 @@ export const DownscaleEffect = utils.IS_IN_PREFERENCES ? } set divider(value) { - if (this._divider !== value) { - this._divider = value; + const v = Math.max(1, value || 1); + if (this._divider !== v) { + this._divider = v; - this.set_uniform_value('divider', this._divider); + uniforms.set_uniform(this, 'divider', this._divider); } } @@ -84,7 +94,19 @@ export const DownscaleEffect = utils.IS_IN_PREFERENCES ? if (this._downsampling_mode !== value) { this._downsampling_mode = value; - this.set_uniform_value('downsampling_mode', this._downsampling_mode); + uniforms.set_uniform(this, 'downsampling_mode', this._downsampling_mode); + } + } + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); } } @@ -93,10 +115,11 @@ export const DownscaleEffect = utils.IS_IN_PREFERENCES ? } set width(value) { - if (this._width !== value) { - this._width = value; + const v = Math.max(1, value || 1); + if (this._width !== v) { + this._width = v; - this.set_uniform_value('width', parseFloat(this._width - 1e-6)); + uniforms.set_uniform(this, 'width', parseFloat(this._width - 1e-6)); } } @@ -105,10 +128,11 @@ export const DownscaleEffect = utils.IS_IN_PREFERENCES ? } set height(value) { - if (this._height !== value) { - this._height = value; + const v = Math.max(1, value || 1); + if (this._height !== v) { + this._height = v; - this.set_uniform_value('height', parseFloat(this._height - 1e-6)); + uniforms.set_uniform(this, 'height', parseFloat(this._height - 1e-6)); } } @@ -132,9 +156,17 @@ export const DownscaleEffect = utils.IS_IN_PREFERENCES ? } vfunc_paint_target(paint_node, paint_context) { - // force setting nearest-neighbour texture filtering - this.get_pipeline().set_layer_filters(0, 9728, 9728); + uniforms.upload_uniforms(this); + + const pipeline = this.get_pipeline(); + if (pipeline) { + pipeline.set_layer_filters(0, 9728, 9728); + } super.vfunc_paint_target(paint_node, paint_context); } - }); \ No newline at end of file +}; + +export const DownscaleEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(DOWNSCALE_EFFECT_META, DownscaleEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effect_groups.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effect_groups.js new file mode 100644 index 0000000..c53a647 --- /dev/null +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effect_groups.js @@ -0,0 +1,31 @@ +export function get_effects_groups(_ = _ => '') { + return { + blur_effects: { + name: _('Blur effects'), + contains: [ + 'native_static_gaussian_blur', + 'gaussian_blur', + 'monte_carlo_blur', + ], + }, + texture_effects: { + name: _('Texture effects'), + contains: [ + 'downscale', + 'upscale', + 'pixelize', + 'refraction', + 'derivative', + 'noise', + 'color', + 'luminosity', + 'rgb_to_hsl', + 'hsl_to_rgb', + ], + }, + shape_effects: { + name: _('Shape effects'), + contains: ['corner'], + }, + }; +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effects.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effects.js index 4ab5a71..984aa47 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effects.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/effects.js @@ -12,41 +12,8 @@ import { DerivativeEffect } from './derivative.js'; import { RgbToHslEffect } from './rgb_to_hsl.js'; import { HslToRgbEffect } from './hsl_to_rgb.js'; import { LuminosityEffect } from './luminosity.js'; - -// We do in this way because I've not found another way to store our preferences in a dictionnary -// while calling `gettext` on it while in preferences. Not so pretty, but works. -export function get_effects_groups(_ = _ => "") { - return { - blur_effects: { - name: _("Blur effects"), - contains: [ - "native_static_gaussian_blur", - "gaussian_blur", - "monte_carlo_blur" - ] - }, - texture_effects: { - name: _("Texture effects"), - contains: [ - "downscale", - "upscale", - "pixelize", - "derivative", - "noise", - "color", - "luminosity", - "rgb_to_hsl", - "hsl_to_rgb" - ] - }, - shape_effects: { - name: _("Shape effects"), - contains: [ - "corner" - ] - } - }; -}; +import { RefractionEffect } from './refraction.js'; +export { get_effects_groups } from './effect_groups.js'; export function get_supported_effects(_ = () => "") { return { @@ -378,6 +345,140 @@ export function get_supported_effects(_ = () => "") { } }, + refraction: { + class: RefractionEffect, + name: _("Liquid Glass"), + description: _("A glossy translucent material with edge refraction, rim lighting, tint, and inner shadow."), + is_advanced: false, + editable_params: { + strength: { + name: _("Refraction scale"), + description: _("How strongly the glass bends the sampled blur texture."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + blur_radius: { + name: _("Blur radius"), + description: _("Blurs the sampled backdrop before the liquid-glass shader is applied."), + type: "float", + min: 0., + max: 48., + increment: 1., + big_increment: 10., + digits: 0 + }, + edge_size: { + name: _("Bezel width"), + description: _("How far the liquid-glass lens reaches inward from the edge."), + type: "float", + min: 1., + max: 100., + increment: 1., + big_increment: 10., + digits: 0 + }, + rim_width: { + name: _("Rim spread"), + description: _("How far the refraction eases inward from the glass edge."), + type: "float", + min: 1., + max: 6.5, + increment: 0.1, + big_increment: 0.5, + digits: 2 + }, + falloff: { + name: _("Glass thickness"), + description: _("Depth used by the Snell-style refraction profile."), + type: "float", + min: 0.25, + max: 8., + increment: 0.05, + big_increment: 0.5, + digits: 2 + }, + corner_radius: { + name: _("Corner radius"), + description: _("The rounded shape used for the glass edge and highlight."), + type: "float", + min: 0., + max: 100., + increment: 1., + big_increment: 10., + digits: 0 + }, + gloss: { + name: _("Fresnel glare"), + description: _("Strength of the Schlick fresnel rim glare from the glass edge."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + tint: { + name: _("Tint strength"), + description: _("Amount of subtle milky glass tint over the blurred texture."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + tint_color: { + name: _("Tint color"), + description: _("Color blended over the blurred texture, weighted by the tint strength."), + type: "rgba", + use_alpha: true + }, + backdrop_zoom: { + name: _("Backdrop zoom"), + description: _("Zoom level of the backdrop visible through the glass."), + type: "float", + min: 0.1, + max: 4., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + shadow: { + name: _("Inner shadow"), + description: _("Darkens the lower and inner edge for a deeper glass surface."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + rgb_fringing: { + name: _("Chromatic dispersion"), + description: _("Physical per-channel refraction dispersion at the glass edge."), + type: "float", + min: 0., + max: 1., + increment: 0.01, + big_increment: 0.1, + digits: 2 + }, + texture_repeat: { + name: _("Edge behavior"), + description: _("How texture coordinates outside the actor are sampled."), + type: "dropdown", + options: [ + _("Clamp"), + _("Mirror") + ] + } + } + }, + rgb_to_hsl: { class: RgbToHslEffect, name: _("RGB to HSL (advanced effect)"), @@ -402,7 +503,7 @@ export function get_supported_effects(_ = () => "") { editable_params: { radius: { name: _("Radius"), - description: _("The radius of the corner. GNOME apps use a radius of 12 px by default."), + description: _("The radius of the corner. GNOME apps use a radius of 15 px by default."), type: "integer", min: 0, max: 150, @@ -421,4 +522,4 @@ export function get_supported_effects(_ = () => "") { } } }; -}; \ No newline at end of file +}; diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.glsl index 809cc93..2bc641f 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.glsl @@ -6,30 +6,35 @@ uniform float width; uniform float height; vec4 getTexture(vec2 uv) { - if (uv.x < 3. / width) - uv.x = 3. / width; + float w = max(1.0, width); + float h = max(1.0, height); - if (uv.y < 3. / height) - uv.y = 3. / height; + if (uv.x < 3. / w) + uv.x = 3. / w; - if (uv.x > 1. - 3. / width) - uv.x = 1. - 3. / width; + if (uv.y < 3. / h) + uv.y = 3. / h; - if (uv.y > 1. - 3. / height) - uv.y = 1. - 3. / height; + if (uv.x > 1. - 3. / w) + uv.x = 1. - 3. / w; + + if (uv.y > 1. - 3. / h) + uv.y = 1. - 3. / h; return texture2D(tex, uv); } void main(void) { vec2 uv = cogl_tex_coord_in[0].xy; - vec2 direction = vec2(dir, (1.0 - dir)); + vec2 direction = vec2(float(dir), 1.0 - float(dir)); + float w = max(1.0, width); + float h = max(1.0, height); float pixel_step; if (dir == 0) - pixel_step = 1.0 / height; + pixel_step = 1.0 / h; else - pixel_step = 1.0 / width; + pixel_step = 1.0 / w; vec3 gauss_coefficient; gauss_coefficient.x = 1.0 / (sqrt(2.0 * 3.14159265) * sigma); @@ -67,4 +72,4 @@ void main(void) { } cogl_color_out = outColor; -} \ No newline at end of file +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.js index 113a6fd..631831e 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/gaussian_blur.js @@ -1,20 +1,20 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const St = await utils.import_in_shell_only('gi://St'); const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'gaussian_blur.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { radius: 30, brightness: .6, width: 0, height: 0, direction: 0, chained_effect: null }; -export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const GAUSSIAN_BLUR_EFFECT_META = { GTypeName: "GaussianBlurEffect", Properties: { 'radius': GObject.ParamSpec.double( @@ -65,21 +65,22 @@ export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? GObject.Object, ), } - }, class GaussianBlurEffect extends Clutter.ShaderEffect { +}; + +const GaussianBlurEffectClass = utils.IS_IN_PREFERENCES ? null : class GaussianBlurEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); - utils.setup_params(this, params); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + utils.setup_params(this, params); const theme_context = St.ThemeContext.get_for_stage(global.stage); theme_context.connectObject( 'notify::scale-factor', _ => - this.set_uniform_value('sigma', + uniforms.set_uniform(this, 'sigma', parseFloat(this.radius * theme_context.scale_factor / 2 - 1e-6) ), this @@ -101,7 +102,7 @@ export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; // like Clutter, we use the assumption radius = 2*sigma - this.set_uniform_value('sigma', parseFloat(this._radius * scale_factor / 2 - 1e-6)); + uniforms.set_uniform(this, 'sigma', parseFloat(this._radius * scale_factor / 2 - 1e-6)); this.set_enabled(this.radius > 0.); if (this.chained_effect) @@ -117,7 +118,7 @@ export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? if (this._brightness !== value) { this._brightness = value; - this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6)); + uniforms.set_uniform(this, 'brightness', parseFloat(this._brightness - 1e-6)); if (this.chained_effect) this.chained_effect.brightness = value; @@ -129,13 +130,14 @@ export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? } set width(value) { - if (this._width !== value) { - this._width = value; + const v = Math.max(1, value || 1); + if (this._width !== v) { + this._width = v; - this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); + uniforms.set_uniform(this, 'width', parseFloat(this._width + 3.0 - 1e-6)); if (this.chained_effect) - this.chained_effect.width = value; + this.chained_effect.width = v; } } @@ -144,13 +146,14 @@ export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? } set height(value) { - if (this._height !== value) { - this._height = value; + const v = Math.max(1, value || 1); + if (this._height !== v) { + this._height = v; - this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); + uniforms.set_uniform(this, 'height', parseFloat(this._height + 3.0 - 1e-6)); if (this.chained_effect) - this.chained_effect.height = value; + this.chained_effect.height = v; } } @@ -159,8 +162,10 @@ export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? } set direction(value) { - if (this._direction !== value) + if (this._direction !== value) { this._direction = value; + uniforms.set_uniform(this, "dir", this._direction); + } } get chained_effect() { @@ -202,12 +207,16 @@ export const GaussianBlurEffect = utils.IS_IN_PREFERENCES ? }); if (actor !== null) actor.add_effect(this.chained_effect); + uniforms.mark_dirty(this.chained_effect); } } vfunc_paint_target(paint_node, paint_context) { - this.set_uniform_value("dir", this.direction); - + uniforms.upload_uniforms(this); super.vfunc_paint_target(paint_node, paint_context); } - }); \ No newline at end of file +}; + +export const GaussianBlurEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(GAUSSIAN_BLUR_EFFECT_META, GaussianBlurEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.glsl index 58d2694..8b9990d 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.glsl @@ -1,4 +1,5 @@ uniform sampler2D tex; +uniform float opacity_factor; vec3 hsl_to_rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); @@ -10,5 +11,5 @@ void main(void) { vec2 uv = cogl_tex_coord_in[0].xy; vec4 hsla = texture2D(tex, uv); vec4 rgba = vec4(hsl_to_rgb(hsla.xyz), hsla.w); - cogl_color_out = rgba; -} \ No newline at end of file + cogl_color_out = mix(hsla, rgba, opacity_factor); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.js index fe53114..b79ee84 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/hsl_to_rgb.js @@ -1,31 +1,64 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'hsl_to_rgb.glsl'; -const DEFAULT_PARAMS = {}; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); +const DEFAULT_PARAMS = { + opacity_factor: 1 +}; -export const HslToRgbEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const HSL_TO_RGB_EFFECT_META = { GTypeName: "HslToRgbEffect", - Properties: {} - }, class HslToRgbEffect extends Clutter.ShaderEffect { + Properties: { + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), + } +}; + +const HslToRgbEffectClass = utils.IS_IN_PREFERENCES ? null : class HslToRgbEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); - utils.setup_params(this, params); + utils.initialize_shader_effect(this, SHADER_SOURCE); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + + utils.setup_params(this, params); } static get default_params() { return DEFAULT_PARAMS; } - }); \ No newline at end of file + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); + } + } + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + super.vfunc_paint_target(paint_node, paint_context); + } +}; + +export const HslToRgbEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(HSL_TO_RGB_EFFECT_META, HslToRgbEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.glsl index 4c50ca4..e7cc855 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.glsl @@ -4,6 +4,7 @@ uniform float brightness_multiplicator; uniform float contrast; uniform float contrast_center; uniform float saturation_multiplicator; +uniform float opacity_factor; vec3 hsl_to_rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); @@ -24,10 +25,16 @@ vec3 rgb_to_hsl(vec3 c) { void main() { vec4 c = texture2D(tex, cogl_tex_coord_in[0].st); + if (c.a <= 0.0) { + cogl_color_out = c; + return; + } + vec3 pix_hsl = rgb_to_hsl(c.xyz) / c.a; pix_hsl.z = clamp(pix_hsl.z * brightness_multiplicator, 0., 1.); pix_hsl.z = clamp((pix_hsl.z - contrast_center) * contrast + contrast_center + brightness_shift, 0., 1.); pix_hsl.y = clamp(pix_hsl.y * saturation_multiplicator, 0., 1.); - cogl_color_out = vec4(hsl_to_rgb(pix_hsl) * c.a, c.a); -} \ No newline at end of file + vec4 effect_color = vec4(hsl_to_rgb(pix_hsl) * c.a, c.a); + cogl_color_out = mix(c, effect_color, opacity_factor); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.js index c22636d..a4b6364 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/luminosity.js @@ -1,18 +1,18 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'luminosity.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { - brightness_shift: 0., brightness_multiplicator: 1., contrast: 1., contrast_center: 0.5, saturation_multiplicator: 1. + brightness_shift: 0., brightness_multiplicator: 1., contrast: 1., contrast_center: 0.5, saturation_multiplicator: 1., opacity_factor: 1. }; -export const LuminosityEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const LUMINOSITY_EFFECT_META = { GTypeName: "LuminosityEffect", Properties: { 'brightness_shift': GObject.ParamSpec.double( @@ -55,17 +55,26 @@ export const LuminosityEffect = utils.IS_IN_PREFERENCES ? 0.0, 2.0, 1.0, ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), } - }, class LuminosityEffect extends Clutter.ShaderEffect { +}; + +const LuminosityEffectClass = utils.IS_IN_PREFERENCES ? null : class LuminosityEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); - utils.setup_params(this, params); + utils.initialize_shader_effect(this, SHADER_SOURCE); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + + utils.setup_params(this, params); } static get default_params() { @@ -80,7 +89,7 @@ export const LuminosityEffect = utils.IS_IN_PREFERENCES ? if (this._brightness_shift !== value) { this._brightness_shift = value; - this.set_uniform_value('brightness_shift', parseFloat(this._brightness_shift - 1e-6)); + uniforms.set_uniform(this, 'brightness_shift', parseFloat(this._brightness_shift - 1e-6)); } } @@ -96,7 +105,7 @@ export const LuminosityEffect = utils.IS_IN_PREFERENCES ? let brightness_mul = 600.; if (value < 1.995) brightness_mul = 3. * (1. / (1. - (value / 2.) ** 2) - 1.); - this.set_uniform_value('brightness_multiplicator', parseFloat(brightness_mul - 1e-6)); + uniforms.set_uniform(this, 'brightness_multiplicator', parseFloat(brightness_mul - 1e-6)); } } @@ -108,7 +117,7 @@ export const LuminosityEffect = utils.IS_IN_PREFERENCES ? if (this._contrast !== value) { this._contrast = value; - this.set_uniform_value('contrast', parseFloat(this._contrast - 1e-6)); + uniforms.set_uniform(this, 'contrast', parseFloat(this._contrast - 1e-6)); } } @@ -120,7 +129,7 @@ export const LuminosityEffect = utils.IS_IN_PREFERENCES ? if (this._contrast_center !== value) { this._contrast_center = value; - this.set_uniform_value('contrast_center', parseFloat(this._contrast_center - 1e-6)); + uniforms.set_uniform(this, 'contrast_center', parseFloat(this._contrast_center - 1e-6)); } } @@ -135,7 +144,28 @@ export const LuminosityEffect = utils.IS_IN_PREFERENCES ? let saturation_mul = 600.; if (value < 1.995) saturation_mul = 3. * (1. / (1. - (value / 2.) ** 2) - 1.); - this.set_uniform_value('saturation_multiplicator', parseFloat(saturation_mul - 1e-6)); + uniforms.set_uniform(this, 'saturation_multiplicator', parseFloat(saturation_mul - 1e-6)); } } - }); \ No newline at end of file + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); + } + } + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + super.vfunc_paint_target(paint_node, paint_context); + } +}; + +export const LuminosityEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(LUMINOSITY_EFFECT_META, LuminosityEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.glsl index c63d266..ee0c35f 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.glsl @@ -4,8 +4,8 @@ uniform int iterations; uniform float brightness; uniform float width; uniform float height; -uniform bool use_base_pixel; -uniform bool prefer_closer_pixels; +uniform int use_base_pixel; +uniform int prefer_closer_pixels; float srand(vec2 a) { return sin(dot(a, vec2(1233.224, 1743.335))); @@ -18,7 +18,7 @@ float rand(inout float r) { void main() { vec2 uv = cogl_tex_coord0_in.st; - vec2 p = 16 * radius / vec2(width, height); + vec2 p = 16.0 * radius / vec2(width, height); float r = srand(uv); vec2 rv; @@ -35,18 +35,18 @@ void main() { dir = vec2(cos(rv.y), sin(rv.y)); new_uv = uv + rv.x * dir * p; if (new_uv.x > 2. / width && new_uv.y > 2. / height && new_uv.x < 1. - 3. / width && new_uv.y < 1. - 3. / height) { - strength = prefer_closer_pixels ? ((iterations - i) * (iterations - i)) : 1; - c += strength * texture2D(tex, new_uv); + strength = prefer_closer_pixels != 0 ? ((iterations - i) * (iterations - i)) : 1; + c += float(strength) * texture2D(tex, new_uv); count += strength; } } - if (count == 0 || use_base_pixel) { - strength = prefer_closer_pixels ? ((iterations + 1) * (iterations + 1)) : 1; - c += strength * texture2D(tex, uv); + if (count == 0 || use_base_pixel != 0) { + strength = prefer_closer_pixels != 0 ? ((iterations + 1) * (iterations + 1)) : 1; + c += float(strength) * texture2D(tex, uv); count += strength; } c.xyz *= brightness; - cogl_color_out = c / count; -} \ No newline at end of file + cogl_color_out = c / max(1.0, float(count)); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.js index 0da56ed..e8deb9c 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/monte_carlo_blur.js @@ -1,11 +1,13 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const St = await utils.import_in_shell_only('gi://St'); const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'monte_carlo_blur.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { radius: 2., iterations: 5, brightness: .6, width: 0, height: 0, use_base_pixel: true, @@ -13,9 +15,7 @@ const DEFAULT_PARAMS = { }; -export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const MONTE_CARLO_BLUR_EFFECT_META = { GTypeName: "MonteCarloBlurEffect", Properties: { 'radius': GObject.ParamSpec.double( @@ -73,21 +73,22 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? true, ), } - }, class MonteCarloBlurEffect extends Clutter.ShaderEffect { +}; + +const MonteCarloBlurEffectClass = utils.IS_IN_PREFERENCES ? null : class MonteCarloBlurEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); - utils.setup_params(this, params); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + utils.setup_params(this, params); const theme_context = St.ThemeContext.get_for_stage(global.stage); theme_context.connectObject( 'notify::scale-factor', - _ => this.set_uniform_value('radius', + _ => uniforms.set_uniform(this, 'radius', parseFloat(this._radius * theme_context.scale_factor - 1e-6) ), this @@ -108,7 +109,7 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - this.set_uniform_value('radius', parseFloat(this._radius * scale_factor - 1e-6)); + uniforms.set_uniform(this, 'radius', parseFloat(this._radius * scale_factor - 1e-6)); this.set_enabled(this.radius > 0. && this.iterations > 0); } } @@ -121,7 +122,7 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? if (this._iterations !== value) { this._iterations = value; - this.set_uniform_value('iterations', this._iterations); + uniforms.set_uniform(this, 'iterations', this._iterations); this.set_enabled(this.radius > 0. && this.iterations > 0); } } @@ -134,7 +135,7 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? if (this._brightness !== value) { this._brightness = value; - this.set_uniform_value('brightness', parseFloat(this._brightness - 1e-6)); + uniforms.set_uniform(this, 'brightness', parseFloat(this._brightness - 1e-6)); } } @@ -143,10 +144,11 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? } set width(value) { - if (this._width !== value) { - this._width = value; + const v = Math.max(1, value || 1); + if (this._width !== v) { + this._width = v; - this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); + uniforms.set_uniform(this, 'width', parseFloat(this._width + 3.0 - 1e-6)); } } @@ -155,10 +157,11 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? } set height(value) { - if (this._height !== value) { - this._height = value; + const v = Math.max(1, value || 1); + if (this._height !== v) { + this._height = v; - this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); + uniforms.set_uniform(this, 'height', parseFloat(this._height + 3.0 - 1e-6)); } } @@ -170,7 +173,7 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? if (this._use_base_pixel !== value) { this._use_base_pixel = value; - this.set_uniform_value('use_base_pixel', this._use_base_pixel ? 1 : 0); + uniforms.set_uniform(this, 'use_base_pixel', this._use_base_pixel ? 1 : 0); } } @@ -182,7 +185,7 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? if (this._prefer_closer_pixels !== value) { this._prefer_closer_pixels = value; - this.set_uniform_value('prefer_closer_pixels', this._prefer_closer_pixels ? 1 : 0); + uniforms.set_uniform(this, 'prefer_closer_pixels', this._prefer_closer_pixels ? 1 : 0); } } @@ -204,4 +207,13 @@ export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES ? super.vfunc_set_actor(actor); } - }); \ No newline at end of file + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + super.vfunc_paint_target(paint_node, paint_context); + } +}; + +export const MonteCarloBlurEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(MONTE_CARLO_BLUR_EFFECT_META, MonteCarloBlurEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_dynamic_gaussian_blur.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_dynamic_gaussian_blur.js index 3df621b..fc24e07 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_dynamic_gaussian_blur.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_dynamic_gaussian_blur.js @@ -3,55 +3,72 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; const St = await utils.import_in_shell_only('gi://St'); -let BlurOrShell = await utils.import_in_shell_only('gi://Blur'); -let IS_BLUR_MODULE = true; -if (BlurOrShell === null) { - BlurOrShell = await utils.import_in_shell_only('gi://Shell'); - IS_BLUR_MODULE = false; -} +const BlurModule = await utils.import_in_shell_only('gi://Blur'); +const Shell = await utils.import_in_shell_only('gi://Shell'); +const BlurOrShell = utils.is_usable_blur_module(BlurModule) ? BlurModule : Shell; +const SUPPORTS_CORNER_RADIUS = Boolean( + BlurOrShell?.BlurEffect?.list_properties() + .some(property => property.name === 'corner-radius') +); const DEFAULT_PARAMS = { - unscaled_radius: 30, brightness: 0.6, corner_radius: 14 + unscaled_radius: 30, + brightness: 0.6, + unscaled_corner_radius: 0, }; export const NativeDynamicBlurEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : + { default_params: DEFAULT_PARAMS, supports_corner_radius: false } : new GObject.registerClass({ GTypeName: "NativeDynamicBlurEffect" }, class NativeDynamicBlurEffect extends BlurOrShell.BlurEffect { constructor(params) { - const { unscaled_radius, brightness, corner_radius, ...parent_params } = params; - if (IS_BLUR_MODULE) - super({ ...parent_params, mode: BlurOrShell.BlurMode.BACKGROUND, ...{ 'corner_radius': corner_radius } }); - else - super({ ...parent_params, mode: BlurOrShell.BlurMode.BACKGROUND }); + const normalized_params = { ...params }; + if (!('unscaled_radius' in normalized_params) && 'radius' in normalized_params) + normalized_params.unscaled_radius = normalized_params.radius; + delete normalized_params.radius; + + if (!('unscaled_corner_radius' in normalized_params) && 'corner_radius' in normalized_params) + normalized_params.unscaled_corner_radius = normalized_params.corner_radius; + delete normalized_params.corner_radius; + + const parent_params = { ...normalized_params }; + delete parent_params.unscaled_radius; + delete parent_params.brightness; + delete parent_params.unscaled_corner_radius; + super({ ...parent_params, mode: BlurOrShell.BlurMode.BACKGROUND }); this._theme_context = St.ThemeContext.get_for_stage(global.stage); this._theme_context.connectObject( 'notify::scale-factor', _ => { - this.radius = this.unscaled_radius * this._theme_context.scale_factor; - this.corner_radius = this.unscaled_corner_radius * this._theme_context.scale_factor; + this.radius = Math.max(0, this.unscaled_radius * this._theme_context.scale_factor); + if (SUPPORTS_CORNER_RADIUS) + this.corner_radius = this.unscaled_corner_radius * this._theme_context.scale_factor; }, this ); - utils.setup_params(this, params); + utils.setup_params(this, normalized_params); } static get default_params() { return DEFAULT_PARAMS; } + static get supports_corner_radius() { + return SUPPORTS_CORNER_RADIUS; + } + get unscaled_radius() { return this._unscaled_radius; } set unscaled_radius(value) { this._unscaled_radius = value; - this.radius = value * this._theme_context.scale_factor; + this.radius = Math.max(0, value * this._theme_context.scale_factor); } get unscaled_corner_radius() { @@ -60,6 +77,7 @@ export const NativeDynamicBlurEffect = utils.IS_IN_PREFERENCES ? set unscaled_corner_radius(value) { this._unscaled_corner_radius = value; - this.corner_radius = value * this._theme_context.scale_factor; + if (SUPPORTS_CORNER_RADIUS) + this.corner_radius = value * this._theme_context.scale_factor; } }); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_static_gaussian_blur.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_static_gaussian_blur.js index fe003f5..cc7aa7b 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_static_gaussian_blur.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/native_static_gaussian_blur.js @@ -15,17 +15,26 @@ export const NativeStaticBlurEffect = utils.IS_IN_PREFERENCES ? GTypeName: "NativeStaticBlurEffect" }, class NativeStaticBlurEffect extends Shell.BlurEffect { constructor(params) { - const { unscaled_radius, brightness, ...parent_params } = params; + const normalized_params = { ...params }; + if (!('unscaled_radius' in normalized_params) && 'radius' in normalized_params) + normalized_params.unscaled_radius = normalized_params.radius; + delete normalized_params.radius; + + const { + unscaled_radius: _unscaled_radius, + brightness: _brightness, + ...parent_params + } = normalized_params; super({ ...parent_params, mode: Shell.BlurMode.ACTOR }); this._theme_context = St.ThemeContext.get_for_stage(global.stage); this._theme_context.connectObject( 'notify::scale-factor', - _ => this.radius = this.unscaled_radius * this._theme_context.scale_factor, + _ => this.radius = Math.max(0.5, this.unscaled_radius * this._theme_context.scale_factor), this ); - utils.setup_params(this, params); + utils.setup_params(this, normalized_params); } static get default_params() { @@ -38,6 +47,6 @@ export const NativeStaticBlurEffect = utils.IS_IN_PREFERENCES ? set unscaled_radius(value) { this._unscaled_radius = value; - this.radius = value * this._theme_context.scale_factor; + this.radius = Math.max(0.5, value * this._theme_context.scale_factor); } - }); \ No newline at end of file + }); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.glsl index 6d701b6..df03b71 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.glsl @@ -1,9 +1,10 @@ uniform sampler2D tex; uniform float noise; uniform float lightness; +uniform float opacity_factor; float PHI = 1.61803398874989484820459; -float SEED = 24; +float SEED = 24.0; float noise_gen(in vec2 xy) { float r = fract(tan(distance(xy * PHI, xy) * SEED) * xy.x); @@ -13,8 +14,9 @@ float noise_gen(in vec2 xy) { void main() { vec4 c = texture2D(tex, cogl_tex_coord_in[0].st); - vec3 pix_color = c.xyz; - float blend = noise * (1. - noise_gen(gl_FragCoord.xy)); + float blend = noise * (1. - noise_gen(gl_FragCoord.xy)) * opacity_factor; + vec3 pix_color = c.rgb; + vec3 noise_color = vec3(lightness); - cogl_color_out = vec4(mix(pix_color, lightness * pix_color, blend), 1.); -} \ No newline at end of file + cogl_color_out = vec4(mix(pix_color, noise_color, blend), c.a); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.js index 3049fa1..5b2c2e1 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/noise.js @@ -1,18 +1,18 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'noise.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { - noise: 0.4, lightness: 0.4 + noise: 0.4, lightness: 0.4, opacity_factor: 1 }; -export const NoiseEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const NOISE_EFFECT_META = { GTypeName: "NoiseEffect", Properties: { 'noise': GObject.ParamSpec.double( @@ -31,17 +31,26 @@ export const NoiseEffect = utils.IS_IN_PREFERENCES ? 0.0, 2.0, 0.4, ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), } - }, class NoiseEffect extends Clutter.ShaderEffect { +}; + +const NoiseEffectClass = utils.IS_IN_PREFERENCES ? null : class NoiseEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); - utils.setup_params(this, params); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + utils.setup_params(this, params); } static get default_params() { @@ -56,7 +65,7 @@ export const NoiseEffect = utils.IS_IN_PREFERENCES ? if (this._noise !== value) { this._noise = value; - this.set_uniform_value('noise', parseFloat(this._noise - 1e-6)); + uniforms.set_uniform(this, 'noise', parseFloat(this._noise - 1e-6)); this.set_enabled(this.noise > 0. && this.lightness != 1); } } @@ -69,8 +78,29 @@ export const NoiseEffect = utils.IS_IN_PREFERENCES ? if (this._lightness !== value) { this._lightness = value; - this.set_uniform_value('lightness', parseFloat(this._lightness - 1e-6)); + uniforms.set_uniform(this, 'lightness', parseFloat(this._lightness - 1e-6)); this.set_enabled(this.noise > 0. && this.lightness != 1); } } - }); \ No newline at end of file + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); + } + } + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + super.vfunc_paint_target(paint_node, paint_context); + } +}; + +export const NoiseEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(NOISE_EFFECT_META, NoiseEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/pixelize.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/pixelize.js index e9cad9b..e4a833c 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/pixelize.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/pixelize.js @@ -3,11 +3,8 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; const Clutter = await utils.import_in_shell_only('gi://Clutter'); -import { UpscaleEffect } from './upscale.js'; -import { DownscaleEffect } from './downscale.js'; - const DEFAULT_PARAMS = { - factor: 8, downsampling_mode: 0 + factor: 8, downsampling_mode: 0, opacity_factor: 1 }; @@ -31,15 +28,20 @@ export const PixelizeEffect = utils.IS_IN_PREFERENCES ? GObject.ParamFlags.READWRITE, 0, 2, 0, + ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, ) } }, class PixelizeEffect extends Clutter.Effect { constructor(params) { super(); - this.upscale_effect = new UpscaleEffect({}); - this.downscale_effect = new DownscaleEffect({}); - utils.setup_params(this, params); } @@ -48,41 +50,26 @@ export const PixelizeEffect = utils.IS_IN_PREFERENCES ? } get factor() { - // should be the same as `this.downscale_effect.divider` - return this.upscale_effect.factor; + return this._factor; } set factor(value) { - this.upscale_effect.factor = value; - this.downscale_effect.divider = value; + this._factor = value; } get downsampling_mode() { - return this.downscale_effect.downsampling_mode; + return this._downsampling_mode; } set downsampling_mode(value) { - this.downscale_effect.downsampling_mode = value; + this._downsampling_mode = value; } - vfunc_set_actor(actor) { - // deattach effects from old actor - this.upscale_effect?.actor?.remove_effect(this.upscale_effect); - this.downscale_effect?.actor?.remove_effect(this.downscale_effect); - // attach effects to new actor - if (actor) { - if (this.upscale_effect) - actor.add_effect(this.upscale_effect); - if (this.downscale_effect) - actor.add_effect(this.downscale_effect); - } - - super.vfunc_set_actor(actor); + get opacity_factor() { + return this._opacity_factor; } - vfunc_set_enabled(is_enabled) { - this.upscale_effect?.set_enabled(is_enabled); - this.downscale_effect?.set_enabled(is_enabled); - super.vfunc_set_enabled(is_enabled); + set opacity_factor(value) { + this._opacity_factor = value; } - }); \ No newline at end of file + }); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.glsl new file mode 100644 index 0000000..5d1d241 --- /dev/null +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.glsl @@ -0,0 +1,412 @@ +// GLSL port of winaviation-tweaks/liquidass LiquidAssBackboardd/Tweak.mm kShaderSrc. +// The sampling and blur pass are adapted for Blur my Shell's Clutter pipeline. +uniform sampler2D tex; +uniform float width; +uniform float height; +uniform float strength; +uniform float blur_radius; +uniform float edge_size; +uniform float falloff; +uniform float corner_radius; +uniform float rim_width; +uniform float rgb_fringing; +uniform float gloss; +uniform float tint; +uniform float tint_r; +uniform float tint_g; +uniform float tint_b; +uniform float tint_a; +uniform float backdrop_zoom; +uniform float shadow; +uniform int texture_repeat; +uniform int blur_direction; +uniform int private_pass; +uniform float clip_x0; +uniform float clip_y0; +uniform float clip_width; +uniform float clip_height; +uniform float opacity_factor; + +const float PI = 3.14159265; +const float REFRACTIVE_INDEX = 1.52; +const float DISPERSION_SCALE = 20.0; + +const float kDispersionRedIndex = 0.98; +const float kDispersionGreenIndex = 1.00; +const float kDispersionBlueIndex = 1.02; + +float surfaceConvexSquircle(float x) { + return pow(1.0 - pow(1.0 - x, 4.0), 0.25); +} + +vec2 refractRay(vec2 normal, float eta) { + float cosI = -normal.y; + float k = 1.0 - eta * eta * (1.0 - cosI * cosI); + if (k < 0.0) + return vec2(0.0); + + float kSqrt = sqrt(k); + return vec2( + -(eta * cosI + kSqrt) * normal.x, + eta - (eta * cosI + kSqrt) * normal.y + ); +} + +float rawRefraction(float bezelRatio, float glassThickness, float bezelWidth, float eta) { + float x = clamp(bezelRatio, 0.05, 0.95); + float y = surfaceConvexSquircle(x); + float y2 = surfaceConvexSquircle(x + 0.001); + float deriv = (y2 - y) / 0.001; + float mag = sqrt(deriv * deriv + 1.0); + vec2 n = vec2(-deriv / mag, -1.0 / mag); + vec2 r = refractRay(n, eta); + if (length(r) < 0.0001 || abs(r.y) < 0.0001) + return 0.0; + + float remaining = y * bezelWidth + glassThickness; + return r.x * (remaining / r.y); +} + +float displacementAtRatio(float bezelRatio, float glassThickness, float bezelWidth, float eta) { + float peak = rawRefraction(0.05, glassThickness, bezelWidth, eta); + if (abs(peak) < 0.0001) + return 0.0; + + float raw = rawRefraction(bezelRatio, glassThickness, bezelWidth, eta); + float norm = raw / peak; + float profileFalloff = 1.0 - smoothstep(0.0, 1.0, bezelRatio); + return norm * profileFalloff; +} + +float fresnelAtRatio(float bezelRatio, float refractiveIndex) { + float x = clamp(bezelRatio, 0.02, 0.98); + float y0 = surfaceConvexSquircle(max(0.001, x - 0.001)); + float y1 = surfaceConvexSquircle(min(0.999, x + 0.001)); + float slope = (y1 - y0) / 0.002; + float cosTheta = inversesqrt(1.0 + slope * slope); + float f0Base = (refractiveIndex - 1.0) / (refractiveIndex + 1.0); + float f0 = f0Base * f0Base; + float grazing = pow(1.0 - clamp(cosTheta, 0.0, 1.0), 5.0); + float fresnel = f0 + (1.0 - f0) * grazing; + return fresnel * (1.0 - smoothstep(0.0, 1.0, bezelRatio)); +} + +float dispersionOffsetScale(float channelIndex, float strengthValue) { + return 1.0 - (channelIndex - 1.0) * strengthValue; +} + +float luminance(vec3 color) { + return dot(color, vec3(0.2126, 0.7152, 0.0722)); +} + +vec2 clampUV(vec2 uv) { + vec2 px = vec2(1.5 / width, 1.5 / height); + return clamp(uv, px, vec2(1.0) - px); +} + +vec2 resolveUV(vec2 uv) { + if (texture_repeat == 1) { + vec2 mirrored = abs(fract(uv * 0.5) * 2.0 - 1.0); + return clampUV(mirrored); + } + + return clampUV(uv); +} + +vec4 sampleBackdrop(vec2 uv) { + return texture2D(tex, resolveUV(uv)); +} + +vec4 sampleGlassBackdrop(vec2 uv) { + if (blur_radius <= 0.01) + return sampleBackdrop(uv); + + float sigma = max(0.1, blur_radius * 0.5); + float pixelStep = blur_direction == 1 ? 1.0 / width : 1.0 / height; + vec2 direction = vec2(float(blur_direction), 1.0 - float(blur_direction)); + + vec3 gauss; + gauss.x = 1.0 / (sqrt(2.0 * PI) * sigma); + gauss.y = exp(-0.5 / (sigma * sigma)); + gauss.z = gauss.y * gauss.y; + + vec4 accum = sampleBackdrop(uv) * gauss.x; + float weightSum = gauss.x; + + gauss.xy *= gauss.yz; + + int radius = int(ceil(1.5 * sigma)) * 2; + for (int i = 1; i <= radius; i += 2) { + float subtotal = gauss.x; + + gauss.xy *= gauss.yz; + subtotal += gauss.x; + + float gaussRatio = gauss.x / subtotal; + float offset = float(i) + gaussRatio; + vec2 uvOffset = direction * offset * pixelStep; + + accum += sampleBackdrop(uv + uvOffset) * subtotal; + accum += sampleBackdrop(uv - uvOffset) * subtotal; + weightSum += subtotal * 2.0; + + gauss.xy *= gauss.yz; + } + + return accum / weightSum; +} + +vec4 tintFallbackSample() { + return vec4(vec3(tint_r, tint_g, tint_b), 1.0); +} + +vec4 sampleOrTintFallback(vec2 uv) { + vec4 sample = sampleGlassBackdrop(uv); + return sample.a < 0.01 ? tintFallbackSample() : sample; +} + +float roundedBoxDistance(vec2 p, vec2 halfSize, float radius) { + radius = min(radius, min(halfSize.x, halfSize.y)); + vec2 q = abs(p) - halfSize + vec2(radius); + return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius; +} + +float squircleCornerDistance(vec2 p, vec2 halfSize, float radius) { + const float continuousCornerExtent = 1.528; + + vec2 extent = min(vec2(radius * continuousCornerExtent), halfSize); + vec2 core = max(halfSize - extent, vec2(0.0)); + vec2 q = abs(p) - core; + vec2 corner = max(q, vec2(0.0)); + vec2 normalized = corner / max(extent, vec2(0.001)); + float superLength = pow(pow(normalized.x, 4.0) + pow(normalized.y, 4.0), 0.25); + + if (q.x <= 0.0 && q.y <= 0.0) + return -min(halfSize.x - abs(p.x), halfSize.y - abs(p.y)); + + return (superLength - 1.0) * min(extent.x, extent.y); +} + +struct EdgeInfo { + float distance; + float alpha; + vec2 dir; +}; + +EdgeInfo estimateAnalyticEdge(vec2 px, vec2 halfSize, float radius, float shortest) { + vec2 p = px - halfSize; + float signedDistance; + vec2 core; + + if (radius >= shortest * 0.49 || radius < 0.5) { + core = max(halfSize - vec2(radius), vec2(0.0)); + signedDistance = roundedBoxDistance(p, halfSize, radius); + } else { + const float continuousCornerExtent = 1.528; + vec2 extent = min(vec2(radius * continuousCornerExtent), halfSize); + core = max(halfSize - extent, vec2(0.0)); + signedDistance = squircleCornerDistance(p, halfSize, radius); + } + + EdgeInfo info; + info.distance = max(0.0, -signedDistance); + info.alpha = clamp(1.0 - max(0.0, signedDistance), 0.0, 1.0); + + vec2 cornerDelta = max(abs(p) - core, vec2(0.0)); + vec2 normalDelta; + + if (radius < shortest * 0.49 && radius >= 0.5 && + cornerDelta.x > 0.0 && cornerDelta.y > 0.0) { + normalDelta = sign(p) * pow(cornerDelta, vec2(3.0)); + } else { + vec2 nearestCore = clamp(p, -core, core); + normalDelta = p - nearestCore; + } + + float normalLength = length(normalDelta); + + if (normalLength > 0.001) { + info.dir = normalDelta / normalLength; + } else { + vec2 lensPx = px; + float dL = lensPx.x; + float dR = halfSize.x * 2.0 - lensPx.x; + float dT = lensPx.y; + float dB = halfSize.y * 2.0 - lensPx.y; + float dm = min(min(dL, dR), min(dT, dB)); + + info.dir = vec2( + (dL < dR && dL == dm) ? -1.0 : (dR <= dL && dR == dm) ? 1.0 : 0.0, + (dT < dB && dT == dm) ? -1.0 : (dB <= dT && dB == dm) ? 1.0 : 0.0 + ); + } + + return info; +} + +vec2 backdropSampleUV(vec2 sampleUV, vec2 displacementPx) { + vec2 displaced = sampleUV + displacementPx / vec2(width, height); + float zoom = max(backdrop_zoom, 0.01); + + displaced = vec2(0.5) + (displaced - vec2(0.5)) / zoom; + return displaced; +} + +vec4 sampleDispersed(vec2 sampleUV, vec2 dispPx, float dispersion) { + float greenScale = dispersionOffsetScale(kDispersionGreenIndex, dispersion); + vec2 greenUV = resolveUV(backdropSampleUV(sampleUV, dispPx * greenScale)); + vec4 greenSample = sampleGlassBackdrop(greenUV); + + vec4 fallback = vec4(0.0); + bool loadedFallback = false; + if (greenSample.a < 0.01) { + vec2 fallbackUV = resolveUV(backdropSampleUV(sampleUV, vec2(0.0))); + + fallback = sampleOrTintFallback(fallbackUV); + loadedFallback = true; + greenSample = fallback; + } + + if (greenSample.a < 0.01) + return tintFallbackSample(); + + vec4 bg = greenSample; + if (dispersion > 0.001 && dot(dispPx, dispPx) > 0.0001) { + float redScale = dispersionOffsetScale(kDispersionRedIndex, dispersion); + float blueScale = dispersionOffsetScale(kDispersionBlueIndex, dispersion); + + vec2 redUV = resolveUV(backdropSampleUV(sampleUV, dispPx * redScale)); + vec2 blueUV = resolveUV(backdropSampleUV(sampleUV, dispPx * blueScale)); + vec4 redSample = sampleGlassBackdrop(redUV); + vec4 blueSample = sampleGlassBackdrop(blueUV); + + if (redSample.a < 0.01 || blueSample.a < 0.01) { + if (!loadedFallback) { + vec2 fallbackUV = resolveUV(backdropSampleUV(sampleUV, vec2(0.0))); + fallback = sampleOrTintFallback(fallbackUV); + } + + if (redSample.a < 0.01) + redSample = fallback.a < 0.01 ? tintFallbackSample() : fallback; + + if (blueSample.a < 0.01) + blueSample = fallback.a < 0.01 ? tintFallbackSample() : fallback; + } + + bg.r = redSample.r; + bg.g = greenSample.g; + bg.b = blueSample.b; + bg.a = greenSample.a; + } + return bg; +} + +vec4 applyTintAndShadow(vec4 sample, vec2 localUV, float alpha) { + vec3 tintColor = vec3(tint_r, tint_g, tint_b); + vec3 outRGB = mix(sample.rgb, tintColor, tint * tint_a); + + outRGB *= 1.0 - smoothstep(0.25, 1.0, localUV.y) * shadow * 0.20; + + return vec4(clamp(outRGB, 0.0, 1.0) * alpha, alpha); +} + +void main() { + vec2 actorSize = vec2(width, height); + vec2 actorUV = cogl_tex_coord_in[0].xy; + + if (private_pass == 1) { + cogl_color_out = sampleGlassBackdrop(actorUV); + return; + } + + vec2 actorPx = actorUV * actorSize; + vec4 bounds = clip_width < 0.0 || clip_height < 0.0 + ? vec4(0.0, 0.0, width, height) + : vec4(clip_x0, clip_y0, clip_x0 + clip_width, clip_y0 + clip_height); + + vec2 glassSize = max(bounds.zw - bounds.xy, vec2(1.0)); + vec2 glassPx = actorPx - bounds.xy; + vec2 halfSize = glassSize * 0.5; + vec2 localUV = glassPx / glassSize; + + float W = glassSize.x; + float H = glassSize.y; + float shortestSide = min(W, H); + float R = clamp(corner_radius, 0.0, shortestSide * 0.5); + float bezel = max(1.0, min(edge_size, shortestSide * 0.5)); + float glassThickness = max(0.5, edge_size * 0.55 * falloff); + float eta = 1.0 / REFRACTIVE_INDEX; + + bool nearlySquare = abs(W - H) < max(4.0, shortestSide * 0.035); + bool useCircularSurface = nearlySquare && R >= shortestSide * 0.34; + + EdgeInfo edge = estimateAnalyticEdge(glassPx, halfSize, R, shortestSide); + if (edge.alpha <= 0.0) { + cogl_color_out = vec4(0.0); + return; + } + + float distFromSide = edge.distance; + float edgeOpacity = edge.alpha; + float edgeBand = 1.0; + float refractionBand = bezel; + vec2 dir = edge.dir; + + if (useCircularSurface) { + float circleRadius = shortestSide * 0.5; + vec2 circleCenter = glassSize * 0.5; + vec2 fromCenter = glassPx - circleCenter; + float circleDistance = length(fromCenter); + + if (circleDistance > circleRadius + 1.0) { + cogl_color_out = vec4(0.0); + return; + } + + distFromSide = max(0.0, circleRadius - circleDistance); + dir = circleDistance > 0.001 ? normalize(fromCenter) : vec2(0.0, -1.0); + edgeOpacity = clamp(1.0 - max(0.0, circleDistance - circleRadius), 0.0, 1.0); + + float rimRadius = max(1.0, bezel * 0.35); + refractionBand = rimRadius; + edgeBand = clamp(1.0 - (distFromSide / rimRadius), 0.0, 1.0); + } else { + float rimRadius = max(1.0, bezel * 0.35 * max(1.0, rim_width)); + refractionBand = rimRadius; + edgeBand = clamp(1.0 - (distFromSide / rimRadius), 0.0, 1.0); + } + + if (!useCircularSurface && R < shortestSide * 0.45 && distFromSide >= refractionBand) { + vec2 flatUV = backdropSampleUV(actorUV, vec2(0.0)); + vec4 flatSample = sampleOrTintFallback(resolveUV(flatUV)); + float finalOpacity = edgeOpacity * opacity_factor; + + cogl_color_out = applyTintAndShadow(flatSample, localUV, finalOpacity); + return; + } + + float bezelRatio = clamp(distFromSide / refractionBand, 0.0, 1.0); + float normDisp = distFromSide < refractionBand + ? displacementAtRatio(bezelRatio, glassThickness, refractionBand, eta) + : 0.0; + float dispStrength = useCircularSurface ? edgeOpacity : edgeBand; + vec2 dispPx = -dir * normDisp * refractionBand * strength * dispStrength; + + float dispersion = clamp(rgb_fringing * DISPERSION_SCALE, 0.0, 20.0); + vec4 bgColor = sampleDispersed(actorUV, dispPx, dispersion); + if (bgColor.a < 0.01) { + cogl_color_out = vec4(0.0); + return; + } + + vec3 outRGB = mix(bgColor.rgb, vec3(tint_r, tint_g, tint_b), tint * tint_a); + float fresnel = fresnelAtRatio(bezelRatio, REFRACTIVE_INDEX) * edgeOpacity; + float bgLuminance = luminance(outRGB); + float glare = clamp(fresnel * 0.70 * mix(0.40, 1.0, bgLuminance), 0.0, 0.18) + * clamp(gloss, 0.0, 1.0); + outRGB = 1.0 - (1.0 - outRGB) * (1.0 - glare); + outRGB *= 1.0 - smoothstep(0.25, 1.0, localUV.y) * shadow * 0.20; + + float finalOpacity = edgeOpacity * opacity_factor; + cogl_color_out = vec4(clamp(outRGB, 0.0, 1.0) * finalOpacity, finalOpacity); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.js new file mode 100644 index 0000000..27fdcc0 --- /dev/null +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/refraction.js @@ -0,0 +1,849 @@ +import GObject from 'gi://GObject'; +import GLib from 'gi://GLib'; + +import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; +const St = await utils.import_in_shell_only('gi://St'); +const Shell = await utils.import_in_shell_only('gi://Shell'); +const Clutter = await utils.import_in_shell_only('gi://Clutter'); + +const SHADER_FILENAME = 'refraction.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); +const CLIP_STABILIZE_EPSILON = 1.0; +const MAX_BLUR_RADIUS = 48.0; + +const DEFAULT_PARAMS = { + strength: 0.42, + blur_radius: 10, + edge_size: 22, + falloff: 2.4, + corner_radius: 22, + rim_width: 4.8, + rgb_fringing: 0.08, + gloss: 0.55, + webcam_gloss: false, + webcam_device: '', + tint: 0.18, + tint_color: [1.0, 1.0, 1.0, 1.0], + backdrop_zoom: 1.0, + shadow: 0.28, + texture_repeat: 0, + blur_direction: 0, + private_pass: 0, + chained_effect: null, + width: 0, + height: 0, + opacity_factor: 1.0, + clip: [0, 0, -1, -1] +}; + +const REFRACTION_EFFECT_META = { + GTypeName: "RefractionEffect", + Properties: { + 'strength': GObject.ParamSpec.double( + `strength`, + `Strength`, + `Refraction strength`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.42, + ), + 'edge_size': GObject.ParamSpec.double( + `edge_size`, + `Edge Size`, + `Refraction edge size`, + GObject.ParamFlags.READWRITE, + 1.0, 200.0, + 22.0, + ), + 'blur_radius': GObject.ParamSpec.double( + `blur_radius`, + `Blur Radius`, + `Internal glass blur radius`, + GObject.ParamFlags.READWRITE, + 0.0, MAX_BLUR_RADIUS, + 10.0, + ), + 'falloff': GObject.ParamSpec.double( + `falloff`, + `Falloff`, + `Refraction falloff`, + GObject.ParamFlags.READWRITE, + 0.25, 8.0, + 2.4, + ), + 'corner_radius': GObject.ParamSpec.double( + `corner_radius`, + `Corner Radius`, + `Refraction corner radius`, + GObject.ParamFlags.READWRITE, + 0.0, 200.0, + 22.0, + ), + 'rim_width': GObject.ParamSpec.double( + `rim_width`, + `Rim Width`, + `Refraction rim width`, + GObject.ParamFlags.READWRITE, + 1.0, 6.5, + 4.8, + ), + 'rgb_fringing': GObject.ParamSpec.double( + `rgb_fringing`, + `RGB Fringing`, + `Chromatic offset strength`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.08, + ), + 'gloss': GObject.ParamSpec.double( + `gloss`, + `Gloss`, + `Specular highlight strength`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.55, + ), + 'webcam_gloss': GObject.ParamSpec.boolean( + `webcam_gloss`, + `Deprecated Webcam Gloss`, + `Deprecated compatibility property`, + GObject.ParamFlags.READWRITE, + false, + ), + 'webcam_device': GObject.ParamSpec.string( + `webcam_device`, + `Deprecated Webcam Device`, + `Deprecated compatibility property`, + GObject.ParamFlags.READWRITE, + '', + ), + 'tint': GObject.ParamSpec.double( + `tint`, + `Tint`, + `Glass tint strength`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.18, + ), + 'tint_red': GObject.ParamSpec.double( + `tint_red`, + `Tint Red`, + `Glass tint color red`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), + 'tint_green': GObject.ParamSpec.double( + `tint_green`, + `Tint Green`, + `Glass tint color green`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), + 'tint_blue': GObject.ParamSpec.double( + `tint_blue`, + `Tint Blue`, + `Glass tint color blue`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), + 'tint_alpha': GObject.ParamSpec.double( + `tint_alpha`, + `Tint Alpha`, + `Glass tint color alpha`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), + 'backdrop_zoom': GObject.ParamSpec.double( + `backdrop_zoom`, + `Backdrop Zoom`, + `Zoom level of the refracted backdrop`, + GObject.ParamFlags.READWRITE, + 0.1, 4.0, + 1.0, + ), + 'shadow': GObject.ParamSpec.double( + `shadow`, + `Shadow`, + `Inner shadow strength`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 0.28, + ), + 'texture_repeat': GObject.ParamSpec.int( + `texture_repeat`, + `Texture Repeat`, + `Texture repeat behavior`, + GObject.ParamFlags.READWRITE, + 0, 1, + 0, + ), + 'blur_direction': GObject.ParamSpec.int( + `blur_direction`, + `Blur Direction`, + `Private Gaussian blur direction`, + GObject.ParamFlags.READWRITE, + 0, 1, + 0, + ), + 'private_pass': GObject.ParamSpec.int( + `private_pass`, + `Private Pass`, + `Private Gaussian blur pass`, + GObject.ParamFlags.READWRITE, + 0, 1, + 0, + ), + 'chained_effect': GObject.ParamSpec.object( + `chained_effect`, + `Chained Effect`, + `Private chained blur effect`, + GObject.ParamFlags.READWRITE, + GObject.Object, + ), + 'width': GObject.ParamSpec.double( + `width`, + `Width`, + `Width`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'height': GObject.ParamSpec.double( + `height`, + `Height`, + `Height`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + // See corner.js: this is backed by an array setter, but represented + // as a dummy property so pipeline parameter assignment can reach it. + 'clip': GObject.ParamSpec.double( + `clip`, + `Clip`, + `Clip`, + GObject.ParamFlags.READWRITE, + 0.0, Number.MAX_SAFE_INTEGER, + 0.0, + ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), + } +}; + +const RefractionEffectClass = utils.IS_IN_PREFERENCES ? null : class RefractionEffect extends Clutter.ShaderEffect { + + constructor(params) { + const { + webcam_gloss: _webcam_gloss, + webcam_device: _webcam_device, + tint_color: _tint_color, + ...parent_params + } = params; + super({ ...parent_params }); + utils.initialize_shader_effect(this, SHADER_SOURCE); + + this._clip_x0 = null; + this._clip_y0 = null; + this._clip_width = null; + this._clip_height = null; + this._stable_clip_x0 = null; + this._stable_clip_y0 = null; + this._stable_clip_width = null; + this._stable_clip_height = null; + this._stabilize_clip_x = false; + this._stabilize_clip_y = false; + this._clip_settle_timeout_id = null; + + utils.setup_params(this, params); + + this._theme_context = St.ThemeContext.get_for_stage(global.stage); + this._theme_context.connectObject( + 'notify::scale-factor', + _ => this.update_scaled_uniforms(), + this + ); + } + + static get default_params() { + return DEFAULT_PARAMS; + } + + get strength() { + return this._strength; + } + + set strength(value) { + if (this._strength !== value) { + this._strength = value; + + this.set_uniform_value('strength', parseFloat(this._strength - 1e-6)); + this.set_enabled(this.strength > 0.); + } + } + + get edge_size() { + return this._edge_size; + } + + set edge_size(value) { + if (this._edge_size !== value) { + this._edge_size = value; + + this.update_scaled_uniforms(); + + if (this.chained_effect) + this.chained_effect.edge_size = value; + } + } + + get blur_radius() { + return this._blur_radius; + } + + set blur_radius(value) { + if (this._blur_radius !== value) { + this._blur_radius = Math.min(value, MAX_BLUR_RADIUS); + + this.update_scaled_uniforms(); + + if (this.chained_effect) + this.chained_effect.blur_radius = this._blur_radius; + } + } + + get falloff() { + return this._falloff; + } + + set falloff(value) { + if (this._falloff !== value) { + this._falloff = value; + + this.set_uniform_value('falloff', parseFloat(this._falloff - 1e-6)); + + if (this.chained_effect) + this.chained_effect.falloff = value; + } + } + + get corner_radius() { + return this._corner_radius; + } + + set corner_radius(value) { + if (this._corner_radius !== value) { + this._corner_radius = value; + + this.update_scaled_uniforms(); + + if (this.chained_effect) + this.chained_effect.corner_radius = value; + } + } + + get rim_width() { + return this._rim_width; + } + + set rim_width(value) { + const rim_width = Math.max(1.0, Math.min(value, 6.5)); + if (this._rim_width !== rim_width) { + this._rim_width = rim_width; + + this.set_uniform_value('rim_width', parseFloat(this._rim_width - 1e-6)); + + if (this.chained_effect) + this.chained_effect.rim_width = rim_width; + } + } + + get rgb_fringing() { + return this._rgb_fringing; + } + + set rgb_fringing(value) { + if (this._rgb_fringing !== value) { + this._rgb_fringing = value; + + this.set_uniform_value('rgb_fringing', parseFloat(this._rgb_fringing - 1e-6)); + } + } + + get gloss() { + return this._gloss; + } + + set gloss(value) { + if (this._gloss !== value) { + this._gloss = value; + + this.set_uniform_value('gloss', parseFloat(this._gloss - 1e-6)); + } + } + + // Deprecated no-op compatibility properties for old saved pipelines. + get webcam_gloss() { + return this._webcam_gloss; + } + + set webcam_gloss(value) { + this._webcam_gloss = value; + } + + get webcam_device() { + return this._webcam_device; + } + + set webcam_device(value) { + this._webcam_device = value ?? ''; + } + + get tint() { + return this._tint; + } + + set tint(value) { + if (this._tint !== value) { + this._tint = value; + + this.set_uniform_value('tint', parseFloat(this._tint - 1e-6)); + } + } + + get tint_red() { + return this._tint_red; + } + + set tint_red(value) { + if (this._tint_red !== value) { + this._tint_red = value; + + this.set_uniform_value('tint_r', parseFloat(this._tint_red - 1e-6)); + } + } + + get tint_green() { + return this._tint_green; + } + + set tint_green(value) { + if (this._tint_green !== value) { + this._tint_green = value; + + this.set_uniform_value('tint_g', parseFloat(this._tint_green - 1e-6)); + } + } + + get tint_blue() { + return this._tint_blue; + } + + set tint_blue(value) { + if (this._tint_blue !== value) { + this._tint_blue = value; + + this.set_uniform_value('tint_b', parseFloat(this._tint_blue - 1e-6)); + } + } + + get tint_alpha() { + return this._tint_alpha; + } + + set tint_alpha(value) { + if (this._tint_alpha !== value) { + this._tint_alpha = value; + + this.set_uniform_value('tint_a', parseFloat(this._tint_alpha - 1e-6)); + } + } + + get tint_color() { + return [this.tint_red, this.tint_green, this.tint_blue, this.tint_alpha]; + } + + set tint_color(rgba) { + const [r, g, b, a] = rgba; + this.tint_red = r; + this.tint_green = g; + this.tint_blue = b; + this.tint_alpha = a ?? 1.0; + } + + get backdrop_zoom() { + return this._backdrop_zoom; + } + + set backdrop_zoom(value) { + if (this._backdrop_zoom !== value) { + this._backdrop_zoom = value; + + this.set_uniform_value('backdrop_zoom', parseFloat(this._backdrop_zoom - 1e-6)); + } + } + + get shadow() { + return this._shadow; + } + + set shadow(value) { + if (this._shadow !== value) { + this._shadow = value; + + this.set_uniform_value('shadow', parseFloat(this._shadow - 1e-6)); + } + } + + get texture_repeat() { + return this._texture_repeat; + } + + set texture_repeat(value) { + if (this._texture_repeat !== value) { + this._texture_repeat = value; + + this.set_uniform_value('texture_repeat', this._texture_repeat); + + if (this.chained_effect) + this.chained_effect.texture_repeat = value; + } + } + + get blur_direction() { + return this._blur_direction; + } + + set blur_direction(value) { + if (this._blur_direction !== value) { + this._blur_direction = value; + + this.set_uniform_value('blur_direction', this._blur_direction); + } + } + + get private_pass() { + return this._private_pass; + } + + set private_pass(value) { + if (this._private_pass !== value) { + this._private_pass = value; + + this.set_uniform_value('private_pass', this._private_pass); + if (this._private_pass === 1) + this.set_enabled(this.blur_radius > 0.01); + } + } + + get chained_effect() { + return this._chained_effect; + } + + set chained_effect(value) { + this._chained_effect = value; + } + + set(params) { + utils.setup_params(this, params); + } + + get width() { + return this._width; + } + + set width(value) { + if (this._width !== value) { + this._width = value; + + this.set_uniform_value('width', parseFloat(this._width + 3.0 - 1e-6)); + this.update_scaled_uniforms(); + + if (this.chained_effect) + this.chained_effect.width = value; + } + } + + get height() { + return this._height; + } + + set height(value) { + if (this._height !== value) { + this._height = value; + + this.set_uniform_value('height', parseFloat(this._height + 3.0 - 1e-6)); + this.update_scaled_uniforms(); + + if (this.chained_effect) + this.chained_effect.height = value; + } + } + + get clip() { + return [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height]; + } + + set clip(value) { + const previous_clip = this.clip; + [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height] = value; + + let shader_clip = this._stabilized_clip(previous_clip); + + this.set_uniform_value('clip_x0', parseFloat(shader_clip[0] - 1e-6)); + this.set_uniform_value('clip_y0', parseFloat(shader_clip[1] - 1e-6)); + this.set_uniform_value('clip_width', parseFloat(shader_clip[2] + 3.0 - 1e-6)); + this.set_uniform_value('clip_height', parseFloat(shader_clip[3] + 3.0 - 1e-6)); + this.update_scaled_uniforms(); + } + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); + + if (this.chained_effect) + this.chained_effect.opacity_factor = value; + } + } + + _stabilized_clip(previous_clip) { + if (this._clip_width < 0 || this._clip_height < 0) { + this._stable_clip_x0 = null; + this._stable_clip_y0 = null; + this._stable_clip_width = null; + this._stable_clip_height = null; + this._stabilize_clip_x = false; + this._stabilize_clip_y = false; + if (this._clip_settle_timeout_id) { + GLib.Source.remove(this._clip_settle_timeout_id); + this._clip_settle_timeout_id = null; + } + return [ + this._clip_x0, + this._clip_y0, + this._clip_width, + this._clip_height + ]; + } + + const [previous_x0, previous_y0, previous_width, previous_height] = previous_clip; + + [this._stable_clip_x0, this._stable_clip_width, this._stabilize_clip_x] = + this._stabilized_clip_axis( + this._clip_x0, + this._clip_width, + previous_x0, + previous_width, + this._stable_clip_x0, + this._stable_clip_width, + this._stabilize_clip_x + ); + [this._stable_clip_y0, this._stable_clip_height, this._stabilize_clip_y] = + this._stabilized_clip_axis( + this._clip_y0, + this._clip_height, + previous_y0, + previous_height, + this._stable_clip_y0, + this._stable_clip_height, + this._stabilize_clip_y + ); + + if (this._clip_settle_timeout_id) + GLib.Source.remove(this._clip_settle_timeout_id); + + if (!this._stabilize_clip_x && !this._stabilize_clip_y) { + this._clip_settle_timeout_id = null; + return [ + this._stable_clip_x0, + this._stable_clip_y0, + this._stable_clip_width, + this._stable_clip_height + ]; + } + + this._clip_settle_timeout_id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 220, () => { + this._stable_clip_x0 = this._clip_x0; + this._stable_clip_y0 = this._clip_y0; + this._stable_clip_width = this._clip_width; + this._stable_clip_height = this._clip_height; + this._stabilize_clip_x = false; + this._stabilize_clip_y = false; + this._clip_settle_timeout_id = null; + this.clip = [this._clip_x0, this._clip_y0, this._clip_width, this._clip_height]; + this.queue_repaint(); + return GLib.SOURCE_REMOVE; + }); + + return [ + this._stable_clip_x0, + this._stable_clip_y0, + this._stable_clip_width, + this._stable_clip_height + ]; + } + + _stabilized_clip_axis( + start, + size, + previous_start, + previous_size, + stable_start, + stable_size, + stabilizing + ) { + const size_changed = + previous_size !== null && + previous_size >= 0 && + Math.abs(size - previous_size) > CLIP_STABILIZE_EPSILON; + + if (!stabilizing && !size_changed) + return [start, size, false]; + + const end = start + size; + const resolved_stable_start = stable_start ?? previous_start ?? start; + const resolved_stable_size = stable_size ?? previous_size ?? size; + const stable_end = resolved_stable_start + resolved_stable_size; + const resolved_start = Math.min(resolved_stable_start, start); + const resolved_end = Math.max(stable_end, end); + + return [resolved_start, resolved_end - resolved_start, true]; + } + + update_scaled_uniforms() { + const scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + const rect_width = + this._stable_clip_width ?? (this._clip_width >= 0 ? this._clip_width : this.width); + const rect_height = + this._stable_clip_height ?? (this._clip_height >= 0 ? this._clip_height : this.height); + const max_edge = Math.max(1, Math.min(rect_width, rect_height) / 2); + const edge_size = Math.min(this.edge_size * scale_factor, max_edge); + const corner_radius = Math.min(this.corner_radius * scale_factor, max_edge); + + this.set_uniform_value('edge_size', parseFloat(edge_size - 1e-6)); + this.set_uniform_value('corner_radius', parseFloat(corner_radius - 1e-6)); + const blur_radius = Math.min(this.blur_radius, MAX_BLUR_RADIUS) * scale_factor; + this.set_uniform_value('blur_radius', parseFloat(blur_radius - 1e-6)); + if (this.private_pass === 1) + this.set_enabled(blur_radius > 0.01); + } + + vfunc_set_actor(actor) { + if (this.chained_effect) + this.chained_effect.get_actor()?.remove_effect(this.chained_effect); + + if (this._actor_connection_size_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_size_id); + } + if (this._actor_connection_clip_rect_id) { + let old_actor = this.get_actor(); + old_actor?.disconnect(this._actor_connection_clip_rect_id); + } + if (this._clip_settle_timeout_id) { + GLib.Source.remove(this._clip_settle_timeout_id); + this._clip_settle_timeout_id = null; + } + if (actor) { + this.width = actor.width; + this.height = actor.height; + this._actor_connection_size_id = actor.connect('notify::size', _ => { + this.width = actor.width; + this.height = actor.height; + }); + + this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; + this._actor_connection_clip_rect_id = actor.connect('notify::clip-rect', _ => { + this.clip = actor.has_clip ? actor.get_clip() : [0, 0, -10, -10]; + }); + } + else { + this._actor_connection_size_id = null; + this._actor_connection_clip_rect_id = null; + this._stable_clip_x0 = null; + this._stable_clip_y0 = null; + this._stable_clip_width = null; + this._stable_clip_height = null; + this._stabilize_clip_x = false; + this._stabilize_clip_y = false; + } + + super.vfunc_set_actor(actor); + + if (this.private_pass === 0) { + if (!this.chained_effect) { + const chained_params = { + strength: this.strength, + blur_radius: this.blur_radius, + edge_size: this.edge_size, + falloff: this.falloff, + corner_radius: this.corner_radius, + rim_width: this.rim_width, + rgb_fringing: this.rgb_fringing, + gloss: this.gloss, + tint: this.tint, + shadow: this.shadow, + texture_repeat: this.texture_repeat, + width: this.width, + height: this.height, + clip: this.clip, + blur_direction: 1, + private_pass: 1, + opacity_factor: this._opacity_factor + }; + + this.chained_effect = new RefractionEffect(chained_params); + } + + if (actor !== null) + actor.add_effect(this.chained_effect); + } + } + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + this.set_uniform_value('blur_direction', this.blur_direction); + this.set_uniform_value('private_pass', this.private_pass); + + super.vfunc_paint_target(paint_node, paint_context); + } + + vfunc_dispose() { + if (this._clip_settle_timeout_id) { + GLib.Source.remove(this._clip_settle_timeout_id); + this._clip_settle_timeout_id = null; + } + + if (this.chained_effect) { + this.chained_effect.get_actor()?.remove_effect(this.chained_effect); + this.chained_effect = null; + } + + this._theme_context?.disconnectObject(this); + this._theme_context = null; + + if (super.vfunc_dispose) + super.vfunc_dispose(); + } +}; + +export const RefractionEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(REFRACTION_EFFECT_META, RefractionEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.glsl index b7a35ac..ba09fe0 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.glsl @@ -1,4 +1,5 @@ uniform sampler2D tex; +uniform float opacity_factor; vec3 rgb_to_hsl(vec3 c) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); @@ -14,5 +15,5 @@ void main(void) { vec2 uv = cogl_tex_coord_in[0].xy; vec4 rgba = texture2D(tex, uv); vec4 hsla = vec4(rgb_to_hsl(rgba.xyz), rgba.w); - cogl_color_out = hsla; -} \ No newline at end of file + cogl_color_out = mix(rgba, hsla, opacity_factor); +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.js index 5c4eb05..81b3596 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/rgb_to_hsl.js @@ -1,31 +1,64 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'rgb_to_hsl.glsl'; -const DEFAULT_PARAMS = {}; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); +const DEFAULT_PARAMS = { + opacity_factor: 1 +}; -export const RgbToHslEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const RGB_TO_HSL_EFFECT_META = { GTypeName: "RgbToHslEffect", - Properties: {} - }, class RgbToHslEffect extends Clutter.ShaderEffect { + Properties: { + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), + } +}; + +const RgbToHslEffectClass = utils.IS_IN_PREFERENCES ? null : class RgbToHslEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); - utils.setup_params(this, params); + utils.initialize_shader_effect(this, SHADER_SOURCE); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + + utils.setup_params(this, params); } static get default_params() { return DEFAULT_PARAMS; } - }); \ No newline at end of file + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; + + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); + } + } + + vfunc_paint_target(paint_node, paint_context) { + uniforms.upload_uniforms(this); + super.vfunc_paint_target(paint_node, paint_context); + } +}; + +export const RgbToHslEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(RGB_TO_HSL_EFFECT_META, RgbToHslEffectClass, SHADER_SOURCE); diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.glsl b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.glsl index 5cc06ec..3d743df 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.glsl +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.glsl @@ -2,13 +2,14 @@ uniform sampler2D tex; uniform int factor; uniform float width; uniform float height; +uniform float opacity_factor; #define CORRECTION 2.25 -#define SIZE_ADDITION 3 +#define SIZE_ADDITION 3.0 vec4 get_texture_at_position(vec2 position) { vec2 raw_position = position + vec2(CORRECTION, CORRECTION); - vec2 raw_uv = raw_position / vec2(width + SIZE_ADDITION, height + SIZE_ADDITION); + vec2 raw_uv = raw_position / vec2(max(1.0, width + SIZE_ADDITION), max(1.0, height + SIZE_ADDITION)); return texture2D(tex, raw_uv); } @@ -20,38 +21,41 @@ ivec2 get_corrected_position() { } void main() { + vec4 source_color = texture2D(tex, cogl_tex_coord0_in.st); ivec2 corrected_position = get_corrected_position(); + int safe_factor = max(1, factor); - vec2 adjusted_position = corrected_position / factor; + vec2 adjusted_position = vec2(corrected_position / safe_factor); - cogl_color_out = get_texture_at_position(adjusted_position); + vec4 effect_color = get_texture_at_position(adjusted_position); + cogl_color_out = mix(source_color, effect_color, opacity_factor); // round - if (distance(corrected_position, (floor(adjusted_position) + 0.5) * factor) < factor / 2.5) { + if (distance(vec2(corrected_position), (floor(adjusted_position) + 0.5) * float(safe_factor)) < float(safe_factor) / 2.5) { //cogl_color_out = get_texture_at_position(adjusted_position); } else { //cogl_color_out = vec4(0, 0, 0, 1); } // square - if (mod(corrected_position.x, factor) >= 2 && mod(corrected_position.y, factor) >= 2) { + if (mod(float(corrected_position.x), float(safe_factor)) >= 2.0 && mod(float(corrected_position.y), float(safe_factor)) >= 2.0) { //cogl_color_out = get_texture_at_position(adjusted_position); } else { //cogl_color_out = vec4(0, 0, 0, 1); } // local mix - vec4 color = vec4(0); + vec4 color = vec4(0.0); int count = 0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { - vec2 lookup_position = adjusted_position + vec2(i, j); - if (all(greaterThanEqual(lookup_position, vec2(0, 0))) && - all(lessThan(lookup_position, vec2(width, height) / factor))) { + vec2 lookup_position = adjusted_position + vec2(float(i), float(j)); + if (all(greaterThanEqual(lookup_position, vec2(0.0, 0.0))) && + all(lessThan(lookup_position, vec2(width, height) / float(safe_factor)))) { color += get_texture_at_position(lookup_position); count += 1; } } } //cogl_color_out = color / count; -} \ No newline at end of file +} diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.js index fb719c3..d29ba8c 100644 --- a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.js +++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/effects/upscale.js @@ -1,18 +1,18 @@ import GObject from 'gi://GObject'; import * as utils from '../conveniences/utils.js'; +import * as uniforms from '../conveniences/shader_uniforms.js'; const Shell = await utils.import_in_shell_only('gi://Shell'); const Clutter = await utils.import_in_shell_only('gi://Clutter'); const SHADER_FILENAME = 'upscale.glsl'; +const SHADER_SOURCE = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); const DEFAULT_PARAMS = { - factor: 8, width: 0, height: 0 + factor: 8, opacity_factor: 1, width: 0, height: 0 }; -export const UpscaleEffect = utils.IS_IN_PREFERENCES ? - { default_params: DEFAULT_PARAMS } : - new GObject.registerClass({ +const UPSCALE_EFFECT_META = { GTypeName: "UpscaleEffect", Properties: { 'factor': GObject.ParamSpec.int( @@ -23,6 +23,14 @@ export const UpscaleEffect = utils.IS_IN_PREFERENCES ? 0, 64, 8, ), + 'opacity_factor': GObject.ParamSpec.double( + `opacity_factor`, + `Opacity factor`, + `Opacity factor`, + GObject.ParamFlags.READWRITE, + 0.0, 1.0, + 1.0, + ), 'width': GObject.ParamSpec.double( `width`, `Width`, @@ -40,16 +48,17 @@ export const UpscaleEffect = utils.IS_IN_PREFERENCES ? 0.0, ) } - }, class UpscaleEffect extends Clutter.ShaderEffect { +}; + +const UpscaleEffectClass = utils.IS_IN_PREFERENCES ? null : class UpscaleEffect extends Clutter.ShaderEffect { + constructor(params) { - super(params); + super(); + + utils.initialize_shader_effect(this, SHADER_SOURCE); - utils.setup_params(this, params); - // set shader source - this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url); - if (this._source) - this.set_shader_source(this._source); + utils.setup_params(this, params); } static get default_params() { @@ -61,10 +70,23 @@ export const UpscaleEffect = utils.IS_IN_PREFERENCES ? } set factor(value) { - if (this._factor !== value) { - this._factor = value; + const v = Math.max(1, value || 1); + if (this._factor !== v) { + this._factor = v; + + uniforms.set_uniform(this, 'factor', this._factor); + } + } + + get opacity_factor() { + return this._opacity_factor; + } + + set opacity_factor(value) { + if (this._opacity_factor !== value) { + this._opacity_factor = value; - this.set_uniform_value('factor', this._factor); + uniforms.set_uniform(this, 'opacity_factor', parseFloat(this._opacity_factor)); } } @@ -73,10 +95,11 @@ export const UpscaleEffect = utils.IS_IN_PREFERENCES ? } set width(value) { - if (this._width !== value) { - this._width = value; + const v = Math.max(1, value || 1); + if (this._width !== v) { + this._width = v; - this.set_uniform_value('width', parseFloat(this._width - 1e-6)); + uniforms.set_uniform(this, 'width', parseFloat(this._width - 1e-6)); } } @@ -85,10 +108,11 @@ export const UpscaleEffect = utils.IS_IN_PREFERENCES ? } set height(value) { - if (this._height !== value) { - this._height = value; + const v = Math.max(1, value || 1); + if (this._height !== v) { + this._height = v; - this.set_uniform_value('height', parseFloat(this._height - 1e-6)); + uniforms.set_uniform(this, 'height', parseFloat(this._height - 1e-6)); } } @@ -112,9 +136,17 @@ export const UpscaleEffect = utils.IS_IN_PREFERENCES ? } vfunc_paint_target(paint_node, paint_context) { - // force setting nearest-neighbour texture filtering - this.get_pipeline().set_layer_filters(0, 9728, 9728); + uniforms.upload_uniforms(this); + + const pipeline = this.get_pipeline(); + if (pipeline) { + pipeline.set_layer_filters(0, 9728, 9728); + } super.vfunc_paint_target(paint_node, paint_context); } - }); \ No newline at end of file +}; + +export const UpscaleEffect = utils.IS_IN_PREFERENCES + ? { default_params: DEFAULT_PARAMS } + : utils.register_shader_effect(UPSCALE_EFFECT_META, UpscaleEffectClass, SHADER_SOURCE); -- cgit v1.3