1 2uniform sampler2D colorBuf; 3uniform sampler2D revealBuf; 4 5in vec4 uvcoordsvar; 6 7/* Reminder: This is considered SRC color in blend equations. 8 * Same operation on all buffers. */ 9layout(location = 0) out vec4 fragColor; 10layout(location = 1) out vec4 fragRevealage; 11 12float gaussian_weight(float x) 13{ 14 return exp(-x * x / (2.0 * 0.35 * 0.35)); 15} 16 17#if defined(COMPOSITE) 18 19uniform bool isFirstPass; 20 21void main() 22{ 23 if (isFirstPass) { 24 /* Blend mode is multiply. */ 25 fragColor.rgb = fragRevealage.rgb = texture(revealBuf, uvcoordsvar.xy).rgb; 26 fragColor.a = fragRevealage.a = 1.0; 27 } 28 else { 29 /* Blend mode is additive. */ 30 fragRevealage = vec4(0.0); 31 fragColor.rgb = texture(colorBuf, uvcoordsvar.xy).rgb; 32 fragColor.a = 0.0; 33 } 34} 35 36#elif defined(COLORIZE) 37 38uniform vec3 lowColor; 39uniform vec3 highColor; 40uniform float factor; 41uniform int mode; 42 43const mat3 sepia_mat = mat3( 44 vec3(0.393, 0.349, 0.272), vec3(0.769, 0.686, 0.534), vec3(0.189, 0.168, 0.131)); 45 46# define MODE_GRAYSCALE 0 47# define MODE_SEPIA 1 48# define MODE_DUOTONE 2 49# define MODE_CUSTOM 3 50# define MODE_TRANSPARENT 4 51 52void main() 53{ 54 fragColor = texture(colorBuf, uvcoordsvar.xy); 55 fragRevealage = texture(revealBuf, uvcoordsvar.xy); 56 57 float luma = dot(fragColor.rgb, vec3(0.2126, 0.7152, 0.723)); 58 59 /* No blending. */ 60 switch (mode) { 61 case MODE_GRAYSCALE: 62 fragColor.rgb = mix(fragColor.rgb, vec3(luma), factor); 63 break; 64 case MODE_SEPIA: 65 fragColor.rgb = mix(fragColor.rgb, sepia_mat * fragColor.rgb, factor); 66 break; 67 case MODE_DUOTONE: 68 fragColor.rgb = luma * ((luma <= factor) ? lowColor : highColor); 69 break; 70 case MODE_CUSTOM: 71 fragColor.rgb = mix(fragColor.rgb, luma * lowColor, factor); 72 break; 73 case MODE_TRANSPARENT: 74 default: 75 fragColor.rgb *= factor; 76 fragRevealage.rgb = mix(vec3(1.0), fragRevealage.rgb, factor); 77 break; 78 } 79} 80 81#elif defined(BLUR) 82 83uniform vec2 offset; 84uniform int sampCount; 85 86void main() 87{ 88 vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy); 89 vec2 ofs = offset * pixel_size; 90 91 fragColor = vec4(0.0); 92 fragRevealage = vec4(0.0); 93 94 /* No blending. */ 95 float weight_accum = 0.0; 96 for (int i = -sampCount; i <= sampCount; i++) { 97 float x = float(i) / float(sampCount); 98 float weight = gaussian_weight(x); 99 weight_accum += weight; 100 vec2 uv = uvcoordsvar.xy + ofs * x; 101 fragColor.rgb += texture(colorBuf, uv).rgb * weight; 102 fragRevealage.rgb += texture(revealBuf, uv).rgb * weight; 103 } 104 105 fragColor /= weight_accum; 106 fragRevealage /= weight_accum; 107} 108 109#elif defined(TRANSFORM) 110 111uniform vec2 axisFlip = vec2(1.0); 112uniform vec2 waveDir = vec2(0.0); 113uniform vec2 waveOffset = vec2(0.0); 114uniform float wavePhase = 0.0; 115uniform vec2 swirlCenter = vec2(0.0); 116uniform float swirlAngle = 0.0; 117uniform float swirlRadius = 0.0; 118 119void main() 120{ 121 vec2 uv = (uvcoordsvar.xy - 0.5) * axisFlip + 0.5; 122 123 /* Wave deform. */ 124 float wave_time = dot(uv, waveDir.xy); 125 uv += sin(wave_time + wavePhase) * waveOffset; 126 /* Swirl deform. */ 127 if (swirlRadius > 0.0) { 128 vec2 tex_size = vec2(textureSize(colorBuf, 0).xy); 129 vec2 pix_coord = uv * tex_size - swirlCenter; 130 float dist = length(pix_coord); 131 float percent = clamp((swirlRadius - dist) / swirlRadius, 0.0, 1.0); 132 float theta = percent * percent * swirlAngle; 133 float s = sin(theta); 134 float c = cos(theta); 135 mat2 rot = mat2(vec2(c, -s), vec2(s, c)); 136 uv = (rot * pix_coord + swirlCenter) / tex_size; 137 } 138 139 fragColor = texture(colorBuf, uv); 140 fragRevealage = texture(revealBuf, uv); 141} 142 143#elif defined(GLOW) 144 145uniform vec4 glowColor; 146uniform vec2 offset; 147uniform int sampCount; 148uniform vec3 threshold; 149uniform bool firstPass; 150uniform bool glowUnder; 151uniform int blendMode; 152 153void main() 154{ 155 vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy); 156 vec2 ofs = offset * pixel_size; 157 158 fragColor = vec4(0.0); 159 fragRevealage = vec4(0.0); 160 161 float weight_accum = 0.0; 162 for (int i = -sampCount; i <= sampCount; i++) { 163 float x = float(i) / float(sampCount); 164 float weight = gaussian_weight(x); 165 weight_accum += weight; 166 vec2 uv = uvcoordsvar.xy + ofs * x; 167 vec3 col = texture(colorBuf, uv).rgb; 168 vec3 rev = texture(revealBuf, uv).rgb; 169 if (threshold.x > -1.0) { 170 if (threshold.y > -1.0) { 171 if (all(lessThan(abs(col - threshold), vec3(0.05)))) { 172 weight = 0.0; 173 } 174 } 175 else { 176 if (dot(col, vec3(1.0 / 3.0)) < threshold.x) { 177 weight = 0.0; 178 } 179 } 180 } 181 fragColor.rgb += col * weight; 182 fragRevealage.rgb += (1.0 - rev) * weight; 183 } 184 185 if (weight_accum > 0.0) { 186 fragColor *= glowColor.rgbb / weight_accum; 187 fragRevealage = fragRevealage / weight_accum; 188 } 189 fragRevealage = 1.0 - fragRevealage; 190 191 if (glowUnder) { 192 if (firstPass) { 193 /* In first pass we copy the revealage buffer in the alpha channel. 194 * This let us do the alpha under in second pass. */ 195 vec3 original_revealage = texture(revealBuf, uvcoordsvar.xy).rgb; 196 fragRevealage.a = clamp(dot(original_revealage.rgb, vec3(0.333334)), 0.0, 1.0); 197 } 198 else { 199 /* Recover original revealage. */ 200 fragRevealage.a = texture(revealBuf, uvcoordsvar.xy).a; 201 } 202 } 203 204 if (!firstPass) { 205 fragColor.a = clamp(1.0 - dot(fragRevealage.rgb, vec3(0.333334)), 0.0, 1.0); 206 fragRevealage.a *= glowColor.a; 207 blend_mode_output(blendMode, fragColor, fragRevealage.a, fragColor, fragRevealage); 208 } 209} 210 211#elif defined(RIM) 212 213uniform vec2 blurDir; 214uniform vec2 uvOffset; 215uniform vec3 rimColor; 216uniform vec3 maskColor; 217uniform int sampCount; 218uniform int blendMode; 219uniform bool isFirstPass; 220 221void main() 222{ 223 /* Blur revealage buffer. */ 224 fragRevealage = vec4(0.0); 225 float weight_accum = 0.0; 226 for (int i = -sampCount; i <= sampCount; i++) { 227 float x = float(i) / float(sampCount); 228 float weight = gaussian_weight(x); 229 weight_accum += weight; 230 vec2 uv = uvcoordsvar.xy + blurDir * x + uvOffset; 231 vec3 col = texture(revealBuf, uv).rgb; 232 if (any(not(equal(vec2(0.0), floor(uv))))) { 233 col = vec3(0.0); 234 } 235 fragRevealage.rgb += col * weight; 236 } 237 fragRevealage /= weight_accum; 238 239 if (isFirstPass) { 240 /* In first pass we copy the reveal buffer. This let us do alpha masking in second pass. */ 241 fragColor = texture(revealBuf, uvcoordsvar.xy); 242 /* Also add the masked color to the reveal buffer. */ 243 vec3 col = texture(colorBuf, uvcoordsvar.xy).rgb; 244 if (all(lessThan(abs(col - maskColor), vec3(0.05)))) { 245 fragColor = vec4(1.0); 246 } 247 } 248 else { 249 /* Premult by foreground alpha (alpha mask). */ 250 float mask = 1.0 - clamp(dot(vec3(0.333334), texture(colorBuf, uvcoordsvar.xy).rgb), 0.0, 1.0); 251 252 /* fragRevealage is blurred shadow. */ 253 float rim = clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0); 254 255 vec4 color = vec4(rimColor, 1.0); 256 257 blend_mode_output(blendMode, color, rim * mask, fragColor, fragRevealage); 258 } 259} 260 261#elif defined(SHADOW) 262 263uniform vec4 shadowColor; 264uniform vec2 uvRotX; 265uniform vec2 uvRotY; 266uniform vec2 uvOffset; 267uniform vec2 blurDir; 268uniform vec2 waveDir; 269uniform vec2 waveOffset; 270uniform float wavePhase; 271uniform int sampCount; 272uniform bool isFirstPass; 273 274vec2 compute_uvs(float x) 275{ 276 vec2 uv = uvcoordsvar.xy; 277 /* Tranform UV (loc, rot, scale) */ 278 uv = uv.x * uvRotX + uv.y * uvRotY + uvOffset; 279 uv += blurDir * x; 280 /* Wave deform. */ 281 float wave_time = dot(uv, waveDir.xy); 282 uv += sin(wave_time + wavePhase) * waveOffset; 283 return uv; 284} 285 286void main() 287{ 288 /* Blur revealage buffer. */ 289 fragRevealage = vec4(0.0); 290 float weight_accum = 0.0; 291 for (int i = -sampCount; i <= sampCount; i++) { 292 float x = float(i) / float(sampCount); 293 float weight = gaussian_weight(x); 294 weight_accum += weight; 295 vec2 uv = compute_uvs(x); 296 vec3 col = texture(revealBuf, uv).rgb; 297 if (any(not(equal(vec2(0.0), floor(uv))))) { 298 col = vec3(1.0); 299 } 300 fragRevealage.rgb += col * weight; 301 } 302 fragRevealage /= weight_accum; 303 304 /* No blending in first pass, alpha over premult in second pass. */ 305 if (isFirstPass) { 306 /* In first pass we copy the reveal buffer. This let us do alpha under in second pass. */ 307 fragColor = texture(revealBuf, uvcoordsvar.xy); 308 } 309 else { 310 /* fragRevealage is blurred shadow. */ 311 float shadow_fac = 1.0 - clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0); 312 /* Premult by foreground revealage (alpha under). */ 313 vec3 original_revealage = texture(colorBuf, uvcoordsvar.xy).rgb; 314 shadow_fac *= clamp(dot(vec3(0.333334), original_revealage), 0.0, 1.0); 315 /* Modulate by opacity */ 316 shadow_fac *= shadowColor.a; 317 /* Apply shadow color. */ 318 fragColor.rgb = mix(vec3(0.0), shadowColor.rgb, shadow_fac); 319 /* Alpha over (mask behind the shadow). */ 320 fragColor.a = shadow_fac; 321 322 fragRevealage.rgb = original_revealage * (1.0 - shadow_fac); 323 /* Replace the whole revealage buffer. */ 324 fragRevealage.a = 1.0; 325 } 326} 327 328#elif defined(PIXELIZE) 329 330uniform vec2 targetPixelSize; 331uniform vec2 targetPixelOffset; 332uniform vec2 accumOffset; 333uniform int sampCount; 334 335void main() 336{ 337 vec2 pixel = floor((uvcoordsvar.xy - targetPixelOffset) / targetPixelSize); 338 vec2 uv = (pixel + 0.5) * targetPixelSize + targetPixelOffset; 339 340 fragColor = vec4(0.0); 341 fragRevealage = vec4(0.0); 342 343 for (int i = -sampCount; i <= sampCount; i++) { 344 float x = float(i) / float(sampCount + 1); 345 vec2 uv_ofs = uv + accumOffset * 0.5 * x; 346 fragColor += texture(colorBuf, uv_ofs); 347 fragRevealage += texture(revealBuf, uv_ofs); 348 } 349 350 fragColor /= float(sampCount) * 2.0 + 1.0; 351 fragRevealage /= float(sampCount) * 2.0 + 1.0; 352} 353 354#endif 355