Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / gradient / gradient.C
blob9e3ef8400bef29a344856ef4af234cc10d0b75b6
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
5 #include "bcdisplayinfo.h"
6 #include "clip.h"
7 #include "bchash.h"
8 #include "filexml.h"
9 #include "gradient.h"
10 #include "keyframe.h"
11 #include "language.h"
12 #include "overlayframe.h"
13 #include "picon_png.h"
14 #include "vframe.h"
19 REGISTER_PLUGIN(GradientMain)
26 GradientConfig::GradientConfig()
28         angle = 0;
29         in_radius = 0;
30         out_radius = 100;
31         in_r = 0xff;
32         in_g = 0xff;
33         in_b = 0xff;
34         in_a = 0xff;
35         out_r = 0x0;
36         out_g = 0x0;
37         out_b = 0x0;
38         out_a = 0x0;
39         shape = GradientConfig::LINEAR;
40         rate = GradientConfig::LINEAR;
41         center_x = 50;
42         center_y = 50;
45 int GradientConfig::equivalent(GradientConfig &that)
47         return (EQUIV(angle, that.angle) &&
48                 EQUIV(in_radius, that.in_radius) &&
49                 EQUIV(out_radius, that.out_radius) &&
50                 in_r == that.in_r &&
51                 in_g == that.in_g &&
52                 in_b == that.in_b &&
53                 in_a == that.in_a &&
54                 out_r == that.out_r &&
55                 out_g == that.out_g &&
56                 out_b == that.out_b &&
57                 out_a == that.out_a &&
58                 shape == that.shape &&
59                 rate == that.rate &&
60                 EQUIV(center_x, that.center_x) &&
61                 EQUIV(center_y, that.center_y));
64 void GradientConfig::copy_from(GradientConfig &that)
66         angle = that.angle;
67         in_radius = that.in_radius;
68         out_radius = that.out_radius;
69         in_r = that.in_r;
70         in_g = that.in_g;
71         in_b = that.in_b;
72         in_a = that.in_a;
73         out_r = that.out_r;
74         out_g = that.out_g;
75         out_b = that.out_b;
76         out_a = that.out_a;
77         shape = that.shape;
78         rate = that.rate;
79         center_x = that.center_x;
80         center_y = that.center_y;
83 void GradientConfig::interpolate(GradientConfig &prev, 
84         GradientConfig &next, 
85         long prev_frame, 
86         long next_frame, 
87         long current_frame)
89         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
90         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
93         this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale);
94         this->in_radius = (int)(prev.in_radius * prev_scale + next.in_radius * next_scale);
95         this->out_radius = (int)(prev.out_radius * prev_scale + next.out_radius * next_scale);
96         in_r = (int)(prev.in_r * prev_scale + next.in_r * next_scale);
97         in_g = (int)(prev.in_g * prev_scale + next.in_g * next_scale);
98         in_b = (int)(prev.in_b * prev_scale + next.in_b * next_scale);
99         in_a = (int)(prev.in_a * prev_scale + next.in_a * next_scale);
100         out_r = (int)(prev.out_r * prev_scale + next.out_r * next_scale);
101         out_g = (int)(prev.out_g * prev_scale + next.out_g * next_scale);
102         out_b = (int)(prev.out_b * prev_scale + next.out_b * next_scale);
103         out_a = (int)(prev.out_a * prev_scale + next.out_a * next_scale);
104         shape = prev.shape;
105         rate = prev.rate;
106         center_x = prev.center_x * prev_scale + next.center_x * next_scale;
107         center_y = prev.center_y * prev_scale + next.center_y * next_scale;
110 int GradientConfig::get_in_color()
112         int result = (in_r << 16) | (in_g << 8) | (in_b);
113         return result;
116 int GradientConfig::get_out_color()
118         int result = (out_r << 16) | (out_g << 8) | (out_b);
119         return result;
130 PLUGIN_THREAD_OBJECT(GradientMain, GradientThread, GradientWindow)
133 #define COLOR_W 100
134 #define COLOR_H 30
136 GradientWindow::GradientWindow(GradientMain *plugin, int x, int y)
137  : BC_Window(plugin->gui_string, 
138         x,
139         y,
140         350, 
141         290, 
142         350, 
143         290, 
144         0, 
145         1)
147         this->plugin = plugin;
148         angle = 0;
149         angle_title = 0;
150         center_x = 0;
151         center_y = 0;
152         center_x_title = 0;
153         center_y_title = 0;
156 GradientWindow::~GradientWindow()
158         delete in_color_thread;
159         delete out_color_thread;
162 int GradientWindow::create_objects()
164         int x = 10, y = 10;
165         BC_Title *title;
167         add_subwindow(title = new BC_Title(x, y, _("Shape:")));
168         add_subwindow(shape = new GradientShape(plugin, 
169                 this, 
170                 x + title->get_w() + 10, 
171                 y));
172         shape->create_objects();
173         y += 40;
174         shape_x = x;
175         shape_y = y;
176         y += 40;
177         add_subwindow(title = new BC_Title(x, y, _("Rate:")));
178         add_subwindow(rate = new GradientRate(plugin,
179                 x + title->get_w() + 10,
180                 y));
181         rate->create_objects();
182         y += 40;
183         add_subwindow(title = new BC_Title(x, y, _("Inner radius:")));
184         add_subwindow(in_radius = new GradientInRadius(plugin, x + title->get_w() + 10, y));
185         y += 30;
186         add_subwindow(title = new BC_Title(x, y, _("Outer radius:")));
187         add_subwindow(out_radius = new GradientOutRadius(plugin, x + title->get_w() + 10, y));
188         y += 35;
189         add_subwindow(in_color = new GradientInColorButton(plugin, this, x, y));
190         in_color_x = x + in_color->get_w() + 10;
191         in_color_y = y;
192         y += 35;
193         add_subwindow(out_color = new GradientOutColorButton(plugin, this, x, y));
194         out_color_x = x + out_color->get_w() + 10;
195         out_color_y = y;
196         in_color_thread = new GradientInColorThread(plugin, this);
197         out_color_thread = new GradientOutColorThread(plugin, this);
198         update_in_color();
199         update_out_color();
200         update_shape();
202         show_window();
203         flush();
204         return 0;
207 void GradientWindow::update_shape()
209         int x = shape_x, y = shape_y;
211         if(plugin->config.shape == GradientConfig::LINEAR)
212         {
213                 delete center_x_title;
214                 delete center_y_title;
215                 delete center_x;
216                 delete center_y;
217                 center_x_title = 0;
218                 center_y_title = 0;
219                 center_x = 0;
220                 center_y = 0;
222                 if(!angle)
223                 {
224                         add_subwindow(angle_title = new BC_Title(x, y, _("Angle:")));
225                         add_subwindow(angle = new GradientAngle(plugin, x + angle_title->get_w() + 10, y));
226                 }
227         }
228         else
229         {
230                 delete angle_title;
231                 delete angle;
232                 angle_title = 0;
233                 angle = 0;
234                 if(!center_x)
235                 {
236                         add_subwindow(center_x_title = new BC_Title(x, y, _("Center X:")));
237                         add_subwindow(center_x = new GradientCenterX(plugin,
238                                 x + center_x_title->get_w() + 10,
239                                 y));
240                         x += center_x_title->get_w() + 10 + center_x->get_w() + 10;
241                         add_subwindow(center_y_title = new BC_Title(x, y, _("Center Y:")));
242                         add_subwindow(center_y = new GradientCenterY(plugin,
243                                 x + center_y_title->get_w() + 10,
244                                 y));
245                 }
246         }
249 int GradientWindow::close_event()
251 // Set result to 1 to indicate a plugin side close
252         set_done(1);
253         return 1;
256 void GradientWindow::update_in_color()
258 //printf("GradientWindow::update_in_color 1 %08x\n", plugin->config.get_in_color());
259         set_color(plugin->config.get_in_color());
260         draw_box(in_color_x, in_color_y, COLOR_W, COLOR_H);
261         flash(in_color_x, in_color_y, COLOR_W, COLOR_H);
264 void GradientWindow::update_out_color()
266 //printf("GradientWindow::update_out_color 1 %08x\n", plugin->config.get_in_color());
267         set_color(plugin->config.get_out_color());
268         draw_box(out_color_x, out_color_y, COLOR_W, COLOR_H);
269         flash(out_color_x, out_color_y, COLOR_W, COLOR_H);
280 GradientShape::GradientShape(GradientMain *plugin, 
281         GradientWindow *gui, 
282         int x, 
283         int y)
284  : BC_PopupMenu(x, y, 100, to_text(plugin->config.shape), 1)
286         this->plugin = plugin;
287         this->gui = gui;
289 void GradientShape::create_objects()
291         add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
292         add_item(new BC_MenuItem(to_text(GradientConfig::RADIAL)));
294 char* GradientShape::to_text(int shape)
296         switch(shape)
297         {
298                 case GradientConfig::LINEAR:
299                         return _("Linear");
300                 default:
301                         return _("Radial");
302         }
304 int GradientShape::from_text(char *text)
306         if(!strcmp(text, to_text(GradientConfig::LINEAR))) 
307                 return GradientConfig::LINEAR;
308         return GradientConfig::RADIAL;
310 int GradientShape::handle_event()
312         plugin->config.shape = from_text(get_text());
313         gui->update_shape();
314         plugin->send_configure_change();
320 GradientCenterX::GradientCenterX(GradientMain *plugin, int x, int y)
321  : BC_FPot(x, y, plugin->config.center_x, 0, 100)
323         this->plugin = plugin;
325 int GradientCenterX::handle_event()
327         plugin->config.center_x = get_value();
328         plugin->send_configure_change();
329         return 1;
334 GradientCenterY::GradientCenterY(GradientMain *plugin, int x, int y)
335  : BC_FPot(x, y, plugin->config.center_y, 0, 100)
337         this->plugin = plugin;
340 int GradientCenterY::handle_event()
342         plugin->config.center_y = get_value();
343         plugin->send_configure_change();
344         return 1;
350 GradientAngle::GradientAngle(GradientMain *plugin, int x, int y)
351  : BC_FPot(x,
352         y,
353         plugin->config.angle,
354         -180,
355         180)
357         this->plugin = plugin;
360 int GradientAngle::handle_event()
362         plugin->config.angle = get_value();
363         plugin->send_configure_change();
364         return 1;
368 GradientRate::GradientRate(GradientMain *plugin, int x, int y)
369  : BC_PopupMenu(x,
370         y,
371         100,
372         to_text(plugin->config.rate),
373         1)
375         this->plugin = plugin;
377 void GradientRate::create_objects()
379         add_item(new BC_MenuItem(to_text(GradientConfig::LINEAR)));
380         add_item(new BC_MenuItem(to_text(GradientConfig::LOG)));
381         add_item(new BC_MenuItem(to_text(GradientConfig::SQUARE)));
383 char* GradientRate::to_text(int shape)
385         switch(shape)
386         {
387                 case GradientConfig::LINEAR:
388                         return _("Linear");
389                 case GradientConfig::LOG:
390                         return _("Log");
391                 default:
392                         return _("Square");
393         }
395 int GradientRate::from_text(char *text)
397         if(!strcmp(text, to_text(GradientConfig::LINEAR))) 
398                 return GradientConfig::LINEAR;
399         if(!strcmp(text, to_text(GradientConfig::LOG)))
400                 return GradientConfig::LOG;
401         return GradientConfig::SQUARE;
403 int GradientRate::handle_event()
405         plugin->config.rate = from_text(get_text());
406         plugin->send_configure_change();
407         return 1;
412 GradientInRadius::GradientInRadius(GradientMain *plugin, int x, int y)
413  : BC_FSlider(x,
414         y,
415         0,
416         200,
417         200,
418         (float)0,
419         (float)100,
420         (float)plugin->config.in_radius)
422         this->plugin = plugin;
425 int GradientInRadius::handle_event()
427         plugin->config.in_radius = get_value();
428         plugin->send_configure_change();
429         return 1;
433 GradientOutRadius::GradientOutRadius(GradientMain *plugin, int x, int y)
434  : BC_FSlider(x,
435         y,
436         0,
437         200,
438         200,
439         (float)0,
440         (float)100,
441         (float)plugin->config.out_radius)
443         this->plugin = plugin;
446 int GradientOutRadius::handle_event()
448         plugin->config.out_radius = get_value();
449         plugin->send_configure_change();
450         return 1;
453 GradientInColorButton::GradientInColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
454  : BC_GenericButton(x, y, _("Inner color:"))
456         this->plugin = plugin;
457         this->window = window;
460 int GradientInColorButton::handle_event()
462         window->in_color_thread->start_window(
463                 plugin->config.get_in_color(),
464                 plugin->config.in_a);
465         return 1;
469 GradientOutColorButton::GradientOutColorButton(GradientMain *plugin, GradientWindow *window, int x, int y)
470  : BC_GenericButton(x, y, _("Outer color:"))
472         this->plugin = plugin;
473         this->window = window;
476 int GradientOutColorButton::handle_event()
478         window->out_color_thread->start_window(
479                 plugin->config.get_out_color(),
480                 plugin->config.out_a);
481         return 1;
486 GradientInColorThread::GradientInColorThread(GradientMain *plugin, 
487         GradientWindow *window)
488  : ColorThread(1, _("Inner color"))
490         this->plugin = plugin;
491         this->window = window;
494 int GradientInColorThread::handle_new_color(int output, int alpha)
496         plugin->config.in_r = (output & 0xff0000) >> 16;
497         plugin->config.in_g = (output & 0xff00) >> 8;
498         plugin->config.in_b = (output & 0xff);
499         plugin->config.in_a = alpha;
500         window->update_in_color();
501         window->flush();
502         plugin->send_configure_change();
503 // printf("GradientInColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
504 // plugin->config.in_r,
505 // plugin->config.in_g,
506 // plugin->config.in_b,
507 // plugin->config.in_a,
508 // plugin->config.out_r,
509 // plugin->config.out_g,
510 // plugin->config.out_b,
511 // plugin->config.out_a);
513         return 1;
518 GradientOutColorThread::GradientOutColorThread(GradientMain *plugin, 
519         GradientWindow *window)
520  : ColorThread(1, _("Outer color"))
522         this->plugin = plugin;
523         this->window = window;
526 int GradientOutColorThread::handle_new_color(int output, int alpha)
528         plugin->config.out_r = (output & 0xff0000) >> 16;
529         plugin->config.out_g = (output & 0xff00) >> 8;
530         plugin->config.out_b = (output & 0xff);
531         plugin->config.out_a = alpha;
532         window->update_out_color();
533         window->flush();
534         plugin->send_configure_change();
535 // printf("GradientOutColorThread::handle_event 1 %d %d %d %d %d %d %d %d\n",
536 // plugin->config.in_r,
537 // plugin->config.in_g,
538 // plugin->config.in_b,
539 // plugin->config.in_a,
540 // plugin->config.out_r,
541 // plugin->config.out_g,
542 // plugin->config.out_b,
543 // plugin->config.out_a);
544         return 1;
558 GradientMain::GradientMain(PluginServer *server)
559  : PluginVClient(server)
561         PLUGIN_CONSTRUCTOR_MACRO
562         need_reconfigure = 1;
563         gradient = 0;
564         engine = 0;
565         overlayer = 0;
568 GradientMain::~GradientMain()
570         PLUGIN_DESTRUCTOR_MACRO
572         if(gradient) delete gradient;
573         if(engine) delete engine;
574         if(overlayer) delete overlayer;
577 char* GradientMain::plugin_title() { return N_("Gradient"); }
578 int GradientMain::is_realtime() { return 1; }
581 NEW_PICON_MACRO(GradientMain)
583 SHOW_GUI_MACRO(GradientMain, GradientThread)
585 SET_STRING_MACRO(GradientMain)
587 RAISE_WINDOW_MACRO(GradientMain)
589 LOAD_CONFIGURATION_MACRO(GradientMain, GradientConfig)
591 int GradientMain::is_synthesis()
593         return 1;
597 int GradientMain::process_buffer(VFrame *frame,
598         int64_t start_position,
599         double frame_rate)
601         this->input = frame;
602         this->output = frame;
603         need_reconfigure |= load_configuration();
605         int need_alpha = config.in_a != 0xff || config.out_a != 0xff;
606         if(need_alpha)
607                 read_frame(frame, 
608                         0, 
609                         start_position, 
610                         frame_rate,
611                         get_use_opengl());
612         if(get_use_opengl()) return run_opengl();
614         int gradient_cmodel = input->get_color_model();
615         if(need_alpha && cmodel_components(gradient_cmodel) == 3)
616         {
617                 switch(gradient_cmodel)
618                 {
619                         case BC_RGB888:
620                                 gradient_cmodel = BC_RGBA8888;
621                                 break;
622                         case BC_RGB_FLOAT:
623                                 gradient_cmodel = BC_RGBA_FLOAT;
624                                 break;
625                         case BC_YUV888:
626                                 gradient_cmodel = BC_YUVA8888;
627                                 break;
628                 }
629         }
631         if(gradient && gradient->get_color_model() != gradient_cmodel)
632         {
633                 delete gradient;
634                 gradient = 0;
635         }
637         if(!gradient) gradient = new VFrame(0, 
638                 input->get_w(),
639                 input->get_h(),
640                 gradient_cmodel);
642         if(!engine) engine = new GradientServer(this,
643                 get_project_smp() + 1,
644                 get_project_smp() + 1);
645         engine->process_packages();
647 // Use overlay routine in GradientServer if mismatched colormodels
648         if(gradient->get_color_model() == output->get_color_model())
649         {
650                 if(!overlayer) overlayer = new OverlayFrame(get_project_smp() + 1);
651                 overlayer->overlay(output, 
652                         gradient,
653                         0, 
654                         0, 
655                         input->get_w(), 
656                         input->get_h(),
657                         0, 
658                         0, 
659                         input->get_w(), 
660                         input->get_h(), 
661                         1.0, 
662                         TRANSFER_NORMAL,
663                         NEAREST_NEIGHBOR);
664         }
667         return 0;
671 void GradientMain::update_gui()
673         if(thread)
674         {
675                 if(load_configuration())
676                 {
677                         thread->window->lock_window("GradientMain::update_gui");
678                         thread->window->rate->set_text(GradientRate::to_text(config.rate));
679                         thread->window->in_radius->update(config.in_radius);
680                         thread->window->out_radius->update(config.out_radius);
681                         thread->window->shape->set_text(GradientShape::to_text(config.shape));
682                         if(thread->window->angle)
683                                 thread->window->angle->update(config.angle);
684                         if(thread->window->center_x)
685                                 thread->window->center_x->update(config.center_x);
686                         if(thread->window->center_y)
687                                 thread->window->center_y->update(config.center_y);
688                         thread->window->update_in_color();
689                         thread->window->update_out_color();
690                         thread->window->update_shape();
691                         thread->window->unlock_window();
692                         thread->window->in_color_thread->update_gui(config.get_in_color(), config.in_a);
693                         thread->window->out_color_thread->update_gui(config.get_out_color(), config.out_a);
694                 }
695         }
699 int GradientMain::load_defaults()
701         char directory[1024], string[1024];
702 // set the default directory
703         sprintf(directory, "%sgradient.rc", BCASTDIR);
705 // load the defaults
706         defaults = new BC_Hash(directory);
707         defaults->load();
709 // printf("GradientMain::load_defaults %d %d %d %d\n",
710 // config.out_r,
711 // config.out_g,
712 // config.out_b,
713 // config.out_a);
714         config.angle = defaults->get("ANGLE", config.angle);
715         config.in_radius = defaults->get("IN_RADIUS", config.in_radius);
716         config.out_radius = defaults->get("OUT_RADIUS", config.out_radius);
717         config.in_r = defaults->get("IN_R", config.in_r);
718         config.in_g = defaults->get("IN_G", config.in_g);
719         config.in_b = defaults->get("IN_B", config.in_b);
720         config.in_a = defaults->get("IN_A", config.in_a);
721         config.out_r = defaults->get("OUT_R", config.out_r);
722         config.out_g = defaults->get("OUT_G", config.out_g);
723         config.out_b = defaults->get("OUT_B", config.out_b);
724         config.out_a = defaults->get("OUT_A", config.out_a);
725         config.shape = defaults->get("SHAPE", config.shape);
726         config.rate = defaults->get("RATE", config.rate);
727         config.center_x = defaults->get("CENTER_X", config.center_x);
728         config.center_y = defaults->get("CENTER_Y", config.center_y);
729         return 0;
733 int GradientMain::save_defaults()
735         defaults->update("ANGLE", config.angle);
736         defaults->update("IN_RADIUS", config.in_radius);
737         defaults->update("OUT_RADIUS", config.out_radius);
738         defaults->update("IN_R", config.in_r);
739         defaults->update("IN_G", config.in_g);
740         defaults->update("IN_B", config.in_b);
741         defaults->update("IN_A", config.in_a);
742         defaults->update("OUT_R", config.out_r);
743         defaults->update("OUT_G", config.out_g);
744         defaults->update("OUT_B", config.out_b);
745         defaults->update("OUT_A", config.out_a);
746         defaults->update("RATE", config.rate);
747         defaults->update("SHAPE", config.shape);
748         defaults->update("CENTER_X", config.center_x);
749         defaults->update("CENTER_Y", config.center_y);
750         defaults->save();
751         return 0;
756 void GradientMain::save_data(KeyFrame *keyframe)
758         FileXML output;
760 // cause data to be stored directly in text
761         output.set_shared_string(keyframe->data, MESSAGESIZE);
762         output.tag.set_title("GRADIENT");
764         output.tag.set_property("ANGLE", config.angle);
765         output.tag.set_property("IN_RADIUS", config.in_radius);
766         output.tag.set_property("OUT_RADIUS", config.out_radius);
767         output.tag.set_property("IN_R", config.in_r);
768         output.tag.set_property("IN_G", config.in_g);
769         output.tag.set_property("IN_B", config.in_b);
770         output.tag.set_property("IN_A", config.in_a);
771         output.tag.set_property("OUT_R", config.out_r);
772         output.tag.set_property("OUT_G", config.out_g);
773         output.tag.set_property("OUT_B", config.out_b);
774         output.tag.set_property("OUT_A", config.out_a);
775         output.tag.set_property("SHAPE", config.shape);
776         output.tag.set_property("RATE", config.rate);
777         output.tag.set_property("CENTER_X", config.center_x);
778         output.tag.set_property("CENTER_Y", config.center_y);
779         output.append_tag();
780         output.terminate_string();
783 void GradientMain::read_data(KeyFrame *keyframe)
785         FileXML input;
787         input.set_shared_string(keyframe->data, strlen(keyframe->data));
789         int result = 0;
791         while(!result)
792         {
793                 result = input.read_tag();
795                 if(!result)
796                 {
797                         if(input.tag.title_is("GRADIENT"))
798                         {
799                                 config.angle = input.tag.get_property("ANGLE", config.angle);
800                                 config.rate = input.tag.get_property("RATE", config.rate);
801                                 config.in_radius = input.tag.get_property("IN_RADIUS", config.in_radius);
802                                 config.out_radius = input.tag.get_property("OUT_RADIUS", config.out_radius);
803                                 config.in_r = input.tag.get_property("IN_R", config.in_r);
804                                 config.in_g = input.tag.get_property("IN_G", config.in_g);
805                                 config.in_b = input.tag.get_property("IN_B", config.in_b);
806                                 config.in_a = input.tag.get_property("IN_A", config.in_a);
807                                 config.out_r = input.tag.get_property("OUT_R", config.out_r);
808                                 config.out_g = input.tag.get_property("OUT_G", config.out_g);
809                                 config.out_b = input.tag.get_property("OUT_B", config.out_b);
810                                 config.out_a = input.tag.get_property("OUT_A", config.out_a);
811                                 config.shape = input.tag.get_property("SHAPE", config.shape);
812                                 config.center_x = input.tag.get_property("CENTER_X", config.center_x);
813                                 config.center_y = input.tag.get_property("CENTER_Y", config.center_y);
814                         }
815                 }
816         }
819 int GradientMain::handle_opengl()
821 #ifdef HAVE_GL
822         char *head_frag =
823                 "uniform sampler2D tex;\n"
824                 "uniform float half_w;\n"
825                 "uniform float half_h;\n"
826                 "uniform float center_x;\n"
827                 "uniform float center_y;\n"
828                 "uniform float half_gradient_size;\n"
829                 "uniform float sin_angle;\n"
830                 "uniform float cos_angle;\n"
831                 "uniform vec4 out_color;\n"
832                 "uniform vec4 in_color;\n"
833                 "uniform float in_radius;\n"
834                 "uniform float out_radius;\n"
835                 "uniform float radius_diff;\n"
836                 "\n"
837                 "void main()\n"
838                 "{\n"
839                 "       vec2 out_coord = gl_TexCoord[0].st;\n";
841         char *linear_shape = 
842                 "       vec2 in_coord = vec2(out_coord.x - half_w, half_h - out_coord.y);\n"
843                 "       float mag = half_gradient_size - \n"
844                 "               (in_coord.x * sin_angle + in_coord.y * cos_angle);\n";
846         char *radial_shape =
847                 "       vec2 in_coord = vec2(out_coord.x - center_x, out_coord.y - center_y);\n"
848                 "       float mag = length(vec2(in_coord.x, in_coord.y));\n";
850 // No clamp function in NVidia
851         char *linear_rate = 
852                 "       mag = min(max(mag, in_radius), out_radius);\n"
853                 "       float opacity = (mag - in_radius) / radius_diff;\n";
855 // NVidia warns about exp, but exp is in the GLSL spec.
856         char *log_rate = 
857                 "       mag = max(mag, in_radius);\n"
858                 "       float opacity = 1.0 - \n"
859                 "               exp(1.0 * -(mag - in_radius) / radius_diff);\n";
861         char *square_rate = 
862                 "       mag = min(max(mag, in_radius), out_radius);\n"
863                 "       float opacity = pow((mag - in_radius) / radius_diff, 2.0);\n"
864                 "       opacity = min(opacity, 1.0);\n";
866         char *tail_frag = 
867                 "       vec4 color = mix(in_color, out_color, opacity);\n"
868                 "       vec4 bg_color = texture2D(tex, out_coord);\n"
869                 "       gl_FragColor.rgb = mix(bg_color.rgb, color.rgb, color.a);\n"
870                 "       gl_FragColor.a = max(bg_color.a, color.a);\n"
871                 "}\n";
874         char *shader_stack[5] = { 0, 0, 0, 0, 0 };
875         shader_stack[0] = head_frag;
877         switch(config.shape)
878         {
879                 case GradientConfig::LINEAR:
880                         shader_stack[1] = linear_shape;
881                         break;
883                 default:
884                         shader_stack[1] = radial_shape;
885                         break;
886         }
888         switch(config.rate)
889         {
890                 case GradientConfig::LINEAR:
891                         shader_stack[2] = linear_rate;
892                         break;
893                 case GradientConfig::LOG:
894                         shader_stack[2] = log_rate;
895                         break;
896                 case GradientConfig::SQUARE:
897                         shader_stack[2] = square_rate;
898                         break;
899         }
901         shader_stack[3] = tail_frag;
902 // Force frame to create texture without copying to it if full alpha.
903         if(config.in_a >= 0xff &&
904                 config.out_a >= 0xff)
905                 get_output()->set_opengl_state(VFrame::TEXTURE);
906         get_output()->to_texture();
907         get_output()->enable_opengl();
908         get_output()->init_screen();
909         get_output()->bind_texture(0);
911         unsigned int frag = VFrame::make_shader(0, 
912                 shader_stack[0], 
913                 shader_stack[1], 
914                 shader_stack[2], 
915                 shader_stack[3], 
916                 0);
918         if(frag)
919         {
920                 glUseProgram(frag);
921                 float w = get_output()->get_w();
922                 float h = get_output()->get_h();
923                 float texture_w = get_output()->get_texture_w();
924                 float texture_h = get_output()->get_texture_h();
925                 glUniform1i(glGetUniformLocation(frag, "tex"), 0);
926                 glUniform1f(glGetUniformLocation(frag, "half_w"), w / 2 / texture_w);
927                 glUniform1f(glGetUniformLocation(frag, "half_h"), h / 2 / texture_h);
928                 if(config.shape == GradientConfig::LINEAR)
929                 {
930                         glUniform1f(glGetUniformLocation(frag, "center_x"), 
931                                 w / 2 / texture_w);
932                         glUniform1f(glGetUniformLocation(frag, "center_y"), 
933                                 h / 2 / texture_h);
934                 }
935                 else
936                 {
937                         glUniform1f(glGetUniformLocation(frag, "center_x"), 
938                                 (float)config.center_x * w / 100 / texture_w);
939                         glUniform1f(glGetUniformLocation(frag, "center_y"), 
940                                 (float)config.center_y * h / 100 / texture_h);
941                 }
942                 float gradient_size = hypotf(w / texture_w, h / texture_h);
943                 glUniform1f(glGetUniformLocation(frag, "half_gradient_size"), 
944                         gradient_size / 2);
945                 glUniform1f(glGetUniformLocation(frag, "sin_angle"), 
946                         sin(config.angle * (M_PI / 180)));
947                 glUniform1f(glGetUniformLocation(frag, "cos_angle"), 
948                         cos(config.angle * (M_PI / 180)));
949                 float in_radius = (float)config.in_radius / 100 * gradient_size;
950                 glUniform1f(glGetUniformLocation(frag, "in_radius"), in_radius);
951                 float out_radius = (float)config.out_radius / 100 * gradient_size;
952                 glUniform1f(glGetUniformLocation(frag, "out_radius"), out_radius);
953                 glUniform1f(glGetUniformLocation(frag, "radius_diff"), 
954                         out_radius - in_radius);
956                 switch(get_output()->get_color_model())
957                 {
958                         case BC_YUV888:
959                         case BC_YUVA8888:
960                         {
961                                 float in1, in2, in3, in4;
962                                 float out1, out2, out3, out4;
963                                 YUV::rgb_to_yuv_f((float)config.in_r / 0xff,
964                                         (float)config.in_g / 0xff,
965                                         (float)config.in_b / 0xff,
966                                         in1,
967                                         in2,
968                                         in3);
969                                 in4 = (float)config.in_a / 0xff;
970                                 YUV::rgb_to_yuv_f((float)config.out_r / 0xff,
971                                         (float)config.out_g / 0xff,
972                                         (float)config.out_b / 0xff,
973                                         out1,
974                                         out2,
975                                         out3);
976                                 in2 += 0.5;
977                                 in3 += 0.5;
978                                 out2 += 0.5;
979                                 out3 += 0.5;
980                                 out4 = (float)config.out_a / 0xff;
981                                 glUniform4f(glGetUniformLocation(frag, "out_color"), 
982                                         out1, out2, out3, out4);
983                                 glUniform4f(glGetUniformLocation(frag, "in_color"), 
984                                         in1, in2, in3, in4);
985                                 break;
986                         }
988                         default:
989                                 glUniform4f(glGetUniformLocation(frag, "out_color"), 
990                                         (float)config.out_r / 0xff,
991                                         (float)config.out_g / 0xff,
992                                         (float)config.out_b / 0xff,
993                                         (float)config.out_a / 0xff);
994                                 glUniform4f(glGetUniformLocation(frag, "in_color"), 
995                                         (float)config.in_r / 0xff,
996                                         (float)config.in_g / 0xff,
997                                         (float)config.in_b / 0xff,
998                                         (float)config.in_a / 0xff);
999                                 break;
1000                 }
1001         }
1003         get_output()->draw_texture();
1004         glUseProgram(0);
1005         get_output()->set_opengl_state(VFrame::SCREEN);
1006         
1007 #endif
1020 GradientPackage::GradientPackage()
1021  : LoadPackage()
1028 GradientUnit::GradientUnit(GradientServer *server, GradientMain *plugin)
1029  : LoadClient(server)
1031         this->plugin = plugin;
1032         this->server = server;
1036 #define SQR(x) ((x) * (x))
1039 static float calculate_opacity(float mag, 
1040         float in_radius, 
1041         float out_radius,
1042         int rate)
1044         float opacity;
1045         switch(rate)
1046         {
1047                 case GradientConfig::LINEAR:
1048                         if(mag < in_radius)
1049                                 opacity = 0.0;
1050                         else
1051                         if(mag >= out_radius)
1052                                 opacity = 1.0;
1053                         else
1054                                 opacity = (float)(mag - in_radius) / (out_radius - in_radius);
1055                         break;
1057                 case GradientConfig::LOG:
1058                         if(mag < in_radius)
1059                                 opacity = 0;
1060                         else
1061 // Let this one decay beyond out_radius
1062                                 opacity = 1 - exp(1.0 * -(float)(mag - in_radius) /
1063                                         (out_radius - in_radius));
1064                         break;
1066                 case GradientConfig::SQUARE:
1067                         if(mag < in_radius)
1068                                 opacity = 0.0; 
1069                         else
1070                         if(mag >= out_radius) 
1071                                 opacity = 1.0;
1072                         else
1073                                 opacity = powf((float)(mag - in_radius) /
1074                                         (out_radius - in_radius), 2.0);
1075                         break;
1076         }
1077         CLAMP(opacity, 0.0, 1.0);
1078         return opacity;
1081 #define CREATE_GRADIENT(type, temp, components, max) \
1082 { \
1083 /* Synthesize linear gradient for lookups */ \
1085         r_table = malloc(sizeof(type) * gradient_size); \
1086         g_table = malloc(sizeof(type) * gradient_size); \
1087         b_table = malloc(sizeof(type) * gradient_size); \
1088         a_table = malloc(sizeof(type) * gradient_size); \
1090         for(int i = 0; i < gradient_size; i++) \
1091         { \
1092                 float opacity = calculate_opacity(i, in_radius, out_radius, plugin->config.rate); \
1093                 float transparency; \
1095                 transparency = 1.0 - opacity; \
1096                 ((type*)r_table)[i] = (type)(out1 * opacity + in1 * transparency); \
1097                 ((type*)g_table)[i] = (type)(out2 * opacity + in2 * transparency); \
1098                 ((type*)b_table)[i] = (type)(out3 * opacity + in3 * transparency); \
1099                 ((type*)a_table)[i] = (type)(out4 * opacity + in4 * transparency); \
1100         } \
1102         for(int i = pkg->y1; i < pkg->y2; i++) \
1103         { \
1104                 type *gradient_row = (type*)plugin->gradient->get_rows()[i]; \
1105                 type *out_row = (type*)plugin->get_output()->get_rows()[i]; \
1107                 switch(plugin->config.shape) \
1108                 { \
1109                         case GradientConfig::LINEAR: \
1110                                 for(int j = 0; j < w; j++) \
1111                                 { \
1112                                         int x = j - half_w; \
1113                                         int y = -(i - half_h); \
1114                  \
1115 /* Rotate by effect angle */ \
1116                                         int mag = (int)(gradient_size / 2 - \
1117                                                 (x * sin_angle + y * cos_angle) + \
1118                                                 0.5); \
1119                  \
1120 /* Get gradient value from these coords */ \
1121                  \
1122                                         if(sizeof(type) == 4) \
1123                                         { \
1124                                                 float opacity = calculate_opacity(mag,  \
1125                                                         in_radius,  \
1126                                                         out_radius, \
1127                                                         plugin->config.rate); \
1128                                                 float transparency = 1.0 - opacity; \
1129                                                 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
1130                                                 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
1131                                                 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
1132                                                 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
1133                                         } \
1134                                         else \
1135                                         if(mag < 0) \
1136                                         { \
1137                                                 gradient_row[0] = out1; \
1138                                                 gradient_row[1] = out2; \
1139                                                 gradient_row[2] = out3; \
1140                                                 if(components == 4) gradient_row[3] = out4; \
1141                                         } \
1142                                         else \
1143                                         if(mag >= gradient_size) \
1144                                         { \
1145                                                 gradient_row[0] = in1; \
1146                                                 gradient_row[1] = in2; \
1147                                                 gradient_row[2] = in3; \
1148                                                 if(components == 4) gradient_row[3] = in4; \
1149                                         } \
1150                                         else \
1151                                         { \
1152                                                 gradient_row[0] = ((type*)r_table)[mag]; \
1153                                                 gradient_row[1] = ((type*)g_table)[mag]; \
1154                                                 gradient_row[2] = ((type*)b_table)[mag]; \
1155                                                 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
1156                                         } \
1158 /* Overlay mixed colormodels onto output */ \
1159                                         if(gradient_cmodel != output_cmodel) \
1160                                         { \
1161                                                 temp opacity = gradient_row[3]; \
1162                                                 temp transparency = max - opacity; \
1163                                                 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
1164                                                 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
1165                                                 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
1166                                                 out_row += 3; \
1167                                         } \
1169                                         gradient_row += components; \
1170                                 } \
1171                                 break; \
1173                         case GradientConfig::RADIAL: \
1174                                 for(int j = 0; j < w; j++) \
1175                                 { \
1176                                         double x = j - center_x; \
1177                                         double y = i - center_y; \
1178                                         double magnitude = hypot(x, y); \
1179                                         int mag = (int)magnitude; \
1180                                         if(sizeof(type) == 4) \
1181                                         { \
1182                                                 float opacity = calculate_opacity(mag,  \
1183                                                         in_radius,  \
1184                                                         out_radius, \
1185                                                         plugin->config.rate); \
1186                                                 float transparency = 1.0 - opacity; \
1187                                                 gradient_row[0] = (type)(out1 * opacity + in1 * transparency); \
1188                                                 gradient_row[1] = (type)(out2 * opacity + in2 * transparency); \
1189                                                 gradient_row[2] = (type)(out3 * opacity + in3 * transparency); \
1190                                                 if(components == 4) gradient_row[3] = (type)(out4 * opacity + in4 * transparency); \
1191                                         } \
1192                                         else \
1193                                         { \
1194                                                 gradient_row[0] = ((type*)r_table)[mag]; \
1195                                                 gradient_row[1] = ((type*)g_table)[mag]; \
1196                                                 gradient_row[2] = ((type*)b_table)[mag]; \
1197                                                 if(components == 4) gradient_row[3] = ((type*)a_table)[mag]; \
1198                                         } \
1200 /* Overlay mixed colormodels onto output */ \
1201                                         if(gradient_cmodel != output_cmodel) \
1202                                         { \
1203                                                 temp opacity = gradient_row[3]; \
1204                                                 temp transparency = max - opacity; \
1205                                                 out_row[0] = (transparency * out_row[0] + opacity * gradient_row[0]) / max; \
1206                                                 out_row[1] = (transparency * out_row[1] + opacity * gradient_row[1]) / max; \
1207                                                 out_row[2] = (transparency * out_row[2] + opacity * gradient_row[2]) / max; \
1208                                                 out_row += 3; \
1209                                         } \
1211                                         gradient_row += components; \
1212                                 } \
1213                                 break; \
1214                 } \
1215         } \
1218 void GradientUnit::process_package(LoadPackage *package)
1220         GradientPackage *pkg = (GradientPackage*)package;
1221         int h = plugin->input->get_h();
1222         int w = plugin->input->get_w();
1223         int half_w = w / 2;
1224         int half_h = h / 2;
1225         int gradient_size = (int)(ceil(hypot(w, h)));
1226         int in_radius = (int)(plugin->config.in_radius / 100 * gradient_size);
1227         int out_radius = (int)(plugin->config.out_radius / 100 * gradient_size);
1228         double sin_angle = sin(plugin->config.angle * (M_PI / 180));
1229         double cos_angle = cos(plugin->config.angle * (M_PI / 180));
1230         double center_x = plugin->config.center_x * w / 100;
1231         double center_y = plugin->config.center_y * h / 100;
1232         void *r_table = 0;
1233         void *g_table = 0;
1234         void *b_table = 0;
1235         void *a_table = 0;
1236         int gradient_cmodel = plugin->gradient->get_color_model();
1237         int output_cmodel = plugin->get_output()->get_color_model();
1239         if(in_radius > out_radius)
1240         {
1241             in_radius ^= out_radius;
1242             out_radius ^= in_radius;
1243             in_radius ^= out_radius;
1244         }
1247         switch(gradient_cmodel)
1248         {
1249                 case BC_RGB888:
1250                 {
1251                         int in1 = plugin->config.in_r;
1252                         int in2 = plugin->config.in_g;
1253                         int in3 = plugin->config.in_b;
1254                         int in4 = plugin->config.in_a;
1255                         int out1 = plugin->config.out_r;
1256                         int out2 = plugin->config.out_g;
1257                         int out3 = plugin->config.out_b;
1258                         int out4 = plugin->config.out_a;
1259                         CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1260                         break;
1261                 }
1263                 case BC_RGBA8888:
1264                 {
1265                         int in1 = plugin->config.in_r;
1266                         int in2 = plugin->config.in_g;
1267                         int in3 = plugin->config.in_b;
1268                         int in4 = plugin->config.in_a;
1269                         int out1 = plugin->config.out_r;
1270                         int out2 = plugin->config.out_g;
1271                         int out3 = plugin->config.out_b;
1272                         int out4 = plugin->config.out_a;
1273                         CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1274                         break;
1275                 }
1277                 case BC_RGB_FLOAT:
1278                 {
1279                         float in1 = (float)plugin->config.in_r / 0xff;
1280                         float in2 = (float)plugin->config.in_g / 0xff;
1281                         float in3 = (float)plugin->config.in_b / 0xff;
1282                         float in4 = (float)plugin->config.in_a / 0xff;
1283                         float out1 = (float)plugin->config.out_r / 0xff;
1284                         float out2 = (float)plugin->config.out_g / 0xff;
1285                         float out3 = (float)plugin->config.out_b / 0xff;
1286                         float out4 = (float)plugin->config.out_a / 0xff;
1287                         CREATE_GRADIENT(float, float, 3, 1.0)
1288                         break;
1289                 }
1291                 case BC_RGBA_FLOAT:
1292                 {
1293                         float in1 = (float)plugin->config.in_r / 0xff;
1294                         float in2 = (float)plugin->config.in_g / 0xff;
1295                         float in3 = (float)plugin->config.in_b / 0xff;
1296                         float in4 = (float)plugin->config.in_a / 0xff;
1297                         float out1 = (float)plugin->config.out_r / 0xff;
1298                         float out2 = (float)plugin->config.out_g / 0xff;
1299                         float out3 = (float)plugin->config.out_b / 0xff;
1300                         float out4 = (float)plugin->config.out_a / 0xff;
1301                         CREATE_GRADIENT(float, float, 4, 1.0)
1302                         break;
1303                 }
1305                 case BC_YUV888:
1306                 {
1307                         int in1, in2, in3, in4;
1308                         int out1, out2, out3, out4;
1309                         yuv.rgb_to_yuv_8(plugin->config.in_r,
1310                                 plugin->config.in_g,
1311                                 plugin->config.in_b,
1312                                 in1,
1313                                 in2,
1314                                 in3);
1315                         in4 = plugin->config.in_a;
1316                         yuv.rgb_to_yuv_8(plugin->config.out_r,
1317                                 plugin->config.out_g,
1318                                 plugin->config.out_b,
1319                                 out1,
1320                                 out2,
1321                                 out3);
1322                         out4 = plugin->config.out_a;
1323                         CREATE_GRADIENT(unsigned char, int, 3, 0xff)
1324                         break;
1325                 }
1327                 case BC_YUVA8888:
1328                 {
1329                         int in1, in2, in3, in4;
1330                         int out1, out2, out3, out4;
1331                         yuv.rgb_to_yuv_8(plugin->config.in_r,
1332                                 plugin->config.in_g,
1333                                 plugin->config.in_b,
1334                                 in1,
1335                                 in2,
1336                                 in3);
1337                         in4 = plugin->config.in_a;
1338                         yuv.rgb_to_yuv_8(plugin->config.out_r,
1339                                 plugin->config.out_g,
1340                                 plugin->config.out_b,
1341                                 out1,
1342                                 out2,
1343                                 out3);
1344                         out4 = plugin->config.out_a;
1345                         CREATE_GRADIENT(unsigned char, int, 4, 0xff)
1346                         break;
1347                 }
1348         }
1350         if(r_table) free(r_table);
1351         if(g_table) free(g_table);
1352         if(b_table) free(b_table);
1353         if(a_table) free(a_table);
1361 GradientServer::GradientServer(GradientMain *plugin, 
1362         int total_clients, 
1363         int total_packages)
1364  : LoadServer(total_clients, total_packages)
1366         this->plugin = plugin;
1369 void GradientServer::init_packages()
1371         for(int i = 0; i < get_total_packages(); i++)
1372         {
1373                 GradientPackage *package = (GradientPackage*)get_package(i);
1374                 package->y1 = plugin->input->get_h() * 
1375                         i / 
1376                         get_total_packages();
1377                 package->y2 = plugin->input->get_h() * 
1378                         (i + 1) /
1379                         get_total_packages();
1380         }
1383 LoadClient* GradientServer::new_client()
1385         return new GradientUnit(this, plugin);
1388 LoadPackage* GradientServer::new_package()
1390         return new GradientPackage;