2110 lines
79 KiB
Diff
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>
|