diff --git a/GlassSurface.qml b/GlassSurface.qml new file mode 100644 index 0000000..3efa473 --- /dev/null +++ b/GlassSurface.qml @@ -0,0 +1,85 @@ +import QtQuick +import Quickshell.Widgets +import Qt5Compat.GraphicalEffects + +ClippingRectangle { + id: root + color: "transparent" + border.width: 1 + border.color: Qt.rgba(1, 1, 1, 0.1) + + property var source + property real time: 0.5 + property real strength: 0.3 + property real speed: 0.25 + property real scale: 3.0 + property real edgeReflectionStrength: 0.2 + property real edgeReflectionWidth: 0 + + // Blur + ShaderEffectSource { + id: blurredBackground + anchors.fill: parent + sourceItem: root.source + sourceRect: Qt.rect(root.x, root.y, root.width, root.height) + hideSource: false + live: true + } + + FastBlur { + id: backgroundBlur + anchors.fill: parent + source: blurredBackground + radius: 8 + transparentBorder: true + } + + // Liquid glass shader warp + ShaderEffect { + anchors.fill: parent + fragmentShader: "root:shaders/liquid-glass.frag.qsb" + + property real time: root.time + property real flowSpeed: root.speed + property real warpStrength: root.strength + property real scale: root.scale + property real edgeReflectionStrength: root.edgeReflectionStrength + property real edgeReflectionWidth: root.edgeReflectionWidth + + property variant source: ShaderEffectSource { + sourceItem: backgroundBlur + hideSource: false + live: true + } + } + + // Subtle glass overlay + Rectangle { + anchors.fill: parent + color: "transparent" + + Rectangle { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 1 + height: parent.height * 0.3 + radius: parent.radius - 1 + + gradient: Gradient { + GradientStop { + position: 0.0 + color: Qt.rgba(1, 1, 1, 0.08) + } + GradientStop { + position: 0.5 + color: Qt.rgba(1, 1, 1, 0.0) + } + GradientStop { + position: 1.0 + color: Qt.rgba(1, 1, 1, 0.0) + } + } + } + } +} diff --git a/resources/scene.jpg b/resources/scene.jpg new file mode 100644 index 0000000..93e1865 Binary files /dev/null and b/resources/scene.jpg differ diff --git a/resources/test.png b/resources/test.png new file mode 100644 index 0000000..2c8e844 Binary files /dev/null and b/resources/test.png differ diff --git a/shaders/liquid-glass.frag b/shaders/liquid-glass.frag new file mode 100644 index 0000000..45855d7 --- /dev/null +++ b/shaders/liquid-glass.frag @@ -0,0 +1,122 @@ +#version 440 + +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float time; + float warpStrength; + float flowSpeed; + float scale; + float edgeReflectionStrength; + float edgeReflectionWidth; +} ubuf; + +layout(binding = 1) uniform sampler2D source; + +// Smooth noise function for organic liquid movement +float noise(vec2 p) { + return sin(p.x * 1.5) * sin(p.y * 1.5); +} + +// Fractal noise for more complex patterns +float fbm(vec2 p) { + float value = 0.0; + float amplitude = 0.5; + + for(int i = 0; i < 4; i++) { + value += amplitude * noise(p); + p *= 2.0; + amplitude *= 0.5; + } + return value; +} + +void main() { + vec2 uv = qt_TexCoord0; + + // Create flowing liquid-like distortion + vec2 flowDir1 = vec2( + fbm(uv * ubuf.scale + ubuf.time * ubuf.flowSpeed), + fbm(uv * ubuf.scale + ubuf.time * ubuf.flowSpeed + 100.0) + ); + + vec2 flowDir2 = vec2( + fbm(uv * ubuf.scale * 0.7 - ubuf.time * ubuf.flowSpeed * 0.8 + 200.0), + fbm(uv * ubuf.scale * 0.7 - ubuf.time * ubuf.flowSpeed * 0.8 + 300.0) + ); + + // Combine flows for more organic movement + vec2 finalFlow = (flowDir1 + flowDir2 * 0.5) * ubuf.warpStrength * 0.01; + + // Apply subtle chromatic aberration + float aberration = length(finalFlow) * 0.5; + + vec2 distortedUV = uv + finalFlow; + + // Sample with slight chromatic separation for main glass effect + float r = texture(source, distortedUV + vec2(aberration, 0.0)).r; + float g = texture(source, distortedUV).g; + float b = texture(source, distortedUV - vec2(aberration, 0.0)).b; + + vec4 glassColor = vec4(r, g, b, 1.0); + + // Simple edge reflection + float edgeWidth = ubuf.edgeReflectionWidth; + + // Calculate distance from edges + float distFromLeft = uv.x; + float distFromRight = 1.0 - uv.x; + float distFromTop = uv.y; + float distFromBottom = 1.0 - uv.y; + + // Find the minimum distance to any edge + float minDistToEdge = min(min(distFromLeft, distFromRight), min(distFromTop, distFromBottom)); + + // Create edge mask + float edgeMask = smoothstep(edgeWidth, 0.0, minDistToEdge); + + if (edgeMask > 0.0) { + vec2 reflectionUV = distortedUV; + + // Simple reflection logic + if (minDistToEdge == distFromLeft) { + // Left edge - flip horizontally + reflectionUV.x = 0.5 - distortedUV.x; + } else if (minDistToEdge == distFromRight) { + // Right edge - keep as is but sample from further right + reflectionUV.x = distortedUV.x + 0.1; + } else if (minDistToEdge == distFromTop) { + // Top edge - flip vertically + reflectionUV.y = 0.5 - distortedUV.y; + } else { + // Bottom edge - flip vertically + reflectionUV.y = 0.5 - distortedUV.y + 0.1; + } + + // Clamp to valid range + reflectionUV = clamp(reflectionUV, 0.0, 1.0); + + // Sample reflection with same chromatic aberration + float rRefl = texture(source, reflectionUV + vec2(aberration, 0.0)).r; + float gRefl = texture(source, reflectionUV).g; + float bRefl = texture(source, reflectionUV - vec2(aberration, 0.0)).b; + + vec4 reflectionColor = vec4(rRefl, gRefl, bRefl, 1.0); + + // Blend reflection with glass effect + glassColor = mix(glassColor, reflectionColor, edgeMask * ubuf.edgeReflectionStrength); + } + + // Simple glass overlay enhancement + vec2 centeredUV = (uv - 0.5) * 2.0; + float fresnel = pow(1.0 - abs(dot(normalize(vec3(centeredUV, 1.0)), vec3(0.0, 0.0, 1.0))), 1.5); + + // Add subtle white tint and fresnel + glassColor.rgb = mix(glassColor.rgb, vec3(1.0), 0.02 + fresnel * 0.03); + + fragColor = glassColor * ubuf.qt_Opacity; +} + diff --git a/shaders/liquid-glass.frag.qsb b/shaders/liquid-glass.frag.qsb new file mode 100644 index 0000000..bcf4206 Binary files /dev/null and b/shaders/liquid-glass.frag.qsb differ diff --git a/shell.qml b/shell.qml new file mode 100644 index 0000000..7aa33f2 --- /dev/null +++ b/shell.qml @@ -0,0 +1,185 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import Quickshell + +ShellRoot { + FloatingWindow { + color: "grey" + implicitWidth: 840 + implicitHeight: 845 + + maximumSize { + width: 840 + height: 845 + } + + minimumSize { + width: 840 + height: 845 + } + + ColumnLayout { + anchors { + centerIn: parent + } + + Item { + Layout.preferredWidth: 600 + Layout.preferredHeight: 600 + + Image { + id: backgroundContent + fillMode: Image.PreserveAspectCrop + source: "root:resources/scene.jpg" + anchors.fill: parent + } + + GlassSurface { + source: backgroundContent + width: 400 + height: 300 + radius: 20 + anchors.centerIn: parent + + // parameters + time: timeSlider.value + speed: speedSlider.value + strength: warpSlider.value + scale: scaleSlider.value + edgeReflectionStrength: edgeReflectionSlider.value + edgeReflectionWidth: edgeWidthSlider.value + } + + RowLayout { + spacing: 40 + + Repeater { + model: ["1", "2", "3"] + delegate: GlassSurface { + id: surface + required property var modelData + source: backgroundContent + width: 100 + height: 100 + radius: 40 + + time: timeSlider.value + speed: speedSlider.value + strength: warpSlider.value + scale: scaleSlider.value + edgeReflectionStrength: edgeReflectionSlider.value + edgeReflectionWidth: edgeWidthSlider.value + + Text { + text: surface.modelData + color: Qt.rgba(1, 1, 1, 0.2) + font.bold: true + font.pointSize: 16 + anchors.centerIn: parent + } + } + } + } + } + + RowLayout { + Text { + text: "Time:" + } + + Slider { + id: timeSlider + from: 0 + to: Math.PI * 2 + value: Math.PI + + Layout.fillWidth: true + Layout.preferredHeight: 30 + } + } + + RowLayout { + Text { + text: "Warp Strength:" + } + + Slider { + id: warpSlider + from: 0 + to: 10 + value: 3 + + Layout.fillWidth: true + Layout.preferredHeight: 30 + } + } + + RowLayout { + Text { + text: "Flow Speed:" + } + + Slider { + id: speedSlider + from: 0 + to: 1 + value: 0.2 + + Layout.fillWidth: true + Layout.preferredHeight: 30 + } + } + + RowLayout { + Text { + text: "Edge Reflection:" + } + + Slider { + id: edgeReflectionSlider + from: 0 + to: 1 + value: 0.3 + + Layout.fillWidth: true + Layout.preferredHeight: 30 + } + } + + RowLayout { + Text { + text: "Edge Width:" + } + + Slider { + id: edgeWidthSlider + from: 0.01 + to: 0.2 + value: 0.1 + + Layout.fillWidth: true + Layout.preferredHeight: 30 + } + } + + RowLayout { + Text { + text: "Scale:" + } + + Slider { + id: scaleSlider + from: 0.0 + to: 20.0 + value: 3.0 + + Layout.fillWidth: true + Layout.preferredHeight: 30 + } + } + } + } +}