4 * Copyright (C) 1997-2020 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dragcheckbox.h"
28 #include "mainerror.h"
30 #include "pluginserver.h"
31 #include "pluginvclient.h"
40 class BoxBlurNumISlider;
41 class BoxBlurNumIText;
42 class BoxBlurNumClear;
60 void copy_from(BoxBlurConfig &that);
61 int equivalent(BoxBlurConfig &that);
62 void interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
63 int64_t prev_frame, int64_t next_frame, int64_t current_frame);
67 int horz_radius, vert_radius, power;
74 class BoxBlurNumISlider : public BC_ISlider
77 BoxBlurNumISlider(BoxBlurNum *num, int x, int y);
82 class BoxBlurNumIText : public BC_TumbleTextBox
85 BoxBlurNumIText(BoxBlurNum *num, int x, int y);
90 class BoxBlurNumClear : public BC_Button
93 BoxBlurNumClear(BoxBlurNum *num, int x, int y);
94 static int calculate_w(BoxBlurNum *num);
103 BoxBlurNum(BoxBlurWindow *gui, int x, int y, int w,
104 const char *name, int *iv, int imn, int imx);
106 void create_objects();
107 void update(int value);
114 int imn, imx, *ivalue;
115 int title_w, text_w, slider_w;
117 BoxBlurNumIText *text;
118 BoxBlurNumISlider *slider;
119 BoxBlurNumClear *clear;
123 class BoxBlurRadius : public BoxBlurNum
126 BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w,
127 const char *name, int *radius);
130 class BoxBlurPower : public BoxBlurNum
133 BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w,
134 const char *name, int *power);
137 class BoxBlurX : public BC_TumbleTextBox
140 BoxBlurX(BoxBlurWindow *gui, int x, int y);
144 class BoxBlurY : public BC_TumbleTextBox
147 BoxBlurY(BoxBlurWindow *gui, int x, int y);
151 class BoxBlurW : public BC_TumbleTextBox
154 BoxBlurW(BoxBlurWindow *gui, int x, int y);
158 class BoxBlurH : public BC_TumbleTextBox
161 BoxBlurH(BoxBlurWindow *gui, int x, int y);
166 class BoxBlurDrag : public DragCheckBox
169 BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y);
172 Track *get_drag_track();
173 int64_t get_drag_position();
174 static int calculate_w(BoxBlurWindow *gui);
177 BoxBlurEffect *plugin;
180 class BoxBlurReset : public BC_GenericButton
183 BoxBlurReset(BoxBlurWindow *gui, int x, int y);
185 static int calculate_w(BoxBlurWindow *gui);
190 class BoxBlurPreset : public BC_GenericButton
193 BoxBlurPreset(BoxBlurWindow *gui, int x, int y);
195 static int calculate_w(BoxBlurWindow *gui);
200 class BoxBlurWindow : public PluginClientWindow
203 BoxBlurWindow(BoxBlurEffect *plugin);
205 void create_objects();
209 BoxBlurEffect *plugin;
211 BoxBlurPreset *preset;
212 BoxBlurRadius *blur_horz;
213 BoxBlurRadius *blur_vert;
214 BoxBlurPower *blur_power;
223 class BoxBlurEffect : public PluginVClient
226 BoxBlurEffect(PluginServer *server);
229 PLUGIN_CLASS_MEMBERS(BoxBlurConfig)
230 int process_realtime(VFrame *input, VFrame *output);
233 void save_data(KeyFrame *keyframe);
234 void read_data(KeyFrame *keyframe);
237 VFrame *input, *output;
242 void BoxBlurConfig::reset()
252 void BoxBlurConfig::preset()
263 BoxBlurConfig::BoxBlurConfig()
268 void BoxBlurConfig::copy_from(BoxBlurConfig &that)
270 horz_radius = that.horz_radius;
271 vert_radius = that.vert_radius;
274 box_x = that.box_x; box_y = that.box_y;
275 box_w = that.box_w; box_h = that.box_h;
278 int BoxBlurConfig::equivalent(BoxBlurConfig &that)
280 return horz_radius == that.horz_radius &&
281 vert_radius == that.vert_radius &&
282 power == that.power && // drag == that.drag &&
283 EQUIV(box_x, that.box_x) && EQUIV(box_y, that.box_y) &&
284 box_w == that.box_w && box_h == that.box_h;
287 void BoxBlurConfig::interpolate(BoxBlurConfig &prev, BoxBlurConfig &next,
288 int64_t prev_frame, int64_t next_frame, int64_t current_frame)
290 double u = (double)(next_frame - current_frame) / (next_frame - prev_frame);
292 this->horz_radius = u*prev.horz_radius + v*next.horz_radius;
293 this->vert_radius = u*prev.vert_radius + v*next.vert_radius;
294 this->power = u*prev.power + v*next.power;
295 this->drag = prev.drag;
296 this->box_x = u*prev.box_x + v*next.box_x;
297 this->box_y = u*prev.box_y + v*next.box_y;
298 this->box_w = u*prev.box_w + v*next.box_w;
299 this->box_h = u*prev.box_h + v*next.box_h;
303 int BoxBlurNum::get_w() { return w; }
304 int BoxBlurNum::get_h() { return h; }
306 BoxBlurNumISlider::BoxBlurNumISlider(BoxBlurNum *num, int x, int y)
307 : BC_ISlider(x, y, 0, num->slider_w, num->slider_w,
308 num->imn, num->imx, *num->ivalue)
313 int BoxBlurNumISlider::handle_event()
315 int iv = get_value();
317 num->gui->update_drag();
321 BoxBlurNumIText::BoxBlurNumIText(BoxBlurNum *num, int x, int y)
322 : BC_TumbleTextBox(num->gui, *num->ivalue, num->imn, num->imx,
328 int BoxBlurNumIText::handle_event()
330 int iv = atoi(get_text());
332 num->gui->update_drag();
336 BoxBlurNumClear::BoxBlurNumClear(BoxBlurNum *num, int x, int y)
337 : BC_Button(x, y, num->gui->plugin->get_theme()->get_image_set("reset_button"))
342 int BoxBlurNumClear::calculate_w(BoxBlurNum *num)
344 VFrame **imgs = num->gui->plugin->get_theme()->get_image_set("reset_button");
345 return imgs[0]->get_w();
348 int BoxBlurNumClear::handle_event()
352 num->gui->update_drag();
356 BoxBlurNum::BoxBlurNum(BoxBlurWindow *gui, int x, int y, int w,
357 const char *name, int *iv, int imn, int imx)
368 int margin = gui->plugin->get_theme()->widget_border;
369 int clear_w = BoxBlurNumClear::calculate_w(this);
370 int tumble_w = BC_Tumbler::calculate_w();
371 int len = w - 2*margin - clear_w - tumble_w;
372 this->title_w = xS(60);
373 this->text_w = xS(60) - tumble_w;
374 this->slider_w = len - title_w - text_w - 2*margin;
382 BoxBlurNum::~BoxBlurNum()
387 void BoxBlurNum::create_objects()
390 gui->add_subwindow(title = new BC_Title(x1, y, name));
391 int margin = gui->plugin->get_theme()->widget_border;
392 x1 += title_w + margin;
393 text = new BoxBlurNumIText(this, x1, y);
394 text->create_objects();
395 x1 += text_w + BC_Tumbler::calculate_w() + margin;
396 gui->add_subwindow(slider = new BoxBlurNumISlider(this, x1, y));
397 x1 += slider_w + 2*margin;
398 gui->add_subwindow(clear = new BoxBlurNumClear(this, x1, y));
399 h = bmax(title->get_h(), bmax(text->get_h(),
400 bmax(slider->get_h(), clear->get_h())));
403 void BoxBlurNum::update(int value)
405 text->update((int64_t)value);
406 slider->update(value);
411 BoxBlurRadius::BoxBlurRadius(BoxBlurWindow *gui, int x, int y, int w,
412 const char *name, int *radius)
413 : BoxBlurNum(gui, x, y, w, name, radius, 0, 100)
417 BoxBlurPower::BoxBlurPower(BoxBlurWindow *gui, int x, int y, int w,
418 const char *name, int *power)
419 : BoxBlurNum(gui, x, y, w, name, power, 1, 10)
423 BoxBlurWindow::BoxBlurWindow(BoxBlurEffect *plugin)
424 : PluginClientWindow(plugin, xS(360), yS(246), xS(360), yS(246), 0)
426 this->plugin = plugin;
430 box_x = 0; box_y = 0;
431 box_w = 0; box_h = 0;
434 BoxBlurWindow::~BoxBlurWindow()
445 void BoxBlurWindow::create_objects()
447 int x = xS(10), y = yS(10);
448 int t1 = x, t2 = t1+xS(24), t3 = t2+xS(100), t4 = t3+xS(24);
449 int ww = get_w() - 2*x, bar_o = xS(30), bar_m = xS(15);
450 int margin = plugin->get_theme()->widget_border;
453 add_subwindow(tbar = new BC_TitleBar(x, y, ww, bar_o, bar_m, _("Position & Size")));
454 y += tbar->get_h() + margin;
455 int x1 = ww - BoxBlurDrag::calculate_w(this) - margin;
456 add_subwindow(drag = new BoxBlurDrag(this, plugin, x1, y));
457 drag->create_objects();
458 if( plugin->config.drag && drag->drag_activate() )
459 eprintf("drag enabled, but compositor already grabbed\n");
462 add_subwindow(title = new BC_Title(t1, y, _("X:")));
463 box_x = new BoxBlurX(this, t2, y);
464 box_x->create_objects();
465 add_subwindow(title = new BC_Title(t3, y, _("W:")));
466 box_w = new BoxBlurW(this, t4, y);
467 box_w->create_objects();
468 y += bmax(title->get_h(), box_w->get_h()) + margin;
469 add_subwindow(title = new BC_Title(t1, y, _("Y:")));
470 box_y = new BoxBlurY(this, t2, y);
471 box_y->create_objects();
472 add_subwindow(title = new BC_Title(t3, y, _("H:")));
473 box_h = new BoxBlurH(this, t4, y);
474 box_h->create_objects();
475 y += bmax(title->get_h(), box_h->get_h()) + 2*margin;
477 add_subwindow(tbar = new BC_TitleBar(x, y, ww, bar_o, bar_m, _("Blur")));
478 y += tbar->get_h() + margin;
479 blur_horz = new BoxBlurRadius(this, x, y, ww, _("Horz:"),
480 &plugin->config.horz_radius);
481 blur_horz->create_objects();
482 y += blur_horz->get_h() + margin;
483 blur_vert = new BoxBlurRadius(this, x, y, ww, _("Vert:"),
484 &plugin->config.vert_radius);
485 blur_vert->create_objects();
486 y += blur_vert->get_h() + margin;
487 blur_power = new BoxBlurPower(this, x, y, ww, _("Power:"),
488 &plugin->config.power);
489 blur_power->create_objects();
490 y += blur_power->get_h() + margin + yS(8);
492 add_subwindow(bar = new BC_Bar(x, y, ww));
493 y += bar->get_h() + 2*margin;
495 add_subwindow(reset = new BoxBlurReset(this, x, y));
496 x1 = x + ww - BoxBlurPreset::calculate_w(this);
497 add_subwindow(preset = new BoxBlurPreset(this, x1, y));
498 y += bmax(title->get_h(), reset->get_h()) + 2*margin;
502 void BoxBlurWindow::update_gui()
504 BoxBlurConfig &config = plugin->config;
505 blur_horz->update(config.horz_radius);
506 blur_vert->update(config.vert_radius);
507 blur_power->update(config.power);
508 box_x->update(config.box_x);
509 box_y->update(config.box_y);
510 box_w->update((int64_t)config.box_w);
511 box_h->update((int64_t)config.box_h);
512 drag->drag_x = config.box_x;
513 drag->drag_y = config.box_y;
514 drag->drag_w = config.box_w;
515 drag->drag_h = config.box_h;
519 REGISTER_PLUGIN(BoxBlurEffect)
520 NEW_WINDOW_MACRO(BoxBlurEffect, BoxBlurWindow)
521 LOAD_CONFIGURATION_MACRO(BoxBlurEffect, BoxBlurConfig)
524 BoxBlurEffect::BoxBlurEffect(PluginServer *server)
525 : PluginVClient(server)
530 BoxBlurEffect::~BoxBlurEffect()
535 const char* BoxBlurEffect::plugin_title() { return N_("BoxBlur"); }
536 int BoxBlurEffect::is_realtime() { return 1; }
539 void BoxBlurEffect::save_data(KeyFrame *keyframe)
542 output.set_shared_output(keyframe->xbuf);
543 output.tag.set_title("BOXBLUR");
544 output.tag.set_property("HORZ_RADIUS", config.horz_radius);
545 output.tag.set_property("VERT_RADIUS", config.vert_radius);
546 output.tag.set_property("POWER", config.power);
547 output.tag.set_property("DRAG", config.drag);
548 output.tag.set_property("BOX_X", config.box_x);
549 output.tag.set_property("BOX_Y", config.box_y);
550 output.tag.set_property("BOX_W", config.box_w);
551 output.tag.set_property("BOX_H", config.box_h);
553 output.tag.set_title("/BOXBLUR");
555 output.append_newline();
556 output.terminate_string();
559 void BoxBlurEffect::read_data(KeyFrame *keyframe)
562 input.set_shared_input(keyframe->xbuf);
565 while( !(result = input.read_tag()) ) {
566 if( input.tag.title_is("BOXBLUR") ) {
567 config.horz_radius = input.tag.get_property("HORZ_RADIUS", config.horz_radius);
568 config.vert_radius = input.tag.get_property("VERT_RADIUS", config.vert_radius);
569 config.power = input.tag.get_property("POWER", config.power);
570 config.drag = input.tag.get_property("DRAG", config.drag);
571 config.box_x = input.tag.get_property("BOX_X", config.box_x);
572 config.box_y = input.tag.get_property("BOX_Y", config.box_y);
573 config.box_w = input.tag.get_property("BOX_W", config.box_w);
574 config.box_h = input.tag.get_property("BOX_H", config.box_h);
579 void BoxBlurEffect::draw_boundry()
581 if( !gui_open() ) return;
582 int box_x = config.box_x, box_y = config.box_y;
583 int box_w = config.box_w ? config.box_w : input->get_w();
584 int box_h = config.box_h ? config.box_h : input->get_h();
585 DragCheckBox::draw_boundary(output, box_x, box_y, box_w, box_h);
588 int BoxBlurEffect::process_realtime(VFrame *input, VFrame *output)
591 this->output = output;
592 load_configuration();
593 int out_w = output->get_w(), out_h = output->get_h();
596 int cpus = (out_w * out_h)/0x80000 + 1;
597 box_blur = new BoxBlur(cpus);
599 int x = config.box_x, y = config.box_y;
600 int ow = config.box_w ? config.box_w : out_w;
601 int oh = config.box_h ? config.box_h : out_h;
602 if( config.horz_radius ) {
603 box_blur->hblur(output, input, config.horz_radius, config.power,
607 if( config.vert_radius ) {
608 box_blur->vblur(output, input, config.vert_radius, config.power,
618 void BoxBlurEffect::update_gui()
620 if( !thread ) return;
621 load_configuration();
622 thread->window->lock_window("BoxBlurEffect::update_gui");
623 BoxBlurWindow *gui = (BoxBlurWindow *)thread->window;
625 thread->window->unlock_window();
629 BoxBlurX::BoxBlurX(BoxBlurWindow *gui, int x, int y)
630 : BC_TumbleTextBox(gui, gui->plugin->config.box_x,
631 -32767.f, 32767.f, x, y, xS(64))
636 int BoxBlurX::handle_event()
638 gui->plugin->config.box_x = atof(get_text());
643 BoxBlurY::BoxBlurY(BoxBlurWindow *gui, int x, int y)
644 : BC_TumbleTextBox(gui, gui->plugin->config.box_y,
645 -32767.f, 32767.f, x, y, xS(64))
650 int BoxBlurY::handle_event()
652 gui->plugin->config.box_y = atof(get_text());
657 BoxBlurW::BoxBlurW(BoxBlurWindow *gui, int x, int y)
658 : BC_TumbleTextBox(gui, gui->plugin->config.box_w,
659 0, 32767, x, y, xS(64))
663 int BoxBlurW::handle_event()
665 gui->plugin->config.box_w = atol(get_text());
670 BoxBlurH::BoxBlurH(BoxBlurWindow *gui, int x, int y)
671 : BC_TumbleTextBox(gui, gui->plugin->config.box_h,
672 0, 32767, x, y, xS(64))
676 int BoxBlurH::handle_event()
678 gui->plugin->config.box_h = atol(get_text());
683 BoxBlurDrag::BoxBlurDrag(BoxBlurWindow *gui, BoxBlurEffect *plugin, int x, int y)
684 : DragCheckBox(plugin->server->mwindow, x, y, _("Drag"), &plugin->config.drag,
685 plugin->config.box_x, plugin->config.box_y,
686 plugin->config.box_w, plugin->config.box_h)
688 this->plugin = plugin;
692 int BoxBlurDrag::calculate_w(BoxBlurWindow *gui)
695 calculate_extents(gui, &w, &h, _("Drag"));
699 Track *BoxBlurDrag::get_drag_track()
701 PluginServer *server = plugin->server;
702 int plugin_id = server->plugin_id;
703 Plugin *plugin = server->edl->tracks->plugin_exists(plugin_id);
704 return !plugin ? 0 : plugin->track;
706 int64_t BoxBlurDrag::get_drag_position()
708 return plugin->get_source_position();
711 void BoxBlurDrag::update_gui()
713 plugin->config.drag = get_value();
714 plugin->config.box_x = drag_x;
715 plugin->config.box_y = drag_y;
716 plugin->config.box_w = drag_w+0.5;
717 plugin->config.box_h = drag_h+0.5;
718 gui->box_x->update((float)plugin->config.box_x);
719 gui->box_y->update((float)plugin->config.box_y);
720 gui->box_w->update((int64_t)plugin->config.box_w);
721 gui->box_h->update((int64_t)plugin->config.box_h);
722 plugin->send_configure_change();
725 int BoxBlurDrag::handle_event()
727 int ret = DragCheckBox::handle_event();
728 plugin->send_configure_change();
732 void BoxBlurWindow::update_drag()
734 drag->drag_x = plugin->config.box_x;
735 drag->drag_y = plugin->config.box_y;
736 drag->drag_w = plugin->config.box_w;
737 drag->drag_h = plugin->config.box_h;
738 plugin->send_configure_change();
741 BoxBlurReset::BoxBlurReset(BoxBlurWindow *gui, int x, int y)
742 : BC_GenericButton(x, y, _("Reset"))
747 int BoxBlurReset::calculate_w(BoxBlurWindow *gui)
749 return BC_GenericButton::calculate_w(gui,_("Reset"));
752 int BoxBlurReset::handle_event()
754 BoxBlurEffect *plugin = gui->plugin;
755 plugin->config.reset();
756 gui->drag->update(0);
757 gui->drag->drag_deactivate();
763 BoxBlurPreset::BoxBlurPreset(BoxBlurWindow *gui, int x, int y)
764 : BC_GenericButton(x, y, _("Default"))
769 int BoxBlurPreset::calculate_w(BoxBlurWindow *gui)
771 return BC_GenericButton::calculate_w(gui,_("Default"));
774 int BoxBlurPreset::handle_event()
776 BoxBlurEffect *plugin = gui->plugin;
777 plugin->config.preset();
778 gui->drag->update(0);
779 gui->drag->drag_deactivate();