Vuo  2.3.2
VuoImageBlend.c
Go to the documentation of this file.
1 
10 #include "node.h"
11 #include "VuoImageBlend.h"
12 #include "VuoImageRenderer.h"
13 
15 #ifdef VUO_COMPILER
17  "title" : "VuoImageBlend",
18  "dependencies" : [
19  "VuoBlendMode",
20  "VuoImageRenderer"
21 ]
22 });
23 #endif
25 
28 #define FilterSource "\
29  \n#include \"VuoGlslAlpha.glsl\"\
30  uniform sampler2D background;\
31  uniform sampler2D foreground;\
32  uniform float foregroundOpacity;\
33  uniform bool replaceOpacity;\
34  varying vec2 fragmentTextureCoordinate;\
35  \
36  float BlendLinearDodgef(float base, float blend) { return min(base + blend, 1.0); }\
37  float BlendLinearBurnf(float base, float blend) { return max(base + blend - 1.0, 0.0); }\
38  float BlendDividef(float base, float blend) { return (blend == 0.0) ? blend : base/blend; }\
39  \
40  float BlendLightenf(float base, float blend) { return max(blend, base); }\
41  float BlendDarkenf(float base, float blend) { return min(blend, base); }\
42  float BlendLinearLightf(float base, float blend) { return (blend < 0.5 ? BlendLinearBurnf(base, (2.0 * blend)) : BlendLinearDodgef(base, (2.0 * (blend - 0.5)))); }\
43  \
44  float BlendScreenf(float base, float blend) { return (1.0 - ((1.0 - base) * (1.0 - blend))); }\
45  float BlendOverlayf(float base, float blend) { return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend))); }\
46  float BlendSoftLightf(float base, float blend) { return ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend))); }\
47  float BlendHardLightf(float base, float blend) { return BlendOverlayf(blend, base); }\
48  float BlendColorDodgef(float base, float blend) { return ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0)); }\
49  float BlendColorBurnf(float base, float blend) { return (blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0); }\
50  \
51  float BlendVividLightf(float base, float blend) { return ((blend < 0.5) ? BlendColorBurnf(base, (2.0 * blend)) : BlendColorDodgef(base, (2.0 * (blend - 0.5)))); }\
52  float BlendPinLightf(float base, float blend) { return ((blend < 0.5) ? BlendDarkenf(base, (2.0 * blend)) : BlendLightenf(base, (2.0 *(blend - 0.5)))); }\
53  float BlendHardMixf(float base, float blend) { return ((BlendVividLightf(base, blend) < 0.5) ? 0.0 : 1.0); }\
54  \
55  \n#include \"VuoGlslHsl.glsl\"\
56  \
57  vec3 blendColors(vec4 bg, vec4 fg);\
58  \
59  void main() \
60  { \
61  vec4 backgroundColor = VuoGlsl_sample(background, fragmentTextureCoordinate); \
62  backgroundColor.rgb /= backgroundColor.a > 0. ? backgroundColor.a : 1.; \
63  vec4 foregroundColor = VuoGlsl_sample(foreground, fragmentTextureCoordinate); \
64  foregroundColor.rgb /= foregroundColor.a > 0. ? foregroundColor.a : 1.; \
65  foregroundColor.a *= foregroundOpacity; \
66  \
67  vec3 blendedColors = clamp(blendColors(backgroundColor, foregroundColor), 0., 1.); \
68  if (replaceOpacity) \
69  blendedColors = mix(foregroundColor.rgb, blendedColors, backgroundColor.a); \
70  \
71  vec4 mixed = replaceOpacity \
72  ? vec4(blendedColors*foregroundColor.a + backgroundColor.rgb*backgroundColor.a*(1.-foregroundColor.a), \
73  foregroundColor.a + backgroundColor.a*(1.-foregroundColor.a)) \
74  : vec4(blendedColors*foregroundColor.a*backgroundColor.a + backgroundColor.rgb*backgroundColor.a*(1.-foregroundColor.a), \
75  backgroundColor.a); \
76  \
77  gl_FragColor = mixed; \
78  } \
79  "
80 
81 #define BLEND_FILTERS(source) "#version 120\n" FilterSource "\n" #source
82 
84  vec3 blendColors(vec4 bg, vec4 fg)
85  {
86  return fg.rgb;
87  }
88 );
89 
91  vec3 blendColors(vec4 bg, vec4 fg)
92  {
93  return bg.rgb * fg.rgb;
94  }
95 );
96 
98  vec3 blendColors(vec4 bg, vec4 fg)
99  {
100  return bg.rgb + fg.rgb;
101  }
102 );
103 
105  vec3 blendColors(vec4 bg, vec4 fg)
106  {
107  return min(bg.rgb, fg.rgb);
108  }
109 );
110 
112  vec3 blendColors(vec4 bg, vec4 fg)
113  {
114  float bgLum = VuoGlsl_rgbToHsl(bg.rgb).b;
115  float fgLum = VuoGlsl_rgbToHsl(fg.rgb).b;
116  return bgLum < fgLum ? bg.rgb : fg.rgb;
117  }
118 );
119 
121  vec3 blendColors(vec4 bg, vec4 fg)
122  {
123  return max(bg.rgb, fg.rgb);
124  }
125 );
126 
128  vec3 blendColors(vec4 bg, vec4 fg)
129  {
130  float bgLum = VuoGlsl_rgbToHsl(bg.rgb).b;
131  float fgLum = VuoGlsl_rgbToHsl(fg.rgb).b;
132  return bgLum > fgLum ? bg.rgb : fg.rgb;
133  }
134 );
135 
137  vec3 blendColors(vec4 bg, vec4 fg)
138  {
139  return bg.rgb + fg.rgb - 1.;
140  }
141 );
142 
144  vec3 blendColors(vec4 bg, vec4 fg)
145  {
146  return vec3(BlendColorBurnf(bg.r, fg.r),
147  BlendColorBurnf(bg.g, fg.g),
148  BlendColorBurnf(bg.b, fg.b));
149  }
150 );
151 
153  vec3 blendColors(vec4 bg, vec4 fg)
154  {
155  return bg.rgb / (1. - fg.rgb*fg.a);
156  }
157 );
158 
160  vec3 blendColors(vec4 bg, vec4 fg)
161  {
162  return vec3(BlendScreenf(bg.r, fg.r),
163  BlendScreenf(bg.g, fg.g),
164  BlendScreenf(bg.b, fg.b));
165  }
166 );
167 
169  vec3 blendColors(vec4 bg, vec4 fg)
170  {
171  return vec3(BlendOverlayf(bg.r, fg.r),
172  BlendOverlayf(bg.g, fg.g),
173  BlendOverlayf(bg.b, fg.b));
174  }
175 );
176 
178  vec3 blendColors(vec4 bg, vec4 fg)
179  {
180  return vec3(BlendSoftLightf(bg.r, fg.r),
181  BlendSoftLightf(bg.g, fg.g),
182  BlendSoftLightf(bg.b, fg.b));
183  }
184 );
185 
187  vec3 blendColors(vec4 bg, vec4 fg)
188  {
189  return vec3(BlendHardLightf(bg.r, fg.r),
190  BlendHardLightf(bg.g, fg.g),
191  BlendHardLightf(bg.b, fg.b));
192  }
193 );
194 
196  vec3 blendColors(vec4 bg, vec4 fg)
197  {
198  return vec3(BlendVividLightf(bg.r, fg.r),
199  BlendVividLightf(bg.g, fg.g),
200  BlendVividLightf(bg.b, fg.b));
201  }
202 );
203 
205  vec3 blendColors(vec4 bg, vec4 fg)
206  {
207  return vec3(BlendLinearLightf(bg.r, fg.r),
208  BlendLinearLightf(bg.g, fg.g),
209  BlendLinearLightf(bg.b, fg.b));
210  }
211 );
212 
214  vec3 blendColors(vec4 bg, vec4 fg)
215  {
216  return vec3(BlendPinLightf(bg.r, fg.r),
217  BlendPinLightf(bg.g, fg.g),
218  BlendPinLightf(bg.b, fg.b));
219  }
220 );
221 
223  vec3 blendColors(vec4 bg, vec4 fg)
224  {
225  return vec3(BlendHardMixf(bg.r, fg.r),
226  BlendHardMixf(bg.g, fg.g),
227  BlendHardMixf(bg.b, fg.b));
228  }
229 );
230 
232  vec3 blendColors(vec4 bg, vec4 fg)
233  {
234  return abs(bg.rgb - fg.rgb);
235  }
236 );
237 
239  vec3 blendColors(vec4 bg, vec4 fg)
240  {
241  return bg.rgb + fg.rgb - 2.*bg.rgb*fg.rgb;
242  }
243 );
244 
246  vec3 blendColors(vec4 bg, vec4 fg)
247  {
248  return bg.rgb - fg.rgb;
249  }
250 );
251 
253  vec3 blendColors(vec4 bg, vec4 fg)
254  {
255  return vec3(BlendDividef(bg.r, fg.r),
256  BlendDividef(bg.g, fg.g),
257  BlendDividef(bg.b, fg.b));
258  }
259 );
260 
262  vec3 blendColors(vec4 bg, vec4 fg)
263  {
264  vec3 baseHSL = VuoGlsl_rgbToHsl(bg.rgb);
265  return VuoGlsl_hslToRgb(vec3(VuoGlsl_rgbToHsl(fg.rgb).r, baseHSL.g, baseHSL.b));
266  }
267 );
268 
270  vec3 blendColors(vec4 bg, vec4 fg)
271  {
272  vec3 baseHSL = VuoGlsl_rgbToHsl(bg.rgb);
273  return VuoGlsl_hslToRgb(vec3(baseHSL.r, VuoGlsl_rgbToHsl(fg.rgb).g, baseHSL.b));
274  }
275 );
276 
278  vec3 blendColors(vec4 bg, vec4 fg)
279  {
280  vec3 blendHSL = VuoGlsl_rgbToHsl(fg.rgb);
281  return VuoGlsl_hslToRgb(vec3(blendHSL.r, blendHSL.g, VuoGlsl_rgbToHsl(bg.rgb).b));
282  }
283 );
284 
286  vec3 blendColors(vec4 bg, vec4 fg)
287  {
288  vec3 baseHSL = VuoGlsl_rgbToHsl(bg.rgb);
289  return VuoGlsl_hslToRgb(vec3(baseHSL.r, baseHSL.g, VuoGlsl_rgbToHsl(fg.rgb).b));
290  }
291 );
292 
294  vec3 blendColors(vec4 bg, vec4 fg)
295  {
296  return pow(bg.rgb, fg.rgb);
297  }
298 );
300 
305 {
306  const char *fragmentShaderSource = fragmentShaderSource_blendNormal;
307  switch (blendMode)
308  {
309  case VuoBlendMode_Normal:
310  fragmentShaderSource = fragmentShaderSource_blendNormal;
311  break;
313  fragmentShaderSource = fragmentShaderSource_blendMultiply;
314  break;
316  fragmentShaderSource = fragmentShaderSource_blendDarkerComponent;
317  break;
319  fragmentShaderSource = fragmentShaderSource_blendDarkerColor;
320  break;
322  fragmentShaderSource = fragmentShaderSource_blendLinearBurn;
323  break;
325  fragmentShaderSource = fragmentShaderSource_blendColorBurn;
326  break;
327  case VuoBlendMode_Screen:
328  fragmentShaderSource = fragmentShaderSource_blendScreen;
329  break;
331  fragmentShaderSource = fragmentShaderSource_blendLighterComponent;
332  break;
334  fragmentShaderSource = fragmentShaderSource_blendLighterColor;
335  break;
337  fragmentShaderSource = fragmentShaderSource_blendLinearDodge;
338  break;
340  fragmentShaderSource = fragmentShaderSource_blendColorDodge;
341  break;
343  fragmentShaderSource = fragmentShaderSource_blendOverlay;
344  break;
346  fragmentShaderSource = fragmentShaderSource_blendSoftLight;
347  break;
349  fragmentShaderSource = fragmentShaderSource_blendHardLight;
350  break;
352  fragmentShaderSource = fragmentShaderSource_blendVividLight;
353  break;
355  fragmentShaderSource = fragmentShaderSource_blendLinearLight;
356  break;
358  fragmentShaderSource = fragmentShaderSource_blendPinLight;
359  break;
361  fragmentShaderSource = fragmentShaderSource_blendHardMix;
362  break;
364  fragmentShaderSource = fragmentShaderSource_blendDifference;
365  break;
367  fragmentShaderSource = fragmentShaderSource_blendExclusion;
368  break;
370  fragmentShaderSource = fragmentShaderSource_blendSubtract;
371  break;
372  case VuoBlendMode_Divide:
373  fragmentShaderSource = fragmentShaderSource_blendDivide;
374  break;
375  case VuoBlendMode_Hue:
376  fragmentShaderSource = fragmentShaderSource_blendHue;
377  break;
379  fragmentShaderSource = fragmentShaderSource_blendSaturation;
380  break;
381  case VuoBlendMode_Color:
382  fragmentShaderSource = fragmentShaderSource_blendColor;
383  break;
385  fragmentShaderSource = fragmentShaderSource_blendLuminosity;
386  break;
387  case VuoBlendMode_Power:
388  fragmentShaderSource = fragmentShaderSource_blendPower;
389  break;
390  }
391 
392  char *blendModeSummary = VuoBlendMode_getSummary(blendMode);
393  VuoShader shader = VuoShader_make(blendModeSummary);
394  free(blendModeSummary);
395 
396  VuoShader_addSource(shader, VuoMesh_IndividualTriangles, NULL, NULL, fragmentShaderSource);
397 
398  return (VuoImageBlend)shader;
399 }
400 
404 VuoImage VuoImageBlend_blend(VuoImageBlend blend, VuoImage background, VuoImage foreground, VuoReal foregroundOpacity, VuoBoolean replaceOpacity)
405 {
406  if (!background && !foreground)
407  return NULL;
408 
409  VuoShader shader = (VuoShader)blend;
410 
411  VuoInteger pixelsWide = background ? background->pixelsWide : foreground->pixelsWide;
412  VuoInteger pixelsHigh = background ? background->pixelsHigh : foreground->pixelsHigh;
413  VuoImageColorDepth colorDepth = VuoImage_getColorDepth(background);
414  VuoImageColorDepth colorDepthForeground = VuoImage_getColorDepth(foreground);
415  if (colorDepthForeground > colorDepth)
416  colorDepth = colorDepthForeground;
417 
418  if (!background)
419  {
420  background = VuoImage_makeColorImage(VuoColor_makeWithRGBA(0, 0, 0, 0), 1, 1);
421  background->scaleFactor = foreground->scaleFactor;
422  }
423  VuoShader_setUniform_VuoImage(shader, "background", background);
424 
425  if (!foreground)
426  {
427  foreground = VuoImage_makeColorImage(VuoColor_makeWithRGBA(0, 0, 0, 0), 1, 1);
428  foreground->scaleFactor = background->scaleFactor;
429  }
430  VuoShader_setUniform_VuoImage(shader, "foreground", foreground);
431 
432  VuoShader_setUniform_VuoReal(shader, "foregroundOpacity", foregroundOpacity);
433  VuoShader_setUniform_VuoBoolean(shader, "replaceOpacity", replaceOpacity);
434 
435  return VuoImageRenderer_render(shader, pixelsWide, pixelsHigh, colorDepth);
436 }