kwin-effects-forceblur/239.patch
Christian Schendel 72f1c8f0e6
upgpkg: kwin-effects-forceblur-1.5.0-11:
rebuild for kwin-6.5.4-1
    incorporate some pull-requests
2025-12-09 21:44:11 +00:00

2110 lines
79 KiB
Diff

From a2ca71ea55f878924213337b40f0d30ba774e964 Mon Sep 17 00:00:00 2001
From: German <igerman@igerman.cc>
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</default>
<entry name="RefractionEdgeSize" type="Double">
<default>20.0</default>
</entry>
+ <entry name="RefractionCornerRadius" type="Double">
+ <default>8.0</default>
+ </entry>
<entry name="RefractionRGBFringing" type="Double">
<default>1.0</default>
</entry>
<entry name="RefractionTextureRepeatMode" type="Int">
<default>0</default>
</entry>
+ <entry name="RefractionMode" type="Int">
+ <default>0</default>
+ </entry>
</group>
</kcfg>
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 <QFileDialog>
#include <QPushButton>
+#include <QComboBox>
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<int>::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 @@
<number>0</number>
</property>
<property name="maximum">
- <number>20</number>
+ <number>30</number>
</property>
<property name="singleStep">
<number>1</number>
@@ -431,6 +431,47 @@
</layout>
</item>
<item>
+ <widget class="QLabel" name="labelRefractionMode">
+ <property name="text">
+ <string>Refraction Mode:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayoutRefractionMode">
+ <item>
+ <spacer name="horizontalSpacerRefractionMode">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QComboBox" name="kcfg_RefractionMode">
+ <item>
+ <property name="text">
+ <string>Basic (Bulge)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Concave (Lens)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<widget class="QLabel" name="labelRefractionEdgeSize">
<property name="text">
<string>Refraction Edge Size:</string>
@@ -468,7 +509,7 @@
<number>0</number>
</property>
<property name="maximum">
- <number>20</number>
+ <number>30</number>
</property>
<property name="singleStep">
<number>1</number>
@@ -563,16 +604,16 @@
</layout>
</item>
<item>
- <widget class="QLabel" name="labelRefractionRGBFringing">
+ <widget class="QLabel" name="labelRefractionCornerRadius">
<property name="text">
- <string>RGB Fringing Strength:</string>
+ <string>Refraction Corner Radius:</string>
</property>
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout">
+ <layout class="QHBoxLayout" name="horizontalLayoutCornerRadius">
<item>
- <spacer name="horizontalSpacer">
+ <spacer name="horizontalSpacerCornerRadius">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -588,28 +629,25 @@
</spacer>
</item>
<item>
- <widget class="QLabel" name="labelRefractionRGBFringingOff">
+ <widget class="QLabel" name="labelRefractionNormalPowRound">
<property name="text">
- <string>Off</string>
+ <string>Square</string>
</property>
</widget>
</item>
<item>
- <widget class="QSlider" name="kcfg_RefractionRGBFringing">
+ <widget class="QSlider" name="kcfg_RefractionCornerRadius">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
- <number>20</number>
+ <number>200</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="pageStep">
- <number>1</number>
- </property>
- <property name="value">
- <number>10</number>
+ <number>7</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -617,26 +655,29 @@
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
+ <property name="tickInterval">
+ <number>7</number>
+ </property>
</widget>
</item>
<item>
- <widget class="QLabel" name="labelRefractionRGBFringingStrong">
+ <widget class="QLabel" name="labelRefractionNormalPowRound">
<property name="text">
- <string>Strong</string>
+ <string>Round</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
- <widget class="QLabel" name="labelRefractionTextureRepeatMode">
+ <widget class="QLabel" name="labelRefractionRGBFringing">
<property name="text">
- <string>Edge Behavior:</string>
+ <string>RGB Fringing Strength:</string>
</property>
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayoutTextureRepeatMode">
+ <layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
@@ -654,21 +695,90 @@
</spacer>
</item>
<item>
- <widget class="QComboBox" name="kcfg_RefractionTextureRepeatMode">
- <item>
- <property name="text">
- <string>Clamp (extend edge pixels)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Flip (mirror texture)</string>
- </property>
- </item>
+ <widget class="QLabel" name="labelRefractionRGBFringingOff">
+ <property name="text">
+ <string>Off</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSlider" name="kcfg_RefractionRGBFringing">
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="maximum">
+ <number>30</number>
+ </property>
+ <property name="singleStep">
+ <number>1</number>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::TicksBelow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelRefractionRGBFringingStrong">
+ <property name="text">
+ <string>Strong</string>
+ </property>
</widget>
</item>
</layout>
</item>
+ <item>
+ <widget class="QLabel" name="labelRefractionTextureRepeatMode">
+ <property name="text">
+ <string>Edge Behavior:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayoutTextureRepeatMode">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QComboBox" name="kcfg_RefractionTextureRepeatMode">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>Clamp (extend edge pixels)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Flip (mirror texture)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
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 <m@rcin.dev>
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 @@
</attribute>
<layout class="QVBoxLayout">
<item>
- <widget class="QLabel" name="labelRefractionNote">
- <property name="text">
- <string>Refraction does not work when using static blur.</string>
- </property>
- </widget>
+ <widget class="QLabel" name="labelRefractionNote">
+ <property name="text">
+ <string>Refraction does not work when using static blur.</string>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="labelRefractionStrength">
@@ -402,7 +402,7 @@
<number>0</number>
</property>
<property name="maximum">
- <number>30</number>
+ <number>30</number>
</property>
<property name="singleStep">
<number>1</number>
@@ -431,47 +431,47 @@
</layout>
</item>
<item>
- <widget class="QLabel" name="labelRefractionMode">
- <property name="text">
- <string>Refraction Mode:</string>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayoutRefractionMode">
- <item>
- <spacer name="horizontalSpacerRefractionMode">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
+ <widget class="QLabel" name="labelRefractionMode">
+ <property name="text">
+ <string>Refraction Mode:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayoutRefractionMode">
+ <item>
+ <spacer name="horizontalSpacerRefractionMode">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QComboBox" name="kcfg_RefractionMode">
+ <item>
+ <property name="text">
+ <string>Basic (Bulge)</string>
</property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
+ </item>
+ <item>
+ <property name="text">
+ <string>Concave (Lens)</string>
</property>
- </spacer>
- </item>
- <item>
- <widget class="QComboBox" name="kcfg_RefractionMode">
- <item>
- <property name="text">
- <string>Basic (Bulge)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Concave (Lens)</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </item>
- <item>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
<widget class="QLabel" name="labelRefractionEdgeSize">
<property name="text">
<string>Refraction Edge Size:</string>
@@ -509,7 +509,7 @@
<number>0</number>
</property>
<property name="maximum">
- <number>30</number>
+ <number>30</number>
</property>
<property name="singleStep">
<number>1</number>
@@ -707,7 +707,7 @@
<number>0</number>
</property>
<property name="maximum">
- <number>30</number>
+ <number>30</number>
</property>
<property name="singleStep">
<number>1</number>
@@ -735,61 +735,61 @@
</item>
</layout>
</item>
- <item>
- <widget class="QLabel" name="labelRefractionTextureRepeatMode">
- <property name="text">
- <string>Edge Behavior:</string>
- </property>
- </widget>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayoutTextureRepeatMode">
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
+ <item>
+ <widget class="QLabel" name="labelRefractionTextureRepeatMode">
+ <property name="text">
+ <string>Edge Behavior:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayoutTextureRepeatMode">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QComboBox" name="kcfg_RefractionTextureRepeatMode">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>Clamp (extend edge pixels)</string>
</property>
- </spacer>
- </item>
- <item>
- <widget class="QComboBox" name="kcfg_RefractionTextureRepeatMode">
- <property name="enabled">
- <bool>true</bool>
+ </item>
+ <item>
+ <property name="text">
+ <string>Flip (mirror texture)</string>
</property>
- <item>
- <property name="text">
- <string>Clamp (extend edge pixels)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Flip (mirror texture)</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </item>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
<item>
<spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>0</width>
- <height>0</height>
- </size>
- </property>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
</spacer>
</item>
</layout>
From 055ad38b569f12de902f88a931264c80ac63b0bd Mon Sep 17 00:00:00 2001
From: taj-ny <m@rcin.dev>
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 <igerman@igerman.cc>
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 <QFileDialog>
#include <QPushButton>
#include <QComboBox>
+#include <QLabel>
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<int>::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 @@
</property>
</spacer>
</item>
- <item>
- <widget class="QLabel" name="labelRefractionNormalPowRound">
+ <item>
+ <widget class="QLabel" name="labelRefractionCornerRadiusSquare">
<property name="text">
<string>Square</string>
</property>
@@ -660,8 +660,8 @@
</property>
</widget>
</item>
- <item>
- <widget class="QLabel" name="labelRefractionNormalPowRound">
+ <item>
+ <widget class="QLabel" name="labelRefractionCornerRadiusRound">
<property name="text">
<string>Round</string>
</property>