Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / scopewindow.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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 #include "bcsignals.h"
22 #include "cicolors.h"
23 #include "clip.h"
24 #include "cursors.h"
25 #include "language.h"
26 #include "scopewindow.h"
27 #include "theme.h"
28
29
30 #include <string.h>
31
32
33
34 ScopePackage::ScopePackage()
35  : LoadPackage()
36 {
37 }
38
39
40
41
42
43
44 ScopeUnit::ScopeUnit(ScopeGUI *gui, 
45         ScopeEngine *server)
46  : LoadClient(server)
47 {
48         this->gui = gui;
49 }
50
51
52
53
54
55 void ScopeUnit::draw_point(unsigned char **rows, 
56         int x, 
57         int y, 
58         int r, 
59         int g, 
60         int b)
61 {
62         unsigned char *pixel = rows[y] + x * 4;
63         pixel[0] = b;
64         pixel[1] = g;
65         pixel[2] = r;
66 }
67
68 #define PROCESS_PIXEL(column) \
69 { \
70 /* Calculate histogram */ \
71         if(use_hist) \
72         { \
73                 int v_i = (intensity - FLOAT_MIN) * (TOTAL_BINS / (FLOAT_MAX - FLOAT_MIN)); \
74                 CLAMP(v_i, 0, TOTAL_BINS - 1); \
75                 bins[3][v_i]++; \
76         } \
77         else \
78         if(use_hist_parade) \
79         { \
80                 int r_i = (r - FLOAT_MIN) * (TOTAL_BINS / (FLOAT_MAX - FLOAT_MIN)); \
81                 int g_i = (g - FLOAT_MIN) * (TOTAL_BINS / (FLOAT_MAX - FLOAT_MIN)); \
82                 int b_i = (b - FLOAT_MIN) * (TOTAL_BINS / (FLOAT_MAX - FLOAT_MIN)); \
83                 CLAMP(r_i, 0, TOTAL_BINS - 1); \
84                 CLAMP(g_i, 0, TOTAL_BINS - 1); \
85                 CLAMP(b_i, 0, TOTAL_BINS - 1); \
86                 bins[0][r_i]++; \
87                 bins[1][g_i]++; \
88                 bins[2][b_i]++; \
89         } \
90  \
91 /* Calculate waveform */ \
92         if(use_wave || use_wave_parade) \
93         { \
94                 x = (column) * wave_w / w; \
95                 if(x >= 0 && x < wave_w)  \
96                 { \
97                         if(use_wave_parade) \
98                         { \
99                                 y = wave_h -  \
100                                         (int)((r - FLOAT_MIN) /  \
101                                                 (FLOAT_MAX - FLOAT_MIN) * \
102                                                 wave_h); \
103          \
104                                 if(y >= 0 && y < wave_h)  \
105                                         draw_point(waveform_rows, x / 3, y, 0xff, 0x0, 0x0);  \
106          \
107                                 y = wave_h -  \
108                                         (int)((g - FLOAT_MIN) /  \
109                                                 (FLOAT_MAX - FLOAT_MIN) * \
110                                                 wave_h); \
111          \
112                                 if(y >= 0 && y < wave_h)  \
113                                         draw_point(waveform_rows, x / 3 + wave_w / 3, y, 0x0, 0xff, 0x0);  \
114          \
115                                 y = wave_h -  \
116                                         (int)((b - FLOAT_MIN) /  \
117                                                 (FLOAT_MAX - FLOAT_MIN) * \
118                                                 wave_h); \
119          \
120                                 if(y >= 0 && y < wave_h)  \
121                                         draw_point(waveform_rows, x / 3 + wave_w / 3 * 2, y, 0x0, 0x0, 0xff);  \
122          \
123                         } \
124                         else \
125                         { \
126                                 y = wave_h -  \
127                                         (int)((intensity - FLOAT_MIN) /  \
128                                                 (FLOAT_MAX - FLOAT_MIN) * \
129                                                 wave_h); \
130                          \
131                                 if(y >= 0 && y < wave_h)  \
132                                         draw_point(waveform_rows,  \
133                                                 x,  \
134                                                 y,  \
135                                                 0xff,  \
136                                                 0xff,  \
137                                                 0xff);  \
138                         } \
139                 } \
140         } \
141  \
142 /* Calculate vectorscope */ \
143         if(use_vector) \
144         { \
145                 float adjacent = cos((h + 90) / 360 * 2 * M_PI); \
146                 float opposite = sin((h + 90) / 360 * 2 * M_PI); \
147          \
148                 x = (int)(vector_w / 2 +  \
149                         adjacent * (s) / (FLOAT_MAX) * radius); \
150          \
151                 y = (int)(vector_h / 2 -  \
152                         opposite * (s) / (FLOAT_MAX) * radius); \
153          \
154          \
155                 CLAMP(x, 0, vector_w - 1); \
156                 CLAMP(y, 0, vector_h - 1); \
157          \
158         /* Get color with full saturation & value */ \
159                 float r_f, g_f, b_f; \
160                 HSV::hsv_to_rgb(r_f, \
161                                 g_f,  \
162                                 b_f,  \
163                                 h,  \
164                                 s,  \
165                                 1); \
166          \
167                 draw_point(vector_rows, \
168                         x,  \
169                         y,  \
170                         (int)(CLIP(r_f, 0, 1) * 255),  \
171                         (int)(CLIP(g_f, 0, 1) * 255),  \
172                         (int)(CLIP(b_f, 0, 1) * 255)); \
173         } \
174 }
175
176 #define PROCESS_RGB_PIXEL(column, max) \
177 { \
178         r = (float)*row++ / max; \
179         g = (float)*row++ / max; \
180         b = (float)*row++ / max; \
181         HSV::rgb_to_hsv(r,  \
182                 g,  \
183                 b,  \
184                 h,  \
185                 s,  \
186                 v); \
187         intensity = v; \
188         PROCESS_PIXEL(column) \
189 }
190
191 #define PROCESS_YUV_PIXEL(column,  \
192         y_in,  \
193         u_in,  \
194         v_in) \
195 { \
196         yuv.yuv_to_rgb_f(r, g, b, (float)y_in / 255, (float)(u_in - 0x80) / 255, (float)(v_in - 0x80) / 255); \
197         HSV::rgb_to_hsv(r,  \
198                 g,  \
199                 b,  \
200                 h,  \
201                 s,  \
202                 v); \
203         intensity = v; \
204         PROCESS_PIXEL(column) \
205 }
206
207
208 void ScopeUnit::process_package(LoadPackage *package)
209 {
210         ScopePackage *pkg = (ScopePackage*)package;
211
212
213         YUV yuv;
214         float r, g, b;
215         float h, s, v;
216         int x, y;
217         float intensity;
218         int use_hist = gui->use_hist;
219         int use_hist_parade = gui->use_hist_parade;
220         int use_vector = gui->use_vector;
221         int use_wave = gui->use_wave;
222         int use_wave_parade = gui->use_wave_parade;
223         BC_Bitmap *waveform_bitmap = gui->waveform_bitmap;
224         BC_Bitmap *vector_bitmap = gui->vector_bitmap;
225         int wave_h = waveform_bitmap->get_h();
226         int wave_w = waveform_bitmap->get_w();
227         int vector_h = vector_bitmap->get_h();
228         int vector_w = vector_bitmap->get_w();
229
230         int w = gui->output_frame->get_w();
231         float radius = MIN(gui->vector_w / 2, gui->vector_h / 2);
232
233
234
235
236         unsigned char **waveform_rows = waveform_bitmap->get_row_pointers();
237         unsigned char **vector_rows = vector_bitmap->get_row_pointers();
238
239
240         switch(gui->output_frame->get_color_model())
241         {
242                 case BC_RGB888:
243                         for(int i = pkg->row1; i < pkg->row2; i++)
244                         {
245                                 unsigned char *row = gui->output_frame->get_rows()[i];
246                                 for(int j = 0; j < w; j++)
247                                 {
248                                         PROCESS_RGB_PIXEL(j, 255)
249                                 }
250                         }
251                         break;
252
253                 case BC_RGBA8888:
254                         for(int i = pkg->row1; i < pkg->row2; i++)
255                         {
256                                 unsigned char *row = gui->output_frame->get_rows()[i];
257                                 for(int j = 0; j < w; j++)
258                                 {
259                                         PROCESS_RGB_PIXEL(j, 255)
260                                         row++;
261                                 }
262                         }
263                         break;
264                         
265                 case BC_RGB_FLOAT:
266                         for(int i = pkg->row1; i < pkg->row2; i++)
267                         {
268                                 float *row = (float*)gui->output_frame->get_rows()[i];
269                                 for(int j = 0; j < w; j++)
270                                 {
271                                         PROCESS_RGB_PIXEL(j, 1.0)
272                                 }
273                         }
274                         break;
275
276                 case BC_RGBA_FLOAT:
277                         for(int i = pkg->row1; i < pkg->row2; i++)
278                         {
279                                 float *row = (float*)gui->output_frame->get_rows()[i];
280                                 for(int j = 0; j < w; j++)
281                                 {
282                                         PROCESS_RGB_PIXEL(j, 1.0)
283                                         row++;
284                                 }
285                         }
286                         break;
287
288                 case BC_YUV888:
289                         for(int i = pkg->row1; i < pkg->row2; i++)
290                         {
291                                 unsigned char *row = gui->output_frame->get_rows()[i];
292                                 for(int j = 0; j < w; j++)
293                                 {
294                                         PROCESS_YUV_PIXEL(j, row[0], row[1], row[2])
295                                         row += 3;
296                                 }
297                         }
298                         break;
299
300                 case BC_YUVA8888:
301                         for(int i = pkg->row1; i < pkg->row2; i++)
302                         {
303                                 unsigned char *row = gui->output_frame->get_rows()[i];
304                                 for(int j = 0; j < w; j++)
305                                 {
306                                         PROCESS_YUV_PIXEL(j, row[0], row[1], row[2])
307                                         row += 4;
308                                 }
309                         }
310                         break;
311                         
312
313                 case BC_YUV420P:
314                         for(int i = pkg->row1; i < pkg->row2; i++)
315                         {
316                                 unsigned char *y_row = gui->output_frame->get_y() + i * gui->output_frame->get_w();
317                                 unsigned char *u_row = gui->output_frame->get_u() + (i / 2) * (gui->output_frame->get_w() / 2);
318                                 unsigned char *v_row = gui->output_frame->get_v() + (i / 2) * (gui->output_frame->get_w() / 2);
319                                 for(int j = 0; j < w; j += 2)
320                                 {
321                                         PROCESS_YUV_PIXEL(j, *y_row, *u_row, *v_row);
322                                         y_row++;
323                                         PROCESS_YUV_PIXEL(j + 1, *y_row, *u_row, *v_row);
324                                         y_row++;
325
326                                         u_row++;
327                                         v_row++;
328                                 }
329                         }
330                         break;
331
332                 case BC_YUV422:
333                         for(int i = pkg->row1; i < pkg->row2; i++)
334                         {
335                                 unsigned char *row = gui->output_frame->get_rows()[i];
336                                 for(int j = 0; j < gui->output_frame->get_w(); j += 2)
337                                 {
338                                         PROCESS_YUV_PIXEL(j, row[0], row[1], row[3]);
339                                         PROCESS_YUV_PIXEL(j + 1, row[2], row[1], row[3]);
340                                         row += 4;
341                                 }
342                         }
343                         break;
344
345                 default:
346                         printf("ScopeUnit::process_package %d: color_model=%d unrecognized\n",
347                                 __LINE__,
348                                 gui->output_frame->get_color_model());
349                         break;
350         }
351
352 }
353
354
355
356
357
358
359 ScopeEngine::ScopeEngine(ScopeGUI *gui, int cpus)
360  : LoadServer(cpus, cpus)
361 {
362 //printf("ScopeEngine::ScopeEngine %d cpus=%d\n", __LINE__, cpus);
363         this->gui = gui;
364 }
365
366 ScopeEngine::~ScopeEngine()
367 {
368 }
369
370 void ScopeEngine::init_packages()
371 {
372         for(int i = 0; i < LoadServer::get_total_packages(); i++)
373         {
374                 ScopePackage *pkg = (ScopePackage*)get_package(i);
375                 pkg->row1 = gui->output_frame->get_h() * i / LoadServer::get_total_packages();
376                 pkg->row2 = gui->output_frame->get_h() * (i + 1) / LoadServer::get_total_packages();
377         }
378
379         for(int i = 0; i < get_total_clients(); i++)
380         {
381                 ScopeUnit *unit = (ScopeUnit*)get_client(i);
382                 for(int j = 0; j < HIST_SECTIONS; j++)
383                         bzero(unit->bins[j], sizeof(int) * TOTAL_BINS);
384         }
385 }
386
387
388 LoadClient* ScopeEngine::new_client()
389 {
390         return new ScopeUnit(gui, this);
391 }
392
393 LoadPackage* ScopeEngine::new_package()
394 {
395         return new ScopePackage;
396 }
397
398 void ScopeEngine::process()
399 {
400         process_packages();
401         
402         for(int i = 0; i < HIST_SECTIONS; i++)
403                 bzero(gui->bins[i], sizeof(int) * TOTAL_BINS);
404
405         for(int i = 0; i < get_total_clients(); i++)
406         {
407                 ScopeUnit *unit = (ScopeUnit*)get_client(i);
408                 for(int j = 0; j < HIST_SECTIONS; j++)
409                 {
410                         for(int k = 0; k < TOTAL_BINS; k++)
411                         {
412                                 gui->bins[j][k] += unit->bins[j][k];
413                         }
414                 }
415         }
416 }
417
418
419
420 ScopeGUI::ScopeGUI(Theme *theme,
421         int x,
422         int y,
423         int w,
424         int h,
425         int cpus)
426  : PluginClientWindow(PROGRAM_NAME ": Scopes", 
427         x, 
428         y, 
429         w, 
430         h, 
431         MIN_SCOPE_W, 
432         MIN_SCOPE_H,
433         1)
434 {
435         this->x = x;
436         this->y = y;
437         this->w = w;
438         this->h = h;
439         this->theme = theme;
440         this->cpus = cpus;
441         reset();
442 }
443
444 ScopeGUI::ScopeGUI(PluginClient *plugin, 
445         int w,
446         int h)
447  : PluginClientWindow(plugin,
448         w, 
449         h, 
450         MIN_SCOPE_W, 
451         MIN_SCOPE_H,
452         1)
453 {
454         this->x = get_x();
455         this->y = get_y();
456         this->w = w;
457         this->h = h;
458         this->theme = plugin->get_theme();
459         this->cpus = plugin->PluginClient::smp + 1;
460         reset();
461 }
462
463 ScopeGUI::~ScopeGUI()
464 {
465         delete waveform_bitmap;
466         delete vector_bitmap;
467         delete engine;
468 }
469
470 void ScopeGUI::reset()
471 {
472         frame_w = 1;
473         waveform_bitmap = 0;
474         vector_bitmap = 0;
475         engine = 0;
476         use_hist = 0;
477         use_wave = 1;
478         use_vector = 1;
479         use_hist_parade = 0;
480         use_wave_parade = 0;
481         waveform = 0;
482         vectorscope = 0;
483         histogram = 0;
484         wave_w = wave_h = vector_w = vector_h = 0;
485 }
486
487
488 void ScopeGUI::create_objects()
489 {
490         if(use_hist && use_hist_parade)
491         {
492                 use_hist = 0;
493         }
494         
495         if(use_wave && use_wave_parade)
496         {
497                 use_wave = 0;
498         }
499
500         if(!engine) engine = new ScopeEngine(this, 
501                 cpus);
502
503         lock_window("ScopeGUI::create_objects");
504         
505         
506         int x = theme->widget_border;
507         int y = theme->widget_border;
508
509
510         add_subwindow(hist_on = new ScopeToggle(this, 
511                 x, 
512                 y,
513                 &use_hist));
514         x += hist_on->get_w() + theme->widget_border;
515
516         add_subwindow(hist_parade_on = new ScopeToggle(this, 
517                 x, 
518                 y,
519                 &use_hist_parade));
520         x += hist_parade_on->get_w() + theme->widget_border;
521
522         add_subwindow(waveform_on = new ScopeToggle(this, 
523                 x, 
524                 y,
525                 &use_wave));
526         x += waveform_on->get_w() + theme->widget_border;
527         add_subwindow(waveform_parade_on = new ScopeToggle(this, 
528                 x, 
529                 y,
530                 &use_wave_parade));
531         x += waveform_parade_on->get_w() + theme->widget_border;
532
533         add_subwindow(vector_on = new ScopeToggle(this, 
534                 x, 
535                 y,
536                 &use_vector));
537         x += vector_on->get_w() + theme->widget_border;
538
539         add_subwindow(value_text = new BC_Title(x, y, ""));
540         x += value_text->get_w() + theme->widget_border;
541
542         y += vector_on->get_h() + theme->widget_border;
543
544
545 //PRINT_TRACE
546
547         create_panels();
548 //PRINT_TRACE
549
550
551
552
553
554
555
556         update_toggles();
557         show_window();
558         unlock_window();
559 }
560
561
562
563 void ScopeGUI::create_panels()
564 {
565         calculate_sizes(get_w(), get_h());
566
567
568         if((use_wave || use_wave_parade))
569         {
570                 if(!waveform)
571                 {
572                         add_subwindow(waveform = new ScopeWaveform(this,
573                                 wave_x, 
574                                 wave_y, 
575                                 wave_w, 
576                                 wave_h));
577                         waveform->create_objects();
578                 }
579                 else
580                 {
581                         waveform->reposition_window(wave_x, 
582                                 wave_y, 
583                                 wave_w, 
584                                 wave_h);
585                         waveform->clear_box(0, 0, wave_w, wave_h);
586                 }
587         }
588         else
589         if(!(use_wave || use_wave_parade) && waveform)
590         {
591                 delete waveform;
592                 waveform = 0;
593         }
594         
595         if(use_vector)
596         {
597                 if(!vectorscope)
598                 {
599                         add_subwindow(vectorscope = new ScopeVectorscope(this,
600                                 vector_x, 
601                                 vector_y, 
602                                 vector_w, 
603                                 vector_h));
604                         vectorscope->create_objects();
605                 }
606                 else
607                 {
608                         vectorscope->reposition_window(vector_x, 
609                                 vector_y, 
610                                 vector_w, 
611                                 vector_h);
612                         vectorscope->clear_box(0, 0, vector_w, vector_h);
613                 }
614         }
615         else
616         if(!use_vector && vectorscope)
617         {
618                 delete vectorscope;
619                 vectorscope = 0;
620         }
621         
622         if((use_hist || use_hist_parade))
623         {
624                 if(!histogram)
625                 {
626 // printf("ScopeGUI::create_panels %d %d %d %d %d\n", __LINE__, hist_x, 
627 // hist_y, 
628 // hist_w, 
629 // hist_h);
630                         add_subwindow(histogram = new ScopeHistogram(this,
631                                 hist_x, 
632                                 hist_y, 
633                                 hist_w, 
634                                 hist_h));
635                         histogram->create_objects();
636                 }
637                 else
638                 {
639                         histogram->reposition_window(hist_x, 
640                                 hist_y, 
641                                 hist_w, 
642                                 hist_h);
643                         histogram->clear_box(0, 0, hist_w, hist_h);
644                 }
645         }
646         else
647         if(!(use_hist || use_hist_parade))
648         {
649                 delete histogram;
650                 histogram = 0;
651         }
652         
653         
654
655         allocate_bitmaps();
656         clear_points(0);
657         draw_overlays(1, 1, 0);
658 }
659
660 void ScopeGUI::clear_points(int flash)
661 {
662         if(histogram) histogram->clear_point();
663         if(waveform) waveform->clear_point();
664         if(vectorscope) vectorscope->clear_point();
665         if(histogram && flash) histogram->flash(0);
666         if(waveform && flash) waveform->flash(0);
667         if(vectorscope && flash) vectorscope->flash(0);
668 }
669
670 void ScopeGUI::toggle_event()
671 {
672         
673 }
674
675 void ScopeGUI::calculate_sizes(int w, int h)
676 {
677         int margin = theme->widget_border;
678         int text_w = get_text_width(SMALLFONT, "000") + margin * 2;
679         int total_panels = ((use_hist || use_hist_parade) ? 1 : 0) +
680                 ((use_wave || use_wave_parade) ? 1 : 0) +
681                 (use_vector ? 1 : 0);
682         int x = margin;
683
684         int panel_w = (w - margin) / (total_panels > 0 ? total_panels : 1);
685 // Vectorscope determines the size of everything else
686 // Always last panel
687         vector_w = 0;
688         if(use_vector)
689         {
690                 vector_x = w - panel_w + text_w;
691                 vector_w = w - margin - vector_x;
692                 vector_y = vector_on->get_h() + margin * 2;
693                 vector_h = h - vector_y - margin;
694                 
695                 if(vector_w > vector_h) 
696                 {
697                         vector_w = vector_h;
698                         vector_x = w - theme->widget_border - vector_w;
699                 }
700
701                 total_panels--;
702                 if(total_panels > 0)
703                         panel_w = (vector_x - text_w - margin) / total_panels;
704         }
705
706 // Histogram is always 1st panel
707         if(use_hist || use_hist_parade)
708         {
709                 hist_x = x;
710                 hist_y = vector_on->get_h() + margin * 2;
711                 hist_w = panel_w - margin;
712                 hist_h = h - hist_y - margin;
713                 
714                 total_panels--;
715                 x += panel_w;
716         }
717
718         if(use_wave || use_wave_parade)
719         {
720                 wave_x = x + text_w;
721                 wave_y = vector_on->get_h() + margin * 2;
722                 wave_w = panel_w - margin - text_w;
723                 wave_h = h - wave_y - margin;
724         }
725
726 }
727
728
729 void ScopeGUI::allocate_bitmaps()
730 {
731         if(waveform_bitmap) delete waveform_bitmap;
732         if(vector_bitmap) delete vector_bitmap;
733
734         int w;
735         int h;
736 // printf("ScopeGUI::allocate_bitmaps %d %d %d %d %d\n",
737 // __LINE__,
738 // wave_w,
739 // wave_h,
740 // vector_w,
741 // vector_h);
742         w = MAX(wave_w, 16);
743         h = MAX(wave_h, 16);
744         waveform_bitmap = new_bitmap(w, h);
745         w = MAX(vector_w, 16);
746         h = MAX(vector_h, 16);
747         vector_bitmap = new_bitmap(w, h);
748 }
749
750
751 int ScopeGUI::resize_event(int w, int h)
752 {
753         clear_box(0, 0, w, h);
754         this->w = w;
755         this->h = h;
756         calculate_sizes(w, h);
757         
758         if(waveform)
759         {
760                 waveform->reposition_window(wave_x, wave_y, wave_w, wave_h);
761                 waveform->clear_box(0, 0, wave_w, wave_h);
762         }
763         
764         if(histogram)
765         {
766                 histogram->reposition_window(hist_x, hist_y, hist_w, hist_h);
767                 histogram->clear_box(0, 0, hist_w, hist_h);
768         }
769         
770         if(vectorscope)
771         {
772                 vectorscope->reposition_window(vector_x, vector_y, vector_w, vector_h);
773                 vectorscope->clear_box(0, 0, vector_w, vector_h);
774         }
775
776         allocate_bitmaps();
777
778
779         clear_points(0);
780         draw_overlays(1, 1, 1);
781
782         return 1;
783 }
784
785 int ScopeGUI::translation_event()
786 {
787         x = get_x();
788         y = get_y();
789         
790         PluginClientWindow::translation_event();
791         return 0;
792 }
793
794
795 void ScopeGUI::draw_overlays(int overlays, int borders, int flush)
796 {
797         BC_Resources *resources = BC_WindowBase::get_resources();
798         int text_color = GREEN;
799         if(resources->bg_color == 0xffffff)
800         {
801                 text_color = BLACK;
802         }
803         
804         if(overlays && borders)
805         {
806                 clear_box(0, 0, get_w(), get_h());
807         }
808
809         if(overlays)
810         {
811                 set_line_dashes(1);
812                 set_color(text_color);
813                 set_font(SMALLFONT);
814
815                 if(histogram && (use_hist || use_hist_parade))
816                 {
817                         histogram->draw_line(hist_w * -FLOAT_MIN / (FLOAT_MAX - FLOAT_MIN), 
818                                         0, 
819                                         hist_w * -FLOAT_MIN / (FLOAT_MAX - FLOAT_MIN), 
820                                         hist_h);
821                         histogram->draw_line(hist_w * (1.0 - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN), 
822                                         0, 
823                                         hist_w * (1.0 - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN), 
824                                         hist_h);
825                         set_line_dashes(0);
826                         histogram->draw_point();
827                         set_line_dashes(1);
828                         histogram->flash(0);
829                 }
830
831 // Waveform overlay
832                 if(waveform && (use_wave || use_wave_parade))
833                 {
834                         set_color(text_color);
835                         for(int i = 0; i <= WAVEFORM_DIVISIONS; i++)
836                         {
837                                 int y = wave_h * i / WAVEFORM_DIVISIONS;
838                                 int text_y = y + wave_y + get_text_ascent(SMALLFONT) / 2;
839                                 CLAMP(text_y, waveform->get_y() + get_text_ascent(SMALLFONT), waveform->get_y() + waveform->get_h() - 1);
840                                 char string[BCTEXTLEN];
841                                 sprintf(string, "%d", 
842                                         (int)((FLOAT_MAX - 
843                                         i * (FLOAT_MAX - FLOAT_MIN) / WAVEFORM_DIVISIONS) * 100));
844                                 int text_x = wave_x - get_text_width(SMALLFONT, string) - theme->widget_border;
845                                 draw_text(text_x, text_y, string);
846
847                                 int y1 = CLAMP(y, 0, waveform->get_h() - 1);
848                                 waveform->draw_line(0, y1, wave_w, y1);
849                                 //waveform->draw_rectangle(0, 0, wave_w, wave_h);
850                         }
851                         set_line_dashes(0);
852                         waveform->draw_point();
853                         set_line_dashes(1);
854                         waveform->flash(0);
855                 }
856
857
858 // Vectorscope overlay
859                 if(vectorscope && use_vector)
860                 {
861                         set_color(text_color);
862                         int radius = MIN(vector_w / 2, vector_h / 2);
863                         for(int i = 1; i <= VECTORSCOPE_DIVISIONS; i += 2)
864                         {
865                                 int x = vector_w / 2 - radius * i / VECTORSCOPE_DIVISIONS;
866                                 int y = vector_h / 2 - radius * i / VECTORSCOPE_DIVISIONS;
867                                 int text_y = y + vector_y + get_text_ascent(SMALLFONT) / 2;
868                                 int w = radius * i / VECTORSCOPE_DIVISIONS * 2;
869                                 int h = radius * i / VECTORSCOPE_DIVISIONS * 2;
870                                 char string[BCTEXTLEN];
871
872                                 sprintf(string, "%d", 
873                                         (int)((FLOAT_MAX / VECTORSCOPE_DIVISIONS * i) * 100));
874                                 int text_x = vector_x - get_text_width(SMALLFONT, string) - theme->widget_border;
875                                 draw_text(text_x, text_y, string);
876 //printf("ScopeGUI::draw_overlays %d %d %d %s\n", __LINE__, text_x, text_y, string);
877                                 
878                                 vectorscope->draw_circle(x, y, w, h);
879                 //vectorscope->draw_rectangle(0, 0, vector_w, vector_h);
880                         }
881                 //      vectorscope->draw_circle(vector_w / 2 - radius, 
882                 //              vector_h / 2 - radius, 
883                 //              radius * 2, 
884                 //              radius * 2);
885
886                         set_line_dashes(0);
887                         vectorscope->draw_point();
888                         set_line_dashes(1);
889                         vectorscope->flash(0);
890                 }
891
892                 set_font(MEDIUMFONT);
893                 set_line_dashes(0);
894         }
895
896         if(borders)
897         {
898                 if(use_hist || use_hist_parade)
899                 {
900                         draw_3d_border(hist_x - 2, 
901                                 hist_y - 2, 
902                                 hist_w + 4, 
903                                 hist_h + 4, 
904                                 get_bg_color(),
905                                 BLACK,
906                                 MDGREY, 
907                                 get_bg_color());
908                 }
909
910                 if(use_wave || use_wave_parade)
911                 {
912                         draw_3d_border(wave_x - 2, 
913                                 wave_y - 2, 
914                                 wave_w + 4, 
915                                 wave_h + 4, 
916                                 get_bg_color(),
917                                 BLACK,
918                                 MDGREY, 
919                                 get_bg_color());
920                 }
921
922                 if(use_vector)
923                 {
924                         draw_3d_border(vector_x - 2, 
925                                 vector_y - 2, 
926                                 vector_w + 4, 
927                                 vector_h + 4, 
928                                 get_bg_color(),
929                                 BLACK,
930                                 MDGREY, 
931                                 get_bg_color());
932                 }
933         }
934
935         flash(0);
936         if(flush) this->flush();
937 }
938
939
940
941 void ScopeGUI::process(VFrame *output_frame)
942 {
943         lock_window("ScopeGUI::process");
944         this->output_frame = output_frame;
945         frame_w = output_frame->get_w();
946         //float radius = MIN(vector_w / 2, vector_h / 2);
947
948         bzero(waveform_bitmap->get_data(), waveform_bitmap->get_data_size());
949         bzero(vector_bitmap->get_data(), vector_bitmap->get_data_size());
950
951
952         engine->process();
953
954         if(histogram)
955         {
956                 histogram->draw(0, 0);
957         }
958
959         if(waveform)
960         {
961                 waveform->draw_bitmap(waveform_bitmap, 
962                         1,
963                         0,
964                         0);
965         }
966
967         if(vectorscope)
968         {
969                 vectorscope->draw_bitmap(vector_bitmap, 
970                         1,
971                         0,
972                         0);
973         }
974
975         draw_overlays(1, 0, 1);
976         unlock_window();
977 }
978
979
980 void ScopeGUI::update_toggles()
981 {
982         hist_parade_on->update(use_hist_parade);
983         hist_on->update(use_hist);
984         waveform_parade_on->update(use_wave_parade);
985         waveform_on->update(use_wave);
986         vector_on->update(use_vector);
987 }
988
989
990
991
992
993
994
995
996
997
998 ScopePanel::ScopePanel(ScopeGUI *gui, 
999         int x, 
1000         int y,
1001         int w,
1002         int h)
1003  : BC_SubWindow(x, y, w, h, BLACK)
1004 {
1005         this->gui = gui;
1006         is_dragging = 0;
1007 }
1008
1009 void ScopePanel::create_objects()
1010 {
1011         set_cursor(CROSS_CURSOR, 0, 0);
1012         clear_box(0, 0, get_w(), get_h());
1013 }
1014
1015 void ScopePanel::update_point(int x, int y)
1016 {
1017 }
1018
1019 void ScopePanel::draw_point()
1020 {
1021 }
1022
1023 void ScopePanel::clear_point()
1024 {
1025 }
1026
1027 int ScopePanel::button_press_event()
1028 {
1029         if(is_event_win() && cursor_inside())
1030         {
1031                 gui->clear_points(1);
1032         
1033                 is_dragging = 1;
1034                 int x = get_cursor_x();
1035                 int y = get_cursor_y();
1036                 CLAMP(x, 0, get_w() - 1);
1037                 CLAMP(y, 0, get_h() - 1);
1038                 update_point(x, y);
1039                 return 1;
1040         }
1041         return 0;
1042 }
1043
1044
1045 int ScopePanel::cursor_motion_event()
1046 {
1047         if(is_dragging)
1048         {
1049                 int x = get_cursor_x();
1050                 int y = get_cursor_y();
1051                 CLAMP(x, 0, get_w() - 1);
1052                 CLAMP(y, 0, get_h() - 1);
1053                 update_point(x, y);
1054                 return 1;
1055         }
1056         return 0;
1057 }
1058
1059
1060 int ScopePanel::button_release_event()
1061 {
1062         if(is_dragging)
1063         {
1064                 is_dragging = 0;
1065                 return 1;
1066         }
1067         return 0;
1068 }
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078 ScopeWaveform::ScopeWaveform(ScopeGUI *gui, 
1079                 int x, 
1080                 int y,
1081                 int w,
1082                 int h)
1083  : ScopePanel(gui, x, y, w, h)
1084 {
1085         drag_x = -1;
1086         drag_y = -1;
1087 }
1088
1089 void ScopeWaveform::update_point(int x, int y)
1090 {
1091         draw_point();
1092         drag_x = x;
1093         drag_y = y;
1094         int frame_x = x * gui->frame_w / get_w();
1095
1096         if(gui->use_wave_parade)
1097         {
1098                 if(x > get_w() / 3 * 2)
1099                         frame_x = (x - get_w() / 3 * 2) * gui->frame_w / (get_w() / 3);
1100                 else
1101                 if(x > get_w() / 3)
1102                         frame_x = (x - get_w() / 3) * gui->frame_w / (get_w() / 3);
1103                 else
1104                         frame_x = x * gui->frame_w / (get_w() / 3);
1105         }
1106
1107         float value = ((float)get_h() - y) / get_h() * (FLOAT_MAX - FLOAT_MIN) + FLOAT_MIN;
1108
1109         char string[BCTEXTLEN];
1110         sprintf(string, "X: %d Value: %.3f", frame_x, value);
1111         gui->value_text->update(string, 0);
1112
1113         draw_point();
1114         flash(1);
1115 }
1116
1117 void ScopeWaveform::draw_point()
1118 {
1119         if(drag_x >= 0)
1120         {
1121                 set_inverse();
1122                 set_color(0xffffff);
1123                 set_line_width(2);
1124                 draw_line(0, drag_y, get_w(), drag_y);
1125                 draw_line(drag_x, 0, drag_x, get_h());
1126                 set_line_width(1);
1127                 set_opaque();
1128         }
1129 }
1130
1131 void ScopeWaveform::clear_point()
1132 {
1133         draw_point();
1134         drag_x = -1;
1135         drag_y = -1;
1136 }
1137
1138
1139
1140
1141
1142
1143
1144 ScopeVectorscope::ScopeVectorscope(ScopeGUI *gui, 
1145                 int x, 
1146                 int y,
1147                 int w,
1148                 int h)
1149  : ScopePanel(gui, x, y, w, h)
1150 {
1151         drag_radius = 0;
1152         drag_angle = 0;
1153 }
1154
1155 void ScopeVectorscope::clear_point()
1156 {
1157 // Hide it
1158         draw_point();
1159         drag_radius = 0;
1160         drag_angle = 0;
1161 }
1162
1163 void ScopeVectorscope::update_point(int x, int y)
1164 {
1165 // Hide it
1166         draw_point();
1167
1168         int radius = MIN(get_w() / 2, get_h() / 2);
1169         drag_radius = sqrt(SQR(x - get_w() / 2) + SQR(y - get_h() / 2));
1170         drag_angle = atan2(y - get_h() / 2, x - get_w() / 2);
1171
1172         drag_radius = MIN(drag_radius, radius);
1173
1174         float saturation = (float)drag_radius / radius * FLOAT_MAX;
1175         float hue = -drag_angle * 360 / 2 / M_PI - 90;
1176         if(hue < 0) hue += 360;
1177
1178         char string[BCTEXTLEN];
1179         sprintf(string, "Hue: %.3f Sat: %.3f", hue, saturation);
1180         gui->value_text->update(string, 0);
1181
1182 // Show it
1183         draw_point();
1184         flash(1);
1185 }
1186
1187 void ScopeVectorscope::draw_point()
1188 {
1189         if(drag_radius > 0)
1190         {
1191                 int radius = MIN(get_w() / 2, get_h() / 2);
1192                 set_inverse();
1193                 set_color(0xff0000);
1194                 set_line_width(2);
1195                 draw_circle(get_w() / 2 - drag_radius, 
1196                         get_h() / 2 - drag_radius, 
1197                         drag_radius * 2, 
1198                         drag_radius * 2);
1199                 
1200                 draw_line(get_w() / 2, 
1201                         get_h() / 2, 
1202                         get_w() / 2 + radius * cos(drag_angle),
1203                         get_h() / 2 + radius * sin(drag_angle));
1204                 set_line_width(1);
1205                 set_opaque();
1206         }
1207 }
1208
1209
1210
1211 ScopeHistogram::ScopeHistogram(ScopeGUI *gui, 
1212                 int x, 
1213                 int y,
1214                 int w,
1215                 int h)
1216  : ScopePanel(gui, x, y, w, h)
1217 {
1218         drag_x = -1;
1219 }
1220
1221 void ScopeHistogram::clear_point()
1222 {
1223 // Hide it
1224         draw_point();
1225         drag_x = -1;
1226 }
1227
1228 void ScopeHistogram::draw_point()
1229 {
1230         if(drag_x >= 0)
1231         {
1232                 set_inverse();
1233                 set_color(0xffffff);
1234                 set_line_width(2);
1235                 draw_line(drag_x, 0, drag_x, get_h());
1236                 set_line_width(1);
1237                 set_opaque();
1238         }
1239 }
1240
1241 void ScopeHistogram::update_point(int x, int y)
1242 {
1243         draw_point();
1244         drag_x = x;
1245         float value = (float)x / get_w() * (FLOAT_MAX - FLOAT_MIN) + FLOAT_MIN;
1246         
1247         char string[BCTEXTLEN];
1248         sprintf(string, "Value: %.3f", value);
1249         gui->value_text->update(string, 0);
1250
1251         draw_point();
1252         flash(1);
1253 }
1254
1255
1256
1257 void ScopeHistogram::draw_mode(int mode, int color, int y, int h)
1258 {
1259 // Highest of all bins
1260         int normalize = 0;
1261         for(int i = 0; i < TOTAL_BINS; i++)
1262         {
1263                 if(gui->bins[mode][i] > normalize) normalize = gui->bins[mode][i];
1264         }
1265
1266
1267
1268         set_color(color);
1269         for(int i = 0; i < get_w(); i++)
1270         {
1271                 int accum_start = (int)(i * TOTAL_BINS / get_w());
1272                 int accum_end = (int)((i + 1) * TOTAL_BINS / get_w());
1273                 CLAMP(accum_start, 0, TOTAL_BINS);
1274                 CLAMP(accum_end, 0, TOTAL_BINS);
1275
1276                 int max = 0;
1277                 for(int k = accum_start; k < accum_end; k++)
1278                 {
1279                         max = MAX(gui->bins[mode][k], max);
1280                 }
1281
1282 //                      max = max * h / normalize;
1283                 max = (int)(log(max) / log(normalize) * h);
1284
1285                 draw_line(i, y + h - max, i, y + h);
1286         }
1287 }
1288
1289 void ScopeHistogram::draw(int flash, int flush)
1290 {
1291         clear_box(0, 0, get_w(), get_h());
1292
1293         if(gui->use_hist_parade)
1294         {
1295                 draw_mode(0, 0xff0000, 0, get_h() / 3);
1296                 draw_mode(1, 0x00ff00, get_h() / 3, get_h() / 3);
1297                 draw_mode(2, 0x0000ff, get_h() / 3 * 2, get_h() / 3);
1298         }
1299         else
1300         {
1301                 draw_mode(3, LTGREY, 0, get_h());
1302         }
1303         
1304         if(flash) this->flash(0);
1305         if(flush) this->flush();
1306 }
1307
1308
1309
1310
1311
1312
1313 ScopeToggle::ScopeToggle(ScopeGUI *gui, 
1314         int x, 
1315         int y,
1316         int *value)
1317  : BC_Toggle(x, 
1318         y, 
1319         get_image_set(gui, value),
1320         *value)
1321 {
1322         this->gui = gui;
1323         this->value = value;
1324         if(value == &gui->use_hist_parade)
1325         {
1326                 set_tooltip("Histogram Parade");
1327         }
1328         else
1329         if(value == &gui->use_hist)
1330         {
1331                 set_tooltip("Histogram");
1332         }
1333         else
1334         if(value == &gui->use_wave_parade)
1335         {
1336                 set_tooltip("Waveform Parade");
1337         }
1338         else
1339         if(value == &gui->use_wave)
1340         {
1341                 set_tooltip("Waveform");
1342         }
1343         else
1344         {
1345                 set_tooltip("Vectorscope");
1346         }
1347 }
1348
1349 VFrame** ScopeToggle::get_image_set(ScopeGUI *gui, int *value)
1350 {
1351         if(value == &gui->use_hist_parade)
1352         {
1353                 return gui->theme->get_image_set("histogram_rgb_toggle");
1354         }
1355         else
1356         if(value == &gui->use_hist)
1357         {
1358                 return gui->theme->get_image_set("histogram_toggle");
1359         }
1360         else
1361         if(value == &gui->use_wave_parade)
1362         {
1363                 return gui->theme->get_image_set("waveform_rgb_toggle");
1364         }
1365         else
1366         if(value == &gui->use_wave)
1367         {
1368                 return gui->theme->get_image_set("waveform_toggle");
1369         }
1370         else
1371         {
1372                 return gui->theme->get_image_set("scope_toggle");
1373         }
1374 }
1375
1376 int ScopeToggle::handle_event()
1377 {
1378         *value = get_value();
1379         if(value == &gui->use_hist_parade)
1380         {
1381                 if(get_value()) gui->use_hist = 0;
1382         }
1383         else
1384         if(value == &gui->use_hist)
1385         {
1386                 if(get_value()) gui->use_hist_parade = 0;
1387         }
1388         else
1389         if(value == &gui->use_wave_parade)
1390         {
1391                 if(get_value()) gui->use_wave = 0;
1392         }
1393         else
1394         if(value == &gui->use_wave)
1395         {
1396                 if(get_value()) gui->use_wave_parade = 0;
1397         }
1398
1399
1400         gui->toggle_event();
1401         gui->update_toggles();
1402         gui->create_panels();
1403         gui->show_window();
1404         return 1;
1405 }
1406
1407
1408