Credit Andrew - fix bug in render farm usage when using in/out pointers or selection
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / chromakeyavid / chromakeyavid.sl
1 uniform sampler2D tex;
2 uniform float red;
3 uniform float green;
4 uniform float blue;
5 uniform float in_slope;
6 uniform float out_slope;
7 uniform float tolerance;
8 uniform float tolerance_in;
9 uniform float tolerance_out;
10 uniform float sat_x;
11 uniform float sat_y;
12 uniform float min_s;
13 uniform float min_s_in;
14 uniform float min_s_out;
15 uniform float min_v;
16 uniform float min_v_in;
17 uniform float min_v_out;
18 uniform float max_v;
19 uniform float max_v_in;
20 uniform float max_v_out;
21 uniform float spill_distance;
22 uniform float spill_x;
23 uniform float spill_y;
24 uniform float spill_tolerance;
25 uniform float min_h;
26 uniform float max_h;
27 uniform bool desaturate_only;
28 uniform float alpha_offset;
29 uniform float hue_key;
30 uniform float saturation_key;
31 uniform float value_key;
32
33
34
35 // shortest distance between 2 hues
36 float hue_distance(float h1, float h2)
37 {
38         float result = h1 - h2;
39     if(result < -180.0) result += 360.0;
40     else
41     if(result > 180.0) result -= 360.0;
42     return result;
43 }
44
45 // shift H & S based on an X & Y offset
46 void shift_hs(out float h_shifted, 
47     out float s_shifted, 
48     float h, 
49     float s, 
50     float x_offset,
51     float y_offset)
52 {
53     float h_rad = radians(h);
54     float x = cos(h_rad) * s;
55     float y = sin(h_rad) * s;
56     x += x_offset;
57     y += y_offset;
58     h_shifted = degrees(atan(y, x));
59     s_shifted = length(vec2(x, y));
60 }
61
62
63 void main()
64 {
65         vec4 color = texture2D(tex, gl_TexCoord[0].st);
66 /* Contribution to alpha from each component */
67         float ah = 1.0;
68         float as = 1.0;
69         float av = 1.0;
70     float a = 1.0;
71         vec4 color2;
72         
73 /* Convert to HSV */
74         color2 = yuv_to_rgb(color);
75         color2 = rgb_to_hsv(color2);
76     float h = color2.r;
77     float s = color2.g;
78     float v = color2.b;
79
80 // shift the color in XY to shift the wedge point
81     float h_shifted, s_shifted;
82     shift_hs(h_shifted, 
83         s_shifted, 
84         h, 
85         s, 
86         sat_x,
87         sat_y);
88
89 /* Get the difference between the current hue & the hue key */
90         float h_diff = abs(hue_distance(h_shifted, hue_key));
91
92 // alpha contribution from hue difference
93 // outside wedge < tolerance_out < tolerance_in < inside wedge < tolerance_in < tolerance_out < outside wedge
94         if (tolerance_out > 0.0)
95     {
96 // completely inside the wedge
97                 if (h_diff < tolerance_in)
98                         ah = 0.0;
99         else
100 // between the outer & inner slope
101                 if(h_diff < tolerance_out)
102                         ah = (h_diff - tolerance_in) / (tolerance_out - tolerance_in);
103         if(ah > 1.0) ah = 1.0;
104     }
105
106 // alpha contribution from saturation
107 // outside wedge < min_s_out < min_s_in < inside wedge
108     if(s_shifted > min_s_out)
109     {
110 // saturation with offset applied
111 // completely inside the wedge
112         if(s_shifted > min_s_in)
113             as = 0.0;
114 // inside the gradient
115         if(s_shifted >= min_s_out)
116                         as = (min_s_in - s_shifted) / (min_s_in - min_s_out);
117     }
118
119
120 // alpha contribution from brightness range
121 // brightness range is defined by 4 in/out variables
122 // outside wedge < min_v_out < min_v_in < inside wedge < max_v_in < max_v_out < outside wedge
123     if(v > min_v_out)
124     {
125         if(v < min_v_in || max_v_in >= 1.0)
126             av = (min_v_in - v) / (min_v_in - min_v_out);
127         else
128         if(v <= max_v_in)
129             av = 0.0;
130         else
131         if(v <= max_v_out)
132             av = (v - max_v_in) / (max_v_out - max_v_in);
133     }
134
135 // combine the alpha contribution of every component into a single alpha
136     a = max(as, ah);
137     a = max(a, av);
138
139 // Spill light processing
140     if(spill_tolerance > 0.0)
141     {
142 // get the difference between the shifted input color to the unshifted spill wedge
143         if(spill_distance != 0.0)
144         {
145             shift_hs(h_shifted, 
146                 s_shifted, 
147                 h, 
148                 s, 
149                 spill_x,
150                 spill_y);
151         }
152         else
153         {
154             h_shifted = h;
155             s_shifted = s;
156         }
157
158 // Difference between the shifted hue & the unshifted hue key
159                 h_diff = hue_distance(h_shifted, hue_key);
160
161 // inside the wedge
162         if(abs(h_diff) < spill_tolerance)
163         {
164             if(!desaturate_only)
165             {
166 // the shifted input color in the unshifted wedge
167 // gives 2 unshifted border colors & the weighting
168                 float blend = 0.5 + h_diff / spill_tolerance / 2.0;
169 // shift the 2 border colors to the output wedge
170                 float min_h_shifted;
171                 float min_s_shifted;
172                 shift_hs(min_h_shifted, 
173                     min_s_shifted, 
174                     min_h, 
175                     s_shifted, 
176                     -spill_x,
177                     -spill_y);
178                 float max_h_shifted;
179                 float max_s_shifted;
180                 shift_hs(max_h_shifted, 
181                     max_s_shifted, 
182                     max_h, 
183                     s_shifted, 
184                     -spill_x,
185                     -spill_y);
186
187
188 // blend the shifted border colors using the unshifted weighting
189 // the only thing which doesn't restore the key color & doesn't make an edge is
190 // fading the saturation to 0 in the middle
191                 if(blend > 0.5)
192                 {
193                     h = max_h_shifted;
194                     s = max_s_shifted;
195                 }
196                 else
197                 {
198                     h = min_h_shifted;
199                     s = min_s_shifted;
200                 }
201             } 
202             else // !desaturate_only
203             {
204
205 // fade the saturation to 0 in the middle
206                 s *= abs(h_diff) / spill_tolerance;
207             }
208
209
210             if(h < 0.0) h += 360.0;
211
212 // store new color
213             color2.r = h;
214             color2.g = s;
215             color2.b = v;
216                     color2 = hsv_to_rgb(color2);
217                     color.rgb = rgb_to_yuv(color2).rgb;
218         }
219     }
220
221
222
223         a += alpha_offset;
224     a = min(a, 1.0);
225     color.a = a;
226 /* Convert mask into image */
227         gl_FragColor = show_mask(color, color2);
228 }
229
230