]> git.sesse.net Git - casparcg/blobdiff - accelerator/ogl/image/blending_glsl.h
[mixer] Merged fixed from 2.0 where contrast adjustment incorrectly worked on premult...
[casparcg] / accelerator / ogl / image / blending_glsl.h
index 2dc65f4ccf69b1ecff6704b48019d7084245dbd5..326e6f7153044b4afaaf84e67882ea2a89592107 100644 (file)
@@ -30,7 +30,7 @@ static std::string get_adjustement_glsl()
                        ** http://irrlicht.sourceforge.net/phpBB2/viewtopic.php?t=21057
                        */
 
-                       vec3 ContrastSaturationBrightness(vec3 color, float brt, float sat, float con)
+                       vec3 ContrastSaturationBrightness(vec4 color, float brt, float sat, float con)
                        {
                                const float AvgLumR = 0.5;
                                const float AvgLumG = 0.5;
@@ -40,11 +40,17 @@ static std::string get_adjustement_glsl()
                                                ? vec3(0.0722, 0.7152, 0.2126)
                                                : vec3(0.114, 0.587, 0.299);
 
+                               if (color.a > 0.0)
+                                       color.rgb /= color.a;
+
                                vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
-                               vec3 brtColor = color * brt;
+                               vec3 brtColor = color.rgb * brt;
                                vec3 intensity = vec3(dot(brtColor, LumCoeff));
                                vec3 satColor = mix(intensity, brtColor, sat);
                                vec3 conColor = mix(AvgLumin, satColor, con);
+
+                               conColor.rgb *= color.a;
+
                                return conColor;
                        }
 
@@ -281,40 +287,97 @@ static std::string get_chroma_glsl()
                //      by F. van den Bergh & V. Lalioti
                // but as a pixel shader algorithm.
                //
-
-               float       chroma_blend_w = chroma_blend.y - chroma_blend.x;
-               const vec4  grey_xfer  = vec4(0.3, 0.59, 0.11, 0.0);
-
-               float fma(float a, float b, float c) { return a*b + c; }
+               vec4  grey_xfer  = is_hd
+                               ? vec4(0.2126, 0.7152, 0.0722, 0)
+                               : vec4(0.299,  0.587,  0.114, 0);
 
                // This allows us to implement the paper's alphaMap curve in software
                // rather than a largeish array
                float alpha_map(float d)
                {
-                   return 1.0-smoothstep(chroma_blend.x, chroma_blend.y, d);
+                   return 1.0 - smoothstep(1.0, chroma_softness, d);
+               }
+
+               // http://stackoverflow.com/questions/15095909/from-rgb-to-hsv-in-opengl-glsl
+               vec3 rgb2hsv(vec3 c)
+               {
+                       vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
+                       vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
+                       vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
+
+                       float d = q.x - min(q.w, q.y);
+                       float e = 1.0e-10;
+                       return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
+               }
+
+               // From the same page
+               vec3 hsv2rgb(vec3 c)
+               {
+                       vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
+                       vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
+                       return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
+               }
+
+               float AngleDiff(float angle1, float angle2)
+               {
+                       return 0.5 - abs(abs(angle1 - angle2) - 0.5);
                }
 
-               vec4 supress_spill(vec4 c, float d)
+               float AngleDiffDirectional(float angle1, float angle2)
                {
-                   float ds = smoothstep(chroma_spill, 1.0, d/chroma_blend.y);
-                   float gl = dot(grey_xfer, c);
-                   return mix(c, vec4(vec3(gl*gl), gl), ds);
+                       float diff = angle1 - angle2;
+
+                       return diff < -0.5
+                                       ? diff + 1.0
+                                       : (diff > 0.5 ? diff - 1.0 : diff);
+               }
+
+               float Distance(float actual, float target)
+               {
+                       return min(0.0, target - actual);
                }
 
-               // Key on green
-               vec4 ChromaOnGreen(vec4 c)
+               float ColorDistance(vec3 hsv)
                {
-                   float d = fma(2.0, c.g, -c.r - c.b)/2.0;
-                   c *= alpha_map(d);
-                   return supress_spill(c, d);
+                       float hueDiff                                   = AngleDiff(hsv.x, chroma_target_hue) * 2;
+                       float saturationDiff                    = Distance(hsv.y, chroma_min_saturation);
+                       float brightnessDiff                    = Distance(hsv.z, chroma_min_brightness);
+
+                       float saturationBrightnessScore = max(brightnessDiff, saturationDiff);
+                       float hueScore                                  = hueDiff - chroma_hue_width;
+
+                       return -hueScore * saturationBrightnessScore;
                }
 
-               //Key on blue
-               vec4 ChromaOnBlue(vec4 c)
+               vec3 supress_spill(vec3 c)
                {
-                   float d = fma(2.0, c.b, -c.r - c.g)/2.0;
-                   c *= alpha_map(d);
-                   return supress_spill(c, d);
+                       float hue               = c.x;
+                       float diff              = AngleDiffDirectional(hue, chroma_target_hue);
+                       float distance  = abs(diff) / chroma_spill_suppress;
+
+                       if (distance < 1)
+                       {
+                               c.x = diff < 0
+                                               ? chroma_target_hue - chroma_spill_suppress
+                                               : chroma_target_hue + chroma_spill_suppress;
+                               c.y *= min(1.0, distance + chroma_spill_suppress_saturation);
+                       }
+
+                       return c;
+               }
+
+               // Key on any color
+               vec4 ChromaOnCustomColor(vec4 c)
+               {
+                       vec3 hsv                = rgb2hsv(c.rgb);
+                       float distance  = ColorDistance(hsv);
+                       float d                 = distance * -2.0 + 1.0;
+                   vec4 suppressed     = vec4(hsv2rgb(supress_spill(hsv)), 1.0);
+                       float alpha             = alpha_map(d);
+
+                       suppressed *= alpha;
+
+                       return chroma_show_mask ? vec4(suppressed.a, suppressed.a, suppressed.a, 1) : suppressed;
                }
        )shader";