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