summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Shaders/frag/wp_stripes.frag
blob: fcc216bb10602060e5d72e957707774b59aae45c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// ===== wp_stripes.frag =====
#version 450

layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;

layout(binding = 1) uniform sampler2D source1;  // Current wallpaper
layout(binding = 2) uniform sampler2D source2;  // Next wallpaper

layout(std140, binding = 0) uniform buf {
    mat4 qt_Matrix;
    float qt_Opacity;
    float progress;      // Transition progress (0.0 to 1.0)
    float stripeCount;   // Number of stripes (default 12.0)
    float angle;         // Angle of stripes in degrees (default 30.0)
    float smoothness;    // Edge smoothness (0.0 to 1.0, 0=sharp, 1=very smooth)
    float aspectRatio;   // Width / Height of the screen

    float fillMode;      // 0=stretch, 1=fit, 2=crop, 3=tile, 4=tileV, 5=tileH, 6=pad
    float imageWidth1;
    float imageHeight1;
    float imageWidth2;
    float imageHeight2;
    float screenWidth;
    float screenHeight;
    vec4 fillColor;
} ubuf;

vec2 calculateUV(vec2 uv, float imgWidth, float imgHeight) {
    vec2 transformedUV = uv;

    if (ubuf.fillMode < 0.5) {
        transformedUV = uv;
    }
    else if (ubuf.fillMode < 1.5) {
        float scale = min(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
        vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
        vec2 offset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - scaledImageSize) * 0.5;
        vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
        vec2 imagePixel = (screenPixel - offset) / scale;
        transformedUV = imagePixel / vec2(imgWidth, imgHeight);
    }
    else if (ubuf.fillMode < 2.5) {
        float scale = max(ubuf.screenWidth / imgWidth, ubuf.screenHeight / imgHeight);
        vec2 scaledImageSize = vec2(imgWidth, imgHeight) * scale;
        vec2 offset = (scaledImageSize - vec2(ubuf.screenWidth, ubuf.screenHeight)) / scaledImageSize;
        transformedUV = uv * (vec2(1.0) - offset) + offset * 0.5;
    }
    else if (ubuf.fillMode < 3.5) {
        transformedUV = fract(uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight));
    }
    else if (ubuf.fillMode < 4.5) {
        vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
        transformedUV = vec2(uv.x, fract(tileUV.y));
    }
    else if (ubuf.fillMode < 5.5) {
        vec2 tileUV = uv * vec2(ubuf.screenWidth, ubuf.screenHeight) / vec2(imgWidth, imgHeight);
        transformedUV = vec2(fract(tileUV.x), uv.y);
    }
    else {
        vec2 screenPixel = uv * vec2(ubuf.screenWidth, ubuf.screenHeight);
        vec2 imageOffset = (vec2(ubuf.screenWidth, ubuf.screenHeight) - vec2(imgWidth, imgHeight)) * 0.5;
        vec2 imagePixel = screenPixel - imageOffset;
        transformedUV = imagePixel / vec2(imgWidth, imgHeight);
    }

    return transformedUV;
}

vec4 sampleWithFillMode(sampler2D tex, vec2 uv, float imgWidth, float imgHeight) {
    vec2 transformedUV = calculateUV(uv, imgWidth, imgHeight);

    if (ubuf.fillMode >= 2.5 && ubuf.fillMode <= 5.5) {
        return texture(tex, transformedUV);
    }

    if (transformedUV.x < 0.0 || transformedUV.x > 1.0 ||
        transformedUV.y < 0.0 || transformedUV.y > 1.0) {
        return ubuf.fillColor;
    }

    return texture(tex, transformedUV);
}

