6 #include "../motion/affine.h"
7 #include "bcdisplayinfo.h"
13 #include "loadbalance.h"
14 #include "picon_png.h"
15 #include "pluginvclient.h"
20 class RadialBlurEngine;
26 class RadialBlurConfig
31 int equivalent(RadialBlurConfig &that);
32 void copy_from(RadialBlurConfig &that);
33 void interpolate(RadialBlurConfig &prev,
34 RadialBlurConfig &next,
51 class RadialBlurSize : public BC_ISlider
54 RadialBlurSize(RadialBlurMain *plugin,
61 RadialBlurMain *plugin;
65 class RadialBlurToggle : public BC_CheckBox
68 RadialBlurToggle(RadialBlurMain *plugin,
74 RadialBlurMain *plugin;
78 class RadialBlurWindow : public BC_Window
81 RadialBlurWindow(RadialBlurMain *plugin, int x, int y);
87 RadialBlurSize *x, *y, *steps, *angle;
88 RadialBlurToggle *r, *g, *b, *a;
89 RadialBlurMain *plugin;
94 PLUGIN_THREAD_HEADER(RadialBlurMain, RadialBlurThread, RadialBlurWindow)
97 class RadialBlurMain : public PluginVClient
100 RadialBlurMain(PluginServer *server);
103 int process_buffer(VFrame *frame,
104 int64_t start_position,
109 void save_data(KeyFrame *keyframe);
110 void read_data(KeyFrame *keyframe);
114 PLUGIN_CLASS_MEMBERS(RadialBlurConfig, RadialBlurThread)
116 VFrame *input, *output, *temp;
117 RadialBlurEngine *engine;
118 // Rotate engine only used for OpenGL
119 AffineEngine *rotate;
122 class RadialBlurPackage : public LoadPackage
129 class RadialBlurUnit : public LoadClient
132 RadialBlurUnit(RadialBlurEngine *server, RadialBlurMain *plugin);
133 void process_package(LoadPackage *package);
134 RadialBlurEngine *server;
135 RadialBlurMain *plugin;
138 class RadialBlurEngine : public LoadServer
141 RadialBlurEngine(RadialBlurMain *plugin,
144 void init_packages();
145 LoadClient* new_client();
146 LoadPackage* new_package();
147 RadialBlurMain *plugin;
168 REGISTER_PLUGIN(RadialBlurMain)
172 RadialBlurConfig::RadialBlurConfig()
184 int RadialBlurConfig::equivalent(RadialBlurConfig &that)
187 angle == that.angle &&
190 steps == that.steps &&
197 void RadialBlurConfig::copy_from(RadialBlurConfig &that)
209 void RadialBlurConfig::interpolate(RadialBlurConfig &prev,
210 RadialBlurConfig &next,
215 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
216 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
217 this->x = (int)(prev.x * prev_scale + next.x * next_scale + 0.5);
218 this->y = (int)(prev.y * prev_scale + next.y * next_scale + 0.5);
219 this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
220 this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale + 0.5);
235 PLUGIN_THREAD_OBJECT(RadialBlurMain, RadialBlurThread, RadialBlurWindow)
239 RadialBlurWindow::RadialBlurWindow(RadialBlurMain *plugin, int x, int y)
240 : BC_Window(plugin->gui_string,
250 this->plugin = plugin;
253 RadialBlurWindow::~RadialBlurWindow()
257 int RadialBlurWindow::create_objects()
261 add_subwindow(new BC_Title(x, y, _("X:")));
263 add_subwindow(this->x = new RadialBlurSize(plugin, x, y, &plugin->config.x, 0, 100));
265 add_subwindow(new BC_Title(x, y, _("Y:")));
267 add_subwindow(this->y = new RadialBlurSize(plugin, x, y, &plugin->config.y, 0, 100));
269 add_subwindow(new BC_Title(x, y, _("Angle:")));
271 add_subwindow(angle = new RadialBlurSize(plugin, x, y, &plugin->config.angle, 0, 360));
273 add_subwindow(new BC_Title(x, y, _("Steps:")));
275 add_subwindow(steps = new RadialBlurSize(plugin, x, y, &plugin->config.steps, 1, 100));
277 add_subwindow(r = new RadialBlurToggle(plugin, x, y, &plugin->config.r, _("Red")));
279 add_subwindow(g = new RadialBlurToggle(plugin, x, y, &plugin->config.g, _("Green")));
281 add_subwindow(b = new RadialBlurToggle(plugin, x, y, &plugin->config.b, _("Blue")));
283 add_subwindow(a = new RadialBlurToggle(plugin, x, y, &plugin->config.a, _("Alpha")));
291 WINDOW_CLOSE_EVENT(RadialBlurWindow)
301 RadialBlurToggle::RadialBlurToggle(RadialBlurMain *plugin,
306 : BC_CheckBox(x, y, *output, string)
308 this->plugin = plugin;
309 this->output = output;
312 int RadialBlurToggle::handle_event()
314 *output = get_value();
315 plugin->send_configure_change();
325 RadialBlurSize::RadialBlurSize(RadialBlurMain *plugin,
331 : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
333 this->plugin = plugin;
334 this->output = output;
336 int RadialBlurSize::handle_event()
338 *output = get_value();
339 plugin->send_configure_change();
352 RadialBlurMain::RadialBlurMain(PluginServer *server)
353 : PluginVClient(server)
355 PLUGIN_CONSTRUCTOR_MACRO
361 RadialBlurMain::~RadialBlurMain()
363 PLUGIN_DESTRUCTOR_MACRO
364 if(engine) delete engine;
365 if(temp) delete temp;
369 char* RadialBlurMain::plugin_title() { return N_("Radial Blur"); }
370 int RadialBlurMain::is_realtime() { return 1; }
373 NEW_PICON_MACRO(RadialBlurMain)
375 SHOW_GUI_MACRO(RadialBlurMain, RadialBlurThread)
377 SET_STRING_MACRO(RadialBlurMain)
379 RAISE_WINDOW_MACRO(RadialBlurMain)
381 LOAD_CONFIGURATION_MACRO(RadialBlurMain, RadialBlurConfig)
383 int RadialBlurMain::process_buffer(VFrame *frame,
384 int64_t start_position,
387 load_configuration();
392 get_source_position(),
397 if(get_use_opengl()) return run_opengl();
399 if(!engine) engine = new RadialBlurEngine(this,
400 get_project_smp() + 1,
401 get_project_smp() + 1);
404 this->output = frame;
407 if(!temp) temp = new VFrame(0,
410 frame->get_color_model());
411 temp->copy_from(frame);
414 engine->process_packages();
419 void RadialBlurMain::update_gui()
423 load_configuration();
424 thread->window->lock_window();
425 thread->window->x->update(config.x);
426 thread->window->y->update(config.y);
427 thread->window->angle->update(config.angle);
428 thread->window->steps->update(config.steps);
429 thread->window->r->update(config.r);
430 thread->window->g->update(config.g);
431 thread->window->b->update(config.b);
432 thread->window->a->update(config.a);
433 thread->window->unlock_window();
438 int RadialBlurMain::load_defaults()
440 char directory[1024], string[1024];
441 // set the default directory
442 sprintf(directory, "%sradialblur.rc", BCASTDIR);
445 defaults = new BC_Hash(directory);
448 config.x = defaults->get("X", config.x);
449 config.y = defaults->get("Y", config.y);
450 config.angle = defaults->get("ANGLE", config.angle);
451 config.steps = defaults->get("STEPS", config.steps);
452 config.r = defaults->get("R", config.r);
453 config.g = defaults->get("G", config.g);
454 config.b = defaults->get("B", config.b);
455 config.a = defaults->get("A", config.a);
460 int RadialBlurMain::save_defaults()
462 defaults->update("X", config.x);
463 defaults->update("Y", config.y);
464 defaults->update("ANGLE", config.angle);
465 defaults->update("STEPS", config.steps);
466 defaults->update("R", config.r);
467 defaults->update("G", config.g);
468 defaults->update("B", config.b);
469 defaults->update("A", config.a);
476 void RadialBlurMain::save_data(KeyFrame *keyframe)
480 // cause data to be stored directly in text
481 output.set_shared_string(keyframe->data, MESSAGESIZE);
482 output.tag.set_title("RADIALBLUR");
484 output.tag.set_property("X", config.x);
485 output.tag.set_property("Y", config.y);
486 output.tag.set_property("ANGLE", config.angle);
487 output.tag.set_property("STEPS", config.steps);
488 output.tag.set_property("R", config.r);
489 output.tag.set_property("G", config.g);
490 output.tag.set_property("B", config.b);
491 output.tag.set_property("A", config.a);
493 output.tag.set_title("/RADIALBLUR");
495 output.terminate_string();
498 void RadialBlurMain::read_data(KeyFrame *keyframe)
502 input.set_shared_string(keyframe->data, strlen(keyframe->data));
508 result = input.read_tag();
512 if(input.tag.title_is("RADIALBLUR"))
514 config.x = input.tag.get_property("X", config.x);
515 config.y = input.tag.get_property("Y", config.y);
516 config.angle = input.tag.get_property("ANGLE", config.angle);
517 config.steps = input.tag.get_property("STEPS", config.steps);
518 config.r = input.tag.get_property("R", config.r);
519 config.g = input.tag.get_property("G", config.g);
520 config.b = input.tag.get_property("B", config.b);
521 config.a = input.tag.get_property("A", config.a);
527 int RadialBlurMain::handle_opengl()
530 get_output()->to_texture();
531 get_output()->enable_opengl();
532 get_output()->init_screen();
533 get_output()->bind_texture(0);
536 int is_yuv = cmodel_is_yuv(get_output()->get_color_model());
537 glClearColor(0.0, 0.0, 0.0, 0.0);
538 glClear(GL_COLOR_BUFFER_BIT);
540 // Draw unselected channels
542 glBlendFunc(GL_ONE, GL_ONE);
543 glDrawBuffer(GL_BACK);
544 if(!config.r || !config.g || !config.b || !config.a)
546 glColor4f(config.r ? 0 : 1,
550 get_output()->draw_texture();
552 glAccum(GL_LOAD, 1.0);
555 // Blur selected channels
556 float fraction = 1.0 / config.steps;
557 for(int i = 0; i < config.steps; i++)
559 get_output()->set_opengl_state(VFrame::TEXTURE);
560 glClear(GL_COLOR_BUFFER_BIT);
561 glColor4f(config.r ? 1 : 0,
566 float w = get_output()->get_w();
567 float h = get_output()->get_h();
571 double current_angle = (double)config.angle *
574 (double)config.angle / 2;
576 if(!rotate) rotate = new AffineEngine(PluginClient::smp + 1,
577 PluginClient::smp + 1);
578 rotate->set_pivot((int)(config.x * w / 100),
579 (int)(config.y * h / 100));
580 rotate->set_opengl(1);
581 rotate->rotate(get_output(),
585 glAccum(GL_ACCUM, fraction);
586 glEnable(GL_TEXTURE_2D);
587 glColor4f(config.r ? 1 : 0,
595 glReadBuffer(GL_BACK);
596 glDisable(GL_TEXTURE_2D);
597 glAccum(GL_RETURN, 1.0);
599 glColor4f(1, 1, 1, 1);
600 get_output()->set_opengl_state(VFrame::SCREEN);
614 RadialBlurPackage::RadialBlurPackage()
620 RadialBlurUnit::RadialBlurUnit(RadialBlurEngine *server,
621 RadialBlurMain *plugin)
624 this->plugin = plugin;
625 this->server = server;
629 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP_TYPE, MAX, DO_YUV) \
631 int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
632 TYPE **in_rows = (TYPE**)plugin->input->get_rows(); \
633 TYPE **out_rows = (TYPE**)plugin->output->get_rows(); \
634 int steps = plugin->config.steps; \
635 double step = (double)plugin->config.angle / 360 * 2 * M_PI / steps; \
637 for(int i = pkg->y1, out_y = pkg->y1 - center_y; \
641 TYPE *out_row = out_rows[i]; \
642 TYPE *in_row = in_rows[i]; \
643 int y_square = out_y * out_y; \
645 for(int j = 0, out_x = -center_x; j < w; j++, out_x++) \
648 TEMP_TYPE accum_r = 0; \
649 TEMP_TYPE accum_g = 0; \
650 TEMP_TYPE accum_b = 0; \
651 TEMP_TYPE accum_a = 0; \
653 /* Output coordinate to polar */ \
654 double magnitude = sqrt(y_square + out_x * out_x); \
657 angle = atan((double)out_x / out_y) + M_PI; \
660 angle = atan((double)out_x / out_y); \
665 angle = M_PI * 1.5; \
667 /* Overlay all steps on this pixel*/ \
668 angle -= (double)plugin->config.angle / 360 * M_PI; \
669 for(int k = 0; k < steps; k++, angle += step) \
671 /* Polar to input coordinate */ \
672 int in_x = (int)(magnitude * sin(angle)) + center_x; \
673 int in_y = (int)(magnitude * cos(angle)) + center_y; \
675 /* Accumulate input coordinate */ \
676 if(in_x >= 0 && in_x < w && in_y >= 0 && in_y < h) \
678 accum_r += in_rows[in_y][in_x * COMPONENTS]; \
681 accum_g += (int)in_rows[in_y][in_x * COMPONENTS + 1]; \
682 accum_b += (int)in_rows[in_y][in_x * COMPONENTS + 2]; \
686 accum_g += in_rows[in_y][in_x * COMPONENTS + 1]; \
687 accum_b += in_rows[in_y][in_x * COMPONENTS + 2]; \
689 if(COMPONENTS == 4) \
690 accum_a += in_rows[in_y][in_x * COMPONENTS + 3]; \
694 accum_g += chroma_offset; \
695 accum_b += chroma_offset; \
699 /* Accumulation to output */ \
702 *out_row++ = (accum_r * fraction) / 0x10000; \
707 *out_row++ = *in_row++; \
713 *out_row++ = ((accum_g * fraction) / 0x10000); \
715 *out_row++ = (accum_g * fraction) / 0x10000; \
720 *out_row++ = *in_row++; \
726 *out_row++ = (accum_b * fraction) / 0x10000; \
728 *out_row++ = (accum_b * fraction) / 0x10000; \
733 *out_row++ = *in_row++; \
736 if(COMPONENTS == 4) \
740 *out_row++ = (accum_a * fraction) / 0x10000; \
745 *out_row++ = *in_row++; \
752 void RadialBlurUnit::process_package(LoadPackage *package)
754 RadialBlurPackage *pkg = (RadialBlurPackage*)package;
755 int h = plugin->output->get_h();
756 int w = plugin->output->get_w();
757 int do_r = plugin->config.r;
758 int do_g = plugin->config.g;
759 int do_b = plugin->config.b;
760 int do_a = plugin->config.a;
761 int fraction = 0x10000 / plugin->config.steps;
762 int center_x = plugin->config.x * w / 100;
763 int center_y = plugin->config.y * h / 100;
765 switch(plugin->input->get_color_model())
768 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
771 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
774 BLEND_LAYER(3, float, float, 1, 0)
777 BLEND_LAYER(4, float, float, 1, 0)
780 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
782 case BC_RGBA16161616:
783 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
786 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
789 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
792 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
794 case BC_YUVA16161616:
795 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
805 RadialBlurEngine::RadialBlurEngine(RadialBlurMain *plugin,
808 : LoadServer(total_clients, total_packages)
809 // : LoadServer(1, 1)
811 this->plugin = plugin;
814 void RadialBlurEngine::init_packages()
816 for(int i = 0; i < get_total_packages(); i++)
818 RadialBlurPackage *package = (RadialBlurPackage*)get_package(i);
819 package->y1 = plugin->output->get_h() * i / get_total_packages();
820 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
824 LoadClient* RadialBlurEngine::new_client()
826 return new RadialBlurUnit(this, plugin);
829 LoadPackage* RadialBlurEngine::new_package()
831 return new RadialBlurPackage;