upgrade ladspa, gradient widget fix
[goodguy/history.git] / cinelerra-5.1 / plugins / gradient / gradient.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include <math.h>
23 #include <stdint.h>
24 #include <string.h>
25
26 #include "bcdisplayinfo.h"
27 #include "clip.h"
28 #include "bchash.h"
29 #include "filexml.h"
30 #include "gradient.h"
31 #include "keyframe.h"
32 #include "language.h"
33 #include "overlayframe.h"
34 #include "theme.h"
35 #include "vframe.h"
36
37
38
39
40 REGISTER_PLUGIN(GradientMain)
41
42
43
44
45
46
47 GradientConfig::GradientConfig()
48 {
49         angle = 0;
50         in_radius = 0;
51         out_radius = 100;
52         in_r = 0xff;
53         in_g = 0xff;
54         in_b = 0xff;
55         in_a = 0xff;
56         out_r = 0x0;
57         out_g = 0x0;
58         out_b = 0x0;
59         out_a = 0x0;
60         shape = GradientConfig::LINEAR;
61         rate = GradientConfig::LINEAR;
62         center_x = 50;
63         center_y = 50;
64 }
65
66 int GradientConfig::equivalent(GradientConfig &that)
67 {
68         return (EQUIV(angle, that.angle) &&
69                 EQUIV(in_radius, that.in_radius) &&
70                 EQUIV(out_radius, that.out_radius) &&
71                 in_r == that.in_r &&
72                 in_g == that.in_g &&
73                 in_b == that.in_b &&
74                 in_a == that.in_a &&
75                 out_r == that.out_r &&
76                 out_g == that.out_g &&
77                 out_b == that.out_b &&
78                 out_a == that.out_a &&
79                 shape == that.shape &&
80                 rate == that.rate &&
81                 EQUIV(center_x, that.center_x) &&
82                 EQUIV(center_y, that.center_y));
83 }
84
85 void GradientConfig::copy_from(GradientConfig &that)
86 {
87         angle = that.angle;
88         in_radius = that.in_radius;
89         out_radius = that.out_radius;
90         in_r = that.in_r;
91         in_g = that.in_g;
92         in_b = that.in_b;
93         in_a = that.in_a;
94         out_r = that.out_r;
95         out_g = that.out_g;
96         out_b = that.out_b;
97         out_a = that.out_a;
98         shape = that.shape;
99         rate = that.rate;
100         center_x = that.center_x;
101         center_y = that.center_y;
102 }
103
104 void GradientConfig::interpolate(GradientConfig &prev,
105         GradientConfig &next,
106         long prev_frame,
107         long next_frame,
108         long current_frame)
109 {
110         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
111         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
112
113
114         this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
115         this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
116         this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
117         in_r = (int)(prev.in_r * prev_scale + next.in_r * next_scale);
118         in_g = (int)(prev.in_g * prev_scale + next.in_g * next_scale);
119         in_b = (int)(prev.in_b * prev_scale + next.in_b * next_scale);
120         in_a = (int)(prev.in_a * prev_scale + next.in_a * next_scale);
121         out_r = (int)(prev.out_r * prev_scale + next.out_r * next_scale);
122         out_g = (int)(prev.out_g * prev_scale + next.out_g * next_scale);
123         out_b = (int)(prev.out_b * prev_scale + next.out_b * next_scale);
124         out_a = (int)(prev.out_a * prev_scale + next.out_a * next_scale);
125         shape = prev.shape;
126         rate = prev.rate;
127         center_x = prev.center_x * prev_scale + next.center_x * next_scale;
128         center_y = prev.center_y * prev_scale + next.center_y * next_scale;
129 }
130
131 int GradientConfig::get_in_color()
132 {
133         int result = (in_r << 16) | (in_g << 8) | (in_b);
134         return result;
135 }
136
137 int GradientConfig::get_out_color()
138 {
139         int result = (out_r << 16) | (out_g << 8) | (out_b);
140         return result;
141 }
142
143
144
145
146
147
148
149
150
151
152
153 #define COLOR_W 100
154 #define COLOR_H 30
155
156 GradientWindow::GradientWindow(GradientMain *plugin)
157  : PluginClientWindow(plugin,
158         350,
159         290,
160         350,
161         290,
162         0)
163 {
164         this->plugin = plugin;
165         angle = 0;
166         angle_title = 0;
167         center_x = 0;
168         center_y = 0;
169         center_x_title = 0;
170         center_y_title = 0;
171 }
172
173 GradientWindow::~GradientWindow()
174 {
175         delete in_color_thread;
176         delete out_color_thread;
177 }
178
179 void GradientWindow::create_objects()
180 {
181         int margin = plugin->get_theme()->widget_border;
182         int x = 10, y = 10;
183         BC_Title *title;
184
185         add_subwindow(title = new BC_Title(x, y, _("Shape:")));
186         add_subwindow(shape = new GradientShape(plugin,
187                 this,
188                 x + title->get_w() + margin,
189                 y));
190         shape->create_objects();
191         y += shape->get_h() + margin;
192         shape_x = x;
193         shape_y = y;
194         y += BC_Pot::calculate_h() + margin;
195
196         add_subwindow(title = new BC_Title(x, y, _("Rate:")));
197         add_subwindow(rate = new GradientRate(plugin,
198                 x + title->get_w() + margin,
199                 y));
200         rate->create_objects();
201         y += rate->get_h() + margin;
202
203         int x1 = x;
204         int y1 = y;
205
206         BC_Title *title1;
207         add_subwindow(title1 = new BC_Title(x, y, _("Inner radius:")));
208
209         y += BC_Slider::get_span(0) + margin;
210
211         BC_Title *title2;
212         add_subwindow(title2 = new BC_Title(x, y, _("Outer radius:")));
213
214         y = y1;
215         x += MAX(title1->get_w(), title2->get_w()) + margin;
216
217         add_subwindow(in_radius = new GradientInRadius(plugin, x, y));
218         y += in_radius->get_h() + margin;
219
220         add_subwindow(out_radius = new GradientOutRadius(plugin, x, y));
221         y += out_radius->get_h() + margin;
222
223         x = x1;
224         y1 = y;
225         add_subwindow(in_color = new GradientInColorButton(plugin, this, x, y));
226         y += COLOR_H + margin;
227
228
229         add_subwindow(out_color = new GradientOutColorButton(plugin, this, x, y));
230         x += MAX(in_color->get_w(), out_color->get_w()) + margin;
231         y = y1;
232
233         in_color_x = x;
234         in_color_y = y;
235         y += COLOR_H + margin;
236         out_color_x = x;
237         out_color_y = y;
238         in_color_thread = new GradientInColorThread(plugin, this);
239         out_color_thread = new GradientOutColorThread(plugin, this);
240         update_in_color();
241         update_out_color();
242         update_shape();
243
244         draw_3d_border(in_color_x - 2,
245                 in_color_y - 2,
246                 COLOR_W + 4,
247                 COLOR_H + 4,
248                 1);
249
250         draw_3d_border(out_color_x - 2,
251                 out_color_y - 2,
252                 COLOR_W + 4,
253                 COLOR_H + 4,
254                 1);
255
256         show_window();
257 }
258
259 void GradientWindow::update_shape()
260 {
261         int x = shape_x, y = shape_y;
262
263         if(plugin->config.shape == GradientConfig::LINEAR)
264         {
265                 delete center_x_title;
266                 delete center_y_title;
267                 delete center_x;
268                 delete center_y;
269                 center_x_title = 0;
270                 center_y_title = 0;
271                 center_x = 0;
272                 center_y = 0;
273
274                 if(!angle)
275                 {
276                         add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
277                         add_subwindow(angle = new GradientAngle(plugin, x + angle_title->get_w() + 10, y));
278                 }
279         }
280         else
281         {
282                 delete angle_title;
283                 delete angle;
284                 angle_title = 0;
285                 angle = 0;
286                 if(!center_x)
287                 {
288                         add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
289                         add_subwindow(center_x = new GradientCenterX(plugin,
290                                 x + center_x_title->get_w() + 10,
291                                 y));
292                         x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
293                         add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
294                         add_subwindow(center_y = new GradientCenterY(plugin,
295                                 x + center_y_title->get_w() + 10,
296                                 y));
297                 }
298         }
299         show_window();
300 }
301
302
303
304
305 void GradientWindow::update_in_color()
306 {
307 //printf("GradientWindow::update_in_color 1 %08x\n", plugin->config.get_in_color());
308         set_color(plugin->config.get_in_color());
309         draw_box(in_color_x, in_color_y, COLOR_W, COLOR_H);
310         flash(in_color_x, in_color_y, COLOR_W, COLOR_H);
311 }
312
313 void GradientWindow::update_out_color()
314 {
315 //printf("GradientWindow::update_out_color 1 %08x\n", plugin->config.get_in_color());
316         set_color(plugin->config.get_out_color());
317         draw_box(out_color_x, out_color_y, COLOR_W, COLOR_H);
318         flash(out_color_x, out_color_y, COLOR_W, COLOR_H);
319 }
320
321 void GradientWindow::done_event(int result)
322 {
323         in_color_thread->close_window();
324         out_color_thread->close_window();
325 }
326
327
328
329
330
331
332
333
334
335 GradientShape::GradientShape(GradientMain *plugin,
336         GradientWindow *gui,
337         int x,
338         int y)
339  : BC_PopupMenu(x, y, 100, to_text(plugin->config.shape), 1)
340 {
341         this->plugin = plugin;
342         this->gui = gui;
343 }
344 void GradientShape::create_objects()
345 {
346         add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
347         add_item(new BC_MenuItem(to_text(GradientConfig::RADIAL)));
348 }
349 char* GradientShape::to_text(int shape)
350 {
351         switch(shape)
352         {
353                 case GradientConfig::LINEAR:
354                         return _("Linear");
355                 default:
356                         return _("Radial");
357         }
358 }
359 int GradientShape::from_text(char *text)
360 {
361         if(!strcmp(text, to_text(GradientConfig::LINEAR)))
362                 return GradientConfig::LINEAR;
363         return GradientConfig::RADIAL;
364 }
365 int GradientShape::handle_event()
366 {
367         plugin->config.shape = from_text(get_text());
368         gui->update_shape();
369         plugin->send_configure_change();
370         return 1;
371 }
372
373
374
375
376 GradientCenterX::GradientCenterX(GradientMain *plugin, int x, int y)
377  : BC_FPot(x, y, plugin->config.center_x, 0, 100)
378 {
379         this->plugin = plugin;
380 }
381 int GradientCenterX::handle_event()
382 {
383         plugin->config.center_x = get_value();
384         plugin->send_configure_change();
385         return 1;
386 }
387
388
389
390 GradientCenterY::GradientCenterY(GradientMain *plugin, int x, int y)
391  : BC_FPot(x, y, plugin->config.center_y, 0, 100)
392 {
393         this->plugin = plugin;
394 }
395
396 int GradientCenterY::handle_event()
397 {
398         plugin->config.center_y = get_value();
399         plugin->send_configure_change();
400         return 1;
401 }
402
403
404
405
406 GradientAngle::GradientAngle(GradientMain *plugin, int x, int y)
407  : BC_FPot(x,
408         y,
409         plugin->config.angle,
410         -180,
411         180)
412 {
413         this->plugin = plugin;
414 }
415
416 int GradientAngle::handle_event()
417 {
418         plugin->config.angle = get_value();
419         plugin->send_configure_change();
420         return 1;
421 }
422
423
424 GradientRate::GradientRate(GradientMain *plugin, int x, int y)
425  : BC_PopupMenu(x,
426         y,
427         100,
428         to_text(plugin->config.rate),
429         1)
430 {
431         this->plugin = plugin;
432 }
433 void GradientRate::create_objects()
434 {
435         add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
436         add_item(new BC_MenuItem(to_text(GradientConfig::LOG)));
437         add_item(new BC_MenuItem(to_text(GradientConfig::SQUARE)));
438 }
439 char* GradientRate::to_text(int shape)
440 {
441         switch(shape)
442         {
443                 case GradientConfig::LINEAR:
444                         return _("Linear");
445                 case GradientConfig::LOG:
446                         return _("Log");
447                 default:
448                         return _("Square");
449         }
450 }
451 int GradientRate::from_text(char *text)
452 {
453         if(!strcmp(text, to_text(GradientConfig::LINEAR)))
454                 return GradientConfig::LINEAR;
455         if(!strcmp(text, to_text(GradientConfig::LOG)))
456                 return GradientConfig::LOG;
457         return GradientConfig::SQUARE;
458 }
459 int GradientRate::handle_event()
460 {
461         plugin->config.rate = from_text(get_text());
462         plugin->send_configure_change();
463         return 1;
464 }
465
466
467
468 GradientInRadius::GradientInRadius(GradientMain *plugin, int x, int y)
469  : BC_FSlider(x,
470         y,
471         0,
472         200,
473         200,
474         (float)0,
475         (float)100,
476         (float)plugin->config.in_radius)
477 {
478         this->plugin = plugin;
479 }
480
481 int GradientInRadius::handle_event()
482 {
483         plugin->config.in_radius = get_value();
484         plugin->send_configure_change();
485         return 1;
486 }
487
488
489 GradientOutRadius::GradientOutRadius(GradientMain *plugin, int x, int y)
490  : BC_FSlider(x,
491         y,
492         0,
493         200,
494         200,
495         (float)0,
496         (float)100,
497         (float)plugin->config.out_radius)
498 {
499         this->plugin = plugin;
500 }
501
502 int GradientOutRadius::handle_event()
503 {
504         plugin->config.out_radius = get_value();
505         plugin->send_configure_change();
506         return 1;
507 }
508
509 GradientInColorButton::GradientInColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
510  : BC_GenericButton(x, y, _("Inner color:"))
511 {
512         this->plugin = plugin;
513         this->window = window;
514 }
515
516 int GradientInColorButton::handle_event()
517 {
518         window->in_color_thread->start_window(
519                 plugin->config.get_in_color(),
520                 plugin->config.in_a);
521         return 1;
522 }
523
524
525 GradientOutColorButton::GradientOutColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
526  : BC_GenericButton(x, y, _("Outer color:"))
527 {
528         this->plugin = plugin;
529         this->window = window;
530 }
531
532 int GradientOutColorButton::handle_event()
533 {
534         window->out_color_thread->start_window(
535                 plugin->config.get_out_color(),
536                 plugin->config.out_a);
537         return 1;
538 }
539
540
541
542 GradientInColorThread::GradientInColorThread(GradientMain *plugin,
543         GradientWindow *window)
544  : ColorPicker(1, _("Inner color"))
545 {
546         this->plugin = plugin;
547         this->window = window;
548 }
549
550 int GradientInColorThread::handle_new_color(int output, int alpha)
551 {
552         plugin->config.in_r = (output & 0xff0000) >> 16;
553         plugin->config.in_g = (output & 0xff00) >> 8;
554         plugin->config.in_b = (output & 0xff);
555         plugin->config.in_a = alpha;
556
557         window->lock_window("GradientInColorThread::handle_new_color");
558         window->update_in_color();
559         window->flush();
560         window->unlock_window();
561         plugin->send_configure_change();
562 // printf("GradientInColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
563 // plugin->config.in_r,
564 // plugin->config.in_g,
565 // plugin->config.in_b,
566 // plugin->config.in_a,
567 // plugin->config.out_r,
568 // plugin->config.out_g,
569 // plugin->config.out_b,
570 // plugin->config.out_a);
571
572         return 1;
573 }
574
575
576
577 GradientOutColorThread::GradientOutColorThread(GradientMain *plugin,
578         GradientWindow *window)
579  : ColorPicker(1, _("Outer color"))
580 {
581         this->plugin = plugin;
582         this->window = window;
583 }
584
585 int GradientOutColorThread::handle_new_color(int output, int alpha)
586 {
587         plugin->config.out_r = (output & 0xff0000) >> 16;
588         plugin->config.out_g = (output & 0xff00) >> 8;
589         plugin->config.out_b = (output & 0xff);
590         plugin->config.out_a = alpha;
591         window->lock_window("GradientOutColorThread::handle_new_color");
592         window->update_out_color();
593         window->flush();
594         window->unlock_window();
595         plugin->send_configure_change();
596 // printf("GradientOutColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
597 // plugin->config.in_r,
598 // plugin->config.in_g,
599 // plugin->config.in_b,
600 // plugin->config.in_a,
601 // plugin->config.out_r,
602 // plugin->config.out_g,
603 // plugin->config.out_b,
604 // plugin->config.out_a);
605         return 1;
606 }
607
608
609
610
611
612
613
614
615
616
617
618
619 GradientMain::GradientMain(PluginServer *server)
620  : PluginVClient(server)
621 {
622
623         need_reconfigure = 1;
624         gradient = 0;
625         engine = 0;
626         overlayer = 0;
627 }
628
629 GradientMain::~GradientMain()
630 {
631
632
633         if(gradient) delete gradient;
634         if(engine) delete engine;
635         if(overlayer) delete overlayer;
636 }
637
638 const char* GradientMain::plugin_title() { return _("Gradient"); }
639 int GradientMain::is_realtime() { return 1; }
640
641
642 NEW_WINDOW_MACRO(GradientMain, GradientWindow)
643
644 LOAD_CONFIGURATION_MACRO(GradientMain, GradientConfig)
645
646 int GradientMain::is_synthesis()
647 {
648         return 1;
649 }
650
651
652 int GradientMain::process_buffer(VFrame *frame,
653         int64_t start_position,
654         double frame_rate)
655 {
656         this->input = frame;
657         this->output = frame;
658         need_reconfigure |= load_configuration();
659
660         int need_alpha = config.in_a != 0xff || config.out_a != 0xff;
661         if(need_alpha)
662                 read_frame(frame,
663                         0,
664                         start_position,
665                         frame_rate,
666                         get_use_opengl());
667         if(get_use_opengl()) return run_opengl();
668
669         int gradient_cmodel = input->get_color_model();
670         if(need_alpha && BC_CModels::components(gradient_cmodel) == 3)
671         {
672                 switch(gradient_cmodel)
673                 {
674                         case BC_RGB888:
675                                 gradient_cmodel = BC_RGBA8888;
676                                 break;
677                         case BC_RGB_FLOAT:
678                                 gradient_cmodel = BC_RGBA_FLOAT;
679                                 break;
680                         case BC_YUV888:
681                                 gradient_cmodel = BC_YUVA8888;
682                                 break;
683                 }
684         }
685
686         if(gradient && gradient->get_color_model() != gradient_cmodel)
687         {
688                 delete gradient;
689                 gradient = 0;
690         }
691
692         if(!gradient) gradient = new VFrame(0,
693                 -1,
694                 input->get_w(),
695                 input->get_h(),
696                 gradient_cmodel,
697                 -1);
698
699         if(!engine) engine = new GradientServer(this,
700                 get_project_smp() + 1,
701                 get_project_smp() + 1);
702         engine->process_packages();
703
704 // Use overlay routine in GradientServer if mismatched colormodels
705         if(gradient->get_color_model() == output->get_color_model())
706         {
707                 if(!overlayer) overlayer = new OverlayFrame(get_project_smp() + 1);
708                 overlayer->overlay(output,
709                         gradient,
710                         0,
711                         0,
712                         input->get_w(),
713                         input->get_h(),
714                         0,
715                         0,
716                         input->get_w(),
717                         input->get_h(),
718                         1.0,
719                         TRANSFER_NORMAL,
720                         NEAREST_NEIGHBOR);
721         }
722
723
724         return 0;
725 }
726
727
728 void GradientMain::update_gui()
729 {
730         if(thread)
731         {
732                 if(load_configuration())
733                 {
734                         ((GradientWindow*)thread->window)->lock_window("GradientMain::update_gui");
735                         ((GradientWindow*)thread->window)->rate->set_text(GradientRate::to_text(config.rate));
736                         ((GradientWindow*)thread->window)->in_radius->update(config.in_radius);
737                         ((GradientWindow*)thread->window)->out_radius->update(config.out_radius);
738                         ((GradientWindow*)thread->window)->shape->set_text(GradientShape::to_text(config.shape));
739                         if(((GradientWindow*)thread->window)->angle)
740                                 ((GradientWindow*)thread->window)->angle->update(config.angle);
741                         if(((GradientWindow*)thread->window)->center_x)
742                                 ((GradientWindow*)thread->window)->center_x->update(config.center_x);
743                         if(((GradientWindow*)thread->window)->center_y)
744                                 ((GradientWindow*)thread->window)->center_y->update(config.center_y);
745                         ((GradientWindow*)thread->window)->update_in_color();
746                         ((GradientWindow*)thread->window)->update_out_color();
747                         ((GradientWindow*)thread->window)->update_shape();
748                         ((GradientWindow*)thread->window)->unlock_window();
749                         ((GradientWindow*)thread->window)->in_color_thread->update_gui(config.get_in_color(), config.in_a);
750                         ((GradientWindow*)thread->window)->out_color_thread->update_gui(config.get_out_color(), config.out_a);
751                 }
752         }
753 }
754
755
756
757
758 void GradientMain::save_data(KeyFrame *keyframe)
759 {
760         FileXML output;
761
762 // cause data to be stored directly in text
763         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
764         output.tag.set_title("GRADIENT");
765
766         output.tag.set_property("ANGLE", config.angle);
767         output.tag.set_property("IN_RADIUS", config.in_radius);
768         output.tag.set_property("OUT_RADIUS", config.out_radius);
769         output.tag.set_property("IN_R", config.in_r);
770         output.tag.set_property("IN_G", config.in_g);
771         output.tag.set_property("IN_B", config.in_b);
772         output.tag.set_property("IN_A", config.in_a);
773         output.tag.set_property("OUT_R", config.out_r);
774         output.tag.set_property("OUT_G", config.out_g);
775         output.tag.set_property("OUT_B", config.out_b);
776         output.tag.set_property("OUT_A", config.out_a);
777         output.tag.set_property("SHAPE", config.shape);
778         output.tag.set_property("RATE", config.rate);
779         output.tag.set_property("CENTER_X", config.center_x);
780         output.tag.set_property("CENTER_Y", config.center_y);
781         output.append_tag();
782         output.tag.set_title("/GRADIENT");
783         output.append_tag();
784         output.append_newline();
785         output.terminate_string();
786 }
787
788 void GradientMain::read_data(KeyFrame *keyframe)
789 {
790         FileXML input;
791
792         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
793
794         int result = 0;
795
796         while(!result)
797         {
798                 result = input.read_tag();
799
800                 if(!result)
801                 {
802                         if(input.tag.title_is("GRADIENT"))
803                         {
804                                 config.angle = input.tag.get_property("ANGLE", config.angle);
805                                 config.rate = input.tag.get_property("RATE", config.rate);
806                                 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
807                                 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
808                                 config.in_r = input.tag.get_property("IN_R", config.in_r);
809                                 config.in_g = input.tag.get_property("IN_G", config.in_g);
810                                 config.in_b = input.tag.get_property("IN_B", config.in_b);
811                                 config.in_a = input.tag.get_property("IN_A", config.in_a);
812                                 config.out_r = input.tag.get_property("OUT_R", config.out_r);
813                                 config.out_g = input.tag.get_property("OUT_G", config.out_g);
814                                 config.out_b = input.tag.get_property("OUT_B", config.out_b);
815                                 config.out_a = input.tag.get_property("OUT_A", config.out_a);
816                                 config.shape = input.tag.get_property("SHAPE", config.shape);
817                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
818                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
819                         }
820                 }
821         }
822 }
823
824 int GradientMain::handle_opengl()
825 {
826 #ifdef HAVE_GL
827         const char *head_frag =
828                 "uniform sampler2D tex;\n"
829                 "uniform float half_w;\n"
830                 "uniform float half_h;\n"
831                 "uniform float center_x;\n"
832                 "uniform float center_y;\n"
833                 "uniform float half_gradient_size;\n"
834                 "uniform float sin_angle;\n"
835                 "uniform float cos_angle;\n"
836                 "uniform vec4 out_color;\n"
837                 "uniform vec4 in_color;\n"
838                 "uniform float in_radius;\n"
839                 "uniform float out_radius;\n"
840                 "uniform float radius_diff;\n"
841                 "\n"
842                 "void main()\n"
843                 "{\n"
844                 "       vec2 out_coord = gl_TexCoord[0].st;\n";
845
846         const char *linear_shape =
847                 "       vec2 in_coord = vec2(out_coord.x - half_w, half_h - out_coord.y);\n"
848                 "       float mag = half_gradient_size - \n"
849                 "               (in_coord.x * sin_angle + in_coord.y * cos_angle);\n";
850
851         const char *radial_shape =
852                 "       vec2 in_coord = vec2(out_coord.x - center_x, out_coord.y - center_y);\n"
853                 "       float mag = length(vec2(in_coord.x, in_coord.y));\n";
854
855 // No clamp function in NVidia
856         const char *linear_rate =
857                 "       mag = min(max(mag, in_radius), out_radius);\n"
858                 "       float opacity = (mag - in_radius) / radius_diff;\n";
859
860 // NVidia warns about exp, but exp is in the GLSL spec.
861         const char *log_rate =
862                 "       mag = max(mag, in_radius);\n"
863                 "       float opacity = 1.0 - \n"
864                 "               exp(1.0 * -(mag - in_radius) / radius_diff);\n";
865
866         const char *square_rate =
867                 "       mag = min(max(mag, in_radius), out_radius);\n"
868                 "       float opacity = pow((mag - in_radius) / radius_diff, 2.0);\n"
869                 "       opacity = min(opacity, 1.0);\n";
870
871         const char *tail_frag =
872                 "       vec4 color = mix(in_color, out_color, opacity);\n"
873                 "       vec4 bg_color = texture2D(tex, out_coord);\n"
874                 "       gl_FragColor.rgb = mix(bg_color.rgb, color.rgb, color.a);\n"
875                 "       gl_FragColor.a = max(bg_color.a, color.a);\n"
876                 "}\n";
877
878
879         const char *shader_stack[5] = { 0, 0, 0, 0, 0 };
880         shader_stack[0] = head_frag;
881
882         switch(config.shape)
883         {
884                 case GradientConfig::LINEAR:
885                         shader_stack[1] = linear_shape;
886                         break;
887
888                 default:
889                         shader_stack[1] = radial_shape;
890                         break;
891         }
892
893         switch(config.rate)
894         {
895                 case GradientConfig::LINEAR:
896                         shader_stack[2] = linear_rate;
897                         break;
898                 case GradientConfig::LOG:
899                         shader_stack[2] = log_rate;
900                         break;
901                 case GradientConfig::SQUARE:
902                         shader_stack[2] = square_rate;
903                         break;
904         }
905
906         shader_stack[3] = tail_frag;
907 // Force frame to create texture without copying to it if full alpha.
908         if(config.in_a >= 0xff &&
909                 config.out_a >= 0xff)
910                 get_output()->set_opengl_state(VFrame::TEXTURE);
911         get_output()->to_texture();
912         get_output()->enable_opengl();
913         get_output()->init_screen();
914         get_output()->bind_texture(0);
915
916         unsigned int frag = VFrame::make_shader(0,
917                 shader_stack[0],
918                 shader_stack[1],
919                 shader_stack[2],
920                 shader_stack[3],
921                 0);
922
923         if(frag)
924         {
925                 glUseProgram(frag);
926                 float w = get_output()->get_w();
927                 float h = get_output()->get_h();
928                 float texture_w = get_output()->get_texture_w();
929                 float texture_h = get_output()->get_texture_h();
930                 glUniform1i(glGetUniformLocation(frag, "tex"), 0);
931                 glUniform1f(glGetUniformLocation(frag, "half_w"), w / 2 / texture_w);
932                 glUniform1f(glGetUniformLocation(frag, "half_h"), h / 2 / texture_h);
933                 if(config.shape == GradientConfig::LINEAR)
934                 {
935                         glUniform1f(glGetUniformLocation(frag, "center_x"),
936                                 w / 2 / texture_w);
937                         glUniform1f(glGetUniformLocation(frag, "center_y"),
938                                 h / 2 / texture_h);
939                 }
940                 else
941                 {
942                         glUniform1f(glGetUniformLocation(frag, "center_x"),
943                                 (float)config.center_x * w / 100 / texture_w);
944                         glUniform1f(glGetUniformLocation(frag, "center_y"),
945                                 (float)config.center_y * h / 100 / texture_h);
946                 }
947                 float gradient_size = hypotf(w / texture_w, h / texture_h);
948                 glUniform1f(glGetUniformLocation(frag, "half_gradient_size"),
949                         gradient_size / 2);
950                 glUniform1f(glGetUniformLocation(frag, "sin_angle"),
951                         sin(config.angle * (M_PI / 180)));
952                 glUniform1f(glGetUniformLocation(frag, "cos_angle"),
953                         cos(config.angle * (M_PI / 180)));
954                 float in_radius = (float)config.in_radius / 100 * gradient_size;
955                 glUniform1f(glGetUniformLocation(frag, "in_radius"), in_radius);
956                 float out_radius = (float)config.out_radius / 100 * gradient_size;
957                 glUniform1f(glGetUniformLocation(frag, "out_radius"), out_radius);
958                 glUniform1f(glGetUniformLocation(frag, "radius_diff"),
959                         out_radius - in_radius);
960
961                 switch(get_output()->get_color_model())
962                 {
963                         case BC_YUV888:
964                         case BC_YUVA8888:
965                         {
966                                 float in1, in2, in3, in4;
967                                 float out1, out2, out3, out4;
968                                 YUV::rgb_to_yuv_f((float)config.in_r / 0xff,
969                                         (float)config.in_g / 0xff,
970                                         (float)config.in_b / 0xff,
971                                         in1,
972                                         in2,
973                                         in3);
974                                 in4 = (float)config.in_a / 0xff;
975                                 YUV::rgb_to_yuv_f((float)config.out_r / 0xff,
976                                         (float)config.out_g / 0xff,
977                                         (float)config.out_b / 0xff,
978                                         out1,
979                                         out2,
980                                         out3);
981                                 in2 += 0.5;
982                                 in3 += 0.5;
983                                 out2 += 0.5;
984                                 out3 += 0.5;
985                                 out4 = (float)config.out_a / 0xff;
986                                 glUniform4f(glGetUniformLocation(frag, "out_color"),
987                                         out1, out2, out3, out4);
988                                 glUniform4f(glGetUniformLocation(frag, "in_color"),
989                                         in1, in2, in3, in4);
990                                 break;
991                         }
992
993                         default:
994                                 glUniform4f(glGetUniformLocation(frag, "out_color"),
995                                         (float)config.out_r / 0xff,
996                                         (float)config.out_g / 0xff,
997                                         (float)config.out_b / 0xff,
998                                         (float)config.out_a / 0xff);
999                                 glUniform4f(glGetUniformLocation(frag, "in_color"),
1000                                         (float)config.in_r / 0xff,
1001                                         (float)config.in_g / 0xff,
1002                                         (float)config.in_b / 0xff,
1003                                         (float)config.in_a / 0xff);
1004                                 break;
1005                 }
1006         }
1007
1008         get_output()->draw_texture();
1009         glUseProgram(0);
1010         get_output()->set_opengl_state(VFrame::SCREEN);
1011
1012 #endif
1013         return 0;
1014 }
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 GradientPackage::GradientPackage()
1027  : LoadPackage()
1028 {
1029 }
1030
1031
1032
1033
1034 GradientUnit::GradientUnit(GradientServer *server, GradientMain *plugin)
1035  : LoadClient(server)
1036 {
1037         this->plugin = plugin;
1038         this->server = server;
1039 }
1040
1041
1042
1043
1044 static float calculate_opacity(float mag,
1045         float in_radius, float out_radius, int rate)
1046 {
1047         float opacity = 0.0;
1048         switch(rate)
1049         {
1050                 case GradientConfig::LINEAR:
1051                         if(mag < in_radius)
1052                                 opacity = 0.0;
1053                         else
1054                         if(mag >= out_radius)
1055                                 opacity = 1.0;
1056                         else
1057                                 opacity = (float)(mag - in_radius) / (out_radius - in_radius);
1058                         break;
1059
1060                 case GradientConfig::LOG:
1061                         if(mag < in_radius)
1062                                 opacity = 0;
1063                         else
1064 // Let this one decay beyond out_radius
1065                                 opacity = 1 - exp(1.0 * -(float)(mag - in_radius) /
1066                                         (out_radius - in_radius));
1067                         break;
1068
1069                 case GradientConfig::SQUARE:
1070                         if(mag < in_radius)
1071                                 opacity = 0.0;
1072                         else
1073                         if(mag >= out_radius)
1074                                 opacity = 1.0;
1075                         else
1076                                 opacity = powf((float)(mag - in_radius) /
1077                                         (out_radius - in_radius), 2.0);
1078                         break;
1079         }
1080         CLAMP(opacity, 0.0, 1.0);
1081         return opacity;
1082 }
1083
1084 #define CREATE_GRADIENT(type, temp, components, max) \
1085 { \
1086 /* Synthesize linear gradient for lookups */ \
1087  \
1088         r_table = malloc(sizeof(type) * gradient_size); \
1089         g_table = malloc(sizeof(type) * gradient_size); \
1090         b_table = malloc(sizeof(type) * gradient_size); \
1091         a_table = malloc(sizeof(type) * gradient_size); \
1092  \
1093         for(int i = 0; i < gradient_size; i++) \
1094         { \
1095                 float opacity = calculate_opacity(i, in_radius, out_radius, plugin->config.rate); \
1096                 float transparency; \
1097  \
1098                 transparency = 1.0 - opacity; \
1099                 ((type*)r_table)[i] = (type)(out1 * opacity + in1 * transparency); \
1100                 ((type*)g_table)[i] = (type)(out2 * opacity + in2 * transparency); \
1101                 ((type*)b_table)[i] = (type)(out3 * opacity + in3 * transparency); \
1102                 ((type*)a_table)[i] = (type)(out4 * opacity + in4 * transparency); \
1103         } \
1104  \
1105         for(int i = pkg->y1; i < pkg->y2; i++) \
1106         { \
1107                 type *gradient_row = (type*)plugin->gradient->get_rows()[i]; \
1108                 type *out_row = (type*)plugin->get_output()->get_rows()[i]; \
1109  \
1110                 switch(plugin->config.shape) \
1111                 { \
1112                         case GradientConfig::LINEAR: \
1113                                 for(int j = 0; j < w; j++) \
1114                                 { \
1115                                         int x = j - half_w; \
1116                                         int y = -(i - half_h); \
1117                  \
1118 /* Rotate by effect angle */ \
1119                                         int mag = (int)(gradient_size / 2 - \
1120                                                 (x * sin_angle + y * cos_angle) + \
1121                                                 0.5); \
1122                  \
1123 /* Get gradient value from these coords */ \
1124                  \
1125                                         if(sizeof(type) == 4) \
1126                                         { \
1127                                                 float opacity = calculate_opacity(mag,  \
1128                                                         in_radius,  \
1129                                                         out_radius, \
1130                                                         plugin->config.rate); \
1131                                                 float transparency = 1.0 - opacity; \
1132                                                 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
1133                                                 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
1134                                                 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
1135                                                 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
1136                                         } \
1137                                         else \
1138                                         if(mag < 0) \
1139                                         { \
1140                                                 gradient_row[0] = out1; \
1141                                                 gradient_row[1] = out2; \
1142                                                 gradient_row[2] = out3; \
1143                                                 if(components == 4) gradient_row[3] = out4; \
1144                                         } \
1145                                         else \
1146                                         if(mag >= gradient_size) \
1147                                         { \
1148                                                 gradient_row[0] = in1; \
1149                                                 gradient_row[1] = in2; \
1150                                                 gradient_row[2] = in3; \
1151                                                 if(components == 4) gradient_row[3] = in4; \
1152                                         } \
1153                                         else \
1154                                         { \
1155                                                 gradient_row[0] = ((type*)r_table)[mag]; \
1156                                                 gradient_row[1] = ((type*)g_table)[mag]; \
1157                                                 gradient_row[2] = ((type*)b_table)[mag]; \
1158                                                 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
1159                                         } \
1160  \
1161 /* Overlay mixed colormodels onto output */ \
1162                                         if(gradient_cmodel != output_cmodel) \
1163                                         { \
1164                                                 temp opacity = gradient_row[3]; \
1165                                                 temp transparency = max - opacity; \
1166                                                 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
1167                                                 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
1168                                                 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
1169                                                 out_row += 3; \
1170                                         } \
1171  \
1172                                         gradient_row += components; \
1173                                 } \
1174                                 break; \
1175  \
1176                         case GradientConfig::RADIAL: \
1177                                 for(int j = 0; j < w; j++) \
1178                                 { \
1179                                         double x = j - center_x; \
1180                                         double y = i - center_y; \
1181                                         double magnitude = hypot(x, y); \
1182                                         int mag = (int)magnitude; \
1183                                         if(sizeof(type) == 4) \
1184                                         { \
1185                                                 float opacity = calculate_opacity(mag,  \
1186                                                         in_radius,  \
1187                                                         out_radius, \
1188                                                         plugin->config.rate); \
1189                                                 float transparency = 1.0 - opacity; \
1190                                                 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
1191                                                 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
1192                                                 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
1193                                                 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
1194                                         } \
1195                                         else \
1196                                         { \
1197                                                 gradient_row[0] = ((type*)r_table)[mag]; \
1198                                                 gradient_row[1] = ((type*)g_table)[mag]; \
1199                                                 gradient_row[2] = ((type*)b_table)[mag]; \
1200                                                 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
1201                                         } \
1202  \
1203 /* Overlay mixed colormodels onto output */ \
1204                                         if(gradient_cmodel != output_cmodel) \
1205                                         { \
1206                                                 temp opacity = gradient_row[3]; \
1207                                                 temp transparency = max - opacity; \
1208                                                 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
1209                                                 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
1210                                                 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
1211                                                 out_row += 3; \
1212                                         } \
1213  \
1214                                         gradient_row += components; \
1215                                 } \
1216                                 break; \
1217                 } \
1218         } \
1219 }
1220
1221 void GradientUnit::process_package(LoadPackage *package)
1222 {
1223         GradientPackage *pkg = (GradientPackage*)package;
1224         int h = plugin->input->get_h();
1225         int w = plugin->input->get_w();
1226         int half_w = w / 2;
1227         int half_h = h / 2;
1228         int gradient_size = (int)(ceil(hypot(w, h)));
1229         int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
1230         int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
1231         double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1232         double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1233         double center_x = plugin->config.center_x * w / 100;
1234         double center_y = plugin->config.center_y * h / 100;
1235         void *r_table = 0;
1236         void *g_table = 0;
1237         void *b_table = 0;
1238         void *a_table = 0;
1239         int gradient_cmodel = plugin->gradient->get_color_model();
1240         int output_cmodel = plugin->get_output()->get_color_model();
1241
1242         if(in_radius > out_radius)
1243         {
1244             in_radius ^= out_radius;
1245             out_radius ^= in_radius;
1246             in_radius ^= out_radius;
1247         }
1248
1249
1250         switch(gradient_cmodel)
1251         {
1252                 case BC_RGB888:
1253                 {
1254                         int in1 = plugin->config.in_r;
1255                         int in2 = plugin->config.in_g;
1256                         int in3 = plugin->config.in_b;
1257                         int in4 = plugin->config.in_a;
1258                         int out1 = plugin->config.out_r;
1259                         int out2 = plugin->config.out_g;
1260                         int out3 = plugin->config.out_b;
1261                         int out4 = plugin->config.out_a;
1262                         CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1263                         break;
1264                 }
1265
1266                 case BC_RGBA8888:
1267                 {
1268                         int in1 = plugin->config.in_r;
1269                         int in2 = plugin->config.in_g;
1270                         int in3 = plugin->config.in_b;
1271                         int in4 = plugin->config.in_a;
1272                         int out1 = plugin->config.out_r;
1273                         int out2 = plugin->config.out_g;
1274                         int out3 = plugin->config.out_b;
1275                         int out4 = plugin->config.out_a;
1276                         CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1277                         break;
1278                 }
1279
1280                 case BC_RGB_FLOAT:
1281                 {
1282                         float in1 = (float)plugin->config.in_r / 0xff;
1283                         float in2 = (float)plugin->config.in_g / 0xff;
1284                         float in3 = (float)plugin->config.in_b / 0xff;
1285                         float in4 = (float)plugin->config.in_a / 0xff;
1286                         float out1 = (float)plugin->config.out_r / 0xff;
1287                         float out2 = (float)plugin->config.out_g / 0xff;
1288                         float out3 = (float)plugin->config.out_b / 0xff;
1289                         float out4 = (float)plugin->config.out_a / 0xff;
1290                         CREATE_GRADIENT(float, float, 3, 1.0)
1291                         break;
1292                 }
1293
1294                 case BC_RGBA_FLOAT:
1295                 {
1296                         float in1 = (float)plugin->config.in_r / 0xff;
1297                         float in2 = (float)plugin->config.in_g / 0xff;
1298                         float in3 = (float)plugin->config.in_b / 0xff;
1299                         float in4 = (float)plugin->config.in_a / 0xff;
1300                         float out1 = (float)plugin->config.out_r / 0xff;
1301                         float out2 = (float)plugin->config.out_g / 0xff;
1302                         float out3 = (float)plugin->config.out_b / 0xff;
1303                         float out4 = (float)plugin->config.out_a / 0xff;
1304                         CREATE_GRADIENT(float, float, 4, 1.0)
1305                         break;
1306                 }
1307
1308                 case BC_YUV888:
1309                 {
1310                         int in1, in2, in3, in4;
1311                         int out1, out2, out3, out4;
1312                         yuv.rgb_to_yuv_8(plugin->config.in_r,
1313                                 plugin->config.in_g,
1314                                 plugin->config.in_b,
1315                                 in1,
1316                                 in2,
1317                                 in3);
1318                         in4 = plugin->config.in_a;
1319                         yuv.rgb_to_yuv_8(plugin->config.out_r,
1320                                 plugin->config.out_g,
1321                                 plugin->config.out_b,
1322                                 out1,
1323                                 out2,
1324                                 out3);
1325                         out4 = plugin->config.out_a;
1326                         CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1327                         break;
1328                 }
1329
1330                 case BC_YUVA8888:
1331                 {
1332                         int in1, in2, in3, in4;
1333                         int out1, out2, out3, out4;
1334                         yuv.rgb_to_yuv_8(plugin->config.in_r,
1335                                 plugin->config.in_g,
1336                                 plugin->config.in_b,
1337                                 in1,
1338                                 in2,
1339                                 in3);
1340                         in4 = plugin->config.in_a;
1341                         yuv.rgb_to_yuv_8(plugin->config.out_r,
1342                                 plugin->config.out_g,
1343                                 plugin->config.out_b,
1344                                 out1,
1345                                 out2,
1346                                 out3);
1347                         out4 = plugin->config.out_a;
1348                         CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1349                         break;
1350                 }
1351         }
1352
1353         if(r_table) free(r_table);
1354         if(g_table) free(g_table);
1355         if(b_table) free(b_table);
1356         if(a_table) free(a_table);
1357 }
1358
1359
1360
1361
1362
1363
1364 GradientServer::GradientServer(GradientMain *plugin,
1365         int total_clients,
1366         int total_packages)
1367  : LoadServer(total_clients, total_packages)
1368 {
1369         this->plugin = plugin;
1370 }
1371
1372 void GradientServer::init_packages()
1373 {
1374         for(int i = 0; i < get_total_packages(); i++)
1375         {
1376                 GradientPackage *package = (GradientPackage*)get_package(i);
1377                 package->y1 = plugin->input->get_h() *
1378                         i /
1379                         get_total_packages();
1380                 package->y2 = plugin->input->get_h() *
1381                         (i + 1) /
1382                         get_total_packages();
1383         }
1384 }
1385
1386 LoadClient* GradientServer::new_client()
1387 {
1388         return new GradientUnit(this, plugin);
1389 }
1390
1391 LoadPackage* GradientServer::new_package()
1392 {
1393         return new GradientPackage;
1394 }
1395
1396
1397
1398
1399