Credit SGE conversion of Adam-s plugins ChromakeyAvid/Color Swatch + updated ContextM...
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / chromakeyavid / chromakeyavid.sl
diff --git a/cinelerra-5.1/plugins/chromakeyavid/chromakeyavid.sl b/cinelerra-5.1/plugins/chromakeyavid/chromakeyavid.sl
new file mode 100644 (file)
index 0000000..2fd86da
--- /dev/null
@@ -0,0 +1,230 @@
+uniform sampler2D tex;
+uniform float red;
+uniform float green;
+uniform float blue;
+uniform float in_slope;
+uniform float out_slope;
+uniform float tolerance;
+uniform float tolerance_in;
+uniform float tolerance_out;
+uniform float sat_x;
+uniform float sat_y;
+uniform float min_s;
+uniform float min_s_in;
+uniform float min_s_out;
+uniform float min_v;
+uniform float min_v_in;
+uniform float min_v_out;
+uniform float max_v;
+uniform float max_v_in;
+uniform float max_v_out;
+uniform float spill_distance;
+uniform float spill_x;
+uniform float spill_y;
+uniform float spill_tolerance;
+uniform float min_h;
+uniform float max_h;
+uniform bool desaturate_only;
+uniform float alpha_offset;
+uniform float hue_key;
+uniform float saturation_key;
+uniform float value_key;
+
+
+
+// shortest distance between 2 hues
+float hue_distance(float h1, float h2)
+{
+       float result = h1 - h2;
+    if(result < -180.0) result += 360.0;
+    else
+    if(result > 180.0) result -= 360.0;
+    return result;
+}
+
+// shift H & S based on an X & Y offset
+void shift_hs(out float h_shifted, 
+    out float s_shifted, 
+    float h, 
+    float s, 
+    float x_offset,
+    float y_offset)
+{
+    float h_rad = radians(h);
+    float x = cos(h_rad) * s;
+    float y = sin(h_rad) * s;
+    x += x_offset;
+    y += y_offset;
+    h_shifted = degrees(atan(y, x));
+    s_shifted = length(vec2(x, y));
+}
+
+
+void main()
+{
+       vec4 color = texture2D(tex, gl_TexCoord[0].st);
+/* Contribution to alpha from each component */
+       float ah = 1.0;
+       float as = 1.0;
+       float av = 1.0;
+    float a = 1.0;
+       vec4 color2;
+       
+/* Convert to HSV */
+       color2 = yuv_to_rgb(color);
+       color2 = rgb_to_hsv(color2);
+    float h = color2.r;
+    float s = color2.g;
+    float v = color2.b;
+
+// shift the color in XY to shift the wedge point
+    float h_shifted, s_shifted;
+    shift_hs(h_shifted, 
+        s_shifted, 
+        h, 
+        s, 
+        sat_x,
+        sat_y);
+
+/* Get the difference between the current hue & the hue key */
+       float h_diff = abs(hue_distance(h_shifted, hue_key));
+
+// alpha contribution from hue difference
+// outside wedge < tolerance_out < tolerance_in < inside wedge < tolerance_in < tolerance_out < outside wedge
+       if (tolerance_out > 0.0)
+    {
+// completely inside the wedge
+               if (h_diff < tolerance_in)
+                       ah = 0.0;
+        else
+// between the outer & inner slope
+               if(h_diff < tolerance_out)
+                       ah = (h_diff - tolerance_in) / (tolerance_out - tolerance_in);
+        if(ah > 1.0) ah = 1.0;
+    }
+
+// alpha contribution from saturation
+// outside wedge < min_s_out < min_s_in < inside wedge
+    if(s_shifted > min_s_out)
+    {
+// saturation with offset applied
+// completely inside the wedge
+        if(s_shifted > min_s_in)
+            as = 0.0;
+// inside the gradient
+        if(s_shifted >= min_s_out)
+                       as = (min_s_in - s_shifted) / (min_s_in - min_s_out);
+    }
+
+
+// alpha contribution from brightness range
+// brightness range is defined by 4 in/out variables
+// outside wedge < min_v_out < min_v_in < inside wedge < max_v_in < max_v_out < outside wedge
+    if(v > min_v_out)
+    {
+        if(v < min_v_in || max_v_in >= 1.0)
+            av = (min_v_in - v) / (min_v_in - min_v_out);
+        else
+        if(v <= max_v_in)
+            av = 0.0;
+        else
+        if(v <= max_v_out)
+            av = (v - max_v_in) / (max_v_out - max_v_in);
+    }
+
+// combine the alpha contribution of every component into a single alpha
+    a = max(as, ah);
+    a = max(a, av);
+
+// Spill light processing
+    if(spill_tolerance > 0.0)
+    {
+// get the difference between the shifted input color to the unshifted spill wedge
+        if(spill_distance != 0.0)
+        {
+            shift_hs(h_shifted, 
+                s_shifted, 
+                h, 
+                s, 
+                spill_x,
+                spill_y);
+        }
+        else
+        {
+            h_shifted = h;
+            s_shifted = s;
+        }
+
+// Difference between the shifted hue & the unshifted hue key
+               h_diff = hue_distance(h_shifted, hue_key);
+
+// inside the wedge
+        if(abs(h_diff) < spill_tolerance)
+        {
+            if(!desaturate_only)
+            {
+// the shifted input color in the unshifted wedge
+// gives 2 unshifted border colors & the weighting
+                float blend = 0.5 + h_diff / spill_tolerance / 2.0;
+// shift the 2 border colors to the output wedge
+                float min_h_shifted;
+                float min_s_shifted;
+                shift_hs(min_h_shifted, 
+                    min_s_shifted, 
+                    min_h, 
+                    s_shifted, 
+                    -spill_x,
+                    -spill_y);
+                float max_h_shifted;
+                float max_s_shifted;
+                shift_hs(max_h_shifted, 
+                    max_s_shifted, 
+                    max_h, 
+                    s_shifted, 
+                    -spill_x,
+                    -spill_y);
+
+
+// blend the shifted border colors using the unshifted weighting
+// the only thing which doesn't restore the key color & doesn't make an edge is
+// fading the saturation to 0 in the middle
+                if(blend > 0.5)
+                {
+                    h = max_h_shifted;
+                    s = max_s_shifted;
+                }
+                else
+                {
+                    h = min_h_shifted;
+                    s = min_s_shifted;
+                }
+            } 
+            else // !desaturate_only
+            {
+
+// fade the saturation to 0 in the middle
+                s *= abs(h_diff) / spill_tolerance;
+            }
+
+
+            if(h < 0.0) h += 360.0;
+
+// store new color
+            color2.r = h;
+            color2.g = s;
+            color2.b = v;
+                   color2 = hsv_to_rgb(color2);
+                   color.rgb = rgb_to_yuv(color2).rgb;
+        }
+    }
+
+
+
+       a += alpha_offset;
+    a = min(a, 1.0);
+    color.a = a;
+/* Convert mask into image */
+       gl_FragColor = show_mask(color, color2);
+}
+
+