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