edit drag handle cursor per track, batchrender col width fix, batchrender path errmsg...
[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         w = MAX(wave_w, 16);
741         h = MAX(wave_h, 16);
742         waveform_bitmap = new_bitmap(w, h);
743         w = MAX(vector_w, 16);
744         h = MAX(vector_h, 16);
745         vector_bitmap = new_bitmap(w, h);
746 }
747
748
749 int ScopeGUI::resize_event(int w, int h)
750 {
751         clear_box(0, 0, w, h);
752         this->w = w;
753         this->h = h;
754         calculate_sizes(w, h);
755
756         if(waveform)
757         {
758                 waveform->reposition_window(wave_x, wave_y, wave_w, wave_h);
759                 waveform->clear_box(0, 0, wave_w, wave_h);
760         }
761
762         if(histogram)
763         {
764                 histogram->reposition_window(hist_x, hist_y, hist_w, hist_h);
765                 histogram->clear_box(0, 0, hist_w, hist_h);
766         }
767
768         if(vectorscope)
769         {
770                 vectorscope->reposition_window(vector_x, vector_y, vector_w, vector_h);
771                 vectorscope->clear_box(0, 0, vector_w, vector_h);
772         }
773
774         allocate_bitmaps();
775
776
777         clear_points(0);
778         draw_overlays(1, 1, 1);
779
780         return 1;
781 }
782
783 int ScopeGUI::translation_event()
784 {
785         x = get_x();
786         y = get_y();
787
788         PluginClientWindow::translation_event();
789         return 0;
790 }
791
792
793 void ScopeGUI::draw_overlays(int overlays, int borders, int flush)
794 {
795         BC_Resources *resources = BC_WindowBase::get_resources();
796         int text_color = GREEN;
797         if(resources->bg_color == 0xffffff)
798         {
799                 text_color = BLACK;
800         }
801
802         if(overlays && borders)
803         {
804                 clear_box(0, 0, get_w(), get_h());
805         }
806
807         if(overlays)
808         {
809                 set_line_dashes(1);
810                 set_color(text_color);
811                 set_font(SMALLFONT);
812
813                 if(histogram && (use_hist || use_hist_parade))
814                 {
815                         histogram->draw_line(hist_w * -FLOAT_MIN / (FLOAT_MAX - FLOAT_MIN),
816                                         0,
817                                         hist_w * -FLOAT_MIN / (FLOAT_MAX - FLOAT_MIN),
818                                         hist_h);
819                         histogram->draw_line(hist_w * (1.0 - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN),
820                                         0,
821                                         hist_w * (1.0 - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN),
822                                         hist_h);
823                         set_line_dashes(0);
824                         histogram->draw_point();
825                         set_line_dashes(1);
826                         histogram->flash(0);
827                 }
828
829 // Waveform overlay
830                 if(waveform && (use_wave || use_wave_parade))
831                 {
832                         set_color(text_color);
833                         for(int i = 0; i <= WAVEFORM_DIVISIONS; i++)
834                         {
835                                 int y = wave_h * i / WAVEFORM_DIVISIONS;
836                                 int text_y = y + wave_y + get_text_ascent(SMALLFONT) / 2;
837                                 CLAMP(text_y, waveform->get_y() + get_text_ascent(SMALLFONT), waveform->get_y() + waveform->get_h() - 1);
838                                 char string[BCTEXTLEN];
839                                 sprintf(string, "%d",
840                                         (int)((FLOAT_MAX -
841                                         i * (FLOAT_MAX - FLOAT_MIN) / WAVEFORM_DIVISIONS) * 100));
842                                 int text_x = wave_x - get_text_width(SMALLFONT, string) - theme->widget_border;
843                                 draw_text(text_x, text_y, string);
844
845                                 int y1 = CLAMP(y, 0, waveform->get_h() - 1);
846                                 waveform->draw_line(0, y1, wave_w, y1);
847                                 //waveform->draw_rectangle(0, 0, wave_w, wave_h);
848                         }
849                         set_line_dashes(0);
850                         waveform->draw_point();
851                         set_line_dashes(1);
852                         waveform->flash(0);
853                 }
854
855
856 // Vectorscope overlay
857                 if(vectorscope && use_vector)
858                 {
859                         set_color(text_color);
860                         int radius = MIN(vector_w / 2, vector_h / 2);
861                         for(int i = 1; i <= VECTORSCOPE_DIVISIONS; i += 2)
862                         {
863                                 int x = vector_w / 2 - radius * i / VECTORSCOPE_DIVISIONS;
864                                 int y = vector_h / 2 - radius * i / VECTORSCOPE_DIVISIONS;
865                                 int text_y = y + vector_y + get_text_ascent(SMALLFONT) / 2;
866                                 int w = radius * i / VECTORSCOPE_DIVISIONS * 2;
867                                 int h = radius * i / VECTORSCOPE_DIVISIONS * 2;
868                                 char string[BCTEXTLEN];
869
870                                 sprintf(string, "%d",
871                                         (int)((FLOAT_MAX / VECTORSCOPE_DIVISIONS * i) * 100));
872                                 int text_x = vector_x - get_text_width(SMALLFONT, string) - theme->widget_border;
873                                 draw_text(text_x, text_y, string);
874 //printf("ScopeGUI::draw_overlays %d %d %d %s\n", __LINE__, text_x, text_y, string);
875
876                                 vectorscope->draw_circle(x, y, w, h);
877                 //vectorscope->draw_rectangle(0, 0, vector_w, vector_h);
878                         }
879                 //      vectorscope->draw_circle(vector_w / 2 - radius,
880                 //              vector_h / 2 - radius,
881                 //              radius * 2,
882                 //              radius * 2);
883
884                         set_line_dashes(0);
885                         vectorscope->draw_point();
886                         set_line_dashes(1);
887                         vectorscope->flash(0);
888                 }
889
890                 set_font(MEDIUMFONT);
891                 set_line_dashes(0);
892         }
893
894         if(borders)
895         {
896                 if(use_hist || use_hist_parade)
897                 {
898                         draw_3d_border(hist_x - 2,
899                                 hist_y - 2,
900                                 hist_w + 4,
901                                 hist_h + 4,
902                                 get_bg_color(),
903                                 BLACK,
904                                 MDGREY,
905                                 get_bg_color());
906                 }
907
908                 if(use_wave || use_wave_parade)
909                 {
910                         draw_3d_border(wave_x - 2,
911                                 wave_y - 2,
912                                 wave_w + 4,
913                                 wave_h + 4,
914                                 get_bg_color(),
915                                 BLACK,
916                                 MDGREY,
917                                 get_bg_color());
918                 }
919
920                 if(use_vector)
921                 {
922                         draw_3d_border(vector_x - 2,
923                                 vector_y - 2,
924                                 vector_w + 4,
925                                 vector_h + 4,
926                                 get_bg_color(),
927                                 BLACK,
928                                 MDGREY,
929                                 get_bg_color());
930                 }
931         }
932
933         flash(0);
934         if(flush) this->flush();
935 }
936
937
938
939 void ScopeGUI::process(VFrame *output_frame)
940 {
941         lock_window("ScopeGUI::process");
942         this->output_frame = output_frame;
943         frame_w = output_frame->get_w();
944         //float radius = MIN(vector_w / 2, vector_h / 2);
945
946         bzero(waveform_bitmap->get_data(), waveform_bitmap->get_data_size());
947         bzero(vector_bitmap->get_data(), vector_bitmap->get_data_size());
948
949
950         engine->process();
951
952         if(histogram)
953         {
954                 histogram->draw(0, 0);
955         }
956
957         if(waveform)
958         {
959                 waveform->draw_bitmap(waveform_bitmap,
960                         1,
961                         0,
962                         0);
963         }
964
965         if(vectorscope)
966         {
967                 vectorscope->draw_bitmap(vector_bitmap,
968                         1,
969                         0,
970                         0);
971         }
972
973         draw_overlays(1, 0, 1);
974         unlock_window();
975 }
976
977
978 void ScopeGUI::update_toggles()
979 {
980         hist_parade_on->update(use_hist_parade);
981         hist_on->update(use_hist);
982         waveform_parade_on->update(use_wave_parade);
983         waveform_on->update(use_wave);
984         vector_on->update(use_vector);
985 }
986
987
988
989
990
991
992
993
994
995
996 ScopePanel::ScopePanel(ScopeGUI *gui,
997         int x,
998         int y,
999         int w,
1000         int h)
1001  : BC_SubWindow(x, y, w, h, BLACK)
1002 {
1003         this->gui = gui;
1004         is_dragging = 0;
1005 }
1006
1007 void ScopePanel::create_objects()
1008 {
1009         set_cursor(CROSS_CURSOR, 0, 0);
1010         clear_box(0, 0, get_w(), get_h());
1011 }
1012
1013 void ScopePanel::update_point(int x, int y)
1014 {
1015 }
1016
1017 void ScopePanel::draw_point()
1018 {
1019 }
1020
1021 void ScopePanel::clear_point()
1022 {
1023 }
1024
1025 int ScopePanel::button_press_event()
1026 {
1027         if(is_event_win() && cursor_inside())
1028         {
1029                 gui->clear_points(1);
1030
1031                 is_dragging = 1;
1032                 int x = get_cursor_x();
1033                 int y = get_cursor_y();
1034                 CLAMP(x, 0, get_w() - 1);
1035                 CLAMP(y, 0, get_h() - 1);
1036                 update_point(x, y);
1037                 return 1;
1038         }
1039         return 0;
1040 }
1041
1042
1043 int ScopePanel::cursor_motion_event()
1044 {
1045         if(is_dragging)
1046         {
1047                 int x = get_cursor_x();
1048                 int y = get_cursor_y();
1049                 CLAMP(x, 0, get_w() - 1);
1050                 CLAMP(y, 0, get_h() - 1);
1051                 update_point(x, y);
1052                 return 1;
1053         }
1054         return 0;
1055 }
1056
1057
1058 int ScopePanel::button_release_event()
1059 {
1060         if(is_dragging)
1061         {
1062                 is_dragging = 0;
1063                 return 1;
1064         }
1065         return 0;
1066 }
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 ScopeWaveform::ScopeWaveform(ScopeGUI *gui,
1077                 int x,
1078                 int y,
1079                 int w,
1080                 int h)
1081  : ScopePanel(gui, x, y, w, h)
1082 {
1083         drag_x = -1;
1084         drag_y = -1;
1085 }
1086
1087 void ScopeWaveform::update_point(int x, int y)
1088 {
1089         draw_point();
1090         drag_x = x;
1091         drag_y = y;
1092         int frame_x = x * gui->frame_w / get_w();
1093
1094         if(gui->use_wave_parade)
1095         {
1096                 if(x > get_w() / 3 * 2)
1097                         frame_x = (x - get_w() / 3 * 2) * gui->frame_w / (get_w() / 3);
1098                 else
1099                 if(x > get_w() / 3)
1100                         frame_x = (x - get_w() / 3) * gui->frame_w / (get_w() / 3);
1101                 else
1102                         frame_x = x * gui->frame_w / (get_w() / 3);
1103         }
1104
1105         float value = ((float)get_h() - y) / get_h() * (FLOAT_MAX - FLOAT_MIN) + FLOAT_MIN;
1106
1107         char string[BCTEXTLEN];
1108         sprintf(string, "X: %d Value: %.3f", frame_x, value);
1109         gui->value_text->update(string, 0);
1110
1111         draw_point();
1112         flash(1);
1113 }
1114
1115 void ScopeWaveform::draw_point()
1116 {
1117         if(drag_x >= 0)
1118         {
1119                 set_inverse();
1120                 set_color(0xffffff);
1121                 set_line_width(2);
1122                 draw_line(0, drag_y, get_w(), drag_y);
1123                 draw_line(drag_x, 0, drag_x, get_h());
1124                 set_line_width(1);
1125                 set_opaque();
1126         }
1127 }
1128
1129 void ScopeWaveform::clear_point()
1130 {
1131         draw_point();
1132         drag_x = -1;
1133         drag_y = -1;
1134 }
1135
1136
1137
1138
1139
1140
1141
1142 ScopeVectorscope::ScopeVectorscope(ScopeGUI *gui,
1143                 int x,
1144                 int y,
1145                 int w,
1146                 int h)
1147  : ScopePanel(gui, x, y, w, h)
1148 {
1149         drag_radius = 0;
1150         drag_angle = 0;
1151 }
1152
1153 void ScopeVectorscope::clear_point()
1154 {
1155 // Hide it
1156         draw_point();
1157         drag_radius = 0;
1158         drag_angle = 0;
1159 }
1160
1161 void ScopeVectorscope::update_point(int x, int y)
1162 {
1163 // Hide it
1164         draw_point();
1165
1166         int radius = MIN(get_w() / 2, get_h() / 2);
1167         drag_radius = sqrt(SQR(x - get_w() / 2) + SQR(y - get_h() / 2));
1168         drag_angle = atan2(y - get_h() / 2, x - get_w() / 2);
1169
1170         drag_radius = MIN(drag_radius, radius);
1171
1172         float saturation = (float)drag_radius / radius * FLOAT_MAX;
1173         float hue = -drag_angle * 360 / 2 / M_PI - 90;
1174         if(hue < 0) hue += 360;
1175
1176         char string[BCTEXTLEN];
1177         sprintf(string, "Hue: %.3f Sat: %.3f", hue, saturation);
1178         gui->value_text->update(string, 0);
1179
1180 // Show it
1181         draw_point();
1182         flash(1);
1183 }
1184
1185 void ScopeVectorscope::draw_point()
1186 {
1187         if(drag_radius > 0)
1188         {
1189                 int radius = MIN(get_w() / 2, get_h() / 2);
1190                 set_inverse();
1191                 set_color(0xff0000);
1192                 set_line_width(2);
1193                 draw_circle(get_w() / 2 - drag_radius,
1194                         get_h() / 2 - drag_radius,
1195                         drag_radius * 2,
1196                         drag_radius * 2);
1197
1198                 draw_line(get_w() / 2,
1199                         get_h() / 2,
1200                         get_w() / 2 + radius * cos(drag_angle),
1201                         get_h() / 2 + radius * sin(drag_angle));
1202                 set_line_width(1);
1203                 set_opaque();
1204         }
1205 }
1206
1207
1208
1209 ScopeHistogram::ScopeHistogram(ScopeGUI *gui,
1210                 int x,
1211                 int y,
1212                 int w,
1213                 int h)
1214  : ScopePanel(gui, x, y, w, h)
1215 {
1216         drag_x = -1;
1217 }
1218
1219 void ScopeHistogram::clear_point()
1220 {
1221 // Hide it
1222         draw_point();
1223         drag_x = -1;
1224 }
1225
1226 void ScopeHistogram::draw_point()
1227 {
1228         if(drag_x >= 0)
1229         {
1230                 set_inverse();
1231                 set_color(0xffffff);
1232                 set_line_width(2);
1233                 draw_line(drag_x, 0, drag_x, get_h());
1234                 set_line_width(1);
1235                 set_opaque();
1236         }
1237 }
1238
1239 void ScopeHistogram::update_point(int x, int y)
1240 {
1241         draw_point();
1242         drag_x = x;
1243         float value = (float)x / get_w() * (FLOAT_MAX - FLOAT_MIN) + FLOAT_MIN;
1244
1245         char string[BCTEXTLEN];
1246         sprintf(string, "Value: %.3f", value);
1247         gui->value_text->update(string, 0);
1248
1249         draw_point();
1250         flash(1);
1251 }
1252
1253
1254
1255 void ScopeHistogram::draw_mode(int mode, int color, int y, int h)
1256 {
1257 // Highest of all bins
1258         int normalize = 0;
1259         for(int i = 0; i < TOTAL_BINS; i++)
1260         {
1261                 if(gui->bins[mode][i] > normalize) normalize = gui->bins[mode][i];
1262         }
1263
1264
1265
1266         set_color(color);
1267         for(int i = 0; i < get_w(); i++)
1268         {
1269                 int accum_start = (int)(i * TOTAL_BINS / get_w());
1270                 int accum_end = (int)((i + 1) * TOTAL_BINS / get_w());
1271                 CLAMP(accum_start, 0, TOTAL_BINS);
1272                 CLAMP(accum_end, 0, TOTAL_BINS);
1273
1274                 int max = 0;
1275                 for(int k = accum_start; k < accum_end; k++)
1276                 {
1277                         max = MAX(gui->bins[mode][k], max);
1278                 }
1279
1280 //                      max = max * h / normalize;
1281                 max = (int)(log(max) / log(normalize) * h);
1282
1283                 draw_line(i, y + h - max, i, y + h);
1284         }
1285 }
1286
1287 void ScopeHistogram::draw(int flash, int flush)
1288 {
1289         clear_box(0, 0, get_w(), get_h());
1290
1291         if(gui->use_hist_parade)
1292         {
1293                 draw_mode(0, 0xff0000, 0, get_h() / 3);
1294                 draw_mode(1, 0x00ff00, get_h() / 3, get_h() / 3);
1295                 draw_mode(2, 0x0000ff, get_h() / 3 * 2, get_h() / 3);
1296         }
1297         else
1298         {
1299                 draw_mode(3, LTGREY, 0, get_h());
1300         }
1301
1302         if(flash) this->flash(0);
1303         if(flush) this->flush();
1304 }
1305
1306
1307
1308
1309
1310
1311 ScopeToggle::ScopeToggle(ScopeGUI *gui,
1312         int x,
1313         int y,
1314         int *value)
1315  : BC_Toggle(x,
1316         y,
1317         get_image_set(gui, value),
1318         *value)
1319 {
1320         this->gui = gui;
1321         this->value = value;
1322         if(value == &gui->use_hist_parade)
1323         {
1324                 set_tooltip(_("Histogram Parade"));
1325         }
1326         else
1327         if(value == &gui->use_hist)
1328         {
1329                 set_tooltip(_("Histogram"));
1330         }
1331         else
1332         if(value == &gui->use_wave_parade)
1333         {
1334                 set_tooltip(_("Waveform Parade"));
1335         }
1336         else
1337         if(value == &gui->use_wave)
1338         {
1339                 set_tooltip(_("Waveform"));
1340         }
1341         else
1342         {
1343                 set_tooltip(_("Vectorscope"));
1344         }
1345 }
1346
1347 VFrame** ScopeToggle::get_image_set(ScopeGUI *gui, int *value)
1348 {
1349         if(value == &gui->use_hist_parade)
1350         {
1351                 return gui->theme->get_image_set("histogram_rgb_toggle");
1352         }
1353         else
1354         if(value == &gui->use_hist)
1355         {
1356                 return gui->theme->get_image_set("histogram_toggle");
1357         }
1358         else
1359         if(value == &gui->use_wave_parade)
1360         {
1361                 return gui->theme->get_image_set("waveform_rgb_toggle");
1362         }
1363         else
1364         if(value == &gui->use_wave)
1365         {
1366                 return gui->theme->get_image_set("waveform_toggle");
1367         }
1368         else
1369         {
1370                 return gui->theme->get_image_set("scope_toggle");
1371         }
1372 }
1373
1374 int ScopeToggle::handle_event()
1375 {
1376         *value = get_value();
1377         if(value == &gui->use_hist_parade)
1378         {
1379                 if(get_value()) gui->use_hist = 0;
1380         }
1381         else
1382         if(value == &gui->use_hist)
1383         {
1384                 if(get_value()) gui->use_hist_parade = 0;
1385         }
1386         else
1387         if(value == &gui->use_wave_parade)
1388         {
1389                 if(get_value()) gui->use_wave = 0;
1390         }
1391         else
1392         if(value == &gui->use_wave)
1393         {
1394                 if(get_value()) gui->use_wave_parade = 0;
1395         }
1396
1397
1398         gui->toggle_event();
1399         gui->update_toggles();
1400         gui->create_panels();
1401         gui->show_window();
1402         return 1;
1403 }
1404
1405
1406