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