|
justburner |
79884d |
#ifdef GL_ES
|
|
justburner |
79884d |
precision mediump float;
|
|
justburner |
79884d |
#endif
|
|
justburner |
79884d |
|
|
justburner |
79884d |
|
|
justburner |
79884d |
uniform mat3 worldToOutput;
|
|
justburner |
79884d |
|
|
justburner |
79884d |
uniform sampler2D inputImage[2];
|
|
justburner |
79884d |
uniform mat3 outputToInput[2];
|
|
justburner |
79884d |
|
|
justburner |
fc0e00 |
uniform bool bhue; // Blend HUE?
|
|
justburner |
fc0e00 |
uniform bool bsat; // Blend Saturation?
|
|
justburner |
fc0e00 |
uniform bool blum; // Blend Luminosity?
|
|
justburner |
fc0e00 |
uniform float balpha; // Blending Alpha
|
|
justburner |
fc0e00 |
uniform bool bmask; // Base mask?
|
|
justburner |
79884d |
|
|
justburner |
fc0e00 |
// ---------------------------
|
|
justburner |
79884d |
// Blending calculations from:
|
|
justburner |
79884d |
// https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_blend_equation_advanced.txt
|
|
justburner |
79884d |
|
|
justburner |
79884d |
float minv3(vec3 c)
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
return min(min(c.r, c.g), c.b);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
|
|
justburner |
79884d |
float maxv3(vec3 c)
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
return max(max(c.r, c.g), c.b);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
|
|
justburner |
79884d |
float lumv3(vec3 c)
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
return dot(c, vec3(0.30, 0.59, 0.11));
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
|
|
justburner |
79884d |
float satv3(vec3 c)
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
return maxv3(c) - minv3(c);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
|
|
justburner |
79884d |
// If any color components are outside [0,1], adjust the color to get the components in range.
|
|
justburner |
79884d |
vec3 ClipColor(vec3 color)
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
float lum = lumv3(color);
|
|
justburner |
79884d |
float mincol = minv3(color);
|
|
justburner |
79884d |
float maxcol = maxv3(color);
|
|
justburner |
79884d |
if (mincol < 0.0) {
|
|
justburner |
79884d |
color = lum + ((color-lum) * lum) / (lum-mincol);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
if (maxcol > 1.0) {
|
|
justburner |
79884d |
color = lum + ((color-lum) * (1.0 -lum)) / (maxcol-lum);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
return color;
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
|
|
justburner |
79884d |
// Take the base RGB color <cbase> and override its luminosity</cbase>
|
|
justburner |
79884d |
// with that of the RGB color <clum>.</clum>
|
|
justburner |
79884d |
vec3 SetLum(vec3 cbase, vec3 clum)
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
float lbase = lumv3(cbase);
|
|
justburner |
79884d |
float llum = lumv3(clum);
|
|
justburner |
79884d |
float ldiff = llum - lbase;
|
|
justburner |
79884d |
vec3 color = cbase + vec3(ldiff);
|
|
justburner |
79884d |
return ClipColor(color);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
|
|
justburner |
79884d |
// Take the base RGB color <cbase> and override its saturation with</cbase>
|
|
justburner |
79884d |
// that of the RGB color <csat>. The override the luminosity of the</csat>
|
|
justburner |
79884d |
// result with that of the RGB color <clum>.</clum>
|
|
justburner |
79884d |
vec3 SetLumSat(vec3 cbase, vec3 csat, vec3 clum)
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
float minbase = minv3(cbase);
|
|
justburner |
79884d |
float sbase = satv3(cbase);
|
|
justburner |
79884d |
float ssat = satv3(csat);
|
|
justburner |
79884d |
vec3 color;
|
|
justburner |
79884d |
if (sbase > 0.0) {
|
|
justburner |
79884d |
// Equivalent (modulo rounding errors) to setting the
|
|
justburner |
79884d |
// smallest (R,G,B) component to 0, the largest to <ssat>,</ssat>
|
|
justburner |
79884d |
// and interpolating the "middle" component based on its
|
|
justburner |
79884d |
// original value relative to the smallest/largest.
|
|
justburner |
79884d |
color = (cbase - minbase) * ssat / sbase;
|
|
justburner |
79884d |
} else {
|
|
justburner |
79884d |
color = vec3(0.0);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
return SetLum(color, clum);
|
|
justburner |
79884d |
}
|
|
justburner |
79884d |
|
|
justburner |
fc0e00 |
// ---------------------------
|
|
justburner |
79884d |
|
|
justburner |
79884d |
void main( void )
|
|
justburner |
79884d |
{
|
|
justburner |
79884d |
// Read sources
|
|
justburner |
fc0e00 |
vec2 fg_texPos = (outputToInput[0] * vec3(gl_FragCoord.xy, 1.0)).xy;
|
|
justburner |
fc0e00 |
vec2 bg_texPos = (outputToInput[1] * vec3(gl_FragCoord.xy, 1.0)).xy;
|
|
justburner |
fc0e00 |
vec4 fg_frag = texture2D(inputImage[0], fg_texPos);
|
|
justburner |
fc0e00 |
vec4 bg_frag = texture2D(inputImage[1], bg_texPos);
|
|
justburner |
79884d |
|
|
justburner |
df8a7d |
// De-premultiplication of textures
|
|
justburner |
fc0e00 |
vec3 fg_pix = vec3(0.0);
|
|
justburner |
fc0e00 |
if (fg_frag.a > 0.0) fg_pix = fg_frag.rgb / fg_frag.a;
|
|
justburner |
fc0e00 |
vec3 bg_pix = vec3(0.0);
|
|
justburner |
fc0e00 |
if (bg_frag.a > 0.0) bg_pix = bg_frag.rgb / bg_frag.a;
|
|
justburner |
79884d |
|
|
justburner |
79884d |
// Figure out output alpha
|
|
justburner |
fc0e00 |
float fg_alpha = fg_frag.a * balpha;
|
|
justburner |
fc0e00 |
float bg_alpha = bg_frag.a;
|
|
justburner |
fc0e00 |
if (bmask) {
|
|
justburner |
fc0e00 |
gl_FragColor.a = bg_alpha;
|
|
justburner |
fc0e00 |
} else {
|
|
justburner |
df8a7d |
gl_FragColor.a = bg_alpha + fg_alpha * (1.0 - bg_alpha);
|
|
justburner |
fc0e00 |
}
|
|
justburner |
79884d |
if (gl_FragColor.a <= 0.0) discard;
|
|
justburner |
79884d |
|
|
justburner |
df8a7d |
// Perform blending
|
|
justburner |
df8a7d |
vec3 o_pix = SetLumSat(bhue ? fg_pix : bg_pix, bsat ? fg_pix : bg_pix, blum ? fg_pix : bg_pix);
|
|
justburner |
df8a7d |
vec3 b_pix = bmask ? vec3(0.0) : fg_pix;
|
|
justburner |
df8a7d |
gl_FragColor.rgb = bg_pix * bg_alpha * (1.0 - fg_alpha) + mix(b_pix, o_pix, bg_alpha) * fg_alpha;
|
|
justburner |
79884d |
}
|