void main() {
    vec2 uv = qt_TexCoord0;

    // Sample textures with fill mode
    vec4 color1 = sampleWithFillMode(source1, uv, ubuf.imageWidth1, ubuf.imageHeight1);
    vec4 color2 = sampleWithFillMode(source2, uv, ubuf.imageWidth2, ubuf.imageHeight2);

    // Map smoothness from 0.0-1.0 to 0.001-0.3 range
    // Using a non-linear mapping for better control at low values
    float mappedSmoothness = mix(0.001, 0.3, ubuf.smoothness * ubuf.smoothness);

    // Use values directly without forcing defaults
    float stripes = (ubuf.stripeCount > 0.0) ? ubuf.stripeCount : 12.0;
    float angleRad = radians(ubuf.angle);
    float edgeSmooth = mappedSmoothness;

    // Create a coordinate system for stripes based on angle
    // At 0°: vertical stripes (divide by x)
    // At 45°: diagonal stripes
    // At 90°: horizontal stripes (divide by y)

    // Transform coordinates based on angle
    float cosA = cos(angleRad);
    float sinA = sin(angleRad);

    // Project the UV position onto the stripe direction
    // This gives us the position along the stripe direction
    float stripeCoord = uv.x * cosA + uv.y * sinA;

    // Perpendicular coordinate (for edge movement)
    float perpCoord = -uv.x * sinA + uv.y * cosA;

    // Calculate the range of perpCoord based on angle
    // This determines how far edges need to travel to fully cover the screen
    float minPerp = min(min(0.0 * -sinA + 0.0 * cosA, 1.0 * -sinA + 0.0 * cosA),
                       min(0.0 * -sinA + 1.0 * cosA, 1.0 * -sinA + 1.0 * cosA));
    float maxPerp = max(max(0.0 * -sinA + 0.0 * cosA, 1.0 * -sinA + 0.0 * cosA),
                       max(0.0 * -sinA + 1.0 * cosA, 1.0 * -sinA + 1.0 * cosA));

    // Determine which stripe we're in
    float stripePos = stripeCoord * stripes;
    int stripeIndex = int(floor(stripePos));

    // Determine if this is an odd or even stripe
    bool isOddStripe = mod(float(stripeIndex), 2.0) != 0.0;

    // Calculate the progress for this specific stripe with wave delay
    // Use absolute stripe position for consistent delay across all stripes
    float normalizedStripePos = clamp(stripePos / stripes, 0.0, 1.0);

    // Increased delay and better distribution
    float maxDelay = 0.1;
    float stripeDelay = normalizedStripePos * maxDelay;

    // Better progress mapping that uses the full 0.0-1.0 range
    // Map progress so that:
    // - First stripe starts at progress = 0.0
    // - Last stripe finishes at progress = 1.0
    float stripeProgress;
    if (ubuf.progress <= stripeDelay) {
        stripeProgress = 0.0;
    } else if (ubuf.progress >= (stripeDelay + (1.0 - maxDelay))) {
        stripeProgress = 1.0;
    } else {
        // Scale the progress within the active window for this stripe
        float activeStart = stripeDelay;
        float activeEnd = stripeDelay + (1.0 - maxDelay);
        stripeProgress = (ubuf.progress - activeStart) / (activeEnd - activeStart);
    }

    // Use gentler easing curve
    stripeProgress = stripeProgress * stripeProgress * (3.0 - 2.0 * stripeProgress);  // Smootherstep instead of smoothstep

    // Use the perpendicular coordinate for edge comparison
    float yPos = perpCoord;

    // Calculate edge position for this stripe
    // Use the actual perpendicular coordinate range for this angle
    float perpRange = maxPerp - minPerp;
    float margin = edgeSmooth * 2.0;  // Simplified margin calculation
    float edgePosition;
    if (isOddStripe) {
        // Odd stripes: edge moves from max to min
        edgePosition = maxPerp + margin - stripeProgress * (perpRange + margin * 2.0);
    } else {
        // Even stripes: edge moves from min to max
        edgePosition = minPerp - margin + stripeProgress * (perpRange + margin * 2.0);
    }

    // Determine which wallpaper to show based on rotated position
    float mask;
    if (isOddStripe) {
        // Odd stripes reveal new wallpaper from bottom
        mask = smoothstep(edgePosition - edgeSmooth, edgePosition + edgeSmooth, yPos);
    } else {
        // Even stripes reveal new wallpaper from top
        mask = 1.0 - smoothstep(edgePosition - edgeSmooth, edgePosition + edgeSmooth, yPos);
    }

    // Mix the wallpapers
    fragColor = mix(color1, color2, mask);

    // Force exact values at start and end to prevent any bleed-through
    if (ubuf.progress <= 0.0) {
        fragColor = color1;  // Only show old wallpaper at start
    } else if (ubuf.progress >= 1.0) {
        fragColor = color2;  // Only show new wallpaper at end
    } else {
        // Add manga-style edge shadow only during transition
        float edgeDist = abs(yPos - edgePosition);
        float shadowStrength = 1.0 - smoothstep(0.0, edgeSmooth * 2.5, edgeDist);
        shadowStrength *= 0.2 * (1.0 - abs(stripeProgress - 0.5) * 2.0);
        fragColor.rgb *= (1.0 - shadowStrength);

        // Add slight vignette during transition for dramatic effect
        float vignette = 1.0 - ubuf.progress * 0.1 * (1.0 - abs(stripeProgress - 0.5) * 2.0);
        fragColor.rgb *= vignette;
    }

    fragColor *= ubuf.qt_Opacity;
}