r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / radialblur / radialblur.C
blobe350cdd9e4b5a6a85382e67cb93e441581905e5a
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
5 #include "bcdisplayinfo.h"
6 #include "clip.h"
7 #include "defaults.h"
8 #include "filexml.h"
9 #include "keyframe.h"
10 #include "loadbalance.h"
11 #include "picon_png.h"
12 #include "pluginvclient.h"
13 #include "vframe.h"
16 #include <libintl.h>
17 #define _(String) gettext(String)
18 #define gettext_noop(String) String
19 #define N_(String) gettext_noop (String)
21 class RadialBlurMain;
22 class RadialBlurEngine;
28 class RadialBlurConfig
30 public:
31         RadialBlurConfig();
33         int equivalent(RadialBlurConfig &that);
34         void copy_from(RadialBlurConfig &that);
35         void interpolate(RadialBlurConfig &prev, 
36                 RadialBlurConfig &next, 
37                 long prev_frame, 
38                 long next_frame, 
39                 long current_frame);
41         int x;
42         int y;
43         int steps;
44         int angle;
45         int r;
46         int g;
47         int b;
48         int a;
53 class RadialBlurSize : public BC_ISlider
55 public:
56         RadialBlurSize(RadialBlurMain *plugin, 
57                 int x, 
58                 int y, 
59                 int *output,
60                 int min,
61                 int max);
62         int handle_event();
63         RadialBlurMain *plugin;
64         int *output;
67 class RadialBlurToggle : public BC_CheckBox
69 public:
70         RadialBlurToggle(RadialBlurMain *plugin, 
71                 int x, 
72                 int y, 
73                 int *output,
74                 char *string);
75         int handle_event();
76         RadialBlurMain *plugin;
77         int *output;
80 class RadialBlurWindow : public BC_Window
82 public:
83         RadialBlurWindow(RadialBlurMain *plugin, int x, int y);
84         ~RadialBlurWindow();
86         int create_objects();
87         int close_event();
89         RadialBlurSize *x, *y, *steps, *angle;
90         RadialBlurToggle *r, *g, *b, *a;
91         RadialBlurMain *plugin;
96 PLUGIN_THREAD_HEADER(RadialBlurMain, RadialBlurThread, RadialBlurWindow)
99 class RadialBlurMain : public PluginVClient
101 public:
102         RadialBlurMain(PluginServer *server);
103         ~RadialBlurMain();
105         int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
106         int is_realtime();
107         int load_defaults();
108         int save_defaults();
109         void save_data(KeyFrame *keyframe);
110         void read_data(KeyFrame *keyframe);
111         void update_gui();
113         PLUGIN_CLASS_MEMBERS(RadialBlurConfig, RadialBlurThread)
115         VFrame *input, *output, *temp;
116         RadialBlurEngine *engine;
119 class RadialBlurPackage : public LoadPackage
121 public:
122         RadialBlurPackage();
123         int y1, y2;
126 class RadialBlurUnit : public LoadClient
128 public:
129         RadialBlurUnit(RadialBlurEngine *server, RadialBlurMain *plugin);
130         void process_package(LoadPackage *package);
131         RadialBlurEngine *server;
132         RadialBlurMain *plugin;
135 class RadialBlurEngine : public LoadServer
137 public:
138         RadialBlurEngine(RadialBlurMain *plugin, 
139                 int total_clients, 
140                 int total_packages);
141         void init_packages();
142         LoadClient* new_client();
143         LoadPackage* new_package();
144         RadialBlurMain *plugin;
165 REGISTER_PLUGIN(RadialBlurMain)
169 RadialBlurConfig::RadialBlurConfig()
171         x = 50;
172         y = 50;
173         steps = 10;
174         angle = 33;
175         r = 1;
176         g = 1;
177         b = 1;
178         a = 1;
181 int RadialBlurConfig::equivalent(RadialBlurConfig &that)
183         return 
184                 angle == that.angle &&
185                 x == that.x &&
186                 y == that.y &&
187                 steps == that.steps &&
188                 r == that.r &&
189                 g == that.g &&
190                 b == that.b &&
191                 a == that.a;
194 void RadialBlurConfig::copy_from(RadialBlurConfig &that)
196         x = that.x;
197         y = that.y;
198         angle = that.angle;
199         steps = that.steps;
200         r = that.r;
201         g = that.g;
202         b = that.b;
203         a = that.a;
206 void RadialBlurConfig::interpolate(RadialBlurConfig &prev, 
207         RadialBlurConfig &next, 
208         long prev_frame, 
209         long next_frame, 
210         long current_frame)
212         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
213         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
214         this->x = (int)(prev.x * prev_scale + next.x * next_scale + 0.5);
215         this->y = (int)(prev.y * prev_scale + next.y * next_scale + 0.5);
216         this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
217         this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale + 0.5);
218         r = prev.r;
219         g = prev.g;
220         b = prev.b;
221         a = prev.a;
232 PLUGIN_THREAD_OBJECT(RadialBlurMain, RadialBlurThread, RadialBlurWindow)
236 RadialBlurWindow::RadialBlurWindow(RadialBlurMain *plugin, int x, int y)
237  : BC_Window(plugin->gui_string, 
238         x,
239         y,
240         230, 
241         340, 
242         230, 
243         340, 
244         0, 
245         1)
247         this->plugin = plugin; 
250 RadialBlurWindow::~RadialBlurWindow()
254 int RadialBlurWindow::create_objects()
256         int x = 10, y = 10;
258         add_subwindow(new BC_Title(x, y, _("X:")));
259         y += 20;
260         add_subwindow(this->x = new RadialBlurSize(plugin, x, y, &plugin->config.x, 0, 100));
261         y += 30;
262         add_subwindow(new BC_Title(x, y, _("Y:")));
263         y += 20;
264         add_subwindow(this->y = new RadialBlurSize(plugin, x, y, &plugin->config.y, 0, 100));
265         y += 30;
266         add_subwindow(new BC_Title(x, y, _("Angle:")));
267         y += 20;
268         add_subwindow(angle = new RadialBlurSize(plugin, x, y, &plugin->config.angle, 0, 360));
269         y += 30;
270         add_subwindow(new BC_Title(x, y, _("Steps:")));
271         y += 20;
272         add_subwindow(steps = new RadialBlurSize(plugin, x, y, &plugin->config.steps, 1, 100));
273         y += 30;
274         add_subwindow(r = new RadialBlurToggle(plugin, x, y, &plugin->config.r, _("Red")));
275         y += 30;
276         add_subwindow(g = new RadialBlurToggle(plugin, x, y, &plugin->config.g, _("Green")));
277         y += 30;
278         add_subwindow(b = new RadialBlurToggle(plugin, x, y, &plugin->config.b, _("Blue")));
279         y += 30;
280         add_subwindow(a = new RadialBlurToggle(plugin, x, y, &plugin->config.a, _("Alpha")));
281         y += 30;
283         show_window();
284         flush();
285         return 0;
288 int RadialBlurWindow::close_event()
290 // Set result to 1 to indicate a plugin side close
291         set_done(1);
292         return 1;
304 RadialBlurToggle::RadialBlurToggle(RadialBlurMain *plugin, 
305         int x, 
306         int y, 
307         int *output, 
308         char *string)
309  : BC_CheckBox(x, y, *output, string)
311         this->plugin = plugin;
312         this->output = output;
315 int RadialBlurToggle::handle_event()
317         *output = get_value();
318         plugin->send_configure_change();
319         return 1;
328 RadialBlurSize::RadialBlurSize(RadialBlurMain *plugin, 
329         int x, 
330         int y, 
331         int *output,
332         int min,
333         int max)
334  : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
336         this->plugin = plugin;
337         this->output = output;
339 int RadialBlurSize::handle_event()
341         *output = get_value();
342         plugin->send_configure_change();
343         return 1;
355 RadialBlurMain::RadialBlurMain(PluginServer *server)
356  : PluginVClient(server)
358         PLUGIN_CONSTRUCTOR_MACRO
359         engine = 0;
360         temp = 0;
363 RadialBlurMain::~RadialBlurMain()
365         PLUGIN_DESTRUCTOR_MACRO
366         if(engine) delete engine;
367         if(temp) delete temp;
370 char* RadialBlurMain::plugin_title() { return _("Radial Blur"); }
371 int RadialBlurMain::is_realtime() { return 1; }
374 NEW_PICON_MACRO(RadialBlurMain)
376 SHOW_GUI_MACRO(RadialBlurMain, RadialBlurThread)
378 SET_STRING_MACRO(RadialBlurMain)
380 RAISE_WINDOW_MACRO(RadialBlurMain)
382 LOAD_CONFIGURATION_MACRO(RadialBlurMain, RadialBlurConfig)
384 int RadialBlurMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
386         load_configuration();
388         if(!engine) engine = new RadialBlurEngine(this,
389                 get_project_smp() + 1,
390                 get_project_smp() + 1);
392         this->input = input_ptr;
393         this->output = output_ptr;
396         if(input_ptr->get_rows()[0] == output_ptr->get_rows()[0])
397         {
398                 if(!temp) temp = new VFrame(0,
399                         input_ptr->get_w(),
400                         input_ptr->get_h(),
401                         input_ptr->get_color_model());
402                 temp->copy_from(input_ptr);
403                 this->input = temp;
404         }
406         engine->process_packages();
407         return 0;
411 void RadialBlurMain::update_gui()
413         if(thread)
414         {
415                 load_configuration();
416                 thread->window->lock_window();
417                 thread->window->x->update(config.x);
418                 thread->window->y->update(config.y);
419                 thread->window->angle->update(config.angle);
420                 thread->window->steps->update(config.steps);
421                 thread->window->r->update(config.r);
422                 thread->window->g->update(config.g);
423                 thread->window->b->update(config.b);
424                 thread->window->a->update(config.a);
425                 thread->window->unlock_window();
426         }
430 int RadialBlurMain::load_defaults()
432         char directory[1024], string[1024];
433 // set the default directory
434         sprintf(directory, "%sradialblur.rc", BCASTDIR);
436 // load the defaults
437         defaults = new Defaults(directory);
438         defaults->load();
440         config.x = defaults->get("X", config.x);
441         config.y = defaults->get("Y", config.y);
442         config.angle = defaults->get("ANGLE", config.angle);
443         config.steps = defaults->get("STEPS", config.steps);
444         config.r = defaults->get("R", config.r);
445         config.g = defaults->get("G", config.g);
446         config.b = defaults->get("B", config.b);
447         config.a = defaults->get("A", config.a);
448         return 0;
452 int RadialBlurMain::save_defaults()
454         defaults->update("X", config.x);
455         defaults->update("Y", config.y);
456         defaults->update("ANGLE", config.angle);
457         defaults->update("STEPS", config.steps);
458         defaults->update("R", config.r);
459         defaults->update("G", config.g);
460         defaults->update("B", config.b);
461         defaults->update("A", config.a);
462         defaults->save();
463         return 0;
468 void RadialBlurMain::save_data(KeyFrame *keyframe)
470         FileXML output;
472 // cause data to be stored directly in text
473         output.set_shared_string(keyframe->data, MESSAGESIZE);
474         output.tag.set_title("RADIALBLUR");
476         output.tag.set_property("X", config.x);
477         output.tag.set_property("Y", config.y);
478         output.tag.set_property("ANGLE", config.angle);
479         output.tag.set_property("STEPS", config.steps);
480         output.tag.set_property("R", config.r);
481         output.tag.set_property("G", config.g);
482         output.tag.set_property("B", config.b);
483         output.tag.set_property("A", config.a);
484         output.append_tag();
485         output.terminate_string();
488 void RadialBlurMain::read_data(KeyFrame *keyframe)
490         FileXML input;
492         input.set_shared_string(keyframe->data, strlen(keyframe->data));
494         int result = 0;
496         while(!result)
497         {
498                 result = input.read_tag();
500                 if(!result)
501                 {
502                         if(input.tag.title_is("RADIALBLUR"))
503                         {
504                                 config.x = input.tag.get_property("X", config.x);
505                                 config.y = input.tag.get_property("Y", config.y);
506                                 config.angle = input.tag.get_property("ANGLE", config.angle);
507                                 config.steps = input.tag.get_property("STEPS", config.steps);
508                                 config.r = input.tag.get_property("R", config.r);
509                                 config.g = input.tag.get_property("G", config.g);
510                                 config.b = input.tag.get_property("B", config.b);
511                                 config.a = input.tag.get_property("A", config.a);
512                         }
513                 }
514         }
522 RadialBlurPackage::RadialBlurPackage()
523  : LoadPackage()
528 RadialBlurUnit::RadialBlurUnit(RadialBlurEngine *server, 
529         RadialBlurMain *plugin)
530  : LoadClient(server)
532         this->plugin = plugin;
533         this->server = server;
537 #define BLEND_LAYER(COMPONENTS, TYPE, MAX, DO_YUV) \
538 { \
539         int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
540         TYPE **in_rows = (TYPE**)plugin->input->get_rows(); \
541         TYPE **out_rows = (TYPE**)plugin->output->get_rows(); \
542         int steps = plugin->config.steps; \
543         double step = (double)plugin->config.angle / 360 * 2 * M_PI / steps; \
545         for(int i = pkg->y1, out_y = pkg->y1 - center_y; \
546                 i < pkg->y2; \
547                 i++, out_y++) \
548         { \
549                 TYPE *out_row = out_rows[i]; \
550                 TYPE *in_row = in_rows[i]; \
551                 int y_square = out_y * out_y; \
553                 for(int j = 0, out_x = -center_x; j < w; j++, out_x++) \
554                 { \
555                         double offset = 0; \
556                         int accum_r = 0; \
557                         int accum_g = 0; \
558                         int accum_b = 0; \
559                         int accum_a = 0; \
561 /* Output coordinate to polar */ \
562                         double magnitude = sqrt(y_square + out_x * out_x); \
563                         double angle; \
564                         if(out_y < 0) \
565                                 angle = atan((double)out_x / out_y) + M_PI; \
566                         else \
567                         if(out_y > 0) \
568                                 angle = atan((double)out_x / out_y); \
569                         else \
570                         if(out_x > 0) \
571                                 angle = M_PI / 2; \
572                         else \
573                                 angle = M_PI * 1.5; \
575 /* Overlay all steps on this pixel*/ \
576                         angle -= (double)plugin->config.angle / 360 * M_PI; \
577                         for(int k = 0; k < steps; k++, angle += step) \
578                         { \
579 /* Polar to input coordinate */ \
580                                 int in_x = (int)(magnitude * sin(angle)) + center_x; \
581                                 int in_y = (int)(magnitude * cos(angle)) + center_y; \
583 /* Accumulate input coordinate */ \
584                                 if(in_x >= 0 && in_x < w && in_y >= 0 && in_y < h) \
585                                 { \
586                                         accum_r += in_rows[in_y][in_x * COMPONENTS]; \
587                                         if(DO_YUV) \
588                                         { \
589                                                 accum_g += (int)in_rows[in_y][in_x * COMPONENTS + 1]; \
590                                                 accum_b += (int)in_rows[in_y][in_x * COMPONENTS + 2]; \
591                                         } \
592                                         else \
593                                         { \
594                                                 accum_g += in_rows[in_y][in_x * COMPONENTS + 1]; \
595                                                 accum_b += in_rows[in_y][in_x * COMPONENTS + 2]; \
596                                         } \
597                                         if(COMPONENTS == 4) \
598                                                 accum_a += in_rows[in_y][in_x * COMPONENTS + 3]; \
599                                 } \
600                                 else \
601                                 { \
602                                         accum_g += chroma_offset; \
603                                         accum_b += chroma_offset; \
604                                 } \
605                         } \
607 /* Accumulation to output */ \
608                         if(do_r) \
609                         { \
610                                 *out_row++ = (accum_r * fraction) >> 16; \
611                                 in_row++; \
612                         } \
613                         else \
614                         { \
615                                 *out_row++ = *in_row++; \
616                         } \
618                         if(do_g) \
619                         { \
620                                 if(DO_YUV) \
621                                         *out_row++ = ((accum_g * fraction) >> 16); \
622                                 else \
623                                         *out_row++ = (accum_g * fraction) >> 16; \
624                                 in_row++; \
625                         } \
626                         else \
627                         { \
628                                 *out_row++ = *in_row++; \
629                         } \
631                         if(do_b) \
632                         { \
633                                 if(DO_YUV) \
634                                         *out_row++ = ((accum_b * fraction) >> 16); \
635                                 else \
636                                         *out_row++ = (accum_b * fraction) >> 16; \
637                                 in_row++; \
638                         } \
639                         else \
640                         { \
641                                 *out_row++ = *in_row++; \
642                         } \
644                         if(COMPONENTS == 4) \
645                         { \
646                                 if(do_a) \
647                                 { \
648                                         *out_row++ = (accum_a * fraction) >> 16; \
649                                         in_row++; \
650                                 } \
651                                 else \
652                                 { \
653                                         *out_row++ = *in_row++; \
654                                 } \
655                         } \
656                 } \
657         } \
660 void RadialBlurUnit::process_package(LoadPackage *package)
662         RadialBlurPackage *pkg = (RadialBlurPackage*)package;
663         int h = plugin->output->get_h();
664         int w = plugin->output->get_w();
665         int do_r = plugin->config.r;
666         int do_g = plugin->config.g;
667         int do_b = plugin->config.b;
668         int do_a = plugin->config.a;
669         int fraction = 0x10000 / plugin->config.steps;
670         int center_x = plugin->config.x * w / 100;
671         int center_y = plugin->config.y * h / 100;
673         switch(plugin->input->get_color_model())
674         {
675                 case BC_RGB888:
676                         BLEND_LAYER(3, uint8_t, 0xff, 0)
677                         break;
678                 case BC_RGBA8888:
679                         BLEND_LAYER(4, uint8_t, 0xff, 0)
680                         break;
681                 case BC_RGB161616:
682                         BLEND_LAYER(3, uint16_t, 0xffff, 0)
683                         break;
684                 case BC_RGBA16161616:
685                         BLEND_LAYER(4, uint16_t, 0xffff, 0)
686                         break;
687                 case BC_YUV888:
688                         BLEND_LAYER(3, uint8_t, 0xff, 1)
689                         break;
690                 case BC_YUVA8888:
691                         BLEND_LAYER(4, uint8_t, 0xff, 1)
692                         break;
693                 case BC_YUV161616:
694                         BLEND_LAYER(3, uint16_t, 0xffff, 1)
695                         break;
696                 case BC_YUVA16161616:
697                         BLEND_LAYER(4, uint16_t, 0xffff, 1)
698                         break;
699         }
707 RadialBlurEngine::RadialBlurEngine(RadialBlurMain *plugin, 
708         int total_clients, 
709         int total_packages)
710  : LoadServer(total_clients, total_packages)
711 // : LoadServer(1, 1)
713         this->plugin = plugin;
716 void RadialBlurEngine::init_packages()
718         int package_h = (int)((float)plugin->output->get_h() / 
719                         total_packages + 1);
720         int y1 = 0;
721         for(int i = 0; i < total_packages; i++)
722         {
723                 RadialBlurPackage *package = (RadialBlurPackage*)packages[i];
724                 package->y1 = y1;
725                 package->y2 = y1 + package_h;
726                 package->y1 = MIN(plugin->output->get_h(), package->y1);
727                 package->y2 = MIN(plugin->output->get_h(), package->y2);
728                 y1 = package->y2;
729         }
732 LoadClient* RadialBlurEngine::new_client()
734         return new RadialBlurUnit(this, plugin);
737 LoadPackage* RadialBlurEngine::new_package()
739         return new RadialBlurPackage;