opengl colorspace + BT2020
[goodguy/history.git] / cinelerra-5.1 / guicast / bccolors.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bccolors.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 HSV::HSV()
28 {
29 }
30
31
32 HSV::~HSV()
33 {
34 }
35
36 int HSV::rgb_to_hsv(float r, float g, float b, float &h, float &s, float &v)
37 {
38         float min = ((r < g) ? r : g) < b ? ((r < g) ? r : g) : b;
39         float max = ((r > g) ? r : g) > b ? ((r > g) ? r : g) : b;
40         float delta = max - min;
41         if( max != 0 && delta != 0 ) {
42                 v = max;
43                 s = delta / max;
44                 h = r == max ? (g - b) / delta :     // between yellow & magenta
45                     g == max ? 2 + (b - r) / delta : // between cyan & yellow
46                                4 + (r - g) / delta;  // between magenta & cyan
47                 if( (h*=60) < 0 ) h += 360;          // degrees
48         }
49         else { // r = g = b
50                 h = 0;  s = 0;  v = max;
51         }
52
53         return 0;
54 }
55
56 int HSV::hsv_to_rgb(float &r, float &g, float &b, float h, float s, float v)
57 {
58         if( s == 0 ) { // achromatic (grey)
59                 r = g = b = v;
60                 return 0;
61         }
62
63         h /= 60;                        // sector 0 to 5
64         int i = (int)h;
65         float f = h - i;                // factorial part of h
66         float p = v * (1 - s);
67         float q = v * (1 - s * f);
68         float t = v * (1 - s * (1 - f));
69
70         switch(i) {
71         case 0:  r = v; g = t; b = p; break;
72         case 1:  r = q; g = v; b = p; break;
73         case 2:  r = p; g = v; b = t; break;
74         case 3:  r = p; g = q; b = v; break;
75         case 4:  r = t; g = p; b = v; break;
76         default: r = v; g = p; b = q; break;
77         }
78         return 0;
79 }
80
81 int HSV::yuv_to_hsv(int y, int u, int v, float &h, float &s, float &va, int max)
82 {
83         float r, g, b;
84         int r_i, g_i, b_i;
85
86 //      if(max == 0xffff)
87 //      {
88 //              YUV::yuv.yuv_to_rgb_16(r_i, g_i, b_i, y, u, v);
89 //      }
90 //      else
91         {
92                 YUV::yuv.yuv_to_rgb_8(r_i, g_i, b_i, y, u, v);
93         }
94         r = (float)r_i / max;
95         g = (float)g_i / max;
96         b = (float)b_i / max;
97
98         float h2, s2, v2;
99         HSV::rgb_to_hsv(r, g, b, h2, s2, v2);
100
101         h = h2;  s = s2;  va = v2;
102         return 0;
103 }
104
105 int HSV::hsv_to_yuv(int &y, int &u, int &v, float h, float s, float va, int max)
106 {
107         float r, g, b;
108         int r_i, g_i, b_i;
109         HSV::hsv_to_rgb(r, g, b, h, s, va);
110         r = r * max + 0.5;
111         g = g * max + 0.5;
112         b = b * max + 0.5;
113         r_i = (int)CLIP(r, 0, max);
114         g_i = (int)CLIP(g, 0, max);
115         b_i = (int)CLIP(b, 0, max);
116
117         int y2, u2, v2;
118 //      if(max == 0xffff)
119 //              YUV::yuv.rgb_to_yuv_16(r_i, g_i, b_i, y2, u2, v2);
120 //      else
121                 YUV::yuv.rgb_to_yuv_8(r_i, g_i, b_i, y2, u2, v2);
122
123         y = y2;  u = u2;  v = v2;
124         return 0;
125 }
126
127
128 YUV YUV::yuv;
129 float YUV::rgb_to_yuv_matrix[10];
130 float YUV::yuv_to_rgb_matrix[10];
131
132 YUV::YUV()
133 {
134         this->tab = new int[0xe0e00];
135         this->tabf = new float[0x40400];
136         yuv_set_colors(0, 0);
137 }
138
139 void YUV::yuv_set_colors(int color_space, int color_range)
140 {
141         double kr, kb;
142         int mpeg;
143         switch( color_space ) {
144         default:
145         case BC_COLORS_BT601:  kr = BT601_Kr;   kb = BT601_Kb;   break;
146         case BC_COLORS_BT709:  kr = BT709_Kr;   kb = BT709_Kb;   break;
147         case BC_COLORS_BT2020: kr = BT2020_Kr;  kb = BT2020_Kb;  break;
148         }
149         switch( color_range ) {
150         default:
151         case BC_COLORS_JPEG: mpeg = 0;  break;
152         case BC_COLORS_MPEG: mpeg = 1;  break;
153         }
154         init(kr, kb, mpeg);
155 }
156
157 void YUV::init(double Kr, double Kb, int mpeg)
158 {
159         this->mpeg   = mpeg;
160         int ymin = !mpeg? 0 : 16;
161         int ymax = !mpeg? 255 : 235;
162         int uvmin = !mpeg? 0 : 16;
163         int uvmax = !mpeg? 255 : 240;
164         this->ymin8  = ymin;
165         this->ymax8  = ymax;
166         this->ymin16 = ymin*0x100;
167         this->ymax16 = (ymax+1)*0x100 - 1;
168         this->yzero  = 0x10000 * ymin;
169         this->uvmin8  = uvmin;
170         this->uvmax8  = uvmax;
171         this->uvmin16 = uvmin*0x100;
172         this->uvmax16 = (uvmax+1)*0x100 - 1;
173         this->uvzero = 0x800000;
174         this->yminf = ymin / 256.;
175         this->ymaxf = (ymax+1) / 256.;
176         this->yrangef = ymaxf - yminf;
177         this->uvminf = uvmin / 256.;
178         this->uvmaxf = (uvmax+1) / 256.;
179         this->uvrangef = uvmaxf - uvminf;
180         this->Kr = Kr;
181         this->Kg = 1. - Kr - Kb;
182         this->Kb = Kb;
183         double R_to_Y = Kr;
184         double G_to_Y = Kg;
185         double B_to_Y = Kb;
186         double R_to_U = -0.5*Kr/(1-Kb);
187         double G_to_U = -0.5*Kg/(1-Kb);
188         double B_to_U =  0.5;
189         double R_to_V =  0.5;
190         double G_to_V = -0.5*Kg/(1-Kr);
191         double B_to_V = -0.5*Kb/(1-Kr);
192         double V_to_R =  2.0*(1-Kr);
193         double V_to_G = -2.0*Kr*(1-Kr)/Kg;
194         double U_to_G = -2.0*Kb*(1-Kb)/Kg;
195         double U_to_B =  2.0*(1-Kb);
196
197         this->r_to_y = yrangef * R_to_Y;
198         this->g_to_y = yrangef * G_to_Y;
199         this->b_to_y = yrangef * B_to_Y;
200         this->r_to_u = uvrangef * R_to_U;
201         this->g_to_u = uvrangef * G_to_U;
202         this->b_to_u = uvrangef * B_to_U;
203         this->r_to_v = uvrangef * R_to_V;
204         this->g_to_v = uvrangef * G_to_V;
205         this->b_to_v = uvrangef * B_to_V;
206         this->v_to_r = V_to_R / uvrangef;
207         this->v_to_g = V_to_G / uvrangef;
208         this->u_to_g = U_to_G / uvrangef;
209         this->u_to_b = U_to_B / uvrangef;
210         
211         init_tables(0x100,
212                 rtoy8, rtou8, rtov8,
213                 gtoy8, gtou8, gtov8,
214                 btoy8, btou8, btov8,
215                 ytab8, vtor8, vtog8, utog8, utob8);
216         init_tables(0x10000,
217                 rtoy16, rtou16, rtov16,
218                 gtoy16, gtou16, gtov16,
219                 btoy16, btou16, btov16,
220                 ytab16, vtor16, vtog16, utog16, utob16); 
221         init_tables(0x100,
222                 vtor8f, vtog8f, utog8f, utob8f);
223         init_tables(0x10000,
224                 vtor16f, vtog16f, utog16f, utob16f);
225
226         rgb_to_yuv_matrix[0] = r_to_y;
227         rgb_to_yuv_matrix[1] = r_to_u;
228         rgb_to_yuv_matrix[2] = r_to_v;
229         rgb_to_yuv_matrix[3] = g_to_y;
230         rgb_to_yuv_matrix[4] = g_to_u;
231         rgb_to_yuv_matrix[5] = g_to_v;
232         rgb_to_yuv_matrix[6] = b_to_y;
233         rgb_to_yuv_matrix[7] = b_to_u;
234         rgb_to_yuv_matrix[8] = b_to_v;
235         rgb_to_yuv_matrix[9] = yminf;
236
237         float yscale = 1.f / yrangef;
238         yuv_to_rgb_matrix[0] = yscale;
239         yuv_to_rgb_matrix[1] = yscale;
240         yuv_to_rgb_matrix[2] = yscale;
241         yuv_to_rgb_matrix[3] = 0;
242         yuv_to_rgb_matrix[4] = u_to_g;
243         yuv_to_rgb_matrix[5] = u_to_b;
244         yuv_to_rgb_matrix[6] = v_to_r;
245         yuv_to_rgb_matrix[7] = v_to_g;
246         yuv_to_rgb_matrix[8] = 0;
247         yuv_to_rgb_matrix[9] = yminf;
248 }
249
250 void YUV::init_tables(int len,
251                 int *rtoy, int *rtou, int *rtov,
252                 int *gtoy, int *gtou, int *gtov,
253                 int *btoy, int *btou, int *btov,
254                 int *ytab,
255                 int *vtor, int *vtog,
256                 int *utog, int *utob)
257 {
258 // rgb->yuv
259         double s = (double)0xffffff / len;
260         double r2y = s*r_to_y, g2y = s*g_to_y, b2y = s*b_to_y;
261         double r2u = s*r_to_u, g2u = s*g_to_u, b2u = s*b_to_u;
262         double r2v = s*r_to_v, g2v = s*g_to_v, b2v = s*b_to_v;
263         for( int rgb=0; rgb<len; ++rgb ) {
264                 rtoy[rgb] = r2y*rgb;  rtou[rgb] = r2u*rgb;  rtov[rgb] = r2v*rgb;
265                 gtoy[rgb] = g2y*rgb;  gtou[rgb] = g2u*rgb;  gtov[rgb] = g2v*rgb;
266                 btoy[rgb] = b2y*rgb;  btou[rgb] = b2u*rgb;  btov[rgb] = b2v*rgb;
267         }
268
269 // yuv->rgb
270         int y0  = ymin8 * len/0x100,  y1 = (ymax8+1) * len/0x100 - 1;
271         s = (double)0xffffff / (y1 - y0);
272         int y = 0, iy = 0;
273         while( y < y0 ) ytab[y++] = 0;
274         while( y < y1 ) ytab[y++] = s*iy++;
275         while( y < len ) ytab[y++] = 0xffffff;
276
277         int uv0 = uvmin8 * len/0x100, uv1 = (uvmax8+1) * len/0x100 - 1;
278         s = (double)0xffffff / (uv1 - uv0);
279         double v2r = s*v_to_r, v2g = s*v_to_g;
280         double u2g = s*u_to_g, u2b = s*u_to_b;
281         int uv = 0, iuv = uv0 - len/2;
282         int vr0 = v2r * iuv, vg0 = v2g * iuv;
283         int ug0 = u2g * iuv, ub0 = u2b * iuv;
284         while( uv < uv0 ) {
285                 vtor[uv] = vr0;  vtog[uv] = vg0;
286                 utog[uv] = ug0;  utob[uv] = ub0;
287                 ++uv;
288         }
289         while( uv < uv1 ) {
290                 vtor[uv] = iuv * v2r;  vtog[uv] = iuv * v2g;
291                 utog[uv] = iuv * u2g;  utob[uv] = iuv * u2b;
292                 ++uv;  ++iuv;
293         }
294         int vr1 = v2r * iuv, vg1 = v2g * iuv;
295         int ug1 = u2g * iuv, ub1 = u2b * iuv;
296         while( uv < len ) {
297                 vtor[uv] = vr1;  vtog[uv] = vg1;
298                 utog[uv] = ug1;  utob[uv] = ub1;
299                 ++uv;
300         }
301 }
302
303 void YUV::init_tables(int len,
304                 float *vtorf, float *vtogf, float *utogf, float *utobf)
305 {
306         int len1 = len-1, len2 = len/2;
307         for( int i=0,k=-len2; i<len; ++i,++k ) {
308                 vtorf[i] = (v_to_r * k)/len1;
309                 vtogf[i] = (v_to_g * k)/len1;
310                 utogf[i] = (u_to_g * k)/len1;
311                 utobf[i] = (u_to_b * k)/len1;
312         }
313 }
314
315 YUV::~YUV()
316 {
317         delete [] tab;
318         delete [] tabf;
319 }
320