f770d878775053e2f266952d73091abefdada7d4
[goodguy/history.git] / cinelerra-5.1 / plugins / bluebanana / bluebananacolor.c
1 /*
2  * Cinelerra :: Blue Banana - color modification plugin for Cinelerra-CV
3  * Copyright (C) 2012-2013 Monty <monty@xiph.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 static inline void rgb8_to_RGB(unsigned char *row, float *R, float *G, float *B, int w){
22   while(w--){
23     *R++ = *row++*.0039215686f;
24     *G++ = *row++*.0039215686f;
25     *B++ = *row++*.0039215686f;
26   }
27 }
28
29 static inline void rgba8_to_RGBA(unsigned char *row, float *R, float *G, float *B, float *A, int w){
30   while(w--){
31     *R++ = *row++*.0039215686f;
32     *G++ = *row++*.0039215686f;
33     *B++ = *row++*.0039215686f;
34     *A++ = *row++*.0039215686f;
35   }
36 }
37
38 static inline void rgbF_to_RGB(float *row, float *R, float *G, float *B, int w){
39   while(w--){
40     *R++ = *row++;
41     *G++ = *row++;
42     *B++ = *row++;
43   }
44 }
45
46 static inline void rgbaF_to_RGBA(float *row, float *R, float *G, float *B, float *A, int w){
47   while(w--){
48     *R++ = *row++;
49     *G++ = *row++;
50     *B++ = *row++;
51     *A++ = *row++;
52   }
53 }
54
55
56 // Full swing and bt601 are chosen below to conform to existing Cinelerra convention.
57 // It's not correct, but it's consistent.
58
59 #if 1
60 // Full swing
61 #define Y_SWING  255.f
62 #define Y_SHIFT  0
63 #define C_SWING  255.f
64 #define C_SHIFT  128
65 #define CLAMP_LO 0
66 #define CLAMP_HI 255
67 #else
68 // Studio swing
69 #define Y_SWING  219.f
70 #define Y_SHIFT  16
71 #define C_SWING  224.f
72 #define C_SHIFT  128
73 #define CLAMP_LO 1
74 #define CLAMP_HI 254
75 #endif
76
77 #if 1
78 // bt601
79 #define Kr .299f
80 #define Kb .114f
81 #else
82 // bt709
83 #define Kr .2126f
84 #define Kb .0722f
85 #endif
86 #define Kg (1.f-Kr-Kb)
87
88 #define Br (.5f*-Kr/(1.f-Kb))
89 #define Bg (.5f*-Kg/(1.f-Kb))
90 #define Bb (.5f)
91
92 #define Rr (.5f)
93 #define Rg (.5f*-Kg/(1.f-Kr))
94 #define Rb (.5f*-Kb/(1.f-Kr))
95
96 #define Rv (2.f*(1.f-Kr))
97 #define Gu (2.f*(1.f-Kb)*Kb/Kg)
98 #define Gv (2.f*(1.f-Kr)*Kr/Kg)
99 #define Bu (2.f*(1.f-Kb))
100
101 static inline void yuv8_to_RGB(unsigned char *row, float *R, float *G, float *B, int w){
102   while(w--){
103     float y = (*row++-Y_SHIFT) * (1.f/Y_SWING);
104     float u = (*row++-C_SHIFT);
105     float v = (*row++-C_SHIFT);
106     *R++ = y                  + (Rv/C_SWING)*v;
107     *G++ = y - (Gu/C_SWING)*u - (Gv/C_SWING)*v;
108     *B++ = y + (Bu/C_SWING)*u;
109   }
110 }
111
112 static inline void yuva8_to_RGBA(unsigned char *row, float *R, float *G, float *B, float *A, int w){
113   while(w--){
114     float y = (*row++-Y_SHIFT) * (1.f/Y_SWING);
115     float u = (*row++-C_SHIFT);
116     float v = (*row++-C_SHIFT);
117     *R++ = y                  + (Rv/C_SWING)*v;
118     *G++ = y - (Gu/C_SWING)*u - (Gv/C_SWING)*v;
119     *B++ = y + (Bu/C_SWING)*u;
120     *A++ = *row++*(1.f/255.f);
121   }
122 }
123
124 static inline void RGB_to_yuv8(float *R, float *G, float *B, float *S, float F, unsigned char *row, int w, int bpp){
125   if(F>SELECT_THRESH){
126     if(S){
127       if(F<1.-SELECT_THRESH){
128         while(w--){
129           float s = *S++*F;
130           float y = (Y_SHIFT + (Kr*Y_SWING)**R   + (Kg*Y_SWING)**G   + (Kb*Y_SWING)**B   - row[0])*s    + row[0] +.5f;
131           float u = (C_SHIFT + (Br*C_SWING)**R   + (Bg*C_SWING)**G   + (Bb*C_SWING)**B   - row[1])*s    + row[1] +.5f;
132           float v = (C_SHIFT + (Rr*C_SWING)**R++ + (Rg*C_SWING)**G++ + (Rb*C_SWING)**B++ - row[2])*s    + row[2] +.5f;
133           row[0] = CLAMP(y,CLAMP_LO,CLAMP_HI);
134           row[1] = CLAMP(u,CLAMP_LO,CLAMP_HI);
135           row[2] = CLAMP(v,CLAMP_LO,CLAMP_HI);
136           row+=bpp;
137         }
138       }else{
139         while(w--){
140           float y = (Y_SHIFT + (Kr*Y_SWING)**R   + (Kg*Y_SWING)**G   + (Kb*Y_SWING)**B   - row[0])**S   + row[0] +.5f;
141           float u = (C_SHIFT + (Br*C_SWING)**R   + (Bg*C_SWING)**G   + (Bb*C_SWING)**B   - row[1])**S   + row[1] +.5f;
142           float v = (C_SHIFT + (Rr*C_SWING)**R++ + (Rg*C_SWING)**G++ + (Rb*C_SWING)**B++ - row[2])**S++ + row[2] +.5f;
143           row[0] = CLAMP(y,CLAMP_LO,CLAMP_HI);
144           row[1] = CLAMP(u,CLAMP_LO,CLAMP_HI);
145           row[2] = CLAMP(v,CLAMP_LO,CLAMP_HI);
146           row+=bpp;
147         }
148       }
149     }else{
150       if(F<1.-SELECT_THRESH){
151         while(w--){
152           float y = (Y_SHIFT + (Kr*Y_SWING)**R   + (Kg*Y_SWING)**G   + (Kb*Y_SWING)**B   - row[0])*F    + row[0] +.5f;
153           float u = (C_SHIFT + (Br*C_SWING)**R   + (Bg*C_SWING)**G   + (Bb*C_SWING)**B   - row[1])*F    + row[1] +.5f;
154           float v = (C_SHIFT + (Rr*C_SWING)**R++ + (Rg*C_SWING)**G++ + (Rb*C_SWING)**B++ - row[2])*F    + row[2] +.5f;
155           row[0] = CLAMP(y,CLAMP_LO,CLAMP_HI);
156           row[1] = CLAMP(u,CLAMP_LO,CLAMP_HI);
157           row[2] = CLAMP(v,CLAMP_LO,CLAMP_HI);
158           row+=bpp;
159         }
160       }else{
161         while(w--){
162           float y = (Y_SHIFT+.5f) + (Kr*Y_SWING)**R   + (Kg*Y_SWING)**G   + (Kb*Y_SWING)**B  ;
163           float u = (C_SHIFT+.5f) + (Br*C_SWING)**R   + (Bg*C_SWING)**G   + (Bb*C_SWING)**B  ;
164           float v = (C_SHIFT+.5f) + (Rr*C_SWING)**R++ + (Rg*C_SWING)**G++ + (Rb*C_SWING)**B++;
165           row[0] = CLAMP(y,CLAMP_LO,CLAMP_HI);
166           row[1] = CLAMP(u,CLAMP_LO,CLAMP_HI);
167           row[2] = CLAMP(v,CLAMP_LO,CLAMP_HI);
168           row+=bpp;
169         }
170       }
171     }
172   }
173 }
174
175 static inline void RGB_to_rgb8(float *R, float *G, float *B, float *S, float F, unsigned char *row, int w, int bpp){
176   if(F>SELECT_THRESH){
177     if(S){
178       if(F<1.-SELECT_THRESH){
179         while(w--){
180           float s = *S++*F;
181           float r = (*R++*255.f-row[0])* s   +row[0] +.5f;
182           float g = (*G++*255.f-row[1])* s   +row[1] +.5f;
183           float b = (*B++*255.f-row[2])* s   +row[2] +.5f;
184           row[0] = CLAMP(r,0,255);
185           row[1] = CLAMP(g,0,255);
186           row[2] = CLAMP(b,0,255);
187           row+=bpp;
188         }
189
190
191       }else{
192         while(w--){
193           float r = (*R++*255.f-row[0])* *S   +row[0] +.5f;
194           float g = (*G++*255.f-row[1])* *S   +row[1] +.5f;
195           float b = (*B++*255.f-row[2])* *S++ +row[2] +.5f;
196           row[0] = CLAMP(r,0,255);
197           row[1] = CLAMP(g,0,255);
198           row[2] = CLAMP(b,0,255);
199           row+=bpp;
200         }
201       }
202     }else{
203       if(F<1.-SELECT_THRESH){
204         while(w--){
205           float r = (*R++*255.f-row[0])* F   +row[0] +.5f;
206           float g = (*G++*255.f-row[1])* F   +row[1] +.5f;
207           float b = (*B++*255.f-row[2])* F   +row[2] +.5f;
208           row[0] = CLAMP(r,0,255);
209           row[1] = CLAMP(g,0,255);
210           row[2] = CLAMP(b,0,255);
211           row+=bpp;
212         }
213       }else{
214         while(w--){
215           float r = *R++*255.f +.5f;
216           float g = *G++*255.f +.5f;
217           float b = *B++*255.f +.5f;
218           row[0] = CLAMP(r,0,255);
219           row[1] = CLAMP(g,0,255);
220           row[2] = CLAMP(b,0,255);
221           row+=bpp;
222         }
223       }
224     }
225   }
226 }
227
228 static inline void Aal_to_alp8(float *S, float F, unsigned char *row, int w, int bpp){
229   if(S){
230     while(w--){
231       float a = *S*F*255.f +.5f;
232       row[3] = CLAMP(a,0,255);
233       row+=bpp;  ++S;
234     }
235   }else{
236     float a = F*255.f +.5f;
237     unsigned char s = CLAMP(a,0,255);
238     while(w--){ row[3] = s; row+=bpp; }
239   }
240 }
241
242
243 static inline void RGB_to_rgbF(float *R, float *G, float *B, float *S, float F, float *row, int w, int bpp){
244   if(F>SELECT_THRESH){
245     if(S){
246       if(F<1.-SELECT_THRESH){
247         while(w--){
248           float s = *S++*F;
249           row[0] = (*R++-row[0])* s   +row[0];
250           row[1] = (*G++-row[1])* s   +row[1];
251           row[2] = (*B++-row[2])* s   +row[2];
252           row+=bpp;
253         }
254       }else{
255         while(w--){
256           row[0] = (*R++-row[0])* *S   +row[0];
257           row[1] = (*G++-row[1])* *S   +row[1];
258           row[2] = (*B++-row[2])* *S++ +row[2];
259           row+=bpp;
260         }
261       }
262     }else{
263       if(F<1.-SELECT_THRESH){
264         while(w--){
265           row[0] = (*R++-row[0])* F   +row[0];
266           row[1] = (*G++-row[1])* F   +row[1];
267           row[2] = (*B++-row[2])* F   +row[2];
268           row+=bpp;
269         }
270       }else{
271         while(w--){
272           row[0] = *R++;
273           row[1] = *G++;
274           row[2] = *B++;
275           row+=bpp;
276         }
277       }
278     }
279   }
280 }
281
282 static inline void Aal_to_alpF(float *S, float F, float *row, int w, int bpp){
283   if(S){
284     while(w--){
285       float a = *S*F;
286       row[3] = a;
287       row+=bpp;
288     }
289   }else{
290     float a = F;
291     while(w--){ row[3] = a; row+=bpp; }
292   }
293 }
294
295
296 static inline void unmask_rgba8(unsigned char *row,int w){
297   while(w--){
298     row[3] = 255;
299     row+=4;
300   }
301 }
302
303 static inline void unmask_rgbaF(float *row, int w){
304   while(w--){
305     row[3] = 1.f;
306     row+=4;
307   }
308 }
309
310 static inline void unmask_yuva8(unsigned char *row, int w){
311   while(w--){
312     row[3] = 255;
313     row+=4;
314   }
315 }
316
317 // A modified HSV colorspace: saturation is calculated using |V| + a
318 // fixed bias to shift the absolute blackpoint well below the in-use
319 // color range.  This eliminates the singularity and desaturates
320 // values near the functional blackpoint (zero).  The modifications
321 // also allows us to use HSV with footroom without clipping chroma
322 // when V<=0.
323
324 // H is constrained to the range 0 to 1.
325 // S is strictly >=0 but the upper range is technically unbounded.
326 //   It is reasonable to clip to the reference range [0:1]
327 // V is unbounded and may extend considerably below 0 and above 1 depending on foot and head room
328
329 /* Simple mods of the original Cinelerra conversion routines */
330 static inline void RGB_to_HSpV(float R, float G, float B, float &H, float &Sp, float &V){
331   if(R<G){
332     if(B<R){
333       V = G;
334       H = 2 + (B-R) / (G-B);
335       Sp = (G-B)/(fabs(V)+HSpV_SATURATION_BIAS)*HSpV_SATURATION_SCALE;
336     }else{
337       if(B<G){
338         V = G;
339         H = 2 + (B-R) / (G-R);
340         Sp = (G-R)/(fabs(V)+HSpV_SATURATION_BIAS)*HSpV_SATURATION_SCALE;
341       }else{
342         V = B;
343         H = 4 + (R-G) / (B-R);
344         Sp = (B-R)/(fabs(V)+HSpV_SATURATION_BIAS)*HSpV_SATURATION_SCALE;
345       }
346     }
347   }else{
348     if(B<G){
349       V = R;
350       H = (G-B) / (R-B);
351       Sp = (R-B)/(fabs(V)+HSpV_SATURATION_BIAS)*HSpV_SATURATION_SCALE;
352     }else{
353       if(B<R){
354         V = R;
355         H = 6 + (G-B) / (R-G);
356         Sp = (R-G)/(fabs(V)+HSpV_SATURATION_BIAS)*HSpV_SATURATION_SCALE;
357       }else{
358         V = B;
359         H = 4 + (R-G) / (B-G+.0001);
360         Sp = (B-G)/(fabs(V)+HSpV_SATURATION_BIAS)*HSpV_SATURATION_SCALE;
361       }
362     }
363   }
364 }
365
366 static inline void HSpV_to_RGB(float H, float Sp, float V, float &R, float &G, float &B){
367   float vp = (fabs(V)+HSpV_SATURATION_BIAS)*Sp*HSpV_SATURATION_ISCALE;
368   int i = (int)H;
369   switch(i){
370   default:
371     R = V;
372     G = V + (H-i-1)*vp;
373     B = V - vp;
374     return;
375   case 1:
376     R = V - (H-i)*vp;
377     G = V;
378     B = V - vp;
379     return;
380   case 2:
381     R = V - vp;
382     G = V;
383     B = V + (H-i-1)*vp;
384     return;
385   case 3:
386     R = V - vp;
387     G = V - (H-i)*vp;
388     B = V;
389     return;
390   case 4:
391     R = V + (H-i-1)*vp;
392     G = V - vp;
393     B = V;
394     return;
395   case 5:
396     R = V;
397     G = V - vp;
398     B = V - (H-i)*vp;
399     return;
400   }
401 }
402
403 static inline void HSpV_correct_RGB(float H, float Sp, float &V, float &R, float &G, float &B){
404   float vp = Sp<0.f?0.f:(fabs(V)+HSpV_SATURATION_BIAS)*Sp*HSpV_SATURATION_ISCALE;
405   int i = (int)H;
406   switch(i){
407   default:
408     R = V = R*R_TO_Y + (G-(H-i-1)*vp)*G_TO_Y + (B+vp)*B_TO_Y;
409     G = V + (H-i-1)*vp;
410     B = V - vp;
411     return;
412   case 1:
413     G = V = (R+(H-i)*vp)*R_TO_Y + G*G_TO_Y + (B+vp)*B_TO_Y;
414     R = V - (H-i)*vp;
415     B = V - vp;
416     return;
417   case 2:
418     G = V = (R+vp)*R_TO_Y + G*G_TO_Y + (B-(H-i-1)*vp)*B_TO_Y;
419     R = V - vp;
420     B = V + (H-i-1)*vp;
421     return;
422   case 3:
423     B = V = (R+vp)*R_TO_Y + (G+(H-i)*vp)*G_TO_Y + B*B_TO_Y;
424     R = V - vp;
425     G = V - (H-i)*vp;
426     return;
427   case 4:
428     B = V = (R-(H-i-1)*vp)*R_TO_Y + (G+vp)*G_TO_Y + B*B_TO_Y;
429     R = V + (H-i-1)*vp;
430     G = V - vp;
431     return;
432   case 5:
433     R = V = R*R_TO_Y + (G+vp)*G_TO_Y + (B+(H-i)*vp)*B_TO_Y;
434     G = V - vp;
435     B = V - (H-i)*vp;
436     return;
437   }
438 }