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