From 72f1c8f0e62f4aa389326df6c3268f3fabc2463a Mon Sep 17 00:00:00 2001 From: Christian Schendel Date: Tue, 9 Dec 2025 21:44:11 +0000 Subject: [PATCH] upgpkg: kwin-effects-forceblur-1.5.0-11: rebuild for kwin-6.5.4-1 incorporate some pull-requests --- .gitignore | 1 + 239.patch | 2110 ++++++++++++++++++++++++++++++++++++++++++++++++++++ PKGBUILD | 10 +- 3 files changed, 2119 insertions(+), 2 deletions(-) create mode 100644 239.patch diff --git a/.gitignore b/.gitignore index ffbfd3c..40c0180 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ !/LICENSES/*.txt !REUSE.toml !*.install +!*.patch diff --git a/239.patch b/239.patch new file mode 100644 index 0000000..ce097a8 --- /dev/null +++ b/239.patch @@ -0,0 +1,2110 @@ +From a2ca71ea55f878924213337b40f0d30ba774e964 Mon Sep 17 00:00:00 2001 +From: German +Date: Sun, 10 Aug 2025 03:01:32 +0200 +Subject: [PATCH 1/4] refraction: add corner radius and mode settings, adjust + maximums, add concave shader mode + +--- + src/blur.cpp | 4 + + src/blur.h | 2 + + src/blur.kcfg | 6 + + src/kcm/blur_config.cpp | 23 ++++ + src/kcm/blur_config.ui | 170 ++++++++++++++++++++++----- + src/settings.cpp | 15 ++- + src/settings.h | 2 + + src/shaders/texture.frag | 43 +++++++ + src/shaders/texture_core.frag | 47 ++++++++ + src/shaders/upsample.frag | 204 +++++++++++++++++++++++++++++++++ + src/shaders/upsample.glsl | 120 +++++++++++++------ + src/shaders/upsample_core.frag | 198 ++++++++++++++++++++++++++++++++ + src/shaders/upsample_core.glsl | 111 ++++++++++++------ + 13 files changed, 847 insertions(+), 98 deletions(-) + create mode 100644 src/shaders/texture.frag + create mode 100644 src/shaders/texture_core.frag + create mode 100644 src/shaders/upsample.frag + create mode 100644 src/shaders/upsample_core.frag + +diff --git a/src/blur.cpp b/src/blur.cpp +index 03992db40..b2e37b845 100644 +--- a/src/blur.cpp ++++ b/src/blur.cpp +@@ -97,10 +97,12 @@ BlurEffect::BlurEffect() + m_upsamplePass.blurSizeLocation = m_upsamplePass.shader->uniformLocation("blurSize"); + m_upsamplePass.opacityLocation = m_upsamplePass.shader->uniformLocation("opacity"); + m_upsamplePass.edgeSizePixelsLocation = m_upsamplePass.shader->uniformLocation("edgeSizePixels"); ++ m_upsamplePass.refractionCornerRadiusPixelsLocation = m_upsamplePass.shader->uniformLocation("refractionCornerRadiusPixels"); + m_upsamplePass.refractionStrengthLocation = m_upsamplePass.shader->uniformLocation("refractionStrength"); + m_upsamplePass.refractionNormalPowLocation = m_upsamplePass.shader->uniformLocation("refractionNormalPow"); + m_upsamplePass.refractionRGBFringingLocation = m_upsamplePass.shader->uniformLocation("refractionRGBFringing"); + m_upsamplePass.refractionTextureRepeatModeLocation = m_upsamplePass.shader->uniformLocation("refractionTextureRepeatMode"); ++ m_upsamplePass.refractionModeLocation = m_upsamplePass.shader->uniformLocation("refractionMode"); + } + + m_texture.shader = ShaderManager::instance()->generateShaderFromFile(ShaderTrait::MapTexture, +@@ -1108,10 +1110,12 @@ void BlurEffect::blur(BlurRenderData &renderInfo, const RenderTarget &renderTarg + if (w && m_settings.refraction.refractionStrength > 0) { + m_upsamplePass.shader->setUniform(m_upsamplePass.edgeSizePixelsLocation, + std::min(m_settings.refraction.edgeSizePixels, (float)std::min(deviceBackgroundRect.width() / 2, deviceBackgroundRect.height() / 2))); ++ m_upsamplePass.shader->setUniform(m_upsamplePass.refractionCornerRadiusPixelsLocation, m_settings.refraction.refractionCornerRadiusPixels); + m_upsamplePass.shader->setUniform(m_upsamplePass.refractionStrengthLocation, m_settings.refraction.refractionStrength); + m_upsamplePass.shader->setUniform(m_upsamplePass.refractionNormalPowLocation, m_settings.refraction.refractionNormalPow); + m_upsamplePass.shader->setUniform(m_upsamplePass.refractionRGBFringingLocation, m_settings.refraction.refractionRGBFringing); + m_upsamplePass.shader->setUniform(m_upsamplePass.refractionTextureRepeatModeLocation, m_settings.refraction.refractionTextureRepeatMode); ++ m_upsamplePass.shader->setUniform(m_upsamplePass.refractionModeLocation, m_settings.refraction.refractionMode); + } + + glEnable(GL_BLEND); +diff --git a/src/blur.h b/src/blur.h +index c06a9ccfe..9ffcf9314 100644 +--- a/src/blur.h ++++ b/src/blur.h +@@ -159,10 +159,12 @@ public Q_SLOTS: + int opacityLocation; + + int edgeSizePixelsLocation; ++ int refractionCornerRadiusPixelsLocation; + int refractionStrengthLocation; + int refractionNormalPowLocation; + int refractionRGBFringingLocation; + int refractionTextureRepeatModeLocation; ++ int refractionModeLocation; + } m_upsamplePass; + + struct +diff --git a/src/blur.kcfg b/src/blur.kcfg +index 7c52203bd..2dc1ea72e 100644 +--- a/src/blur.kcfg ++++ b/src/blur.kcfg +@@ -91,11 +91,17 @@ class3 + + 20.0 + ++ ++ 8.0 ++ + + 1.0 + + + 0 + ++ ++ 0 ++ + + +diff --git a/src/kcm/blur_config.cpp b/src/kcm/blur_config.cpp +index d50254ff4..cabef7893 100644 +--- a/src/kcm/blur_config.cpp ++++ b/src/kcm/blur_config.cpp +@@ -15,6 +15,7 @@ + + #include + #include ++#include + + namespace KWin + { +@@ -28,6 +29,28 @@ BlurEffectConfig::BlurEffectConfig(QObject *parent, const KPluginMetaData &data) + BlurConfig::instance("kwinrc"); + addConfig(BlurConfig::self(), widget()); + ++ // Disable Edge Behavior when Concave mode is selected - not relevant ++ auto updateEdgeBehaviorEnabled = [this]() { ++ const bool concave = ui.kcfg_RefractionMode && ui.kcfg_RefractionMode->currentIndex() == 1; ++ if (ui.kcfg_RefractionTextureRepeatMode) { ++ ui.kcfg_RefractionTextureRepeatMode->setEnabled(!concave); ++ } ++ if (ui.labelRefractionTextureRepeatMode) { ++ ui.labelRefractionTextureRepeatMode->setEnabled(!concave); ++ } ++ // Corner radius is only relevant for Concave as Basic breaks with low values ++ if (ui.kcfg_RefractionCornerRadius) { ++ ui.kcfg_RefractionCornerRadius->setEnabled(concave); ++ } ++ if (ui.labelRefractionCornerRadius) { ++ ui.labelRefractionCornerRadius->setEnabled(concave); ++ } ++ }; ++ if (ui.kcfg_RefractionMode) { ++ connect(ui.kcfg_RefractionMode, QOverload::of(&QComboBox::currentIndexChanged), this, [updateEdgeBehaviorEnabled](int){ updateEdgeBehaviorEnabled(); }); ++ updateEdgeBehaviorEnabled(); ++ } ++ + connect(ui.staticBlurImagePicker, &QPushButton::clicked, this, &BlurEffectConfig::slotStaticBlurImagePickerClicked); + + QFile about(":/effects/forceblur/kcm/about.html"); +diff --git a/src/kcm/blur_config.ui b/src/kcm/blur_config.ui +index 2d806bd08..787819a1b 100644 +--- a/src/kcm/blur_config.ui ++++ b/src/kcm/blur_config.ui +@@ -402,7 +402,7 @@ + 0 + + +- 20 ++ 30 + + + 1 +@@ -431,6 +431,47 @@ + + + ++ ++ ++ Refraction Mode: ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Fixed ++ ++ ++ ++ 20 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ Basic (Bulge) ++ ++ ++ ++ ++ Concave (Lens) ++ ++ ++ ++ ++ ++ ++ + + + Refraction Edge Size: +@@ -468,7 +509,7 @@ + 0 + + +- 20 ++ 30 + + + 1 +@@ -563,16 +604,16 @@ + + + +- ++ + +- RGB Fringing Strength: ++ Refraction Corner Radius: + + + + +- ++ + +- ++ + + Qt::Horizontal + +@@ -588,28 +629,25 @@ + + + +- ++ + +- Off ++ Square + + + + +- ++ + + 0 + + +- 20 ++ 200 + + + 1 + + +- 1 +- +- +- 10 ++ 7 + + + Qt::Horizontal +@@ -617,26 +655,29 @@ + + QSlider::TicksBelow + ++ ++ 7 ++ + + + +- ++ + +- Strong ++ Round + + + + + + +- ++ + +- Edge Behavior: ++ RGB Fringing Strength: + + + + +- ++ + + + +@@ -654,21 +695,90 @@ + + + +- +- +- +- Clamp (extend edge pixels) +- +- +- +- +- Flip (mirror texture) +- +- ++ ++ ++ Off ++ ++ ++ ++ ++ ++ ++ 0 ++ ++ ++ 30 ++ ++ ++ 1 ++ ++ ++ 1 ++ ++ ++ 10 ++ ++ ++ Qt::Horizontal ++ ++ ++ QSlider::TicksBelow ++ ++ ++ ++ ++ ++ ++ Strong ++ + + + + ++ ++ ++ ++ Edge Behavior: ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Fixed ++ ++ ++ ++ 20 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ ++ Clamp (extend edge pixels) ++ ++ ++ ++ ++ Flip (mirror texture) ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/settings.cpp b/src/settings.cpp +index ae3db6001..37c0aa98c 100644 +--- a/src/settings.cpp ++++ b/src/settings.cpp +@@ -66,10 +66,21 @@ void BlurSettings::read() + staticBlur.blurCustomImage = BlurConfig::fakeBlurCustomImageBlur(); + + refraction.edgeSizePixels = BlurConfig::refractionEdgeSize() * 10; +- refraction.refractionStrength = BlurConfig::refractionStrength() / 20.0; ++ ++ { ++ const double maxCorner = 200.0; ++ const double steps = 30.0; ++ const double stepSize = maxCorner / steps; // ≈6.6667 ++ const double raw = BlurConfig::refractionCornerRadius(); ++ const double snapped = std::round(raw / stepSize) * stepSize; ++ refraction.refractionCornerRadiusPixels = snapped; ++ } ++ ++ refraction.refractionStrength = BlurConfig::refractionStrength() / 30.0; + refraction.refractionNormalPow = BlurConfig::refractionNormalPow() / 2.0; +- refraction.refractionRGBFringing = BlurConfig::refractionRGBFringing() / 20.0; // Scale to 0-1 range ++ refraction.refractionRGBFringing = BlurConfig::refractionRGBFringing() / 30.0; + refraction.refractionTextureRepeatMode = BlurConfig::refractionTextureRepeatMode(); ++ refraction.refractionMode = BlurConfig::refractionMode(); + } + + } +\ No newline at end of file +diff --git a/src/settings.h b/src/settings.h +index 33cf06eae..37e84bbe2 100644 +--- a/src/settings.h ++++ b/src/settings.h +@@ -61,10 +61,12 @@ struct StaticBlurSettings + struct RefractionSettings + { + float edgeSizePixels; ++ float refractionCornerRadiusPixels; + float refractionStrength; + float refractionNormalPow; + float refractionRGBFringing; + int refractionTextureRepeatMode; ++ int refractionMode; // 0: Basic (bulge), 1: Concave (lens) + }; + + class BlurSettings +diff --git a/src/shaders/texture.frag b/src/shaders/texture.frag +new file mode 100644 +index 000000000..28fcc67a2 +--- /dev/null ++++ b/src/shaders/texture.frag +@@ -0,0 +1,43 @@ ++uniform float topCornerRadius; ++uniform float bottomCornerRadius; ++uniform float antialiasing; ++ ++uniform vec2 blurSize; ++uniform float opacity; ++ ++vec4 roundedRectangle(vec2 fragCoord, vec3 texture) ++{ ++ if (topCornerRadius == 0 && bottomCornerRadius == 0) { ++ return vec4(texture, opacity); ++ } ++ ++ vec2 halfblurSize = blurSize * 0.5; ++ vec2 p = fragCoord - halfblurSize; ++ float radius = 0.0; ++ if ((fragCoord.y <= bottomCornerRadius) ++ && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { ++ radius = bottomCornerRadius; ++ p.y -= radius; ++ } else if ((fragCoord.y >= blurSize.y - topCornerRadius) ++ && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { ++ radius = topCornerRadius; ++ p.y += radius; ++ } ++ float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; ++ ++ float s = smoothstep(0.0, antialiasing, distance); ++ return vec4(texture, mix(1.0, 0.0, s) * opacity); ++} ++ ++ ++uniform sampler2D texUnit; ++uniform vec2 textureSize; ++uniform vec2 texStartPos; ++ ++varying vec2 uv; ++ ++void main(void) ++{ ++ vec2 tex = (texStartPos.xy + vec2(uv.x, 1.0 - uv.y) * blurSize) / textureSize; ++ gl_FragColor = roundedRectangle(uv * blurSize, texture2D(texUnit, tex).rgb); ++} +\ No newline at end of file +diff --git a/src/shaders/texture_core.frag b/src/shaders/texture_core.frag +new file mode 100644 +index 000000000..6ec76f7be +--- /dev/null ++++ b/src/shaders/texture_core.frag +@@ -0,0 +1,47 @@ ++#version 140 ++ ++uniform float topCornerRadius; ++uniform float bottomCornerRadius; ++uniform float antialiasing; ++ ++uniform vec2 blurSize; ++uniform float opacity; ++ ++vec4 roundedRectangle(vec2 fragCoord, vec3 texture) ++{ ++ if (topCornerRadius == 0 && bottomCornerRadius == 0) { ++ return vec4(texture, opacity); ++ } ++ ++ vec2 halfblurSize = blurSize * 0.5; ++ vec2 p = fragCoord - halfblurSize; ++ float radius = 0.0; ++ if ((fragCoord.y <= bottomCornerRadius) ++ && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { ++ radius = bottomCornerRadius; ++ p.y -= radius; ++ } else if ((fragCoord.y >= blurSize.y - topCornerRadius) ++ && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { ++ radius = topCornerRadius; ++ p.y += radius; ++ } ++ float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; ++ ++ float s = smoothstep(0.0, antialiasing, distance); ++ return vec4(texture, mix(1.0, 0.0, s) * opacity); ++} ++ ++ ++uniform sampler2D texUnit; ++uniform vec2 textureSize; ++uniform vec2 texStartPos; ++ ++in vec2 uv; ++ ++out vec4 fragColor; ++ ++void main(void) ++{ ++ vec2 tex = (texStartPos.xy + vec2(uv.x, 1.0 - uv.y) * blurSize) / textureSize; ++ fragColor = roundedRectangle(uv * blurSize, texture(texUnit, tex).rgb); ++} +diff --git a/src/shaders/upsample.frag b/src/shaders/upsample.frag +new file mode 100644 +index 000000000..4cea5bb03 +--- /dev/null ++++ b/src/shaders/upsample.frag +@@ -0,0 +1,204 @@ ++uniform float topCornerRadius; ++uniform float bottomCornerRadius; ++uniform float antialiasing; ++ ++uniform vec2 blurSize; ++uniform float opacity; ++ ++vec4 roundedRectangle(vec2 fragCoord, vec3 texture) ++{ ++ if (topCornerRadius == 0 && bottomCornerRadius == 0) { ++ return vec4(texture, opacity); ++ } ++ ++ vec2 halfblurSize = blurSize * 0.5; ++ vec2 p = fragCoord - halfblurSize; ++ float radius = 0.0; ++ if ((fragCoord.y <= bottomCornerRadius) ++ && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { ++ radius = bottomCornerRadius; ++ p.y -= radius; ++ } else if ((fragCoord.y >= blurSize.y - topCornerRadius) ++ && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { ++ radius = topCornerRadius; ++ p.y += radius; ++ } ++ float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; ++ ++ float s = smoothstep(0.0, antialiasing, distance); ++ return vec4(texture, mix(1.0, 0.0, s) * opacity); ++} ++ ++ ++uniform sampler2D texUnit; ++uniform float offset; ++uniform vec2 halfpixel; ++ ++uniform bool noise; ++uniform sampler2D noiseTexture; ++uniform vec2 noiseTextureSize; ++ ++uniform float edgeSizePixels; ++uniform float refractionCornerRadiusPixels; ++uniform float refractionStrength; ++uniform float refractionNormalPow; ++uniform float refractionRGBFringing; ++uniform int refractionTextureRepeatMode; ++uniform int refractionMode; // 0: Basic, 1: Concave ++ ++varying vec2 uv; ++ ++vec2 applyTextureRepeatMode(vec2 coord) ++{ ++ if (refractionTextureRepeatMode == 0) { ++ return clamp(coord, 0.0, 1.0); ++ } else if (refractionTextureRepeatMode == 1) { ++ // flip on both axes ++ vec2 flip = mod(coord, 2.0); ++ ++ vec2 result = coord; ++ if (flip.x > 1.0) { ++ result.x = 1.0 - mod(coord.x, 1.0); ++ } else { ++ result.x = mod(coord.x, 1.0); ++ } ++ ++ if (flip.y > 1.0) { ++ result.y = 1.0 - mod(coord.y, 1.0); ++ } else { ++ result.y = mod(coord.y, 1.0); ++ } ++ ++ return result; ++ } ++ return coord; ++} ++ ++// Concave lens-style radial mapping around the rect center, shaped by distance to edge ++vec2 concaveLensCoord(vec2 uv, float strength, float fringing, float dist, vec2 halfBlurSize) ++{ ++ // Edge proximity: 0 in the deep interior, 1 near the rounded rectangle edge ++ float edgeProximity = clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ ++ float scaleR = 1.0 - shaped * strength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * strength; ++ float scaleB = 1.0 - shaped * strength * (1.0 - fringing); ++ ++ // Return per-channel lens coords packed in vec2 three times via caller ++ // Caller samples each channel separately with the right scale ++ // Here we just return the green channel scale as a convenience; R and B will be built in caller ++ return vec2(0.5) + fromCenter * scaleG; ++} ++ ++// source: https://iquilezles.org/articles/distfunctions2d/ ++// https://www.shadertoy.com/view/4llXD7 ++float roundedRectangleDist(vec2 p, vec2 b, float r) ++{ ++ vec2 q = abs(p) - b + r; ++ return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; ++} ++ ++void main(void) ++{ ++ vec2 offsets[8] = vec2[]( ++ vec2(-halfpixel.x * 2.0, 0.0), ++ vec2(-halfpixel.x, halfpixel.y), ++ vec2(0.0, halfpixel.y * 2.0), ++ vec2(halfpixel.x, halfpixel.y), ++ vec2(halfpixel.x * 2.0, 0.0), ++ vec2(halfpixel.x, -halfpixel.y), ++ vec2(0.0, -halfpixel.y * 2.0), ++ vec2(-halfpixel.x, -halfpixel.y) ++ ); ++ float weights[8] = float[](1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0); ++ float weightSum = 12.0; ++ vec4 sum = vec4(0, 0, 0, 0); ++ ++ if (refractionStrength > 0) { ++ vec2 halfBlurSize = 0.5 * blurSize; ++ vec2 position = uv * blurSize - halfBlurSize.xy; ++ float cornerR = min(refractionCornerRadiusPixels, min(halfBlurSize.x, halfBlurSize.y)); ++ float distConcave = roundedRectangleDist(position, halfBlurSize, cornerR); ++ float distBulge = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); ++ ++ // Different refraction behavior depending on mode ++ if (refractionMode == 1) { ++ // Concave: lens-like radial mapping with RGB fringing ++ float fringing = refractionRGBFringing * 0.3; ++ float baseStrength = 0.2 * refractionStrength; ++ ++ // Edge proximity shaping ++ float edgeProximity = clamp(1.0 + distConcave / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ float scaleR = 1.0 - shaped * baseStrength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * baseStrength; ++ float scaleB = 1.0 - shaped * baseStrength * (1.0 - fringing); ++ ++ vec2 coordR = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleR); ++ vec2 coordG = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleG); ++ vec2 coordB = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture2D(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture2D(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture2D(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture2D(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } else { ++ // Basic: convex/bulge-like along inward normal from the rounded-rect edge ++ float concaveFactor = pow(clamp(1.0 + distBulge / edgeSizePixels, 0.0, 1.0), refractionNormalPow); ++ ++ // Initial 2D normal ++ const float h = 1.0; ++ vec2 gradient = vec2( ++ roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), ++ roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) ++ ); ++ ++ vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); ++ ++ float finalStrength = 0.2 * concaveFactor * refractionStrength; ++ ++ // Different refraction offsets for each color channel ++ float fringingFactor = refractionRGBFringing * 0.3; ++ vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most ++ vec2 refractOffsetG = normal.xy * finalStrength; ++ vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least ++ ++ vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); ++ vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); ++ vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture2D(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture2D(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture2D(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture2D(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } ++ } else { ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum += texture2D(texUnit, uv + off) * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } ++ ++ if (noise) { ++ sum += vec4(texture2D(noiseTexture, vec2(uv.x, 1.0 - uv.y) * blurSize / noiseTextureSize).rrr, 0.0); ++ } ++ ++ gl_FragColor = roundedRectangle(uv * blurSize, sum.rgb); ++} +\ No newline at end of file +diff --git a/src/shaders/upsample.glsl b/src/shaders/upsample.glsl +index 713566a94..048ec89ea 100644 +--- a/src/shaders/upsample.glsl ++++ b/src/shaders/upsample.glsl +@@ -9,10 +9,12 @@ uniform sampler2D noiseTexture; + uniform vec2 noiseTextureSize; + + uniform float edgeSizePixels; ++uniform float refractionCornerRadiusPixels; + uniform float refractionStrength; + uniform float refractionNormalPow; + uniform float refractionRGBFringing; + uniform int refractionTextureRepeatMode; ++uniform int refractionMode; // 0: Basic, 1: Concave + + varying vec2 uv; + +@@ -42,6 +44,25 @@ vec2 applyTextureRepeatMode(vec2 coord) + return coord; + } + ++// Concave lens-style radial mapping around the rect center, shaped by distance to edge ++vec2 concaveLensCoord(vec2 uv, float strength, float fringing, float dist, vec2 halfBlurSize) ++{ ++ // Edge proximity: 0 in the deep interior, 1 near the rounded rectangle edge ++ float edgeProximity = clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ ++ float scaleR = 1.0 - shaped * strength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * strength; ++ float scaleB = 1.0 - shaped * strength * (1.0 - fringing); ++ ++ // Return per-channel lens coords packed in vec2 three times via caller ++ // Caller samples each channel separately with the right scale ++ // Here we just return the green channel scale as a convenience; R and B will be built in caller ++ return vec2(0.5) + fromCenter * scaleG; ++} ++ + // source: https://iquilezles.org/articles/distfunctions2d/ + // https://www.shadertoy.com/view/4llXD7 + float roundedRectangleDist(vec2 p, vec2 b, float r) +@@ -69,40 +90,73 @@ void main(void) + if (refractionStrength > 0) { + vec2 halfBlurSize = 0.5 * blurSize; + vec2 position = uv * blurSize - halfBlurSize.xy; +- float dist = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); +- +- float concaveFactor = pow(clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0), refractionNormalPow); +- +- // Initial 2D normal +- const float h = 1.0; +- vec2 gradient = vec2( +- roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), +- roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) +- ); +- +- vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); +- +- float finalStrength = 0.2 * concaveFactor * refractionStrength; +- +- // Different refraction offsets for each color channel +- float fringingFactor = refractionRGBFringing * 0.3; +- vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most +- vec2 refractOffsetG = normal.xy * finalStrength; +- vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least +- +- vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); +- vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); +- vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); +- +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum.r += texture2D(texUnit, coordR + off).r * weights[i]; +- sum.g += texture2D(texUnit, coordG + off).g * weights[i]; +- sum.b += texture2D(texUnit, coordB + off).b * weights[i]; +- sum.a += texture2D(texUnit, coordG + off).a * weights[i]; ++ float cornerR = min(refractionCornerRadiusPixels, min(halfBlurSize.x, halfBlurSize.y)); ++ float distConcave = roundedRectangleDist(position, halfBlurSize, cornerR); ++ float distBulge = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); ++ ++ // Different refraction behavior depending on mode ++ if (refractionMode == 1) { ++ // Concave: lens-like radial mapping with RGB fringing ++ float fringing = refractionRGBFringing * 0.3; ++ float baseStrength = 0.2 * refractionStrength; ++ ++ // Edge proximity shaping ++ float edgeProximity = clamp(1.0 + distConcave / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ float scaleR = 1.0 - shaped * baseStrength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * baseStrength; ++ float scaleB = 1.0 - shaped * baseStrength * (1.0 - fringing); ++ ++ vec2 coordR = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleR); ++ vec2 coordG = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleG); ++ vec2 coordB = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture2D(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture2D(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture2D(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture2D(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } else { ++ // Basic: convex/bulge-like along inward normal from the rounded-rect edge ++ float concaveFactor = pow(clamp(1.0 + distBulge / edgeSizePixels, 0.0, 1.0), refractionNormalPow); ++ ++ // Initial 2D normal ++ const float h = 1.0; ++ vec2 gradient = vec2( ++ roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), ++ roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) ++ ); ++ ++ vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); ++ ++ float finalStrength = 0.2 * concaveFactor * refractionStrength; ++ ++ // Different refraction offsets for each color channel ++ float fringingFactor = refractionRGBFringing * 0.3; ++ vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most ++ vec2 refractOffsetG = normal.xy * finalStrength; ++ vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least ++ ++ vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); ++ vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); ++ vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture2D(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture2D(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture2D(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture2D(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; + } +- +- sum /= weightSum; + } else { + for (int i = 0; i < 8; ++i) { + vec2 off = offsets[i] * offset; +diff --git a/src/shaders/upsample_core.frag b/src/shaders/upsample_core.frag +new file mode 100644 +index 000000000..80f5ba2ea +--- /dev/null ++++ b/src/shaders/upsample_core.frag +@@ -0,0 +1,198 @@ ++#version 140 ++ ++uniform float topCornerRadius; ++uniform float bottomCornerRadius; ++uniform float antialiasing; ++ ++uniform vec2 blurSize; ++uniform float opacity; ++ ++vec4 roundedRectangle(vec2 fragCoord, vec3 texture) ++{ ++ if (topCornerRadius == 0 && bottomCornerRadius == 0) { ++ return vec4(texture, opacity); ++ } ++ ++ vec2 halfblurSize = blurSize * 0.5; ++ vec2 p = fragCoord - halfblurSize; ++ float radius = 0.0; ++ if ((fragCoord.y <= bottomCornerRadius) ++ && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { ++ radius = bottomCornerRadius; ++ p.y -= radius; ++ } else if ((fragCoord.y >= blurSize.y - topCornerRadius) ++ && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { ++ radius = topCornerRadius; ++ p.y += radius; ++ } ++ float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; ++ ++ float s = smoothstep(0.0, antialiasing, distance); ++ return vec4(texture, mix(1.0, 0.0, s) * opacity); ++} ++ ++ ++uniform sampler2D texUnit; ++uniform float offset; ++uniform vec2 halfpixel; ++ ++uniform bool noise; ++uniform sampler2D noiseTexture; ++uniform vec2 noiseTextureSize; ++ ++uniform float edgeSizePixels; ++uniform float refractionCornerRadiusPixels; ++uniform float refractionStrength; ++uniform float refractionNormalPow; ++uniform float refractionRGBFringing; ++uniform int refractionTextureRepeatMode; ++uniform int refractionMode; // 0: Basic, 1: Concave ++ ++in vec2 uv; ++out vec4 fragColor; ++ ++vec2 applyTextureRepeatMode(vec2 coord) ++{ ++ if (refractionTextureRepeatMode == 0) { ++ return clamp(coord, 0.0, 1.0); ++ } else if (refractionTextureRepeatMode == 1) { ++ // flip on both axes ++ vec2 flip = mod(coord, 2.0); ++ ++ vec2 result = coord; ++ if (flip.x > 1.0) { ++ result.x = 1.0 - mod(coord.x, 1.0); ++ } else { ++ result.x = mod(coord.x, 1.0); ++ } ++ ++ if (flip.y > 1.0) { ++ result.y = 1.0 - mod(coord.y, 1.0); ++ } else { ++ result.y = mod(coord.y, 1.0); ++ } ++ ++ return result; ++ } ++ return coord; ++} ++ ++// Concave lens-style radial mapping around the rect center, shaped by distance to edge ++vec2 concaveLensCoord(vec2 uv, float strength, float fringing, float dist, vec2 halfBlurSize) ++{ ++ float edgeProximity = clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ ++ float scaleR = 1.0 - shaped * strength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * strength; ++ float scaleB = 1.0 - shaped * strength * (1.0 - fringing); ++ ++ return vec2(0.5) + fromCenter * scaleG; ++} ++ ++// source: https://iquilezles.org/articles/distfunctions2d/ ++// https://www.shadertoy.com/view/4llXD7 ++float roundedRectangleDist(vec2 p, vec2 b, float r) ++{ ++ vec2 q = abs(p) - b + r; ++ return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; ++} ++ ++void main(void) ++{ ++ vec2 offsets[8] = vec2[]( ++ vec2(-halfpixel.x * 2.0, 0.0), ++ vec2(-halfpixel.x, halfpixel.y), ++ vec2(0.0, halfpixel.y * 2.0), ++ vec2(halfpixel.x, halfpixel.y), ++ vec2(halfpixel.x * 2.0, 0.0), ++ vec2(halfpixel.x, -halfpixel.y), ++ vec2(0.0, -halfpixel.y * 2.0), ++ vec2(-halfpixel.x, -halfpixel.y) ++ ); ++ float weights[8] = float[](1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0); ++ float weightSum = 12.0; ++ vec4 sum = vec4(0, 0, 0, 0); ++ ++ if (refractionStrength > 0) { ++ vec2 halfBlurSize = 0.5 * blurSize; ++ vec2 position = uv * blurSize - halfBlurSize.xy; ++ float cornerR = min(refractionCornerRadiusPixels, min(halfBlurSize.x, halfBlurSize.y)); ++ float distConcave = roundedRectangleDist(position, halfBlurSize, cornerR); ++ float distBulge = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); ++ if (refractionMode == 1) { ++ float fringing = refractionRGBFringing * 0.3; ++ float baseStrength = 0.2 * refractionStrength; ++ ++ float edgeProximity = clamp(1.0 + distConcave / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ float scaleR = 1.0 - shaped * baseStrength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * baseStrength; ++ float scaleB = 1.0 - shaped * baseStrength * (1.0 - fringing); ++ ++ vec2 coordR = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleR); ++ vec2 coordG = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleG); ++ vec2 coordB = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } else { ++ float concaveFactor = pow(clamp(1.0 + distBulge / edgeSizePixels, 0.0, 1.0), refractionNormalPow); ++ ++ // Initial 2D normal ++ const float h = 1.0; ++ vec2 gradient = vec2( ++ roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), ++ roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) ++ ); ++ ++ vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); ++ ++ float finalStrength = 0.2 * concaveFactor * refractionStrength; ++ ++ // Different refraction offsets for each color channel ++ float fringingFactor = refractionRGBFringing * 0.3; ++ vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most ++ vec2 refractOffsetG = normal.xy * finalStrength; ++ vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least ++ ++ vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); ++ vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); ++ vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } ++ } else { ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum += texture(texUnit, uv + off) * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } ++ ++ if (noise) { ++ sum += vec4(texture(noiseTexture, vec2(uv.x, 1.0 - uv.y) * blurSize / noiseTextureSize).rrr, 0.0); ++ } ++ ++ fragColor = roundedRectangle(uv * blurSize, sum.rgb); ++} +\ No newline at end of file +diff --git a/src/shaders/upsample_core.glsl b/src/shaders/upsample_core.glsl +index 6f6dd5206..7b55e00b6 100644 +--- a/src/shaders/upsample_core.glsl ++++ b/src/shaders/upsample_core.glsl +@@ -11,10 +11,12 @@ uniform sampler2D noiseTexture; + uniform vec2 noiseTextureSize; + + uniform float edgeSizePixels; ++uniform float refractionCornerRadiusPixels; + uniform float refractionStrength; + uniform float refractionNormalPow; + uniform float refractionRGBFringing; + uniform int refractionTextureRepeatMode; ++uniform int refractionMode; // 0: Basic, 1: Concave + + in vec2 uv; + out vec4 fragColor; +@@ -45,6 +47,21 @@ vec2 applyTextureRepeatMode(vec2 coord) + return coord; + } + ++// Concave lens-style radial mapping around the rect center, shaped by distance to edge ++vec2 concaveLensCoord(vec2 uv, float strength, float fringing, float dist, vec2 halfBlurSize) ++{ ++ float edgeProximity = clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ ++ float scaleR = 1.0 - shaped * strength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * strength; ++ float scaleB = 1.0 - shaped * strength * (1.0 - fringing); ++ ++ return vec2(0.5) + fromCenter * scaleG; ++} ++ + // source: https://iquilezles.org/articles/distfunctions2d/ + // https://www.shadertoy.com/view/4llXD7 + float roundedRectangleDist(vec2 p, vec2 b, float r) +@@ -72,40 +89,68 @@ void main(void) + if (refractionStrength > 0) { + vec2 halfBlurSize = 0.5 * blurSize; + vec2 position = uv * blurSize - halfBlurSize.xy; +- float dist = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); +- +- float concaveFactor = pow(clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0), refractionNormalPow); +- +- // Initial 2D normal +- const float h = 1.0; +- vec2 gradient = vec2( +- roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), +- roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) +- ); +- +- vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); +- +- float finalStrength = 0.2 * concaveFactor * refractionStrength; +- +- // Different refraction offsets for each color channel +- float fringingFactor = refractionRGBFringing * 0.3; +- vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most +- vec2 refractOffsetG = normal.xy * finalStrength; +- vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least +- +- vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); +- vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); +- vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); +- +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum.r += texture(texUnit, coordR + off).r * weights[i]; +- sum.g += texture(texUnit, coordG + off).g * weights[i]; +- sum.b += texture(texUnit, coordB + off).b * weights[i]; +- sum.a += texture(texUnit, coordG + off).a * weights[i]; ++ float cornerR = min(refractionCornerRadiusPixels, min(halfBlurSize.x, halfBlurSize.y)); ++ float distConcave = roundedRectangleDist(position, halfBlurSize, cornerR); ++ float distBulge = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); ++ if (refractionMode == 1) { ++ float fringing = refractionRGBFringing * 0.3; ++ float baseStrength = 0.2 * refractionStrength; ++ ++ float edgeProximity = clamp(1.0 + distConcave / edgeSizePixels, 0.0, 1.0); ++ float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); ++ ++ vec2 fromCenter = uv - vec2(0.5); ++ float scaleR = 1.0 - shaped * baseStrength * (1.0 + fringing); ++ float scaleG = 1.0 - shaped * baseStrength; ++ float scaleB = 1.0 - shaped * baseStrength * (1.0 - fringing); ++ ++ vec2 coordR = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleR); ++ vec2 coordG = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleG); ++ vec2 coordB = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; ++ } else { ++ float concaveFactor = pow(clamp(1.0 + distBulge / edgeSizePixels, 0.0, 1.0), refractionNormalPow); ++ ++ // Initial 2D normal ++ const float h = 1.0; ++ vec2 gradient = vec2( ++ roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), ++ roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) ++ ); ++ ++ vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); ++ ++ float finalStrength = 0.2 * concaveFactor * refractionStrength; ++ ++ // Different refraction offsets for each color channel ++ float fringingFactor = refractionRGBFringing * 0.3; ++ vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most ++ vec2 refractOffsetG = normal.xy * finalStrength; ++ vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least ++ ++ vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); ++ vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); ++ vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); ++ ++ for (int i = 0; i < 8; ++i) { ++ vec2 off = offsets[i] * offset; ++ sum.r += texture(texUnit, coordR + off).r * weights[i]; ++ sum.g += texture(texUnit, coordG + off).g * weights[i]; ++ sum.b += texture(texUnit, coordB + off).b * weights[i]; ++ sum.a += texture(texUnit, coordG + off).a * weights[i]; ++ } ++ ++ sum /= weightSum; + } +- +- sum /= weightSum; + } else { + for (int i = 0; i < 8; ++i) { + vec2 off = offsets[i] * offset; + +From b218838176d09b758bc1dfc514804f0fd82695c1 Mon Sep 17 00:00:00 2001 +From: taj-ny +Date: Tue, 12 Aug 2025 22:09:34 +0200 +Subject: [PATCH 2/4] format blur_config.ui + +--- + src/kcm/blur_config.ui | 196 ++++++++++++++++++++--------------------- + 1 file changed, 98 insertions(+), 98 deletions(-) + +diff --git a/src/kcm/blur_config.ui b/src/kcm/blur_config.ui +index 787819a1b..07dab0215 100644 +--- a/src/kcm/blur_config.ui ++++ b/src/kcm/blur_config.ui +@@ -358,11 +358,11 @@ + + + +- +- +- Refraction does not work when using static blur. +- +- ++ ++ ++ Refraction does not work when using static blur. ++ ++ + + + +@@ -402,7 +402,7 @@ + 0 + + +- 30 ++ 30 + + + 1 +@@ -431,47 +431,47 @@ + + + +- +- +- Refraction Mode: +- +- +- +- +- +- +- +- +- Qt::Horizontal +- +- +- QSizePolicy::Fixed ++ ++ ++ Refraction Mode: ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Fixed ++ ++ ++ ++ 20 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ Basic (Bulge) + +- +- +- 20 +- 20 +- ++ ++ ++ ++ Concave (Lens) + +- +- +- +- +- +- +- Basic (Bulge) +- +- +- +- +- Concave (Lens) +- +- +- +- +- +- +- ++ ++ ++ ++ ++ ++ + + + Refraction Edge Size: +@@ -509,7 +509,7 @@ + 0 + + +- 30 ++ 30 + + + 1 +@@ -707,7 +707,7 @@ + 0 + + +- 30 ++ 30 + + + 1 +@@ -735,61 +735,61 @@ + + + +- +- +- +- Edge Behavior: +- +- +- +- +- +- +- +- +- Qt::Horizontal +- +- +- QSizePolicy::Fixed +- +- +- +- 20 +- 20 +- ++ ++ ++ ++ Edge Behavior: ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QSizePolicy::Fixed ++ ++ ++ ++ 20 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ ++ Clamp (extend edge pixels) + +- +- +- +- +- +- true ++ ++ ++ ++ Flip (mirror texture) + +- +- +- Clamp (extend edge pixels) +- +- +- +- +- Flip (mirror texture) +- +- +- +- +- +- ++ ++ ++ ++ ++ + + +- +- Qt::Vertical +- +- +- +- 0 +- 0 +- +- ++ ++ Qt::Vertical ++ ++ ++ ++ 0 ++ 0 ++ ++ + + + + +From 055ad38b569f12de902f88a931264c80ac63b0bd Mon Sep 17 00:00:00 2001 +From: taj-ny +Date: Tue, 12 Aug 2025 22:10:21 +0200 +Subject: [PATCH 3/4] delete generated shaders + +--- + src/shaders/texture.frag | 43 ------- + src/shaders/texture_core.frag | 47 -------- + src/shaders/upsample.frag | 204 --------------------------------- + src/shaders/upsample_core.frag | 198 -------------------------------- + 4 files changed, 492 deletions(-) + delete mode 100644 src/shaders/texture.frag + delete mode 100644 src/shaders/texture_core.frag + delete mode 100644 src/shaders/upsample.frag + delete mode 100644 src/shaders/upsample_core.frag + +diff --git a/src/shaders/texture.frag b/src/shaders/texture.frag +deleted file mode 100644 +index 28fcc67a2..000000000 +--- a/src/shaders/texture.frag ++++ /dev/null +@@ -1,43 +0,0 @@ +-uniform float topCornerRadius; +-uniform float bottomCornerRadius; +-uniform float antialiasing; +- +-uniform vec2 blurSize; +-uniform float opacity; +- +-vec4 roundedRectangle(vec2 fragCoord, vec3 texture) +-{ +- if (topCornerRadius == 0 && bottomCornerRadius == 0) { +- return vec4(texture, opacity); +- } +- +- vec2 halfblurSize = blurSize * 0.5; +- vec2 p = fragCoord - halfblurSize; +- float radius = 0.0; +- if ((fragCoord.y <= bottomCornerRadius) +- && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { +- radius = bottomCornerRadius; +- p.y -= radius; +- } else if ((fragCoord.y >= blurSize.y - topCornerRadius) +- && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { +- radius = topCornerRadius; +- p.y += radius; +- } +- float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; +- +- float s = smoothstep(0.0, antialiasing, distance); +- return vec4(texture, mix(1.0, 0.0, s) * opacity); +-} +- +- +-uniform sampler2D texUnit; +-uniform vec2 textureSize; +-uniform vec2 texStartPos; +- +-varying vec2 uv; +- +-void main(void) +-{ +- vec2 tex = (texStartPos.xy + vec2(uv.x, 1.0 - uv.y) * blurSize) / textureSize; +- gl_FragColor = roundedRectangle(uv * blurSize, texture2D(texUnit, tex).rgb); +-} +\ No newline at end of file +diff --git a/src/shaders/texture_core.frag b/src/shaders/texture_core.frag +deleted file mode 100644 +index 6ec76f7be..000000000 +--- a/src/shaders/texture_core.frag ++++ /dev/null +@@ -1,47 +0,0 @@ +-#version 140 +- +-uniform float topCornerRadius; +-uniform float bottomCornerRadius; +-uniform float antialiasing; +- +-uniform vec2 blurSize; +-uniform float opacity; +- +-vec4 roundedRectangle(vec2 fragCoord, vec3 texture) +-{ +- if (topCornerRadius == 0 && bottomCornerRadius == 0) { +- return vec4(texture, opacity); +- } +- +- vec2 halfblurSize = blurSize * 0.5; +- vec2 p = fragCoord - halfblurSize; +- float radius = 0.0; +- if ((fragCoord.y <= bottomCornerRadius) +- && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { +- radius = bottomCornerRadius; +- p.y -= radius; +- } else if ((fragCoord.y >= blurSize.y - topCornerRadius) +- && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { +- radius = topCornerRadius; +- p.y += radius; +- } +- float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; +- +- float s = smoothstep(0.0, antialiasing, distance); +- return vec4(texture, mix(1.0, 0.0, s) * opacity); +-} +- +- +-uniform sampler2D texUnit; +-uniform vec2 textureSize; +-uniform vec2 texStartPos; +- +-in vec2 uv; +- +-out vec4 fragColor; +- +-void main(void) +-{ +- vec2 tex = (texStartPos.xy + vec2(uv.x, 1.0 - uv.y) * blurSize) / textureSize; +- fragColor = roundedRectangle(uv * blurSize, texture(texUnit, tex).rgb); +-} +diff --git a/src/shaders/upsample.frag b/src/shaders/upsample.frag +deleted file mode 100644 +index 4cea5bb03..000000000 +--- a/src/shaders/upsample.frag ++++ /dev/null +@@ -1,204 +0,0 @@ +-uniform float topCornerRadius; +-uniform float bottomCornerRadius; +-uniform float antialiasing; +- +-uniform vec2 blurSize; +-uniform float opacity; +- +-vec4 roundedRectangle(vec2 fragCoord, vec3 texture) +-{ +- if (topCornerRadius == 0 && bottomCornerRadius == 0) { +- return vec4(texture, opacity); +- } +- +- vec2 halfblurSize = blurSize * 0.5; +- vec2 p = fragCoord - halfblurSize; +- float radius = 0.0; +- if ((fragCoord.y <= bottomCornerRadius) +- && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { +- radius = bottomCornerRadius; +- p.y -= radius; +- } else if ((fragCoord.y >= blurSize.y - topCornerRadius) +- && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { +- radius = topCornerRadius; +- p.y += radius; +- } +- float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; +- +- float s = smoothstep(0.0, antialiasing, distance); +- return vec4(texture, mix(1.0, 0.0, s) * opacity); +-} +- +- +-uniform sampler2D texUnit; +-uniform float offset; +-uniform vec2 halfpixel; +- +-uniform bool noise; +-uniform sampler2D noiseTexture; +-uniform vec2 noiseTextureSize; +- +-uniform float edgeSizePixels; +-uniform float refractionCornerRadiusPixels; +-uniform float refractionStrength; +-uniform float refractionNormalPow; +-uniform float refractionRGBFringing; +-uniform int refractionTextureRepeatMode; +-uniform int refractionMode; // 0: Basic, 1: Concave +- +-varying vec2 uv; +- +-vec2 applyTextureRepeatMode(vec2 coord) +-{ +- if (refractionTextureRepeatMode == 0) { +- return clamp(coord, 0.0, 1.0); +- } else if (refractionTextureRepeatMode == 1) { +- // flip on both axes +- vec2 flip = mod(coord, 2.0); +- +- vec2 result = coord; +- if (flip.x > 1.0) { +- result.x = 1.0 - mod(coord.x, 1.0); +- } else { +- result.x = mod(coord.x, 1.0); +- } +- +- if (flip.y > 1.0) { +- result.y = 1.0 - mod(coord.y, 1.0); +- } else { +- result.y = mod(coord.y, 1.0); +- } +- +- return result; +- } +- return coord; +-} +- +-// Concave lens-style radial mapping around the rect center, shaped by distance to edge +-vec2 concaveLensCoord(vec2 uv, float strength, float fringing, float dist, vec2 halfBlurSize) +-{ +- // Edge proximity: 0 in the deep interior, 1 near the rounded rectangle edge +- float edgeProximity = clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0); +- float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); +- +- vec2 fromCenter = uv - vec2(0.5); +- +- float scaleR = 1.0 - shaped * strength * (1.0 + fringing); +- float scaleG = 1.0 - shaped * strength; +- float scaleB = 1.0 - shaped * strength * (1.0 - fringing); +- +- // Return per-channel lens coords packed in vec2 three times via caller +- // Caller samples each channel separately with the right scale +- // Here we just return the green channel scale as a convenience; R and B will be built in caller +- return vec2(0.5) + fromCenter * scaleG; +-} +- +-// source: https://iquilezles.org/articles/distfunctions2d/ +-// https://www.shadertoy.com/view/4llXD7 +-float roundedRectangleDist(vec2 p, vec2 b, float r) +-{ +- vec2 q = abs(p) - b + r; +- return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; +-} +- +-void main(void) +-{ +- vec2 offsets[8] = vec2[]( +- vec2(-halfpixel.x * 2.0, 0.0), +- vec2(-halfpixel.x, halfpixel.y), +- vec2(0.0, halfpixel.y * 2.0), +- vec2(halfpixel.x, halfpixel.y), +- vec2(halfpixel.x * 2.0, 0.0), +- vec2(halfpixel.x, -halfpixel.y), +- vec2(0.0, -halfpixel.y * 2.0), +- vec2(-halfpixel.x, -halfpixel.y) +- ); +- float weights[8] = float[](1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0); +- float weightSum = 12.0; +- vec4 sum = vec4(0, 0, 0, 0); +- +- if (refractionStrength > 0) { +- vec2 halfBlurSize = 0.5 * blurSize; +- vec2 position = uv * blurSize - halfBlurSize.xy; +- float cornerR = min(refractionCornerRadiusPixels, min(halfBlurSize.x, halfBlurSize.y)); +- float distConcave = roundedRectangleDist(position, halfBlurSize, cornerR); +- float distBulge = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); +- +- // Different refraction behavior depending on mode +- if (refractionMode == 1) { +- // Concave: lens-like radial mapping with RGB fringing +- float fringing = refractionRGBFringing * 0.3; +- float baseStrength = 0.2 * refractionStrength; +- +- // Edge proximity shaping +- float edgeProximity = clamp(1.0 + distConcave / edgeSizePixels, 0.0, 1.0); +- float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); +- +- vec2 fromCenter = uv - vec2(0.5); +- float scaleR = 1.0 - shaped * baseStrength * (1.0 + fringing); +- float scaleG = 1.0 - shaped * baseStrength; +- float scaleB = 1.0 - shaped * baseStrength * (1.0 - fringing); +- +- vec2 coordR = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleR); +- vec2 coordG = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleG); +- vec2 coordB = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleB); +- +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum.r += texture2D(texUnit, coordR + off).r * weights[i]; +- sum.g += texture2D(texUnit, coordG + off).g * weights[i]; +- sum.b += texture2D(texUnit, coordB + off).b * weights[i]; +- sum.a += texture2D(texUnit, coordG + off).a * weights[i]; +- } +- +- sum /= weightSum; +- } else { +- // Basic: convex/bulge-like along inward normal from the rounded-rect edge +- float concaveFactor = pow(clamp(1.0 + distBulge / edgeSizePixels, 0.0, 1.0), refractionNormalPow); +- +- // Initial 2D normal +- const float h = 1.0; +- vec2 gradient = vec2( +- roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), +- roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) +- ); +- +- vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); +- +- float finalStrength = 0.2 * concaveFactor * refractionStrength; +- +- // Different refraction offsets for each color channel +- float fringingFactor = refractionRGBFringing * 0.3; +- vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most +- vec2 refractOffsetG = normal.xy * finalStrength; +- vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least +- +- vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); +- vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); +- vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); +- +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum.r += texture2D(texUnit, coordR + off).r * weights[i]; +- sum.g += texture2D(texUnit, coordG + off).g * weights[i]; +- sum.b += texture2D(texUnit, coordB + off).b * weights[i]; +- sum.a += texture2D(texUnit, coordG + off).a * weights[i]; +- } +- +- sum /= weightSum; +- } +- } else { +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum += texture2D(texUnit, uv + off) * weights[i]; +- } +- +- sum /= weightSum; +- } +- +- if (noise) { +- sum += vec4(texture2D(noiseTexture, vec2(uv.x, 1.0 - uv.y) * blurSize / noiseTextureSize).rrr, 0.0); +- } +- +- gl_FragColor = roundedRectangle(uv * blurSize, sum.rgb); +-} +\ No newline at end of file +diff --git a/src/shaders/upsample_core.frag b/src/shaders/upsample_core.frag +deleted file mode 100644 +index 80f5ba2ea..000000000 +--- a/src/shaders/upsample_core.frag ++++ /dev/null +@@ -1,198 +0,0 @@ +-#version 140 +- +-uniform float topCornerRadius; +-uniform float bottomCornerRadius; +-uniform float antialiasing; +- +-uniform vec2 blurSize; +-uniform float opacity; +- +-vec4 roundedRectangle(vec2 fragCoord, vec3 texture) +-{ +- if (topCornerRadius == 0 && bottomCornerRadius == 0) { +- return vec4(texture, opacity); +- } +- +- vec2 halfblurSize = blurSize * 0.5; +- vec2 p = fragCoord - halfblurSize; +- float radius = 0.0; +- if ((fragCoord.y <= bottomCornerRadius) +- && (fragCoord.x <= bottomCornerRadius || fragCoord.x >= blurSize.x - bottomCornerRadius)) { +- radius = bottomCornerRadius; +- p.y -= radius; +- } else if ((fragCoord.y >= blurSize.y - topCornerRadius) +- && (fragCoord.x <= topCornerRadius || fragCoord.x >= blurSize.x - topCornerRadius)) { +- radius = topCornerRadius; +- p.y += radius; +- } +- float distance = length(max(abs(p) - (halfblurSize + vec2(0.0, radius)) + radius, 0.0)) - radius; +- +- float s = smoothstep(0.0, antialiasing, distance); +- return vec4(texture, mix(1.0, 0.0, s) * opacity); +-} +- +- +-uniform sampler2D texUnit; +-uniform float offset; +-uniform vec2 halfpixel; +- +-uniform bool noise; +-uniform sampler2D noiseTexture; +-uniform vec2 noiseTextureSize; +- +-uniform float edgeSizePixels; +-uniform float refractionCornerRadiusPixels; +-uniform float refractionStrength; +-uniform float refractionNormalPow; +-uniform float refractionRGBFringing; +-uniform int refractionTextureRepeatMode; +-uniform int refractionMode; // 0: Basic, 1: Concave +- +-in vec2 uv; +-out vec4 fragColor; +- +-vec2 applyTextureRepeatMode(vec2 coord) +-{ +- if (refractionTextureRepeatMode == 0) { +- return clamp(coord, 0.0, 1.0); +- } else if (refractionTextureRepeatMode == 1) { +- // flip on both axes +- vec2 flip = mod(coord, 2.0); +- +- vec2 result = coord; +- if (flip.x > 1.0) { +- result.x = 1.0 - mod(coord.x, 1.0); +- } else { +- result.x = mod(coord.x, 1.0); +- } +- +- if (flip.y > 1.0) { +- result.y = 1.0 - mod(coord.y, 1.0); +- } else { +- result.y = mod(coord.y, 1.0); +- } +- +- return result; +- } +- return coord; +-} +- +-// Concave lens-style radial mapping around the rect center, shaped by distance to edge +-vec2 concaveLensCoord(vec2 uv, float strength, float fringing, float dist, vec2 halfBlurSize) +-{ +- float edgeProximity = clamp(1.0 + dist / edgeSizePixels, 0.0, 1.0); +- float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); +- +- vec2 fromCenter = uv - vec2(0.5); +- +- float scaleR = 1.0 - shaped * strength * (1.0 + fringing); +- float scaleG = 1.0 - shaped * strength; +- float scaleB = 1.0 - shaped * strength * (1.0 - fringing); +- +- return vec2(0.5) + fromCenter * scaleG; +-} +- +-// source: https://iquilezles.org/articles/distfunctions2d/ +-// https://www.shadertoy.com/view/4llXD7 +-float roundedRectangleDist(vec2 p, vec2 b, float r) +-{ +- vec2 q = abs(p) - b + r; +- return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; +-} +- +-void main(void) +-{ +- vec2 offsets[8] = vec2[]( +- vec2(-halfpixel.x * 2.0, 0.0), +- vec2(-halfpixel.x, halfpixel.y), +- vec2(0.0, halfpixel.y * 2.0), +- vec2(halfpixel.x, halfpixel.y), +- vec2(halfpixel.x * 2.0, 0.0), +- vec2(halfpixel.x, -halfpixel.y), +- vec2(0.0, -halfpixel.y * 2.0), +- vec2(-halfpixel.x, -halfpixel.y) +- ); +- float weights[8] = float[](1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0); +- float weightSum = 12.0; +- vec4 sum = vec4(0, 0, 0, 0); +- +- if (refractionStrength > 0) { +- vec2 halfBlurSize = 0.5 * blurSize; +- vec2 position = uv * blurSize - halfBlurSize.xy; +- float cornerR = min(refractionCornerRadiusPixels, min(halfBlurSize.x, halfBlurSize.y)); +- float distConcave = roundedRectangleDist(position, halfBlurSize, cornerR); +- float distBulge = roundedRectangleDist(position, halfBlurSize, edgeSizePixels); +- if (refractionMode == 1) { +- float fringing = refractionRGBFringing * 0.3; +- float baseStrength = 0.2 * refractionStrength; +- +- float edgeProximity = clamp(1.0 + distConcave / edgeSizePixels, 0.0, 1.0); +- float shaped = sin(pow(edgeProximity, refractionNormalPow) * 1.57079632679); +- +- vec2 fromCenter = uv - vec2(0.5); +- float scaleR = 1.0 - shaped * baseStrength * (1.0 + fringing); +- float scaleG = 1.0 - shaped * baseStrength; +- float scaleB = 1.0 - shaped * baseStrength * (1.0 - fringing); +- +- vec2 coordR = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleR); +- vec2 coordG = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleG); +- vec2 coordB = applyTextureRepeatMode(vec2(0.5) + fromCenter * scaleB); +- +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum.r += texture(texUnit, coordR + off).r * weights[i]; +- sum.g += texture(texUnit, coordG + off).g * weights[i]; +- sum.b += texture(texUnit, coordB + off).b * weights[i]; +- sum.a += texture(texUnit, coordG + off).a * weights[i]; +- } +- +- sum /= weightSum; +- } else { +- float concaveFactor = pow(clamp(1.0 + distBulge / edgeSizePixels, 0.0, 1.0), refractionNormalPow); +- +- // Initial 2D normal +- const float h = 1.0; +- vec2 gradient = vec2( +- roundedRectangleDist(position + vec2(h, 0), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(h, 0), halfBlurSize, edgeSizePixels), +- roundedRectangleDist(position + vec2(0, h), halfBlurSize, edgeSizePixels) - roundedRectangleDist(position - vec2(0, h), halfBlurSize, edgeSizePixels) +- ); +- +- vec2 normal = length(gradient) > 1e-6 ? -normalize(gradient) : vec2(0.0, 1.0); +- +- float finalStrength = 0.2 * concaveFactor * refractionStrength; +- +- // Different refraction offsets for each color channel +- float fringingFactor = refractionRGBFringing * 0.3; +- vec2 refractOffsetR = normal.xy * (finalStrength * (1.0 + fringingFactor)); // Red bends most +- vec2 refractOffsetG = normal.xy * finalStrength; +- vec2 refractOffsetB = normal.xy * (finalStrength * (1.0 - fringingFactor)); // Blue bends least +- +- vec2 coordR = applyTextureRepeatMode(uv - refractOffsetR); +- vec2 coordG = applyTextureRepeatMode(uv - refractOffsetG); +- vec2 coordB = applyTextureRepeatMode(uv - refractOffsetB); +- +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum.r += texture(texUnit, coordR + off).r * weights[i]; +- sum.g += texture(texUnit, coordG + off).g * weights[i]; +- sum.b += texture(texUnit, coordB + off).b * weights[i]; +- sum.a += texture(texUnit, coordG + off).a * weights[i]; +- } +- +- sum /= weightSum; +- } +- } else { +- for (int i = 0; i < 8; ++i) { +- vec2 off = offsets[i] * offset; +- sum += texture(texUnit, uv + off) * weights[i]; +- } +- +- sum /= weightSum; +- } +- +- if (noise) { +- sum += vec4(texture(noiseTexture, vec2(uv.x, 1.0 - uv.y) * blurSize / noiseTextureSize).rrr, 0.0); +- } +- +- fragColor = roundedRectangle(uv * blurSize, sum.rgb); +-} +\ No newline at end of file + +From c881e295f842b0d74c397dd82060bcef9537ff99 Mon Sep 17 00:00:00 2001 +From: German +Date: Tue, 12 Aug 2025 22:18:48 +0200 +Subject: [PATCH 4/4] refraction: also disable labels + +--- + src/kcm/blur_config.cpp | 7 +++++++ + src/kcm/blur_config.ui | 8 ++++---- + 2 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/src/kcm/blur_config.cpp b/src/kcm/blur_config.cpp +index cabef7893..ca368ef68 100644 +--- a/src/kcm/blur_config.cpp ++++ b/src/kcm/blur_config.cpp +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + namespace KWin + { +@@ -45,6 +46,12 @@ BlurEffectConfig::BlurEffectConfig(QObject *parent, const KPluginMetaData &data) + if (ui.labelRefractionCornerRadius) { + ui.labelRefractionCornerRadius->setEnabled(concave); + } ++ if (ui.labelRefractionCornerRadiusSquare) { ++ ui.labelRefractionCornerRadiusSquare->setEnabled(concave); ++ } ++ if (ui.labelRefractionCornerRadiusRound) { ++ ui.labelRefractionCornerRadiusRound->setEnabled(concave); ++ } + }; + if (ui.kcfg_RefractionMode) { + connect(ui.kcfg_RefractionMode, QOverload::of(&QComboBox::currentIndexChanged), this, [updateEdgeBehaviorEnabled](int){ updateEdgeBehaviorEnabled(); }); +diff --git a/src/kcm/blur_config.ui b/src/kcm/blur_config.ui +index 07dab0215..b917560e4 100644 +--- a/src/kcm/blur_config.ui ++++ b/src/kcm/blur_config.ui +@@ -628,8 +628,8 @@ + + + +- +- ++ ++ + + Square + +@@ -660,8 +660,8 @@ + + + +- +- ++ ++ + + Round + diff --git a/PKGBUILD b/PKGBUILD index 85aa9a3..03e04ec 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -3,7 +3,7 @@ pkgname=kwin-effects-forceblur pkgver=1.5.0 -pkgrel=10 +pkgrel=11 pkgdesc="KWin Blur effect fork with window class force blur feature (Wayland & X11)" arch=( x86_64 @@ -25,7 +25,7 @@ depends=( kcoreaddons knotifications kwidgetsaddons - 'kwin=6.5.3' + 'kwin=6.5.4' libepoxy libepoxy.so 'qt6-base=6.10.1' ) @@ -43,11 +43,17 @@ makedepends=( provides=(kwin-effects-better-blur) source=( "$pkgname-$pkgver::git+$url.git#tag=v$pkgver" + "239.patch" "$pkgname.install") install="$pkgname.install" b2sums=('ccce168b60300b0480f02fed094a74f761fc7ad49062c3a4bf30c8bbfa14c5b83b41495fbd7d9669ff771c2c7d981a993dc988cd3791ef4586288eb25fa28c98' + 'fd5d0eced9d7463df4e4af08c88721e6141ad6248eb599a2107a15b60150f257da597f5f83861a6b7b4bb1e1e51a0e05aee277a13170d46cb5c5fbcc414bd7bd' '5de5efda9bdc11103a6b5ada6fd1f5907920cb55bd129bc3bcc55f9424d5703031a7a6696fa20ffabe456bd66881ccfa93d804c4b88ed9d7ca2f3f8d6c5005a7') +prepare() { + patch -d $pkgname-$pkgver -Np1 -i ../239.patch +} + build() { local cmake_options=( -B build