1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * Author: Peter Schlaile < peter [at] schlaile [dot] de >
17  */
18 
19 /** \file
20  * \ingroup spseq
21  */
22 
23 #include <math.h>
24 #include <string.h>
25 
26 #include "BLI_task.h"
27 #include "BLI_utildefines.h"
28 
29 #include "IMB_colormanagement.h"
30 #include "IMB_imbuf.h"
31 #include "IMB_imbuf_types.h"
32 
33 #include "atomic_ops.h"
34 
35 #include "sequencer_intern.h"
36 
37 /* XXX, why is this function better than BLI_math version?
38  * only difference is it does some normalize after, need to double check on this - campbell */
rgb_to_yuv_normalized(const float rgb[3],float yuv[3])39 static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
40 {
41   yuv[0] = 0.299f * rgb[0] + 0.587f * rgb[1] + 0.114f * rgb[2];
42   yuv[1] = 0.492f * (rgb[2] - yuv[0]);
43   yuv[2] = 0.877f * (rgb[0] - yuv[0]);
44 
45   /* Normalize. */
46   yuv[1] *= 255.0f / (122 * 2.0f);
47   yuv[1] += 0.5f;
48 
49   yuv[2] *= 255.0f / (157 * 2.0f);
50   yuv[2] += 0.5f;
51 }
52 
scope_put_pixel(const uchar * table,uchar * pos)53 static void scope_put_pixel(const uchar *table, uchar *pos)
54 {
55   uchar newval = table[*pos];
56   pos[0] = pos[1] = pos[2] = newval;
57   pos[3] = 255;
58 }
59 
scope_put_pixel_single(const uchar * table,uchar * pos,int col)60 static void scope_put_pixel_single(const uchar *table, uchar *pos, int col)
61 {
62   char newval = table[pos[col]];
63   pos[col] = newval;
64   pos[3] = 255;
65 }
66 
wform_put_line(int w,uchar * last_pos,uchar * new_pos)67 static void wform_put_line(int w, uchar *last_pos, uchar *new_pos)
68 {
69   if (last_pos > new_pos) {
70     uchar *temp = new_pos;
71     new_pos = last_pos;
72     last_pos = temp;
73   }
74 
75   while (last_pos < new_pos) {
76     if (last_pos[0] == 0) {
77       last_pos[0] = last_pos[1] = last_pos[2] = 32;
78       last_pos[3] = 255;
79     }
80     last_pos += 4 * w;
81   }
82 }
83 
wform_put_line_single(int w,uchar * last_pos,uchar * new_pos,int col)84 static void wform_put_line_single(int w, uchar *last_pos, uchar *new_pos, int col)
85 {
86   if (last_pos > new_pos) {
87     uchar *temp = new_pos;
88     new_pos = last_pos;
89     last_pos = temp;
90   }
91 
92   while (last_pos < new_pos) {
93     if (last_pos[col] == 0) {
94       last_pos[col] = 32;
95       last_pos[3] = 255;
96     }
97     last_pos += 4 * w;
98   }
99 }
100 
wform_put_border(uchar * tgt,int w,int h)101 static void wform_put_border(uchar *tgt, int w, int h)
102 {
103   int x, y;
104 
105   for (x = 0; x < w; x++) {
106     uchar *p = tgt + 4 * x;
107     p[1] = p[3] = 155;
108     p[4 * w + 1] = p[4 * w + 3] = 155;
109     p = tgt + 4 * (w * (h - 1) + x);
110     p[1] = p[3] = 155;
111     p[-4 * w + 1] = p[-4 * w + 3] = 155;
112   }
113 
114   for (y = 0; y < h; y++) {
115     uchar *p = tgt + 4 * w * y;
116     p[1] = p[3] = 155;
117     p[4 + 1] = p[4 + 3] = 155;
118     p = tgt + 4 * (w * y + w - 1);
119     p[1] = p[3] = 155;
120     p[-4 + 1] = p[-4 + 3] = 155;
121   }
122 }
123 
wform_put_gridrow(uchar * tgt,float perc,int w,int h)124 static void wform_put_gridrow(uchar *tgt, float perc, int w, int h)
125 {
126   tgt += (int)(perc / 100.0f * h) * w * 4;
127 
128   for (int i = 0; i < w * 2; i++) {
129     tgt[0] = 255;
130 
131     tgt += 4;
132   }
133 }
134 
wform_put_grid(uchar * tgt,int w,int h)135 static void wform_put_grid(uchar *tgt, int w, int h)
136 {
137   wform_put_gridrow(tgt, 90.0, w, h);
138   wform_put_gridrow(tgt, 70.0, w, h);
139   wform_put_gridrow(tgt, 10.0, w, h);
140 }
141 
make_waveform_view_from_ibuf_byte(ImBuf * ibuf)142 static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf)
143 {
144   ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
145   int x, y;
146   const uchar *src = (uchar *)ibuf->rect;
147   uchar *tgt = (uchar *)rval->rect;
148   int w = ibuf->x + 3;
149   int h = 515;
150   float waveform_gamma = 0.2;
151   uchar wtable[256];
152 
153   wform_put_grid(tgt, w, h);
154   wform_put_border(tgt, w, h);
155 
156   for (x = 0; x < 256; x++) {
157     wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
158   }
159 
160   for (y = 0; y < ibuf->y; y++) {
161     uchar *last_p = NULL;
162 
163     for (x = 0; x < ibuf->x; x++) {
164       const uchar *rgb = src + 4 * (ibuf->x * y + x);
165       float v = (float)IMB_colormanagement_get_luminance_byte(rgb) / 255.0f;
166       uchar *p = tgt;
167       p += 4 * (w * ((int)(v * (h - 3)) + 1) + x + 1);
168 
169       scope_put_pixel(wtable, p);
170       p += 4 * w;
171       scope_put_pixel(wtable, p);
172 
173       if (last_p != NULL) {
174         wform_put_line(w, last_p, p);
175       }
176       last_p = p;
177     }
178   }
179 
180   return rval;
181 }
182 
make_waveform_view_from_ibuf_float(ImBuf * ibuf)183 static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf)
184 {
185   ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
186   int x, y;
187   const float *src = ibuf->rect_float;
188   uchar *tgt = (uchar *)rval->rect;
189   int w = ibuf->x + 3;
190   int h = 515;
191   float waveform_gamma = 0.2;
192   uchar wtable[256];
193 
194   wform_put_grid(tgt, w, h);
195 
196   for (x = 0; x < 256; x++) {
197     wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
198   }
199 
200   for (y = 0; y < ibuf->y; y++) {
201     uchar *last_p = NULL;
202 
203     for (x = 0; x < ibuf->x; x++) {
204       const float *rgb = src + 4 * (ibuf->x * y + x);
205       float v = IMB_colormanagement_get_luminance(rgb);
206       uchar *p = tgt;
207 
208       CLAMP(v, 0.0f, 1.0f);
209 
210       p += 4 * (w * ((int)(v * (h - 3)) + 1) + x + 1);
211 
212       scope_put_pixel(wtable, p);
213       p += 4 * w;
214       scope_put_pixel(wtable, p);
215 
216       if (last_p != NULL) {
217         wform_put_line(w, last_p, p);
218       }
219       last_p = p;
220     }
221   }
222 
223   wform_put_border(tgt, w, h);
224 
225   return rval;
226 }
227 
make_waveform_view_from_ibuf(ImBuf * ibuf)228 ImBuf *make_waveform_view_from_ibuf(ImBuf *ibuf)
229 {
230   if (ibuf->rect_float) {
231     return make_waveform_view_from_ibuf_float(ibuf);
232   }
233   return make_waveform_view_from_ibuf_byte(ibuf);
234 }
235 
make_sep_waveform_view_from_ibuf_byte(ImBuf * ibuf)236 static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf)
237 {
238   ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
239   int x, y;
240   const uchar *src = (const uchar *)ibuf->rect;
241   uchar *tgt = (uchar *)rval->rect;
242   int w = ibuf->x + 3;
243   int sw = ibuf->x / 3;
244   int h = 515;
245   float waveform_gamma = 0.2;
246   uchar wtable[256];
247 
248   wform_put_grid(tgt, w, h);
249 
250   for (x = 0; x < 256; x++) {
251     wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
252   }
253 
254   for (y = 0; y < ibuf->y; y++) {
255     uchar *last_p[3] = {NULL, NULL, NULL};
256 
257     for (x = 0; x < ibuf->x; x++) {
258       int c;
259       const uchar *rgb = src + 4 * (ibuf->x * y + x);
260       for (c = 0; c < 3; c++) {
261         uchar *p = tgt;
262         p += 4 * (w * ((rgb[c] * (h - 3)) / 255 + 1) + c * sw + x / 3 + 1);
263 
264         scope_put_pixel_single(wtable, p, c);
265         p += 4 * w;
266         scope_put_pixel_single(wtable, p, c);
267 
268         if (last_p[c] != NULL) {
269           wform_put_line_single(w, last_p[c], p, c);
270         }
271         last_p[c] = p;
272       }
273     }
274   }
275 
276   wform_put_border(tgt, w, h);
277 
278   return rval;
279 }
280 
make_sep_waveform_view_from_ibuf_float(ImBuf * ibuf)281 static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf)
282 {
283   ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
284   int x, y;
285   const float *src = ibuf->rect_float;
286   uchar *tgt = (uchar *)rval->rect;
287   int w = ibuf->x + 3;
288   int sw = ibuf->x / 3;
289   int h = 515;
290   float waveform_gamma = 0.2;
291   uchar wtable[256];
292 
293   wform_put_grid(tgt, w, h);
294 
295   for (x = 0; x < 256; x++) {
296     wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
297   }
298 
299   for (y = 0; y < ibuf->y; y++) {
300     uchar *last_p[3] = {NULL, NULL, NULL};
301 
302     for (x = 0; x < ibuf->x; x++) {
303       int c;
304       const float *rgb = src + 4 * (ibuf->x * y + x);
305       for (c = 0; c < 3; c++) {
306         uchar *p = tgt;
307         float v = rgb[c];
308 
309         CLAMP(v, 0.0f, 1.0f);
310 
311         p += 4 * (w * ((int)(v * (h - 3)) + 1) + c * sw + x / 3 + 1);
312 
313         scope_put_pixel_single(wtable, p, c);
314         p += 4 * w;
315         scope_put_pixel_single(wtable, p, c);
316 
317         if (last_p[c] != NULL) {
318           wform_put_line_single(w, last_p[c], p, c);
319         }
320         last_p[c] = p;
321       }
322     }
323   }
324 
325   wform_put_border(tgt, w, h);
326 
327   return rval;
328 }
329 
make_sep_waveform_view_from_ibuf(ImBuf * ibuf)330 ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf)
331 {
332   if (ibuf->rect_float) {
333     return make_sep_waveform_view_from_ibuf_float(ibuf);
334   }
335   return make_sep_waveform_view_from_ibuf_byte(ibuf);
336 }
337 
draw_zebra_byte(ImBuf * src,ImBuf * ibuf,float perc)338 static void draw_zebra_byte(ImBuf *src, ImBuf *ibuf, float perc)
339 {
340   uint limit = 255.0f * perc / 100.0f;
341   uchar *p = (uchar *)src->rect;
342   uchar *o = (uchar *)ibuf->rect;
343   int x;
344   int y;
345 
346   for (y = 0; y < ibuf->y; y++) {
347     for (x = 0; x < ibuf->x; x++) {
348       uchar r = *p++;
349       uchar g = *p++;
350       uchar b = *p++;
351       uchar a = *p++;
352 
353       if (r >= limit || g >= limit || b >= limit) {
354         if (((x + y) & 0x08) != 0) {
355           r = 255 - r;
356           g = 255 - g;
357           b = 255 - b;
358         }
359       }
360       *o++ = r;
361       *o++ = g;
362       *o++ = b;
363       *o++ = a;
364     }
365   }
366 }
367 
draw_zebra_float(ImBuf * src,ImBuf * ibuf,float perc)368 static void draw_zebra_float(ImBuf *src, ImBuf *ibuf, float perc)
369 {
370   float limit = perc / 100.0f;
371   const float *p = src->rect_float;
372   uchar *o = (uchar *)ibuf->rect;
373   int x;
374   int y;
375 
376   for (y = 0; y < ibuf->y; y++) {
377     for (x = 0; x < ibuf->x; x++) {
378       float r = *p++;
379       float g = *p++;
380       float b = *p++;
381       float a = *p++;
382 
383       if (r >= limit || g >= limit || b >= limit) {
384         if (((x + y) & 0x08) != 0) {
385           r = -r;
386           g = -g;
387           b = -b;
388         }
389       }
390 
391       *o++ = unit_float_to_uchar_clamp(r);
392       *o++ = unit_float_to_uchar_clamp(g);
393       *o++ = unit_float_to_uchar_clamp(b);
394       *o++ = unit_float_to_uchar_clamp(a);
395     }
396   }
397 }
398 
make_zebra_view_from_ibuf(ImBuf * ibuf,float perc)399 ImBuf *make_zebra_view_from_ibuf(ImBuf *ibuf, float perc)
400 {
401   ImBuf *new_ibuf = IMB_allocImBuf(ibuf->x, ibuf->y, 32, IB_rect);
402 
403   if (ibuf->rect_float) {
404     draw_zebra_float(ibuf, new_ibuf, perc);
405   }
406   else {
407     draw_zebra_byte(ibuf, new_ibuf, perc);
408   }
409   return new_ibuf;
410 }
411 
draw_histogram_marker(ImBuf * ibuf,int x)412 static void draw_histogram_marker(ImBuf *ibuf, int x)
413 {
414   uchar *p = (uchar *)ibuf->rect;
415   int barh = ibuf->y * 0.1;
416 
417   p += 4 * (x + ibuf->x * (ibuf->y - barh + 1));
418 
419   for (int i = 0; i < barh - 1; i++) {
420     p[0] = p[1] = p[2] = 255;
421     p += ibuf->x * 4;
422   }
423 }
424 
draw_histogram_bar(ImBuf * ibuf,int x,float val,int col)425 static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
426 {
427   uchar *p = (uchar *)ibuf->rect;
428   int barh = ibuf->y * val * 0.9f;
429 
430   p += 4 * (x + ibuf->x);
431 
432   for (int i = 0; i < barh; i++) {
433     p[col] = 255;
434     p += ibuf->x * 4;
435   }
436 }
437 
438 #define HIS_STEPS 512
439 
440 typedef struct MakeHistogramViewData {
441   const ImBuf *ibuf;
442 } MakeHistogramViewData;
443 
make_histogram_view_from_ibuf_byte_fn(void * __restrict userdata,const int y,const TaskParallelTLS * __restrict tls)444 static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata,
445                                                   const int y,
446                                                   const TaskParallelTLS *__restrict tls)
447 {
448   MakeHistogramViewData *data = userdata;
449   const ImBuf *ibuf = data->ibuf;
450   const uchar *src = (uchar *)ibuf->rect;
451 
452   uint32_t(*cur_bins)[HIS_STEPS] = tls->userdata_chunk;
453 
454   for (int x = 0; x < ibuf->x; x++) {
455     const uchar *pixel = src + (y * ibuf->x + x) * 4;
456 
457     for (int j = 3; j--;) {
458       cur_bins[j][pixel[j]]++;
459     }
460   }
461 }
462 
make_histogram_view_from_ibuf_reduce(const void * __restrict UNUSED (userdata),void * __restrict chunk_join,void * __restrict chunk)463 static void make_histogram_view_from_ibuf_reduce(const void *__restrict UNUSED(userdata),
464                                                  void *__restrict chunk_join,
465                                                  void *__restrict chunk)
466 {
467   uint32_t(*join_bins)[HIS_STEPS] = chunk_join;
468   uint32_t(*bins)[HIS_STEPS] = chunk;
469 
470   for (int j = 3; j--;) {
471     for (int i = 0; i < HIS_STEPS; i++) {
472       join_bins[j][i] += bins[j][i];
473     }
474   }
475 }
476 
make_histogram_view_from_ibuf_byte(ImBuf * ibuf)477 static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
478 {
479   ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
480   int x;
481   uint nr, ng, nb;
482 
483   uint bins[3][HIS_STEPS];
484 
485   memset(bins, 0, sizeof(bins));
486 
487   MakeHistogramViewData data = {
488       .ibuf = ibuf,
489   };
490   TaskParallelSettings settings;
491   BLI_parallel_range_settings_defaults(&settings);
492   settings.use_threading = (ibuf->y >= 256);
493   settings.userdata_chunk = bins;
494   settings.userdata_chunk_size = sizeof(bins);
495   settings.func_reduce = make_histogram_view_from_ibuf_reduce;
496   BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_fn, &settings);
497 
498   nr = nb = ng = 0;
499   for (x = 0; x < HIS_STEPS; x++) {
500     if (bins[0][x] > nr) {
501       nr = bins[0][x];
502     }
503     if (bins[1][x] > ng) {
504       ng = bins[1][x];
505     }
506     if (bins[2][x] > nb) {
507       nb = bins[2][x];
508     }
509   }
510 
511   for (x = 0; x < HIS_STEPS; x++) {
512     if (nr) {
513       draw_histogram_bar(rval, x * 2 + 1, ((float)bins[0][x]) / nr, 0);
514       draw_histogram_bar(rval, x * 2 + 2, ((float)bins[0][x]) / nr, 0);
515     }
516     if (ng) {
517       draw_histogram_bar(rval, x * 2 + 1, ((float)bins[1][x]) / ng, 1);
518       draw_histogram_bar(rval, x * 2 + 2, ((float)bins[1][x]) / ng, 1);
519     }
520     if (nb) {
521       draw_histogram_bar(rval, x * 2 + 1, ((float)bins[2][x]) / nb, 2);
522       draw_histogram_bar(rval, x * 2 + 2, ((float)bins[2][x]) / nb, 2);
523     }
524   }
525 
526   wform_put_border((uchar *)rval->rect, rval->x, rval->y);
527 
528   return rval;
529 }
530 
get_bin_float(float f)531 BLI_INLINE int get_bin_float(float f)
532 {
533   if (f < -0.25f) {
534     return 0;
535   }
536   if (f >= 1.25f) {
537     return 511;
538   }
539 
540   return (int)(((f + 0.25f) / 1.5f) * 512);
541 }
542 
make_histogram_view_from_ibuf_float_fn(void * __restrict userdata,const int y,const TaskParallelTLS * __restrict tls)543 static void make_histogram_view_from_ibuf_float_fn(void *__restrict userdata,
544                                                    const int y,
545                                                    const TaskParallelTLS *__restrict tls)
546 {
547   const MakeHistogramViewData *data = userdata;
548   const ImBuf *ibuf = data->ibuf;
549   const float *src = ibuf->rect_float;
550 
551   uint32_t(*cur_bins)[HIS_STEPS] = tls->userdata_chunk;
552 
553   for (int x = 0; x < ibuf->x; x++) {
554     const float *pixel = src + (y * ibuf->x + x) * 4;
555 
556     for (int j = 3; j--;) {
557       cur_bins[j][get_bin_float(pixel[j])]++;
558     }
559   }
560 }
561 
make_histogram_view_from_ibuf_float(ImBuf * ibuf)562 static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
563 {
564   ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
565   int nr, ng, nb;
566   int x;
567 
568   uint bins[3][HIS_STEPS];
569 
570   memset(bins, 0, sizeof(bins));
571 
572   MakeHistogramViewData data = {
573       .ibuf = ibuf,
574   };
575   TaskParallelSettings settings;
576   BLI_parallel_range_settings_defaults(&settings);
577   settings.use_threading = (ibuf->y >= 256);
578   settings.userdata_chunk = bins;
579   settings.userdata_chunk_size = sizeof(bins);
580   settings.func_reduce = make_histogram_view_from_ibuf_reduce;
581   BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_fn, &settings);
582 
583   nr = nb = ng = 0;
584   for (x = 0; x < HIS_STEPS; x++) {
585     if (bins[0][x] > nr) {
586       nr = bins[0][x];
587     }
588     if (bins[1][x] > ng) {
589       ng = bins[1][x];
590     }
591     if (bins[2][x] > nb) {
592       nb = bins[2][x];
593     }
594   }
595 
596   for (x = 0; x < HIS_STEPS; x++) {
597     if (nr) {
598       draw_histogram_bar(rval, x + 1, ((float)bins[0][x]) / nr, 0);
599     }
600     if (ng) {
601       draw_histogram_bar(rval, x + 1, ((float)bins[1][x]) / ng, 1);
602     }
603     if (nb) {
604       draw_histogram_bar(rval, x + 1, ((float)bins[2][x]) / nb, 2);
605     }
606   }
607 
608   draw_histogram_marker(rval, get_bin_float(0.0));
609   draw_histogram_marker(rval, get_bin_float(1.0));
610   wform_put_border((uchar *)rval->rect, rval->x, rval->y);
611 
612   return rval;
613 }
614 
615 #undef HIS_STEPS
616 
make_histogram_view_from_ibuf(ImBuf * ibuf)617 ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf)
618 {
619   if (ibuf->rect_float) {
620     return make_histogram_view_from_ibuf_float(ibuf);
621   }
622   return make_histogram_view_from_ibuf_byte(ibuf);
623 }
624 
vectorscope_put_cross(uchar r,uchar g,uchar b,char * tgt,int w,int h,int size)625 static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, int h, int size)
626 {
627   float rgb[3], yuv[3];
628   char *p;
629   int x = 0;
630   int y = 0;
631 
632   rgb[0] = (float)r / 255.0f;
633   rgb[1] = (float)g / 255.0f;
634   rgb[2] = (float)b / 255.0f;
635   rgb_to_yuv_normalized(rgb, yuv);
636 
637   p = tgt + 4 * (w * (int)((yuv[2] * (h - 3) + 1)) + (int)((yuv[1] * (w - 3) + 1)));
638 
639   if (r == 0 && g == 0 && b == 0) {
640     r = 255;
641   }
642 
643   for (y = -size; y <= size; y++) {
644     for (x = -size; x <= size; x++) {
645       char *q = p + 4 * (y * w + x);
646       q[0] = r;
647       q[1] = g;
648       q[2] = b;
649       q[3] = 255;
650     }
651   }
652 }
653 
make_vectorscope_view_from_ibuf_byte(ImBuf * ibuf)654 static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
655 {
656   ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect);
657   int x, y;
658   const char *src = (const char *)ibuf->rect;
659   char *tgt = (char *)rval->rect;
660   float rgb[3], yuv[3];
661   int w = 515;
662   int h = 515;
663   float scope_gamma = 0.2;
664   uchar wtable[256];
665 
666   for (x = 0; x < 256; x++) {
667     wtable[x] = (uchar)(pow(((float)x + 1) / 256, scope_gamma) * 255);
668   }
669 
670   for (x = 0; x < 256; x++) {
671     vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
672     vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
673     vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
674     vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
675     vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
676     vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
677   }
678 
679   for (y = 0; y < ibuf->y; y++) {
680     for (x = 0; x < ibuf->x; x++) {
681       const char *src1 = src + 4 * (ibuf->x * y + x);
682       char *p;
683 
684       rgb[0] = (float)src1[0] / 255.0f;
685       rgb[1] = (float)src1[1] / 255.0f;
686       rgb[2] = (float)src1[2] / 255.0f;
687       rgb_to_yuv_normalized(rgb, yuv);
688 
689       p = tgt + 4 * (w * (int)((yuv[2] * (h - 3) + 1)) + (int)((yuv[1] * (w - 3) + 1)));
690       scope_put_pixel(wtable, (uchar *)p);
691     }
692   }
693 
694   vectorscope_put_cross(0, 0, 0, tgt, w, h, 3);
695 
696   return rval;
697 }
698 
make_vectorscope_view_from_ibuf_float(ImBuf * ibuf)699 static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
700 {
701   ImBuf *rval = IMB_allocImBuf(515, 515, 32, IB_rect);
702   int x, y;
703   const float *src = ibuf->rect_float;
704   char *tgt = (char *)rval->rect;
705   float rgb[3], yuv[3];
706   int w = 515;
707   int h = 515;
708   float scope_gamma = 0.2;
709   uchar wtable[256];
710 
711   for (x = 0; x < 256; x++) {
712     wtable[x] = (uchar)(pow(((float)x + 1) / 256, scope_gamma) * 255);
713   }
714 
715   for (x = 0; x <= 255; x++) {
716     vectorscope_put_cross(255, 0, 255 - x, tgt, w, h, 1);
717     vectorscope_put_cross(255, x, 0, tgt, w, h, 1);
718     vectorscope_put_cross(255 - x, 255, 0, tgt, w, h, 1);
719     vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
720     vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
721     vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
722   }
723 
724   for (y = 0; y < ibuf->y; y++) {
725     for (x = 0; x < ibuf->x; x++) {
726       const float *src1 = src + 4 * (ibuf->x * y + x);
727       const char *p;
728 
729       memcpy(rgb, src1, sizeof(float[3]));
730 
731       clamp_v3(rgb, 0.0f, 1.0f);
732 
733       rgb_to_yuv_normalized(rgb, yuv);
734 
735       p = tgt + 4 * (w * (int)((yuv[2] * (h - 3) + 1)) + (int)((yuv[1] * (w - 3) + 1)));
736       scope_put_pixel(wtable, (uchar *)p);
737     }
738   }
739 
740   vectorscope_put_cross(0, 0, 0, tgt, w, h, 3);
741 
742   return rval;
743 }
744 
make_vectorscope_view_from_ibuf(ImBuf * ibuf)745 ImBuf *make_vectorscope_view_from_ibuf(ImBuf *ibuf)
746 {
747   if (ibuf->rect_float) {
748     return make_vectorscope_view_from_ibuf_float(ibuf);
749   }
750   return make_vectorscope_view_from_ibuf_byte(ibuf);
751 }
752