5 #include "bcdisplayinfo.h"
11 #include "loadbalance.h"
12 #include "picon_png.h"
13 #include "pluginvclient.h"
19 class LinearBlurEngine;
25 class LinearBlurConfig
30 int equivalent(LinearBlurConfig &that);
31 void copy_from(LinearBlurConfig &that);
32 void interpolate(LinearBlurConfig &prev,
33 LinearBlurConfig &next,
49 class LinearBlurSize : public BC_ISlider
52 LinearBlurSize(LinearBlurMain *plugin,
59 LinearBlurMain *plugin;
63 class LinearBlurToggle : public BC_CheckBox
66 LinearBlurToggle(LinearBlurMain *plugin,
72 LinearBlurMain *plugin;
76 class LinearBlurWindow : public BC_Window
79 LinearBlurWindow(LinearBlurMain *plugin, int x, int y);
85 LinearBlurSize *angle, *steps, *radius;
86 LinearBlurToggle *r, *g, *b, *a;
87 LinearBlurMain *plugin;
92 PLUGIN_THREAD_HEADER(LinearBlurMain, LinearBlurThread, LinearBlurWindow)
95 // Output coords for a layer of blurring
96 // Used for OpenGL only
100 LinearBlurLayer() {};
104 class LinearBlurMain : public PluginVClient
107 LinearBlurMain(PluginServer *server);
110 int process_buffer(VFrame *frame,
111 int64_t start_position,
116 void save_data(KeyFrame *keyframe);
117 void read_data(KeyFrame *keyframe);
121 PLUGIN_CLASS_MEMBERS(LinearBlurConfig, LinearBlurThread)
123 void delete_tables();
124 VFrame *input, *output, *temp;
125 LinearBlurEngine *engine;
128 LinearBlurLayer *layer_table;
130 int need_reconfigure;
131 // The accumulation buffer is needed because 8 bits isn't precise enough
132 unsigned char *accum;
135 class LinearBlurPackage : public LoadPackage
142 class LinearBlurUnit : public LoadClient
145 LinearBlurUnit(LinearBlurEngine *server, LinearBlurMain *plugin);
146 void process_package(LoadPackage *package);
147 LinearBlurEngine *server;
148 LinearBlurMain *plugin;
151 class LinearBlurEngine : public LoadServer
154 LinearBlurEngine(LinearBlurMain *plugin,
157 void init_packages();
158 LoadClient* new_client();
159 LoadPackage* new_package();
160 LinearBlurMain *plugin;
181 REGISTER_PLUGIN(LinearBlurMain)
185 LinearBlurConfig::LinearBlurConfig()
196 int LinearBlurConfig::equivalent(LinearBlurConfig &that)
199 radius == that.radius &&
200 angle == that.angle &&
201 steps == that.steps &&
208 void LinearBlurConfig::copy_from(LinearBlurConfig &that)
210 radius = that.radius;
219 void LinearBlurConfig::interpolate(LinearBlurConfig &prev,
220 LinearBlurConfig &next,
225 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
226 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
227 this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale + 0.5);
228 this->angle = (int)(prev.angle * prev_scale + next.angle * next_scale + 0.5);
229 this->steps = (int)(prev.steps * prev_scale + next.steps * next_scale + 0.5);
244 PLUGIN_THREAD_OBJECT(LinearBlurMain, LinearBlurThread, LinearBlurWindow)
248 LinearBlurWindow::LinearBlurWindow(LinearBlurMain *plugin, int x, int y)
249 : BC_Window(plugin->gui_string,
259 this->plugin = plugin;
262 LinearBlurWindow::~LinearBlurWindow()
266 int LinearBlurWindow::create_objects()
270 add_subwindow(new BC_Title(x, y, _("Length:")));
272 add_subwindow(radius = new LinearBlurSize(plugin, x, y, &plugin->config.radius, 0, 100));
274 add_subwindow(new BC_Title(x, y, _("Angle:")));
276 add_subwindow(angle = new LinearBlurSize(plugin, x, y, &plugin->config.angle, -180, 180));
278 add_subwindow(new BC_Title(x, y, _("Steps:")));
280 add_subwindow(steps = new LinearBlurSize(plugin, x, y, &plugin->config.steps, 1, 200));
282 add_subwindow(r = new LinearBlurToggle(plugin, x, y, &plugin->config.r, _("Red")));
284 add_subwindow(g = new LinearBlurToggle(plugin, x, y, &plugin->config.g, _("Green")));
286 add_subwindow(b = new LinearBlurToggle(plugin, x, y, &plugin->config.b, _("Blue")));
288 add_subwindow(a = new LinearBlurToggle(plugin, x, y, &plugin->config.a, _("Alpha")));
296 WINDOW_CLOSE_EVENT(LinearBlurWindow)
307 LinearBlurToggle::LinearBlurToggle(LinearBlurMain *plugin,
312 : BC_CheckBox(x, y, *output, string)
314 this->plugin = plugin;
315 this->output = output;
318 int LinearBlurToggle::handle_event()
320 *output = get_value();
321 plugin->send_configure_change();
331 LinearBlurSize::LinearBlurSize(LinearBlurMain *plugin,
337 : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
339 this->plugin = plugin;
340 this->output = output;
342 int LinearBlurSize::handle_event()
344 *output = get_value();
345 plugin->send_configure_change();
358 LinearBlurMain::LinearBlurMain(PluginServer *server)
359 : PluginVClient(server)
361 PLUGIN_CONSTRUCTOR_MACRO
367 need_reconfigure = 1;
372 LinearBlurMain::~LinearBlurMain()
374 PLUGIN_DESTRUCTOR_MACRO
375 if(engine) delete engine;
377 if(accum) delete [] accum;
378 if(temp) delete temp;
381 char* LinearBlurMain::plugin_title() { return N_("Linear Blur"); }
382 int LinearBlurMain::is_realtime() { return 1; }
385 NEW_PICON_MACRO(LinearBlurMain)
387 SHOW_GUI_MACRO(LinearBlurMain, LinearBlurThread)
389 SET_STRING_MACRO(LinearBlurMain)
391 RAISE_WINDOW_MACRO(LinearBlurMain)
393 LOAD_CONFIGURATION_MACRO(LinearBlurMain, LinearBlurConfig)
395 void LinearBlurMain::delete_tables()
399 for(int i = 0; i < table_entries; i++)
400 delete [] scale_x_table[i];
401 delete [] scale_x_table;
406 for(int i = 0; i < table_entries; i++)
407 delete [] scale_y_table[i];
408 delete [] scale_y_table;
410 delete [] layer_table;
417 int LinearBlurMain::process_buffer(VFrame *frame,
418 int64_t start_position,
421 need_reconfigure |= load_configuration();
425 get_source_position(),
429 // Generate tables here. The same table is used by many packages to render
430 // each horizontal stripe. Need to cover the entire output range in each
431 // table to avoid green borders
434 int w = frame->get_w();
435 int h = frame->get_h();
438 int angle = config.angle;
439 int radius = config.radius * MIN(w, h) / 100;
441 while(angle < 0) angle += 360;
462 y_offset = (int)(sin((float)config.angle / 360 * 2 * M_PI) * radius);
463 x_offset = (int)(cos((float)config.angle / 360 * 2 * M_PI) * radius);
469 scale_x_table = new int*[config.steps];
470 scale_y_table = new int*[config.steps];
471 table_entries = config.steps;
472 layer_table = new LinearBlurLayer[table_entries];
474 //printf("LinearBlurMain::process_realtime 1 %d %d %d\n", radius, x_offset, y_offset);
476 for(int i = 0; i < config.steps; i++)
478 float fraction = (float)(i - config.steps / 2) / config.steps;
479 int x = (int)(fraction * x_offset);
480 int y = (int)(fraction * y_offset);
484 scale_y_table[i] = y_table = new int[h];
485 scale_x_table[i] = x_table = new int[w];
487 layer_table[i].x = x;
488 layer_table[i].y = y;
489 for(int j = 0; j < h; j++)
492 CLAMP(y_table[j], 0, h - 1);
494 for(int j = 0; j < w; j++)
497 CLAMP(x_table[j], 0, w - 1);
500 need_reconfigure = 0;
503 if(get_use_opengl()) return run_opengl();
506 if(!engine) engine = new LinearBlurEngine(this,
507 get_project_smp() + 1,
508 get_project_smp() + 1);
509 if(!accum) accum = new unsigned char[frame->get_w() *
511 cmodel_components(frame->get_color_model()) *
512 MAX(sizeof(int), sizeof(float))];
515 this->output = frame;
518 if(!temp) temp = new VFrame(0,
521 frame->get_color_model());
522 temp->copy_from(frame);
529 cmodel_components(frame->get_color_model()) *
530 MAX(sizeof(int), sizeof(float)));
531 engine->process_packages();
536 void LinearBlurMain::update_gui()
540 load_configuration();
541 thread->window->lock_window();
542 thread->window->radius->update(config.radius);
543 thread->window->angle->update(config.angle);
544 thread->window->steps->update(config.steps);
545 thread->window->r->update(config.r);
546 thread->window->g->update(config.g);
547 thread->window->b->update(config.b);
548 thread->window->a->update(config.a);
549 thread->window->unlock_window();
554 int LinearBlurMain::load_defaults()
556 char directory[1024], string[1024];
557 // set the default directory
558 sprintf(directory, "%slinearblur.rc", BCASTDIR);
561 defaults = new BC_Hash(directory);
564 config.radius = defaults->get("RADIUS", config.radius);
565 config.angle = defaults->get("ANGLE", config.angle);
566 config.steps = defaults->get("STEPS", config.steps);
567 config.r = defaults->get("R", config.r);
568 config.g = defaults->get("G", config.g);
569 config.b = defaults->get("B", config.b);
570 config.a = defaults->get("A", config.a);
575 int LinearBlurMain::save_defaults()
577 defaults->update("RADIUS", config.radius);
578 defaults->update("ANGLE", config.angle);
579 defaults->update("STEPS", config.steps);
580 defaults->update("R", config.r);
581 defaults->update("G", config.g);
582 defaults->update("B", config.b);
583 defaults->update("A", config.a);
590 void LinearBlurMain::save_data(KeyFrame *keyframe)
594 // cause data to be stored directly in text
595 output.set_shared_string(keyframe->data, MESSAGESIZE);
596 output.tag.set_title("LINEARBLUR");
598 output.tag.set_property("RADIUS", config.radius);
599 output.tag.set_property("ANGLE", config.angle);
600 output.tag.set_property("STEPS", config.steps);
601 output.tag.set_property("R", config.r);
602 output.tag.set_property("G", config.g);
603 output.tag.set_property("B", config.b);
604 output.tag.set_property("A", config.a);
606 output.terminate_string();
609 void LinearBlurMain::read_data(KeyFrame *keyframe)
613 input.set_shared_string(keyframe->data, strlen(keyframe->data));
619 result = input.read_tag();
623 if(input.tag.title_is("LINEARBLUR"))
625 config.radius = input.tag.get_property("RADIUS", config.radius);
626 config.angle = input.tag.get_property("ANGLE", config.angle);
627 config.steps = input.tag.get_property("STEPS", config.steps);
628 config.r = input.tag.get_property("R", config.r);
629 config.g = input.tag.get_property("G", config.g);
630 config.b = input.tag.get_property("B", config.b);
631 config.a = input.tag.get_property("A", config.a);
638 static void draw_box(float x1, float y1, float x2, float y2)
641 glVertex3f(x1, y1, 0.0);
642 glVertex3f(x2, y1, 0.0);
643 glVertex3f(x2, y2, 0.0);
644 glVertex3f(x1, y2, 0.0);
649 int LinearBlurMain::handle_opengl()
652 get_output()->to_texture();
653 get_output()->enable_opengl();
654 get_output()->init_screen();
655 get_output()->bind_texture(0);
657 int is_yuv = cmodel_is_yuv(get_output()->get_color_model());
658 glClearColor(0.0, 0.0, 0.0, 0.0);
659 glClear(GL_COLOR_BUFFER_BIT);
661 // Draw unselected channels
663 glBlendFunc(GL_ONE, GL_ONE);
664 glDrawBuffer(GL_BACK);
665 if(!config.r || !config.g || !config.b || !config.a)
667 glColor4f(config.r ? 0 : 1,
671 get_output()->draw_texture();
673 glAccum(GL_LOAD, 1.0);
675 // Blur selected channels
676 float fraction = 1.0 / config.steps;
677 for(int i = 0; i < config.steps; i++)
679 glClear(GL_COLOR_BUFFER_BIT);
680 glColor4f(config.r ? 1 : 0,
685 int w = get_output()->get_w();
686 int h = get_output()->get_h();
687 get_output()->draw_texture(0,
692 get_output()->get_h() - layer_table[i].y,
693 layer_table[i].x + w,
694 get_output()->get_h() - layer_table[i].y - h,
699 glDisable(GL_TEXTURE_2D);
702 glColor4f(config.r ? 0.0 : 0,
706 float center_x1 = 0.0;
707 float center_x2 = get_output()->get_w();
708 float project_x1 = layer_table[i].x;
709 float project_x2 = layer_table[i].x + get_output()->get_w();
710 float project_y1 = layer_table[i].y;
711 float project_y2 = layer_table[i].y + get_output()->get_h();
714 center_x1 = project_x1;
715 draw_box(0, 0, project_x1, -get_output()->get_h());
717 if(project_x2 < get_output()->get_w())
719 center_x2 = project_x2;
720 draw_box(project_x2, 0, get_output()->get_w(), -get_output()->get_h());
725 -get_output()->get_h(),
727 -get_output()->get_h() + project_y1);
729 if(project_y2 < get_output()->get_h())
732 -get_output()->get_h() + project_y2,
741 glAccum(GL_ACCUM, fraction);
742 glEnable(GL_TEXTURE_2D);
743 glColor4f(config.r ? 1 : 0,
750 glDisable(GL_TEXTURE_2D);
751 glReadBuffer(GL_BACK);
752 glAccum(GL_RETURN, 1.0);
754 glColor4f(1, 1, 1, 1);
755 get_output()->set_opengl_state(VFrame::SCREEN);
764 LinearBlurPackage::LinearBlurPackage()
772 LinearBlurUnit::LinearBlurUnit(LinearBlurEngine *server,
773 LinearBlurMain *plugin)
776 this->plugin = plugin;
777 this->server = server;
781 #define BLEND_LAYER(COMPONENTS, TYPE, TEMP, MAX, DO_YUV) \
783 const int chroma_offset = (DO_YUV ? ((MAX + 1) / 2) : 0); \
784 for(int j = pkg->y1; j < pkg->y2; j++) \
786 TEMP *out_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
787 int in_y = y_table[j]; \
790 TYPE *in_row = (TYPE*)plugin->input->get_rows()[in_y]; \
791 for(int k = 0; k < w; k++) \
793 int in_x = x_table[k]; \
795 int in_offset = in_x * COMPONENTS; \
796 *out_row++ += in_row[in_offset]; \
799 *out_row++ += in_row[in_offset + 1]; \
800 *out_row++ += in_row[in_offset + 2]; \
804 *out_row++ += in_row[in_offset + 1]; \
805 *out_row++ += in_row[in_offset + 2]; \
807 if(COMPONENTS == 4) \
808 *out_row++ += in_row[in_offset + 3]; \
812 /* Copy to output */ \
813 if(i == plugin->config.steps - 1) \
815 for(int j = pkg->y1; j < pkg->y2; j++) \
817 TEMP *in_row = (TEMP*)plugin->accum + COMPONENTS * w * j; \
818 TYPE *in_backup = (TYPE*)plugin->input->get_rows()[j]; \
819 TYPE *out_row = (TYPE*)plugin->output->get_rows()[j]; \
820 for(int k = 0; k < w; k++) \
824 *out_row++ = (*in_row++ * fraction) / 0x10000; \
829 *out_row++ = *in_backup++; \
837 *out_row++ = (*in_row++ * fraction) / 0x10000; \
842 *out_row++ = *in_backup++; \
848 *out_row++ = (*in_row++ * fraction) / 0x10000; \
853 *out_row++ = *in_backup++; \
861 *out_row++ = (*in_row++ * fraction) / 0x10000; \
866 *out_row++ = *in_backup++; \
872 *out_row++ = (*in_row++ * fraction) / 0x10000; \
877 *out_row++ = *in_backup++; \
882 if(COMPONENTS == 4) \
886 *out_row++ = (*in_row++ * fraction) / 0x10000; \
891 *out_row++ = *in_backup++; \
900 void LinearBlurUnit::process_package(LoadPackage *package)
902 LinearBlurPackage *pkg = (LinearBlurPackage*)package;
903 int h = plugin->output->get_h();
904 int w = plugin->output->get_w();
906 int fraction = 0x10000 / plugin->config.steps;
907 int do_r = plugin->config.r;
908 int do_g = plugin->config.g;
909 int do_b = plugin->config.b;
910 int do_a = plugin->config.a;
911 for(int i = 0; i < plugin->config.steps; i++)
913 int *x_table = plugin->scale_x_table[i];
914 int *y_table = plugin->scale_y_table[i];
916 switch(plugin->input->get_color_model())
919 BLEND_LAYER(3, float, float, 1, 0)
922 BLEND_LAYER(3, uint8_t, int, 0xff, 0)
925 BLEND_LAYER(4, float, float, 1, 0)
928 BLEND_LAYER(4, uint8_t, int, 0xff, 0)
931 BLEND_LAYER(3, uint16_t, int, 0xffff, 0)
933 case BC_RGBA16161616:
934 BLEND_LAYER(4, uint16_t, int, 0xffff, 0)
937 BLEND_LAYER(3, uint8_t, int, 0xff, 1)
940 BLEND_LAYER(4, uint8_t, int, 0xff, 1)
943 BLEND_LAYER(3, uint16_t, int, 0xffff, 1)
945 case BC_YUVA16161616:
946 BLEND_LAYER(4, uint16_t, int, 0xffff, 1)
957 LinearBlurEngine::LinearBlurEngine(LinearBlurMain *plugin,
960 : LoadServer(total_clients, total_packages)
962 this->plugin = plugin;
965 void LinearBlurEngine::init_packages()
967 for(int i = 0; i < get_total_packages(); i++)
969 LinearBlurPackage *package = (LinearBlurPackage*)get_package(i);
970 package->y1 = plugin->output->get_h() * i / get_total_packages();
971 package->y2 = plugin->output->get_h() * (i + 1) / get_total_packages();
975 LoadClient* LinearBlurEngine::new_client()
977 return new LinearBlurUnit(this, plugin);
980 LoadPackage* LinearBlurEngine::new_package()
982 return new LinearBlurPackage;